diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-04-22 23:10:13 -0300 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-04-22 23:14:12 -0300 |
commit | ae018d9bc900d6355dea4af05119b49c67945184 (patch) | |
tree | 07a311ae16ac331f1044503bbb01a4e111331fb2 /src/shared/cgroup-util.c | |
parent | cd8f53ab1601513cc3407447bfe3359ee7139676 (diff) |
cgroup: make sure all our cgroup objects have a suffix and are properly escaped
Session objects will now get the .session suffix, user objects the .user
suffix, nspawn containers the .nspawn suffix.
This also changes the user cgroups to be named after the numeric UID
rather than the username, since this allows us the parse these paths
standalone without requiring access to the cgroup file system.
This also changes the mapping of instanced units to cgroups. Instead of
mapping foo@bar.service to the cgroup path /user/foo@.service/bar we
will now map it to /user/foo@.service/foo@bar.service, in order to
ensure that all our objects are properly suffixed in the tree.
Diffstat (limited to 'src/shared/cgroup-util.c')
-rw-r--r-- | src/shared/cgroup-util.c | 123 |
1 files changed, 105 insertions, 18 deletions
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index e54b94658c..9ec4f40c88 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -1197,8 +1197,8 @@ int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) { return 0; } -/* non-static only for testing purposes */ int cg_path_decode_unit(const char *cgroup, char **unit){ + _cleanup_free_ char *unescaped = NULL; char *p, *e, *c, *s, *k; assert(cgroup); @@ -1206,6 +1206,7 @@ int cg_path_decode_unit(const char *cgroup, char **unit){ e = strchrnul(cgroup, '/'); c = strndupa(cgroup, e - cgroup); + c = cg_unescape(c); /* Could this be a valid unit name? */ if (!unit_name_is_valid(c, true)) @@ -1218,15 +1219,15 @@ int cg_path_decode_unit(const char *cgroup, char **unit){ return -EINVAL; e += strspn(e, "/"); + p = strchrnul(e, '/'); + k = strndupa(e, p - e); + k = cg_unescape(k); - /* Don't allow empty instance strings */ - if (p == e) + if (!unit_name_is_valid(k, false)) return -EINVAL; - k = strndupa(e, p - e); - - s = unit_name_replace_instance(c, k); + s = strdup(k); } if (!s) @@ -1320,7 +1321,7 @@ int cg_pid_get_user_unit(pid_t pid, char **unit) { int cg_path_get_machine_name(const char *path, char **machine) { const char *e, *n; - char *s, *dot; + char *s, *r; assert(path); assert(machine); @@ -1333,15 +1334,13 @@ int cg_path_get_machine_name(const char *path, char **machine) { if (e == n) return -ENOENT; - s = strndup(e, n - e); - if (!s) - return -ENOMEM; + s = strndupa(e, n - e); - dot = strrchr(s, '.'); - if (dot) - *dot = 0; + r = strdup(cg_unescape(s)); + if (!r) + return -ENOMEM; - *machine = s; + *machine = r; return 0; } @@ -1375,13 +1374,12 @@ int cg_path_get_session(const char *path, char **session) { return -ENOENT; n = strchrnul(e, '/'); - if (e == n) + if (n - e < 8) return -ENOENT; - - if (n - e == 6 && memcmp(e, "shared", 6) == 0) + if (memcmp(n - 8, ".session", 8) != 0) return -ENOENT; - s = strndup(e, n - e); + s = strndup(e, n - e - 8); if (!s) return -ENOMEM; @@ -1402,6 +1400,43 @@ int cg_pid_get_session(pid_t pid, char **session) { return cg_path_get_session(cgroup, session); } +int cg_path_get_owner_uid(const char *path, uid_t *uid) { + const char *e, *n; + char *s; + + assert(path); + assert(uid); + + e = path_startswith(path, "/user/"); + if (!e) + return -ENOENT; + + n = strchrnul(e, '/'); + if (n - e < 5) + return -ENOENT; + if (memcmp(n - 5, ".user", 5) != 0) + return -ENOENT; + + s = strndupa(e, n - e - 5); + if (!s) + return -ENOMEM; + + return parse_uid(s, uid); +} + +int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(uid); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_owner_uid(cgroup, uid); +} + int cg_controller_from_attr(const char *attr, char **controller) { const char *dot; char *c; @@ -1430,3 +1465,55 @@ int cg_controller_from_attr(const char *attr, char **controller) { *controller = c; return 1; } + +char *cg_escape(const char *p) { + bool need_prefix = false; + + /* This implements very minimal escaping for names to be used + * as file names in the cgroup tree: any name which might + * conflict with a kernel name or is prefixed with '_' is + * prefixed with a '_'. That way, when reading cgroup names it + * is sufficient to remove a single prefixing underscore if + * there is one. */ + + /* The return value of this function (unlike cg_unescape()) + * needs free()! */ + + if (p[0] == '_' || streq(p, "notify_on_release") || streq(p, "release_agent") || streq(p, "tasks")) + need_prefix = true; + else { + const char *dot; + + dot = strrchr(p, '.'); + if (dot) { + + if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0) + need_prefix = true; + else { + char *n; + + n = strndupa(p, dot - p); + + if (check_hierarchy(n) >= 0) + need_prefix = true; + } + } + } + + if (need_prefix) + return strappend("_", p); + else + return strdup(p); +} + +char *cg_unescape(const char *p) { + assert(p); + + /* The return value of this function (unlike cg_escape()) + * doesn't need free()! */ + + if (p[0] == '_') + return (char*) p+1; + + return (char*) p; +} |