X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=process.c;h=a9ff3d92648557d7692d9da97fe864c41227a5fe;hp=d9d01cec2c1abc090e8c4911482c071664f3d514;hb=3c35339bc4d3db033cc44558baf66c80e87fbd85;hpb=042a8da9053c205ea74ec1785c93ca4bcf4ea5e0 diff --git a/process.c b/process.c index d9d01ce..a9ff3d9 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; @@ -40,7 +42,7 @@ static void set_default_signals(void); their exit status using the callback function. We block SIGCHLD until signal processing has begun. */ pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb, - void *est, void *cst, string_t desc) + void *est, void *cst, cstring_t desc) { struct child *c; pid_t p; @@ -51,7 +53,7 @@ pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb, c->cst=cst; if (!signal_handling) { - fatal("makesubproc called before signal handling started\n"); + fatal("makesubproc called before signal handling started"); } p=fork(); if (p==0) { @@ -123,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\n", + 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; @@ -167,16 +193,19 @@ static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io, return 0; } +/* Bodge to work around Ubuntu's strict header files */ +static void discard(int anything) {} + 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; sigset_t todo,old; if (nfds && (fds->revents & POLLIN)) { - read(spr,buf,16); /* We don't actually care what we read; as + discard(read(spr,buf,16)); + /* We don't actually care what we read; as long as there was at least one byte (which there was) we'll pick up the signals in the pending set */ @@ -217,11 +246,22 @@ static void set_default_signals(void) static void signal_handler(int signum) { + int saved_errno; uint8_t thing=0; sigaddset(&pending,signum); - write(spw,&thing,1); /* We don't care if this fails (i.e. the pipe + /* 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; + discard(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)