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 char **narr = realloc(arr, sizeof(char *) * (n + 1));
29 pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
30 const char *cmd, va_list ap)
32 char **arr = gather_args(cmd, ap);
39 ret = pipecmdarr(fd_fromchild, fd_tochild, fd_errfromchild, arr);
44 pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
47 int tochild[2], fromchild[2], errfromchild[2], execfail[2];
52 if (pipe(tochild) != 0)
55 tochild[0] = open("/dev/null", O_RDONLY);
60 if (pipe(fromchild) != 0)
61 goto close_tochild_fail;
63 fromchild[1] = open("/dev/null", O_WRONLY);
65 goto close_tochild_fail;
67 if (fd_errfromchild) {
68 if (fd_errfromchild == fd_fromchild) {
69 errfromchild[0] = fromchild[0];
70 errfromchild[1] = fromchild[1];
72 if (pipe(errfromchild) != 0)
73 goto close_fromchild_fail;
76 errfromchild[1] = open("/dev/null", O_WRONLY);
77 if (errfromchild[1] < 0)
78 goto close_fromchild_fail;
81 if (pipe(execfail) != 0)
82 goto close_errfromchild_fail;
84 if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD)
86 goto close_execfail_fail;
90 goto close_execfail_fail;
97 if (fd_errfromchild && fd_errfromchild != fd_fromchild)
98 close(errfromchild[0]);
102 // Child runs command.
103 if (tochild[0] != STDIN_FILENO) {
104 if (dup2(tochild[0], STDIN_FILENO) == -1)
105 goto child_errno_fail;
108 if (fromchild[1] != STDOUT_FILENO) {
109 if (dup2(fromchild[1], STDOUT_FILENO) == -1)
110 goto child_errno_fail;
113 if (fd_errfromchild && fd_errfromchild == fd_fromchild) {
114 if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
115 goto child_errno_fail;
116 } else if (errfromchild[1] != STDERR_FILENO) {
117 if (dup2(errfromchild[1], STDERR_FILENO) == -1)
118 goto child_errno_fail;
119 close(errfromchild[1]);
125 /* Gcc's warn-unused-result fail. */
126 if (write(execfail[1], &err, sizeof(err))) {
134 close(errfromchild[1]);
136 /* Child will close this without writing on successful exec. */
137 if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
139 waitpid(childpid, NULL, 0);
145 *fd_tochild = tochild[1];
147 *fd_fromchild = fromchild[0];
149 *fd_errfromchild = errfromchild[0];
153 close_noerr(execfail[0]);
154 close_noerr(execfail[1]);
155 close_errfromchild_fail:
157 close_noerr(errfromchild[0]);
158 close_noerr(errfromchild[1]);
159 close_fromchild_fail:
161 close_noerr(fromchild[0]);
162 close_noerr(fromchild[1]);
164 close_noerr(tochild[0]);
166 close_noerr(tochild[1]);
171 pid_t pipecmd(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
172 const char *cmd, ...)
178 childpid = pipecmdv(fd_fromchild, fd_tochild, fd_errfromchild, cmd, ap);