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=be00b40fa2346afb2ebf43ab6847d4d61a025f6f;hp=18cbf0412ab823ec5d9045c1b0ef2f8238857e71;hb=76877b46b652fbfcf8618458556178717b815cd8;hpb=f274ece0f76b5709408821e317e87aef76123db6 diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 18cbf0412..be00b40fa 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -36,6 +36,8 @@ #include "util.h" #include "path-util.h" #include "strv.h" +#include "unit-name.h" +#include "fileio.h" int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { char *fs; @@ -374,18 +376,20 @@ int cg_kill_recursive_and_wait(const char *controller, const char *path, bool re return 0; } -int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) { +int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) { bool done = false; - Set *s; + _cleanup_set_free_ Set *s = NULL; int r, ret = 0; pid_t my_pid; - FILE *f = NULL; + _cleanup_fclose_ FILE *f = NULL; - assert(controller); - assert(from); - assert(to); + assert(cfrom); + assert(pfrom); + assert(cto); + assert(pto); - if (!(s = set_new(trivial_hash_func, trivial_compare_func))) + s = set_new(trivial_hash_func, trivial_compare_func); + if (!s) return -ENOMEM; my_pid = getpid(); @@ -394,11 +398,12 @@ int cg_migrate(const char *controller, const char *from, const char *to, bool ig pid_t pid = 0; done = true; - if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) { + r = cg_enumerate_tasks(cfrom, pfrom, &f); + if (r < 0) { if (ret >= 0 && r != -ENOENT) ret = r; - goto finish; + return ret; } while ((r = cg_read_pid(f, &pid)) > 0) { @@ -412,7 +417,8 @@ int cg_migrate(const char *controller, const char *from, const char *to, bool ig if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) continue; - if ((r = cg_attach(controller, to, pid)) < 0) { + r = cg_attach(cto, pto, pid); + if (r < 0) { if (ret >= 0 && r != -ESRCH) ret = r; } else if (ret == 0) @@ -420,11 +426,12 @@ int cg_migrate(const char *controller, const char *from, const char *to, bool ig done = false; - if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) { + r = set_put(s, LONG_TO_PTR(pid)); + if (r < 0) { if (ret >= 0) ret = r; - goto finish; + return ret; } } @@ -432,56 +439,48 @@ int cg_migrate(const char *controller, const char *from, const char *to, bool ig if (ret >= 0) ret = r; - goto finish; + return ret; } fclose(f); f = NULL; - } while (!done); -finish: - set_free(s); - - if (f) - fclose(f); - return ret; } -int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) { +int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem) { int r, ret = 0; - DIR *d = NULL; + _cleanup_closedir_ DIR *d = NULL; char *fn; - assert(controller); - assert(from); - assert(to); + assert(cfrom); + assert(pfrom); + assert(cto); + assert(pto); - ret = cg_migrate(controller, from, to, ignore_self); + ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self); - if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) { + r = cg_enumerate_subgroups(cfrom, pfrom, &d); + if (r < 0) { if (ret >= 0 && r != -ENOENT) ret = r; - goto finish; + return ret; } while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; + _cleanup_free_ char *p = NULL; - r = asprintf(&p, "%s/%s", from, fn); + p = strjoin(pfrom, "/", fn, NULL); free(fn); - - if (r < 0) { + if (!p) { if (ret >= 0) ret = -ENOMEM; - goto finish; + return ret; } - r = cg_migrate_recursive(controller, p, to, ignore_self, rem); - free(p); - + r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem); if (r != 0 && ret >= 0) ret = r; } @@ -489,17 +488,11 @@ int cg_migrate_recursive(const char *controller, const char *from, const char *t if (r < 0 && ret >= 0) ret = r; - if (rem) - if ((r = cg_rmdir(controller, from, true)) < 0) { - if (ret >= 0 && - r != -ENOENT && - r != -EBUSY) - ret = r; - } - -finish: - if (d) - closedir(d); + if (rem) { + r = cg_rmdir(cfrom, pfrom, true); + if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY) + return r; + } return ret; } @@ -677,7 +670,7 @@ int cg_delete(const char *controller, const char *path) { if ((r = path_get_parent(path, &parent)) < 0) return r; - r = cg_migrate_recursive(controller, path, parent, false, true); + r = cg_migrate_recursive(controller, path, controller, parent, false, true); free(parent); return r == -ENOENT ? 0 : r; @@ -819,7 +812,7 @@ int cg_get_by_pid(const char *controller, pid_t pid, char **path) { continue; l++; - if (strncmp(l, controller, cs) != 0) + if (!strneq(l, controller, cs)) continue; if (l[cs] != ':') @@ -947,7 +940,6 @@ int cg_is_empty_by_spec(const char *spec, bool ignore_self) { return cg_is_empty(controller, path, ignore_self); } - int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) { int r; DIR *d = NULL; @@ -997,12 +989,14 @@ int cg_split_spec(const char *spec, char **controller, char **path) { char *t = NULL, *u = NULL; assert(spec); - assert(controller || path); if (*spec == '/') { + if (!path_is_safe(spec)) + return -EINVAL; if (path) { - if (!(t = strdup(spec))) + t = strdup(spec); + if (!t) return -ENOMEM; *path = t; @@ -1014,13 +1008,14 @@ int cg_split_spec(const char *spec, char **controller, char **path) { return 0; } - if (!(e = strchr(spec, ':'))) { - - if (strchr(spec, '/') || spec[0] == 0) + e = strchr(spec, ':'); + if (!e) { + if (!filename_is_safe(spec)) return -EINVAL; if (controller) { - if (!(t = strdup(spec))) + t = strdup(spec); + if (!t) return -ENOMEM; *controller = t; @@ -1032,26 +1027,34 @@ int cg_split_spec(const char *spec, char **controller, char **path) { return 0; } - if (e[1] != '/' || - e == spec || - memchr(spec, '/', e-spec)) + t = strndup(spec, e-spec); + if (!t) + return -ENOMEM; + if (!filename_is_safe(t)) { + free(t); return -EINVAL; + } - if (controller) - if (!(t = strndup(spec, e-spec))) - return -ENOMEM; - - if (path) - if (!(u = strdup(e+1))) { - free(t); - return -ENOMEM; - } + u = strdup(e+1); + if (!u) { + free(t); + return -ENOMEM; + } + if (!path_is_safe(u)) { + free(t); + free(u); + return -EINVAL; + } if (controller) *controller = t; + else + free(t); if (path) *path = u; + else + free(u); return 0; } @@ -1216,10 +1219,63 @@ int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) { return 0; } -int cg_pid_get_unit(pid_t pid, char **unit) { +static int instance_unit_from_cgroup(char *cgroup){ + char *at; + + assert(cgroup); + + at = strstr(cgroup, "@."); + if (at) { + /* This is a templated service */ + + char *i; + char _cleanup_free_ *i2 = NULL, *s = NULL; + + i = strchr(at, '/'); + if (!i || !i[1]) /* disallow empty instances */ + return -EINVAL; + + s = strndup(at + 1, i - at - 1); + i2 = strdup(i + 1); + if (!s || !i2) + return -ENOMEM; + + strcpy(at + 1, i2); + strcat(at + 1, s); + } + + return 0; +} + +/* non-static only for testing purposes */ +int cgroup_to_unit(char *cgroup, char **unit){ + int r; + char *p; + + assert(cgroup); + assert(unit); + + r = instance_unit_from_cgroup(cgroup); + if (r < 0) + return r; + + p = strrchr(cgroup, '/'); + assert(p); + + r = unit_name_is_valid(p + 1, true); + if (!r) + return -EINVAL; + + *unit = strdup(p + 1); + if (!*unit) + return -ENOMEM; + + return 0; +} + +static int cg_pid_get(const char *prefix, pid_t pid, char **unit) { int r; - char *cgroup, *p, *at, *b; - size_t k; + char _cleanup_free_ *cgroup = NULL; assert(pid >= 0); assert(unit); @@ -1228,43 +1284,46 @@ int cg_pid_get_unit(pid_t pid, char **unit) { if (r < 0) return r; - if (!startswith(cgroup, "/system/")) { - free(cgroup); + if (!startswith(cgroup, prefix)) return -ENOENT; - } - p = cgroup + 8; - k = strcspn(p, "/"); + r = cgroup_to_unit(cgroup, unit); + return r; +} - at = memchr(p, '@', k); - if (at && at[1] == '.') { - size_t j; +int cg_pid_get_unit(pid_t pid, char **unit) { + return cg_pid_get("/system/", pid, unit); +} - /* This is a templated service */ - if (p[k] != '/') { - free(cgroup); - return -EIO; - } +int cg_pid_get_user_unit(pid_t pid, char **unit) { + return cg_pid_get("/user/", pid, unit); +} - j = strcspn(p+k+1, "/"); +int cg_controller_from_attr(const char *attr, char **controller) { + const char *dot; + char *c; - b = malloc(k + j + 1); + assert(attr); + assert(controller); - 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); + if (!filename_is_safe(attr)) + return -EINVAL; - free(cgroup); + dot = strchr(attr, '.'); + if (!dot) { + *controller = NULL; + return 0; + } - if (!b) + c = strndup(attr, dot - attr); + if (!c) return -ENOMEM; - *unit = b; - return 0; + if (!filename_is_safe(c)) { + free(c); + return -EINVAL; + } + *controller = c; + return 1; }