Exemple #1
0
static int do_start(void *arg)
{
	struct start_arg *start_arg = arg;
	char **args = *start_arg->args;
	int flags = *start_arg->flags;
	uid_t uid = *start_arg->uid;
	int want_default_mounts = start_arg->want_default_mounts;
	const char *want_hostname = start_arg->want_hostname;

	if ((flags & CLONE_NEWNS) && want_default_mounts)
		lxc_setup_fs();

	if ((flags & CLONE_NEWUTS) && want_hostname)
		if (sethostname(want_hostname, strlen(want_hostname)) < 0) {
			ERROR("failed to set hostname %s: %s", want_hostname, strerror(errno));
			exit(1);
		}

	// Setuid is useful even without a new user id space
	if (start_arg->setuid && setuid(uid)) {
		ERROR("failed to set uid %d: %s", uid, strerror(errno));
		exit(1);
	}

	execvp(args[0], args);

	ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
	return 1;
}
Exemple #2
0
int main(int argc, char *argv[])
{
	pid_t pid;
	int err;
	char **aargv;
	sigset_t mask, omask;
	int i, have_status = 0, shutdown = 0;
	int opt;
	char *lxcpath = NULL, *name = NULL, *logpriority = NULL;

	while ((opt = getopt_long(argc, argv, "n:l:qP:", options, NULL)) != -1) {
		switch(opt) {
		case 'n':
			name = optarg;
			break;
		case 'l':
			logpriority = optarg;
			break;
		case 'q':
			quiet = 1;
 			break;
		case 'P':
			lxcpath = optarg;
			break;
		default: /* '?' */
			usage();
			exit(EXIT_FAILURE);
		}
	}

	if (lxc_caps_init())
		exit(EXIT_FAILURE);

	err = lxc_log_init(name, name ? NULL : "none", logpriority,
			   basename(argv[0]), quiet, lxcpath);
	if (err < 0)
		exit(EXIT_FAILURE);
	lxc_log_options_no_override();

	if (!argv[optind]) {
		ERROR("missing command to launch");
		exit(EXIT_FAILURE);
	}

	aargv = &argv[optind];

        /*
	 * mask all the signals so we are safe to install a
	 * signal handler and to fork
	 */
	if (sigfillset(&mask) ||
	    sigdelset(&mask, SIGILL) ||
	    sigdelset(&mask, SIGSEGV) ||
	    sigdelset(&mask, SIGBUS) ||
	    sigprocmask(SIG_SETMASK, &mask, &omask)) {
		SYSERROR("failed to set signal mask");
		exit(EXIT_FAILURE);
	}

	for (i = 1; i < NSIG; i++) {
		struct sigaction act;

		/* Exclude some signals: ILL, SEGV and BUS are likely to
		 * reveal a bug and we want a core. STOP and KILL cannot be
		 * handled anyway: they're here for documentation.
		 */
		if (i == SIGILL ||
		    i == SIGSEGV ||
		    i == SIGBUS ||
		    i == SIGSTOP ||
		    i == SIGKILL ||
		    i == 32 || i == 33)
			continue;

		if (sigfillset(&act.sa_mask) ||
		    sigdelset(&act.sa_mask, SIGILL) ||
		    sigdelset(&act.sa_mask, SIGSEGV) ||
		    sigdelset(&act.sa_mask, SIGBUS) ||
		    sigdelset(&act.sa_mask, SIGSTOP) ||
		    sigdelset(&act.sa_mask, SIGKILL)) {
			ERROR("failed to set signal");
			exit(EXIT_FAILURE);
		}

		act.sa_flags = 0;
		act.sa_handler = interrupt_handler;
		if (sigaction(i, &act, NULL) && errno != EINVAL) {
			SYSERROR("failed to sigaction");
			exit(EXIT_FAILURE);
		}
	}

	lxc_setup_fs();

	if (lxc_caps_reset())
		exit(EXIT_FAILURE);

	pid = fork();

	if (pid < 0)
		exit(EXIT_FAILURE);

	if (!pid) {

		/* restore default signal handlers */
		for (i = 1; i < NSIG; i++)
			signal(i, SIG_DFL);

		if (sigprocmask(SIG_SETMASK, &omask, NULL)) {
			SYSERROR("failed to set signal mask");
			exit(EXIT_FAILURE);
		}

		NOTICE("about to exec '%s'", aargv[0]);

		execvp(aargv[0], aargv);
		ERROR("failed to exec: '%s' : %m", aargv[0]);
		exit(err);
	}

	/* let's process the signals now */
	if (sigdelset(&omask, SIGALRM) ||
	    sigprocmask(SIG_SETMASK, &omask, NULL)) {
		SYSERROR("failed to set signal mask");
		exit(EXIT_FAILURE);
	}

	/* no need of other inherited fds but stderr */
	close(fileno(stdin));
	close(fileno(stdout));

	err = EXIT_SUCCESS;
	for (;;) {
		int status;
		pid_t waited_pid;

		switch (was_interrupted) {

		case 0:
			break;

		case SIGTERM:
			if (!shutdown) {
				shutdown = 1;
				kill(-1, SIGTERM);
				alarm(1);
			}
			break;

		case SIGALRM:
			kill(-1, SIGKILL);
			break;

		default:
			kill(pid, was_interrupted);
			break;
		}

		was_interrupted = 0;
		waited_pid = wait(&status);
		if (waited_pid < 0) {
			if (errno == ECHILD)
				goto out;
			if (errno == EINTR)
				continue;

			ERROR("failed to wait child : %s",
			      strerror(errno));
			goto out;
		}

		/* reset timer each time a process exited */
		if (shutdown)
			alarm(1);

		/*
		 * keep the exit code of started application
		 * (not wrapped pid) and continue to wait for
		 * the end of the orphan group.
		 */
		if (waited_pid == pid && !have_status) {
			err = lxc_error_set_and_log(waited_pid, status);
			have_status = 1;
		}
	}
out:
	return err;
}