chiark / gitweb /
silence a bunch of gcc warnings
[elogind.git] / src / shared / cgroup-util.c
index 904d300..d34c142 100644 (file)
@@ -6,16 +6,16 @@
   Copyright 2010 Lennart Poettering
 
   systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
   (at your option) any later version.
 
   systemd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
+  Lesser General Public License for more details.
 
-  You should have received a copy of the GNU General Public License
+  You should have received a copy of the GNU Lesser General Public License
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
 #include "set.h"
 #include "macro.h"
 #include "util.h"
+#include "strv.h"
 
 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
         char *fs;
         int r;
         FILE *f;
 
-        assert(controller);
         assert(path);
         assert(_f);
 
-        if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
+        r = cg_get_path(controller, path, "cgroup.procs", &fs);
+        if (r < 0)
                 return r;
 
         f = fopen(fs, "re");
@@ -62,11 +63,11 @@ int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
         int r;
         FILE *f;
 
-        assert(controller);
         assert(path);
         assert(_f);
 
-        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+        r = cg_get_path(controller, path, "tasks", &fs);
+        if (r < 0)
                 return r;
 
         f = fopen(fs, "re");
@@ -106,13 +107,13 @@ int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
         int r;
         DIR *d;
 
-        assert(controller);
         assert(path);
         assert(_d);
 
         /* This is not recursive! */
 
-        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
                 return r;
 
         d = opendir(fs);
@@ -502,12 +503,51 @@ finish:
         return ret;
 }
 
+static const char *normalize_controller(const char *controller) {
+
+        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+                return "systemd";
+        else if (startswith(controller, "name="))
+                return controller + 5;
+        else
+                return controller;
+}
+
+static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
+        char *t = NULL;
+
+        if (!(controller || path))
+                return -EINVAL;
+
+        if (controller) {
+                if (path && suffix)
+                        t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
+                else if (path)
+                        t = join("/sys/fs/cgroup/", controller, "/", path, NULL);
+                else if (suffix)
+                        t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL);
+                else
+                        t = join("/sys/fs/cgroup/", controller, NULL);
+        } else {
+                if (path && suffix)
+                        t = join(path, "/", suffix, NULL);
+                else if (path)
+                        t = strdup(path);
+        }
+
+        if (!t)
+                return -ENOMEM;
+
+        path_kill_slashes(t);
+
+        *fs = t;
+        return 0;
+}
+
 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
         const char *p;
-        char *t;
         static __thread bool good = false;
 
-        assert(controller);
         assert(fs);
 
         if (_unlikely_(!good)) {
@@ -521,38 +561,29 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
                 good = true;
         }
 
-        if (isempty(controller))
-                return -EINVAL;
+        p = controller ? normalize_controller(controller) : NULL;
+        return join_path(p, path, suffix, fs);
+}
 
-        /* This is a very minimal lookup from controller names to
-         * paths. Since we have mounted most hierarchies ourselves
-         * should be kinda safe, but eventually we might want to
-         * extend this to have a fallback to actually check
-         * /proc/mounts. Might need caching then. */
+int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
+        const char *p;
+        char *cc;
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
-                p = "systemd";
-        else if (startswith(controller, "name="))
-                p = controller + 5;
-        else
-                p = controller;
-
-        if (path && suffix)
-                t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
-        else if (path)
-                t = join("/sys/fs/cgroup/", p, "/", path, NULL);
-        else if (suffix)
-                t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
-        else
-                t = join("/sys/fs/cgroup/", p, NULL);
+        assert(controller);
+        assert(fs);
 
-        if (!t)
-                return -ENOMEM;
+        if (isempty(controller))
+                return -EINVAL;
 
-        path_kill_slashes(t);
+        p = normalize_controller(controller);
 
-        *fs = t;
-        return 0;
+        /* Check if this controller actually really exists */
+        cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
+        strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
+        if (access(cc, F_OK) < 0)
+                return -errno;
+
+        return join_path(p, path, suffix, fs);
 }
 
 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
@@ -637,32 +668,6 @@ int cg_delete(const char *controller, const char *path) {
         return r == -ENOENT ? 0 : r;
 }
 
