Commit d3d2242b authored by Rusty Russell's avatar Rusty Russell

pipecmd: reverse order of args to match documentation; add pipecmd_preserve.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 440efa55
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* exit(1); * exit(1);
* exit(0); * exit(0);
* } * }
* child = pipecmd(&outputfd, NULL, NULL, argv[0], "ignoredarg", NULL); * child = pipecmd(NULL, &outputfd, NULL, argv[0], "ignoredarg", NULL);
* if (child < 0) * if (child < 0)
* err(1, "Creating child"); * err(1, "Creating child");
* if (read(outputfd, input, sizeof(input)) != sizeof(input)) * if (read(outputfd, input, sizeof(input)) != sizeof(input))
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
int pipecmd_preserve;
static char **gather_args(const char *arg0, va_list ap) static char **gather_args(const char *arg0, va_list ap)
{ {
size_t n = 1; size_t n = 1;
...@@ -26,7 +28,7 @@ static char **gather_args(const char *arg0, va_list ap) ...@@ -26,7 +28,7 @@ static char **gather_args(const char *arg0, va_list ap)
return arr; return arr;
} }
pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, pid_t pipecmdv(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
const char *cmd, va_list ap) const char *cmd, va_list ap)
{ {
char **arr = gather_args(cmd, ap); char **arr = gather_args(cmd, ap);
...@@ -36,12 +38,12 @@ pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, ...@@ -36,12 +38,12 @@ pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
ret = pipecmdarr(fd_fromchild, fd_tochild, fd_errfromchild, arr); ret = pipecmdarr(fd_tochild, fd_fromchild, fd_errfromchild, arr);
free_noerr(arr); free_noerr(arr);
return ret; return ret;
} }
pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
char *const *arr) char *const *arr)
{ {
int tochild[2], fromchild[2], errfromchild[2], execfail[2]; int tochild[2], fromchild[2], errfromchild[2], execfail[2];
...@@ -49,7 +51,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, ...@@ -49,7 +51,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
int err; int err;
if (fd_tochild) { 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; goto fail;
} else { } else {
tochild[0] = open("/dev/null", O_RDONLY); tochild[0] = open("/dev/null", O_RDONLY);
...@@ -57,7 +62,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, ...@@ -57,7 +62,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
goto fail; goto fail;
} }
if (fd_fromchild) { 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; goto close_tochild_fail;
} else { } else {
fromchild[1] = open("/dev/null", O_WRONLY); fromchild[1] = open("/dev/null", O_WRONLY);
...@@ -65,7 +73,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, ...@@ -65,7 +73,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
goto close_tochild_fail; goto close_tochild_fail;
} }
if (fd_errfromchild) { if (fd_errfromchild) {
if (fd_errfromchild == fd_fromchild) { if (fd_errfromchild == &pipecmd_preserve) {
errfromchild[1] = STDERR_FILENO;
fd_errfromchild = NULL;
} else if (fd_errfromchild == fd_fromchild) {
errfromchild[0] = fromchild[0]; errfromchild[0] = fromchild[0];
errfromchild[1] = fromchild[1]; errfromchild[1] = fromchild[1];
} else { } else {
...@@ -77,7 +88,7 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, ...@@ -77,7 +88,7 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild,
if (errfromchild[1] < 0) if (errfromchild[1] < 0)
goto close_fromchild_fail; goto close_fromchild_fail;
} }
if (pipe(execfail) != 0) if (pipe(execfail) != 0)
goto close_errfromchild_fail; goto close_errfromchild_fail;
...@@ -168,14 +179,14 @@ fail: ...@@ -168,14 +179,14 @@ fail:
return -1; return -1;
} }
pid_t pipecmd(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, pid_t pipecmd(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
const char *cmd, ...) const char *cmd, ...)
{ {
pid_t childpid; pid_t childpid;
va_list ap; va_list ap;
va_start(ap, cmd); va_start(ap, cmd);
childpid = pipecmdv(fd_fromchild, fd_tochild, fd_errfromchild, cmd, ap); childpid = pipecmdv(fd_tochild, fd_fromchild, fd_errfromchild, cmd, ap);
va_end(ap); va_end(ap);
return childpid; return childpid;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* If @errfd is NULL, the child's stderr is (write-only) /dev/null. * If @errfd is NULL, the child's stderr is (write-only) /dev/null.
* *
* If @errfd == @outfd (and non-NULL) they will be shared. * If @errfd == @outfd (and non-NULL) they will be shared.
* If @infd, @outfd or @errfd is &pipecmd_preserve, it is unchanged.
* *
* The return value is the pid of the child, or -1. * The return value is the pid of the child, or -1.
*/ */
...@@ -41,4 +42,10 @@ pid_t pipecmdv(int *infd, int *outfd, int *errfd, const char *cmd, va_list ap); ...@@ -41,4 +42,10 @@ pid_t pipecmdv(int *infd, int *outfd, int *errfd, const char *cmd, va_list ap);
* @arr: NULL-terminated array for arguments (first is program to run). * @arr: NULL-terminated array for arguments (first is program to run).
*/ */
pid_t pipecmdarr(int *infd, int *outfd, int *errfd, char *const *arr); pid_t pipecmdarr(int *infd, int *outfd, int *errfd, char *const *arr);
/**
* pipecmd_preserve - special value for fds to indicate it is unchanged
*/
extern int pipecmd_preserve;
#endif /* CCAN_PIPECMD_H */ #endif /* CCAN_PIPECMD_H */
...@@ -21,7 +21,7 @@ int main(int argc, char *argv[]) ...@@ -21,7 +21,7 @@ int main(int argc, char *argv[])
/* This is how many tests you plan to run */ /* This is how many tests you plan to run */
plan_tests(13); plan_tests(13);
child = pipecmd(&outfd, NULL, NULL, argv[0], "out", NULL); child = pipecmd(NULL, &outfd, NULL, argv[0], "out", NULL);
if (!ok1(child > 0)) if (!ok1(child > 0))
exit(1); exit(1);
ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf)); ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf));
......
#include <ccan/pipecmd/pipecmd.h>
/* Include the C files directly. */
#include <ccan/pipecmd/pipecmd.c>
#include <ccan/tap/tap.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t child;
int fd, oldfd, status;
char buf[5] = "test";
char template[] = "/tmp/run-preserve.XXXXXX";
/* We call ourselves, to test pipe. */
if (argc == 2) {
if (strcmp(argv[1], "out") == 0) {
if (write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf))
exit(2);
} else if (strcmp(argv[1], "in") == 0) {
if (read(STDIN_FILENO, buf, sizeof(buf)) != sizeof(buf))
exit(3);
if (memcmp(buf, "test", sizeof(buf)) != 0)
exit(4);
} else if (strcmp(argv[1], "err") == 0) {
if (write(STDERR_FILENO, buf, sizeof(buf)) != sizeof(buf))
exit(5);
} else
abort();
exit(0);
}
/* This is how many tests you plan to run */
plan_tests(25);
/* Preserve stdin test. */
fd = mkstemp(template);
ok1(write(fd, buf, sizeof(buf)) == sizeof(buf));
ok1(fd >= 0);
ok1(dup2(fd, STDIN_FILENO) == STDIN_FILENO);
ok1(lseek(STDIN_FILENO, 0, SEEK_SET) == 0);
child = pipecmd(&pipecmd_preserve, NULL, NULL, argv[0], "in", NULL);
if (!ok1(child > 0))
exit(1);
ok1(waitpid(child, &status, 0) == child);
ok1(WIFEXITED(status));
ok1(WEXITSTATUS(status) == 0);
close(STDIN_FILENO);
/* Preserve stdout test */
fd = open(template, O_WRONLY|O_TRUNC);
ok1(fd >= 0);
oldfd = dup(STDOUT_FILENO);
/* Can't use OK after this, since we mug stdout */
if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO)
exit(1);
child = pipecmd(NULL, &pipecmd_preserve, NULL, argv[0], "out", NULL);
if (child == -1)
exit(1);
/* Restore stdout */
dup2(oldfd, STDOUT_FILENO);
close(oldfd);
ok1(waitpid(child, &status, 0) == child);
ok1(WIFEXITED(status));
ok1(WEXITSTATUS(status) == 0);
fd = open(template, O_RDONLY);
ok1(read(fd, buf, sizeof(buf)) == sizeof(buf));
ok1(close(fd) == 0);
ok1(memcmp(buf, "test", sizeof(buf)) == 0);
/* Preserve stderr test. */
fd = open(template, O_WRONLY|O_TRUNC);
ok1(fd >= 0);
oldfd = dup(STDERR_FILENO);
ok1(dup2(fd, STDERR_FILENO) == STDERR_FILENO);
child = pipecmd(NULL, NULL, &pipecmd_preserve, argv[0], "err", NULL);
if (!ok1(child > 0))
exit(1);
/* Restore stderr. */
ok1(dup2(oldfd, STDERR_FILENO));
ok1(waitpid(child, &status, 0) == child);
ok1(WIFEXITED(status));
ok1(WEXITSTATUS(status) == 0);
close(oldfd);
fd = open(template, O_RDONLY);
ok1(read(fd, buf, sizeof(buf)) == sizeof(buf));
ok1(close(fd) == 0);
ok1(memcmp(buf, "test", sizeof(buf)) == 0);
unlink(template);
/* This exits depending on whether all tests passed */
return exit_status();
}
...@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) ...@@ -48,7 +48,7 @@ int main(int argc, char *argv[])
/* This is how many tests you plan to run */ /* This is how many tests you plan to run */
plan_tests(67); plan_tests(67);
child = pipecmd(&outfd, &infd, &errfd, argv[0], "inout", NULL); child = pipecmd(&infd, &outfd, &errfd, argv[0], "inout", NULL);
if (!ok1(child > 0)) if (!ok1(child > 0))
exit(1); exit(1);
ok1(write(infd, buf, sizeof(buf)) == sizeof(buf)); ok1(write(infd, buf, sizeof(buf)) == sizeof(buf));
...@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) ...@@ -63,7 +63,7 @@ int main(int argc, char *argv[])
ok1(WIFEXITED(status)); ok1(WIFEXITED(status));
ok1(WEXITSTATUS(status) == 0); ok1(WEXITSTATUS(status) == 0);
child = pipecmd(NULL, &infd, NULL, argv[0], "in", NULL); child = pipecmd(&infd, NULL, NULL, argv[0], "in", NULL);
if (!ok1(child > 0)) if (!ok1(child > 0))
exit(1); exit(1);
ok1(write(infd, buf, sizeof(buf)) == sizeof(buf)); ok1(write(infd, buf, sizeof(buf)) == sizeof(buf));
...@@ -72,7 +72,7 @@ int main(int argc, char *argv[]) ...@@ -72,7 +72,7 @@ int main(int argc, char *argv[])
ok1(WIFEXITED(status)); ok1(WIFEXITED(status));
ok1(WEXITSTATUS(status) == 0); ok1(WEXITSTATUS(status) == 0);
child = pipecmd(&outfd, NULL, NULL, argv[0], "out", NULL); child = pipecmd(NULL, &outfd, NULL, argv[0], "out", NULL);
if (!ok1(child > 0)) if (!ok1(child > 0))
exit(1); exit(1);
ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf)); ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf));
...@@ -94,7 +94,7 @@ int main(int argc, char *argv[]) ...@@ -94,7 +94,7 @@ int main(int argc, char *argv[])
ok1(WEXITSTATUS(status) == 0); ok1(WEXITSTATUS(status) == 0);
/* errfd == outfd should work with both. */ /* errfd == outfd should work with both. */
child = pipecmd(&errfd, NULL, &errfd, argv[0], "err", NULL); child = pipecmd(NULL, &errfd, &errfd, argv[0], "err", NULL);
if (!ok1(child > 0)) if (!ok1(child > 0))
exit(1); exit(1);
ok1(read(errfd, buf, sizeof(buf)) == sizeof(buf)); ok1(read(errfd, buf, sizeof(buf)) == sizeof(buf));
...@@ -104,7 +104,7 @@ int main(int argc, char *argv[]) ...@@ -104,7 +104,7 @@ int main(int argc, char *argv[])
ok1(WIFEXITED(status)); ok1(WIFEXITED(status));
ok1(WEXITSTATUS(status) == 0); ok1(WEXITSTATUS(status) == 0);
child = pipecmd(&outfd, NULL, &outfd, argv[0], "out", NULL); child = pipecmd(NULL, &outfd, &outfd, argv[0], "out", NULL);
if (!ok1(child > 0)) if (!ok1(child > 0))
exit(1); exit(1);
ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf)); ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment