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 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: ####################### V 1.6.0.1:
new features: 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; const char *progname;
int msglevel; int msglevel;
int exitlevel; int exitlevel;
int logstderr;
int syslog; int syslog;
FILE *logfile; FILE *logfile;
int logfacility; int logfacility;
@ -51,7 +50,7 @@ struct diag_opts {
struct diag_opts diagopts = 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); 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) { void diag_set(char what, const char *arg) {
DIAG_INIT;
switch (what) { switch (what) {
const struct wordent *keywd; const struct wordent *keywd;
@ -104,14 +117,24 @@ void diag_set(char what, const char *arg) {
} }
} }
openlog(diagopts.progname, LOG_PID, diagopts.logfacility); openlog(diagopts.progname, LOG_PID, diagopts.logfacility);
diagopts.logstderr = false; break; if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
case 'f': if ((diagopts.logfile = fopen(arg, "a")) == NULL) { 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)); Error2("cannot open log file \"%s\": %s", arg, strerror(errno));
break; 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; case 'p': diagopts.progname = arg;
openlog(diagopts.progname, LOG_PID, diagopts.logfacility); openlog(diagopts.progname, LOG_PID, diagopts.logfacility);
break; break;
@ -122,6 +145,7 @@ void diag_set(char what, const char *arg) {
} }
void diag_set_int(char what, int arg) { void diag_set_int(char what, int arg) {
DIAG_INIT;
switch (what) { switch (what) {
case 'D': diagopts.msglevel = arg; break; case 'D': diagopts.msglevel = arg; break;
case 'e': diagopts.exitlevel = 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) { int diag_get_int(char what) {
DIAG_INIT;
switch (what) { switch (what) {
case 'y': return diagopts.syslog; case 'y': return diagopts.syslog;
case 's': return diagopts.logstderr; case 's': return diagopts.logfile == stderr;
case 'd': case 'D': return diagopts.msglevel; case 'd': case 'D': return diagopts.msglevel;
case 'e': return diagopts.exitlevel; case 'e': return diagopts.exitlevel;
} }
@ -148,6 +173,7 @@ int diag_get_int(char what) {
} }
const char *diag_get_string(char what) { const char *diag_get_string(char what) {
DIAG_INIT;
switch (what) { switch (what) {
case 'p': return diagopts.progname; case 'p': return diagopts.progname;
} }
@ -170,6 +196,7 @@ void msg(int level, const char *format, ...) {
size_t bytes; size_t bytes;
va_list ap; va_list ap;
DIAG_INIT;
if (level < diagopts.msglevel) return; if (level < diagopts.msglevel) return;
va_start(ap, format); va_start(ap, format);
#if HAVE_GETTIMEOFDAY || 1 #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) { static void _msg(int level, const char *buff, const char *syslp) {
if (diagopts.logstderr) {
fputs(buff, stderr); fflush(stderr);
}
if (diagopts.syslog) { if (diagopts.syslog) {
/* prevent format string attacks (thanks to CoKi) */ /* prevent format string attacks (thanks to CoKi) */
syslog(syslevel[level], "%s", syslp); 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); 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 */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __error_h_included #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 void diag_set_int(char what, int arg);
extern int diag_get_int(char what); extern int diag_get_int(char what);
extern const char *diag_get_string(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, ...); extern void msg(int level, const char *format, ...);
#endif /* !defined(__error_h_included) */ #endif /* !defined(__error_h_included) */

18
test.sh
View file

@ -5713,6 +5713,7 @@ esac
N=$((N+1)) N=$((N+1))
# there was an error in address EXEC with options pipes,stderr
NAME=EXECPIPESSTDERR NAME=EXECPIPESSTDERR
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%$NAME%*)
@ -5721,6 +5722,23 @@ testecho "$N" "$TEST" "" "exec:$CAT,pipes,stderr" "$opts"
esac esac
N=$((N+1)) 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 NAME=SIMPLEPARSE
case "$TESTS" in case "$TESTS" in

View file

@ -1,5 +1,5 @@
/* source: xio-exec.c */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */ /* 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; int status;
bool dash = false; bool dash = false;
int duptostderr;
if (argc != 2) { if (argc != 2) {
Error3("\"%s:%s\": wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1); 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); 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) return status;
if (status == 0) { /* child */ if (status == 0) { /* child */
const char *ends[] = { " ", NULL }; const char *ends[] = { " ", NULL };
@ -118,6 +119,11 @@ static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
/* only now redirect stderr */
if (duptostderr >= 0) {
diag_dup();
Dup2(duptostderr, 2);
}
Notice1("execvp'ing \"%s\"", token); Notice1("execvp'ing \"%s\"", token);
result = Execvp(token, pargv); result = Execvp(token, pargv);
/* here we come only if execvp() failed */ /* 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. */ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
struct single *fd, struct single *fd,
unsigned groups, 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 */ struct opt *popts; /* parent process options */
int numleft; int numleft;
@ -261,7 +262,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
} }
if (tn == NULL) { if (tn == NULL) {
Error("could not open pty"); Error("could not open pty");
return STAT_NORETRY; return -1;
} }
#endif #endif
Info1("opened pseudo terminal %s", tn); Info1("opened pseudo terminal %s", tn);
@ -280,7 +281,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
#endif /* HAVE_OPENPTY */ #endif /* HAVE_OPENPTY */
free(*copts); free(*copts);
if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return STAT_RETRYLATER; return -1;
} }
applyopts_cloexec(ptyfd, popts);/*!*/ applyopts_cloexec(ptyfd, popts);/*!*/
/* exec:...,pty did not kill child process under some circumstances */ /* 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 (rw != XIO_WRONLY) {
if (Pipe(rdpip) < 0) { if (Pipe(rdpip) < 0) {
Error2("pipe(%p): %s", rdpip, strerror(errno)); Error2("pipe(%p): %s", rdpip, strerror(errno));
return STAT_RETRYLATER; return -1;
} }
} }
/*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/ /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
@ -315,7 +316,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
free(*copts); free(*copts);
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
== NULL) { == NULL) {
return STAT_RETRYLATER; return -1;
} }
popts2 = copyopts(popts, GROUP_ALL); popts2 = copyopts(popts, GROUP_ALL);
@ -330,7 +331,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_RDONLY) { if (rw != XIO_RDONLY) {
if (Pipe(wrpip) < 0) { if (Pipe(wrpip) < 0) {
Error2("pipe(%p): %s", wrpip, strerror(errno)); Error2("pipe(%p): %s", wrpip, strerror(errno));
return STAT_RETRYLATER; return -1;
} }
} }
/*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[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) { if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s", Error5("socketpair(%d, %d, %d, %p): %s",
d, type, protocol, sv, strerror(errno)); d, type, protocol, sv, strerror(errno));
return STAT_RETRYLATER; return -1;
} }
/*0 Info5("socketpair(%d, %d, %d, {%d,%d})", /*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
d, type, protocol, sv[0], sv[1]);*/ d, type, protocol, sv[0], sv[1]);*/
free(*copts); free(*copts);
if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
return STAT_RETRYLATER; return -1;
} }
applyopts(sv[0], *copts, PH_PASTSOCKET); applyopts(sv[0], *copts, PH_PASTSOCKET);
applyopts(sv[1], popts, 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; if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
} }
/*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL) /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
return STAT_RETRYLATER;*/ return -1;*/
retropt_bool(*copts, OPT_STDERR, &withstderr); retropt_bool(*copts, OPT_STDERR, &withstderr);
xiosetchilddied(); /* set SIGCHLD handler */ xiosetchilddied(); /* set SIGCHLD handler */
@ -409,7 +410,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
pid = Fork(); pid = Fork();
if (pid < 0) { if (pid < 0) {
Error1("fork(): %s", strerror(errno)); Error1("fork(): %s", strerror(errno));
return STAT_RETRYLATER; return -1;
} }
/* gdb recommends to have env controlled sleep after fork */ /* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) { 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 (rw != XIO_RDONLY && fdi != ttyfd) {
if (Dup2(ttyfd, fdi) < 0) { if (Dup2(ttyfd, fdi) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno)); Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
return STAT_RETRYLATER; } return -1; }
/*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/ /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
} }
if (rw != XIO_WRONLY && fdo != ttyfd) { if (rw != XIO_WRONLY && fdo != ttyfd) {
if (Dup2(ttyfd, fdo) < 0) { if (Dup2(ttyfd, fdo) < 0) {
Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno)); Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
return STAT_RETRYLATER; } return -1; }
/*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/ /*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
} }
if ((rw == XIO_RDONLY || fdi != ttyfd) && 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 (fdi == rdpip[1]) { /* a conflict here */
if ((tmpi = Dup(wrpip[0])) < 0) { if ((tmpi = Dup(wrpip[0])) < 0) {
Error2("dup(%d): %s", wrpip[0], strerror(errno)); Error2("dup(%d): %s", wrpip[0], strerror(errno));
return STAT_RETRYLATER; return -1;
} }
/*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/ /*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
rdpip[1] = tmpi; rdpip[1] = tmpi;
@ -474,7 +475,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (fdo == wrpip[0]) { /* a conflict here */ if (fdo == wrpip[0]) { /* a conflict here */
if ((tmpo = Dup(rdpip[1])) < 0) { if ((tmpo = Dup(rdpip[1])) < 0) {
Error2("dup(%d): %s", rdpip[1], strerror(errno)); Error2("dup(%d): %s", rdpip[1], strerror(errno));
return STAT_RETRYLATER; return -1;
} }
/*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/ /*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
wrpip[0] = tmpo; wrpip[0] = tmpo;
@ -483,7 +484,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
if (rw != XIO_WRONLY && rdpip[1] != fdo) { if (rw != XIO_WRONLY && rdpip[1] != fdo) {
if (Dup2(rdpip[1], fdo) < 0) { if (Dup2(rdpip[1], fdo) < 0) {
Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno)); Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
return STAT_RETRYLATER; return -1;
} }
Close(rdpip[1]); Close(rdpip[1]);
/*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/ /*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 (rw != XIO_RDONLY && wrpip[0] != fdi) {
if (Dup2(wrpip[0], fdi) < 0) { if (Dup2(wrpip[0], fdi) < 0) {
Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno)); Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
return STAT_RETRYLATER; return -1;
} }
Close(wrpip[0]); Close(wrpip[0]);
/*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/ /*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 (rw != XIO_RDONLY && fdi != sv[1]) {
if (Dup2(sv[1], fdi) < 0) { if (Dup2(sv[1], fdi) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno)); Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
return STAT_RETRYLATER; } return -1; }
/*0 Info2("dup2(%d, %d)", sv[1], fdi);*/ /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
} }
if (rw != XIO_WRONLY && fdo != sv[1]) { if (rw != XIO_WRONLY && fdo != sv[1]) {
if (Dup2(sv[1], fdo) < 0) { if (Dup2(sv[1], fdo) < 0) {
Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno)); Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
return STAT_RETRYLATER; } return -1; }
/*0 Info2("dup2(%d, %d)", sv[1], fdo);*/ /*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
} }
if (fdi != sv[1] && fdo != sv[1]) { 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_LATE);
applyopts(-1, *copts, PH_LATE2); 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(); _xioopen_setdelayeduser();
/* set group before user - maybe you are not permitted afterwards */ /* set group before user - maybe you are not permitted afterwards */
if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) { 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) { if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) {
Setuid(user); Setuid(user);
} }
if (withstderr) {
*duptostderr = fdo;
} else {
*duptostderr = -1;
}
return 0; /* indicate child process */ return 0; /* indicate child process */
} }

