chiark / gitweb /
autoconf: Update to autoconf 2.69
[secnet.git] / process.c
index d9d01cec2c1abc090e8c4911482c071664f3d514..64683159ccc40be20132f5bc8d40beb89ed325c1 100644 (file)
--- a/process.c
+++ b/process.c
@@ -1,8 +1,10 @@
+#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. */
@@ -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)
@@ -270,9 +310,7 @@ void start_signal_handling(void)
     sigemptyset(&registered);
     sigemptyset(&pending);
 
-    if (pipe(p)!=0) {
-       fatal_perror("start_signal_handling: pipe");
-    }
+    pipe_cloexec(p);
     spw=p[1];
     spr=p[0];
     if (fcntl(spw, F_SETFL, fcntl(spw, F_GETFL)|O_NONBLOCK)==-1) {