Merge pull request #1140 from poettering/sd-event-signals

A variety of sd-event, sd-login and cgroup fixes
This commit is contained in:
David Herrmann 2015-09-05 15:20:21 +02:00
commit 17258f5f27
30 changed files with 952 additions and 341 deletions

View File

@ -1937,6 +1937,7 @@ MANPAGES_ALIAS += \
man/sd_login_monitor_get_fd.3 \
man/sd_login_monitor_get_timeout.3 \
man/sd_login_monitor_unref.3 \
man/sd_peer_get_cgroup.3 \
man/sd_peer_get_machine_name.3 \
man/sd_peer_get_owner_uid.3 \
man/sd_peer_get_session.3 \
@ -1944,6 +1945,7 @@ MANPAGES_ALIAS += \
man/sd_peer_get_unit.3 \
man/sd_peer_get_user_slice.3 \
man/sd_peer_get_user_unit.3 \
man/sd_pid_get_cgroup.3 \
man/sd_pid_get_machine_name.3 \
man/sd_pid_get_owner_uid.3 \
man/sd_pid_get_slice.3 \
@ -1981,6 +1983,7 @@ man/sd_login_monitor_get_events.3: man/sd_login_monitor_new.3
man/sd_login_monitor_get_fd.3: man/sd_login_monitor_new.3
man/sd_login_monitor_get_timeout.3: man/sd_login_monitor_new.3
man/sd_login_monitor_unref.3: man/sd_login_monitor_new.3
man/sd_peer_get_cgroup.3: man/sd_pid_get_session.3
man/sd_peer_get_machine_name.3: man/sd_pid_get_session.3
man/sd_peer_get_owner_uid.3: man/sd_pid_get_session.3
man/sd_peer_get_session.3: man/sd_pid_get_session.3
@ -1988,6 +1991,7 @@ man/sd_peer_get_slice.3: man/sd_pid_get_session.3
man/sd_peer_get_unit.3: man/sd_pid_get_session.3
man/sd_peer_get_user_slice.3: man/sd_pid_get_session.3
man/sd_peer_get_user_unit.3: man/sd_pid_get_session.3
man/sd_pid_get_cgroup.3: man/sd_pid_get_session.3
man/sd_pid_get_machine_name.3: man/sd_pid_get_session.3
man/sd_pid_get_owner_uid.3: man/sd_pid_get_session.3
man/sd_pid_get_slice.3: man/sd_pid_get_session.3
@ -2043,6 +2047,9 @@ man/sd_login_monitor_get_timeout.html: man/sd_login_monitor_new.html
man/sd_login_monitor_unref.html: man/sd_login_monitor_new.html
$(html-alias)
man/sd_peer_get_cgroup.html: man/sd_pid_get_session.html
$(html-alias)
man/sd_peer_get_machine_name.html: man/sd_pid_get_session.html
$(html-alias)
@ -2064,6 +2071,9 @@ man/sd_peer_get_user_slice.html: man/sd_pid_get_session.html
man/sd_peer_get_user_unit.html: man/sd_pid_get_session.html
$(html-alias)
man/sd_pid_get_cgroup.html: man/sd_pid_get_session.html
$(html-alias)
man/sd_pid_get_machine_name.html: man/sd_pid_get_session.html
$(html-alias)

View File

@ -111,8 +111,8 @@
<para>Here's an example <filename>/etc/nsswitch.conf</filename>
file, that enables <command>myhostname</command> correctly:</para>
<programlisting>passwd: compat
group: compat
<programlisting>passwd: compat mymachines
group: compat mymachines
shadow: compat
hosts: files resolve mymachines <command>myhostname</command>

View File

@ -82,8 +82,8 @@
<para>Here's an example <filename>/etc/nsswitch.conf</filename>
file, that enables <command>resolve</command> correctly:</para>
<programlisting>passwd: compat
group: compat
<programlisting>passwd: compat mymachines
group: compat mymachines
shadow: compat
hosts: files <command>resolve</command> mymachines myhostname

View File

@ -115,6 +115,29 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -161,20 +161,20 @@
is no timeout to wait for this will fill in <constant>(uint64_t)
-1</constant> instead. Note that <function>poll()</function> takes
a relative timeout in milliseconds rather than an absolute timeout
in microseconds. To convert the absolute 'us' timeout into
in microseconds. To convert the absolute 'µs' timeout into
relative 'ms', use code like the following:</para>
<programlisting>uint64_t t;
int msec;
sd_login_monitor_get_timeout(m, &amp;t);
if (t == (uint64_t) -1)
msec = -1;
msec = -1;
else {
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
}</programlisting>
<para>The code above does not do any error checking for brevity's
@ -203,6 +203,29 @@ else {
always returns <constant>NULL</constant>.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted). The specified category to
watch is not known.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -56,7 +56,7 @@
<funcprototype>
<funcdef>int <function>sd_machine_get_class</function></funcdef>
<paramdef>const char* <parameter>machine</parameter></paramdef>
<paramdef>char *<parameter>class</parameter></paramdef>
<paramdef>char **<parameter>class</parameter></paramdef>
</funcprototype>
<funcprototype>
@ -98,6 +98,35 @@
code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified machine does not exist or is currently not running.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -50,6 +50,7 @@
<refname>sd_pid_get_machine_name</refname>
<refname>sd_pid_get_slice</refname>
<refname>sd_pid_get_user_slice</refname>
<refname>sd_pid_get_cgroup</refname>
<refname>sd_peer_get_session</refname>
<refname>sd_peer_get_unit</refname>
<refname>sd_peer_get_user_unit</refname>
@ -57,6 +58,7 @@
<refname>sd_peer_get_machine_name</refname>
<refname>sd_peer_get_slice</refname>
<refname>sd_peer_get_user_slice</refname>
<refname>sd_peer_get_cgroup</refname>
<refpurpose>Determine session, unit, owner of a session,
container/VM or slice of a specific PID or socket
peer</refpurpose>
@ -108,6 +110,12 @@
<paramdef>char **<parameter>slice</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_pid_get_cgroup</function></funcdef>
<paramdef>pid_t <parameter>pid</parameter></paramdef>
<paramdef>char **<parameter>cgroup</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_peer_get_session</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
@ -149,6 +157,12 @@
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>char **<parameter>slice</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_peer_get_cgroup</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>char **<parameter>cgroup</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@ -163,7 +177,7 @@
processes, user processes that are shared between multiple
sessions of the same user, or kernel threads). For processes not
being part of a login session this function will fail with
-ENXIO. The returned string needs to be freed with the libc
-ENODATA. 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>
@ -175,9 +189,9 @@
paths. Note that not all processes are part of a system
unit/service (e.g. user processes, or kernel threads). For
processes not being part of a systemd system unit this function
will fail with -ENXIO (More specifically: this call will not work
for kernel threads.) The returned string needs to be freed with
the libc <citerefentry
will fail with -ENODATA (More specifically: this call will not
work for kernel threads.) 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>
@ -194,7 +208,7 @@
multiple login sessions of the same user, where
<function>sd_pid_get_session()</function> will fail. For processes
not being part of a login session and not being a shared process
of a user this function will fail with -ENXIO.</para>
of a user this function will fail with -ENODATA.</para>
<para><function>sd_pid_get_machine_name()</function> may be used
to determine the name of the VM or container is a member of. The
@ -203,7 +217,7 @@
<citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use. For processes not part of a VM or containers this
function fails with -ENXIO.</para>
function fails with -ENODATA.</para>
<para><function>sd_pid_get_slice()</function> may be used to
determine the slice unit the process is a member of. See
@ -217,6 +231,17 @@
returns the user slice (as managed by the user's systemd instance)
of a process.</para>
<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> (if the unified control group
setup is used), or
<filename>/sys/fs/cgroup/<replaceable>HIERARCHY</replaceable>/</filename>
(if the legacy multi-hierarchy control group setup is used).</para>
<para>If the <varname>pid</varname> parameter of any of these
functions is passed as 0, the operation is executed for the
calling process.</para>
@ -226,13 +251,14 @@
<function>sd_peer_get_user_unit()</function>,
<function>sd_peer_get_owner_uid()</function>,
<function>sd_peer_get_machine_name()</function>,
<function>sd_peer_get_slice()</function> and
<function>sd_peer_get_user_slice()</function> calls operate
similar to their PID counterparts, but operate on a connected
AF_UNIX 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_slice()</function>,
<function>sd_peer_get_user_slice()</function> and
<function>sd_peer_get_cgroup()</function> calls operate similar to
their PID counterparts, but operate on a connected AF_UNIX 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>
</refsect1>
<refsect1>
@ -251,7 +277,22 @@
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<term><constant>-ESRCH</constant></term>
<listitem><para>The specified PID does not refer to a running
process.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-BADF</constant></term>
<listitem><para>The specified socket file descriptor was
invalid.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
process or peer.</para>
@ -259,11 +300,10 @@
</varlistentry>
<varlistentry>
<term><constant>-ESRCH</constant></term>
<term><constant>-EINVAL</constant></term>
<listitem><para>The specified PID does not refer to a running
process.</para>
</listitem>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -148,6 +148,43 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
seat.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified seat is unknown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -289,6 +289,43 @@
negative errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified session does not exist.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
session.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -169,6 +169,45 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
user.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified seat is unknown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted). This is also returned if
the passed user ID is 0xFFFF or 0xFFFFFFFF, which are
undefined on Linux.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -36,6 +36,11 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
assert(id);
/* We don't convert ENOENT to ESRCH here, since we can't
* really distuingish between "audit is not available in the
* kernel" and "the process does not exist", both which will
* result in ENOENT. */
p = procfs_file_alloca(pid, "sessionid");
r = read_one_line_file(p, &s);
@ -47,7 +52,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
return r;
if (u == AUDIT_SESSION_INVALID || u <= 0)
return -ENXIO;
return -ENODATA;
*id = u;
return 0;
@ -68,6 +73,8 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
return r;
r = parse_uid(s, &u);
if (r == -ENXIO) /* the UID was -1 */
return -ENODATA;
if (r < 0)
return r;

