// callback for find_file_in_subdirs() void found_subdir_in_dir(const char *dir) { debug(D_CGROUP, "examining cgroup dir '%s'", dir); struct cgroup *cg = cgroup_find(dir); if(!cg) { if(*dir && cgroup_max_depth > 0) { int depth = 0; const char *s; for(s = dir; *s ;s++) if(unlikely(*s == '/')) depth++; if(depth > cgroup_max_depth) { info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth); return; } } debug(D_CGROUP, "will add dir '%s' as cgroup", dir); cg = cgroup_add(dir); } if(cg) cg->available = 1; }
int main(int argc, char *argv[]) { int rc, sync[2]; pid_t pid = -1; siginfo_t status; struct mount *mounts = NULL; struct netif *netifs = NULL; struct cgroup *cgroups = NULL; struct user *users = NULL; #if HAVE_LIBCAP_NG struct capability *caps = NULL; #endif char *master; _close_ int master_fd = -1; char ephemeral_dir[] = "/tmp/pflask-ephemeral-XXXXXX"; int clone_flags = CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWPID | #ifdef CLONE_NEWCGROUP CLONE_NEWCGROUP | #endif CLONE_NEWUTS; struct gengetopt_args_info args; if (cmdline_parser(argc, argv, &args) != 0) return 1; for (unsigned int i = 0; i < args.mount_given; i++) { validate_optlist("--mount", args.mount_arg[i]); mount_add_from_spec(&mounts, args.mount_arg[i]); } for (unsigned int i = 0; i < args.netif_given; i++) { clone_flags |= CLONE_NEWNET; if (args.netif_arg != NULL) { validate_optlist("--netif", args.netif_arg[i]); netif_add_from_spec(&netifs, args.netif_arg[i]); } } if (args.user_given && !args.user_map_given) { uid_t uid; gid_t gid; clone_flags |= CLONE_NEWUSER; if (user_get_uid_gid(args.user_arg, &uid, &gid)) { user_add_map(&users, 'u', uid, uid, 1); user_add_map(&users, 'g', gid, gid, 1); } } for (unsigned int i = 0; i < args.user_map_given; i++) { size_t count; uid_t id, host_id; char *start = args.user_map_arg[i], *end = NULL; validate_optlist("--user-map", args.user_map_arg[i]); clone_flags |= CLONE_NEWUSER; id = strtoul(start, &end, 10); if (*end != ':') fail_printf("Invalid value '%s' for --user-map", args.user_map_arg[i]); start = end + 1; host_id = strtoul(start, &end, 10); if (*end != ':') fail_printf("Invalid value '%s' for --user-map", args.user_map_arg[i]); start = end + 1; count = strtoul(start, &end, 10); if (*end != '\0') fail_printf("Invalid value '%s' for --user-map", args.user_map_arg[i]); user_add_map(&users, 'u', id, host_id, count); user_add_map(&users, 'g', id, host_id, count); } for (unsigned int i = 0; i < args.cgroup_given; i++) cgroup_add(&cgroups, args.cgroup_arg[i]); #if HAVE_LIBCAP_NG for (unsigned int i = 0; i < args.caps_given; i++) capability_add(&caps, args.caps_arg[i]); #endif if (args.no_userns_flag) clone_flags &= ~(CLONE_NEWUSER); if (args.no_mountns_flag) clone_flags &= ~(CLONE_NEWNS); if (args.no_netns_flag) clone_flags &= ~(CLONE_NEWNET); if (args.no_ipcns_flag) clone_flags &= ~(CLONE_NEWIPC); if (args.no_utsns_flag) clone_flags &= ~(CLONE_NEWUTS); if (args.no_pidns_flag) clone_flags &= ~(CLONE_NEWPID); if (args.attach_given) { master_fd = recv_pty(args.attach_arg); fail_if(master_fd < 0, "Invalid PID '%u'", args.attach_arg); process_pty(master_fd); return 0; } open_master_pty(&master_fd, &master); if (args.detach_flag) do_daemonize(); sync_init(sync); if (args.ephemeral_flag) { if (!mkdtemp(ephemeral_dir)) sysf_printf("mkdtemp()"); } pid = do_clone(&clone_flags); if (!pid) { closep(&master_fd); rc = prctl(PR_SET_PDEATHSIG, SIGKILL); sys_fail_if(rc < 0, "prctl(PR_SET_PDEATHSIG)"); rc = setsid(); sys_fail_if(rc < 0, "setsid()"); sync_barrier_parent(sync, SYNC_START); sync_close(sync); open_slave_pty(master); setup_user(args.user_arg); if (args.hostname_given) { rc = sethostname(args.hostname_arg, strlen(args.hostname_arg)); sys_fail_if(rc < 0, "Error setting hostname"); } setup_mount(mounts, args.chroot_arg, args.ephemeral_flag ? ephemeral_dir : NULL); if (args.chroot_given) { setup_nodes(args.chroot_arg); setup_ptmx(args.chroot_arg); setup_symlinks(args.chroot_arg); setup_console(args.chroot_arg, master); do_chroot(args.chroot_arg); } if (clone_flags & CLONE_NEWNET) config_netif(); umask(0022); #if HAVE_LIBCAP_NG setup_capabilities(caps); #endif if (args.chdir_given) { rc = chdir(args.chdir_arg); sys_fail_if(rc < 0, "Error changing cwd"); } if (args.chroot_given) { char *term = getenv("TERM"); if (!args.keepenv_flag) clearenv(); setenv("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1); setenv("USER", args.user_arg, 1); setenv("LOGNAME", args.user_arg, 1); if (term) setenv("TERM", term, 1); } for (unsigned int i = 0; i < args.setenv_given; i++) { rc = putenv(strdup(args.setenv_arg[i])); sys_fail_if(rc != 0, "Error setting environment"); } setenv("container", "pflask", 1); if (argc > optind) rc = execvpe(argv[optind], argv + optind, environ); else rc = execle("/bin/bash", "-bash", NULL, environ); sys_fail_if(rc < 0, "Error executing command"); } sync_wait_child(sync, SYNC_START); if (args.chroot_given && (clone_flags & CLONE_NEWUSER)) setup_console_owner(master, users); setup_cgroup(cgroups, pid); setup_netif(netifs, pid); #ifdef HAVE_DBUS register_machine(pid, args.chroot_given ? args.chroot_arg : ""); #endif if (clone_flags & CLONE_NEWUSER) setup_user_map(users, pid); sync_wake_child(sync, SYNC_DONE); sync_close(sync); if (args.detach_flag) serve_pty(master_fd); else process_pty(master_fd); kill(pid, SIGKILL); rc = waitid(P_PID, pid, &status, WEXITED); sys_fail_if(rc < 0, "Error waiting for child"); switch (status.si_code) { case CLD_EXITED: if (status.si_status != 0) err_printf("Child failed with code '%d'", status.si_status); else ok_printf("Child exited"); break; case CLD_KILLED: err_printf("Child was terminated by signal '%d'", status.si_status); break; default: err_printf("Child failed"); break; } sync_close(sync); clean_cgroup(cgroups); if (args.ephemeral_flag) { rc = rmdir(ephemeral_dir); sys_fail_if(rc != 0, "Error deleting ephemeral directory: %s", ephemeral_dir); } cmdline_parser_free(&args); return status.si_status; }