chiark / gitweb /
cgroup: the "tasks" attribute is obsolete, cgroup.procs is the new replacement
[elogind.git] / src / shared / cgroup-util.c
index 016080f65b902b49eae26e2195ff5a8f7d77a159..7af0c3c1243c5ddf5d3977ef4bfd70ea37771eb4 100644 (file)
@@ -58,25 +58,6 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **_f)
         return 0;
 }
 
         return 0;
 }
 
-int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
-        _cleanup_free_ char *fs = NULL;
-        FILE *f;
-        int r;
-
-        assert(_f);
-
-        r = cg_get_path(controller, path, "tasks", &fs);
-        if (r < 0)
-                return r;
-
-        f = fopen(fs, "re");
-        if (!f)
-                return -errno;
-
-        *_f = f;
-        return 0;
-}
-
 int cg_read_pid(FILE *f, pid_t *_pid) {
         unsigned long ul;
 
 int cg_read_pid(FILE *f, pid_t *_pid) {
         unsigned long ul;
 
@@ -159,16 +140,28 @@ int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
                 return r;
 
         if (honour_sticky) {
                 return r;
 
         if (honour_sticky) {
-                char *tasks;
+                char *fn;
 
 
-                /* If the sticky bit is set don't remove the directory */
+                /* If the sticky bit is set on cgroup.procs, don't
+                 * remove the directory */
 
 
-                tasks = strappend(p, "/tasks");
-                if (!tasks)
+                fn = strappend(p, "/cgroup.procs");
+                if (!fn)
                         return -ENOMEM;
 
                         return -ENOMEM;
 
-                r = file_is_priv_sticky(tasks);
-                free(tasks);
+                r = file_is_priv_sticky(fn);
+                free(fn);
+
+                if (r > 0)
+                        return 0;
+
+                /* Compatibility ... */
+                fn = strappend(p, "/tasks");
+                if (!fn)
+                        return -ENOMEM;
+
+                r = file_is_priv_sticky(fn);
+                free(fn);
 
                 if (r > 0)
                         return 0;
 
                 if (r > 0)
                         return 0;
@@ -365,7 +358,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
                 pid_t pid = 0;
                 done = true;
 
                 pid_t pid = 0;
                 done = true;
 
-                r = cg_enumerate_tasks(cfrom, pfrom, &f);
+                r = cg_enumerate_processes(cfrom, pfrom, &f);
                 if (r < 0) {
                         if (ret >= 0 && r != -ENOENT)
                                 return r;
                 if (r < 0) {
                         if (ret >= 0 && r != -ENOENT)
                                 return r;
@@ -573,6 +566,19 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
         if (ftwbuf->level < 1)
                 return 0;
 
         if (ftwbuf->level < 1)
                 return 0;
 
+        p = strappend(path, "/cgroup.procs");
+        if (!p) {
+                errno = ENOMEM;
+                return 1;
+        }
+
+        is_sticky = file_is_priv_sticky(p) > 0;
+        free(p);
+
+        if (is_sticky)
+                return 0;
+
+        /* Compatibility */
         p = strappend(path, "/tasks");
         if (!p) {
                 errno = ENOMEM;
         p = strappend(path, "/tasks");
         if (!p) {
                 errno = ENOMEM;
@@ -607,13 +613,22 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
                 bool is_sticky;
                 char *p;
 
                 bool is_sticky;
                 char *p;
 
-                p = strappend(fs, "/tasks");
+                p = strappend(fs, "/cgroup.procs");
                 if (!p)
                         return -ENOMEM;
 
                 is_sticky = file_is_priv_sticky(p) > 0;
                 free(p);
 
                 if (!p)
                         return -ENOMEM;
 
                 is_sticky = file_is_priv_sticky(p) > 0;
                 free(p);
 
+                if (!is_sticky) {
+                        p = strappend(fs, "/tasks");
+                        if (!p)
+                                return -ENOMEM;
+
+                        is_sticky = file_is_priv_sticky(p) > 0;
+                        free(p);
+                }
+
                 if (!is_sticky)
                         if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
                                 return -errno;
                 if (!is_sticky)
                         if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
                                 return -errno;
@@ -644,7 +659,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
         assert(path);
         assert(pid >= 0);
 
         assert(path);
         assert(pid >= 0);
 
-        r = cg_get_path_and_check(controller, path, "tasks", &fs);
+        r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -697,7 +712,7 @@ int cg_set_task_access(
         if (mode != (mode_t) -1)
                 mode &= 0666;
 
         if (mode != (mode_t) -1)
                 mode &= 0666;
 
-        r = cg_get_path(controller, path, "tasks", &fs);
+        r = cg_get_path(controller, path, "cgroup.procs", &fs);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -727,8 +742,9 @@ int cg_set_task_access(
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
-        /* Always keep values for "cgroup.procs" in sync with "tasks" */
-        r = cg_get_path(controller, path, "cgroup.procs", &procs);
+        /* Compatibility, Always keep values for "tasks" in sync with
+         * "cgroup.procs" */
+        r = cg_get_path(controller, path, "tasks", &procs);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -736,24 +752,27 @@ int cg_set_task_access(
 }
 
 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
 }
 
 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
-        char fs[sizeof("/proc/") - 1 + DECIMAL_STR_MAX(pid_t) + sizeof("/cgroup")];
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
+        const char *fs;
         size_t cs;
 
         assert(path);
         assert(pid >= 0);
 
         size_t cs;
 
         assert(path);
         assert(pid >= 0);
 
-        if (controller && !cg_controller_is_valid(controller, true))
-                return -EINVAL;
+        if (controller) {
+                if (!cg_controller_is_valid(controller, true))
+                        return -EINVAL;
 
 
-        if (!controller)
+                controller = normalize_controller(controller);
+        } else
                 controller = SYSTEMD_CGROUP_CONTROLLER;
 
         if (pid == 0)
                 controller = SYSTEMD_CGROUP_CONTROLLER;
 
         if (pid == 0)
-                pid = getpid();
+                fs = "/proc/self/cgroup";
+        else
+                fs = procfs_file_alloca(pid, "cgroup");
 
 
-        sprintf(fs, "/proc/%lu/cgroup", (unsigned long) pid);
         f = fopen(fs, "re");
         if (!f)
                 return errno == ENOENT ? -ESRCH : -errno;
         f = fopen(fs, "re");
         if (!f)
                 return errno == ENOENT ? -ESRCH : -errno;
@@ -761,7 +780,10 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         cs = strlen(controller);
 
         FOREACH_LINE(line, f, return -errno) {
         cs = strlen(controller);
 
         FOREACH_LINE(line, f, return -errno) {
-                char *l, *p;
+                char *l, *p, *w, *e;
+                size_t k;
+                char *state;
+                bool found = false;
 
                 truncate_nl(line);
 
 
                 truncate_nl(line);
 
@@ -770,13 +792,31 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
                         continue;
 
                 l++;
                         continue;
 
                 l++;
-                if (!strneq(l, controller, cs))
+                e = strchr(l, ':');
+                if (!e)
                         continue;
 
                         continue;
 
-                if (l[cs] != ':')
+                *e = 0;
+
+                FOREACH_WORD_SEPARATOR(w, k, l, ",", state) {
+
+                        if (k == cs && memcmp(w, controller, cs) == 0) {
+                                found = true;
+                                break;
+                        }
+
+                        if (k == 5 + cs &&
+                            memcmp(w, "name=", 5) == 0 &&
+                            memcmp(w+5, controller, cs) == 0) {
+                                found = true;
+                                break;
+                        }
+                }
+
+                if (!found)
                         continue;
 
                         continue;
 
-                p = strdup(l + cs + 1);
+                p = strdup(e + 1);
                 if (!p)
                         return -ENOMEM;
 
                 if (!p)
                         return -ENOMEM;
 
@@ -845,7 +885,7 @@ int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
 
         assert(path);
 
 
         assert(path);
 
-        r = cg_enumerate_tasks(controller, path, &f);
+        r = cg_enumerate_processes(controller, path, &f);
         if (r < 0)
                 return r == -ENOENT ? 1 : r;
 
         if (r < 0)
                 return r == -ENOENT ? 1 : r;
 
@@ -1122,17 +1162,22 @@ int cg_get_user_path(char **path) {
         return 0;
 }
 
         return 0;
 }
 
-int cg_get_machine_path(char **path) {
-        _cleanup_free_ char *root = NULL;
+int cg_get_machine_path(const char *machine, char **path) {
+        _cleanup_free_ char *root = NULL, *escaped = NULL;
         char *p;
 
         assert(path);
 
         char *p;
 
         assert(path);
 
-        if (cg_get_root_path(&root) < 0 || streq(root, "/"))
-                p = strdup("/machine");
-        else
-                p = strappend(root, "/machine");
+        if (machine) {
+                const char *name = strappenda(machine, ".nspawn");
+
+                escaped = cg_escape(name);
+                if (!escaped)
+                        return -ENOMEM;
+        }
 
 
+        p = strjoin(cg_get_root_path(&root) >= 0 && !streq(root, "/") ? root : "",
+                    "/machine", machine ? "/" : "", machine ? escaped : "", NULL);
         if (!p)
                 return -ENOMEM;
 
         if (!p)
                 return -ENOMEM;
 
@@ -1282,7 +1327,7 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
         return cg_path_get_unit(cgroup, unit);
 }
 
         return cg_path_get_unit(cgroup, unit);
 }
 
-static const char *skip_label(const char *e) {
+_pure_ static const char *skip_label(const char *e) {
         assert(e);
 
         e = strchr(e, '/');
         assert(e);
 
         e = strchr(e, '/');
@@ -1498,7 +1543,12 @@ char *cg_escape(const char *p) {
         /* The return value of this function (unlike cg_unescape())
          * needs free()! */
 
         /* The return value of this function (unlike cg_unescape())
          * needs free()! */
 
-        if (p[0] == '_' || streq(p, "notify_on_release") || streq(p, "release_agent") || streq(p, "tasks"))
+        if (p[0] == 0 ||
+            p[0] == '_' ||
+            p[0] == '.' ||
+            streq(p, "notify_on_release") ||
+            streq(p, "release_agent") ||
+            streq(p, "tasks"))
                 need_prefix = true;
         else {
                 const char *dot;
                 need_prefix = true;
         else {
                 const char *dot;