View File

@ -187,7 +187,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
if (ignore_self && pid == my_pid)
continue;
if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
continue;
/* If we haven't killed this process yet, kill
@ -205,7 +205,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
done = false;
r = set_put(s, LONG_TO_PTR(pid));
r = set_put(s, PID_TO_PTR(pid));
if (r < 0) {
if (ret >= 0)
return r;
@ -318,7 +318,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
if (ignore_self && pid == my_pid)
continue;
if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
continue;
/* Ignore kernel threads. Since they can only
@ -338,7 +338,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
done = false;
r = set_put(s, LONG_TO_PTR(pid));
r = set_put(s, PID_TO_PTR(pid));
if (r < 0) {
if (ret >= 0)
return r;
@ -460,20 +460,23 @@ static const char *controller_to_dirname(const char *controller) {
return controller;
}
static int join_path_legacy(const char *controller_dn, const char *path, const char *suffix, char **fs) {
static int join_path_legacy(const char *controller, const char *path, const char *suffix, char **fs) {
const char *dn;
char *t = NULL;
assert(fs);
assert(controller_dn);
assert(controller);
dn = controller_to_dirname(controller);
if (isempty(path) && isempty(suffix))
t = strappend("/sys/fs/cgroup/", controller_dn);
t = strappend("/sys/fs/cgroup/", dn);
else if (isempty(path))
t = strjoin("/sys/fs/cgroup/", controller_dn, "/", suffix, NULL);
t = strjoin("/sys/fs/cgroup/", dn, "/", suffix, NULL);
else if (isempty(suffix))
t = strjoin("/sys/fs/cgroup/", controller_dn, "/", path, NULL);
t = strjoin("/sys/fs/cgroup/", dn, "/", path, NULL);
else
t = strjoin("/sys/fs/cgroup/", controller_dn, "/", path, "/", suffix, NULL);
t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix, NULL);
if (!t)
return -ENOMEM;
@ -509,15 +512,15 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (!controller) {
char *t;
/* If no controller is specified, we assume only the
* path below the controller matters */
/* If no controller is specified, we return the path
* *below* the controllers, without any prefix. */
if (!path && !suffix)
return -EINVAL;
if (isempty(suffix))
if (!suffix)
t = strdup(path);
else if (isempty(path))
else if (!path)
t = strdup(suffix);
else
t = strjoin(path, "/", suffix, NULL);
@ -537,14 +540,8 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (unified > 0)
r = join_path_unified(path, suffix, fs);
else {
const char *dn;
dn = controller_to_dirname(controller);
r = join_path_legacy(dn, path, suffix, fs);
}
else
r = join_path_legacy(controller, path, suffix, fs);
if (r < 0)
return r;
@ -873,7 +870,7 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
return 0;
}
return -ENOENT;
return -ENODATA;
}
int cg_install_release_agent(const char *controller, const char *agent) {
@ -902,7 +899,7 @@ int cg_install_release_agent(const char *controller, const char *agent) {
r = write_string_file(fs, agent, 0);
if (r < 0)
return r;
} else if (!streq(sc, agent))
} else if (!path_equal(sc, agent))
return -EEXIST;
fs = mfree(fs);
@ -1005,6 +1002,8 @@ int cg_is_empty_recursive(const char *controller, const char *path) {
return r;
r = read_one_line_file(populated, &t);
if (r == -ENOENT)
return 1;
if (r < 0)
return r;
@ -1898,7 +1897,7 @@ int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids,
int r = 0;
SET_FOREACH(pidp, pids, i) {
pid_t pid = PTR_TO_LONG(pidp);
pid_t pid = PTR_TO_PID(pidp);
int q;
q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
@ -1911,7 +1910,7 @@ int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids,
int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
CGroupController c;
int r, unified;
int r = 0, unified;
if (!path_equal(from, to)) {
r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
@ -1982,14 +1981,22 @@ int cg_mask_supported(CGroupMask *ret) {
if (unified < 0)
return unified;
if (unified > 0) {
_cleanup_free_ char *controllers = NULL;
_cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
const char *c;
/* In the unified hierarchy we can read the supported
* and accessible controllers from a the top-level
* cgroup attribute */
r = read_one_line_file("/sys/fs/cgroup/cgroup.controllers", &controllers);
r = cg_get_root_path(&root);
if (r < 0)
return r;
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
if (r < 0)
return r;
r = read_one_line_file(path, &controllers);
if (r < 0)
return r;
@ -2156,7 +2163,7 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
r = write_string_file(fs, s, 0);
if (r < 0)
log_warning_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
}
}

View File

@ -298,6 +298,9 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
#define memzero(x,l) (memset((x), 0, (l)))
#define zero(x) (memzero(&(x), sizeof(x)))

View File

@ -373,6 +373,19 @@ int parse_pid(const char *s, pid_t* ret_pid) {
return 0;
}
bool uid_is_valid(uid_t uid) {
/* Some libc APIs use UID_INVALID as special placeholder */
if (uid == (uid_t) 0xFFFFFFFF)
return false;
/* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
if (uid == (uid_t) 0xFFFF)
return false;
return true;
}
int parse_uid(const char *s, uid_t* ret_uid) {
unsigned long ul = 0;
uid_t uid;
@ -389,13 +402,11 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if ((unsigned long) uid != ul)
return -ERANGE;
/* Some libc APIs use UID_INVALID as special placeholder */
if (uid == (uid_t) 0xFFFFFFFF)
return -ENXIO;
/* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
if (uid == (uid_t) 0xFFFF)
return -ENXIO;
if (!uid_is_valid(uid))
return -ENXIO; /* we return ENXIO instead of EINVAL
* here, to make it easy to distuingish
* invalid numeric uids invalid
* strings. */
if (ret_uid)
*ret_uid = uid;

View File

@ -154,7 +154,10 @@ int parse_size(const char *t, off_t base, off_t *size);
int parse_boolean(const char *v) _pure_;
int parse_pid(const char *s, pid_t* ret_pid);
int parse_uid(const char *s, uid_t* ret_uid);
#define parse_gid(s, ret_uid) parse_uid(s, ret_uid)
#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
bool uid_is_valid(uid_t uid);
#define gid_is_valid(gid) uid_is_valid(gid)
int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);

View File

@ -507,15 +507,20 @@ CGroupMask unit_get_own_mask(Unit *u) {
return 0;
/* If delegation is turned on, then turn on all cgroups,
* unless the process we fork into it is known to drop
* privileges anyway, and shouldn't get access to the
* controllers anyway. */
* unless we are on the legacy hierarchy and the process we
* fork into it is known to drop privileges, and hence
* shouldn't get access to the controllers.
*
* Note that on the unified hierarchy it is safe to delegate
* controllers to unprivileged services. */
if (c->delegate) {
ExecContext *e;
e = unit_get_exec_context(u);
if (!e || exec_context_maintains_privileges(e))
if (!e ||
exec_context_maintains_privileges(e) ||
cg_unified() > 0)
return _CGROUP_MASK_ALL;
}
@ -1378,32 +1383,42 @@ Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
}
}
Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid) {
_cleanup_free_ char *cgroup = NULL;
Unit *u;
int r;
assert(m);
if (pid <= 0)
return NULL;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return NULL;
return manager_get_unit_by_cgroup(m, cgroup);
}
Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
Unit *u;
assert(m);
if (pid <= 0)
return NULL;
if (pid == 1)
return hashmap_get(m->units, SPECIAL_INIT_SCOPE);
u = hashmap_get(m->watch_pids1, LONG_TO_PTR(pid));
u = hashmap_get(m->watch_pids1, PID_TO_PTR(pid));
if (u)
return u;
u = hashmap_get(m->watch_pids2, LONG_TO_PTR(pid));
u = hashmap_get(m->watch_pids2, PID_TO_PTR(pid));
if (u)
return u;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return NULL;
return manager_get_unit_by_cgroup(m, cgroup);
return manager_get_unit_by_pid_cgroup(m, pid);
}
int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {

View File

@ -130,6 +130,7 @@ void manager_shutdown_cgroup(Manager *m, bool delete);
unsigned manager_dispatch_cgroup_queue(Manager *m);
Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup);
Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid);
Unit* manager_get_unit_by_pid(Manager *m, pid_t pid);
int unit_search_main_pid(Unit *u, pid_t *ret);

