chiark / gitweb /
string_item_to_iaddr: Actually set port if !CONFIG_IPV6
[secnet.git] / process.c
index 343be9b58bc59b0eac0330cf5e168e31d7608772..f83625815456648ced0ad0a1781f2610e04a07d4 100644 (file)
--- a/process.c
+++ b/process.c
@@ -35,8 +35,6 @@ static struct signotify *sigs=NULL;
 
 static int spw,spr; /* file descriptors for signal notification pipe */
 
-static void set_default_signals(void);
-
 /* Long-lived subprocesses can only be started once we've started
    signal processing so that we can catch SIGCHLD for them and report
    their exit status using the callback function.  We block SIGCHLD
@@ -47,7 +45,7 @@ pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
     struct child *c;
     pid_t p;
 
-    c=safe_malloc(sizeof(*c),"makesubproc");
+    NEW(c);
     c->desc=desc;
     c->cb=cb;
     c->cst=cst;
@@ -58,8 +56,7 @@ pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
     p=fork();
     if (p==0) {
        /* Child process */
-       set_default_signals();
-       sigprocmask(SIG_SETMASK,&emptyset,NULL);
+       afterfork();
        entry(est);
        abort();
     } else if (p==-1) {
@@ -95,7 +92,7 @@ static void sigchld_handler(void *st, int signum)
        if (rv==i->pid) {
            i->finished=True;
            
-           nw=safe_malloc(sizeof(*nw),"sigchld_handler");
+           NEW(nw);
            nw->pid=i->pid;
            nw->cb=i->cb;
            nw->cst=i->cst;
@@ -143,17 +140,8 @@ int sys_cmd(const char *path, const char *arg, ...)
            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);
+           /* If the command failed report its exit status */
+           lg_exitstatus(0,"sys_cmd",0,M_ERR,rv,path);
        }
     } else if (c==0) {
        char *args[100];
@@ -164,6 +152,7 @@ int sys_cmd(const char *path, const char *arg, ...)
           if the execvp() fails this seems somewhat pointless, and
           increases the chance of the child process failing before it
           gets to exec(). */
+       afterfork();
        va_start(ap,arg);
        args[0]=(char *)arg; /* program name */
        i=1;
@@ -183,16 +172,15 @@ static beforepoll_fn signal_beforepoll;
 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
                             int *timeout_io)
 {
-    if (*nfds_io<1) {
-       *nfds_io=1;
-       return ERANGE;
-    }
-    *nfds_io=1;
+    BEFOREPOLL_WANT_FDS(1);
     fds[0].fd=spr;
     fds[0].events=POLLIN;
     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)
 {
@@ -201,7 +189,8 @@ static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
     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 */
@@ -223,12 +212,16 @@ static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
     }
 }
 
-static void set_default_signals(void)
+void afterfork(void)
 {
     struct signotify *n;
     sigset_t done;
     struct sigaction sa;
 
+    clear_phase_hooks(PHASE_SHUTDOWN);
+    /* Prevents calls to fatal() etc. in the child from running off
+       and doing a lot of unhelpful things */
+
     sigemptyset(&done);
     for (n=sigs; n; n=n->next)
        if (!sigismember(&done,n->signum)) {
@@ -238,6 +231,19 @@ static void set_default_signals(void)
            sa.sa_flags=0;
            sigaction(n->signum,&sa,NULL);
        }
+
+    sigemptyset(&emptyset);
+    sigprocmask(SIG_SETMASK,&emptyset,NULL);
+}
+
+void childpersist_closefd_hook(void *fd_vp, uint32_t newphase)
+{
+    int *fd_p=fd_vp;
+    int fd=*fd_p;
+    if (fd<0) return;
+    *fd_p=-1;
+    setnonblock(fd); /* in case close() might block */
+    close(fd); /* discard errors - we don't care, in the child */
 }
 
 static void signal_handler(int signum)
@@ -253,7 +259,8 @@ static void signal_handler(int signum)
        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
+    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;
@@ -284,7 +291,7 @@ void request_signal_notification(int signum, signal_notify_fn *notify,
     struct signotify *s;
     sigset_t old;
 
-    s=safe_malloc(sizeof(*s),"request_signal_notification");
+    NEW(s);
     s->signum=signum;
     s->notify=notify;
     s->cst=cst;
@@ -305,16 +312,13 @@ 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) {
-       fatal_perror("start_signal_handling: fcntl(O_NONBLOCK)");
-    }
+    setnonblock(spw);
+    setnonblock(spr);
 
-    register_for_poll(NULL,signal_beforepoll,signal_afterpoll,1,"signal");
+    register_for_poll(NULL,signal_beforepoll,signal_afterpoll,"signal");
     signal_handling=True;
 
     /* Register signal handlers for all the signals we're interested in */