pipecmd: add stderr fd arg.
[ccan] / ccan / pipecmd / pipecmd.c
index c97fa312396dbb728e9cdceb6b795e21f6ee33da..42c6689445876e5b832520bd55a1e1aecf288c43 100644 (file)
@@ -23,7 +23,8 @@ static char **gather_args(const char *arg0, va_list ap)
        return arr;
 }
 
-pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, const char *cmd, va_list ap)
+pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
+              const char *cmd, va_list ap)
 {
        char **arr = gather_args(cmd, ap);
        pid_t ret;
@@ -32,14 +33,15 @@ 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_fromchild, fd_tochild, 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_fromchild, int *fd_tochild, 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;
 
@@ -59,8 +61,22 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr)
                if (fromchild[1] < 0)
                        goto close_tochild_fail;
        }
+       if (fd_errfromchild) {
+               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 +91,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,6 +107,14 @@ 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:
@@ -98,6 +125,7 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr)
 
        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)) {
@@ -111,11 +139,17 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr)
                *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]);
@@ -128,13 +162,14 @@ fail:
        return -1;
 }
 
-pid_t pipecmd(int *fd_fromchild, int *fd_tochild, const char *cmd, ...)
+pid_t pipecmd(int *fd_fromchild, int *fd_tochild, 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_fromchild, fd_tochild, fd_errfromchild, cmd, ap);
        va_end(ap);
 
        return childpid;