EXEC and SYSTEM with stderr injected socat messages into the data stream

This commit is contained in:
Gerhard Rieger 2008-06-07 10:14:56 +02:00
parent c4751d50ec
commit ad4bd0d9db
9 changed files with 126 additions and 67 deletions

View file

@ -9,6 +9,9 @@ corrections:
corrected a few mistakes that caused compiler warnings on 64bit hosts
EXEC and SYSTEM with stderr injected socat messages into the data
stream. test: EXECSTDERRLOG
####################### V 1.6.0.1:
new features:

View file

@ -1 +1 @@
"1.6.0.1+ip4bind+recvfromfork+x64"
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr"

67
error.c
View file

@ -39,7 +39,6 @@ struct diag_opts {
const char *progname;
int msglevel;
int exitlevel;
int logstderr;
int syslog;
FILE *logfile;
int logfacility;
@ -51,7 +50,7 @@ struct diag_opts {
struct diag_opts diagopts =
{ NULL, E_ERROR, E_ERROR, 1, 0, NULL, LOG_DAEMON, false, 0 } ;
{ NULL, E_ERROR, E_ERROR, 0, NULL, LOG_DAEMON, false, 0 } ;
static void _msg(int level, const char *buff, const char *syslp);
@ -89,7 +88,21 @@ static struct wordent facilitynames[] = {
} ;
static int diaginitialized;
static int diag_init(void) {
if (diaginitialized) {
return 0;
}
diaginitialized = 1;
/* gcc with GNU libc refuses to set this in the initializer */
diagopts.logfile = stderr;
return 0;
}
#define DIAG_INIT ((void)(diaginitialized || diag_init()))
void diag_set(char what, const char *arg) {
DIAG_INIT;
switch (what) {
const struct wordent *keywd;
@ -104,14 +117,24 @@ void diag_set(char what, const char *arg) {
}
}
openlog(diagopts.progname, LOG_PID, diagopts.logfacility);
diagopts.logstderr = false; break;
case 'f': if ((diagopts.logfile = fopen(arg, "a")) == NULL) {
if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
diagopts.logfile = NULL;
break;
case 'f':
if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
if ((diagopts.logfile = fopen(arg, "a")) == NULL) {
Error2("cannot open log file \"%s\": %s", arg, strerror(errno));
break;
} else {
diagopts.logstderr = false; break;
}
case 's': diagopts.logstderr = true; break; /* logging to stderr is default */
case 's':
if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
diagopts.logfile = stderr; break; /* logging to stderr is default */
case 'p': diagopts.progname = arg;
openlog(diagopts.progname, LOG_PID, diagopts.logfacility);
break;
@ -122,6 +145,7 @@ void diag_set(char what, const char *arg) {
}
void diag_set_int(char what, int arg) {
DIAG_INIT;
switch (what) {
case 'D': diagopts.msglevel = arg; break;
case 'e': diagopts.exitlevel = arg; break;
@ -138,9 +162,10 @@ void diag_set_int(char what, int arg) {
}
int diag_get_int(char what) {
DIAG_INIT;
switch (what) {
case 'y': return diagopts.syslog;
case 's': return diagopts.logstderr;
case 's': return diagopts.logfile == stderr;
case 'd': case 'D': return diagopts.msglevel;
case 'e': return diagopts.exitlevel;
}
@ -148,6 +173,7 @@ int diag_get_int(char what) {
}
const char *diag_get_string(char what) {
DIAG_INIT;
switch (what) {
case 'p': return diagopts.progname;
}
@ -170,6 +196,7 @@ void msg(int level, const char *format, ...) {
size_t bytes;
va_list ap;
DIAG_INIT;
if (level < diagopts.msglevel) return;
va_start(ap, format);
#if HAVE_GETTIMEOFDAY || 1
@ -236,9 +263,6 @@ void msg(int level, const char *format, ...) {
static void _msg(int level, const char *buff, const char *syslp) {
if (diagopts.logstderr) {
fputs(buff, stderr); fflush(stderr);
}
if (diagopts.syslog) {
/* prevent format string attacks (thanks to CoKi) */
syslog(syslevel[level], "%s", syslp);
@ -247,3 +271,24 @@ static void _msg(int level, const char *buff, const char *syslp) {
fputs(buff, diagopts.logfile); fflush(diagopts.logfile);
}
}
/* use a new log output file descriptor that is dup'ed from the current one.
this is useful when socat logs to stderr but fd 2 should be redirected to
serve other purposes */
int diag_dup(void) {
int newfd;
DIAG_INIT;
if (diagopts.logfile == NULL) {
return -1;
}
newfd = dup(fileno(diagopts.logfile));
if (diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
if (newfd >= 0) {
diagopts.logfile = fdopen(newfd, "w");
}
return newfd;
}

View file

@ -1,5 +1,5 @@
/* source: error.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __error_h_included
@ -202,7 +202,8 @@ extern void diag_set(char what, const char *arg);
extern void diag_set_int(char what, int arg);
extern int diag_get_int(char what);
extern const char *diag_get_string(char what);
extern int diag_dup(void);
extern int diag_dup2(int newfd);
extern void msg(int level, const char *format, ...);
#endif /* !defined(__error_h_included) */

18
test.sh
View file

@ -5713,6 +5713,7 @@ esac
N=$((N+1))
# there was an error in address EXEC with options pipes,stderr
NAME=EXECPIPESSTDERR
case "$TESTS" in
*%functions%*|*%$NAME%*)
@ -5721,6 +5722,23 @@ testecho "$N" "$TEST" "" "exec:$CAT,pipes,stderr" "$opts"
esac
N=$((N+1))
# EXEC and SYSTEM with stderr injected socat messages into the data stream.
NAME=EXECSTDERRLOG
case "$TESTS" in
*%functions%*|*%$NAME%*)
TEST="$NAME: simple echo via exec of cat with pipes,stderr"
SAVE_opts="$opts"
# make sure at least two -d are there
case "$opts" in
*-d*-d*) ;;
*-d*) opts="$opts -d" ;;
*) opts="-d -d" ;;
esac
testecho "$N" "$TEST" "" "exec:$CAT,pipes,stderr" "$opts"
opts="$SAVE_opts"
esac
N=$((N+1))
NAME=SIMPLEPARSE
case "$TESTS" in

View file

@ -1,5 +1,5 @@
/* source: xio-exec.c */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */
@ -32,6 +32,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
) {
int status;
bool dash = false;
int duptostderr;
if (argc != 2) {
Error3("\"%s:%s\": wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1);
@ -39,7 +40,7 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_DASH, &dash);
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts);
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts, &duptostderr);
if (status < 0) return status;
if (status == 0) { /* child */
const char *ends[] = { " ", NULL };
@ -118,6 +119,11 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY;
}
/* only now redirect stderr */
if (duptostderr >= 0) {
diag_dup();
Dup2(duptostderr, 2);
}
Notice1("execvp'ing \"%s\"", token);
result = Execvp(token, pargv);
/* here we come only if execvp() failed */

View file

@ -44,7 +44,8 @@ const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_P
int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
struct single *fd,
unsigned groups,
struct opt **copts /* in: opts; out: opts for child */
struct opt **copts, /* in: opts; out: opts for child */
int *duptostderr /* out: redirect stderr to output fd */
) {
struct opt *popts; /* parent process options */
int numleft;
@ -261,7 +262,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
}
if (tn == NULL) {
Error("could not open pty");
return STAT_NORETRY;
return -1;
}
#endif
Info1("opened pseudo terminal %s", tn);
@ -280,7 +281,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
#endif /* HAVE_OPENPTY */
free(*copts);
if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return STAT_RETRYLATER;
return -1;
}
applyopts_cloexec(ptyfd, popts);/*!*/
/* exec:...,pty did not kill child process under some circumstances */
@ -307,7 +308,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_WRONLY) {
if (Pipe(rdpip) < 0) {
Error2("pipe(%p): %s", rdpip, strerror(errno));
return STAT_RETRYLATER;
return -1;
}
}
/*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
@ -315,7 +316,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
free(*copts);
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
== NULL) {
return STAT_RETRYLATER;
return -1;
}
popts2 = copyopts(popts, GROUP_ALL);
@ -330,7 +331,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_RDONLY) {
if (Pipe(wrpip) < 0) {
Error2("pipe(%p): %s", wrpip, strerror(errno));
return STAT_RETRYLATER;
return -1;
}
}
/*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
@ -364,13 +365,13 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
d, type, protocol, sv, strerror(errno));
return STAT_RETRYLATER;
return -1;
}
/*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
d, type, protocol, sv[0], sv[1]);*/
free(*copts);
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return STAT_RETRYLATER;
return -1;
}
applyopts(sv[0], *copts, PH_PASTSOCKET);
applyopts(sv[1], popts, PH_PASTSOCKET);
@ -397,7 +398,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
}
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return STAT_RETRYLATER;*/
return -1;*/
retropt_bool(*copts, OPT_STDERR, &withstderr);
xiosetchilddied(); /* set SIGCHLD handler */
@ -409,7 +410,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
pid = Fork();
if (pid < 0) {
Error1("fork(): %s", strerror(errno));
return STAT_RETRYLATER;
return -1;
}
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
@ -438,13 +439,13 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_RDONLY && fdi != ttyfd) {
if (Dup2(ttyfd, fdi) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
return STAT_RETRYLATER; }
return -1; }
/*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
}
if (rw != XIO_WRONLY && fdo != ttyfd) {
if (Dup2(ttyfd, fdo) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
return STAT_RETRYLATER; }
return -1; }
/*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
}
if ((rw == XIO_RDONLY || fdi != ttyfd) &&
@ -466,7 +467,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (fdi == rdpip[1]) { /* a conflict here */
if ((tmpi = Dup(wrpip[0])) < 0) {
Error2("dup(%d): %s", wrpip[0], strerror(errno));
return STAT_RETRYLATER;
return -1;
}
/*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
rdpip[1] = tmpi;
@ -474,7 +475,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (fdo == wrpip[0]) { /* a conflict here */
if ((tmpo = Dup(rdpip[1])) < 0) {
Error2("dup(%d): %s", rdpip[1], strerror(errno));
return STAT_RETRYLATER;
return -1;
}
/*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
wrpip[0] = tmpo;
@ -483,7 +484,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_WRONLY && rdpip[1] != fdo) {
if (Dup2(rdpip[1], fdo) < 0) {
Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
return STAT_RETRYLATER;
return -1;
}
Close(rdpip[1]);
/*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/
@ -492,7 +493,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_RDONLY && wrpip[0] != fdi) {
if (Dup2(wrpip[0], fdi) < 0) {
Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
return STAT_RETRYLATER;
return -1;
}
Close(wrpip[0]);
/*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/
@ -509,13 +510,13 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_RDONLY && fdi != sv[1]) {
if (Dup2(sv[1], fdi) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
return STAT_RETRYLATER; }
return -1; }
/*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
}
if (rw != XIO_WRONLY && fdo != sv[1]) {
if (Dup2(sv[1], fdo) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
return STAT_RETRYLATER; }
return -1; }
/*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
}
if (fdi != sv[1] && fdo != sv[1]) {
@ -530,36 +531,6 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
applyopts(-1, *copts, PH_LATE);
applyopts(-1, *copts, PH_LATE2);
}
/* what to do with stderr? */
if (withstderr) {
/* handle it just like ordinary process output, i.e. copy output fd */
if (!withfork) {
if (Dup2(fdo, 2) < 0) {
Error2("dup2(%d, 2): %s", fdo, strerror(errno));
}
/*0 Info1("dup2(%d, 2)", fdo);*/
} else
#if HAVE_PTY
if (usepty) {
if (Dup2(ttyfd, 2) < 0) {
Error2("dup2(%d, 2): %s", ttyfd, strerror(errno));
}
/*0 Info1("dup2(%d, 2)", ttyfd);*/
} else
#endif /* HAVE_PTY */
if (usepipes) {
if (Dup2(/*rdpip[1]*/ fdo, 2) < 0) {
Error2("dup2(%d, 2): %s", /*rdpip[1]*/ fdo, strerror(errno));
}
/*0 Info1("dup2(%d, 2)", rdpip[1]);*/
} else {
if (Dup2(sv[1], 2) < 0) {
Error2("dup2(%d, 2): %s", sv[1], strerror(errno));
}
/*0 Info1("dup2(%d, 2)", sv[1]);*/
}
}
_xioopen_setdelayeduser();
/* set group before user - maybe you are not permitted afterwards */
if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) {
@ -568,6 +539,12 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) {
Setuid(user);
}
if (withstderr) {
*duptostderr = fdo;
} else {
*duptostderr = -1;
}
return 0; /* indicate child process */
}

View file

@ -1,5 +1,5 @@
/* source: xio-progcall.h */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_progcall_h_included
@ -21,8 +21,11 @@ extern const struct optdesc opt_sigquit;
extern int _xioopen_foxec(int rw, /* O_RDONLY etc. */
struct single *fd,
unsigned groups,
struct opt **opts
struct opt **opts,
int *duptostderr
);
extern int setopt_path(struct opt *opts, char **path);
extern
int _xioopen_redir_stderr(int fdo);
#endif /* !defined(__xio_progcall_h_included) */

View file

@ -31,10 +31,11 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
) {
int status;
char *path = NULL;
int duptostderr;
int result;
const char *string = argv[1];
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts);
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts, &duptostderr);
if (status < 0) return status;
if (status == 0) { /* child */
int numleft;
@ -50,6 +51,11 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY;
}
/* only now redirect stderr */
if (duptostderr >= 0) {
diag_dup();
Dup2(duptostderr, 2);
}
Info1("executing shell command \"%s\"", string);
result = System(string);
if (result != 0) {