int VSUB_run(struct vsb *sb, vsub_func_f *func, void *priv, const char *name, int maxlines) { int rv, p[2], sfd, status; pid_t pid; struct vlu *vlu; struct vsub_priv sp; sp.sb = sb; sp.name = name; sp.lines = 0; sp.maxlines = maxlines; if (pipe(p) < 0) { VSB_printf(sb, "Starting %s: pipe() failed: %s", name, strerror(errno)); return (-1); } assert(p[0] > STDERR_FILENO); assert(p[1] > STDERR_FILENO); if ((pid = fork()) < 0) { VSB_printf(sb, "Starting %s: fork() failed: %s", name, strerror(errno)); AZ(close(p[0])); AZ(close(p[1])); return (-1); } if (pid == 0) { AZ(close(STDIN_FILENO)); assert(open("/dev/null", O_RDONLY) == STDIN_FILENO); assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO); assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO); /* Close all other fds */ for (sfd = STDERR_FILENO + 1; sfd < 100; sfd++) (void)close(sfd); func(priv); _exit(1); } AZ(close(p[1])); vlu = VLU_New(&sp, vsub_vlu, 0); while (!VLU_Fd(p[0], vlu)) continue; AZ(close(p[0])); VLU_Destroy(vlu); if (sp.maxlines >= 0 && sp.lines > sp.maxlines) VSB_printf(sb, "[%d lines truncated]\n", sp.lines - sp.maxlines); do { rv = waitpid(pid, &status, 0); if (rv < 0 && errno != EINTR) { VSB_printf(sb, "Running %s: waitpid() failed: %s\n", name, strerror(errno)); return (-1); } } while (rv < 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { VSB_printf(sb, "Running %s failed", name); if (WIFEXITED(status)) VSB_printf(sb, ", exit %d", WEXITSTATUS(status)); if (WIFSIGNALED(status)) VSB_printf(sb, ", signal %d", WTERMSIG(status)); if (WCOREDUMP(status)) VSB_printf(sb, ", core dumped"); VSB_printf(sb, "\n"); return (-1); } return (0); }
static void mgt_reap_child(void) { int i; int status = 0xffff; struct vsb *vsb; pid_t r = 0; assert(child_pid != -1); /* * Close the CLI connections * This signals orderly shut down to child */ mgt_cli_stop_child(); if (child_cli_out >= 0) closex(&child_cli_out); if (child_cli_in >= 0) closex(&child_cli_in); /* Stop the poker */ if (ev_poker != NULL) { vev_del(mgt_evb, ev_poker); free(ev_poker); } ev_poker = NULL; /* Stop the listener */ if (ev_listen != NULL) { vev_del(mgt_evb, ev_listen); free(ev_listen); ev_listen = NULL; } /* Compose obituary */ vsb = VSB_new_auto(); XXXAN(vsb); /* Wait for child to die */ for (i = 0; i < mgt_param.cli_timeout; i++) { r = waitpid(child_pid, &status, WNOHANG); if (r == child_pid) break; (void)sleep(1); } if (r == 0) { VSB_printf(vsb, "Child (%jd) not dying, killing", (intmax_t)r); /* Kick it Jim... */ if (MGT_FEATURE(FEATURE_NO_COREDUMP)) (void)kill(child_pid, SIGKILL); else (void)kill(child_pid, SIGQUIT); r = waitpid(child_pid, &status, 0); } if (r != child_pid) fprintf(stderr, "WAIT 0x%jx\n", (uintmax_t)r); assert(r == child_pid); MAC_reopen_sockets(NULL); VSB_printf(vsb, "Child (%jd) %s", (intmax_t)r, status ? "died" : "ended"); if (WIFEXITED(status) && WEXITSTATUS(status)) { VSB_printf(vsb, " status=%d", WEXITSTATUS(status)); exit_status |= 0x20; if (WEXITSTATUS(status) == 1) VSC_C_mgt->child_exit = ++static_VSC_C_mgt.child_exit; else VSC_C_mgt->child_stop = ++static_VSC_C_mgt.child_stop; } if (WIFSIGNALED(status)) { VSB_printf(vsb, " signal=%d", WTERMSIG(status)); exit_status |= 0x40; VSC_C_mgt->child_died = ++static_VSC_C_mgt.child_died; } #ifdef WCOREDUMP if (WCOREDUMP(status)) { VSB_printf(vsb, " (core dumped)"); exit_status |= 0x80; VSC_C_mgt->child_dump = ++static_VSC_C_mgt.child_dump; } #endif AZ(VSB_finish(vsb)); MGT_complain(status ? C_ERR : C_INFO, "%s", VSB_data(vsb)); VSB_delete(vsb); /* Dispose of shared memory but evacuate panic messages first */ if (heritage.panic_str[0] != '\0') { mgt_panic_record(r); mgt_SHM_Destroy(1); VSC_C_mgt->child_panic = ++static_VSC_C_mgt.child_panic; } else { mgt_SHM_Destroy(MGT_DO_DEBUG(DBG_VSM_KEEP)); } mgt_SHM_Create(); mgt_SHM_Commit(); if (child_state == CH_RUNNING) child_state = CH_DIED; /* Pick up any stuff lingering on stdout/stderr */ (void)child_listener(NULL, EV_RD); closex(&child_output); VLU_Destroy(child_std_vlu); child_pid = -1; MGT_complain(C_DEBUG, "Child cleanup complete"); if (child_state == CH_DIED && mgt_param.auto_restart) mgt_launch_child(NULL); else if (child_state == CH_DIED) child_state = CH_STOPPED; else if (child_state == CH_STOPPING) child_state = CH_STOPPED; }