static void startservice(struct svdir *s)
{
	int p;
	char *run[2];

	if (s->state == S_FINISH)
		run[0] = (char*)"./finish";
	else {
		run[0] = (char*)"./run";
		custom(s, 'u');
	}
	run[1] = NULL;

	if (s->pid != 0)
		stopservice(s); /* should never happen */
	while ((p = vfork()) == -1) {
		warn_cannot("vfork, sleeping");
		sleep(5);
	}
	if (p == 0) {
		/* child */
		if (haslog) {
			/* NB: bug alert! right order is close, then dup2 */
			if (s->islog) {
				xchdir("./log");
				close(logpipe.wr);
				xdup2(logpipe.rd, 0);
			} else {
				close(logpipe.rd);
				xdup2(logpipe.wr, 1);
			}
		}
		bb_signals(0
			+ (1 << SIGCHLD)
			+ (1 << SIGTERM)
			, SIG_DFL);
		sig_unblock(SIGCHLD);
		sig_unblock(SIGTERM);
		execvp(*run, run);
		fatal2_cannot(s->islog ? "start log/" : "start ", *run);
	}
	/* parent */
	if (s->state != S_FINISH) {
		gettimeofday_ns(&s->start);
		s->state = S_RUN;
	}
	s->pid = p;
	pidchanged = 1;
	s->ctrl = C_NOOP;
	update_status(s);
}
Beispiel #2
0
static int ctrl(struct svdir *s, char c)
{
	int sig;

	switch (c) {
	case 'd': /* down */
		s->sd_want = W_DOWN;
		update_status(s);
		if (s->pid && s->state != S_FINISH)
			stopservice(s);
		break;
	case 'u': /* up */
		s->sd_want = W_UP;
		update_status(s);
		if (s->pid == 0)
			startservice(s);
		break;
	case 'x': /* exit */
		if (s->islog)
			break;
		s->sd_want = W_EXIT;
		update_status(s);
		/* FALLTHROUGH */
	case 't': /* sig term */
		if (s->pid && s->state != S_FINISH)
			stopservice(s);
		break;
	case 'k': /* sig kill */
		if (s->pid && !custom(s, c))
			kill(s->pid, SIGKILL);
		s->state = S_DOWN;
		break;
	case 'p': /* sig pause */
		if (s->pid && !custom(s, c))
			kill(s->pid, SIGSTOP);
		s->ctrl |= C_PAUSE;
		update_status(s);
		break;
	case 'c': /* sig cont */
		if (s->pid && !custom(s, c))
			kill(s->pid, SIGCONT);
		s->ctrl &= ~C_PAUSE;
		update_status(s);
		break;
	case 'o': /* once */
		s->sd_want = W_DOWN;
		update_status(s);
		if (!s->pid)
			startservice(s);
		break;
	case 'a': /* sig alarm */
		sig = SIGALRM;
		goto sendsig;
	case 'h': /* sig hup */
		sig = SIGHUP;
		goto sendsig;
	case 'i': /* sig int */
		sig = SIGINT;
		goto sendsig;
	case 'q': /* sig quit */
		sig = SIGQUIT;
		goto sendsig;
	case '1': /* sig usr1 */
		sig = SIGUSR1;
		goto sendsig;
	case '2': /* sig usr2 */
		sig = SIGUSR2;
		goto sendsig;
	}
	return 1;
 sendsig:
	if (s->pid && !custom(s, c))
		kill(s->pid, sig);
	return 1;
}
Beispiel #3
0
static void startservice(struct svdir *s)
{
	int p;
	const char *arg[4];
	char exitcode[sizeof(int)*3 + 2];

	if (s->state == S_FINISH) {
/* Two arguments are given to ./finish. The first one is ./run exit code,
 * or -1 if ./run didnt exit normally. The second one is
 * the least significant byte of the exit status as determined by waitpid;
 * for instance it is 0 if ./run exited normally, and the signal number
 * if ./run was terminated by a signal. If runsv cannot start ./run
 * for some reason, the exit code is 111 and the status is 0.
 */
		arg[0] = "./finish";
		arg[1] = "-1";
		if (WIFEXITED(s->wstat)) {
			*utoa_to_buf(WEXITSTATUS(s->wstat), exitcode, sizeof(exitcode)) = '\0';
			arg[1] = exitcode;
		}
		//arg[2] = "0";
		//if (WIFSIGNALED(s->wstat)) {
			arg[2] = utoa(WTERMSIG(s->wstat));
		//}
		arg[3] = NULL;
	} else {
		arg[0] = "./run";
		arg[1] = NULL;
		custom(s, 'u');
	}

	if (s->pid != 0)
		stopservice(s); /* should never happen */
	while ((p = vfork()) == -1) {
		warn_cannot("vfork, sleeping");
		sleep(5);
	}
	if (p == 0) {
		/* child */
		if (haslog) {
			/* NB: bug alert! right order is close, then dup2 */
			if (s->islog) {
				xchdir("./log");
				close(logpipe.wr);
				xdup2(logpipe.rd, 0);
			} else {
				close(logpipe.rd);
				xdup2(logpipe.wr, 1);
			}
		}
		/* Non-ignored signals revert to SIG_DFL on exec anyway */
		/*bb_signals(0
			+ (1 << SIGCHLD)
			+ (1 << SIGTERM)
			, SIG_DFL);*/
		sig_unblock(SIGCHLD);
		sig_unblock(SIGTERM);
		execv(arg[0], (char**) arg);
		fatal2_cannot(s->islog ? "start log/" : "start ", arg[0]);
	}
	/* parent */
	if (s->state != S_FINISH) {
		gettimeofday_ns(&s->start);
		s->state = S_RUN;
	}
	s->pid = p;
	pidchanged = 1;
	s->ctrl = C_NOOP;
	update_status(s);
}