Example #1
0
/* Generate children*/
static void fork_children(void)
{
	while (shm->running_childs < max_children) {
		int childno;
		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 child it's replacing.
		 * (special case startup, or we reseed unnecessarily)
		 */
		if (shm->ready == TRUE)
			reseed();

		/* Find a space for it in the pid map */
		childno = find_childno(EMPTY_PIDSLOT);
		if (childno == CHILD_NOT_FOUND) {
			outputerr("## Pid map was full!\n");
			dump_childnos();
			exit_main_fail();
		}

		fflush(stdout);
		pid = fork();

		if (pid == 0) {
			/* Child process. */
			init_child(childno);
			child_process();
			debugf("child %d %d exiting.\n", childno, getpid());
			close_logfile(&this_child->logfile);
			_exit(EXIT_SUCCESS);
		} else {
			if (pid == -1) {
				/* We failed, wait for a child to exit before retrying. */
				if (shm->running_childs > 0)
					return;

				output(0, "couldn't create child! (%s)\n", strerror(errno));
				panic(EXIT_FORK_FAILURE);
				exit_main_fail();
			}
		}

		shm->children[childno]->pid = pid;
		shm->running_childs++;

		debugf("Created child %d (pid:%d) [total:%d/%d]\n",
			childno, pid, shm->running_childs, max_children);

		if (shm->exit_reason != STILL_RUNNING)
			return;

	}
	shm->ready = TRUE;

	debugf("created enough children\n");
}
Example #2
0
File: main.c Project: guwu/trinity
/*
 * reap_child: Remove all references to a running child.
 *
 * This can get called from three possible places.
 * 1. A child calls this itself just before it exits to clear out
 *    its child struct in the shm.
 * 2. From the watchdog if it finds reference to a pid that no longer exists.
 * 3. From the main pid if it gets a SIGBUS or SIGSTOP from the child.
 *
 * The reaper lock protects against these happening at the same time.
 */
void reap_child(pid_t childpid)
{
	struct childdata *child;
	int i;

	lock(&shm->reaper_lock);

	if (childpid == shm->last_reaped) {
		debugf("already reaped %d!\n", childpid);
		goto out;
	}

	i = find_childno(childpid);
	if (i == CHILD_NOT_FOUND)
		goto out;

	debugf("Removing pid %d from pidmap.\n", childpid);
	child = shm->children[i];
	child->pid = EMPTY_PIDSLOT;
	child->syscall.tv.tv_sec = 0;
	shm->running_childs--;
	shm->last_reaped = childpid;

out:
	unlock(&shm->reaper_lock);
}
Example #3
0
/*
 * level defines whether it gets displayed to the screen with printf.
 * (it always logs).
 *   0 = everything, even all the registers
 *   1 = prints syscall count
 *   2 = Just the reseed values
 *
 */
