]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cgroup-util: add cg_path_get_unit_full() helper and related calls
authorLennart Poettering <lennart@poettering.net>
Wed, 21 May 2025 15:21:36 +0000 (17:21 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 11 Jul 2025 16:15:08 +0000 (18:15 +0200)
This helper returns not only the unit a cgroup belongs to, but also the
cgroup sub-path beyond it.

src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/test/test-cgroup-util.c

index f3270ff2787b50c19a0de1b96a4ede202e0ebb59..0184cbffbecc569129c08e0944c41b37b276e994 100644 (file)
@@ -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;
 }
 
index f49fc48832868fa4ed012f779711b3d875c987b8..81424418e08545dcf5bfd9b48c72098d574b6f77 100644 (file)
@@ -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);
index 5fa6fe2da30c7c56f500d1402ef824326174928c..7c8cfaaa119a0ffd3cc04528a73e507d77630172 100644 (file)
@@ -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;