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; }
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; }