View file

@ -1,5 +1,5 @@
/* source: xio-progcall.h */ /* 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 */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_progcall_h_included #ifndef __xio_progcall_h_included
@ -21,8 +21,11 @@ extern const struct optdesc opt_sigquit;
extern int _xioopen_foxec(int rw, /* O_RDONLY etc. */ extern int _xioopen_foxec(int rw, /* O_RDONLY etc. */
struct single *fd, struct single *fd,
unsigned groups, unsigned groups,
struct opt **opts struct opt **opts,
int *duptostderr
); );
extern int setopt_path(struct opt *opts, char **path); extern int setopt_path(struct opt *opts, char **path);
extern
int _xioopen_redir_stderr(int fdo);
#endif /* !defined(__xio_progcall_h_included) */ #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; int status;
char *path = NULL; char *path = NULL;
int duptostderr;
int result; int result;
const char *string = argv[1]; 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) return status;
if (status == 0) { /* child */ if (status == 0) { /* child */
int numleft; int numleft;
@ -50,6 +51,11 @@ static int xioopen_system(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
/* only now redirect stderr */
if (duptostderr >= 0) {
diag_dup();
Dup2(duptostderr, 2);
}
Info1("executing shell command \"%s\"", string); Info1("executing shell command \"%s\"", string);
result = System(string); result = System(string);
if (result != 0) { if (result != 0) {