1 /* CC0 license (public domain) - see LICENSE file for details */
2 #include <ccan/pipecmd/pipecmd.h>
3 #include <ccan/noerr/noerr.h>
9 static char **gather_args(const char *arg0, va_list ap)
12 char **arr = calloc(sizeof(char *), n + 1);
16 arr[0] = (char *)arg0;
18 while ((arr[n++] = va_arg(ap, char *)) != NULL) {
19 arr = realloc(arr, sizeof(char *) * (n + 1));
26 pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, const char *cmd, va_list ap)
28 char **arr = gather_args(cmd, ap);
35 ret = pipecmdarr(fd_fromchild, fd_tochild, arr);
40 pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr)
42 int tochild[2], fromchild[2], execfail[2];
47 if (pipe(tochild) != 0)
50 tochild[0] = open("/dev/null", O_RDONLY);
55 if (pipe(fromchild) != 0)
56 goto close_tochild_fail;
58 fromchild[1] = open("/dev/null", O_WRONLY);
60 goto close_tochild_fail;
62 if (pipe(execfail) != 0)
63 goto close_fromchild_fail;
65 if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD)
67 goto close_execfail_fail;
71 goto close_execfail_fail;
80 // Child runs command.
81 if (tochild[0] != STDIN_FILENO) {
82 if (dup2(tochild[0], STDIN_FILENO) == -1)
83 goto child_errno_fail;
86 if (fromchild[1] != STDOUT_FILENO) {
87 if (dup2(fromchild[1], STDOUT_FILENO) == -1)
88 goto child_errno_fail;
95 write(execfail[1], &err, sizeof(err));
102 /* Child will close this without writing on successful exec. */
103 if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
105 waitpid(childpid, NULL, 0);
111 *fd_tochild = tochild[1];
113 *fd_fromchild = fromchild[0];
117 close_noerr(execfail[0]);
118 close_noerr(execfail[1]);
119 close_fromchild_fail:
121 close_noerr(fromchild[0]);
122 close_noerr(fromchild[1]);
124 close_noerr(tochild[0]);
126 close_noerr(tochild[1]);
131 pid_t pipecmd(int *fd_fromchild, int *fd_tochild, const char *cmd, ...)
137 childpid = pipecmdv(fd_fromchild, fd_tochild, cmd, ap);