int noise_from_prog::execprog (const char *const *av) { int fds[2]; if (pipe (fds) < 0) fatal ("pipe: %m\n"); pid = afork (); if (!pid) { close (fds[0]); if (fds[1] != 1) dup2 (fds[1], 1); if (fds[1] != 2) dup2 (fds[1], 2); if (fds[1] != 1 && fds[1] != 2) close (fds[1]); close (0); rc_ignore (chdir ("/")); open ("/dev/null", O_RDONLY); char *env[] = { NULL }; execve (av[0], const_cast<char *const *> (av), env); //warn ("%s: %m\n", av[0]); _exit (1); } close (fds[1]); close_on_exec (fds[0]); return fds[0]; }
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); } }
str agent_userdir (u_int32_t uid, bool create) { int fd = open (".", O_RDONLY); if (fd < 0) { warn ("current working directory (.): %m\n"); return NULL; } const char *tmpdir = safegetenv ("TMPDIR"); if (!tmpdir || tmpdir[0] != '/') tmpdir = "/tmp"; str ret; struct stat sb; uid_t myuid = getuid (); if (chdir (tmpdir) < 0) warn ("%s: %m\n", tmpdir); else if (stat (".", &sb) < 0) warn ("%s: %m\n", tmpdir); else if ((sb.st_mode & 022) && !(sb.st_mode & 01000)) warn ("bad permissions on %s; chmod +t or set TMPDIR elsewhere", tmpdir); else if (myuid == uid) ret = agent_userdir_search (tmpdir, uid, create); else if (!myuid) { int fds[2]; if (pipe (fds) < 0) warn ("pipe: %m\n"); else if (pid_t pid = afork ()) { close (fds[1]); strbuf sb; while (sb.tosuio ()->input (fds[0]) > 0) ; close (fds[0]); int status = 1; if (!waitpid (pid, &status, 0) && !status) ret = sb; } else { close (fds[0]); _exit (setuid (uid) || !(ret = agent_userdir_search (tmpdir, uid, create)) || (write (fds[1], ret, ret.len ()) != implicit_cast<ssize_t> (ret.len ()))); } } rc_ignore (fchdir (fd)); close (fd); return ret ? str (strbuf ("%s/", tmpdir) << ret) : str (NULL); }
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; }
pid_t aspawn (const char *path, char *const *argv, int in, int out, int err, cbv::ptr postforkcb, char *const *env) { pid_t pid = afork (); if (pid < 0) return pid; if (pid) return pid; setstdfds (in, out, err); if (postforkcb) (*postforkcb) (); if (env) execve (path, argv, env); else execv (path, argv); warn ("%s: %m\n", path); _exit (1); }