From e8107b1889a620b6ba446953e698b30f1803b2cb Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Tue, 23 May 2017 15:16:27 +0200 Subject: mshow: spawn a pager for interactive use --- pipeto.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 pipeto.c (limited to 'pipeto.c') diff --git a/pipeto.c b/pipeto.c new file mode 100644 index 0000000..77982e1 --- /dev/null +++ b/pipeto.c @@ -0,0 +1,98 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +pid_t +pipeto(const char *cmdline) +{ + int pipe0[2]; // stdout -> stdin + int pipe1[2]; // child errno -> parent + pid_t pid; + + if (pipe(pipe0) < 0) + return -1; + if (pipe(pipe1) < 0) + return -1; + + pid = fork(); + if (pid < 0) { + return -1; + } else if (pid == 0) { // in child + close(pipe1[0]); + // close errno pipe on successful exec + fcntl(pipe1[1], F_SETFD, FD_CLOEXEC); + + if (dup2(pipe0[0], 0) < 0) + exit(111); + + close(pipe0[0]); + close(pipe0[1]); + + // split cmdline, just on spaces + char *argv[16]; + int argc = 0; + char *cp = strdup(cmdline); + if (!cp) + exit(111); + while (argc < 16 && *cp) { + argv[argc++] = cp; + cp = strchr(cp, ' '); + if (!cp) + break; + *cp++ = 0; + while (*cp == ' ') + cp++; + } + argv[argc] = 0; + + execvp(argv[0], argv); + + // execvp failed, write errno to parent + long e = errno; + if (write(pipe1[1], &e, sizeof e) < 0) + exit(111); // do a magic dance for gcc -Wunused-result + exit(111); + } else { // in parent + close(pipe1[1]); + + long e; + ssize_t n = read(pipe1[0], &e, sizeof e); + if (n < 0) + e = errno; + close(pipe1[0]); + + if (n == 0) { + // child executed successfully, redirect stdout to it + if (dup2(pipe0[1], 1) < 0) + return -1; + + close(pipe0[0]); + close(pipe0[1]); + + return pid; + } else { + errno = e; + return -1; + } + } + +// return pid; +} + +int +pipeclose(pid_t pid) +{ + int s; + + fflush(0); + close(1); + waitpid(pid, &s, 0); + + return s; +} -- cgit 1.4.1