diff options
60 files changed, 1264 insertions, 420 deletions
diff --git a/CODING_STYLE b/CODING_STYLE index a96ddd3598..f13f9becbc 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -295,25 +295,15 @@ EXIT_FAILURE and EXIT_SUCCESS as defined by libc. - The order in which header files are included doesn't matter too - much. However, please try to include the headers of external - libraries first (these are all headers enclosed in <>), followed by - the headers of our own public headers (these are all headers - starting with "sd-"), internal utility libraries from src/shared/, - followed by the headers of the specific component. Or in other - words: - - #include <stdio.h> - #include "sd-daemon.h" - #include "util.h" - #include "frobnicator.h" - - Where stdio.h is a public glibc API, sd-daemon.h is a public API of - our own, util.h is a utility library header from src/shared, and - frobnicator.h is an placeholder name for any systemd component. The - benefit of following this ordering is that more local definitions - are always defined after more global ones. Thus, our local - definitions will never "leak" into the global header files, possibly - altering their effect due to #ifdeffery. + much. systemd-internal headers must not rely on an include order, so + it is safe to include them in any order possible. + However, to not clutter global includes, and to make sure internal + definitions will not affect global headers, please always include the + headers of external components first (these are all headers enclosed + in <>), followed by our own exported headers (usually everything + that's prefixed by "sd-"), and then followed by internal headers. + Furthermore, in all three groups, order all includes alphabetically + so duplicate includes can easily be detected. - To implement an endless loop, use "for (;;)" rather than "while (1)". The latter is a bit ugly anyway, since you probably really diff --git a/Makefile-man.am b/Makefile-man.am index 65287371b9..ab68c81b1d 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -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) @@ -1,5 +1,66 @@ systemd System and Service Manager +CHANGES WITH 226: + + * The DHCP implementation of systemd-networkd gained a set of new + features: + + - Server and client now support transmission and reception of + timezone information. It can be configured via the newly introduced + network options 'DHCP.UseTimezone=', 'DHCPServer.EmitTimezone=', + and 'DHCPServer.Timezone='. + Transmission of timezone information is enabled for containers by + default now. Furthermore, if systemd-timesyncd is running, it will + be updated with the received information. + + - The DHCP server now supports emitting DNS and NTP information. It + can be enabled and configured via 'EmitDNS=', 'DNS=', 'EmitNTP=', + and 'NTP='. + If transmission of DNS and NTP information is enabled, but no + specific data-set is configured, the uplink information is used. + + - Lease timeouts can now be configured via 'MaxLeaseTimeSec=' and + 'DefaultLeaseTimeSec='. + + - The DHCP server now supports improved predictability of leases. + Clients are more likely to get the same lease information back, + even if the server loses state. + + - The DHCP server supports two new configuration options to specify + the lease pool, 'PoolOffset=' and 'PoolSize='. + + * The encapsulation limit of tunnels in systemd-networkd can now be + configured via 'EncapsulationLimit='. It allows modifying the maximum + additional levels of encapsulation that are permitted to be prepended + to a packet. + + * systemd now supports the concept of user-buses over session-buses, if + used with dbus-1.10 (and enabled via dbus --enable-user-session). + + * systemd-networkd now supports predictable interface names for virtio + devices. + + * systemd now optionally supports the unified cgroup hierarchy. If + enabled via the kernel command-line option + 'systemd.unified_cgroup_hierarchy=1', systemd will try to mount the + unified cgroup hierarchy directly on /sys/fs/cgroup. If not enabled, + or not available, systemd will fall back to legacy cgroups. + Host system and containers can mix and match legacy and unified + hierarchies as they wish. By default, nspawn will use the same + hierarchy as the host. + Please note that the unified hierarchy is an experimental kernel + feature and is likely to change in one of the next kernel releases. + Therefore, it should not be enabled by default. + + Contributions from: Cristian Rodríguez, Daniel Mack, David Herrmann, + Eugene Yakubovich, Evgeny Vereshchagin, Filipe Brandenburger, Jan + Alexander Steffens (heftig), Jan Synacek, Kay Sievers, Lennart + Poettering, Mangix, Marcel Holtmann, Martin Pitt, Michal Sekletar, Peter + Hutterer, Piotr Drąg, reverendhomer, Robin Hack, Susant Sahani, Sylvain + Pasche, Thomas Hindoe Paaboel Andersen, Tom Gundersen + + -- Berlin, 2015-09-XX + CHANGES WITH 225: * machinectl gained a new verb 'shell' which opens a fresh shell on the @@ -316,8 +316,6 @@ Features: (throughout the codebase, not only PID1) * networkd: - - make DHCP server IP range configurable, including only with a single IP address - - dhcp server: try to assign stable IP addresses based on client's MAC address - add LLDP client side support - the DHCP lease data (such as NTP/DNS) is still made available when a carrier is lost on a link. It should be removed instantly. @@ -332,6 +330,7 @@ Features: support Name=foo*|bar*|baz ? - duplicate address check for static IPs (like ARPCHECK in network-scripts) - allow DUID/IAID to be customized, see issue #394. + - support configuration option for TSO (tcp segmentation offload) - networkd: whenever uplink info changes, make DHCP server send out FORCERENEW * resolved: diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb index b36c897bd6..8e674b1123 100644 --- a/hwdb/70-pointingstick.hwdb +++ b/hwdb/70-pointingstick.hwdb @@ -98,6 +98,8 @@ evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX240 evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT440s:* # Lenovo Thinkpad T540p evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT540p:* +# Lenovo Thinkpad T550 / W550s +evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT550:* POINTINGSTICK_SENSITIVITY=200 POINTINGSTICK_CONST_ACCEL=1.0 diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml index b7b7e1b555..4481fdf8cb 100644 --- a/man/nss-myhostname.xml +++ b/man/nss-myhostname.xml @@ -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> diff --git a/man/nss-resolve.xml b/man/nss-resolve.xml index dd402b359c..7d291b83c1 100644 --- a/man/nss-resolve.xml +++ b/man/nss-resolve.xml @@ -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 diff --git a/man/sd_get_seats.xml b/man/sd_get_seats.xml index 4390d36ebe..f1981f7ea2 100644 --- a/man/sd_get_seats.xml +++ b/man/sd_get_seats.xml @@ -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> diff --git a/man/sd_login_monitor_new.xml b/man/sd_login_monitor_new.xml index a7b47a3207..a8854dd590 100644 --- a/man/sd_login_monitor_new.xml +++ b/man/sd_login_monitor_new.xml @@ -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, &t); if (t == (uint64_t) -1) - msec = -1; + msec = -1; else { - struct timespec ts; - uint64_t n; - clock_getttime(CLOCK_MONOTONIC, &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, &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 @@ -204,6 +204,29 @@ else { </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> <para>The <function>sd_login_monitor_new()</function>, diff --git a/man/sd_machine_get_class.xml b/man/sd_machine_get_class.xml index 5b881ccea1..9ad7f3fc66 100644 --- a/man/sd_machine_get_class.xml +++ b/man/sd_machine_get_class.xml @@ -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> @@ -99,6 +99,35 @@ </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> <para>The <function>sd_machine_get_class()</function> and diff --git a/man/sd_pid_get_session.xml b/man/sd_pid_get_session.xml index 9c6706caf8..035effcaa9 100644 --- a/man/sd_pid_get_session.xml +++ b/man/sd_pid_get_session.xml @@ -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> @@ -109,6 +111,12 @@ </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> <paramdef>char **<parameter>session</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> diff --git a/man/sd_seat_get_active.xml b/man/sd_seat_get_active.xml index 3c57ec9ea4..4d3e0822e0 100644 --- a/man/sd_seat_get_active.xml +++ b/man/sd_seat_get_active.xml @@ -149,6 +149,43 @@ </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> <para>The <function>sd_seat_get_active()</function>, diff --git a/man/sd_session_is_active.xml b/man/sd_session_is_active.xml index 4ca3a6c150..7de9523789 100644 --- a/man/sd_session_is_active.xml +++ b/man/sd_session_is_active.xml @@ -290,6 +290,43 @@ </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> <para>The <function>sd_session_is_active()</function>, diff --git a/man/sd_uid_get_state.xml b/man/sd_uid_get_state.xml index b158f3528c..13ddf08c65 100644 --- a/man/sd_uid_get_state.xml +++ b/man/sd_uid_get_state.xml @@ -170,6 +170,45 @@ </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> <para>Functions described here are available as a shared library, diff --git a/po/POTFILES.in b/po/POTFILES.in index b4c1121d1c..f33c53fb4a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -5,3 +5,4 @@ src/locale/org.freedesktop.locale1.policy.in src/login/org.freedesktop.login1.policy.in src/machine/org.freedesktop.machine1.policy.in src/timedate/org.freedesktop.timedate1.policy.in +src/core/dbus-unit.c diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index 21c79cae8e..4d63e2870f 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -85,6 +85,12 @@ __get_masked_units () { __systemctl $1 list-unit-files \ | { while read -r a b c ; do [[ $b == "masked" ]] && echo " $a"; done; }; } __get_all_unit_files () { { __systemctl $1 list-unit-files; } | { while read -r a b; do echo " $a"; done; }; } +__get_machines() { + local a b + (machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager) | \ + { while read a b; do echo " $a"; done; } | sort -u; +} + _systemctl () { local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} local i verb comps mode @@ -92,8 +98,10 @@ _systemctl () { local -A OPTS=( [STANDALONE]='--all -a --reverse --after --before --defaults --failed --force -f --full -l --global --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall - --quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware-setup' - [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root' + --quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware-setup + --show-types -i --ignore-inhibitors --plain' + [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root + --preset-mode -n --lines -o --output -M --machine' ) if __contains_word "--user" ${COMP_WORDS[*]}; then @@ -132,6 +140,16 @@ _systemctl () { --property|-p) comps=$(__systemd_properties $mode) ;; + --preset-mode) + comps='full enable-only disable-only' + ;; + --output|-o) + comps='short short-iso short-precise short-monotonic verbose export json + json-pretty json-sse cat' + ;; + --machine|-M) + comps=$( __get_machines ) + ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 diff --git a/src/basic/audit.c b/src/basic/audit.c index 54148fcf18..1f593aa813 100644 --- a/src/basic/audit.c +++ b/src/basic/audit.c @@ -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; diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 0ebe570bb8..a298b29382 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -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); } } diff --git a/src/basic/macro.h b/src/basic/macro.h index 627d768b76..cbc3ca97b8 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -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))) diff --git a/src/basic/util.c b/src/basic/util.c index f01f5f237b..86aacad307 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -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; diff --git a/src/basic/util.h b/src/basic/util.h index ff7a00e928..0fafebd52d 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -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); @@ -564,6 +567,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, void *arg); #define _(String) gettext (String) +#define N_(String) String void init_gettext(void); bool is_locale_utf8(void); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 1e78f871c7..9a025cf929 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -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,9 +1383,8 @@ 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); @@ -1388,22 +1392,33 @@ Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) { 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) { diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 1ce21f43f2..438f5bf50f 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -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); diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 31016b6c4a..f9275ed935 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -391,6 +391,29 @@ static int property_get_load_error( return sd_bus_message_append(reply, "(ss)", e.name, e.message); } +static int bus_verify_manage_units_async_full( + Unit *u, + const char *verb, + int capability, + const char *polkit_message, + sd_bus_message *call, + sd_bus_error *error) { + + const char *details[9] = { + "unit", u->id, + "verb", verb, + }; + + if (polkit_message) { + details[4] = "polkit.message"; + details[5] = polkit_message; + details[6] = "polkit.gettext_domain"; + details[7] = GETTEXT_PACKAGE; + } + + return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error); +} + int bus_unit_method_start_generic( sd_bus_message *message, Unit *u, @@ -400,6 +423,14 @@ int bus_unit_method_start_generic( const char *smode; JobMode mode; + _cleanup_free_ char *verb = NULL; + static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = { + [JOB_START] = N_("Authentication is required to start '$(unit)'."), + [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."), + [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."), + [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."), + [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."), + }; int r; assert(message); @@ -418,7 +449,20 @@ int bus_unit_method_start_generic( if (mode < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode); - r = bus_verify_manage_units_async(u->manager, message, error); + if (reload_if_possible) + verb = strjoin("reload-or-", job_type_to_string(job_type), NULL); + else + verb = strdup(job_type_to_string(job_type)); + if (!verb) + return -ENOMEM; + + r = bus_verify_manage_units_async_full( + u, + verb, + CAP_SYS_ADMIN, + job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL, + message, + error); if (r < 0) return r; if (r == 0) @@ -484,7 +528,13 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error * if (signo <= 0 || signo >= _NSIG) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); - r = bus_verify_manage_units_async_for_kill(u->manager, message, error); + r = bus_verify_manage_units_async_full( + u, + "kill", + CAP_KILL, + N_("Authentication is required to kill '$(unit)'."), + message, + error); if (r < 0) return r; if (r == 0) @@ -508,7 +558,13 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus if (r < 0) return r; - r = bus_verify_manage_units_async(u->manager, message, error); + r = bus_verify_manage_units_async_full( + u, + "reset-failed", + CAP_SYS_ADMIN, + N_("Authentication is required to reset the \"failed\" state of '$(unit)'."), + message, + error); if (r < 0) return r; if (r == 0) @@ -534,7 +590,13 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b if (r < 0) return r; - r = bus_verify_manage_units_async(u->manager, message, error); + r = bus_verify_manage_units_async_full( + u, + "set-property", + CAP_SYS_ADMIN, + N_("Authentication is required to set properties on '$(unit)'."), + message, + error); if (r < 0) return r; if (r == 0) diff --git a/src/core/dbus.c b/src/core/dbus.c index 7ad16aa42b..0a2180c6a7 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -1198,22 +1198,17 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) { } int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { - return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error); -} - -/* Same as bus_verify_manage_unit_async(), but checks for CAP_KILL instead of CAP_SYS_ADMIN */ -int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error) { - return bus_verify_polkit_async(call, CAP_KILL, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error); + return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", NULL, false, UID_INVALID, &m->polkit_registry, error); } int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { - return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", false, UID_INVALID, &m->polkit_registry, error); + return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", NULL, false, UID_INVALID, &m->polkit_registry, error); } int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { - return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", false, UID_INVALID, &m->polkit_registry, error); + return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", NULL, false, UID_INVALID, &m->polkit_registry, error); } int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { - return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", false, UID_INVALID, &m->polkit_registry, error); + return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error); } diff --git a/src/core/dbus.h b/src/core/dbus.h index 4832722069..4f06ad11c4 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -37,7 +37,6 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l); int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata); int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error); -int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error); int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error); int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error); int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error); diff --git a/src/core/killall.c b/src/core/killall.c index 2a9d72c901..ee5d388560 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -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(); } diff --git a/src/core/manager.c b/src/core/manager.c index c3327e37f5..fc10ddb5d9 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -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); } diff --git a/src/core/unit.c b/src/core/unit.c index 8c07c6140d..a5714adf38 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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; } diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a78516c8b5..c423be3767 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -434,6 +434,7 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error * m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-hostname", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -486,6 +487,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_ m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-static-hostname", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -557,6 +559,7 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess m, CAP_SYS_ADMIN, prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info", + NULL, interactive, UID_INVALID, &c->polkit_registry, diff --git a/src/import/importd.c b/src/import/importd.c index 8b508eaeec..ffff94ee72 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -735,6 +735,7 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ msg, CAP_SYS_ADMIN, "org.freedesktop.import1.import", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -799,6 +800,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ msg, CAP_SYS_ADMIN, "org.freedesktop.import1.export", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -864,6 +866,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er msg, CAP_SYS_ADMIN, "org.freedesktop.import1.pull", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -945,6 +948,7 @@ static int method_pull_dkr(sd_bus_message *msg, void *userdata, sd_bus_error *er msg, CAP_SYS_ADMIN, "org.freedesktop.import1.pull", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -1079,6 +1083,7 @@ static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *erro msg, CAP_SYS_ADMIN, "org.freedesktop.import1.pull", + NULL, false, UID_INVALID, &t->manager->polkit_registry, @@ -1108,6 +1113,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er msg, CAP_SYS_ADMIN, "org.freedesktop.import1.pull", + NULL, false, UID_INVALID, &m->polkit_registry, diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 7bf1d66dde..d5ad127bcb 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -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; diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 1c365b7fcd..c3cc2b7212 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -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) { diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 0593aa658a..1d061cb9cf 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -169,11 +169,18 @@ static int add_enumerated_to_set( return 0; } +enum { + /* if set, add_subtree() works recursively */ + CHILDREN_RECURSIVE = (1U << 1), + /* if set, add_subtree() scans object-manager hierarchies recursively */ + CHILDREN_SUBHIERARCHIES = (1U << 0), +}; + static int add_subtree_to_set( sd_bus *bus, const char *prefix, struct node *n, - bool skip_subhierarchies, + unsigned int flags, Set *s, sd_bus_error *error) { @@ -205,8 +212,9 @@ static int add_subtree_to_set( if (r < 0 && r != -EEXIST) return r; - if (!skip_subhierarchies || !i->object_managers) { - r = add_subtree_to_set(bus, prefix, i, skip_subhierarchies, s, error); + if ((flags & CHILDREN_RECURSIVE) && + ((flags & CHILDREN_SUBHIERARCHIES) || !i->object_managers)) { + r = add_subtree_to_set(bus, prefix, i, flags, s, error); if (r < 0) return r; if (bus->nodes_modified) @@ -221,7 +229,7 @@ static int get_child_nodes( sd_bus *bus, const char *prefix, struct node *n, - bool skip_subhierarchies, + unsigned int flags, Set **_s, sd_bus_error *error) { @@ -237,7 +245,7 @@ static int get_child_nodes( if (!s) return -ENOMEM; - r = add_subtree_to_set(bus, prefix, n, skip_subhierarchies, s, error); + r = add_subtree_to_set(bus, prefix, n, flags, s, error); if (r < 0) { set_free_free(s); return r; @@ -907,7 +915,7 @@ static int process_introspect( assert(n); assert(found_object); - r = get_child_nodes(bus, m->path, n, false, &s, &error); + r = get_child_nodes(bus, m->path, n, 0, &s, &error); if (r < 0) return bus_maybe_reply_error(m, r, &error); if (bus->nodes_modified) @@ -1173,7 +1181,7 @@ static int process_get_managed_objects( if (require_fallback || !n->object_managers) return 0; - r = get_child_nodes(bus, m->path, n, true, &s, &error); + r = get_child_nodes(bus, m->path, n, CHILDREN_RECURSIVE, &s, &error); if (r < 0) return r; if (bus->nodes_modified) diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 4ed508427e..4a9181613a 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1241,6 +1241,8 @@ fail: int bus_set_address_user(sd_bus *b) { const char *e; + uid_t uid; + int r; assert(b); @@ -1248,6 +1250,10 @@ int bus_set_address_user(sd_bus *b) { if (e) return sd_bus_set_address(b, e); + r = cg_pid_get_owner_uid(0, &uid); + if (r < 0) + uid = getuid(); + e = secure_getenv("XDG_RUNTIME_DIR"); if (e) { _cleanup_free_ char *ee = NULL; @@ -1256,9 +1262,9 @@ int bus_set_address_user(sd_bus *b) { if (!ee) return -ENOMEM; - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee); + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee); } else - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()); + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid); if (!b->address) return -ENOMEM; diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index edd5033db2..580117165a 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -22,11 +22,17 @@ #include "sd-bus.h" #include "bus-dump.h" #include "bus-util.h" +#include "cgroup-util.h" int main(int argc, char *argv[]) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; int r; + if (cg_unified() == -ENOEXEC) { + puts("Skipping test: /sys/fs/cgroup/ not available"); + return EXIT_TEST_SKIP; + } + r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL); assert_se(r >= 0); diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index c419be820a..838ee4d454 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -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; + + d = new0(struct signal_data, 1); + if (!d) + return -ENOMEM; + + d->wakeup = WAKEUP_SIGNAL_DATA; + d->fd = -1; + d->priority = priority; + + r = hashmap_put(e->signal_data, &d->priority, d); + if (r < 0) + return r; - e->signal_fd = r; + 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 (!add_to_epoll) + if (d->fd >= 0) { + if (ret) + *ret = d; return 0; + } + + d->fd = r; ev.events = EPOLLIN; - ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL); + ev.data.ptr = d; - 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; + 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; } diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 408e1679a2..c092e56b7a 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -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; } diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 7d6a4b78cf..55da26e9d9 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -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); + assert_return(uid_is_valid(uid), -EINVAL); - variable = require_active ? "ACTIVE_UID" : "UIDS"; + r = file_of_seat(seat, &p); + if (r < 0) + return r; - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; + 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 (!s) - return -EIO; + 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) { diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index ddea7ffa14..f734ce9eee 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -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); diff --git a/src/locale/localed.c b/src/locale/localed.c index 4fa84df8c0..e304588c58 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -960,6 +960,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-locale", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -1049,6 +1050,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -1180,6 +1182,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", + NULL, interactive, UID_INVALID, &c->polkit_registry, diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 7cc68d4865..14b6e0ddad 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -942,6 +942,7 @@ static int method_lock_sessions(sd_bus_message *message, void *userdata, sd_bus_ message, CAP_SYS_ADMIN, "org.freedesktop.login1.lock-sessions", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -1096,6 +1097,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu message, CAP_SYS_ADMIN, "org.freedesktop.login1.set-user-linger", + NULL, interactive, UID_INVALID, &m->polkit_registry, @@ -1268,6 +1270,7 @@ static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_ message, CAP_SYS_ADMIN, "org.freedesktop.login1.attach-device", + NULL, interactive, UID_INVALID, &m->polkit_registry, @@ -1299,6 +1302,7 @@ static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_ message, CAP_SYS_ADMIN, "org.freedesktop.login1.flush-devices", + NULL, interactive, UID_INVALID, &m->polkit_registry, @@ -1649,7 +1653,7 @@ static int verify_shutdown_creds( blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); if (multiple_sessions && action_multiple_sessions) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, interactive, UID_INVALID, &m->polkit_registry, error); + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) @@ -1657,7 +1661,7 @@ static int verify_shutdown_creds( } if (blocked && action_ignore_inhibit) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, interactive, UID_INVALID, &m->polkit_registry, error); + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) @@ -1665,7 +1669,7 @@ static int verify_shutdown_creds( } if (!multiple_sessions && !blocked && action) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, interactive, UID_INVALID, &m->polkit_registry, error); + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) @@ -1796,9 +1800,11 @@ static int update_schedule_file(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to create shutdown subdirectory: %m"); - t = cescape(m->wall_message); - if (!t) - return log_oom(); + if (!isempty(m->wall_message)) { + t = cescape(m->wall_message); + if (!t) + return log_oom(); + } r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path); if (r < 0) @@ -1814,7 +1820,7 @@ static int update_schedule_file(Manager *m) { m->enable_wall_messages, m->scheduled_shutdown_type); - if (!isempty(m->wall_message)) + if (t) fprintf(f, "WALL_MESSAGE=%s\n", t); r = fflush_and_check(f); @@ -2083,7 +2089,7 @@ static int method_can_shutdown_or_sleep( blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); if (multiple_sessions) { - r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, UID_INVALID, &challenge, error); + r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error); if (r < 0) return r; @@ -2096,7 +2102,7 @@ static int method_can_shutdown_or_sleep( } if (blocked) { - r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, UID_INVALID, &challenge, error); + r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, UID_INVALID, &challenge, error); if (r < 0) return r; @@ -2112,7 +2118,7 @@ static int method_can_shutdown_or_sleep( /* If neither inhibit nor multiple sessions * apply then just check the normal policy */ - r = bus_test_polkit(message, CAP_SYS_BOOT, action, UID_INVALID, &challenge, error); + r = bus_test_polkit(message, CAP_SYS_BOOT, action, NULL, UID_INVALID, &challenge, error); if (r < 0) return r; @@ -2231,6 +2237,7 @@ static int method_set_reboot_to_firmware_setup( r = bus_verify_polkit_async(message, CAP_SYS_ADMIN, "org.freedesktop.login1.set-reboot-to-firmware-setup", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -2269,6 +2276,7 @@ static int method_can_reboot_to_firmware_setup( r = bus_test_polkit(message, CAP_SYS_ADMIN, "org.freedesktop.login1.set-reboot-to-firmware-setup", + NULL, UID_INVALID, &challenge, error); @@ -2305,6 +2313,7 @@ static int method_set_wall_message( r = bus_verify_polkit_async(message, CAP_SYS_ADMIN, "org.freedesktop.login1.set-wall-message", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -2376,6 +2385,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" : w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" : "org.freedesktop.login1.inhibit-handle-lid-switch", + NULL, false, UID_INVALID, &m->polkit_registry, diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index ce67ffde37..346e1d2cec 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -204,6 +204,7 @@ int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_er message, CAP_KILL, "org.freedesktop.login1.manage", + NULL, false, UID_INVALID, &s->manager->polkit_registry, diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 563153e2d9..e6b4ccd7c6 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -191,6 +191,7 @@ int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus message, CAP_KILL, "org.freedesktop.login1.manage", + NULL, false, s->user->uid, &s->manager->polkit_registry, @@ -232,6 +233,7 @@ int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_erro message, CAP_SYS_ADMIN, "org.freedesktop.login1.lock-sessions", + NULL, false, s->user->uid, &s->manager->polkit_registry, @@ -306,6 +308,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro message, CAP_KILL, "org.freedesktop.login1.manage", + NULL, false, s->user->uid, &s->manager->polkit_registry, diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 36c0e8626d..20ea2fbdc4 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -179,6 +179,7 @@ int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_er message, CAP_KILL, "org.freedesktop.login1.manage", + NULL, false, u->uid, &u->manager->polkit_registry, @@ -207,6 +208,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error * message, CAP_KILL, "org.freedesktop.login1.manage", + NULL, false, u->uid, &u->manager->polkit_registry, diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 95d7bca4bf..2453a9ff04 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -43,6 +43,7 @@ int bus_image_method_remove( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -83,6 +84,7 @@ int bus_image_method_rename( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -123,6 +125,7 @@ int bus_image_method_clone( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -158,6 +161,7 @@ int bus_image_method_mark_read_only( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", + NULL, false, UID_INVALID, &m->polkit_registry, @@ -194,6 +198,7 @@ int bus_image_method_set_limit( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", + NULL, false, UID_INVALID, &m->polkit_registry, diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index a63b9785af..fbeace0ed6 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -124,6 +124,7 @@ int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus message, CAP_KILL, "org.freedesktop.machine1.manage-machines", + NULL, false, UID_INVALID, &m->manager->polkit_registry, @@ -169,6 +170,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro message, CAP_KILL, "org.freedesktop.machine1.manage-machines", + NULL, false, UID_INVALID, &m->manager->polkit_registry, @@ -488,6 +490,7 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_ message, CAP_SYS_ADMIN, m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty", + NULL, false, UID_INVALID, &m->manager->polkit_registry, @@ -577,6 +580,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu message, CAP_SYS_ADMIN, m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login", + NULL, false, UID_INVALID, &m->manager->polkit_registry, @@ -675,6 +679,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu message, CAP_SYS_ADMIN, m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell", + NULL, false, UID_INVALID, &m->manager->polkit_registry, @@ -883,6 +888,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-machines", + NULL, false, UID_INVALID, &m->manager->polkit_registry, @@ -1145,6 +1151,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-machines", + NULL, false, UID_INVALID, &m->manager->polkit_registry, diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 0d52c693e4..eef9c5fa5f 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -810,6 +810,7 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-machines", + NULL, false, UID_INVALID, &m->polkit_registry, diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 36601367bf..4ffb01382f 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -60,7 +60,7 @@ static int link_set_dhcp_routes(Link *link) { assert(link->dhcp_lease); r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); - if (r < 0 && r != -ENOENT) + if (r < 0 && r != -ENODATA) return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m"); if (r >= 0) { @@ -112,7 +112,7 @@ static int link_set_dhcp_routes(Link *link) { } n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); - if (n == -ENOENT) + if (n == -ENODATA) return 0; if (n < 0) return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m"); @@ -378,7 +378,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { prefixlen = in_addr_netmask_to_prefixlen(&netmask); r = sd_dhcp_lease_get_router(lease, &gateway); - if (r < 0 && r != -ENOENT) + if (r < 0 && r != -ENODATA) return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); if (r >= 0) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 16f732f244..92b607297d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -757,7 +757,7 @@ int manager_save(Manager *m) { r = set_put_in_addrv(dns, addresses, r); if (r < 0) return r; - } else if (r < 0 && r != -ENOENT) + } else if (r < 0 && r != -ENODATA) return r; } @@ -769,7 +769,7 @@ int manager_save(Manager *m) { r = set_put_in_addrv(ntp, addresses, r); if (r < 0) return r; - } else if (r < 0 && r != -ENOENT) + } else if (r < 0 && r != -ENODATA) return r; } @@ -781,7 +781,7 @@ int manager_save(Manager *m) { r = set_put_strdup(domains, domainname); if (r < 0) return r; - } else if (r != -ENOENT) + } else if (r != -ENODATA) return r; } } diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index a56960506c..1c64c3e771 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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; } diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 1369a61458..d9cc19700e 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -220,6 +220,7 @@ int bus_test_polkit( sd_bus_message *call, int capability, const char *action, + const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e) { @@ -242,29 +243,52 @@ int bus_test_polkit( return 1; #ifdef ENABLE_POLKIT else { + _cleanup_bus_message_unref_ sd_bus_message *request = NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int authorized = false, challenge = false; - const char *sender; + const char *sender, **k, **v; sender = sd_bus_message_get_sender(call); if (!sender) return -EBADMSG; - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( call->bus, + &request, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", - "CheckAuthorization", - e, - &reply, - "(sa{sv})sa{ss}us", + "CheckAuthorization"); + if (r < 0) + return r; + + r = sd_bus_message_append( + request, + "(sa{sv})s", "system-bus-name", 1, "name", "s", sender, - action, - 0, - 0, - ""); + action); + if (r < 0) + return r; + + r = sd_bus_message_open_container(request, 'a', "{ss}"); + if (r < 0) + return r; + STRV_FOREACH_PAIR(k, v, details) { + r = sd_bus_message_append(request, "{ss}", *k, *v); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(request); + if (r < 0) + return r; + + r = sd_bus_message_append(request, "us", 0, NULL); + if (r < 0) + return r; + + r = sd_bus_call(call->bus, request, 0, e, &reply); if (r < 0) { /* Treat no PK available as access denied */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { @@ -354,6 +378,7 @@ int bus_verify_polkit_async( sd_bus_message *call, int capability, const char *action, + const char **details, bool interactive, uid_t good_user, Hashmap **registry, @@ -362,7 +387,7 @@ int bus_verify_polkit_async( #ifdef ENABLE_POLKIT _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; AsyncPolkitQuery *q; - const char *sender; + const char *sender, **k, **v; sd_bus_message_handler_t callback; void *userdata; int c; @@ -460,12 +485,27 @@ int bus_verify_polkit_async( r = sd_bus_message_append( pk, - "(sa{sv})sa{ss}us", + "(sa{sv})s", "system-bus-name", 1, "name", "s", sender, - action, - 0, - !!interactive, - NULL); + action); + if (r < 0) + return r; + + r = sd_bus_message_open_container(pk, 'a', "{ss}"); + if (r < 0) + return r; + + STRV_FOREACH_PAIR(k, v, details) { + r = sd_bus_message_append(pk, "{ss}", *k, *v); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(pk); + if (r < 0) + return r; + + r = sd_bus_message_append(pk, "us", !!interactive, NULL); if (r < 0) return r; diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 4ae216b7d9..d2b2d701ce 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -60,9 +60,9 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error); int bus_check_peercred(sd_bus *c); -int bus_test_polkit(sd_bus_message *call, int capability, const char *action, uid_t good_user, bool *_challenge, sd_bus_error *e); +int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e); -int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); +int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); void bus_verify_polkit_async_registry_free(Hashmap *registry); int bus_open_system_systemd(sd_bus **_bus); diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index 9260396d5d..59c6eedcda 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -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); diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index ecc9d70bf4..ff7e45901c 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -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; } diff --git a/src/test/test-engine.c b/src/test/test-engine.c index a7ab21a415..6596069ade 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { + if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { printf("Skipping test: manager_new: %s", strerror(-r)); return EXIT_TEST_SKIP; } diff --git a/src/test/test-path.c b/src/test/test-path.c index 5d190378f1..676c9f1793 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -40,7 +40,7 @@ static int setup_test(Manager **m) { assert_se(m); r = manager_new(MANAGER_USER, true, &tmp); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { + if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { printf("Skipping test: manager_new: %s", strerror(-r)); return -EXIT_TEST_SKIP; } diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index f915539e00..ebc9110c4d 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) { /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { + if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { printf("Skipping test: manager_new: %s", strerror(-r)); return EXIT_TEST_SKIP; } diff --git a/src/test/test-util.c b/src/test/test-util.c index dff38ab6f6..8ceb71f22a 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -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) { diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 42ae70fd1d..6de9e246f6 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -361,6 +361,7 @@ static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error * m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-timezone", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -428,6 +429,7 @@ static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-local-rtc", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -543,6 +545,7 @@ static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *erro m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-time", + NULL, interactive, UID_INVALID, &c->polkit_registry, @@ -601,6 +604,7 @@ static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-ntp", + NULL, interactive, UID_INVALID, &c->polkit_registry, |