-/* $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>
{
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:
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;