1 /* CC0 license (public domain) - see LICENSE file for details */
2 #include <ccan/pipecmd/pipecmd.h>
3 #include <ccan/noerr/noerr.h>
11 static char **gather_args(const char *arg0, va_list ap)
14 char **arr = calloc(sizeof(char *), n + 1);
18 arr[0] = (char *)arg0;
20 while ((arr[n++] = va_arg(ap, char *)) != NULL) {
21 char **narr = realloc(arr, sizeof(char *) * (n + 1));
31 pid_t pipecmdv(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
32 const char *cmd, va_list ap)
34 char **arr = gather_args(cmd, ap);
41 ret = pipecmdarr(fd_tochild, fd_fromchild, fd_errfromchild, arr);
46 pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
49 int tochild[2], fromchild[2], errfromchild[2], execfail[2];
54 if (fd_tochild == &pipecmd_preserve) {
55 tochild[0] = STDIN_FILENO;
57 } else if (pipe(tochild) != 0)
60 tochild[0] = open("/dev/null", O_RDONLY);
65 if (fd_fromchild == &pipecmd_preserve) {
66 fromchild[1] = STDOUT_FILENO;
68 } else if (pipe(fromchild) != 0)
69 goto close_tochild_fail;
71 fromchild[1] = open("/dev/null", O_WRONLY);
73 goto close_tochild_fail;
75 if (fd_errfromchild) {
76 if (fd_errfromchild == &pipecmd_preserve) {
77 errfromchild[1] = STDERR_FILENO;
78 fd_errfromchild = NULL;
79 } else if (fd_errfromchild == fd_fromchild) {
80 errfromchild[0] = fromchild[0];
81 errfromchild[1] = fromchild[1];
83 if (pipe(errfromchild) != 0)
84 goto close_fromchild_fail;
87 errfromchild[1] = open("/dev/null", O_WRONLY);
88 if (errfromchild[1] < 0)
89 goto close_fromchild_fail;
92 if (pipe(execfail) != 0)
93 goto close_errfromchild_fail;
95 if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD)
97 goto close_execfail_fail;
101 goto close_execfail_fail;
108 if (fd_errfromchild && fd_errfromchild != fd_fromchild)
109 close(errfromchild[0]);
113 // Child runs command.
114 if (tochild[0] != STDIN_FILENO) {
115 if (dup2(tochild[0], STDIN_FILENO) == -1)
116 goto child_errno_fail;
119 if (fromchild[1] != STDOUT_FILENO) {
120 if (dup2(fromchild[1], STDOUT_FILENO) == -1)
121 goto child_errno_fail;
124 if (fd_errfromchild && fd_errfromchild == fd_fromchild) {
125 if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
126 goto child_errno_fail;
127 } else if (errfromchild[1] != STDERR_FILENO) {
128 if (dup2(errfromchild[1], STDERR_FILENO) == -1)
129 goto child_errno_fail;
130 close(errfromchild[1]);
136 /* Gcc's warn-unused-result fail. */
137 if (write(execfail[1], &err, sizeof(err))) {
145 close(errfromchild[1]);
147 /* Child will close this without writing on successful exec. */
148 if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
150 waitpid(childpid, NULL, 0);
156 *fd_tochild = tochild[1];
158 *fd_fromchild = fromchild[0];
160 *fd_errfromchild = errfromchild[0];
164 close_noerr(execfail[0]);
165 close_noerr(execfail[1]);
166 close_errfromchild_fail:
168 close_noerr(errfromchild[0]);
169 close_noerr(errfromchild[1]);
170 close_fromchild_fail:
172 close_noerr(fromchild[0]);
173 close_noerr(fromchild[1]);
175 close_noerr(tochild[0]);
177 close_noerr(tochild[1]);
182 pid_t pipecmd(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
183 const char *cmd, ...)
189 childpid = pipecmdv(fd_tochild, fd_fromchild, fd_errfromchild, cmd, ap);