clean up after the traphandler children, otherwise they will live on
authorbenno <benno@openbsd.org>
Fri, 23 May 2014 18:37:20 +0000 (18:37 +0000)
committerbenno <benno@openbsd.org>
Fri, 23 May 2014 18:37:20 +0000 (18:37 +0000)
as zombies. ok blambert

usr.sbin/snmpd/snmpd.c

index b59733c..37c5290 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: snmpd.c,v 1.22 2014/04/28 08:25:05 blambert Exp $     */
+/*     $OpenBSD: snmpd.c,v 1.23 2014/05/23 18:37:20 benno Exp $        */
 
 /*
  * Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -61,7 +61,9 @@ snmpd_sig_handler(int sig, short event, void *arg)
 {
        struct privsep  *ps = arg;
        struct snmpd    *env = ps->ps_env;
-       int              die = 0, id;
+       int              die = 0, status, fail, id;
+       pid_t           pid;
+       char            *cause;
 
        switch (sig) {
        case SIGTERM:
@@ -69,11 +71,39 @@ snmpd_sig_handler(int sig, short event, void *arg)
                die = 1;
                /* FALLTHROUGH */
        case SIGCHLD:
-               for (id = 0; id < PROC_MAX; id++) {
-                       if (check_child(ps->ps_pid[id],
-                           ps->ps_title[id]))
-                               die  = 1;
-               }
+               do {
+                       pid = waitpid(WAIT_ANY, &status, WNOHANG);
+                       if (pid <= 0)
+                               continue;
+
+                       fail = 0;
+                       if (WIFSIGNALED(status)) {
+                               fail = 1;
+                               asprintf(&cause, "terminated; signal %d",
+                                   WTERMSIG(status));
+                       } else if (WIFEXITED(status)) {
+                               if (WEXITSTATUS(status) != 0) {
+                                       fail = 1;
+                                       asprintf(&cause, "exited abnormally");
+                               } else
+                                       asprintf(&cause, "exited okay");
+                       } else
+                               fatalx("unexpected cause of SIGCHLD");
+                       
+                       for (id = 0; id < PROC_MAX; id++) {
+                               if (pid == ps->ps_pid[id] &&
+                                   check_child(ps->ps_pid[id],
+                                   ps->ps_title[id])) {
+                                       die  = 1;
+                                       if (fail)
+                                               log_warnx("lost child: %s %s",
+                                                   ps->ps_title[id], cause);
+                                       break;
+                               }
+                       }
+                       free(cause);
+               } while (pid > 0 || (pid == -1 && errno == EINTR));
+
                if (die)
                        snmpd_shutdown(env);
                break;