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=48da4cb3b722f473057176b7379e98e9f7d80633;hb=ba1261bc02693ac8a7712ade14aab8e22989ba88;hpb=c3175a7f40a2d2fabc3a2de63033a6810d45221a diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 48da4cb3b..6740d3b88 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -34,6 +34,8 @@ #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; @@ -513,7 +515,7 @@ static const char *normalize_controller(const char *controller) { } static int join_path(const char *controller, const char *path, const char *suffix, char **fs) { - char *t; + char *t = NULL; if (!(controller || path)) return -EINVAL; @@ -564,9 +566,23 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch return join_path(p, path, suffix, fs); } +static int check(const char *p) { + char *cc; + + assert(p); + + /* 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 0; +} + int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) { const char *p; - char *cc; + int r; assert(controller); assert(fs); @@ -574,13 +590,13 @@ int cg_get_path_and_check(const char *controller, const char *path, const char * if (isempty(controller)) return -EINVAL; + /* Normalize the controller syntax */ p = normalize_controller(controller); /* 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; + r = check(p); + if (r < 0) + return r; return join_path(p, path, suffix, fs); } @@ -658,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); @@ -1050,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; @@ -1062,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); @@ -1099,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; + +}