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=6740d3b8856c2c1f0d616e1a8e0e124a3f2bac3b;hp=904d30095226a6f027f1d527634cb4e9cc311b24;hb=ba1261bc02693ac8a7712ade14aab8e22989ba88;hpb=77d47be64f8b0497c44a4288f2531fc1056624ae diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 904d30095..6740d3b88 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,19 @@ #include "set.h" #include "macro.h" #include "util.h" +#include "path-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 +64,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 +108,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 +504,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,40 +562,45 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch good = true; } - if (isempty(controller)) - return -EINVAL; - - /* 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. */ + p = controller ? normalize_controller(controller) : NULL; + return join_path(p, path, suffix, fs); +} - 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); +static int check(const char *p) { + char *cc; - if (!t) - return -ENOMEM; + assert(p); - path_kill_slashes(t); + /* 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; - *fs = t; return 0; } +int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) { + const char *p; + int r; + + assert(controller); + assert(fs); + + if (isempty(controller)) + return -EINVAL; + + /* Normalize the controller syntax */ + p = normalize_controller(controller); + + /* Check if this controller actually really exists */ + r = check(p); + if (r < 0) + return r; + + return join_path(p, path, suffix, fs); +} + static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { char *p; bool is_sticky; @@ -628,7 +674,7 @@ int cg_delete(const char *controller, const char *path) { assert(controller); assert(path); - if ((r = parent_of_path(path, &parent)) < 0) + if ((r = path_get_parent(path, &parent)) < 0) return r; r = cg_migrate_recursive(controller, path, parent, false, true); @@ -637,32 +683,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 +692,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 +708,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 +904,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 +939,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 +1066,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 +1078,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 +1116,141 @@ 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++) { + int r; + const char *p; + + if (streq(*f, "systemd") || streq(*f, SYSTEMD_CGROUP_CONTROLLER)) { + free(*f); + continue; + } + + p = normalize_controller(*f); + + r = check(p); + if (r < 0) { + log_debug("Controller %s is not available, removing from controllers list.", *f); + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return controllers; +} + +int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) { + char *cg_process, *cg_init, *p; + int r; + + assert(pid >= 0); + + if (pid == 0) + pid = getpid(); + + r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); + if (r < 0) + return r; + + r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init); + if (r < 0) { + free(cg_process); + return r; + } + + if (endswith(cg_init, "/system")) + cg_init[strlen(cg_init)-7] = 0; + else if (streq(cg_init, "/")) + cg_init[0] = 0; + + if (startswith(cg_process, cg_init)) + p = cg_process + strlen(cg_init); + else + p = cg_process; + + free(cg_init); + + if (cgroup) { + char* c; + + c = strdup(p); + if (!c) { + free(cg_process); + return -ENOMEM; + } + + *cgroup = c; + } + + if (root) { + cg_process[p-cg_process] = 0; + *root = cg_process; + } else + free(cg_process); + + return 0; +} + +int cg_pid_get_unit(pid_t pid, char **unit) { + int r; + char *cgroup, *p, *at, *b; + size_t k; + + assert(pid >= 0); + assert(unit); + + r = cg_pid_get_cgroup(pid, NULL, &cgroup); + if (r < 0) + return r; + + if (!startswith(cgroup, "/system/")) { + free(cgroup); + return -ENOENT; + } + + p = cgroup + 8; + k = strcspn(p, "/"); + + at = memchr(p, '@', k); + if (at && at[1] == '.') { + size_t j; + + /* This is a templated service */ + if (p[k] != '/') { + free(cgroup); + return -EIO; + } + + j = strcspn(p+k+1, "/"); + + b = malloc(k + j + 1); + + if (b) { + memcpy(b, p, at - p + 1); + memcpy(b + (at - p) + 1, p + k + 1, j); + memcpy(b + (at - p) + 1 + j, at + 1, k - (at - p) - 1); + b[k+j] = 0; + } + } else + b = strndup(p, k); + + free(cgroup); + + if (!b) + return -ENOMEM; + + *unit = b; + return 0; + +}