void getfilenoise (datasink *dst, const char *path, cbv cb, size_t maxbytes) { int fds[2]; if (pipe (fds) < 0) fatal ("pipe: %m\n"); pid_t pid = afork (); if (pid == -1) (*cb) (); else if (!pid) { close (fds[0]); int fd = open (path, O_RDONLY|O_NONBLOCK, 0); if (fd < 0) { fatal ("%s: %m\n", path); _exit (1); return; } for (;;) { char buf[1024]; size_t n = read (fd, buf, min (maxbytes, sizeof (buf))); if (n <= 0) _exit (0); v_write (fds[1], buf, n); maxbytes -= n; if (!maxbytes) _exit (0); } } else { close (fds[1]); close_on_exec (fds[0]); getprognoise (dst, fds[0], pid, cb); } }
static void sigcatch (int sig) { sigdocheck = 1; sigcaught[sig] = 1; selwait.tv_sec = selwait.tv_usec = 0; /* On some operating systems, select is not a system call but is * implemented inside libc. This may cause a race condition in * which select ends up being called with the original (non-zero) * value of selwait. We avoid the problem by writing to a pipe that * will wake up the select. */ v_write (sigpipes[1], "", 1); }
pid_t spawn (const char *path, char *const *argv, int in, int out, int err, cbv::ptr postforkcb, char *const *env) { int fds[2]; if (pipe (fds) < 0) return -1; close_on_exec (fds[0]); close_on_exec (fds[1]); pid_t pid = afork (); if (pid < 0) return pid; if (!pid) { amain_panic = true; close (fds[0]); setstdfds (in, out, err); if (postforkcb) (*postforkcb) (); if (env) execve (path, argv, env); else execv (path, argv); int saved_err = errno; v_write (fds[1], &saved_err, sizeof (saved_err)); close (fds[1]); // Since we return a useful errno, there is no need to print // anything in the child process. Just exit. _exit (1); } close (fds[1]); int chld_err; int n = read (fds[0], &chld_err, sizeof (chld_err)); close (fds[0]); if (n == 0) return pid; errno = chld_err; return -1; }