static void *cgm_init(const char *name) { struct cgm_data *d; d = malloc(sizeof(*d)); if (!d) return NULL; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); goto err1; } memset(d, 0, sizeof(*d)); d->name = strdup(name); if (!d->name) { cgm_dbus_disconnect(); goto err1; } d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); // cgm_create immediately gets called so keep the connection open return d; err1: free(d); return NULL; }
/* * Make sure that all the controllers are writeable. * If any are not, then * - if they are listed in lxc.cgroup.use, refuse to start * - else if they are crucial subsystems, refuse to start * - else warn and do not use them */ static bool verify_final_subsystems(const char *cgroup_use) { int i; bool dropped_any = false; bool bret = false; const char *cgroup_pattern; char tmpnam[50], *probe; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); i = snprintf(tmpnam, 50, "lxcprobe-%d", getpid()); if (i < 0 || i >= 50) { ERROR("Attack - format string modified?"); return false; } probe = lxc_string_replace("%n", tmpnam, cgroup_pattern); if (!probe) goto out; i = 0; while (i < nr_subsystems) { char *p = get_last_controller_in_list(subsystems[i]); if (!subsys_is_writeable(p, probe)) { if (is_crucial_subsys(p)) { ERROR("Cannot write to crucial subsystem %s\n", subsystems[i]); goto out; } if (cgroup_use && any_in_comma_list(subsystems[i], cgroup_use)) { ERROR("Cannot write to subsystem %s which is requested in lxc.cgroup.use\n", subsystems[i]); goto out; } WARN("Cannot write to subsystem %s, continuing with out it\n", subsystems[i]); dropped_any = true; drop_subsystem(i); } else { cgm_remove_cgroup(subsystems[i], probe); i++; } } if (dropped_any) cgm_all_controllers_same = false; bret = true; out: free(probe); cgm_dbus_disconnect(); return bret; }
static void *cgm_init(const char *name) { struct cgm_data *d; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return NULL; } d = malloc(sizeof(*d)); if (!d) { cgm_dbus_disconnect(); return NULL; } memset(d, 0, sizeof(*d)); d->name = strdup(name); if (!d->name) { cgm_dbus_disconnect(); goto err1; } /* if we are running as root, use system cgroup pattern, otherwise * just create a cgroup under the current one. But also fall back to * that if for some reason reading the configuration fails and no * default value is available */ if (geteuid() == 0) d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); if (!d->cgroup_pattern) d->cgroup_pattern = "%n"; // cgm_create immediately gets called so keep the connection open return d; err1: free(d); return NULL; }
static bool collect_subsytems(void) { char *line = NULL; nih_local char **cgm_subsys_list = NULL; size_t sz = 0; FILE *f = NULL; if (subsystems) // already initialized return true; subsystems_inone = malloc(2 * sizeof(char *)); if (!subsystems_inone) return false; subsystems_inone[0] = "all"; subsystems_inone[1] = NULL; if (lxc_list_controllers(&cgm_subsys_list)) { while (cgm_subsys_list[nr_subsystems]) { char **tmp = NIH_MUST( realloc(subsystems, (nr_subsystems+2)*sizeof(char *)) ); tmp[nr_subsystems] = NIH_MUST( strdup(cgm_subsys_list[nr_subsystems++]) ); subsystems = tmp; } if (nr_subsystems) subsystems[nr_subsystems] = NULL; goto collected; } INFO("cgmanager_list_controllers failed, falling back to /proc/self/cgroups"); f = fopen_cloexec("/proc/self/cgroup", "r"); if (!f) { f = fopen_cloexec("/proc/1/cgroup", "r"); if (!f) return false; } while (getline(&line, &sz, f) != -1) { /* file format: hierarchy:subsystems:group, * with multiple subsystems being ,-separated */ char *slist, *end, *p, *saveptr = NULL, **tmp; if (!line[0]) continue; slist = strchr(line, ':'); if (!slist) continue; slist++; end = strchr(slist, ':'); if (!end) continue; *end = '\0'; for (p = strtok_r(slist, ",", &saveptr); p; p = strtok_r(NULL, ",", &saveptr)) { tmp = realloc(subsystems, (nr_subsystems+2)*sizeof(char *)); if (!tmp) goto out_free; subsystems = tmp; tmp[nr_subsystems] = strdup(p); tmp[nr_subsystems+1] = NULL; if (!tmp[nr_subsystems]) goto out_free; nr_subsystems++; } } fclose(f); f = NULL; free(line); line = NULL; collected: if (!nr_subsystems) { ERROR("No cgroup subsystems found"); return false; } /* make sure that cgroup.use can be and is honored */ const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use"); if (!cgroup_use && errno != 0) goto final_verify; if (cgroup_use) { if (!verify_and_prune(cgroup_use)) { free_subsystems(); return false; } subsystems_inone[0] = NIH_MUST( strdup(cgroup_use) ); cgm_all_controllers_same = false; } final_verify: return verify_final_subsystems(cgroup_use); out_free: free(line); if (f) fclose(f); free_subsystems(); return false; }
const char *default_cgroup_pattern(void) { return lxc_global_config_value("cgroup.pattern"); }
const char *default_cgroup_use(void) { return lxc_global_config_value("cgroup.use"); }
const char *default_lxc_path(void) { return lxc_global_config_value("lxcpath"); }
const char *default_zfs_root(void) { return lxc_global_config_value("zfsroot"); }
const char *default_lvm_thin_pool(void) { return lxc_global_config_value("lvm_thin_pool"); }
const char *default_lvm_vg(void) { return lxc_global_config_value("lvm_vg"); }
extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, char *const argv[]) { int ret = 0; char shortopts[256]; ret = build_shortopts(args->options, shortopts, sizeof(shortopts)); if (ret < 0) { lxc_error(args, "build_shortopts() failed : %s", strerror(errno)); return ret; } while (true) { int c; int index = 0; c = getopt_long(argc, argv, shortopts, args->options, &index); if (c == -1) break; switch (c) { case 'n': args->name = optarg; break; case 'o': args->log_file = optarg; break; case 'l': args->log_priority = optarg; break; case 'q': args->quiet = 1; break; case OPT_RCFILE: args->rcfile = optarg; break; case 'P': remove_trailing_slashes(optarg); ret = lxc_arguments_lxcpath_add(args, optarg); if (ret < 0) return ret; break; case OPT_USAGE: print_usage(args->options, args); case OPT_VERSION: print_version(); case '?': print_help(args, 1); case 'h': print_help(args, 0); default: if (args->parser) { ret = args->parser(args, c, optarg); if (ret) goto error; } } } /* * Reclaim the remaining command arguments */ args->argv = &argv[optind]; args->argc = argc - optind; /* If no lxcpaths were given, use default */ if (!args->lxcpath_cnt) { ret = lxc_arguments_lxcpath_add( args, lxc_global_config_value("lxc.lxcpath")); if (ret < 0) return ret; } /* Check the command options */ if (!args->name && strcmp(args->progname, "lxc-autostart") != 0) { lxc_error(args, "missing container name, use --name option"); return -1; } if (args->checker) ret = args->checker(args); error: if (ret) lxc_error(args, "could not parse command line"); return ret; }
/* * lxc_log_init: * Called from lxc front-end programs (like lxc-create, lxc-start) to * initalize the log defaults. */ extern int lxc_log_init(const char *name, const char *file, const char *priority, const char *prefix, int quiet, const char *lxcpath) { int lxc_priority = LXC_LOG_PRIORITY_ERROR; int ret; if (lxc_log_fd != -1) { WARN("lxc_log_init called with log already initialized"); return 0; } if (priority) lxc_priority = lxc_log_priority_to_int(priority); if (!lxc_loglevel_specified) { lxc_log_category_lxc.priority = lxc_priority; lxc_loglevel_specified = 1; } if (!lxc_quiet_specified) { if (!quiet) lxc_log_category_lxc.appender->next = &log_appender_stderr; } if (prefix) lxc_log_set_prefix(prefix); if (file) { if (strcmp(file, "none") == 0) return 0; ret = __lxc_log_set_file(file, 1); lxc_log_use_global_fd = 1; } else { /* if no name was specified, there nothing to do */ if (!name) return 0; ret = -1; if (!lxcpath) lxcpath = LOGPATH; /* try LOGPATH if lxcpath is the default for the privileged containers */ if (!geteuid() && strcmp(lxcpath, lxc_global_config_value("lxc.lxcpath")) == 0) ret = _lxc_log_set_file(name, NULL, 0); /* try in lxcpath */ if (ret < 0) ret = _lxc_log_set_file(name, lxcpath, 1); /* try LOGPATH in case its writable by the caller */ if (ret < 0) ret = _lxc_log_set_file(name, NULL, 0); } /* * If !file, that is, if the user did not request this logpath, then * ignore failures and continue logging to console */ if (!file && ret != 0) { INFO("Ignoring failure to open default logfile."); ret = 0; } return ret; }
int zfs_clone(const char *opath, const char *npath, const char *oname, const char *nname, const char *lxcpath, int snapshot) { // use the 'zfs list | grep opath' entry to get the zfsroot char output[MAXPATHLEN], option[MAXPATHLEN]; char *p; const char *zfsroot = output; int ret; pid_t pid; if (zfs_list_entry(opath, output, MAXPATHLEN)) { // zfsroot is output up to ' ' if ((p = strchr(output, ' ')) == NULL) return -1; *p = '\0'; if ((p = strrchr(output, '/')) == NULL) return -1; *p = '\0'; } else { zfsroot = lxc_global_config_value("lxc.bdev.zfs.root"); } ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s/%s/rootfs", lxcpath, nname); if (ret < 0 || ret >= MAXPATHLEN) return -1; // zfs create -omountpoint=$lxcpath/$lxcname $zfsroot/$nname if (!snapshot) { if ((pid = fork()) < 0) return -1; if (!pid) { char dev[MAXPATHLEN]; ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, nname); if (ret < 0 || ret >= MAXPATHLEN) exit(EXIT_FAILURE); execlp("zfs", "zfs", "create", option, dev, NULL); exit(EXIT_FAILURE); } return wait_for_pid(pid); } else { // if snapshot, do // 'zfs snapshot zfsroot/oname@nname // zfs clone zfsroot/oname@nname zfsroot/nname char path1[MAXPATHLEN], path2[MAXPATHLEN]; ret = snprintf(path1, MAXPATHLEN, "%s/%s@%s", zfsroot, oname, nname); if (ret < 0 || ret >= MAXPATHLEN) return -1; (void) snprintf(path2, MAXPATHLEN, "%s/%s", zfsroot, nname); // if the snapshot exists, delete it if ((pid = fork()) < 0) return -1; if (!pid) { execlp("zfs", "zfs", "destroy", path1, NULL); exit(EXIT_FAILURE); } // it probably doesn't exist so destroy probably will fail. (void) wait_for_pid(pid); // run first (snapshot) command if ((pid = fork()) < 0) return -1; if (!pid) { execlp("zfs", "zfs", "snapshot", path1, NULL); exit(EXIT_FAILURE); } if (wait_for_pid(pid) < 0) return -1; // run second (clone) command if ((pid = fork()) < 0) return -1; if (!pid) { execlp("zfs", "zfs", "clone", option, path1, path2, NULL); exit(EXIT_FAILURE); } return wait_for_pid(pid); } }