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 (#44254)
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. Split out from https://github.com/systemd/systemd/pull/43885
This commit is contained in:
9 files changed
+525
-53
No files matched your search
@@ -925,23 +925,29 @@ manpages = [
|
||||
'sd_peer_get_session',
|
||||
'sd_peer_get_slice',
|
||||
'sd_peer_get_unit',
|
||||
'sd_peer_get_unit_cgroup',
|
||||
'sd_peer_get_user_slice',
|
||||
'sd_peer_get_user_unit',
|
||||
'sd_peer_get_user_unit_cgroup',
|
||||
'sd_pid_get_cgroup',
|
||||
'sd_pid_get_machine_name',
|
||||
'sd_pid_get_session',
|
||||
'sd_pid_get_slice',
|
||||
'sd_pid_get_unit',
|
||||
'sd_pid_get_unit_cgroup',
|
||||
'sd_pid_get_user_slice',
|
||||
'sd_pid_get_user_unit',
|
||||
'sd_pid_get_user_unit_cgroup',
|
||||
'sd_pidfd_get_cgroup',
|
||||
'sd_pidfd_get_machine_name',
|
||||
'sd_pidfd_get_owner_uid',
|
||||
'sd_pidfd_get_session',
|
||||
'sd_pidfd_get_slice',
|
||||
'sd_pidfd_get_unit',
|
||||
'sd_pidfd_get_unit_cgroup',
|
||||
'sd_pidfd_get_user_slice',
|
||||
'sd_pidfd_get_user_unit'],
|
||||
'sd_pidfd_get_user_unit',
|
||||
'sd_pidfd_get_user_unit_cgroup'],
|
||||
'HAVE_PAM'],
|
||||
['sd_pidfd_get_inode_id', '3', [], ''],
|
||||
['sd_seat_get_active',
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
<refname>sd_pid_get_slice</refname>
|
||||
<refname>sd_pid_get_user_slice</refname>
|
||||
<refname>sd_pid_get_cgroup</refname>
|
||||
<refname>sd_pid_get_unit_cgroup</refname>
|
||||
<refname>sd_pid_get_user_unit_cgroup</refname>
|
||||
<refname>sd_pidfd_get_owner_uid</refname>
|
||||
<refname>sd_pidfd_get_session</refname>
|
||||
<refname>sd_pidfd_get_user_unit</refname>
|
||||
@@ -33,6 +35,8 @@
|
||||
<refname>sd_pidfd_get_slice</refname>
|
||||
<refname>sd_pidfd_get_user_slice</refname>
|
||||
<refname>sd_pidfd_get_cgroup</refname>
|
||||
<refname>sd_pidfd_get_unit_cgroup</refname>
|
||||
<refname>sd_pidfd_get_user_unit_cgroup</refname>
|
||||
<refname>sd_peer_get_owner_uid</refname>
|
||||
<refname>sd_peer_get_session</refname>
|
||||
<refname>sd_peer_get_user_unit</refname>
|
||||
@@ -41,6 +45,8 @@
|
||||
<refname>sd_peer_get_slice</refname>
|
||||
<refname>sd_peer_get_user_slice</refname>
|
||||
<refname>sd_peer_get_cgroup</refname>
|
||||
<refname>sd_peer_get_unit_cgroup</refname>
|
||||
<refname>sd_peer_get_user_unit_cgroup</refname>
|
||||
<refpurpose>Determine the owner uid of the user unit or session,
|
||||
or the session, user unit, system unit, container/VM or slice that
|
||||
a specific PID or socket peer belongs to</refpurpose>
|
||||
@@ -98,6 +104,18 @@
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_pid_get_unit_cgroup</function></funcdef>
|
||||
<paramdef>pid_t <parameter>pid</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_pid_get_user_unit_cgroup</function></funcdef>
|
||||
<paramdef>pid_t <parameter>pid</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_pidfd_get_owner_uid</function></funcdef>
|
||||
<paramdef>int <parameter>pidfd</parameter></paramdef>
|
||||
@@ -146,6 +164,18 @@
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_pidfd_get_unit_cgroup</function></funcdef>
|
||||
<paramdef>int <parameter>pidfd</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_pidfd_get_user_unit_cgroup</function></funcdef>
|
||||
<paramdef>int <parameter>pidfd</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_peer_get_owner_uid</function></funcdef>
|
||||
<paramdef>int <parameter>fd</parameter></paramdef>
|
||||
@@ -193,6 +223,18 @@
|
||||
<paramdef>int <parameter>fd</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_peer_get_unit_cgroup</function></funcdef>
|
||||
<paramdef>int <parameter>fd</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_peer_get_user_unit_cgroup</function></funcdef>
|
||||
<paramdef>int <parameter>fd</parameter></paramdef>
|
||||
<paramdef>char **<parameter>cgroup</parameter></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@@ -266,7 +308,17 @@
|
||||
<para><function>sd_pid_get_cgroup()</function> returns the control group path of the specified process,
|
||||
relative to the root of the hierarchy. Returns the path without trailing slash, except for processes
|
||||
located in the root control group, where "/" is returned. To find the actual control group path
|
||||
in the file system, the returned path needs to be prefixed with <filename>/sys/fs/cgroup/</filename>.</para>
|
||||
in the file system, the returned path needs to be prefixed with <filename>/sys/fs/cgroup/</filename>.
|
||||
The returned string needs to be freed with the libc
|
||||
<citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
call after use.</para>
|
||||
|
||||
<para><function>sd_pid_get_unit_cgroup()</function> is like <function>sd_pid_get_cgroup()</function>,
|
||||
but returns the control group path of the systemd system unit that contains the process. If the process
|
||||
is not part of a systemd unit, then this function fails with <constant>-ENODATA</constant>.</para>
|
||||
|
||||
<para><function>sd_pid_get_user_unit_cgroup()</function> is like <function>sd_pid_get_unit_cgroup()</function>,
|
||||
but operates on systemd user units (as managed by the user's systemd instance).</para>
|
||||
|
||||
<para>If the <varname>pid</varname> parameter of any of these
|
||||
functions is passed as 0, the operation is executed for the
|
||||
@@ -278,12 +330,14 @@
|
||||
<function>sd_pidfd_get_unit()</function>,
|
||||
<function>sd_pidfd_get_machine_name()</function>,
|
||||
<function>sd_pidfd_get_slice()</function>,
|
||||
<function>sd_pidfd_get_user_slice()</function> and
|
||||
<function>sd_pidfd_get_cgroup()</function> calls operate similarly to their PID counterparts, but accept a
|
||||
<constant>PIDFD</constant> instead of a <constant>PID</constant>, which means they are not subject to recycle
|
||||
race conditions as the process is pinned by the file descriptor during the whole duration of the invocation.
|
||||
Note that these require a kernel that supports <constant>PIDFD</constant>. A suitable file descriptor may be
|
||||
acquired via
|
||||
<function>sd_pidfd_get_user_slice()</function>,
|
||||
<function>sd_pidfd_get_cgroup()</function>,
|
||||
<function>sd_pidfd_get_unit_cgroup()</function>, and
|
||||
<function>sd_pidfd_get_user_unit_cgroup()</function>, calls operate similarly to their PID counterparts,
|
||||
but accept a <constant>PIDFD</constant> instead of a <constant>PID</constant>, which means they are not
|
||||
subject to recycle race conditions as the process is pinned by the file descriptor during the whole
|
||||
duration of the invocation. Note that these require a kernel that supports <constant>PIDFD</constant>.
|
||||
A suitable file descriptor may be acquired via
|
||||
<citerefentry project='man-pages'><refentrytitle>pidfd_open</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>The <function>sd_peer_get_owner_uid()</function>,
|
||||
@@ -292,11 +346,13 @@
|
||||
<function>sd_peer_get_unit()</function>,
|
||||
<function>sd_peer_get_machine_name()</function>,
|
||||
<function>sd_peer_get_slice()</function>,
|
||||
<function>sd_peer_get_user_slice()</function> and
|
||||
<function>sd_peer_get_cgroup()</function> calls operate similarly to their PID counterparts, but accept a
|
||||
connected <constant>AF_UNIX</constant> socket and retrieve information about the connected peer process.
|
||||
Note that these fields are retrieved via <filename>/proc/</filename>, and hence are not suitable for
|
||||
authorization purposes, as they are subject to races.</para>
|
||||
<function>sd_peer_get_user_slice()</function>,
|
||||
<function>sd_peer_get_cgroup()</function>,
|
||||
<function>sd_peer_get_unit_cgroup()</function>, and
|
||||
<function>sd_peer_get_user_unit_cgroup()</function> calls operate similarly to their PIDFD counterparts,
|
||||
but accept a connected <constant>AF_UNIX</constant> socket and retrieve information about the connected
|
||||
peer process. On kernels that support <constant>SO_PEERPIDFD</constant> (Linux 6.5 or newer), these calls
|
||||
are not subject to recycle race conditions.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@@ -386,6 +442,12 @@
|
||||
<function>sd_pidfd_get_slice()</function>,
|
||||
<function>sd_pidfd_get_user_slice()</function>, and
|
||||
<function>sd_pidfd_get_cgroup()</function> were added in version 253.</para>
|
||||
<para><function>sd_pid_get_unit_cgroup()</function>,
|
||||
<function>sd_pid_get_user_unit_cgroup()</function>,
|
||||
<function>sd_pidfd_get_unit_cgroup()</function>,
|
||||
<function>sd_pidfd_get_user_unit_cgroup()</function>,
|
||||
<function>sd_peer_get_unit_cgroup()</function>, and
|
||||
<function>sd_peer_get_user_unit_cgroup()</function> were added in version 263.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
+230
-25
@@ -696,14 +696,14 @@ int cg_get_root_path(char **ret_path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted) {
|
||||
int cg_shift_path(const char *cgroup, const char *cached_root, const char **ret_shifted) {
|
||||
int r;
|
||||
|
||||
assert(cgroup);
|
||||
assert(ret_shifted);
|
||||
|
||||
_cleanup_free_ char *rt = NULL;
|
||||
if (!root) {
|
||||
if (!cached_root) {
|
||||
/* If the root was specified let's use that, otherwise
|
||||
* let's determine it from PID 1 */
|
||||
|
||||
@@ -711,14 +711,14 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
root = rt;
|
||||
cached_root = rt;
|
||||
}
|
||||
|
||||
*ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup;
|
||||
*ret_shifted = path_startswith_full(cgroup, cached_root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_pid_get_path_shifted(pid_t pid, const char *root, char **ret_cgroup) {
|
||||
int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **ret_cgroup) {
|
||||
_cleanup_free_ char *raw = NULL;
|
||||
const char *c;
|
||||
int r;
|
||||
@@ -730,7 +730,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **ret_cgroup) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_shift_path(raw, root, &c);
|
||||
r = cg_shift_path(raw, cached_root, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -742,7 +742,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **ret_cgroup) {
|
||||
return strdup_to(ret_cgroup, c);
|
||||
}
|
||||
|
||||
int cg_pidref_get_path_shifted(const PidRef *pidref, const char *root, char **ret_cgroup) {
|
||||
int cg_pidref_get_path_shifted(const PidRef *pidref, const char *cached_root, char **ret_cgroup) {
|
||||
_cleanup_free_ char *raw = NULL;
|
||||
const char *c;
|
||||
int r;
|
||||
@@ -753,7 +753,7 @@ int cg_pidref_get_path_shifted(const PidRef *pidref, const char *root, char **re
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_shift_path(raw, root, &c);
|
||||
r = cg_shift_path(raw, cached_root, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -765,21 +765,37 @@ int cg_pidref_get_path_shifted(const PidRef *pidref, const char *root, char **re
|
||||
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;
|
||||
@@ -1070,6 +1209,28 @@ int cg_pid_get_machine_name(pid_t pid, char **ret_machine) {
|
||||
return cg_path_get_machine_name(cgroup, ret_machine);
|
||||
}
|
||||
|
||||
int cg_pidref_get_machine_name(const PidRef *pidref, char **ret_machine) {
|
||||
int r;
|
||||
|
||||
if (!pidref_is_set(pidref))
|
||||
return -ESRCH;
|
||||
if (pidref_is_remote(pidref))
|
||||
return -EREMOTE;
|
||||
|
||||
_cleanup_free_ char *machine = NULL;
|
||||
r = cg_pid_get_machine_name(pidref->pid, &machine);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_verify(pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_machine)
|
||||
*ret_machine = TAKE_PTR(machine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_path_get_session(const char *path, char **ret_session) {
|
||||
_cleanup_free_ char *unit = NULL;
|
||||
char *start, *end;
|
||||
@@ -1232,6 +1393,28 @@ int cg_pid_get_slice(pid_t pid, char **ret_slice) {
|
||||
return cg_path_get_slice(cgroup, ret_slice);
|
||||
}
|
||||
|
||||
int cg_pidref_get_slice(const PidRef *pidref, char **ret_slice) {
|
||||
int r;
|
||||
|
||||
if (!pidref_is_set(pidref))
|
||||
return -ESRCH;
|
||||
if (pidref_is_remote(pidref))
|
||||
return -EREMOTE;
|
||||
|
||||
_cleanup_free_ char *slice = NULL;
|
||||
r = cg_pid_get_slice(pidref->pid, &slice);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_verify(pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_slice)
|
||||
*ret_slice = TAKE_PTR(slice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_path_get_user_slice(const char *p, char **ret_slice) {
|
||||
const char *t;
|
||||
assert(p);
|
||||
@@ -1256,6 +1439,28 @@ int cg_pid_get_user_slice(pid_t pid, char **ret_slice) {
|
||||
return cg_path_get_user_slice(cgroup, ret_slice);
|
||||
}
|
||||
|
||||
int cg_pidref_get_user_slice(const PidRef *pidref, char **ret_slice) {
|
||||
int r;
|
||||
|
||||
if (!pidref_is_set(pidref))
|
||||
return -ESRCH;
|
||||
if (pidref_is_remote(pidref))
|
||||
return -EREMOTE;
|
||||
|
||||
_cleanup_free_ char *slice = NULL;
|
||||
r = cg_pid_get_user_slice(pidref->pid, &slice);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_verify(pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_slice)
|
||||
*ret_slice = TAKE_PTR(slice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool cg_needs_escape(const char *p) {
|
||||
|
||||
/* Checks if the specified path is a valid cgroup name by our rules, or if it must be escaped. Note
|
||||
|
||||
@@ -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,21 +207,28 @@ 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_pidref_get_machine_name(const PidRef *pidref, char **ret_machine);
|
||||
int cg_pid_get_slice(pid_t pid, char **ret_slice);
|
||||
int cg_pidref_get_slice(const PidRef *pidref, char **ret_slice);
|
||||
int cg_pid_get_user_slice(pid_t pid, char **ret_slice);
|
||||
int cg_pidref_get_user_slice(const PidRef *pidref, char **ret_slice);
|
||||
|
||||
int cg_path_decode_unit(const char *cgroup, char **ret_unit);
|
||||
|
||||
|
||||
@@ -1121,4 +1121,10 @@ global:
|
||||
sd_varlink_invoke_and_upgrade;
|
||||
sd_varlink_invoke_and_upgradeb;
|
||||
sd_varlink_wants_reply;
|
||||
sd_pid_get_unit_cgroup;
|
||||
sd_pid_get_user_unit_cgroup;
|
||||
sd_pidfd_get_unit_cgroup;
|
||||
sd_pidfd_get_user_unit_cgroup;
|
||||
sd_peer_get_unit_cgroup;
|
||||
sd_peer_get_user_unit_cgroup;
|
||||
} LIBSYSTEMD_262;
|
||||
@@ -124,6 +124,38 @@ _public_ int sd_pid_get_cgroup(pid_t pid, char **ret_cgroup) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_pid_get_unit_cgroup(pid_t pid, char **ret_cgroup) {
|
||||
int r;
|
||||
|
||||
assert_return(pid >= 0, -EINVAL);
|
||||
|
||||
_cleanup_free_ char *c = NULL;
|
||||
r = cg_pid_get_unit_path(pid, &c);
|
||||
if (r < 0)
|
||||
return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
|
||||
|
||||
if (ret_cgroup)
|
||||
*ret_cgroup = TAKE_PTR(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_pid_get_user_unit_cgroup(pid_t pid, char **ret_cgroup) {
|
||||
int r;
|
||||
|
||||
assert_return(pid >= 0, -EINVAL);
|
||||
|
||||
_cleanup_free_ char *c = NULL;
|
||||
r = cg_pid_get_user_unit_path(pid, &c);
|
||||
if (r < 0)
|
||||
return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
|
||||
|
||||
if (ret_cgroup)
|
||||
*ret_cgroup = TAKE_PTR(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_pidfd_get_session(int pidfd, char **ret_session) {
|
||||
_cleanup_free_ char *session = NULL;
|
||||
pid_t pid;
|
||||
@@ -316,6 +348,54 @@ _public_ int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_pidfd_get_unit_cgroup(int pidfd, char **ret_cgroup) {
|
||||
_cleanup_free_ char *cgroup = NULL;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert_return(pidfd >= 0, -EBADF);
|
||||
|
||||
r = pidfd_get_pid(pidfd, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_pid_get_unit_cgroup(pid, &cgroup);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidfd_verify_pid(pidfd, pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_cgroup)
|
||||
*ret_cgroup = TAKE_PTR(cgroup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_pidfd_get_user_unit_cgroup(int pidfd, char **ret_cgroup) {
|
||||
_cleanup_free_ char *cgroup = NULL;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert_return(pidfd >= 0, -EBADF);
|
||||
|
||||
r = pidfd_get_pid(pidfd, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_pid_get_user_unit_cgroup(pid, &cgroup);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidfd_verify_pid(pidfd, pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_cgroup)
|
||||
*ret_cgroup = TAKE_PTR(cgroup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_session(int fd, char **ret_session) {
|
||||
int r;
|
||||
|
||||
@@ -356,55 +436,55 @@ _public_ int sd_peer_get_unit(int fd, char **ret_unit) {
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_user_unit(int fd, char **ret_unit) {
|
||||
struct ucred ucred;
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
r = getpeercred(fd, &ucred);
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = getpeerpidref(fd, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return cg_pid_get_user_unit(ucred.pid, ret_unit);
|
||||
return cg_pidref_get_user_unit(&pidref, ret_unit);
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_machine_name(int fd, char **ret_machine) {
|
||||
struct ucred ucred;
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
r = getpeercred(fd, &ucred);
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = getpeerpidref(fd, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return cg_pid_get_machine_name(ucred.pid, ret_machine);
|
||||
return cg_pidref_get_machine_name(&pidref, ret_machine);
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_slice(int fd, char **ret_slice) {
|
||||
struct ucred ucred;
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
r = getpeercred(fd, &ucred);
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = getpeerpidref(fd, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return cg_pid_get_slice(ucred.pid, ret_slice);
|
||||
return cg_pidref_get_slice(&pidref, ret_slice);
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_user_slice(int fd, char **ret_slice) {
|
||||
struct ucred ucred;
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
r = getpeercred(fd, &ucred);
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = getpeerpidref(fd, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return cg_pid_get_user_slice(ucred.pid, ret_slice);
|
||||
return cg_pidref_get_user_slice(&pidref, ret_slice);
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_cgroup(int fd, char **ret_cgroup) {
|
||||
@@ -437,6 +517,46 @@ _public_ int sd_peer_get_cgroup(int fd, char **ret_cgroup) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_unit_cgroup(int fd, char **ret_cgroup) {
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = getpeerpidref(fd, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *c = NULL;
|
||||
r = cg_pidref_get_unit_path(&pidref, &c);
|
||||
if (r < 0)
|
||||
return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
|
||||
|
||||
if (ret_cgroup)
|
||||
*ret_cgroup = TAKE_PTR(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_peer_get_user_unit_cgroup(int fd, char **ret_cgroup) {
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = getpeerpidref(fd, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *c = NULL;
|
||||
r = cg_pidref_get_user_unit_path(&pidref, &c);
|
||||
if (r < 0)
|
||||
return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
|
||||
|
||||
if (ret_cgroup)
|
||||
*ret_cgroup = TAKE_PTR(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int file_of_uid(uid_t uid, char **ret) {
|
||||
|
||||
assert_return(uid_is_valid(uid), -EINVAL);
|
||||
|
||||
@@ -45,7 +45,8 @@ TEST(login) {
|
||||
*display = NULL, *remote_user = NULL, *remote_host = NULL,
|
||||
*type = NULL, *class = NULL, *state = NULL, *state2 = NULL,
|
||||
*seat = NULL, *session = NULL,
|
||||
*unit = NULL, *user_unit = NULL, *slice = NULL;
|
||||
*unit = NULL, *user_unit = NULL, *slice = NULL,
|
||||
*unit_cgroup = NULL, *user_unit_cgroup = NULL;
|
||||
_cleanup_close_ int pidfd = -EBADF;
|
||||
int r;
|
||||
uid_t u, u2 = UID_INVALID;
|
||||
@@ -55,10 +56,18 @@ TEST(login) {
|
||||
log_info("sd_pid_get_unit(0, …) → %s / \"%s\"", e(r), strnull(unit));
|
||||
ASSERT_TRUE(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_unit_cgroup(/* pid= */ 0, &unit_cgroup);
|
||||
log_info("sd_pid_get_unit_cgroup(0, …) → %s / \"%s\"", e(r), strnull(unit_cgroup));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_user_unit(/* pid= */ 0, &user_unit);
|
||||
log_info("sd_pid_get_user_unit(0, …) → %s / \"%s\"", e(r), strnull(user_unit));
|
||||
ASSERT_TRUE(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_user_unit_cgroup(/* pid= */ 0, &user_unit_cgroup);
|
||||
log_info("sd_pid_get_user_unit_cgroup(0, …) → %s / \"%s\"", e(r), strnull(user_unit_cgroup));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
/* Coverage for https://github.com/systemd/systemd/issues/39949 */
|
||||
ASSERT_TRUE(!unit || !user_unit || !streq(unit, user_unit));
|
||||
|
||||
@@ -80,16 +89,25 @@ TEST(login) {
|
||||
pidfd = pidfd_open(getpid_cached(), /* flags= */ 0);
|
||||
if (pidfd >= 0) {
|
||||
_cleanup_free_ char *cgroup2 = NULL, *session2 = NULL,
|
||||
*unit2 = NULL, *user_unit2 = NULL, *slice2 = NULL;
|
||||
*unit2 = NULL, *user_unit2 = NULL, *slice2 = NULL,
|
||||
*unit_cgroup2 = NULL, *user_unit_cgroup2 = NULL;
|
||||
|
||||
r = sd_pidfd_get_unit(pidfd, &unit2);
|
||||
log_info("sd_pidfd_get_unit(pidfd, …) → %s / \"%s\"", e(r), strnull(unit2));
|
||||
ASSERT_TRUE(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pidfd_get_unit_cgroup(pidfd, &unit_cgroup2);
|
||||
log_info("sd_pidfd_get_unit_cgroup(pidfd, …) → %s / \"%s\"", e(r), strnull(unit_cgroup2));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pidfd_get_user_unit(pidfd, &user_unit2);
|
||||
log_info("sd_pidfd_get_user_unit(pidfd, …) → %s / \"%s\"", e(r), strnull(user_unit2));
|
||||
ASSERT_TRUE(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pidfd_get_user_unit_cgroup(pidfd, &user_unit_cgroup2);
|
||||
log_info("sd_pidfd_get_user_unit_cgroup(pidfd, …) → %s / \"%s\"", e(r), strnull(user_unit_cgroup2));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pidfd_get_slice(pidfd, &slice2);
|
||||
log_info("sd_pidfd_get_slice(pidfd, …) → %s / \"%s\"", e(r), strnull(slice2));
|
||||
ASSERT_TRUE(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
@@ -77,6 +77,16 @@ int sd_pid_get_machine_name(pid_t pid, char **ret_machine);
|
||||
* hierarchy. */
|
||||
int sd_pid_get_cgroup(pid_t pid, char **ret_cgroup);
|
||||
|
||||
/* Get systemd non-slice unit (i.e. service) control group from PID,
|
||||
* for system services. This will return an error for non-service
|
||||
* processes. */
|
||||
int sd_pid_get_unit_cgroup(pid_t pid, char **ret_cgroup);
|
||||
|
||||
/* Get systemd non-slice unit (i.e. service) control group from PID,
|
||||
* for user services. This will return an error for non-service
|
||||
* processes. */
|
||||
int sd_pid_get_user_unit_cgroup(pid_t pid, char **ret_cgroup);
|
||||
|
||||
/* Equivalent to the corresponding sd_pid_get* functions, but take a
|
||||
* PIDFD instead of a PID, to ensure there can be no possible PID
|
||||
* recycle issues before/after the calls. */
|
||||
@@ -88,6 +98,8 @@ int sd_pidfd_get_slice(int pidfd, char **ret_slice);
|
||||
int sd_pidfd_get_user_slice(int pidfd, char **ret_slice);
|
||||
int sd_pidfd_get_machine_name(int pidfd, char **ret_machine);
|
||||
int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup);
|
||||
int sd_pidfd_get_unit_cgroup(int pidfd, char **ret_cgroup);
|
||||
int sd_pidfd_get_user_unit_cgroup(int pidfd, char **ret_cgroup);
|
||||
|
||||
/* Similar to sd_pid_get_session(), but retrieves data about the peer
|
||||
* of a connected AF_UNIX socket */
|
||||
@@ -121,6 +133,14 @@ int sd_peer_get_machine_name(int fd, char **ret_machine);
|
||||
* of a connected AF_UNIX socket. */
|
||||
int sd_peer_get_cgroup(int fd, char **ret_cgroup);
|
||||
|
||||
/* Similar to sd_pid_get_unit_cgroup(), but retrieves data about the peer
|
||||
* of a connected AF_UNIX socket. */
|
||||
int sd_peer_get_unit_cgroup(int fd, char **ret_cgroup);
|
||||
|
||||
/* Similar to sd_pid_get_user_unit_cgroup(), but retrieves data about the peer
|
||||
* of a connected AF_UNIX socket. */
|
||||
int sd_peer_get_user_unit_cgroup(int fd, char **ret_cgroup);
|
||||
|
||||
/* Get state from UID. Possible states: offline, lingering, online, active, closing */
|
||||
int sd_uid_get_state(uid_t uid, char **ret_state);
|
||||
|
||||
|
||||
@@ -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