View File

@ -108,7 +108,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
return;
}
set_remove(pids, ULONG_TO_PTR(pid));
(void) set_remove(pids, PID_TO_PTR(pid));
}
/* Now explicitly check who might be remaining, who
@ -117,7 +117,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
/* We misuse getpgid as a check whether a
* process still exists. */
if (getpgid((pid_t) PTR_TO_ULONG(p)) >= 0)
if (getpgid(PTR_TO_PID(p)) >= 0)
continue;
if (errno != ESRCH)
@ -179,7 +179,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
if (kill(pid, sig) >= 0) {
if (pids) {
r = set_put(pids, ULONG_TO_PTR(pid));
r = set_put(pids, PID_TO_PTR(pid));
if (r < 0)
log_oom();
}

View File

@ -1585,19 +1585,19 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
/* Notify every unit that might be interested, but try
* to avoid notifying the same one multiple times. */
u1 = manager_get_unit_by_pid(m, ucred->pid);
u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
if (u1) {
manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
found = true;
}
u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid));
u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
if (u2 && u2 != u1) {
manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
found = true;
}
u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid));
u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
if (u3 && u3 != u2 && u3 != u1) {
manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
found = true;
@ -1663,13 +1663,13 @@ static int manager_dispatch_sigchld(Manager *m) {
/* And now figure out the unit this belongs
* to, it might be multiple... */
u1 = manager_get_unit_by_pid(m, si.si_pid);
u1 = manager_get_unit_by_pid_cgroup(m, si.si_pid);
if (u1)
invoke_sigchld_event(m, u1, &si);
u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid));
u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(si.si_pid));
if (u2 && u2 != u1)
invoke_sigchld_event(m, u2, &si);
u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid));
u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(si.si_pid));
if (u3 && u3 != u2 && u3 != u1)
invoke_sigchld_event(m, u3, &si);
}

View File

