X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fcgroup-util.c;h=d34c142729da00f229d4e9dc103fd4ba2c5711d1;hp=904d30095226a6f027f1d527634cb4e9cc311b24;hb=018ef268b1667ba0dbfc15804ab33deed6092147;hpb=77d47be64f8b0497c44a4288f2531fc1056624ae diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 904d30095..d34c14272 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -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 . ***/ @@ -34,17 +34,18 @@ #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; +}