From 7bb1147b009772c96250e5fef93b96b7023fa36c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 May 2025 17:21:36 +0200 Subject: [PATCH] cgroup-util: add cg_path_get_unit_full() helper and related calls This helper returns not only the unit a cgroup belongs to, but also the cgroup sub-path beyond it. --- src/basic/cgroup-util.c | 51 ++++++++++++++++++++++++------------- src/basic/cgroup-util.h | 15 ++++++++--- src/test/test-cgroup-util.c | 30 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index f3270ff2787..0184cbffbec 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -973,15 +973,14 @@ static const char* skip_slices(const char *p) { } } -int cg_path_get_unit(const char *path, char **ret) { - _cleanup_free_ char *unit = NULL; - const char *e; +int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup) { int r; assert(path); - e = skip_slices(path); + const char *e = skip_slices(path); + _cleanup_free_ char *unit = NULL; r = cg_path_decode_unit(e, &unit); if (r < 0) return r; @@ -990,8 +989,27 @@ int cg_path_get_unit(const char *path, char **ret) { if (endswith(unit, ".slice")) return -ENXIO; - if (ret) - *ret = TAKE_PTR(unit); + if (ret_subgroup) { + _cleanup_free_ char *subgroup = NULL; + e += strcspn(e, "/"); + e += strspn(e, "/"); + + if (isempty(e)) + subgroup = NULL; + else { + subgroup = strdup(e); + if (!subgroup) + return -ENOMEM; + } + + path_simplify(subgroup); + + *ret_subgroup = TAKE_PTR(subgroup); + } + + if (ret_unit) + *ret_unit = TAKE_PTR(unit); + return 0; } @@ -1017,31 +1035,27 @@ int cg_path_get_unit_path(const char *path, char **ret) { return 0; } -int cg_pid_get_unit(pid_t pid, char **ret_unit) { - _cleanup_free_ char *cgroup = NULL; +int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) { int r; - assert(ret_unit); - + _cleanup_free_ char *cgroup = NULL; r = cg_pid_get_path_shifted(pid, NULL, &cgroup); if (r < 0) return r; - return cg_path_get_unit(cgroup, ret_unit); + return cg_path_get_unit_full(cgroup, ret_unit, ret_subgroup); } -int cg_pidref_get_unit(const PidRef *pidref, char **ret) { - _cleanup_free_ char *unit = NULL; +int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup) { int r; - assert(ret); - if (!pidref_is_set(pidref)) return -ESRCH; if (pidref_is_remote(pidref)) return -EREMOTE; - r = cg_pid_get_unit(pidref->pid, &unit); + _cleanup_free_ char *unit = NULL, *subgroup = NULL; + r = cg_pid_get_unit_full(pidref->pid, &unit, &subgroup); if (r < 0) return r; @@ -1049,7 +1063,10 @@ int cg_pidref_get_unit(const PidRef *pidref, char **ret) { if (r < 0) return r; - *ret = TAKE_PTR(unit); + if (ret_unit) + *ret_unit = TAKE_PTR(unit); + if (ret_subgroup) + *ret_subgroup = TAKE_PTR(subgroup); return 0; } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index f49fc488328..81424418e08 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -203,7 +203,10 @@ int cg_get_root_path(char **path); int cg_path_get_session(const char *path, char **ret_session); int cg_path_get_owner_uid(const char *path, uid_t *ret_uid); -int cg_path_get_unit(const char *path, char **ret_unit); +int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup); +static inline int cg_path_get_unit(const char *path, char **ret_unit) { + return cg_path_get_unit_full(path, ret_unit, NULL); +} int cg_path_get_unit_path(const char *path, char **ret_unit); int cg_path_get_user_unit(const char *path, char **ret_unit); int cg_path_get_machine_name(const char *path, char **ret_machine); @@ -217,8 +220,14 @@ int cg_pid_get_session(pid_t pid, char **ret_session); int cg_pidref_get_session(const PidRef *pidref, char **ret); int cg_pid_get_owner_uid(pid_t pid, uid_t *ret_uid); int cg_pidref_get_owner_uid(const PidRef *pidref, uid_t *ret); -int cg_pid_get_unit(pid_t pid, char **ret_unit); -int cg_pidref_get_unit(const PidRef *pidref, char **ret); +int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup); +static inline int cg_pid_get_unit(pid_t pid, char **ret_unit) { + return cg_pid_get_unit_full(pid, ret_unit, NULL); +} +int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup); +static inline int cg_pidref_get_unit(const PidRef *pidref, char **ret_unit) { + return cg_pidref_get_unit_full(pidref, ret_unit, NULL); +} int cg_pid_get_user_unit(pid_t pid, char **ret_unit); int cg_pid_get_machine_name(pid_t pid, char **ret_machine); int cg_pid_get_slice(pid_t pid, char **ret_slice); diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 5fa6fe2da30..7c8cfaaa119 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -60,6 +60,36 @@ TEST(path_get_unit) { check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL); } +static void check_p_g_u_f(const char *path, int expected_code, const char *expected_unit, const char *expected_subgroup) { + _cleanup_free_ char *unit = NULL, *subgroup = NULL; + int r; + + r = cg_path_get_unit_full(path, &unit, &subgroup); + printf("%s: %s → %s %s %d expected %s %s %d\n", __func__, path, unit, subgroup, r, strnull(expected_unit), strnull(expected_subgroup), expected_code); + ASSERT_EQ(r, expected_code); + ASSERT_STREQ(unit, expected_unit); + ASSERT_STREQ(subgroup, expected_subgroup); +} + +TEST(path_get_unit_full) { + check_p_g_u_f("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service", "sdfdsaf"); + check_p_g_u_f("/system.slice/foobar.service//sdfdsaf", 0, "foobar.service", "sdfdsaf"); + check_p_g_u_f("/system.slice/foobar.service/sdfdsaf/", 0, "foobar.service", "sdfdsaf"); + check_p_g_u_f("/system.slice/foobar.service//sdfdsaf/", 0, "foobar.service", "sdfdsaf"); + check_p_g_u_f("/system.slice/foobar.service//sdfdsaf//", 0, "foobar.service", "sdfdsaf"); + check_p_g_u_f("/system.slice/foobar.service/sdfdsaf/urks", 0, "foobar.service", "sdfdsaf/urks"); + check_p_g_u_f("/system.slice/foobar.service//sdfdsaf//urks", 0, "foobar.service", "sdfdsaf/urks"); + check_p_g_u_f("/system.slice/foobar.service/sdfdsaf/urks/", 0, "foobar.service", "sdfdsaf/urks"); + check_p_g_u_f("/system.slice/foobar.service//sdfdsaf//urks//", 0, "foobar.service", "sdfdsaf/urks"); + check_p_g_u_f("/system.slice/foobar.service", 0, "foobar.service", NULL); + check_p_g_u_f("/system.slice/foobar.service/", 0, "foobar.service", NULL); + check_p_g_u_f("/system.slice/foobar.service//", 0, "foobar.service", NULL); + check_p_g_u_f("/system.slice/", -ENXIO, NULL, NULL); + check_p_g_u_f("/system.slice/piff", -ENXIO, NULL, NULL); + check_p_g_u_f("/system.service/piff", 0, "system.service", "piff"); + check_p_g_u_f("//system.service//piff", 0, "system.service", "piff"); +} + static void check_p_g_u_p(const char *path, int code, const char *result) { _cleanup_free_ char *unit_path = NULL; int r; -- 2.47.3