struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
FILE *proc_file;
char proc_fn[MAXPATHLEN];
- char *line = NULL, *ptr, *ptr2;
+ char *line = NULL;
size_t line_bufsz = 0;
- int ret, found, l;
- int i;
+ int ret, found;
if (!info) {
SYSERROR("Could not allocate memory.");
goto out_error;
}
- /* read cgroups */
- snprintf(proc_fn, MAXPATHLEN, "/proc/%d/cgroup", pid);
-
- proc_file = fopen(proc_fn, "r");
- if (!proc_file) {
- SYSERROR("Could not open %s", proc_fn);
- goto out_error;
- }
-
- /* we don't really know how many cgroup subsystems there are
- * mounted, so we go through the whole file twice */
- i = 0;
- while (getline(&line, &line_bufsz, proc_file) != -1) {
- /* we assume that all lines containing at least two colons
- * are valid */
- ptr = strchr(line, ':');
- if (ptr && strchr(ptr + 1, ':'))
- i++;
- }
-
- rewind(proc_file);
-
- info->cgroups = calloc(i, sizeof(*(info->cgroups)));
- info->cgroups_count = i;
-
- i = 0;
- while (getline(&line, &line_bufsz, proc_file) != -1 && i < info->cgroups_count) {
- /* format of the lines is:
- * id:subsystems:path, where subsystems are separated by
- * commas and each subsystem may also be of the form
- * name=xxx if it describes a private named hierarchy
- * we will ignore the id in the following */
- ptr = strchr(line, ':');
- ptr2 = ptr ? strchr(ptr + 1, ':') : NULL;
-
- /* ignore invalid lines */
- if (!ptr || !ptr2) continue;
-
- l = strlen(ptr2) - 1;
- if (ptr2[l] == '\n')
- ptr2[l] = '\0';
-
- info->cgroups[i].subsystems = strndup(ptr + 1, ptr2 - (ptr + 1));
- info->cgroups[i].cgroup = strdup(ptr2 + 1);
-
- i++;
- }
-
- free(line);
- fclose(proc_file);
-
return info;
out_error:
- lxc_proc_free_context_info(info);
+ free(info);
free(line);
return NULL;
}
-void lxc_proc_free_context_info(struct lxc_proc_context_info *info)
-{
- if (!info)
- return;
-
- if (info->cgroups) {
- int i;
- for (i = 0; i < info->cgroups_count; i++) {
- free(info->cgroups[i].subsystems);
- free(info->cgroups[i].cgroup);
- }
- }
- free(info->cgroups);
- free(info);
-}
-
-int lxc_attach_proc_to_cgroups(pid_t pid, struct lxc_proc_context_info *ctx)
-{
- int i, ret;
-
- if (!ctx) {
- ERROR("No valid context supplied when asked to attach "
- "process to cgroups.");
- return -1;
- }
-
- for (i = 0; i < ctx->cgroups_count; i++) {
- char *path;
-
- /* the kernel should return paths that start with '/' */
- if (ctx->cgroups[i].cgroup[0] != '/') {
- ERROR("For cgroup subsystem(s) %s the path '%s' does "
- "not start with a '/'",
- ctx->cgroups[i].subsystems,
- ctx->cgroups[i].cgroup);
- return -1;
- }
-
- /* lxc_cgroup_path_get can process multiple subsystems */
- ret = lxc_cgroup_path_get(&path, ctx->cgroups[i].subsystems,
- &ctx->cgroups[i].cgroup[1]);
- if (ret)
- return -1;
-
- ret = lxc_cgroup_attach(path, pid);
- if (ret)
- return -1;
- }
-
- return 0;
-}
-
int lxc_attach_to_ns(pid_t pid)
{
char path[MAXPATHLEN];
#include <sys/types.h>
-struct lxc_proc_cgroup_info {
- char *subsystems;
- char *cgroup;
-};
-
struct lxc_proc_context_info {
unsigned long personality;
unsigned long long capability_mask;
- struct lxc_proc_cgroup_info* cgroups;
- int cgroups_count;
};
extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
-extern void lxc_proc_free_context_info(struct lxc_proc_context_info *info);
-extern int lxc_attach_proc_to_cgroups(pid_t pid, struct lxc_proc_context_info *ctx);
extern int lxc_attach_to_ns(pid_t other_pid);
extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
CGROUP_CLONE_CHILDREN,
};
-static char *hasmntopt_multiple(struct mntent *mntent, const char *options)
-{
- const char *ptr = options;
- const char *ptr2 = strchr(options, ',');
- char *result;
-
- while (ptr2 != NULL) {
- char *option = strndup(ptr, ptr2 - ptr);
- if (!option) {
- SYSERROR("Temporary memory allocation error");
- return NULL;
- }
-
- result = hasmntopt(mntent, option);
- free(option);
-
- if (!result) {
- return NULL;
- }
-
- ptr = ptr2 + 1;
- ptr2 = strchr(ptr, ',');
- }
-
- /* for multiple mount options, the return value is basically NULL
- * or non-NULL, so this should suffice for our purposes */
- return hasmntopt(mntent, ptr);
-}
-
/*
* get_init_cgroup: get the cgroup init is in.
* dsg: preallocated buffer to put the output in
while ((mntent = getmntent(file))) {
if (strcmp(mntent->mnt_type, "cgroup"))
continue;
- if (subsystem && !hasmntopt_multiple(mntent, subsystem))
+ if (subsystem && !hasmntopt(mntent, subsystem))
continue;
flags = get_cgroup_flags(mntent);
return ret;
}
-int lxc_cgroup_attach(const char *path, pid_t pid)
+static int lxc_one_cgroup_attach(const char *name,
+ struct mntent *mntent, pid_t pid)
{
FILE *f;
- char tasks[MAXPATHLEN];
- int ret = 0;
+ char tasks[MAXPATHLEN], initcgroup[MAXPATHLEN];
+ char *cgmnt = mntent->mnt_dir;
+ int flags, ret = 0;
+
+ flags = get_cgroup_flags(mntent);
- snprintf(tasks, MAXPATHLEN, "%s/tasks", path);
+ snprintf(tasks, MAXPATHLEN, "%s%s%s/%s/tasks", cgmnt,
+ get_init_cgroup(NULL, mntent, initcgroup),
+ (flags & CGROUP_NS_CGROUP) ? "" : "/lxc",
+ name);
f = fopen(tasks, "w");
if (!f) {
return ret;
}
+/*
+ * for each mounted cgroup, attach a pid to the cgroup for the container
+ */
+int lxc_cgroup_attach(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;
+
+ INFO("[%d] found cgroup mounted at '%s',opts='%s'",
+ ++found, mntent->mnt_dir, mntent->mnt_opts);
+
+ 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;
+}
+
/*
* rename cgname, which is under cgparent, to a new name starting
* with 'cgparent/dead'. That way cgname can be reused. Return
return -1;
}
- /* Let's add the pid to the 'tasks' file */
- if (lxc_cgroup_attach(cgname, pid)) {
- SYSERROR("failed to attach pid '%d' to '%s'", pid, cgname);
- rmdir(cgname);
- return -1;
- }
-
INFO("created cgroup '%s'", cgname);
return 0;
}
/*
- * for each mounted cgroup, create a cgroup for the container
+ * for each mounted cgroup, create a cgroup for the container and attach a pid
*/
int lxc_cgroup_create(const char *name, pid_t pid)
{
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)
extern int lxc_cgroup_destroy(const char *name);
extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name);
extern int lxc_cgroup_nrtasks(const char *name);
-extern int lxc_cgroup_attach(const char *path, pid_t pid);
+extern int lxc_cgroup_attach(const char *name, pid_t pid);
extern int lxc_ns_is_mounted(void);
#endif
#include "commands.h"
#include "arguments.h"
#include "caps.h"
-#include "attach.h"
+#include "cgroup.h"
#include "confile.h"
#include "start.h"
#include "sync.h"
if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
return -1;
- if (!elevated_privileges && lxc_attach_proc_to_cgroups(pid, init_ctx))
+ if (!elevated_privileges && lxc_cgroup_attach(my_args.name, pid))
return -1;
/* tell the child we are done initializing */