/* * for each mounted cgroup, destroy the cgroup for the container */ int lxc_cgroup_destroy(const char *name) { struct mntent *mntent; FILE *file = NULL; int err = -1; file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return -1; } while ((mntent = getmntent(file))) { if (strcmp(mntent->mnt_type, "cgroup")) continue; if (!mount_has_subsystem(mntent)) continue; err = lxc_one_cgroup_destroy(mntent, name); if (err) break; } endmntent(file); return err; }
/* * for each mounted cgroup, destroy the cgroup for the container */ int lxc_cgroup_destroy(const char *cgpath) { struct mntent *mntent; FILE *file = NULL; int err, retv = 0; file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return -1; } while ((mntent = getmntent(file))) { if (strcmp(mntent->mnt_type, "cgroup")) continue; if (!mount_has_subsystem(mntent)) continue; err = lxc_one_cgroup_destroy(mntent, cgpath); if (err) // keep trying to clean up the others retv = -1; } endmntent(file); return retv; }
static int get_cgroup_mount(const char *subsystem, char *mnt) { struct mntent *mntent; char initcgroup[MAXPATHLEN]; FILE *file = NULL; int ret, flags, err = -1; file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return -1; } while ((mntent = getmntent(file))) { if (strcmp(mntent->mnt_type, "cgroup")) continue; if (subsystem) { if (!hasmntopt(mntent, subsystem)) continue; } else { if (!mount_has_subsystem(mntent)) continue; } flags = get_cgroup_flags(mntent); ret = snprintf(mnt, MAXPATHLEN, "%s%s%s", mntent->mnt_dir, get_init_cgroup(subsystem, NULL, initcgroup), (flags & CGROUP_NS_CGROUP) ? "" : "/lxc"); if (ret < 0 || ret >= MAXPATHLEN) goto fail; DEBUG("using cgroup mounted at '%s'", mnt); err = 0; goto out; }; fail: DEBUG("Failed to find cgroup for %s\n", subsystem ? subsystem : "(NULL)"); out: endmntent(file); return err; }
/* * Make sure the 'cgroup group' exists, so that we don't have to worry about * that later. * * @lxcgroup: the cgroup group, i.e. 'lxc' by default. * * See detailed comments at lxc_cgroup_path_create for more information. * * Returns 0 on success, -1 on error. */ static int create_lxcgroups(const char *lxcgroup) { FILE *file = NULL; struct mntent *mntent; int ret, retv = -1; char path[MAXPATHLEN]; file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return -1; } while ((mntent = getmntent(file))) { if (strcmp(mntent->mnt_type, "cgroup")) continue; if (!mount_has_subsystem(mntent)) continue; /* * TODO - handle case where lxcgroup has subdirs? (i.e. build/l1) * We probably only want to support that for /users/joe */ ret = snprintf(path, MAXPATHLEN, "%s/%s", mntent->mnt_dir, lxcgroup ? lxcgroup : "lxc"); if (ret < 0 || ret >= MAXPATHLEN) goto fail; if (access(path, F_OK)) { set_clone_children(mntent->mnt_dir); ret = mkdir(path, 0755); if (ret == -1 && errno != EEXIST) { SYSERROR("failed to create '%s' directory", path); goto fail; } } } retv = 0; fail: endmntent(file); return retv; }
/* * for each mounted cgroup, create a cgroup for the container and attach a pid */ int lxc_cgroup_create(const char *name, pid_t pid) { struct mntent *mntent; FILE *file = NULL; int err = -1; int found = 0; file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return -1; } while ((mntent = getmntent(file))) { DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type); if (strcmp(mntent->mnt_type, "cgroup")) continue; if (!mount_has_subsystem(mntent)) continue; INFO("[%d] found cgroup mounted at '%s',opts='%s'", ++found, mntent->mnt_dir, mntent->mnt_opts); err = lxc_one_cgroup_create(name, mntent, pid); if (err) goto out; err = lxc_one_cgroup_attach(name, mntent, pid); if (err) goto out; }; if (!found) ERROR("No cgroup mounted on the system"); out: endmntent(file); return err; }
int lxc_cgroup_enter(const char *cgpath, pid_t pid) { char path[MAXPATHLEN]; FILE *file = NULL, *fout; struct mntent *mntent; int ret, retv = -1; file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return -1; } while ((mntent = getmntent(file))) { if (strcmp(mntent->mnt_type, "cgroup")) continue; if (!mount_has_subsystem(mntent)) continue; ret = snprintf(path, MAXPATHLEN, "%s/%s/tasks", mntent->mnt_dir, cgpath); if (ret < 0 || ret >= MAXPATHLEN) { ERROR("entering cgroup"); goto out; } fout = fopen(path, "w"); if (!fout) { ERROR("entering cgroup"); goto out; } fprintf(fout, "%d\n", (int)pid); fclose(fout); } retv = 0; out: endmntent(file); return retv; }
/* * For a new container, find a cgroup path which is unique in all cgroup mounts. * I.e. if r1 is already running, then /lxc/r1-1 may be used. * * @lxcgroup: the cgroup 'group' the contaienr should run in. By default, this * is just 'lxc'. Admins may wish to group some containers into other groups, * i.e. 'build', to take advantage of cgroup hierarchy to simplify group * administration. Also, unprivileged users who are placed into a cgroup by * libcgroup_pam will be using that cgroup rather than the system-wide 'lxc' * group. * @name: the name of the container * * The chosen cgpath is returned as a strdup'd string. The caller will have to * free that eventually, however the lxc monitor will keep that string so as to * return it in response to a LXC_COMMAND_CGROUP query. * * Note the path is relative to cgroup mounts. I.e. if the freezer subsystem * is at /sys/fs/cgroup/freezer, and this fn returns '/lxc/r1', then the * freezer cgroup's full path will be /sys/fs/cgroup/freezer/lxc/r1/. * * XXX This should probably be locked globally * * Races won't be determintal, you'll just end up with leftover unused cgroups */ char *lxc_cgroup_path_create(const char *lxcgroup, const char *name) { int i = 0, ret; char *retpath, path[MAXPATHLEN]; char tail[12]; FILE *file = NULL; struct mntent *mntent; if (create_lxcgroups(lxcgroup) < 0) return NULL; again: file = setmntent(MTAB, "r"); if (!file) { SYSERROR("failed to open %s", MTAB); return NULL; } if (i) snprintf(tail, 12, "-%d", i); else *tail = '\0'; while ((mntent = getmntent(file))) { if (strcmp(mntent->mnt_type, "cgroup")) continue; if (!mount_has_subsystem(mntent)) continue; /* find unused mnt_dir + lxcgroup + name + -$i */ ret = snprintf(path, MAXPATHLEN, "%s/%s/%s%s", mntent->mnt_dir, lxcgroup ? lxcgroup : "lxc", name, tail); if (ret < 0 || ret >= MAXPATHLEN) goto fail; if (access(path, F_OK) == 0) goto next; if (mkdir(path, 0755)) { ERROR("Error creating cgroups"); goto fail; } } endmntent(file); // print out the cgpath part ret = snprintf(path, MAXPATHLEN, "%s/%s%s", lxcgroup ? lxcgroup : "lxc", name, tail); if (ret < 0 || ret >= MAXPATHLEN) // can't happen goto fail; retpath = strdup(path); return retpath; next: endmntent(file); i++; goto again; fail: endmntent(file); return NULL; }