int main(int argc, char *argv[]) { int ret; pid_t pid; lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; lxc_attach_command_t command; ret = lxc_caps_init(); if (ret) return ret; ret = lxc_arguments_parse(&my_args, argc, argv); if (ret) return ret; if (!my_args.log_file) my_args.log_file = "none"; ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority, my_args.progname, my_args.quiet, my_args.lxcpath[0]); if (ret) return ret; lxc_log_options_no_override(); if (remount_sys_proc) attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; if (elevated_privileges) attach_options.attach_flags &= ~(elevated_privileges); attach_options.namespaces = namespace_flags; attach_options.personality = new_personality; attach_options.env_policy = env_policy; attach_options.extra_env_vars = extra_env; attach_options.extra_keep_env = extra_keep; if (my_args.argc) { command.program = my_args.argv[0]; command.argv = (char**)my_args.argv; ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_command, &command, &attach_options, &pid); } else { ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_shell, NULL, &attach_options, &pid); } if (ret < 0) return -1; ret = lxc_wait_for_pid_status(pid); if (ret < 0) return -1; if (WIFEXITED(ret)) return WEXITSTATUS(ret); return -1; }
int main(int argc, char *argv[]) { int opt, status; int ret; char *namespaces = NULL; char **args; int flags = 0; int daemonize = 0; uid_t uid = 0; /* valid only if (flags & CLONE_NEWUSER) */ pid_t pid; struct my_iflist *tmpif, *my_iflist = NULL; struct start_arg start_arg = { .args = &args, .uid = &uid, .setuid = false, .flags = &flags, .want_hostname = NULL, .want_default_mounts = 0, }; while ((opt = getopt(argc, argv, "s:u:hH:i:dM")) != -1) { switch (opt) { case 's': namespaces = optarg; break; case 'i': if (!(tmpif = malloc(sizeof(*tmpif)))) { perror("malloc"); exit(1); } tmpif->mi_ifname = optarg; tmpif->mi_next = my_iflist; my_iflist = tmpif; break; case 'd': daemonize = 1; break; case 'M': start_arg.want_default_mounts = 1; break; case 'H': start_arg.want_hostname = optarg; break; case 'h': usage(argv[0]); break; case 'u': if (!lookup_user(optarg, &uid)) return 1; start_arg.setuid = true; } } if (argv[optind] == NULL) { ERROR("a command to execute in the new namespace is required"); return 1; } args = &argv[optind]; ret = lxc_caps_init(); if (ret) return 1; ret = lxc_fill_namespace_flags(namespaces, &flags); if (ret) usage(argv[0]); if (!(flags & CLONE_NEWNET) && my_iflist) { ERROR("-i <interfacename> needs -s NETWORK option"); return 1; } if (!(flags & CLONE_NEWUTS) && start_arg.want_hostname) { ERROR("-H <hostname> needs -s UTSNAME option"); return 1; } if (!(flags & CLONE_NEWNS) && start_arg.want_default_mounts) { ERROR("-M needs -s MOUNT option"); return 1; } pid = lxc_clone(do_start, &start_arg, flags); if (pid < 0) { ERROR("failed to clone"); return 1; } if (my_iflist) { for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) { if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid) < 0) fprintf(stderr,"Could not move interface %s into container %d: %s\n", tmpif->mi_ifname, pid, strerror(errno)); } } if (daemonize) exit(0); if (waitpid(pid, &status, 0) < 0) { ERROR("failed to wait for '%d'", pid); return 1; } return lxc_error_set_and_log(pid, status); }
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; }
int main(int argc, char *argv[]) { int opt, status; int ret; char *namespaces = NULL; char **args; int flags = 0; uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */ pid_t pid; struct start_arg start_arg = { .args = &args, .uid = &uid, .flags = &flags, }; while ((opt = getopt(argc, argv, "s:u:h")) != -1) { switch (opt) { case 's': namespaces = optarg; break; case 'h': usage(argv[0]); case 'u': uid = lookup_user(optarg); if (uid == -1) return 1; } } if (argv[optind] == NULL) { ERROR("a command to execute in the new namespace is required"); return 1; } args = &argv[optind]; ret = lxc_caps_init(); if (ret) return ret; ret = lxc_fill_namespace_flags(namespaces, &flags); if (ret) usage(argv[0]); if (!(flags & CLONE_NEWUSER) && uid != -1) { ERROR("-u <uid> needs -s USER option"); return 1; } pid = lxc_clone(do_start, &start_arg, flags); if (pid < 0) { ERROR("failed to clone"); return -1; } if (waitpid(pid, &status, 0) < 0) { ERROR("failed to wait for '%d'", pid); return -1; } return lxc_error_set_and_log(pid, status); }