/* wydawca - automatic release submission daemon Copyright (C) 2007, 2009 Sergey Poznyakoff Wydawca is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Wydawca is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wydawca. If not, see . */ #include "wydawca.h" #include "save-cwd.h" #include #include #include #include /* Execute a program from ARGC/ARGV. Return PID in PPID. Return FILE connected to the program's stdout and stderr. */ static FILE * start_prog (int argc, const char **argv, pid_t *ppid) { int p[2]; FILE *fp; pid_t pid; int i; pipe (p); switch (pid = fork ()) { case 0: /* Child process */ if (p[1] != 1) dup2 (p[1], 1); if (p[1] != 1) dup2 (p[1], 2); close (p[0]); /* Close unneded descripitors */ for (i = getdtablesize (); i > 2; i--) close (i); execvp (argv[0], (char**) argv); logmsg (LOG_CRIT, _("cannot run %s: %s"), argv[0], strerror (errno)); exit (EX_UNAVAILABLE); case -1: logmsg (LOG_CRIT, _("cannot run `%s': fork failed: %s"), argv[0], strerror (errno)); return NULL; default: /* Master process */ close (p[1]); fp = fdopen (p[0], "r"); if (!fp) logmsg (LOG_ERR, _("cannot fdopen: %s"), strerror (errno)); *ppid = pid; } return fp; } /* Log everything read from FP as the output from the program PROG, using syslog priority PRIO. */ void log_output (int prio, const char *prog, FILE *fp) { size_t size = 0; char *buf = NULL; logmsg (prio, _("%s output follows:"), prog); while (getline (&buf, &size, fp) > 0) logmsg (prio, "%s", buf); logmsg (prio, _("end of %s output"), prog); free (buf); } /* Execute ARGC/ARGV. Return the exit code in RETCODE. */ enum exec_result wydawca_exec (int argc, const char **argv, int *retcode) { FILE *fp; pid_t pid, npid; int status; int i; enum exec_result res; fp = start_prog (5, argv, &pid); if (!fp) { logmsg (LOG_CRIT, _("cannot start %s"), argv[0]); return exec_error; } for (i = 0; i < 5 && (npid = waitpid (pid, &status, WNOHANG)) == 0; i++) sleep (1); switch (npid) { case -1: logmsg (LOG_CRIT, _("cannot execute %s: waitpid failed: %s"), argv[0], strerror (errno)); fclose (fp); return exec_error; case 0: logmsg (LOG_CRIT, _("cannot execute %s: the process did not respond " "within 5 seconds: %s"), argv[0], strerror (errno)); kill (pid, SIGKILL); fclose (fp); return exec_error; default: break; } if (WIFEXITED (status)) { int rc = WEXITSTATUS (status); if (rc) { res = exec_fail; logmsg (LOG_ERR, _("command %s returned %d"), argv[0], rc); log_output (LOG_ERR, argv[0], fp); } else { res = exec_success; if (debug_level > 1) log_output (LOG_DEBUG, argv[0], fp); } if (retcode) *retcode = rc; } else { res = exec_error; if (WIFSIGNALED (status)) logmsg (LOG_ERR, _("%s terminated on signal %d"), argv[0], WTERMSIG (status)); else if (WIFSTOPPED (status)) logmsg (LOG_ERR, _("%s stopped on signal %d"), argv[0], WTERMSIG (status)); else logmsg (LOG_ERR, _("%s terminated with unrecognized status"), argv[0]); } fclose (fp); return res; }