+#define _GNU_SOURCE
#include "secnet.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
+#include <string.h>
#include "process.h"
/* Process handling - subprocesses, signals, etc. */
struct child {
pid_t pid;
- string_t desc;
+ cstring_t desc;
process_callback_fn *cb;
void *cst;
bool_t finished;
signal processing so that we can catch SIGCHLD for them and report
their exit status using the callback function. We block SIGCHLD
until signal processing has begun. */
-extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb,
- void *est, void *cst, string_t desc)
+pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
+ void *est, void *cst, cstring_t desc)
{
struct child *c;
- sigset_t sigchld;
pid_t p;
c=safe_malloc(sizeof(*c),"makesubproc");
c->cst=cst;
if (!signal_handling) {
- sigemptyset(&sigchld);
- sigaddset(&sigchld,SIGCHLD);
- sigprocmask(SIG_BLOCK,&sigchld,NULL);
+ fatal("makesubproc called before signal handling started");
}
p=fork();
if (p==0) {
c->finished=False;
c->next=children;
children=c;
+ return p;
}
static signal_notify_fn sigchld_handler;
}
}
-int sys_cmd(const char *path, char *arg, ...)
+int sys_cmd(const char *path, const char *arg, ...)
{
va_list ap;
- int rv;
+ int rv, rc;
pid_t c;
- va_start(ap,arg);
c=fork();
if (c) {
/* Parent -> wait for child */
- waitpid(c,&rv,0);
+ do {
+ rc = waitpid(c,&rv,0);
+ } while(rc < 0 && errno == EINTR);
+ if (rc < 0)
+ fatal_perror("sys_cmd: waitpid for %s", path);
+ if (rc != c) /* OS has gone mad */
+ fatal("sys_cmd: waitpid for %s returned wrong process ID!",
+ path);
+ if (rv) {
+ /* If the command failed reporting its exit status */
+ if (WIFEXITED(rv))
+ Message(M_ERR, "sys_cmd(%s,%s,...) exited with status %d\n",
+ path, arg, WEXITSTATUS(rv));
+ else if(WIFSIGNALED(rv))
+ Message(M_ERR, "sys_cmd(%s,%s,...) exited with signal %d (%s)%s\n",
+ path, arg, WTERMSIG(rv), strsignal(WTERMSIG(rv)),
+ WCOREDUMP(rv) ? " - core dumped" : "");
+ else
+ Message(M_ERR, "sys_cmd(%s,%s,...) exited with wstat %#x",
+ path, arg, rv);
+ }
} else if (c==0) {
char *args[100];
int i;
/* Child -> exec command */
- args[0]=arg;
+ /* Really we ought to strcpy() the arguments into the args array,
+ since the arguments are const char *. Since we'll exit anyway
+ if the execvp() fails this seems somewhat pointless, and
+ increases the chance of the child process failing before it
+ gets to exec(). */
+ va_start(ap,arg);
+ args[0]=(char *)arg; /* program name */
i=1;
while ((args[i++]=va_arg(ap,char *)));
execvp(path,args);
- exit(1);
+ fprintf(stderr, "sys_cmd(%s,%s,...): %s\n", path, arg, strerror(errno));
+ _exit(1);
} else {
/* Error */
- fatal_perror("sys_cmd(%s,%s,...)");
+ fatal_perror("sys_cmd(%s,%s,...)", path, arg);
}
- va_end(ap);
return rv;
}
static beforepoll_fn signal_beforepoll;
static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
- int *timeout_io, const struct timeval *tv_now,
- uint64_t *now)
+ int *timeout_io)
{
if (*nfds_io<1) {
*nfds_io=1;
}
static afterpoll_fn signal_afterpoll;
-static void signal_afterpoll(void *st, struct pollfd *fds, int nfds,
- const struct timeval *tv, uint64_t *now)
+static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
{
uint8_t buf[16];
struct signotify *n;
static void signal_handler(int signum)
{
+ int saved_errno;
uint8_t thing=0;
sigaddset(&pending,signum);
+ /* XXX the write() may set errno, which can make the main program fail.
+ However, signal handlers aren't allowed to modify anything which
+ is not of type sig_atomic_t. The world is broken. */
+ /* I have decided to save and restore errno anyway; on most
+ architectures on which secnet can run modifications to errno
+ will be atomic, and it seems to be the lesser of the two
+ evils. */
+ saved_errno=errno;
write(spw,&thing,1); /* We don't care if this fails (i.e. the pipe
is full) because the service routine will
spot the pending signal anyway */
+ errno=saved_errno;
}
static void register_signal_handler(struct signotify *s)