mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
cgroup-util: Add get_user_unit_path helpers
This is similar to get_user_unit_name, but instead of returning just the unit name it returns the full cgroup path up to the user unit. This also refactors the existing get_unit_path helper, so that the bulk of the logic can be shared. Additionally, the refactor means that we only duplicate exactly as many bytes as we need, rather than duplicating the entire cgroup path (which may be quite long!) and putting a null-terminator in the middle of the memory allocation.
This commit is contained in:
3 files changed
+189
-18
No files matched your search
+156
-17
@@ -765,21 +765,37 @@ int cg_pidref_get_path_shifted(const PidRef *pidref, const char *cached_root, ch
|
||||
return strdup_to(ret_cgroup, c);
|
||||
}
|
||||
|
||||
int cg_path_decode_unit(const char *cgroup, char **ret_unit) {
|
||||
static const char* skip_unit(const char *cgroup) {
|
||||
assert(cgroup);
|
||||
|
||||
size_t n = strcspn(cgroup, "/");
|
||||
if (n < 3)
|
||||
return -ENXIO;
|
||||
return NULL;
|
||||
|
||||
char *c = strndupa_safe(cgroup, n);
|
||||
c = cg_unescape(c);
|
||||
|
||||
if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
|
||||
return NULL;
|
||||
|
||||
return cgroup + n;
|
||||
}
|
||||
|
||||
int cg_path_decode_unit(const char *cgroup, char **ret_unit) {
|
||||
assert(cgroup);
|
||||
|
||||
const char *end = skip_unit(cgroup);
|
||||
if (!end)
|
||||
return -ENXIO;
|
||||
|
||||
if (ret_unit)
|
||||
return strdup_to(ret_unit, c);
|
||||
if (ret_unit) {
|
||||
const char *start = cg_unescape(cgroup);
|
||||
_cleanup_free_ char *unit = strndup(start, end - start);
|
||||
if (!unit)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_unit = TAKE_PTR(unit);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -855,25 +871,24 @@ int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_path_get_unit_path(const char *path, char **ret) {
|
||||
_cleanup_free_ char *path_copy = NULL;
|
||||
char *unit_name;
|
||||
static const char* skip_unit_path(const char *cgroup) {
|
||||
const char *end = skip_slices(cgroup);
|
||||
return skip_unit(end);
|
||||
}
|
||||
|
||||
int cg_path_get_unit_path(const char *path, char **ret_path) {
|
||||
assert(path);
|
||||
assert(ret);
|
||||
assert(ret_path);
|
||||
|
||||
path_copy = strdup(path);
|
||||
if (!path_copy)
|
||||
return -ENOMEM;
|
||||
|
||||
unit_name = (char*) skip_slices(path_copy);
|
||||
unit_name[strcspn(unit_name, "/")] = 0;
|
||||
|
||||
if (!unit_name_is_valid(cg_unescape(unit_name), UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
|
||||
const char *end = skip_unit_path(path);
|
||||
if (!end)
|
||||
return -ENXIO;
|
||||
|
||||
*ret = TAKE_PTR(path_copy);
|
||||
_cleanup_free_ char *unit_path = strndup(path, end - path);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = TAKE_PTR(unit_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -888,6 +903,34 @@ int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) {
|
||||
return cg_path_get_unit_full(cgroup, ret_unit, ret_subgroup);
|
||||
}
|
||||
|
||||
int cg_pid_get_unit_path(pid_t pid, char **ret_path) {
|
||||
int r;
|
||||
|
||||
assert(pid >= 0);
|
||||
assert(ret_path);
|
||||
|
||||
_cleanup_free_ char *cgroup = NULL;
|
||||
r = cg_pid_get_path(pid, &cgroup);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *end;
|
||||
r = cg_shift_path(cgroup, /* cached_root= */ NULL, &end);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
end = skip_unit_path(end);
|
||||
if (!end)
|
||||
return -ENXIO;
|
||||
|
||||
_cleanup_free_ char *unit_path = strndup(cgroup, end - cgroup);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = TAKE_PTR(unit_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup) {
|
||||
int r;
|
||||
|
||||
@@ -912,6 +955,28 @@ int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_su
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_pidref_get_unit_path(const PidRef *pidref, char **ret_path) {
|
||||
int r;
|
||||
|
||||
if (!pidref_is_set(pidref))
|
||||
return -ESRCH;
|
||||
if (pidref_is_remote(pidref))
|
||||
return -EREMOTE;
|
||||
|
||||
_cleanup_free_ char *unit_path = NULL;
|
||||
r = cg_pid_get_unit_path(pidref->pid, &unit_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_verify(pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(unit_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* skip_session(const char *p) {
|
||||
size_t n;
|
||||
|
||||
@@ -1011,6 +1076,30 @@ int cg_path_get_user_unit_full(const char *path, char **ret_unit, char **ret_sub
|
||||
return cg_path_get_unit_full(t, ret_unit, ret_subgroup);
|
||||
}
|
||||
|
||||
static const char* skip_user_unit_path(const char *cgroup) {
|
||||
const char *end = skip_user_prefix(cgroup);
|
||||
if (!end)
|
||||
return NULL;
|
||||
|
||||
return skip_unit_path(end);
|
||||
}
|
||||
|
||||
int cg_path_get_user_unit_path(const char *path, char **ret_path) {
|
||||
assert(path);
|
||||
assert(ret_path);
|
||||
|
||||
const char *end = skip_user_unit_path(path);
|
||||
if (!end)
|
||||
return -ENXIO;
|
||||
|
||||
_cleanup_free_ char *unit_path = strndup(path, end - path);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = TAKE_PTR(unit_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_pid_get_user_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) {
|
||||
int r;
|
||||
|
||||
@@ -1022,6 +1111,34 @@ int cg_pid_get_user_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) {
|
||||
return cg_path_get_user_unit_full(cgroup, ret_unit, ret_subgroup);
|
||||
}
|
||||
|
||||
int cg_pid_get_user_unit_path(pid_t pid, char **ret_path) {
|
||||
int r;
|
||||
|
||||
assert(pid >= 0);
|
||||
assert(ret_path);
|
||||
|
||||
_cleanup_free_ char *cgroup = NULL;
|
||||
r = cg_pid_get_path(pid, &cgroup);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *end;
|
||||
r = cg_shift_path(cgroup, /* cached_root= */ NULL, &end);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
end = skip_user_unit_path(end);
|
||||
if (!end)
|
||||
return -ENXIO;
|
||||
|
||||
_cleanup_free_ char *unit_path = strndup(cgroup, end - cgroup);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = TAKE_PTR(unit_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_pidref_get_user_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup) {
|
||||
int r;
|
||||
|
||||
@@ -1046,6 +1163,28 @@ int cg_pidref_get_user_unit_full(const PidRef *pidref, char **ret_unit, char **r
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_pidref_get_user_unit_path(const PidRef *pidref, char **ret_path) {
|
||||
int r;
|
||||
|
||||
if (!pidref_is_set(pidref))
|
||||
return -ESRCH;
|
||||
if (pidref_is_remote(pidref))
|
||||
return -EREMOTE;
|
||||
|
||||
_cleanup_free_ char *unit_path = NULL;
|
||||
r = cg_pid_get_user_unit_path(pidref->pid, &unit_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_verify(pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(unit_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_path_get_machine_name(const char *path, char **ret_machine) {
|
||||
_cleanup_free_ char *u = NULL;
|
||||
const char *sl;
|
||||
|
||||
@@ -185,7 +185,8 @@ 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, /* ret_subgroup= */ NULL);
|
||||
}
|
||||
int cg_path_get_unit_path(const char *path, char **ret_unit);
|
||||
int cg_path_get_unit_path(const char *path, char **ret_path);
|
||||
int cg_path_get_user_unit_path(const char *path, char **ret_path);
|
||||
int cg_path_get_user_unit_full(const char *path, char **ret_unit, char **ret_subgroup);
|
||||
static inline int cg_path_get_user_unit(const char *path, char **ret_unit) {
|
||||
return cg_path_get_user_unit_full(path, ret_unit, /* ret_subgroup= */ NULL);
|
||||
@@ -206,18 +207,22 @@ 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, /* ret_subgroup= */ NULL);
|
||||
}
|
||||
int cg_pid_get_unit_path(pid_t pid, char **ret_path);
|
||||
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, /* ret_subgroup= */ NULL);
|
||||
}
|
||||
int cg_pidref_get_unit_path(const PidRef *pidref, char **ret_path);
|
||||
int cg_pid_get_user_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup);
|
||||
static inline int cg_pid_get_user_unit(pid_t pid, char **ret_unit) {
|
||||
return cg_pid_get_user_unit_full(pid, ret_unit, /* ret_subgroup= */ NULL);
|
||||
}
|
||||
int cg_pid_get_user_unit_path(pid_t pid, char **ret_path);
|
||||
int cg_pidref_get_user_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup);
|
||||
static inline int cg_pidref_get_user_unit(const PidRef *pidref, char **ret_unit) {
|
||||
return cg_pidref_get_user_unit_full(pidref, ret_unit, /* ret_subgroup= */ NULL);
|
||||
}
|
||||
int cg_pidref_get_user_unit_path(const PidRef *pidref, char **ret_path);
|
||||
int cg_pid_get_machine_name(pid_t pid, char **ret_machine);
|
||||
int cg_pid_get_slice(pid_t pid, char **ret_slice);
|
||||
int cg_pid_get_user_slice(pid_t pid, char **ret_slice);
|
||||
|
||||
@@ -148,6 +148,33 @@ TEST(path_get_user_unit) {
|
||||
check_p_g_u_u("/capsule.slice/capsule@#.service/foo.slice/foo-bar.slice/run-p9-i1.service", -ENXIO, /* result= */ NULL);
|
||||
}
|
||||
|
||||
static void check_p_g_u_u_p(const char *path, int code, const char *result) {
|
||||
_cleanup_free_ char *unit_path = NULL;
|
||||
int r;
|
||||
|
||||
r = cg_path_get_user_unit_path(path, &unit_path);
|
||||
printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit_path, r, strnull(result), code);
|
||||
ASSERT_EQ(r, code);
|
||||
ASSERT_STREQ(unit_path, result);
|
||||
}
|
||||
|
||||
TEST(path_get_user_unit_path) {
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service/", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service/asdf", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service/asdf", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service/asdf", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/example.slice/foobar.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/example.slice/foobar.service");
|
||||
check_p_g_u_u_p("/capsule.slice/capsule@test.service/app.slice/foobar.service", 0, "/capsule.slice/capsule@test.service/app.slice/foobar.service");
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "/user.slice/user-1000.slice/session-2.scope/foobar.service");
|
||||
check_p_g_u_u_p("sadfdsafsda", -ENXIO, NULL);
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foo###bar.service", -ENXIO, NULL);
|
||||
check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@.service", -ENXIO, NULL);
|
||||
check_p_g_u_u_p("/system.slice/foobar.service", -ENXIO, NULL);
|
||||
}
|
||||
|
||||
static void check_p_g_s(const char *path, int code, const char *result) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
|
||||
Reference in new issue
Block a user