@ -1995,16 +1995,16 @@ int unit_watch_pid(Unit *u, pid_t pid) {
if (r < 0)
return r;
r = hashmap_put(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
r = hashmap_put(u->manager->watch_pids1, PID_TO_PTR(pid), u);
if (r == -EEXIST) {
r = hashmap_ensure_allocated(&u->manager->watch_pids2, NULL);
if (r < 0)
return r;
r = hashmap_put(u->manager->watch_pids2, LONG_TO_PTR(pid), u);
r = hashmap_put(u->manager->watch_pids2, PID_TO_PTR(pid), u);
}
q = set_put(u->pids, LONG_TO_PTR(pid));
q = set_put(u->pids, PID_TO_PTR(pid));
if (q < 0)
return q;
@ -2015,16 +2015,16 @@ void unit_unwatch_pid(Unit *u, pid_t pid) {
assert(u);
assert(pid >= 1);
(void) hashmap_remove_value(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
(void) hashmap_remove_value(u->manager->watch_pids2, LONG_TO_PTR(pid), u);
(void) set_remove(u->pids, LONG_TO_PTR(pid));
(void) hashmap_remove_value(u->manager->watch_pids1, PID_TO_PTR(pid), u);
(void) hashmap_remove_value(u->manager->watch_pids2, PID_TO_PTR(pid), u);
(void) set_remove(u->pids, PID_TO_PTR(pid));
}
void unit_unwatch_all_pids(Unit *u) {
assert(u);
while (!set_isempty(u->pids))
unit_unwatch_pid(u, PTR_TO_LONG(set_first(u->pids)));
unit_unwatch_pid(u, PTR_TO_PID(set_first(u->pids)));
u->pids = set_free(u->pids);
}
@ -2038,7 +2038,7 @@ void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) {
/* Cleans dead PIDs from our list */
SET_FOREACH(e, u->pids, i) {
pid_t pid = PTR_TO_LONG(e);
pid_t pid = PTR_TO_PID(e);
if (pid == except1 || pid == except2)
continue;
@ -2993,13 +2993,13 @@ static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
/* Exclude the main/control pids from being killed via the cgroup */
if (main_pid > 0) {
r = set_put(pid_set, LONG_TO_PTR(main_pid));
r = set_put(pid_set, PID_TO_PTR(main_pid));
if (r < 0)
goto fail;
}
if (control_pid > 0) {
r = set_put(pid_set, LONG_TO_PTR(control_pid));
r = set_put(pid_set, PID_TO_PTR(control_pid));
if (r < 0)
goto fail;
}

View File

@ -467,3 +467,9 @@ global:
sd_bus_emit_object_removed;
sd_bus_flush_close_unref;
} LIBSYSTEMD_221;
LIBSYSTEMD_226 {
global:
sd_pid_get_cgroup;
sd_peer_get_cgroup;
} LIBSYSTEMD_222;

View File

@ -1062,8 +1062,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
r = audit_session_from_pid(pid, &c->audit_session_id);
if (r == -ENXIO) {
/* ENXIO means: no audit session id assigned */
if (r == -ENODATA) {
/* ENODATA means: no audit session id assigned */
c->audit_session_id = AUDIT_SESSION_INVALID;
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
} else if (r < 0) {
@ -1075,8 +1075,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
if (r == -ENXIO) {
/* ENXIO means: no audit login uid assigned */
if (r == -ENODATA) {
/* ENODATA means: no audit login uid assigned */
c->audit_login_uid = UID_INVALID;
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
} else if (r < 0) {

View File

@ -56,9 +56,22 @@ typedef enum EventSourceType {
_SOURCE_EVENT_SOURCE_TYPE_INVALID = -1
} EventSourceType;
/* All objects we use in epoll events start with this value, so that
* we know how to dispatch it */
typedef enum WakeupType {
WAKEUP_NONE,
WAKEUP_EVENT_SOURCE,
WAKEUP_CLOCK_DATA,
WAKEUP_SIGNAL_DATA,
_WAKEUP_TYPE_MAX,
_WAKEUP_TYPE_INVALID = -1,
} WakeupType;
#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
struct sd_event_source {
WakeupType wakeup;
unsigned n_ref;
sd_event *event;
@ -120,6 +133,7 @@ struct sd_event_source {
};
struct clock_data {
WakeupType wakeup;
int fd;
/* For all clocks we maintain two priority queues each, one
@ -136,11 +150,23 @@ struct clock_data {
bool needs_rearm:1;
};
struct signal_data {
WakeupType wakeup;
/* For each priority we maintain one signal fd, so that we
* only have to dequeue a single event per priority at a
* time. */
int fd;
int64_t priority;
sigset_t sigset;
sd_event_source *current;
};
struct sd_event {
unsigned n_ref;
int epoll_fd;
int signal_fd;
int watchdog_fd;
Prioq *pending;
@ -157,8 +183,8 @@ struct sd_event {
usec_t perturb;
sigset_t sigset;
sd_event_source **signal_sources;
sd_event_source **signal_sources; /* indexed by signal number */
Hashmap *signal_data; /* indexed by priority */
Hashmap *child_sources;
unsigned n_enabled_child_sources;
@ -355,6 +381,7 @@ static int exit_prioq_compare(const void *a, const void *b) {
static void free_clock_data(struct clock_data *d) {
assert(d);
assert(d->wakeup == WAKEUP_CLOCK_DATA);
safe_close(d->fd);
prioq_free(d->earliest);
@ -378,7 +405,6 @@ static void event_free(sd_event *e) {
*(e->default_event_ptr) = NULL;
safe_close(e->epoll_fd);
safe_close(e->signal_fd);
safe_close(e->watchdog_fd);
free_clock_data(&e->realtime);
@ -392,6 +418,7 @@ static void event_free(sd_event *e) {
prioq_free(e->exit);
free(e->signal_sources);
hashmap_free(e->signal_data);
hashmap_free(e->child_sources);
set_free(e->post_sources);
@ -409,13 +436,12 @@ _public_ int sd_event_new(sd_event** ret) {
return -ENOMEM;
e->n_ref = 1;
e->signal_fd = e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY;
e->realtime.wakeup = e->boottime.wakeup = e->monotonic.wakeup = e->realtime_alarm.wakeup = e->boottime_alarm.wakeup = WAKEUP_CLOCK_DATA;
e->original_pid = getpid();
e->perturb = USEC_INFINITY;
assert_se(sigemptyset(&e->sigset) == 0);
e->pending = prioq_new(pending_prioq_compare);
if (!e->pending) {
r = -ENOMEM;
@ -509,7 +535,6 @@ static int source_io_register(
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
else
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
if (r < 0)
return -errno;
@ -591,45 +616,171 @@ static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) {
}
}
static bool need_signal(sd_event *e, int signal) {
return (e->signal_sources && e->signal_sources[signal] &&
e->signal_sources[signal]->enabled != SD_EVENT_OFF)
||
(signal == SIGCHLD &&
e->n_enabled_child_sources > 0);
}
static int event_make_signal_data(
sd_event *e,
int sig,
struct signal_data **ret) {
static int event_update_signal_fd(sd_event *e) {
struct epoll_event ev = {};
bool add_to_epoll;
struct signal_data *d;
bool added = false;
sigset_t ss_copy;
int64_t priority;
int r;
assert(e);
if (event_pid_changed(e))
return 0;
return -ECHILD;
add_to_epoll = e->signal_fd < 0;
if (e->signal_sources && e->signal_sources[sig])
priority = e->signal_sources[sig]->priority;
else
priority = 0;
r = signalfd(e->signal_fd, &e->sigset, SFD_NONBLOCK|SFD_CLOEXEC);
if (r < 0)
return -errno;
d = hashmap_get(e->signal_data, &priority);
if (d) {
if (sigismember(&d->sigset, sig) > 0) {
if (ret)
*ret = d;
return 0;
}
} else {
r = hashmap_ensure_allocated(&e->signal_data, &uint64_hash_ops);
if (r < 0)
return r;
e->signal_fd = r;
d = new0(struct signal_data, 1);
if (!d)
return -ENOMEM;
if (!add_to_epoll)
return 0;
d->wakeup = WAKEUP_SIGNAL_DATA;
d->fd = -1;
d->priority = priority;
ev.events = EPOLLIN;
ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL);
r = hashmap_put(e->signal_data, &d->priority, d);
if (r < 0)
return r;
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev);
if (r < 0) {
e->signal_fd = safe_close(e->signal_fd);
return -errno;
added = true;
}
ss_copy = d->sigset;
assert_se(sigaddset(&ss_copy, sig) >= 0);
r = signalfd(d->fd, &ss_copy, SFD_NONBLOCK|SFD_CLOEXEC);
if (r < 0) {
r = -errno;
goto fail;
}
d->sigset = ss_copy;
if (d->fd >= 0) {
if (ret)
*ret = d;
return 0;
}
d->fd = r;
ev.events = EPOLLIN;
ev.data.ptr = d;
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev);
if (r < 0) {
r = -errno;
goto fail;
}
if (ret)
*ret = d;
return 0;
fail:
if (added) {
d->fd = safe_close(d->fd);
hashmap_remove(e->signal_data, &d->priority);
free(d);
}
return r;
}
static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig) {
assert(e);
assert(d);
/* Turns off the specified signal in the signal data
* object. If the signal mask of the object becomes empty that
* way removes it. */
if (sigismember(&d->sigset, sig) == 0)
return;
assert_se(sigdelset(&d->sigset, sig) >= 0);
if (sigisemptyset(&d->sigset)) {
/* If all the mask is all-zero we can get rid of the structure */
hashmap_remove(e->signal_data, &d->priority);
assert(!d->current);
safe_close(d->fd);
free(d);
return;
}
assert(d->fd >= 0);
if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0)
log_debug_errno(errno, "Failed to unset signal bit, ignoring: %m");
}
static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) {
struct signal_data *d;
static const int64_t zero_priority = 0;
assert(e);
/* Rechecks if the specified signal is still something we are
* interested in. If not, we'll unmask it, and possibly drop
* the signalfd for it. */
if (sig == SIGCHLD &&
e->n_enabled_child_sources > 0)
return;
if (e->signal_sources &&
e->signal_sources[sig] &&
e->signal_sources[sig]->enabled != SD_EVENT_OFF)
return;
/*
* The specified signal might be enabled in three different queues:
*
* 1) the one that belongs to the priority passed (if it is non-NULL)
* 2) the one that belongs to the priority of the event source of the signal (if there is one)
* 3) the 0 priority (to cover the SIGCHLD case)
*
* Hence, let's remove it from all three here.
*/
if (priority) {
d = hashmap_get(e->signal_data, priority);
if (d)
event_unmask_signal_data(e, d, sig);
}
if (e->signal_sources && e->signal_sources[sig]) {
d = hashmap_get(e->signal_data, &e->signal_sources[sig]->priority);
if (d)
event_unmask_signal_data(e, d, sig);
}
d = hashmap_get(e->signal_data, &zero_priority);
if (d)
event_unmask_signal_data(e, d, sig);
}
static void source_disconnect(sd_event_source *s) {
@ -668,17 +819,11 @@ static void source_disconnect(sd_event_source *s) {
case SOURCE_SIGNAL:
if (s->signal.sig > 0) {
if (s->event->signal_sources)
s->event->signal_sources[s->signal.sig] = NULL;
/* If the signal was on and now it is off... */
if (s->enabled != SD_EVENT_OFF && !need_signal(s->event, s->signal.sig)) {
assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
(void) event_update_signal_fd(s->event);
/* If disabling failed, we might get a spurious event,
* but otherwise nothing bad should happen. */
}
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
}
break;
@ -688,18 +833,10 @@ static void source_disconnect(sd_event_source *s) {
if (s->enabled != SD_EVENT_OFF) {
assert(s->event->n_enabled_child_sources > 0);
s->event->n_enabled_child_sources--;
/* We know the signal was on, if it is off now... */
if (!need_signal(s->event, SIGCHLD)) {
assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
(void) event_update_signal_fd(s->event);
/* If disabling failed, we might get a spurious event,
* but otherwise nothing bad should happen. */
}
}
hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
(void) hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
}
break;
@ -778,6 +915,14 @@ static int source_set_pending(sd_event_source *s, bool b) {
d->needs_rearm = true;
}
if (s->type == SOURCE_SIGNAL && !b) {
struct signal_data *d;
d = hashmap_get(s->event->signal_data, &s->priority);
if (d && d->current == s)
d->current = NULL;
}
return 0;
}
@ -827,6 +972,7 @@ _public_ int sd_event_add_io(
if (!s)
return -ENOMEM;
s->wakeup = WAKEUP_EVENT_SOURCE;
s->io.fd = fd;
s->io.events = events;
s->io.callback = callback;
@ -883,7 +1029,7 @@ static int event_setup_timer_fd(
return -errno;
ev.events = EPOLLIN;
ev.data.ptr = INT_TO_PTR(clock_to_event_source_type(clock));
ev.data.ptr = d;
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
if (r < 0) {
@ -993,9 +1139,9 @@ _public_ int sd_event_add_signal(
void *userdata) {
sd_event_source *s;
struct signal_data *d;
sigset_t ss;
int r;
bool previous;
assert_return(e, -EINVAL);
assert_return(sig > 0, -EINVAL);
@ -1020,8 +1166,6 @@ _public_ int sd_event_add_signal(
} else if (e->signal_sources[sig])
return -EBUSY;
previous = need_signal(e, sig);
s = source_new(e, !ret, SOURCE_SIGNAL);
if (!s)
return -ENOMEM;
@ -1033,14 +1177,10 @@ _public_ int sd_event_add_signal(
e->signal_sources[sig] = s;
if (!previous) {
assert_se(sigaddset(&e->sigset, sig) == 0);
r = event_update_signal_fd(e);
if (r < 0) {
source_free(s);
return r;
}
r = event_make_signal_data(e, sig, &d);
if (r < 0) {
source_free(s);
return r;
}
/* Use the signal name as description for the event source by default */
@ -1062,7 +1202,6 @@ _public_ int sd_event_add_child(
sd_event_source *s;
int r;
bool previous;
assert_return(e, -EINVAL);
assert_return(pid > 1, -EINVAL);
@ -1079,8 +1218,6 @@ _public_ int sd_event_add_child(
if (hashmap_contains(e->child_sources, INT_TO_PTR(pid)))
return -EBUSY;
previous = need_signal(e, SIGCHLD);
s = source_new(e, !ret, SOURCE_CHILD);
if (!s)
return -ENOMEM;
@ -1099,14 +1236,11 @@ _public_ int sd_event_add_child(
e->n_enabled_child_sources ++;
if (!previous) {
assert_se(sigaddset(&e->sigset, SIGCHLD) == 0);
r = event_update_signal_fd(e);
if (r < 0) {
source_free(s);
return r;
}
r = event_make_signal_data(e, SIGCHLD, NULL);
if (r < 0) {
e->n_enabled_child_sources--;
source_free(s);
return r;
}
e->need_process_child = true;
@ -1406,6 +1540,8 @@ _public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority)
}
_public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) {
int r;
assert_return(s, -EINVAL);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
@ -1413,7 +1549,25 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
if (s->priority == priority)
return 0;
s->priority = priority;
if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) {
struct signal_data *old, *d;
/* Move us from the signalfd belonging to the old
* priority to the signalfd of the new priority */
assert_se(old = hashmap_get(s->event->signal_data, &s->priority));
s->priority = priority;
r = event_make_signal_data(s->event, s->signal.sig, &d);
if (r < 0) {
s->priority = old->priority;
return r;
}
event_unmask_signal_data(s->event, old, s->signal.sig);
} else
s->priority = priority;
if (s->pending)
prioq_reshuffle(s->event->pending, s, &s->pending_index);
@ -1478,34 +1632,18 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
}
case SOURCE_SIGNAL:
assert(need_signal(s->event, s->signal.sig));
s->enabled = m;
if (!need_signal(s->event, s->signal.sig)) {
assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
(void) event_update_signal_fd(s->event);
/* If disabling failed, we might get a spurious event,
* but otherwise nothing bad should happen. */
}
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
break;
case SOURCE_CHILD:
assert(need_signal(s->event, SIGCHLD));
s->enabled = m;
assert(s->event->n_enabled_child_sources > 0);
s->event->n_enabled_child_sources--;
if (!need_signal(s->event, SIGCHLD)) {
assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
(void) event_update_signal_fd(s->event);
}
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
break;
case SOURCE_EXIT:
@ -1551,37 +1689,33 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
}
case SOURCE_SIGNAL:
/* Check status before enabling. */
if (!need_signal(s->event, s->signal.sig)) {
assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0);
r = event_update_signal_fd(s->event);
if (r < 0) {
s->enabled = SD_EVENT_OFF;
return r;
}
}
s->enabled = m;
r = event_make_signal_data(s->event, s->signal.sig, NULL);
if (r < 0) {
s->enabled = SD_EVENT_OFF;
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
return r;
}
break;
case SOURCE_CHILD:
/* Check status before enabling. */
if (s->enabled == SD_EVENT_OFF) {
if (!need_signal(s->event, SIGCHLD)) {
assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0);
r = event_update_signal_fd(s->event);
if (r < 0) {
s->enabled = SD_EVENT_OFF;
return r;
}
}
if (s->enabled == SD_EVENT_OFF)
s->event->n_enabled_child_sources++;
}
s->enabled = m;
r = event_make_signal_data(s->event, s->signal.sig, SIGCHLD);
if (r < 0) {
s->enabled = SD_EVENT_OFF;
s->event->n_enabled_child_sources--;
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
return r;
}
break;
case SOURCE_EXIT:
@ -2025,20 +2159,35 @@ static int process_child(sd_event *e) {
return 0;
}
static int process_signal(sd_event *e, uint32_t events) {
static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
bool read_one = false;
int r;
assert(e);
assert_return(events == EPOLLIN, -EIO);
/* If there's a signal queued on this priority and SIGCHLD is
on this priority too, then make sure to recheck the
children we watch. This is because we only ever dequeue
the first signal per priority, and if we dequeue one, and
SIGCHLD might be enqueued later we wouldn't know, but we
might have higher priority children we care about hence we
need to check that explicitly. */
if (sigismember(&d->sigset, SIGCHLD))
e->need_process_child = true;
/* If there's already an event source pending for this
* priority we don't read another */
if (d->current)
return 0;
for (;;) {
struct signalfd_siginfo si;
ssize_t n;
sd_event_source *s = NULL;
n = read(e->signal_fd, &si, sizeof(si));
n = read(d->fd, &si, sizeof(si));
if (n < 0) {
if (errno == EAGAIN || errno == EINTR)
return read_one;
@ -2053,24 +2202,21 @@ static int process_signal(sd_event *e, uint32_t events) {
read_one = true;
if (si.ssi_signo == SIGCHLD) {
r = process_child(e);
if (r < 0)
return r;
if (r > 0)
continue;
}
if (e->signal_sources)
s = e->signal_sources[si.ssi_signo];
if (!s)
continue;
if (s->pending)
continue;
s->signal.siginfo = si;
d->current = s;
r = source_set_pending(s, true);
if (r < 0)
return r;
return 1;
}
}
@ -2388,23 +2534,31 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
for (i = 0; i < m; i++) {
if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME))
r = flush_timer(e, e->realtime.fd, ev_queue[i].events, &e->realtime.next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME))
r = flush_timer(e, e->boottime.fd, ev_queue[i].events, &e->boottime.next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_MONOTONIC))
r = flush_timer(e, e->monotonic.fd, ev_queue[i].events, &e->monotonic.next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME_ALARM))
r = flush_timer(e, e->realtime_alarm.fd, ev_queue[i].events, &e->realtime_alarm.next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME_ALARM))
r = flush_timer(e, e->boottime_alarm.fd, ev_queue[i].events, &e->boottime_alarm.next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL))
r = process_signal(e, ev_queue[i].events);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
else
r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
else {
WakeupType *t = ev_queue[i].data.ptr;
switch (*t) {
case WAKEUP_EVENT_SOURCE:
r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
break;
case WAKEUP_CLOCK_DATA: {
struct clock_data *d = ev_queue[i].data.ptr;
r = flush_timer(e, d->fd, ev_queue[i].events, &d->next);
break;
}
case WAKEUP_SIGNAL_DATA:
r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events);
break;
default:
assert_not_reached("Invalid wake-up pointer");
}
}
if (r < 0)
goto finish;
}

View File

@ -156,7 +156,7 @@ static int exit_handler(sd_event_source *s, void *userdata) {
return 3;
}
int main(int argc, char *argv[]) {
static void test_basic(void) {
sd_event *e = NULL;
sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
static const char ch = 'x';
@ -244,6 +244,70 @@ int main(int argc, char *argv[]) {
safe_close_pair(b);
safe_close_pair(d);
safe_close_pair(k);
}
static int last_rtqueue_sigval = 0;
static int n_rtqueue = 0;
static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
last_rtqueue_sigval = si->ssi_int;
n_rtqueue ++;
return 0;
}
static void test_rtqueue(void) {
sd_event_source *u = NULL, *v = NULL, *s = NULL;
sd_event *e = NULL;
assert_se(sd_event_default(&e) >= 0);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
assert_se(sd_event_add_signal(e, &u, SIGRTMIN+2, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_add_signal(e, &v, SIGRTMIN+3, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_add_signal(e, &s, SIGUSR2, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_source_set_priority(v, -10) >= 0);
assert(sigqueue(getpid(), SIGRTMIN+2, (union sigval) { .sival_int = 1 }) >= 0);
assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 2 }) >= 0);
assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 3 }) >= 0);
assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 4 }) >= 0);
assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 5 }) >= 0);
assert_se(n_rtqueue == 0);
assert_se(last_rtqueue_sigval == 0);
assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
assert_se(n_rtqueue == 1);
assert_se(last_rtqueue_sigval == 2); /* first SIGRTMIN+3 */
assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
assert_se(n_rtqueue == 2);
assert_se(last_rtqueue_sigval == 4); /* second SIGRTMIN+3 */
assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
assert_se(n_rtqueue == 3);
assert_se(last_rtqueue_sigval == 3); /* first SIGUSR2 */
assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
assert_se(n_rtqueue == 4);
assert_se(last_rtqueue_sigval == 1); /* SIGRTMIN+2 */
assert_se(sd_event_run(e, 0) == 0); /* the other SIGUSR2 is dropped, because the first one was still queued */
assert_se(n_rtqueue == 4);
assert_se(last_rtqueue_sigval == 1);
sd_event_source_unref(u);
sd_event_source_unref(v);
sd_event_source_unref(s);
sd_event_unref(e);
}
int main(int argc, char *argv[]) {
test_basic();
test_rtqueue();
return 0;
}

View File

@ -35,6 +35,16 @@
#include "hostname-util.h"
#include "sd-login.h"
/* Error codes:
*
* invalid input parameters -EINVAL
* invalid fd -EBADF
* process does not exist -ESRCH
* cgroup does not exist -ENOENT
* machine, session does not exist -ENXIO
* requested metadata on object is missing -ENODATA
*/
_public_ int sd_pid_get_session(pid_t pid, char **session) {
assert_return(pid >= 0, -EINVAL);
@ -91,6 +101,32 @@ _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
return cg_pid_get_owner_uid(pid, uid);
}
_public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
char *c;
int r;
assert_return(pid >= 0, -EINVAL);
assert_return(cgroup, -EINVAL);
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
if (r < 0)
return r;
/* The internal APIs return the empty string for the root
* cgroup, let's return the "/" in the public APIs instead, as
* that's easier and less ambigious for people to grok. */
if (isempty(c)) {
free(c);
c = strdup("/");
if (!c)
return -ENOMEM;
}
*cgroup = c;
return 0;
}
_public_ int sd_peer_get_session(int fd, char **session) {
struct ucred ucred = {};
int r;
@ -189,7 +225,23 @@ _public_ int sd_peer_get_user_slice(int fd, char **slice) {
return cg_pid_get_user_slice(ucred.pid, slice);
}
_public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
struct ucred ucred;
int r;
assert_return(fd >= 0, -EBADF);
assert_return(cgroup, -EINVAL);
r = getpeercred(fd, &ucred);
if (r < 0)
return r;
return sd_pid_get_cgroup(ucred.pid, cgroup);
}
static int file_of_uid(uid_t uid, char **p) {
assert_return(uid_is_valid(uid), -EINVAL);
assert(p);
if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
@ -216,11 +268,15 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) {
if (!s)
return -ENOMEM;
} else if (r < 0) {
}
if (r < 0) {
free(s);
return r;
} else if (!s)
}
if (isempty(s)) {
free(s);
return -EIO;
}
*state = s;
return 0;
@ -238,12 +294,11 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
return -ENODATA;
if (r < 0)
return r;
if (isempty(s))
return -ENXIO;
return -ENODATA;
*session = s;
s = NULL;
@ -251,35 +306,63 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
return 0;
}
static int file_of_seat(const char *seat, char **_p) {
char *p;
int r;
assert(_p);
if (seat) {
if (!filename_is_valid(seat))
return -EINVAL;
p = strappend("/run/systemd/seats/", seat);
} else {
_cleanup_free_ char *buf = NULL;
r = sd_session_get_seat(NULL, &buf);
if (r < 0)
return r;
p = strappend("/run/systemd/seats/", buf);
}
if (!p)
return -ENOMEM;
*_p = p;
p = NULL;
return 0;
}
_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
_cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
size_t l;
int r;
const char *word, *variable, *state;
assert_return(seat, -EINVAL);
variable = require_active ? "ACTIVE_UID" : "UIDS";
p = strappend("/run/systemd/seats/", seat);
if (!p)
return -ENOMEM;
r = parse_env_file(p, NEWLINE, variable, &s, NULL);
assert_return(uid_is_valid(uid), -EINVAL);
r = file_of_seat(seat, &p);
if (r < 0)
return r;
if (!s)
return -EIO;
variable = require_active ? "ACTIVE_UID" : "UIDS";
r = parse_env_file(p, NEWLINE, variable, &s, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
if (isempty(s))
return 0;
if (asprintf(&t, UID_FMT, uid) < 0)
return -ENOMEM;
FOREACH_WORD(word, l, s, state) {
FOREACH_WORD(word, l, s, state)
if (strneq(t, word, l))
return 1;
}
return 0;
}
@ -289,31 +372,22 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) {
char **a;
int r;
assert(variable);
r = file_of_uid(uid, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE,
variable, &s,
NULL);
if (r < 0) {
if (r == -ENOENT) {
if (array)
*array = NULL;
return 0;
}
return r;
}
if (!s) {
r = parse_env_file(p, NEWLINE, variable, &s, NULL);
if (r == -ENOENT || (r >= 0 && isempty(s))) {
if (array)
*array = NULL;
return 0;
}
if (r < 0)
return r;
a = strv_split(s, " ");
if (!a)
return -ENOMEM;
@ -375,37 +449,39 @@ static int file_of_session(const char *session, char **_p) {
}
_public_ int sd_session_is_active(const char *session) {
int r;
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
r = file_of_session(session, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
if (isempty(s))
return -EIO;
return parse_boolean(s);
}
_public_ int sd_session_is_remote(const char *session) {
int r;
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
r = file_of_session(session, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
return -EIO;
if (isempty(s))
return -ENODATA;
return parse_boolean(s);
}
@ -421,9 +497,11 @@ _public_ int sd_session_get_state(const char *session, char **state) {
return r;
r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
else if (!s)
if (isempty(s))
return -EIO;
*state = s;
@ -443,10 +521,11 @@ _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
return r;
r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
if (isempty(s))
return -EIO;
return parse_uid(s, uid);
@ -457,17 +536,19 @@ static int session_get_string(const char *session, const char *field, char **val
int r;
assert_return(value, -EINVAL);
assert(field);
r = file_of_session(session, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE, field, &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (isempty(s))
return -ENXIO;
return -ENODATA;
*value = s;
s = NULL;
@ -487,6 +568,8 @@ _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
unsigned u;
int r;
assert_return(vtnr, -EINVAL);
r = session_get_string(session, "VTNR", &vtnr_string);
if (r < 0)
return r;
@ -542,32 +625,6 @@ _public_ int sd_session_get_remote_host(const char *session, char **remote_host)
return session_get_string(session, "REMOTE_HOST", remote_host);
}
static int file_of_seat(const char *seat, char **_p) {
char *p;
int r;
assert(_p);
if (seat)
p = strappend("/run/systemd/seats/", seat);
else {
_cleanup_free_ char *buf = NULL;
r = sd_session_get_seat(NULL, &buf);
if (r < 0)
return r;
p = strappend("/run/systemd/seats/", buf);
}
if (!p)
return -ENOMEM;
*_p = p;
p = NULL;
return 0;
}
_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
_cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
int r;
@ -582,6 +639,8 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
"ACTIVE", &s,
"ACTIVE_UID", &t,
NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
@ -620,7 +679,8 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
"SESSIONS", &s,
"ACTIVE_SESSIONS", &t,
NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
@ -652,7 +712,6 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
return -ENOMEM;
r = parse_uid(k, b + i);
if (r < 0)
continue;
@ -683,7 +742,7 @@ static int seat_get_can(const char *seat, const char *variable) {
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
assert_return(variable, -EINVAL);
assert(variable);
r = file_of_seat(seat, &p);
if (r < 0)
@ -692,10 +751,12 @@ static int seat_get_can(const char *seat, const char *variable) {
r = parse_env_file(p, NEWLINE,
variable, &s,
NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
return 0;
if (isempty(s))
return -ENODATA;
return parse_boolean(s);
}
@ -819,6 +880,8 @@ _public_ int sd_machine_get_class(const char *machine, char **class) {
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!c)
@ -842,6 +905,8 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!netif) {

View File

@ -33,7 +33,7 @@ static void test_login(void) {
_cleanup_free_ char *pp = NULL, *qq = NULL;
int r, k;
uid_t u, u2;
char *seat, *type, *class, *display, *remote_user, *remote_host, *display_session;
char *seat, *type, *class, *display, *remote_user, *remote_host, *display_session, *cgroup;
char *session;
char *state;
char *session2;
@ -50,9 +50,13 @@ static void test_login(void) {
assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
printf("user = "UID_FMT"\n", u2);
assert_se(sd_pid_get_cgroup(0, &cgroup) == 0);
printf("cgroup = %s\n", cgroup);
free(cgroup);
display_session = NULL;
r = sd_uid_get_display(u2, &display_session);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("user's display session = %s\n", strna(display_session));
free(display_session);
@ -108,19 +112,19 @@ static void test_login(void) {
display = NULL;
r = sd_session_get_display(session, &display);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("display = %s\n", strna(display));
free(display);
remote_user = NULL;
r = sd_session_get_remote_user(session, &remote_user);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("remote_user = %s\n", strna(remote_user));
free(remote_user);
remote_host = NULL;
r = sd_session_get_remote_host(session, &remote_host);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("remote_host = %s\n", strna(remote_host));
free(remote_host);

View File

@ -4737,6 +4737,7 @@ static int create_subcgroup(pid_t pid) {
_cleanup_free_ char *cgroup = NULL;
const char *child;
int unified, r;
CGroupMask supported;
/* In the unified hierarchy inner nodes may only only contain
* subgroups, but not processes. Hence, if we running in the
@ -4756,6 +4757,10 @@ static int create_subcgroup(pid_t pid) {
if (unified == 0)
return 0;
r = cg_mask_supported(&supported);
if (r < 0)
return log_error_errno(r, "Failed to determine supported controllers: %m");
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0)
return log_error_errno(r, "Failed to get our control group: %m");
@ -4770,6 +4775,8 @@ static int create_subcgroup(pid_t pid) {
if (r < 0)
return log_error_errno(r, "Failed to create %s subcgroup: %m", child);
/* Try to enable as many controllers as possible for the new payload. */
(void) cg_enable_everywhere(supported, supported, cgroup);
return 0;
}

View File

@ -81,34 +81,42 @@ int sd_pid_get_user_slice(pid_t pid, char **slice);
* container. This will return an error for non-machine processes. */
int sd_pid_get_machine_name(pid_t pid, char **machine);
/* Similar to sd_pid_get_session(), but retrieves data about peer of
* connected AF_UNIX socket */
/* Get the control group from a PID, relative to the root of the
* hierarchy. */
int sd_pid_get_cgroup(pid_t pid, char **cgroup);
/* Similar to sd_pid_get_session(), but retrieves data about the peer
* of a connected AF_UNIX socket */
int sd_peer_get_session(int fd, char **session);
/* Similar to sd_pid_get_owner_uid(), but retrieves data about peer of
* connected AF_UNIX socket */
/* Similar to sd_pid_get_owner_uid(), but retrieves data about the peer of
* a connected AF_UNIX socket */
int sd_peer_get_owner_uid(int fd, uid_t *uid);
/* Similar to sd_pid_get_unit(), but retrieves data about peer of
* connected AF_UNIX socket */
/* Similar to sd_pid_get_unit(), but retrieves data about the peer of
* a connected AF_UNIX socket */
int sd_peer_get_unit(int fd, char **unit);
/* Similar to sd_pid_get_user_unit(), but retrieves data about peer of
* connected AF_UNIX socket */
/* Similar to sd_pid_get_user_unit(), but retrieves data about the peer of
* a connected AF_UNIX socket */
int sd_peer_get_user_unit(int fd, char **unit);
/* Similar to sd_pid_get_slice(), but retrieves data about peer of
* connected AF_UNIX socket */
/* Similar to sd_pid_get_slice(), but retrieves data about the peer of
* a connected AF_UNIX socket */
int sd_peer_get_slice(int fd, char **slice);
/* Similar to sd_pid_get_user_slice(), but retrieves data about peer of
* connected AF_UNIX socket */
/* Similar to sd_pid_get_user_slice(), but retrieves data about the peer of
* a connected AF_UNIX socket */
int sd_peer_get_user_slice(int fd, char **slice);
/* Similar to sd_pid_get_machine_name(), but retrieves data about peer
* of connected AF_UNIX socket */
/* Similar to sd_pid_get_machine_name(), but retrieves data about the
* peer of a a connected AF_UNIX socket */
int sd_peer_get_machine_name(int fd, char **machine);
/* Similar to sd_pid_get_cgroup(), but retrieves data about the peer
* of a connected AF_UNIX socket. */
int sd_peer_get_cgroup(pid_t pid, char **cgroup);
/* Get state from UID. Possible states: offline, lingering, online, active, closing */
int sd_uid_get_state(uid_t uid, char **state);

View File

@ -295,6 +295,17 @@ static void test_shift_path(void) {
test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
}
static void test_mask_supported(void) {
CGroupMask m;
CGroupController c;
assert_se(cg_mask_supported(&m) >= 0);
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
}
int main(void) {
test_path_decode_unit();
test_path_get_unit();
@ -309,6 +320,7 @@ int main(void) {
test_controller_is_valid();
test_slice_to_path();
test_shift_path();
test_mask_supported();
return 0;
}

View File

@ -270,6 +270,9 @@ static void test_parse_pid(void) {
r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
assert_se(r == -ERANGE);
assert_se(pid == 65);
r = parse_pid("junk", &pid);
assert_se(r == -EINVAL);
}
static void test_parse_uid(void) {
@ -282,6 +285,9 @@ static void test_parse_uid(void) {
r = parse_uid("65535", &uid);
assert_se(r == -ENXIO);
r = parse_uid("asdsdas", &uid);
assert_se(r == -EINVAL);
}
static void test_safe_atou16(void) {