/* 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;
}