X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=process.c;h=343be9b58bc59b0eac0330cf5e168e31d7608772;hp=b40801b17a593fc5ce5875687c64220af6eab0b9;hb=45cfab8ca7db61ce4677e2e77e76b9266c57ab12;hpb=7138d0c54cd2212439434d27cb2d6ea775c3039b diff --git a/process.c b/process.c index b40801b..343be9b 100644 --- a/process.c +++ b/process.c @@ -1,8 +1,10 @@ +#define _GNU_SOURCE #include "secnet.h" #include #include #include #include +#include #include "process.h" /* Process handling - subprocesses, signals, etc. */ @@ -13,7 +15,7 @@ static sigset_t registered,pending; struct child { pid_t pid; - string_t desc; + cstring_t desc; process_callback_fn *cb; void *cst; bool_t finished; @@ -39,11 +41,10 @@ static void set_default_signals(void); 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"); @@ -52,9 +53,7 @@ extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb, 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) { @@ -70,6 +69,7 @@ extern void makesubproc(process_entry_fn *entry, process_callback_fn *cb, c->finished=False; c->next=children; children=c; + return p; } static signal_notify_fn sigchld_handler; @@ -125,39 +125,63 @@ static void sigchld_handler(void *st, int signum) } } -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; @@ -170,8 +194,7 @@ static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io, } 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; @@ -219,11 +242,21 @@ static void set_default_signals(void) 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)