static FILE * find_logfile_handle(void) { pid_t pid; int i; unsigned int j; pid = getpid(); if (pid == initpid) return mainlogfile; if (pid == shm->mainpid) return mainlogfile; if (pid == watchdog_pid) return mainlogfile; i = find_pid_slot(pid); if (i != PIDSLOT_NOT_FOUND) return shm->logfiles[i]; else { /* try one more time. FIXME: This is awful. */ sleep(1); i = find_pid_slot(pid); if (i != PIDSLOT_NOT_FOUND) return shm->logfiles[i]; outputerr("## Couldn't find logfile for pid %d\n", pid); dump_pid_slots(); outputerr("## Logfiles for pids: "); for_each_pidslot(j) outputerr("%p ", shm->logfiles[j]); outputerr("\n"); } return NULL; }
void reap_child(pid_t childpid) { int i; while (shm->reaper_lock == LOCKED); shm->reaper_lock = LOCKED; if (childpid == shm->last_reaped) { debugf("already reaped %d!\n", childpid); goto out; } i = find_pid_slot(childpid); if (i == PIDSLOT_NOT_FOUND) goto out; debugf("Removing pid %d from pidmap.\n", childpid); shm->pids[i] = EMPTY_PIDSLOT; shm->running_childs--; shm->tv[i].tv_sec = 0; shm->last_reaped = childpid; out: shm->reaper_lock = UNLOCKED; }
static void fork_children(void) { int pidslot; static char childname[17]; /* Generate children*/ while (shm->running_childs < shm->max_children) { int pid = 0; int fd; if (shm->spawn_no_more == TRUE) return; /* a new child means a new seed, or the new child * will do the same syscalls as the one in the pidslot it's replacing. * (special case startup, or we reseed unnecessarily) */ if (shm->ready == TRUE) reseed(); /* Find a space for it in the pid map */ pidslot = find_pid_slot(EMPTY_PIDSLOT); if (pidslot == PIDSLOT_NOT_FOUND) { outputerr("## Pid map was full!\n"); dump_pid_slots(); exit(EXIT_FAILURE); } if (logging == TRUE) { fd = fileno(shm->logfiles[pidslot]); if (ftruncate(fd, 0) == 0) lseek(fd, 0, SEEK_SET); } (void)alarm(0); fflush(stdout); pid = fork(); if (pid != 0) shm->pids[pidslot] = pid; else { /* Child process. */ int ret = 0; mask_signals_child(); memset(childname, 0, sizeof(childname)); sprintf(childname, "trinity-child%d", pidslot); prctl(PR_SET_NAME, (unsigned long) &childname); oom_score_adj(500); /* Wait for parent to set our pidslot */ while (shm->pids[pidslot] != getpid()) { /* Make sure parent is actually alive to wait for us. */ ret = pid_alive(shm->mainpid); if (ret != 0) { shm->exit_reason = EXIT_SHM_CORRUPTION; outputerr(BUGTXT "parent (%d) went away!\n", shm->mainpid); sleep(20000); } } /* Wait for all the children to start up. */ while (shm->ready == FALSE) sleep(1); init_child(pidslot); ret = child_process(pidslot); output(1, "child exiting.\n"); _exit(ret); } shm->running_childs++; debugf("Created child %d in pidslot %d [total:%d/%d]\n", shm->pids[pidslot], pidslot, shm->running_childs, shm->max_children); if (shm->exit_reason != STILL_RUNNING) return; } shm->ready = TRUE; debugf("created enough children\n"); }
static void handle_child(pid_t childpid, int childstatus) { unsigned int i; int slot; switch (childpid) { case 0: //debugf("Nothing changed. children:%d\n", shm->running_childs); break; case -1: if (shm->exit_reason != STILL_RUNNING) return; if (errno == ECHILD) { debugf("All children exited!\n"); for_each_pidslot(i) { if (shm->pids[i] != EMPTY_PIDSLOT) { if (pid_alive(shm->pids[i]) == -1) { debugf("Removing %d from pidmap\n", shm->pids[i]); shm->pids[i] = EMPTY_PIDSLOT; shm->running_childs--; } else { debugf("%d looks still alive! ignoring.\n", shm->pids[i]); } } } break; } output(0, "error! (%s)\n", strerror(errno)); break; default: debugf("Something happened to pid %d\n", childpid); if (WIFEXITED(childstatus)) { slot = find_pid_slot(childpid); if (slot == PIDSLOT_NOT_FOUND) { /* If we reaped it, it wouldn't show up, so check that. */ if (shm->last_reaped != childpid) { outputerr("## Couldn't find pid slot for %d\n", childpid); shm->exit_reason = EXIT_LOST_PID_SLOT; dump_pid_slots(); } } else { debugf("Child %d exited after %ld syscalls.\n", childpid, shm->child_syscall_count[slot]); reap_child(childpid); } break; } else if (WIFSIGNALED(childstatus)) { switch (WTERMSIG(childstatus)) { case SIGALRM: debugf("got a alarm signal from pid %d\n", childpid); break; case SIGFPE: case SIGSEGV: case SIGKILL: case SIGPIPE: case SIGABRT: debugf("got a signal from pid %d (%s)\n", childpid, strsignal(WTERMSIG(childstatus))); reap_child(childpid); break; default: debugf("** Child got an unhandled signal (%d)\n", WTERMSIG(childstatus)); break; } break; } else if (WIFSTOPPED(childstatus)) { switch (WSTOPSIG(childstatus)) { case SIGALRM: debugf("got an alarm signal from pid %d\n", childpid); break; case SIGSTOP: debugf("Sending PTRACE_DETACH (and then KILL)\n"); ptrace(PTRACE_DETACH, childpid, NULL, NULL); kill(childpid, SIGKILL); reap_child(childpid); break; case SIGFPE: case SIGSEGV: case SIGKILL: case SIGPIPE: case SIGABRT: debugf("Child %d was stopped by %s\n", childpid, strsignal(WTERMSIG(childstatus))); reap_child(childpid); break; default: debugf("Child %d was stopped by unhandled signal (%s).\n", childpid, strsignal(WSTOPSIG(childstatus))); break; } break; } else if (WIFCONTINUED(childstatus)) { break; } else { output(0, "erk, wtf\n"); } }
/* Generate children*/ static void fork_children(void) { while (shm->running_childs < max_children) { int pidslot; int pid = 0; if (shm->spawn_no_more == TRUE) return; /* a new child means a new seed, or the new child * will do the same syscalls as the one in the pidslot it's replacing. * (special case startup, or we reseed unnecessarily) */ if (shm->ready == TRUE) reseed(); /* Find a space for it in the pid map */ pidslot = find_pid_slot(EMPTY_PIDSLOT); if (pidslot == PIDSLOT_NOT_FOUND) { outputerr("## Pid map was full!\n"); dump_pid_slots(); exit(EXIT_FAILURE); } if (logging == TRUE) { int fd; fd = fileno(shm->logfiles[pidslot]); if (ftruncate(fd, 0) == 0) lseek(fd, 0, SEEK_SET); } (void)alarm(0); fflush(stdout); pid = fork(); if (pid == 0) { /* Child process. */ init_child(pidslot); child_process(pidslot); debugf("child %d exiting.\n", pidslot); _exit(EXIT_SUCCESS); } else { if (pid == -1) { output(0, "couldn't create child! (%s)\n", strerror(errno)); shm->exit_reason = EXIT_FORK_FAILURE; exit(EXIT_FAILURE); } } shm->pids[pidslot] = pid; shm->running_childs++; debugf("Created child %d in pidslot %d [total:%d/%d]\n", shm->pids[pidslot], pidslot, shm->running_childs, max_children); if (shm->exit_reason != STILL_RUNNING) return; } shm->ready = TRUE; debugf("created enough children\n"); }
/* * level defines whether it gets displayed to the screen with printf. * (it always logs). * 0 = everything, even all the registers * 1 = Watchdog prints syscall count * 2 = Just the reseed values * */ void output(unsigned char level, const char *fmt, ...) { va_list args; int n; FILE *handle; unsigned int len, i, j; pid_t pid; char outputbuf[BUFSIZE]; char monobuf[BUFSIZE]; char *prefix = NULL; char watchdog_prefix[]="[watchdog]"; char init_prefix[]="[init]"; char main_prefix[]="[main]"; char child_prefix[]="[childNN:1234567890]"; unsigned int slot; if (logging == FALSE && level >= quiet_level) return; /* prefix preparation */ pid = getpid(); if (pid == watchdog_pid) prefix = watchdog_prefix; if (pid == initpid) prefix = init_prefix; if (pid == shm->mainpid) prefix = main_prefix; if (prefix == NULL) { slot = find_pid_slot(pid); sprintf(child_prefix, "[child%d:%d]", slot, pid); prefix = child_prefix; } /* formatting output */ va_start(args, fmt); n = vsnprintf(outputbuf, sizeof(outputbuf), fmt, args); va_end(args); if (n < 0) { outputerr("## Something went wrong in output() [%d]\n", n); exit(EXIT_FAILURE); } /* stdout output if needed */ if (quiet_level > level) { printf("%s %s", prefix, outputbuf); (void)fflush(stdout); } /* go on with file logs only if enabled */ if (logging == FALSE) return; handle = robust_find_logfile_handle(); if (!handle) return; /* If we've specified monochrome, we can just dump the buffer into * the logfile as is, because there shouldn't be any ANSI codes * in the buffer to be stripped out. */ if (monochrome == FALSE) { /* copy buffer, sans ANSI codes */ len = strlen(outputbuf); for (i = 0, j = 0; (i < len) && (i + 2 < BUFSIZE) && (j < BUFSIZE); i++) { if (outputbuf[i] == '') { if (outputbuf[i + 2] == '1') i += 6; // ANSI_COLOUR else i += 3; // ANSI_RESET } else { monobuf[j] = outputbuf[i]; j++; } } monobuf[j] = '\0'; fprintf(handle, "%s %s", prefix, monobuf); } else { fprintf(handle, "%s %s", prefix, outputbuf); } (void)fflush(handle); }
static void fork_children(void) { int pidslot; static char childname[17]; /* Generate children*/ while (shm->running_childs < shm->max_children) { int pid = 0; /* Find a space for it in the pid map */ pidslot = find_pid_slot(EMPTY_PIDSLOT); if (pidslot == PIDSLOT_NOT_FOUND) { printf("[%d] ## Pid map was full!\n", getpid()); dump_pid_slots(); exit(EXIT_FAILURE); } (void)alarm(0); fflush(stdout); pid = fork(); if (pid != 0) shm->pids[pidslot] = pid; else { /* Child process. */ int ret = 0; mask_signals_child(); memset(childname, 0, sizeof(childname)); sprintf(childname, "trinity-child%d", pidslot); prctl(PR_SET_NAME, (unsigned long) &childname); oom_score_adj(500); /* Wait for parent to set our pidslot */ while (shm->pids[pidslot] != getpid()) { /* Make sure parent is actually alive to wait for us. */ ret = pid_alive(shm->parentpid); if (ret != 0) { shm->exit_reason = EXIT_SHM_CORRUPTION; printf("[%d] " BUGTXT "parent (%d) went away!\n", getpid(), shm->parentpid); sleep(20000); } } init_child(pidslot); ret = child_process(pidslot); output(1, "child %d exiting\n", getpid()); _exit(ret); } shm->running_childs++; debugf("[%d] Created child %d in pidslot %d [total:%d/%d]\n", getpid(), shm->pids[pidslot], pidslot, shm->running_childs, shm->max_children); if (shm->exit_reason != STILL_RUNNING) return; } debugf("[%d] created enough children\n", getpid()); }