void output(unsigned char level, const char *fmt, ...)
{
	va_list args;
	int n;
	FILE *handle;
	pid_t pid;
	char outputbuf[BUFSIZE];
	char *prefix = NULL;
	char main_prefix[]="[main]";
	char child_prefix[32];

	if (logging == LOGGING_DISABLED && level >= quiet_level)
		return;

	/* prefix preparation */
	pid = getpid();

	if (pid == mainpid)
		prefix = main_prefix;
	else if (prefix == NULL) {
		unsigned int childno;

		childno = find_childno(pid);
		snprintf(child_prefix, sizeof(child_prefix), "[child%u:%u]", childno, pid);
		prefix = child_prefix;
		shm->children[childno]->logdirty = TRUE;
	}

	/* 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 == LOGGING_FILES)
		return;

	handle = find_logfile_handle();
	if (!handle)
		return;

	strip_ansi(outputbuf);

	fprintf(handle, "%s %s", prefix, outputbuf);

	(void)fflush(handle);
}
Example #4
0
static FILE * find_child_logfile_handle(pid_t pid)
{
	int i;
	unsigned int j;
	FILE *log = NULL;

	i = find_childno(pid);
	if (i != CHILD_NOT_FOUND) {
		log = shm->children[i]->logfile;
	} else {
		/* This is pretty ugly, and should never happen,
		 * but try again a second later, in case we're racing setup/teardown.
		 * FIXME: We may not even need this now that we have proper locking; test it.
		 */
		sleep(1);
		i = find_childno(pid);
		if (i == CHILD_NOT_FOUND) {
			outputerr("Couldn't find child for pid %d\n", pid);
			return mainlogfile;
		}
		log = shm->children[i]->logfile;

	}

	if (log != NULL)
		return log;

	/* if the logfile hadn't been set, log to main. */
	shm->children[i]->logfile = mainlogfile;
	outputerr("## child %d logfile handle was null logging to main!\n", i);

	outputerr("## Couldn't find logfile for pid %d\n", pid);
	dump_childnos();
	outputerr("## Logfiles for pids: ");
	for_each_child(j)
		outputerr("%p ", shm->children[j]->logfile);
	outputerr("\n");

	(void)fflush(stdout);

	sleep(5);
	return mainlogfile;
}
Example #5
0
void kill_pid(pid_t pid)
{
	int ret;
	int childno;

	childno = find_childno(pid);
	if (childno != CHILD_NOT_FOUND) {
		if (shm->children[childno]->dontkillme == TRUE)
			return;
	}

	ret = kill(pid, SIGKILL);
	if (ret != 0)
		debugf("couldn't kill pid %d [%s]\n", pid, strerror(errno));
}
Example #6
0
static FILE * find_logfile_handle(void)
{
	pid_t pid;
	int i;

	pid = getpid();
	if (pid == initpid)
		return mainlogfile;

	if (pid == shm->mainpid)
		return mainlogfile;

	if (pid == watchdog_pid)
		return mainlogfile;

	i = find_childno(pid);
	if (i != CHILD_NOT_FOUND)
		return shm->children[i]->logfile;
	else {
		/* try one more time. FIXME: This is awful. */
		unsigned int j;

		sleep(1);
		i = find_childno(pid);
		if (i != CHILD_NOT_FOUND)
			return shm->children[i]->logfile;

		outputerr("## Couldn't find logfile for pid %d\n", pid);
		dump_childnos();
		outputerr("## Logfiles for pids: ");
		for_each_child(j)
			outputerr("%p ", shm->children[j]->logfile);
		outputerr("\n");
	}
	return NULL;
}
Example #7
0
static void sighandler(int sig)
{
	int childno;

	sigwas = sig;

	switch (sig) {
	case SIGALRM:
		childno = find_childno(getpid());
		if (childno == CHILD_NOT_FOUND)
			_exit(EXIT_SUCCESS);	/* Hell knows what happened, just bail. */

		/* Re-arm the alarm. */
		alarm(1);

		/* Jump back, maybe we'll make progress. */
		(void)signal(sig, sighandler);
		siglongjmp(ret_jump, 1);
		break;

	default:
		_exit(EXIT_SUCCESS);
	}
}
Example #8
0
File: main.c Project: guwu/trinity
static void handle_child(pid_t childpid, int childstatus)
{
	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) {
			unsigned int i;
			bool seen = FALSE;

			debugf("All children exited!\n");

			for_each_child(i) {
				struct childdata *child;

				child = shm->children[i];

				if (child->pid != EMPTY_PIDSLOT) {
					if (pid_alive(child->pid) == -1) {
						debugf("Removing %d from pidmap\n", child->pid);
						child->pid = EMPTY_PIDSLOT;
						shm->running_childs--;
					} else {
						debugf("%d looks still alive! ignoring.\n", child->pid);
					}
					seen = TRUE;
				}
			}
			if (seen == FALSE)
				shm->running_childs = 0;
			break;
		}
		output(0, "error! (%s)\n", strerror(errno));
		break;

	default:
		debugf("Something happened to pid %d\n", childpid);

		if (WIFEXITED(childstatus)) {

			int childno;

			childno = find_childno(childpid);
			if (childno != CHILD_NOT_FOUND) {
				debugf("Child %d exited after %ld operations.\n",
					childpid, shm->children[childno]->syscall.op_nr);
				reap_child(childpid);
			}
			break;

		} else if (WIFSIGNALED(childstatus)) {
			handle_childsig(childpid, childstatus, FALSE);
		} else if (WIFSTOPPED(childstatus)) {
			handle_childsig(childpid, childstatus, TRUE);
		} else if (WIFCONTINUED(childstatus)) {
			break;
		} else {
			output(0, "erk, wtf\n");
		}
	}