chiark / gitweb /
bus: make bus ref counting atomic
[elogind.git] / src / shared / cgroup-util.c
index b79a24a495e6f6ddccf8e09d6c1e144df01af113..43c415d760d67dee78646908affe51cf207fd268 100644 (file)
@@ -736,24 +736,27 @@ int cg_set_task_access(
 }
 
 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];
+        const char *fs;
         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)
-                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;
@@ -761,7 +764,10 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         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);
 
@@ -770,13 +776,31 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
                         continue;
 
                 l++;
-                if (!strneq(l, controller, cs))
+                e = strchr(l, ':');
+                if (!e)
                         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;
 
-                p = strdup(l + cs + 1);
+                p = strdup(e + 1);
                 if (!p)
                         return -ENOMEM;
 
@@ -916,6 +940,7 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
 int cg_split_spec(const char *spec, char **controller, char **path) {
         const char *e;
         char *t = NULL, *u = NULL;
+        _cleanup_free_ char *v = NULL;
 
         assert(spec);
 
@@ -928,6 +953,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                         if (!t)
                                 return -ENOMEM;
 
+                        path_kill_slashes(t);
                         *path = t;
                 }
 
@@ -943,7 +969,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                         return -EINVAL;
 
                 if (controller) {
-                        t = strdup(spec);
+                        t = strdup(normalize_controller(spec));
                         if (!t)
                                 return -ENOMEM;
 
@@ -956,7 +982,10 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                 return 0;
         }
 
-        t = strndup(spec, e-spec);
+        v = strndup(spec, e-spec);
+        if (!v)
+                return -ENOMEM;
+        t = strdup(normalize_controller(v));
         if (!t)
                 return -ENOMEM;
         if (!cg_controller_is_valid(t, true)) {
@@ -969,12 +998,15 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                 free(t);
                 return -ENOMEM;
         }
-        if (!path_is_safe(u)) {
+        if (!path_is_safe(u) ||
+            !path_is_absolute(u)) {
                 free(t);
                 free(u);
                 return -EINVAL;
         }
 
+        path_kill_slashes(u);
+
         if (controller)
                 *controller = t;
         else
@@ -993,7 +1025,6 @@ int cg_join_spec(const char *controller, const char *path, char **spec) {
 
         assert(path);
 
-
         if (!controller)
                 controller = "systemd";
         else {
@@ -1010,6 +1041,8 @@ int cg_join_spec(const char *controller, const char *path, char **spec) {
         if (!s)
                 return -ENOMEM;
 
+        path_kill_slashes(s + strlen(controller) + 1);
+
         *spec = s;
         return 0;
 }
@@ -1029,6 +1062,7 @@ int cg_mangle_path(const char *path, char **result) {
                 if (!t)
                         return -ENOMEM;
 
+                path_kill_slashes(t);
                 *result = t;
                 return 0;
         }
@@ -1112,17 +1146,22 @@ int cg_get_user_path(char **path) {
         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);
 
-        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;
 
@@ -1208,7 +1247,6 @@ int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) {
 }
 
 int cg_path_decode_unit(const char *cgroup, char **unit){
-        _cleanup_free_ char *unescaped = NULL;
         char *p, *e, *c, *s, *k;
 
         assert(cgroup);
@@ -1273,7 +1311,7 @@ int cg_pid_get_unit(pid_t pid, char **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, '/');
@@ -1489,7 +1527,12 @@ char *cg_escape(const char *p) {
         /* 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;