X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fpipecmd%2Fpipecmd.c;h=c2b514df5e97189230dbc282f3b673293a77028c;hb=d3d2242ba8d975f8d7ddaa0348953dfd6f45ffce;hp=671d39198089b424f00e3f5041a7d79291ec55f8;hpb=c7e55a1601a5754363ee095d8c3f04fbc8b11ff5;p=ccan diff --git a/ccan/pipecmd/pipecmd.c b/ccan/pipecmd/pipecmd.c index 671d3919..c2b514df 100644 --- a/ccan/pipecmd/pipecmd.c +++ b/ccan/pipecmd/pipecmd.c @@ -6,6 +6,8 @@ #include #include +int pipecmd_preserve; + static char **gather_args(const char *arg0, va_list ap) { size_t n = 1; @@ -16,14 +18,18 @@ static char **gather_args(const char *arg0, va_list ap) arr[0] = (char *)arg0; while ((arr[n++] = va_arg(ap, char *)) != NULL) { - arr = realloc(arr, sizeof(char *) * (n + 1)); - if (!arr) + char **narr = realloc(arr, sizeof(char *) * (n + 1)); + if (!narr) { + free(arr); return NULL; + } + arr = narr; } return arr; } -pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, const char *cmd, va_list ap) +pid_t pipecmdv(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, + const char *cmd, va_list ap) { char **arr = gather_args(cmd, ap); pid_t ret; @@ -32,19 +38,23 @@ pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, const char *cmd, va_list ap) errno = ENOMEM; return -1; } - ret = pipecmdarr(fd_fromchild, fd_tochild, arr); + ret = pipecmdarr(fd_tochild, fd_fromchild, fd_errfromchild, arr); free_noerr(arr); return ret; } -pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr) +pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, + char *const *arr) { - int tochild[2], fromchild[2], execfail[2]; + int tochild[2], fromchild[2], errfromchild[2], execfail[2]; pid_t childpid; int err; if (fd_tochild) { - if (pipe(tochild) != 0) + if (fd_tochild == &pipecmd_preserve) { + tochild[0] = STDIN_FILENO; + fd_tochild = NULL; + } else if (pipe(tochild) != 0) goto fail; } else { tochild[0] = open("/dev/null", O_RDONLY); @@ -52,15 +62,35 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr) goto fail; } if (fd_fromchild) { - if (pipe(fromchild) != 0) + if (fd_fromchild == &pipecmd_preserve) { + fromchild[1] = STDOUT_FILENO; + fd_fromchild = NULL; + } else if (pipe(fromchild) != 0) goto close_tochild_fail; } else { fromchild[1] = open("/dev/null", O_WRONLY); if (fromchild[1] < 0) goto close_tochild_fail; } + if (fd_errfromchild) { + if (fd_errfromchild == &pipecmd_preserve) { + errfromchild[1] = STDERR_FILENO; + fd_errfromchild = NULL; + } else if (fd_errfromchild == fd_fromchild) { + errfromchild[0] = fromchild[0]; + errfromchild[1] = fromchild[1]; + } else { + if (pipe(errfromchild) != 0) + goto close_fromchild_fail; + } + } else { + errfromchild[1] = open("/dev/null", O_WRONLY); + if (errfromchild[1] < 0) + goto close_fromchild_fail; + } + if (pipe(execfail) != 0) - goto close_fromchild_fail; + goto close_errfromchild_fail; if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD) | FD_CLOEXEC) < 0) @@ -75,6 +105,9 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr) close(tochild[1]); if (fd_fromchild) close(fromchild[0]); + if (fd_errfromchild && fd_errfromchild != fd_fromchild) + close(errfromchild[0]); + close(execfail[0]); // Child runs command. @@ -88,32 +121,52 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr) goto child_errno_fail; close(fromchild[1]); } + if (fd_errfromchild && fd_errfromchild == fd_fromchild) { + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) + goto child_errno_fail; + } else if (errfromchild[1] != STDERR_FILENO) { + if (dup2(errfromchild[1], STDERR_FILENO) == -1) + goto child_errno_fail; + close(errfromchild[1]); + } execvp(arr[0], arr); child_errno_fail: err = errno; - write(execfail[1], &err, sizeof(err)); + /* Gcc's warn-unused-result fail. */ + if (write(execfail[1], &err, sizeof(err))) { + ; + } exit(127); } close(tochild[0]); close(fromchild[1]); + close(errfromchild[1]); close(execfail[1]); /* Child will close this without writing on successful exec. */ if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) { + close(execfail[0]); waitpid(childpid, NULL, 0); errno = err; return -1; } + close(execfail[0]); if (fd_tochild) *fd_tochild = tochild[1]; if (fd_fromchild) *fd_fromchild = fromchild[0]; + if (fd_errfromchild) + *fd_errfromchild = errfromchild[0]; return childpid; close_execfail_fail: close_noerr(execfail[0]); close_noerr(execfail[1]); +close_errfromchild_fail: + if (fd_errfromchild) + close_noerr(errfromchild[0]); + close_noerr(errfromchild[1]); close_fromchild_fail: if (fd_fromchild) close_noerr(fromchild[0]); @@ -126,13 +179,14 @@ fail: return -1; } -pid_t pipecmd(int *fd_fromchild, int *fd_tochild, const char *cmd, ...) +pid_t pipecmd(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, + const char *cmd, ...) { pid_t childpid; va_list ap; va_start(ap, cmd); - childpid = pipecmdv(fd_fromchild, fd_tochild, cmd, ap); + childpid = pipecmdv(fd_tochild, fd_fromchild, fd_errfromchild, cmd, ap); va_end(ap); return childpid;