mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
New feature SHELL address
This commit is contained in:
parent
50b199dcd9
commit
03f028a985
15 changed files with 399 additions and 45 deletions
2
CHANGES
2
CHANGES
|
@ -133,6 +133,8 @@ Features:
|
|||
Tests: LINUX_POSIXMQ_READ_PRIO LINUX_POSIXMQ_RECV_FORK
|
||||
LINUX_POSIXMQ_RECV_MAXCHILDREN LINUX_POSIXMQ_SEND_MAXCHILDREN
|
||||
|
||||
New address SHELL invokes a shell but without the overhead of SYSTEM
|
||||
|
||||
Corrections:
|
||||
When a sub process (EXEC, SYSTEM) terminated with exit code other than
|
||||
0, its last sent data might have been lost depending on timing of read/
|
||||
|
|
|
@ -50,7 +50,8 @@ XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \
|
|||
xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c \
|
||||
xio-sctp.c xio-rawip.c xio-posixmq.c \
|
||||
xio-socks.c xio-socks5.c xio-proxy.c xio-udp.c \
|
||||
xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \
|
||||
xio-progcall.c xio-exec.c xio-system.c xio-shell.c \
|
||||
xio-termios.c xio-readline.c \
|
||||
xio-pty.c xio-openssl.c xio-streams.c xio-namespaces.c \
|
||||
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-fs.c xio-tun.c
|
||||
XIOOBJS = $(XIOSRCS:.c=.o)
|
||||
|
@ -68,7 +69,7 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.
|
|||
xio-ip.h xio-ip4.h xio-ip6.h xio-rawip.h xio-posixmq.h \
|
||||
xio-ipapp.h xio-tcp.h xio-udp.h xio-sctp.h \
|
||||
xio-socks.h xio-socks5.h xio-proxy.h xio-progcall.h xio-exec.h \
|
||||
xio-system.h xio-termios.h xio-readline.h \
|
||||
xio-system.h xio-shell.h xio-termios.h xio-readline.h \
|
||||
xio-pty.h xio-openssl.h xio-streams.h xio-namespaces.h \
|
||||
xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-fs.h xio-tun.h
|
||||
|
||||
|
|
|
@ -713,6 +713,7 @@
|
|||
#undef WITH_PROXY
|
||||
#undef WITH_EXEC
|
||||
#undef WITH_SYSTEM
|
||||
#undef WITH_SHELL
|
||||
#undef WITH_READLINE
|
||||
#undef WITH_TUN
|
||||
#undef WITH_PTY
|
||||
|
|
|
@ -489,6 +489,14 @@ AC_ARG_ENABLE(system, [ --disable-system disable system (shell) support]
|
|||
esac],
|
||||
[AC_DEFINE(WITH_SYSTEM) AC_MSG_RESULT(yes)])
|
||||
|
||||
AC_MSG_CHECKING([whether to include shell invocation support])
|
||||
AC_ARG_ENABLE(system, [ --disable-shell disable shell invocation support],
|
||||
[case "$enableval" in
|
||||
no) AC_MSG_RESULT(no);;
|
||||
*) AC_DEFINE(WITH_SHELL) AC_MSG_RESULT(yes);;
|
||||
esac],
|
||||
[AC_DEFINE(WITH_SHELL) AC_MSG_RESULT(yes)])
|
||||
|
||||
AC_MSG_CHECKING(whether to include pty address support)
|
||||
AC_ARG_ENABLE(pty, [ --disable-pty disable pty support],
|
||||
[case "$enableval" in
|
||||
|
|
56
doc/socat.yo
56
doc/socat.yo
|
@ -335,6 +335,7 @@ label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>)))
|
|||
link(su)(OPTION_SUBSTUSER),
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED),
|
||||
link(nofork)(OPTION_NOFORK),
|
||||
link(socktype)(OPTION_SO_TYPE),
|
||||
link(pty)(OPTION_PTY),
|
||||
link(stderr)(OPTION_STDERR),
|
||||
link(ctty)(OPTION_CTTY),
|
||||
|
@ -344,7 +345,7 @@ label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>)))
|
|||
link(sigint)(OPTION_SIGINT),
|
||||
link(sigquit)(OPTION_SIGQUIT),
|
||||
link(netns)(OPTION_NETNS)nl()
|
||||
See also: link(SYSTEM)(ADDRESS_SYSTEM)
|
||||
See also: link(SYSTEM)(ADDRESS_SYSTEM),link(SHELL)(ADDRESS_SHELL)
|
||||
label(ADDRESS_FD)dit(bf(tt(FD:<fdnum>)))
|
||||
Uses the file descriptor link(<fdnum>)(TYPE_FDNUM). It must already exist as
|
||||
valid unix() file descriptor.nl()
|
||||
|
@ -785,7 +786,7 @@ label(ADDRESS_PTY)dit(bf(tt(PTY)))
|
|||
See also:
|
||||
link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN),
|
||||
link(PIPE)(ADDRESS_NAMED_PIPE),
|
||||
link(EXEC)(ADDRESS_EXEC), link(SYSTEM)(ADDRESS_SYSTEM)
|
||||
link(EXEC)(ADDRESS_EXEC), link(SYSTEM)(ADDRESS_SYSTEM), link(SHELL)(ADDRESS_SHELL)
|
||||
label(ADDRESS_READLINE)dit(bf(tt(READLINE)))
|
||||
Uses GNU readline and history on stdio to allow editing and reusing input
|
||||
lines (link(example)(EXAMPLE_ADDRESS_READLINE)). This requires the GNU readline and
|
||||
|
@ -1087,6 +1088,32 @@ label(ADDRESS_STDOUT)dit(bf(tt(STDOUT)))
|
|||
link(-U)(option_U), and link(dual addresses)(ADDRESS_DUAL).nl()
|
||||
Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl()
|
||||
See also: link(FD)(ADDRESS_FD)
|
||||
label(ADDRESS_SHELL)dit(bf(tt(SHELL:<shell-command>)))
|
||||
Forks a sub process that establishes communication with its parent process
|
||||
and invokes the specified program with the configured shell ($SHELL).
|
||||
Note that <shell-command> [link(string)(TYPE_STRING)] must
|
||||
not contain ',' or "!!", and that shell meta characters may have to be
|
||||
protected.
|
||||
After successful program start, socat() writes data to stdin of the
|
||||
process and reads from its stdout.nl()
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl()
|
||||
Useful options:
|
||||
link(path)(OPTION_PATH),
|
||||
link(fdin)(OPTION_FDIN),
|
||||
link(fdout)(OPTION_FDOUT),
|
||||
link(chroot)(OPTION_CHROOT),
|
||||
link(su)(OPTION_SUBSTUSER),
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED),
|
||||
link(nofork)(OPTION_NOFORK),
|
||||
link(socktype)(OPTION_SO_TYPE),
|
||||
link(pty)(OPTION_PTY),
|
||||
link(stderr)(OPTION_STDERR),
|
||||
link(ctty)(OPTION_CTTY),
|
||||
link(setsid)(OPTION_SETSID),
|
||||
link(pipes)(OPTION_PIPES),
|
||||
link(sigint)(OPTION_SIGINT),
|
||||
link(sigquit)(OPTION_SIGQUIT)nl()
|
||||
See also: link(EXEC)(ADDRESS_EXEC), link(SYSTEM)(ADDRESS_SYSTEM)
|
||||
label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<shell-command>)))
|
||||
Forks a sub process that establishes communication with its parent process
|
||||
and invokes the specified program with code(system()). Please note that
|
||||
|
@ -1104,6 +1131,7 @@ label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<shell-command>)))
|
|||
link(su)(OPTION_SUBSTUSER),
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED),
|
||||
link(nofork)(OPTION_NOFORK),
|
||||
link(socktype)(OPTION_SO_TYPE),
|
||||
link(pty)(OPTION_PTY),
|
||||
link(stderr)(OPTION_STDERR),
|
||||
link(ctty)(OPTION_CTTY),
|
||||
|
@ -1112,7 +1140,7 @@ label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:<shell-command>)))
|
|||
link(sigint)(OPTION_SIGINT),
|
||||
link(sigquit)(OPTION_SIGQUIT),
|
||||
link(netns)(OPTION_NETNS)nl()
|
||||
See also: link(EXEC)(ADDRESS_EXEC)
|
||||
See also: link(EXEC)(ADDRESS_EXEC), link(SHELL)(ADDRESS_SHELL)
|
||||
label(ADDRESS_TCP_CONNECT)dit(bf(tt(TCP:<host>:<port>)))
|
||||
Connects to <port> [link(TCP service)(TYPE_TCP_SERVICE)] on
|
||||
<host> [link(IP address)(TYPE_IP_ADDRESS)] using TCP/IP version 4 or 6
|
||||
|
@ -2163,6 +2191,7 @@ label(OPTION_SO_TYPE)dit(bf(tt(socktype=<type>)))
|
|||
[link(int)(TYPE_INT)]. Address resolution is not affected by this option.
|
||||
Under Linux, 1 means stream oriented socket, 2 means datagram socket, 3
|
||||
means raw socket, and 5 seqpacket (stream keeping packet boundaries).
|
||||
Datagrams are useful when you want to keep packet boundaries.
|
||||
label(OPTION_SO_PROTOCOL)dit(bf(tt(protocol)))
|
||||
Sets the protocol of the socket, specified as third argument to the
|
||||
code(socket()) or code(socketpair()) calls, to <protocol>
|
||||
|
@ -2786,6 +2815,19 @@ enddit()
|
|||
startdit()enddit()nl()
|
||||
|
||||
|
||||
label(GROUP_SHELL)
|
||||
|
||||
Options for link(address SHELL)(ADDRESS_SHELL)
|
||||
|
||||
label(OPTION_SHELL)dit(bf(tt(shell=<filename>)))
|
||||
Overwrites use the default shell with the named executable, e.g.
|
||||
tt(/bin/dash). Also sets the tt(SHELL) environment variable.
|
||||
|
||||
enddit()
|
||||
|
||||
startdit()enddit()nl()
|
||||
|
||||
|
||||
label(GROUP_TERMIOS)em(bf(TERMIOS option group))
|
||||
|
||||
For addresses that work on a tty (e.g., stdio, file:/dev/tty, exec:...,pty), the terminal parameters defined in the unix() termios mechanism are made available as address option parameters.
|
||||
|
@ -4409,8 +4451,8 @@ temporary versions; can be used in scripts invoked by socat.
|
|||
|
||||
dit(bf(SOCAT_PID) (output)) Socat sets this variable to its process id. In case
|
||||
of link(fork)(OPTION_FORK) address option, SOCAT_PID gets the child processes
|
||||
id. Forking for link(exec)(ADDRESS_EXEC) and link(system)(ADDRESS_SYSTEM) does
|
||||
not change SOCAT_PID.
|
||||
id. Forking for link(exec)(ADDRESS_EXEC), link(system)(ADDRESS_SYSTEM), and
|
||||
link(SHELL)(ADDRESS_SHELL) does not change SOCAT_PID.
|
||||
|
||||
dit(bf(SOCAT_PPID) (output)) Socat sets this variable to its process id. In
|
||||
case of link(fork)(OPTION_FORK), SOCAT_PPID keeps the pid of the master process.
|
||||
|
@ -4506,8 +4548,8 @@ link(su-d)(OPTION_SUBSTUSER_DELAYED), SHELL is set to the login shell of the
|
|||
given user.
|
||||
|
||||
dit(bf(PATH) (output))
|
||||
Can be set with option link(path)(OPTION_PATH) for link(exec)(ADDRESS_EXEC) and
|
||||
link(system)(ADDRESS_SYSTEM) addresses.
|
||||
Can be set with option link(path)(OPTION_PATH) for link(exec)(ADDRESS_EXEC),
|
||||
link(system)(ADDRESS_SYSTEM), and link(SHELL)(ADDRESS_SHELL) addresses.
|
||||
|
||||
dit(bf(HOME) (output))
|
||||
With options link(su)(OPTION_SUBSTUSER) and
|
||||
|
|
5
socat.c
5
socat.c
|
@ -644,6 +644,11 @@ void socat_version(FILE *fd) {
|
|||
#else
|
||||
fputs(" #undef WITH_SYSTEM\n", fd);
|
||||
#endif
|
||||
#ifdef WITH_SHELL
|
||||
fprintf(fd, " #define WITH_SHELL %d\n", WITH_SHELL);
|
||||
#else
|
||||
fputs(" #undef WITH_SHELL\n", fd);
|
||||
#endif
|
||||
#ifdef WITH_EXEC
|
||||
fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC);
|
||||
#else
|
||||
|
|
240
test.sh
240
test.sh
|
@ -814,11 +814,11 @@ childprocess () {
|
|||
return 0
|
||||
}
|
||||
|
||||
# return a list of child process pids
|
||||
# return a list of child process pids [killchild]
|
||||
childpids () {
|
||||
case "$UNAME" in
|
||||
AIX) l="$(ps -fade |grep "^........ ...... $(printf %6u $1)" |awk '{print($2);}')" ;;
|
||||
FreeBSD) l="$(ps -fl |grep "^[^ ][^ ]*[ ][ ]*[0-9][0-9]*[ ][ ]*$(printf %5u $1)" |awk '{print($2);}')" ;;
|
||||
FreeBSD) l="$(ps -fl |grep "^[^ ][^ ]*[ ][ ]*[0-9][0-9]*[ ][ ]*$1[ ]" |awk '{print($2);}')" ;;
|
||||
HP-UX) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)" |awk '{print($2);}')" ;;
|
||||
# Linux) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)" |awk '{print($2);}')" ;;
|
||||
Linux) l="$(ps -fade |grep "^[^[:space:]][^[:space:]]*[[:space:]][[:space:]]*[^[:space:]][^[:space:]]*[[:space:]][[:space:]]*$1 " |awk '{print($2);}')" ;;
|
||||
|
@ -4466,7 +4466,7 @@ elif ! feat=$(testfeats readline pty); then
|
|||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
SAVETERM="$TERM"; TERM= # 'cause konsole might print controls even in raw
|
||||
SAVETERM="$TERM"; TERM= # 'cause console might print controls even in raw
|
||||
SAVEMICS=$MICROS
|
||||
#MICROS=2000000
|
||||
ts="$td/test$N.sh"
|
||||
|
@ -4478,7 +4478,7 @@ tr="$td/test$N.ref"
|
|||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
|
||||
# the feature that we really want to test is in the readline.sh script:
|
||||
CMD="$TRACE $SOCAT $opts -t1 open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
|
||||
CMD="$TRACE $SOCAT -lpwrapper $opts -t1 open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
|
||||
#echo "$CMD" >"$ts"
|
||||
#chmod a+x "$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
|
@ -4487,6 +4487,7 @@ mkfifo "$tpi"
|
|||
touch "$tpo"
|
||||
#
|
||||
# during development of this test, the following command line succeeded:
|
||||
# ECHO="echo -e" SOCAT=./socat
|
||||
# (sleep 1; $ECHO "user\n\c"; sleep 1; $ECHO "password\c"; sleep 1; $ECHO "\n\c"; sleep 1; $ECHO "test 1\n\c"; sleep 1; $ECHO "\003\c"; sleep 1; $ECHO "test 2\n\c"; sleep 1; $ECHO "exit\n\c"; sleep 1) |$TRACE $SOCAT -d -d -d -d -lf/tmp/$USER/debug1 -v -x - exec:'./readline.sh ./readline-test.sh',pty,ctty,setsid,raw,echo=0,isig
|
||||
#
|
||||
# the following cat, in case of socat failure, reads the pipe to prevent below writer from hanging
|
||||
|
@ -4530,14 +4531,16 @@ EOF
|
|||
wait
|
||||
if ! tr "$($ECHO '\r \c')" "% " <$tpo |sed 's/%$//g' |sed 's/.*%//g' |diff "$tr" - >"$tdiff" 2>&1; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD"
|
||||
cat "$te"
|
||||
cat "$tdiff"
|
||||
echo "$CMD" 2>&1
|
||||
cat "$te" 2>&1
|
||||
echo diff: 2>&1
|
||||
cat "$tdiff" 2>&1
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat $te; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
kill $pid 2>/dev/null # necc on OpenBSD
|
||||
|
@ -5978,7 +5981,7 @@ to="$td/test$N.out"
|
|||
te="$td/test$N.err"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
|
||||
# the feature that we really want to test is in the readline.sh script:
|
||||
#
|
||||
CMD="$TRACE $SOCAT $opts -u open:$ti,readbytes=100 -"
|
||||
printf "test $F_n $TEST... " $N
|
||||
rm -f "$tf" "$ti" "$to"
|
||||
|
@ -17066,21 +17069,21 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# Test the sigint option
|
||||
NAME=EXEC_SIGINT
|
||||
# Test the sigint option with SHELL address
|
||||
NAME=SHELL_SIGINT
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%socket%*|*%exec%*|*%sigint%*|*%$NAME%*)
|
||||
TEST="$NAME: sigint option with EXEC"
|
||||
*%$N%*|*%functions%*|*%socket%*|*%shell%*|*%progcall%*|*%sigint%*|*%$NAME%*)
|
||||
TEST="$NAME: sigint option with SHELL"
|
||||
# Run Socat with an EXEC address invoking Socat, with option sigint
|
||||
# Send the parent a SIGINT; when the child gets SIGINT too (vs.SIGTERM)
|
||||
# the test succeeded
|
||||
if ! eval $NUMCOND; then :;
|
||||
# Remove unneeded checks, adapt lists of the remaining ones
|
||||
elif ! F=$(testfeats STDIO EXEC PIPE); then
|
||||
elif ! F=$(testfeats STDIO SHELL PIPE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO EXEC PIPE); then
|
||||
elif ! A=$(testaddrs STDIO SHELL PIPE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
|
@ -17093,8 +17096,11 @@ tf="$td/test$N.stdout"
|
|||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts -T 2 PIPE EXEC:\"$CAT\",pty,setsid,sigint"
|
||||
#CMD0="$TRACE $SOCAT $opts -T 2 PIPE EXEC:\"socat\ -d\ -d\ -d\ -d\ -lu\ PIPE\ PIPE\",pty,setsid,sigint"
|
||||
#CMD0="$TRACE $SOCAT $opts -T 2 PIPE EXEC:\"$CAT\",pty,setsid,sigint"
|
||||
CMD0="$TRACE $SOCAT $opts -T 2 SOCKETPAIR EXEC:\"$CAT\",pty,setsid,sigint"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval $CMD0 >/dev/null 2>"${te}0" &
|
||||
$CMD0 >/dev/null 2>"${te}0" &
|
||||
pid0=$!
|
||||
sleep 1
|
||||
|
@ -17120,6 +17126,167 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# Test the SHELL address with socketpair (default)
|
||||
NAME=SHELL_SOCKETPAIR
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%shell%*|*%socketpair%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via SHELL of cat with socketpair"
|
||||
# testecho ...
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! F=$(testfeats STDIO SHELL); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO SHELL); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
testecho "$N" "$TEST" "" "SHELL:$CAT" "$opts" "$val_t"
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
# Test the SHELL address with pipes
|
||||
NAME=SHELL_PIPES
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%shell%*|*%pipe%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via SHELL of cat with pipes"
|
||||
# testecho ...
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! F=$(testfeats STDIO SHELL SOCKETPAIR); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO SHELL PIPE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
testecho "$N" "$TEST" "" "SHELL:$CAT,pipes" "$opts" "$val_t"
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
# Test the SHELL address with pty
|
||||
NAME=SHELL_PTY
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%shell%*|*%pty%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via SHELL of cat with pty"
|
||||
# testecho ...
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! F=$(testfeats STDIO SHELL PTY); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO SHELL PTY); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
testecho "$N" "$TEST" "" "SHELL:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts" "$val_t"
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
# Test the SHELL address halfclose with socketpair
|
||||
NAME=SHELL_SOCKETPAIR_FLUSH
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%shell%*|*%socketpair%*|*%halfclose%*|*%$NAME%*)
|
||||
TEST="$NAME: call od -c via SHELL using socketpair"
|
||||
# testecho ...
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! F=$(testfeats STDIO SHELL); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO SHELL); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
testod "$N" "$TEST" "" "SHELL:$OD_C" "$opts" "$val_t"
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
# Test SHELL address halfclose with pipes
|
||||
NAME=SHELL_PIPES
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%shell%*|*%pipe%*|*%halfclose%*|*%$NAME%*)
|
||||
TEST="$NAME: call od -c via SHELL using pipes"
|
||||
# testecho ...
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! F=$(testfeats STDIO SHELL SOCKETPAIR); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO SHELL PIPE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
testod "$N" "$TEST" "" "SHELL:$OD_C,pipes" "$opts" "$val_t"
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# Test the sigint option with SYSTEM address
|
||||
NAME=SYSTEM_SIGINT
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%socket%*|*%progcall%*|*%system%*|*%sigint%*|*%$NAME%*)
|
||||
TEST="$NAME: sigint option with SYSTEM"
|
||||
# Run Socat with a SYSTEM address invoking Socat, with option sigint
|
||||
# Send the parent a SIGINT; when the child gets SIGINT too (vs.SIGTERM)
|
||||
# the test succeeded
|
||||
# setsid is required so the initial SIGINT is not delivered to the sub process.
|
||||
if ! eval $NUMCOND; then :;
|
||||
# Remove unneeded checks, adapt lists of the remaining ones
|
||||
elif ! F=$(testfeats STDIO SYSTEM PIPE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs STDIO SYSTEM PIPE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! o=$(testoptions setsid sigint) >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
#CMD0="$TRACE $SOCAT $opts PIPE SHELL:\"$SOCAT\ -dddd\ -lf ${te}1\ PIPE\ PIPE\",setsid,sigint"
|
||||
CMD0="$TRACE $SOCAT $opts SOCKETPAIR SHELL:\"$SOCAT\ -dddd\ -lf ${te}1\ PIPE\ PIPE\",setsid,sigint"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval $CMD0 >/dev/null 2>"${te}0" &
|
||||
pid0=$!
|
||||
sleep 1
|
||||
kill -INT $(childpids $pid0)
|
||||
wait
|
||||
if grep -q " W waitpid..: child .* exited with status 130" "${te}0"; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
namesFAIL="$namesFAIL $NAME"
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# end of common tests
|
||||
|
||||
##################################################################################
|
||||
|
@ -17308,14 +17475,25 @@ wait<something>port $PORT 1
|
|||
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
|
||||
rc1=$?
|
||||
kill $pid0 2>/dev/null; wait
|
||||
if echo "$da" |diff "${tf}1" - >$tdiff; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
elif [ !?!?! ]; then
|
||||
if [ "$rc1" -ne 0 ]; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}1" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
namesFAIL="$namesFAIL $NAME"
|
||||
elif ! echo "$da" |diff "${tf}1" - >$tdiff; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}1" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
namesFAIL="$namesFAIL $NAME"
|
||||
elif [ ??? ]; then
|
||||
# The test could not run meaningfully
|
||||
$PRINTF "$CANT\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
|
@ -17325,14 +17503,12 @@ elif [ !?!?! ]; then
|
|||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}1" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
namesFAIL="$namesFAIL $NAME"
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
|
|
98
xio-shell.c
Normal file
98
xio-shell.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
/* source: xio-shell.c */
|
||||
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of shell type */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
#include "xio-progcall.h"
|
||||
#include "xio-shell.h"
|
||||
|
||||
|
||||
#if WITH_SHELL
|
||||
|
||||
static int xioopen_shell(int arg, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
|
||||
|
||||
const struct addrdesc xioaddr_shell = { "SHELL", 3, xioopen_shell, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT|GROUP_SHELL, 1, 0, 0 HELP(":<shell-command>") };
|
||||
|
||||
const struct optdesc opt_shell = { "shell", NULL, OPT_SHELL, GROUP_SHELL, PH_PREEXEC, TYPE_STRING, OFUNC_SPEC, 0, 0 };
|
||||
|
||||
static int xioopen_shell(
|
||||
int argc,
|
||||
const char *argv[],
|
||||
struct opt *opts,
|
||||
int xioflags,
|
||||
xiofile_t *xfd,
|
||||
const struct addrdesc *addrdesc)
|
||||
{
|
||||
struct single *sfd = &xfd->stream;
|
||||
int status;
|
||||
char *path = NULL;
|
||||
int duptostderr;
|
||||
int result;
|
||||
char *shellpath = NULL;
|
||||
const char *shellname;
|
||||
const char *string = argv[1];
|
||||
|
||||
if (argc != 2) {
|
||||
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
shellpath = getenv("SHELL");
|
||||
retropt_string(opts, OPT_SHELL, &shellpath);
|
||||
if (shellpath == NULL) {
|
||||
Error("SHELL variable undefined");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
shellname = strrchr(shellpath, '/');
|
||||
if (shellname == NULL) {
|
||||
Error1("SHELL \"%s\" variable does not specify a path (has no '/')", shellpath);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
++shellname;
|
||||
|
||||
status = _xioopen_foxec(xioflags, sfd, addrdesc->groups, &opts, &duptostderr);
|
||||
if (status < 0) return status;
|
||||
if (status == 0) { /* child */
|
||||
int numleft;
|
||||
|
||||
if (setopt_path(opts, &path) < 0) {
|
||||
/* this could be dangerous, so let us abort this child... */
|
||||
Exit(1);
|
||||
}
|
||||
|
||||
if ((numleft = leftopts(opts)) > 0) {
|
||||
Error1("%d option(s) could not be used", numleft);
|
||||
showleft(opts);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
/* only now redirect stderr */
|
||||
if (duptostderr >= 0) {
|
||||
diag_dup();
|
||||
Dup2(duptostderr, 2);
|
||||
}
|
||||
|
||||
Setenv("SHELL", shellpath, 1);
|
||||
|
||||
Info1("executing shell command \"%s\"", string);
|
||||
Debug3("execl(\"%s\", \"%s\", \"-c\", \"%s\", NULL",
|
||||
shellpath, shellname, string);
|
||||
result = execl(shellpath, shellname, "-c", string, (char *)NULL);
|
||||
if (result != 0) {
|
||||
Warn2("execl(\"%s\") returned with status %d", string, result);
|
||||
Warn1("execl(): %s", strerror(errno));
|
||||
}
|
||||
Exit(0); /* this child process */
|
||||
}
|
||||
|
||||
/* parent */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_SHELL */
|
12
xio-shell.h
Normal file
12
xio-shell.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* source: xio-shell.h */
|
||||
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_shell_h_included
|
||||
#define __xio_shell_h_included 1
|
||||
|
||||
extern const struct addrdesc xioaddr_shell;
|
||||
|
||||
extern const struct optdesc opt_shell;
|
||||
|
||||
#endif /* !defined(__xio_shell_h_included) */
|
|
@ -43,7 +43,7 @@ static const char *addressgroupnames[] = {
|
|||
"FD", "FIFO", "CHR", "BLK",
|
||||
"REG", "SOCKET", "READLINE", "undef",
|
||||
"NAMED", "OPEN", "EXEC", "FORK",
|
||||
"LISTEN", "DEVICE", "CHILD", "RETRY",
|
||||
"LISTEN", "SHELL", "CHILD", "RETRY",
|
||||
"TERMIOS", "RANGE", "PTY", "PARENT",
|
||||
"UNIX", "IP4", "IP6", "INTERFACE",
|
||||
"UDP", "TCP", "SOCKS4", "OPENSSL",
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "xio-progcall.h"
|
||||
#include "xio-exec.h"
|
||||
#include "xio-system.h"
|
||||
#include "xio-shell.h"
|
||||
#include "xio-termios.h"
|
||||
#include "xio-readline.h"
|
||||
#include "xio-pty.h"
|
||||
|
|
|
@ -194,6 +194,9 @@ const struct addrname addressnames[] = {
|
|||
#if WITH_GENERICSOCKET
|
||||
{ "SENDTO", &xioaddr_socket_sendto },
|
||||
#endif
|
||||
#if WITH_SHELL
|
||||
{ "SHELL", &xioaddr_shell },
|
||||
#endif
|
||||
#if WITH_GENERICSOCKET
|
||||
{ "SOCKET-CONNECT", &xioaddr_socket_connect },
|
||||
{ "SOCKET-DATAGRAM", &xioaddr_socket_datagram },
|
||||
|
|
|
@ -1518,6 +1518,9 @@ const struct optname optionnames[] = {
|
|||
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
|
||||
IF_ANY ("setuid", &opt_setuid)
|
||||
IF_ANY ("setuid-early", &opt_setuid_early)
|
||||
#if WITH_SHELL
|
||||
IF_ANY ("shell", &opt_shell)
|
||||
#endif
|
||||
IF_ANY ("shut-close", &opt_shut_close)
|
||||
IF_ANY ("shut-down", &opt_shut_down)
|
||||
IF_ANY ("shut-none", &opt_shut_none)
|
||||
|
|
|
@ -163,7 +163,7 @@ enum e_func {
|
|||
#define GROUP_FORK 0x00000800 /* communication with forked process */
|
||||
|
||||
#define GROUP_LISTEN 0x00001000 /* socket in listening mode */
|
||||
/* 0x00002000 */
|
||||
#define GROUP_SHELL 0x00002000
|
||||
#define GROUP_CHILD 0x00004000 /* autonom child process */
|
||||
#define GROUP_RETRY 0x00008000 /* when open/connect etc. fails */
|
||||
#define GROUP_TERMIOS 0x00010000
|
||||
|
@ -655,6 +655,7 @@ enum e_optcode {
|
|||
OPT_SETUID,
|
||||
OPT_SETUID_EARLY,
|
||||
OPT_SET_NETNS, /* set net namespace */
|
||||
OPT_SHELL,
|
||||
OPT_SHUT_CLOSE,
|
||||
OPT_SHUT_DOWN,
|
||||
OPT_SHUT_NONE,
|
||||
|
|
|
@ -55,7 +55,7 @@ void socatsignalpass(int sig) {
|
|||
|
||||
_errno = errno;
|
||||
diag_in_handler = 1;
|
||||
Notice1("socatsignalpass(%d)", sig);
|
||||
Notice1("socatsignalpass(sig=%d)", sig);
|
||||
if ((sigdesc = socat_get_sig_desc(sig)) == NULL) { /* is async-signal-safe */
|
||||
diag_in_handler = 0;
|
||||
errno = _errno;
|
||||
|
@ -73,7 +73,8 @@ void socatsignalpass(int sig) {
|
|||
}
|
||||
}
|
||||
}
|
||||
Info1("socatsignalpass(): n=%d", n);
|
||||
if (n >= 0)
|
||||
Info1("socatsignalpass(): propagated signal to %d sub processes", n);
|
||||
}
|
||||
#if !HAVE_SIGACTION
|
||||
Signal(sig, socatsignalpass);
|
||||
|
|
Loading…
Reference in a new issue