/* based on concepts from the mutt filter code... * * This code basically does what popen should have been... and what * popen2/popen3/popen4 in python do... it allows you access to * as many of stdin/stdout/stderr for a sub program as you want, instead * of just one (which is what popen is). */ #include "cs_config.h" #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include "util/neo_misc.h" #include "util/neo_err.h" #include "util/filter.h" NEOERR *filter_wait (pid_t pid, int options, int *exitcode) { int r; pid_t rpid; rpid = waitpid (pid, &r, options); if (WIFEXITED(r)) { r = WEXITSTATUS(r); if (exitcode) { *exitcode = r; /* If they're asking for the exit code, we don't generate an error */ return STATUS_OK; } if (r == 0) return STATUS_OK; else return nerr_raise(NERR_SYSTEM, "Child %d returned status %d:", rpid, r); } if (WIFSIGNALED(r)) { r = WTERMSIG(r); return nerr_raise(NERR_SYSTEM, "Child %d died on signal %d:", rpid, r); } if (WIFSTOPPED(r)) { r = WSTOPSIG(r); return nerr_raise(NERR_SYSTEM, "Child %d stopped on signal %d:", rpid, r); } return nerr_raise(NERR_ASSERT, "ERROR: waitpid(%d, %d) returned (%d, %d)", pid, options, rpid, r); } NEOERR *filter_create_fd (const char *cmd, int *fdin, int *fdout, int *fderr, pid_t *pid) { int pi[2]={-1,-1}, po[2]={-1,-1}, pe[2]={-1,-1}; int rpid; *pid = 0; if (fdin) { *fdin = 0; if (pipe (pi) == -1) return nerr_raise_errno(NERR_SYSTEM, "Unable to open in pipe for command: %s", cmd); } if (fdout) { *fdout = 0; if (pipe (po) == -1) { if (fdin) { close (pi[0]); close (pi[1]); } return nerr_raise_errno(NERR_SYSTEM, "Unable to open out pipe for command: %s", cmd); } } if (fderr) { *fderr = 0; if (pipe (pe) == -1) { if (fdin) { close (pi[0]); close (pi[1]); } if (fdout) { close (po[0]); close (po[1]); } return nerr_raise_errno(NERR_SYSTEM, "Unable to open err pipe for command: %s", cmd); } } /* block signals */ if ((rpid = fork ()) == 0) { /* unblock signals */ if (fdin) { close (pi[1]); dup2 (pi[0], 0); close (pi[0]); } if (fdout) { close (po[0]); dup2 (po[1], 1); close (po[1]); } if (fderr) { close (pe[0]); dup2 (pe[1], 2); close (pe[1]); } execl ("/bin/sh", "sh", "-c", cmd, (void *)NULL); _exit (127); } else if (rpid == -1) { /* unblock signals */ if (fdin) { close (pi[0]); close (pi[1]); } if (fdout) { close (po[0]); close (po[1]); } if (fderr) { close (pe[0]); close (pe[1]); } return nerr_raise_errno(NERR_SYSTEM, "Unable to fork for command: %s", cmd); } if (fdout) { close (po[1]); *fdout = po[0]; } if (fdin) { close (pi[0]); *fdin = pi[1]; } if (fderr) { close (pe[1]); *fderr = pe[0]; } *pid = rpid; return STATUS_OK; } NEOERR *filter_create_fp(const char *cmd, FILE **in, FILE **out, FILE **err, pid_t *pid) { NEOERR *nerr; int fdin = 0, fdout = 0, fderr = 0; int *pfdin = NULL, *pfdout = NULL, *pfderr = NULL; if (in) pfdin = &fdin; if (out) pfdout = &fdout; if (err) pfderr = &fderr; nerr = filter_create_fd(cmd, pfdin, pfdout, pfderr, pid); if (nerr) return nerr_pass(nerr); if (in) { *in = fdopen (fdin, "w"); if (*in == NULL) return nerr_raise_errno(NERR_IO, "Unable to fdopen in for command: %s", cmd); } if (out) { *out = fdopen (fdout, "r"); if (*out == NULL) { if (in) fclose(*in); return nerr_raise_errno(NERR_IO, "Unable to fdopen out for command: %s", cmd); } } if (err) { *err = fdopen (fderr, "r"); if (*err == NULL) { if (in) fclose(*in); if (out) fclose(*out); return nerr_raise_errno(NERR_IO, "Unable to fdopen err for command: %s", cmd); } } return STATUS_OK; }