-int cg_create(const char *controller, const char *path) {
-        char *fs;
-        int r;
-
-        assert(controller);
-        assert(path);
-
-        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
-                return r;
-
-        r = mkdir_parents(fs, 0755);
-
-        if (r >= 0) {
-                if (mkdir(fs, 0755) >= 0)
-                        r = 1;
-                else if (errno == EEXIST)
-                        r = 0;
-                else
-                        r = -errno;
-        }
-
-        free(fs);
-
-        return r;
-}
-
 int cg_attach(const char *controller, const char *path, pid_t pid) {
         char *fs;
         int r;
@@ -672,7 +677,8 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
         assert(path);
         assert(pid >= 0);
 
-        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+        r = cg_get_path_and_check(controller, path, "tasks", &fs);
+        if (r < 0)
                 return r;
 
         if (pid == 0)
@@ -687,24 +693,6 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
         return r;
 }
 
-int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
-        int r, q;
-
-        assert(controller);
-        assert(path);
-        assert(pid >= 0);
-
-        if ((r = cg_create(controller, path)) < 0)
-                return r;
-
-        if ((q = cg_attach(controller, path, pid)) < 0)
-                return q;
-
-        /* This does not remove the cgroup on failure */
-
-        return r;
-}
-
 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
         char *fs;
         int r;
@@ -901,20 +889,22 @@ finish:
 }
 
 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
-        pid_t pid = 0;
+        pid_t pid = 0, self_pid;
         int r;
         FILE *f = NULL;
         bool found = false;
 
-        assert(controller);
         assert(path);
 
-        if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
+        r = cg_enumerate_tasks(controller, path, &f);
+        if (r < 0)
                 return r == -ENOENT ? 1 : r;
 
+        self_pid = getpid();
+
         while ((r = cg_read_pid(f, &pid)) > 0) {
 
-                if (ignore_self && pid == getpid())
+                if (ignore_self && pid == self_pid)
                         continue;
 
                 found = true;
@@ -934,13 +924,14 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
         DIR *d = NULL;
         char *fn;
 
-        assert(controller);
         assert(path);
 
-        if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
+        r = cg_is_empty(controller, path, ignore_self);
+        if (r <= 0)
                 return r;
 
-        if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
+        r = cg_enumerate_subgroups(controller, path, &d);
+        if (r < 0)
                 return r == -ENOENT ? 1 : r;
 
         while ((r = cg_read_subgroup(d, &fn)) > 0) {
@@ -1060,11 +1051,11 @@ int cg_fix_path(const char *path, char **result) {
         assert(result);
 
         /* First check if it already is a filesystem path */
-        if (path_is_absolute(path) &&
-            path_startswith(path, "/sys/fs/cgroup") &&
+        if (path_startswith(path, "/sys/fs/cgroup") &&
             access(path, F_OK) >= 0) {
 
-                if (!(t = strdup(path)))
+                t = strdup(path);
+                if (!t)
                         return -ENOMEM;
 
                 *result = t;
@@ -1072,7 +1063,8 @@ int cg_fix_path(const char *path, char **result) {
         }
 
         /* Otherwise treat it as cg spec */
-        if ((r = cg_split_spec(path, &c, &p)) < 0)
+        r = cg_split_spec(path, &c, &p);
+        if (r < 0)
                 return r;
 
         r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
@@ -1109,3 +1101,35 @@ int cg_get_user_path(char **path) {
         *path = p;
         return 0;
 }
+
+char **cg_shorten_controllers(char **controllers) {
+        char **f, **t;
+
+        controllers = strv_uniq(controllers);
+
+        if (!controllers)
+                return controllers;
+
+        for (f = controllers, t = controllers; *f; f++) {
+                char *cc;
+
+                if (streq(*f, "systemd") || streq(*f, SYSTEMD_CGROUP_CONTROLLER)) {
+                        free(*f);
+                        continue;
+                }
+
+                cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(*f));
+                strcpy(stpcpy(cc, "/sys/fs/cgroup/"), *f);
+
+                if (access(cc, F_OK) < 0) {
+                        log_debug("Controller %s is not available, removing from controllers list.", *f);
+                        free(*f);
+                        continue;
+                }
+
+                *(t++) = *f;
+        }
+
+        *t = NULL;
+        return controllers;
+}