summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-01-05 19:46:38 +0100
committerGitHub <noreply@github.com>2018-01-05 19:46:38 +0100
commit2df46112052ee9752ce2d2920ad6184b304c77ed (patch)
treeb89e539530c0485e172417c2d1b4050de2ca4bb8
parent65d36b49508a53e56bae9609ff00fdc3de340608 (diff)
parentf3c33b234d9f0256805722f02c7b4c4b59fd6de6 (diff)
downloadsystemd-2df46112052ee9752ce2d2920ad6184b304c77ed.tar.gz
Merge pull request #7714 from poettering/sd-bus-watch-connect
many sd-bus improvements
-rw-r--r--TODO7
-rw-r--r--man/busctl.xml10
-rw-r--r--man/rules/meson.build21
-rw-r--r--man/runlevel.xml5
-rw-r--r--man/sd_bus_add_match.xml137
-rw-r--r--man/sd_bus_is_open.xml137
-rw-r--r--man/sd_bus_message_set_destination.xml137
-rw-r--r--man/sd_bus_request_name.xml140
-rw-r--r--man/sd_bus_set_connected_signal.xml143
-rw-r--r--man/sd_bus_set_sender.xml136
-rw-r--r--man/sd_bus_set_watch_bind.xml152
-rw-r--r--meson.build8
-rw-r--r--src/basic/def.h7
-rw-r--r--src/basic/fs-util.c57
-rw-r--r--src/basic/io-util.c9
-rw-r--r--src/basic/socket-label.c23
-rw-r--r--src/basic/socket-util.c35
-rw-r--r--src/basic/socket-util.h12
-rw-r--r--src/basic/verbs.c39
-rw-r--r--src/busctl/busctl.c23
-rw-r--r--src/core/dbus.c66
-rw-r--r--src/core/manager.c2
-rw-r--r--src/core/unit.c2
-rw-r--r--src/hostname/hostnamed.c4
-rw-r--r--src/import/importd.c4
-rw-r--r--src/libsystemd/libsystemd.sym17
-rw-r--r--src/libsystemd/sd-bus/bus-control.c427
-rw-r--r--src/libsystemd/sd-bus/bus-control.h4
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c66
-rw-r--r--src/libsystemd/sd-bus/bus-internal.c15
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h99
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.c46
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.h2
-rw-r--r--src/libsystemd/sd-bus/bus-message.c10
-rw-r--r--src/libsystemd/sd-bus/bus-message.h4
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c2
-rw-r--r--src/libsystemd/sd-bus/bus-slot.c13
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c303
-rw-r--r--src/libsystemd/sd-bus/bus-socket.h1
-rw-r--r--src/libsystemd/sd-bus/bus-track.c30
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c826
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-watch-bind.c239
-rw-r--r--src/libsystemd/sd-login/sd-login.c7
-rw-r--r--src/libudev/libudev-queue.c10
-rw-r--r--src/locale/localed.c4
-rw-r--r--src/login/logind-user-dbus.c12
-rw-r--r--src/login/logind.c95
-rw-r--r--src/login/pam_systemd.c2
-rw-r--r--src/machine/machinectl.c37
-rw-r--r--src/machine/machined.c96
-rw-r--r--src/network/netdev/netdev.c18
-rw-r--r--src/network/netdev/netdev.h5
-rw-r--r--src/network/networkd-manager.c98
-rw-r--r--src/network/networkd-manager.h1
-rw-r--r--src/nspawn/nspawn.c16
-rw-r--r--src/resolve/resolved-bus.c55
-rw-r--r--src/run/run.c19
-rw-r--r--src/shared/ask-password-api.c2
-rw-r--r--src/shared/bus-unit-util.c30
-rw-r--r--src/shared/bus-util.c79
-rw-r--r--src/shared/bus-util.h2
-rw-r--r--src/systemctl/systemctl.c26
-rw-r--r--src/systemd/sd-bus.h16
-rw-r--r--src/test/meson.build4
-rw-r--r--src/test/test-condition.c6
-rw-r--r--src/test/test-fs-util.c87
-rw-r--r--src/timedate/timedated.c4
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c2
-rw-r--r--tools/meson-check-api-docs.sh11
70 files changed, 3115 insertions, 1053 deletions
diff --git a/TODO b/TODO
index 251ce4f8ec..a28c82ed66 100644
--- a/TODO
+++ b/TODO
@@ -35,6 +35,9 @@ Features:
* add bpf-based implementation of devices cgroup controller logic for compat with cgroupsv2 as supported by newest kernel
+* sd-bus: add vtable flag, that may be used to request client creds implicitly
+ and asynchronously before dispatching the operation
+
* implement transient socket unit.
* make systemd-run create transient path and socket unit.
@@ -56,8 +59,6 @@ Features:
the runtime dir as we maintain for the fdstore: i.e. keep it around as long
as the unit is running or has a job queued.
-* add async version of sd_bus_add_match and make use of that
-
* support projid-based quota in machinectl for containers, and then drop
implicit btrfs loopback magic in machined
@@ -495,14 +496,12 @@ Features:
- see if we can introduce a new sd_bus_get_owner_machine_id() call to retrieve the machine ID of the machine of the bus itself
- see if we can drop more message validation on the sending side
- add API to clone sd_bus_message objects
- - make AddMatch calls on dbus1 transports async?
- longer term: priority inheritance
- dbus spec updates:
- NameLost/NameAcquired obsolete
- GVariant
- path escaping
- update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now
- - test bloom filter generation indexes
* sd-event
- allow multiple signal handlers per signal?
diff --git a/man/busctl.xml b/man/busctl.xml
index 0c0d28b5d3..2320cb8ed3 100644
--- a/man/busctl.xml
+++ b/man/busctl.xml
@@ -241,6 +241,16 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--watch-bind=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem>
+ <para>Controls whether to wait for the specified <constant>AF_UNIX</constant> bus socket to appear in the
+ file system before connecting to it. Defaults to off. When enabled, the tool will watch the file system until
+ the socket is created and then connect to it.</para>
+ </listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="user" />
<xi:include href="user-system-options.xml" xpointer="system" />
<xi:include href="user-system-options.xml" xpointer="host" />
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 54c5a9d923..bfc267b544 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -105,7 +105,12 @@ manpages = [
['sd-journal', '3', [], ''],
['sd-login', '3', [], 'HAVE_PAM'],
['sd_booted', '3', [], ''],
- ['sd_bus_add_match', '3', [], ''],
+ ['sd_bus_add_match',
+ '3',
+ ['sd_bus_add_match_async',
+ 'sd_bus_match_signal',
+ 'sd_bus_match_signal_async'],
+ ''],
['sd_bus_creds_get_pid',
'3',
['sd_bus_creds_get_audit_login_uid',
@@ -181,6 +186,7 @@ manpages = [
['SD_BUS_ERROR_END', 'SD_BUS_ERROR_MAP', 'sd_bus_error_map'],
''],
['sd_bus_get_fd', '3', [], ''],
+ ['sd_bus_is_open', '3', ['sd_bus_is_ready'], ''],
['sd_bus_message_append', '3', ['sd_bus_message_appendv'], ''],
['sd_bus_message_append_array',
'3',
@@ -200,6 +206,7 @@ manpages = [
['sd_bus_message_get_realtime_usec', 'sd_bus_message_get_seqnum'],
''],
['sd_bus_message_read_basic', '3', [], ''],
+ ['sd_bus_message_set_destination', '3', ['sd_bus_message_set_sender'], ''],
['sd_bus_negotiate_fds',
'3',
['sd_bus_negotiate_creds', 'sd_bus_negotiate_timestamp'],
@@ -210,7 +217,15 @@ manpages = [
['sd_bus_path_decode', 'sd_bus_path_decode_many', 'sd_bus_path_encode_many'],
''],
['sd_bus_process', '3', [], ''],
- ['sd_bus_request_name', '3', ['sd_bus_release_name'], ''],
+ ['sd_bus_request_name',
+ '3',
+ ['sd_bus_release_name',
+ 'sd_bus_release_name_async',
+ 'sd_bus_request_name_async'],
+ ''],
+ ['sd_bus_set_connected_signal', '3', ['sd_bus_get_connected_signal'], ''],
+ ['sd_bus_set_sender', '3', ['sd_bus_get_sender'], ''],
+ ['sd_bus_set_watch_bind', '3', ['sd_bus_get_watch_bind'], ''],
['sd_bus_track_add_name',
'3',
['sd_bus_track_add_sender',
@@ -655,6 +670,7 @@ manpages = [
['systemd', '1', ['init'], ''],
['systemd.automount', '5', [], ''],
['systemd.device', '5', [], ''],
+ ['systemd.dnssd', '5', [], 'ENABLE_RESOLVE'],
['systemd.environment-generator', '7', [], 'ENABLE_ENVIRONMENT_D'],
['systemd.exec', '5', [], ''],
['systemd.generator', '7', [], ''],
@@ -663,7 +679,6 @@ manpages = [
['systemd.link', '5', [], ''],
['systemd.mount', '5', [], ''],
['systemd.netdev', '5', [], 'ENABLE_NETWORKD'],
- ['systemd.dnssd', '5', [], 'ENABLE_RESOLVE'],
['systemd.network', '5', [], 'ENABLE_NETWORKD'],
['systemd.nspawn', '5', [], ''],
['systemd.offline-updates', '7', [], ''],
diff --git a/man/runlevel.xml b/man/runlevel.xml
index b3d90d8ff4..596307af9f 100644
--- a/man/runlevel.xml
+++ b/man/runlevel.xml
@@ -173,10 +173,9 @@
<variablelist>
<varlistentry>
- <term><filename>/var/run/utmp</filename></term>
+ <term><filename>/run/utmp</filename></term>
- <listitem><para>The utmp database <command>runlevel</command>
- reads the previous and current runlevel
+ <listitem><para>The utmp database <command>runlevel</command> reads the previous and current runlevel
from.</para></listitem>
</varlistentry>
</variablelist>
diff --git a/man/sd_bus_add_match.xml b/man/sd_bus_add_match.xml
index 4772c738ac..f11d078284 100644
--- a/man/sd_bus_add_match.xml
+++ b/man/sd_bus_add_match.xml
@@ -45,8 +45,11 @@
<refnamediv>
<refname>sd_bus_add_match</refname>
+ <refname>sd_bus_add_match_async</refname>
+ <refname>sd_bus_match_signal</refname>
+ <refname>sd_bus_match_signal_async</refname>
- <refpurpose>Add a match rule for message dispatching</refpurpose>
+ <refpurpose>Add a match rule for incoming message dispatching</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -54,6 +57,13 @@
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<funcprototype>
+ <funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_bus_add_match</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
<paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
@@ -63,57 +73,111 @@
</funcprototype>
<funcprototype>
- <funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
- <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <funcdef>int <function>sd_bus_add_match_async</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>match</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>callback</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>install_callback</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_match_signal</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>sender</parameter></paramdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>const char *<parameter>member</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>callback</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_match_signal_async</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>sender</parameter></paramdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>const char *<parameter>member</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>callback</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>install_callback</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
- <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
</funcprototype>
+
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para>
- <function>sd_bus_add_match()</function> installs a match rule for incoming messages received on the specified bus
- connection object <parameter>bus</parameter>. The syntax of the match rule expression passed in
- <parameter>match</parameter> is described in the <ulink
- url="https://dbus.freedesktop.org/doc/dbus-specification.html">D-Bus Specification</ulink>. The specified handler
- function <parameter>callback</parameter> is called for eaching incoming message matching the specified
- expression, the <parameter>userdata</parameter> parameter is passed as-is to the callback function.
+ <para><function>sd_bus_add_match()</function> installs a match rule for messages received on the specified bus
+ connection object <parameter>bus</parameter>. The syntax of the match rule expression passed in
+ <parameter>match</parameter> is described in the <ulink
+ url="https://dbus.freedesktop.org/doc/dbus-specification.html">D-Bus Specification</ulink>. The specified handler
+ function <parameter>callback</parameter> is called for eaching incoming message matching the specified expression,
+ the <parameter>userdata</parameter> parameter is passed as-is to the callback function. The match is installed
+ synchronously when connected to a bus broker, i.e. the call sends a control message requested the match to be added
+ to the broker and waits until the broker confirms the match has been installed successfully.</para>
+
+ <para><function>sd_bus_add_match_async()</function> operates very similar to
+ <function>sd_bus_match_signal()</function>, however it installs the match asynchronously, in a non-blocking
+ fashion: a request is sent to the broker, but the call does not wait for a response. The
+ <parameter>install_callback</parameter> function is called when the response is later received, with the response
+ message from the broker as parameter. If this function is specified as <constant>NULL</constant> a default
+ implementation is used that terminates the bus connection should installing the match fail.</para>
+
+ <para><function>sd_bus_match_signal()</function> is very similar to <function>sd_bus_add_match()</function>, but
+ only matches signals, and instead of a match expression accepts four parameters: <parameter>sender</parameter> (the
+ service name of the sender), <parameter>path</parameter> (the object path of the emitting object),
+ <parameter>interface</parameter> (the interface the signal belongs to), <parameter>member</parameter> (the signal
+ name), from which the match string is internally generated. Optionally, these parameters may be specified as
+ <constant>NULL</constant> in which case the relevant field of incoming signals is not tested.</para>
+
+ <para><function>sd_bus_match_signal_async()</function> is combines the signal matching logic of
+ <function>sd_bus_match_signal()</function> with the asynchronous behaviour of
+ <function>sd_bus_add_match_async()</function>.</para>
+
+ <para>On success, and if non-<constant>NULL</constant>, the <parameter>slot</parameter> return parameter will be
+ set to a slot object that may be used as a reference to the installed match, and may be utilized to remove it again
+ at a later time with
+ <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If specified
+ as <constant>NULL</constant> the lifetime of the match is bound to the lifetime of the bus object itself, and the
+ match cannot be removed independently.</para>
+
+ <para>The message <parameter>m</parameter> passed to the callback is only borrowed, that is, the callback should
+ not call <citerefentry><refentrytitle>sd_bus_message_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ on it. If the callback wants to hold on to the message beyond the lifetime of the callback, it needs to call
+ <citerefentry><refentrytitle>sd_bus_message_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry> to create a
+ new reference.</para>
+
+ <para>If an error occurs during the callback invocation, the callback should return a negative error number
+ (optionally, a more precise error may be returned in <parameter>ret_error</parameter>, as well). If it wants other
+ callbacks that match the same rule to be called, it should return 0. Otherwise it should return a positive integer.
</para>
- <para>
- On success, and if non-<constant>NULL</constant>, the <parameter>slot</parameter> return parameter will be set to
- a slot object that may be used as a reference to the installed match, and may be utilized to remove it again at a
- later time with
- <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If
- specified as <constant>NULL</constant> the lifetime of the match is bound to the lifetime of the bus object itself, and the match
- cannot be removed independently.
- </para>
+ <para>If the <parameter>bus</parameter> refers to a direct connection (i.e. not a bus connection, as set with
+ <citerefentry><refentrytitle>sd_bus_set_bus_client</refentrytitle><manvolnum>3</manvolnum></citerefentry>) the
+ match is only installed on the client side, and the synchronous and asynchronous functions operate the same.</para>
+ </refsect1>
- <para>
- The message <parameter>m</parameter> passed to the callback is only borrowed, that is, the callback should not
- call <citerefentry><refentrytitle>sd_bus_message_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry> on
- it. If the callback wants to hold on to the message beyond the lifetime of the callback, it needs to call
- <citerefentry><refentrytitle>sd_bus_message_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry> to create
- a new reference.
- </para>
+ <refsect1>
+ <title>Return Value</title>
<para>
- If an error occurs during the callback invocation, the callback should return a negative error number. If it
- wants other callbacks that match the same rule to be called, it should return 0. Otherwise it should return a
- positive integer.
+ On success, <function>sd_bus_add_match()</function> and the other calls return 0 or a positive integer. On
+ failure, they return a negative errno-style error code.
</para>
</refsect1>
<refsect1>
- <title>Return Value</title>
+ <title>Notes</title>
- <para>
- On success, <function>sd_bus_add_match()</function> returns 0 or a positive integer. On failure, it returns a
- negative errno-style error code.
- </para>
+ <para><function>sd_bus_add_match()</function> and the other functions described here are available as a shared
+ library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
</refsect1>
<refsect1>
@@ -121,7 +185,10 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_message_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_set_bus_client</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/sd_bus_is_open.xml b/man/sd_bus_is_open.xml
new file mode 100644
index 0000000000..9bc671fc37
--- /dev/null
+++ b/man/sd_bus_is_open.xml
@@ -0,0 +1,137 @@
+<?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">
+
+<!--
+ SPDX-License-Identifier: LGPL-2.1+
+
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_bus_is_open">
+
+ <refentryinfo>
+ <title>sd_bus_is_open</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Lennart</firstname>
+ <surname>Poettering</surname>
+ <email>lennart@poettering.net</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_is_open</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_is_open</refname>
+ <refname>sd_bus_is_ready</refname>
+
+ <refpurpose>Check whether the a bus connection is open or ready.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_is_open</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_is_ready</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_is_open()</function> checks whether the specified bus connection is open, i.e. in the
+ process of being established, already established or in the process of being torn down. It returns zero when the
+ connection has not been started yet
+ (i.e. <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry> or some
+ equivalent call has not been invoked yet), or is fully terminated again (for example after
+ <citerefentry><refentrytitle>sd_bus_close</refentrytitle><manvolnum>3</manvolnum></citerefentry>), it returns
+ positive otherwise.</para>
+
+ <para><function>sd_bus_is_ready()</function> checks whether the specified connection is fully established,
+ i.e. completed the connection and authentication phases of the protocol and received the
+ <function>Hello()</function> method call response, and is not in the process of being torn down again. It returns
+ zero outside of this state, and positive otherwise. Effectively, this function returns positive while regular
+ messages can be sent or received on the connection.</para>
+
+ <para>To be notified when the connection is fully established, use
+ <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
+ install a match for the <function>Connected()</function> signal on the
+ <literal>org.freedesktop.DBus.Local</literal> interface. To be notified when the connection is torn down again,
+ install a match for the <function>Disconnected()</function> signal on the
+ <literal>org.freedesktop.DBus.Local</literal> interface.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
+ error code.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus connection has been created in a different process.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para><function>sd_bus_is_open()</function> and <function>sd_bus_is_ready()</function> are available as
+ a shared library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_close</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/sd_bus_message_set_destination.xml b/man/sd_bus_message_set_destination.xml
new file mode 100644
index 0000000000..ff69a23152
--- /dev/null
+++ b/man/sd_bus_message_set_destination.xml
@@ -0,0 +1,137 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+ SPDX-License-Identifier: LGPL-2.1+
+
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_bus_message_set_destination">
+
+ <refentryinfo>
+ <title>sd_bus_message_set_destination</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Lennart</firstname>
+ <surname>Poettering</surname>
+ <email>lennart@poettering.net</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_message_set_destination</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_message_set_destination</refname>
+ <refname>sd_bus_message_set_sender</refname>
+ <refpurpose>Set the destination or sender service name of a bus message</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_message_set_destination</function></funcdef>
+ <paramdef>sd_bus_message *<parameter>message</parameter></paramdef>
+ <paramdef>const char *<parameter>destination</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_message_set_sender</function></funcdef>
+ <paramdef>sd_bus_message *<parameter>message</parameter></paramdef>
+ <paramdef>const char *<parameter>sender</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_message_set_destination()</function> sets the destination service name for the specified bus
+ message object. The specified name must be a valid unique or well-known service name.</para>
+
+ <para><function>sd_bus_message_set_sender()</function> sets the sender service name for the specified bus message
+ object. The specified name must be a valid unique or well-known service name. This function is useful only for
+ messages to send on direct connections as for connections to bus brokers the broker will fill in the destination
+ field anyway, and the sender field set by original sender is ignored.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these calls return 0 or a positive integer. On failure, these calls return a negative 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>A specified parameter is invalid.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EPERM</constant></term>
+
+ <listitem><para>The message is already sealed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EEXIST</constant></term>
+
+ <listitem><para>The message already has a destination or sender field set.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>The <function>sd_bus_message_set_destination()</function> and
+ <function>sd_bus_message_set_sender()</function> interfaces
+ are available as a shared library, which can be compiled and
+ linked to with the
+ <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_set_sender</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/sd_bus_request_name.xml b/man/sd_bus_request_name.xml
index f44cfdb1ac..9e668f0b02 100644
--- a/man/sd_bus_request_name.xml
+++ b/man/sd_bus_request_name.xml
@@ -46,7 +46,9 @@
<refnamediv>
<refname>sd_bus_request_name</refname>
+ <refname>sd_bus_request_name_async</refname>
<refname>sd_bus_release_name</refname>
+ <refname>sd_bus_release_name_async</refname>
<refpurpose>Request or release a well-known service name on a bus</refpurpose>
</refnamediv>
@@ -62,70 +64,102 @@
</funcprototype>
<funcprototype>
+ <funcdef>int <function>sd_bus_request_name_async</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>uint64_t <parameter>flags</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>callback</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_bus_release_name</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
</funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_release_name_async</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>sd_bus_message_handler_t <parameter>callback</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_bus_request_name()</function> requests a
- well-known service name on a bus. It takes a bus connection, a
- valid bus name and a flags parameter. The flags parameter is a
- combination of the following flags:</para>
+ <para><function>sd_bus_request_name()</function> requests a well-known service name on a bus. It takes a bus
+ connection, a valid bus name and a flags parameter. The flags parameter is a combination of the following
+ flags:</para>
<variablelist>
<varlistentry>
<term><varname>SD_BUS_NAME_ALLOW_REPLACEMENT</varname></term>
- <listitem><para>After acquiring the name successfully, permit
- other peers to take over the name when they try to acquire it
- with the <varname>SD_BUS_NAME_REPLACE_EXISTING</varname> flag
- set. If <varname>SD_BUS_NAME_ALLOW_REPLACEMENT</varname> is
- not set on the original request, such a request by other peers
- will be denied.</para></listitem>
+ <listitem><para>After acquiring the name successfully, permit other peers to take over the name when they try
+ to acquire it with the <varname>SD_BUS_NAME_REPLACE_EXISTING</varname> flag set. If
+ <varname>SD_BUS_NAME_ALLOW_REPLACEMENT</varname> is not set on the original request, such a request by other
+ peers will be denied.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SD_BUS_NAME_REPLACE_EXISTING</varname></term>
- <listitem><para>Take over the name if it is already acquired
- by another peer, and that other peer has permitted takeover by
- setting <varname>SD_BUS_NAME_ALLOW_REPLACEMENT</varname> while
- acquiring it.</para></listitem>
+ <listitem><para>Take over the name if it is already acquired by another peer, and that other peer has permitted
+ takeover by setting <varname>SD_BUS_NAME_ALLOW_REPLACEMENT</varname> while acquiring it.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SD_BUS_NAME_QUEUE</varname></term>
- <listitem><para>Queue the acquisition of the name when the
- name is already taken.</para></listitem>
+ <listitem><para>Queue the acquisition of the name when the name is already taken.</para></listitem>
</varlistentry>
</variablelist>
- <para><function>sd_bus_release_name()</function> releases an
- acquired well-known name. It takes a bus connection and a valid
- bus name as parameters.</para>
+ <para><function>sd_bus_request_name()</function> operates in a synchronous fashion: a message requesting the name
+ is sent to the bus broker, and the call waits until the broker responds.</para>
+
+ <para><function>sd_bus_request_name_async()</function> is an asynchronous version of of
+ <function>sd_bus_release_name()</function>. Instead of waiting for the request to complete, the request message is
+ enqueued. The specified <parameter>callback</parameter> will be called when the broker's response is received. If
+ the parameter is specified as <constant>NULL</constant> a default implementation is used instead which will
+ terminate the connection when the name cannot be acquired. The function returns a slot object in its
+ <parameter>slot</parameter> parameter — if it is passed as non-<constant>NULL</constant> — which may be used as a
+ reference to the name request operation. Use
+ <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry> to destroy
+ this reference. Note that destroying the reference will not unregister the name, but simply ensure the specified
+ callback is no longer called.</para>
+
+ <para><function>sd_bus_release_name()</function> releases an acquired well-known name. It takes a bus connection
+ and a valid bus name as parameters. This function operates synchronously, sending a release request message to the
+ bus broker and waiting for it to reply.</para>
+
+ <para><function>sd_bus_release_name_async()</function> is an asynchronous version of
+ <function>sd_bus_release_name()</function>. The specified <parameter>callback</parameter> function is called when
+ the name has been released successfully. If specified as <constant>NULL</constant> a generic implementation is used
+ that ignores the result of the operation. As above, the <parameter>slot</parameter> (if
+ non-<constant>NULL</constant>) is set to an object that may be used to reference the operation.</para>
+
+ <para>These functions are supported only on bus connections, i.e. connections to a bus broker and not on direct
+ connections.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para>On success, these calls return 0 or a positive integer. On
- failure, these calls return a negative errno-style error
- code.</para>
-
- <para>If <varname>SD_BUS_NAME_QUEUE</varname> is specified,
- <function>sd_bus_request_name()</function> will return 0 when the
- name is already taken by another peer and the client has been
- added to the queue for the name. In that case, the caller can
- subscribe to <literal>NameOwnerChanged</literal> signals to be
- notified when the name is successfully acquired.
- <function>sd_bus_request_name()</function> returns &gt; 0 when the
- name has immediately been acquired successfully.</para>
+ <para>On success, these calls return 0 or a positive integer. On failure, these calls return a negative errno-style
+ error code.</para>
+
+ <para>If <varname>SD_BUS_NAME_QUEUE</varname> is specified, <function>sd_bus_request_name()</function> will return
+ 0 when the name is already taken by another peer and the client has been added to the queue for the name. In that
+ case, the caller can subscribe to <literal>NameOwnerChanged</literal> signals to be notified when the name is
+ successfully acquired. <function>sd_bus_request_name()</function> returns &gt; 0 when the name has immediately
+ been acquired successfully.</para>
</refsect1>
<refsect1>
@@ -137,56 +171,50 @@
<varlistentry>
<term><constant>-EALREADY</constant></term>
- <listitem><para>The caller already is the owner of the
- specified name.</para></listitem>
+ <listitem><para>The caller already is the owner of the specified name.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-EEXIST</constant></term>
- <listitem><para>The name has already been acquired by a
- different peer, and SD_BUS_NAME_REPLACE_EXISTING was not
- specified or the other peer did not specify
- SD_BUS_NAME_ALLOW_REPLACEMENT while acquiring the
+ <listitem><para>The name has already been acquired by a different peer, and SD_BUS_NAME_REPLACE_EXISTING was
+ not specified or the other peer did not specify SD_BUS_NAME_ALLOW_REPLACEMENT while acquiring the
name.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ESRCH</constant></term>
- <listitem><para>It was attempted to release a name that is
- currently not registered on the bus.</para></listitem>
+ <listitem><para>It was attempted to release a name that is currently not registered on the
+ bus.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-EADDRINUSE</constant></term>
- <listitem><para>It was attempted to release a name that is
- owned by a different peer on the bus.</para></listitem>
+ <listitem><para>It was attempted to release a name that is owned by a different peer on the
+ bus.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
- <listitem><para>A specified parameter is invalid. This is also
- generated when the requested name is a special service name
- reserved by the D-Bus specification, or when the operation is
- requested on a connection that does not refer to a
- bus.</para></listitem>
+ <listitem><para>A specified parameter is invalid. This is also generated when the requested name is a special
+ service name reserved by the D-Bus specification, or when the operation is requested on a connection that does
+ not refer to a bus.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOTCONN</constant></term>
- <listitem><para>The bus connection has been
- disconnected.</para></listitem>
+ <listitem><para>The bus connection has been disconnected.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ECHILD</constant></term>
- <listitem><para>The bus connection has been created in a
- different process than the current one.</para></listitem>
+ <listitem><para>The bus connection has been created in a different process than the current
+ one.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
@@ -194,12 +222,9 @@
<refsect1>
<title>Notes</title>
- <para>The <function>sd_bus_acquire_name()</function> and
- <function>sd_bus_release_name()</function> interfaces are
- available as a shared library, which can be compiled and linked to
- with the
- <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- file.</para>
+ <para>The <function>sd_bus_acquire_name()</function> and the other interfaces described here are available as a
+ shared library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
</refsect1>
<refsect1>
@@ -208,7 +233,8 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/sd_bus_set_connected_signal.xml b/man/sd_bus_set_connected_signal.xml
new file mode 100644
index 0000000000..9374dac3a5
--- /dev/null
+++ b/man/sd_bus_set_connected_signal.xml
@@ -0,0 +1,143 @@
+<?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">
+
+<!--
+ SPDX-License-Identifier: LGPL-2.1+
+
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_bus_set_connected_signal">
+
+ <refentryinfo>
+ <title>sd_bus_set_connected_signal</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Lennart</firstname>
+ <surname>Poettering</surname>
+ <email>lennart@poettering.net</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_set_connected_signal</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_set_connected_signal</refname>
+ <refname>sd_bus_get_connected_signal</refname>
+
+ <refpurpose>Control emmission of local connection establishment signal on bus connections</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_set_connected_signal</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>int <parameter>b</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_connected_signal</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_set_connected_signal()</function> may be used to control whether a local, synthetic
+ <function>Connected()</function> signal message shall be generated and enqueued for dispatching when the connection
+ is fully established. If the <parameter>b</parameter> parameter is zero the message is not generated (the default),
+ otherwise it is generated.</para>
+
+ <para><function>sd_bus_get_connected_signal()</function> may be used to query whether this feature is enabled. It
+ returns zero if not, positive otherwise.</para>
+
+ <para>The <function>Connected()</function> signal message is generated from the
+ <literal>org.freedesktop.DBus.Local</literal> service and interface, and
+ <literal>/org/freedesktop/DBus/Local</literal> object path. Use
+ <citerefentry><refentrytitle>sd_bus_match_signal_async</refentrytitle><manvolnum>3</manvolnum></citerefentry> to
+ match on this signal.</para>
+
+ <para>This message is particularly useful on slow transports where connections take a long time to be
+ established. This is especially the case when
+ <citerefentry><refentrytitle>sd_bus_set_watch_bind</refentrytitle><manvolnum>3</manvolnum></citerefentry> is
+ used. The signal is generated when the
+ <citerefentry><refentrytitle>sd_bus_is_ready</refentrytitle><manvolnum>3</manvolnum></citerefentry> returns
+ positive for the first time.</para>
+
+ <para>The <function>Connected()</function> signal corresponds with the <function>Disconnected()</function> signal
+ that is synthesized locally when the connection is terminated. The latter is generated unconditionally however,
+ unlike the former which needs to be enabled explicitly before it is generated, with
+ <function>sd_bus_set_connected_signal()</function>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
+ error code.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus connection has been created in a different process.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para><function>sd_bus_set_connected_signal()</function> and <function>sd_bus_get_connected_signal()</function> are available as
+ a shared library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_match_signal_async</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_set_watch_bind</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_is_ready</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/sd_bus_set_sender.xml b/man/sd_bus_set_sender.xml
new file mode 100644
index 0000000000..38efda7286
--- /dev/null
+++ b/man/sd_bus_set_sender.xml
@@ -0,0 +1,136 @@
+<?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">
+
+<!--
+ SPDX-License-Identifier: LGPL-2.1+
+
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_bus_set_sender">
+
+ <refentryinfo>
+ <title>sd_bus_set_sender</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Lennart</firstname>
+ <surname>Poettering</surname>
+ <email>lennart@poettering.net</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_set_sender</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_set_sender</refname>
+ <refname>sd_bus_get_sender</refname>
+
+ <refpurpose>Configure default sender for outgoing messages</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_set_sender</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_sender</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>const char** <parameter>name</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_set_sender()</function> configures the default sender service name to use for outgoing
+ messages. The service name specified in the <parameter>name</parameter> parameter is set on all outgoing messages
+ that are sent on the connection and have no sender set yet, for example through
+ <citerefentry><refentrytitle>sd_bus_message_set_sender</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Note
+ that this function is only supported on direct connections, i.e. not on connections to a bus broker as the broker
+ will fill in the sender service name automatically anyway. By default no sender name is configured, and hence
+ messages are sent without sender field set. If the <parameter>name</parameter> parameter is specified as
+ <constant>NULL</constant> the default sender service name is cleared, returning to the default state if a default
+ sender service name was set before. If passed as non-<constant>NULL</constant> the specified name must be a valid
+ unique or well-known service name.</para>
+
+ <para><function>sd_bus_get_sender()</function> may be used to query the current default service name for outgoing
+ messages.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
+ error code.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus connection has been created in a different process.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EPERM</constant></term>
+
+ <listitem><para>The specified bus connection object is a not a direct but a brokered connection.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para><function>sd_bus_set_sender()</function> and <function>sd_bus_get_sender()</function> are available as
+ a shared library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_message_set_sender</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/sd_bus_set_watch_bind.xml b/man/sd_bus_set_watch_bind.xml
new file mode 100644
index 0000000000..5e6a6fa588
--- /dev/null
+++ b/man/sd_bus_set_watch_bind.xml
@@ -0,0 +1,152 @@
+<?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">
+
+<!--
+ SPDX-License-Identifier: LGPL-2.1+
+
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_bus_set_watch_bind">
+
+ <refentryinfo>
+ <title>sd_bus_set_watch_bind</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Lennart</firstname>
+ <surname>Poettering</surname>
+ <email>lennart@poettering.net</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_set_watch_bind</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_set_watch_bind</refname>
+ <refname>sd_bus_get_watch_bind</refname>
+
+ <refpurpose>Control socket binding watching on bus connections</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_set_watch_bind</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>int <parameter>b</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_watch_bind</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_set_watch_bind()</function> may be used to enable or disable client-side watching of server
+ socket binding for a bus connection object. If the <parameter>b</parameter> is true, the feature is enabled,
+ otherwise disabled (which is the default). When enabled, and the selected bus address refers to an
+ <filename>AF_UNIX</filename> socket in the file system which does not exist while the connection attempt is made an
+ <citerefentry><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry> watch is installed on
+ it, waiting for the socket to appear. As soon as the socket appears the connection is made. This functionality is
+ useful in particular in early-boot programs that need to run before the system bus is available, but want to
+ connect to it the instant it may be connected to.</para>
+
+ <para><function>sd_bus_get_watch_bind()</function> may be used to query the current setting of this feature. It
+ returns zero when the feature is disabled, and positive if enabled.</para>
+
+ <para>Note that no timeout is applied while it is waited for the socket to appear. This means that any synchronous
+ remote operation (such as
+ <citerefentry><refentrytitle>sd_bus_call</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
+ <citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>), that is
+ used on a connection with this feature enabled that is not established yet might block unbounded if the socket is
+ never created. However, asynchronous remote operations (such as
+ <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_add_match_async</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
+ <citerefentry><refentrytitle>sd_bus_request_match_async</refentrytitle><manvolnum>3</manvolnum></citerefentry>) do
+ not block in this case, and safely enqueue the requested operations to be dispatched the instant the connection is
+ set up.</para>
+
+ <para>Use <citerefentry><refentrytitle>sd_bus_is_ready</refentrytitle><manvolnum>3</manvolnum></citerefentry> to
+ determine whether the connection is fully established, i.e. whether the peer socket has been bound, connected to
+ and authenticated. Use
+ <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry> to
+ be notified when the connection is fully established.</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
+ error code.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus connection has been created in a different process.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para><function>sd_bus_set_watch_bind()</function> and <function>sd_bus_get_watch_bind()</function> are available as
+ a shared library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_call</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_is_ready</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/meson.build b/meson.build
index f95feee99d..924274de63 100644
--- a/meson.build
+++ b/meson.build
@@ -2556,6 +2556,14 @@ endif
############################################################
+meson_check_api_docs_sh = find_program('tools/meson-check-api-docs.sh')
+run_target(
+ 'check-api-docs',
+ depends : [man, libsystemd, libudev],
+ command : [meson_check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
+
+############################################################
+
status = [
'@0@ @1@'.format(meson.project_name(), meson.project_version()),
diff --git a/src/basic/def.h b/src/basic/def.h
index 77ab735aed..43e7e17008 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -53,9 +53,10 @@
"/usr/lib/kbd/keymaps/\0"
#endif
-#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
-#define DEFAULT_SYSTEM_BUS_ADDRESS UNIX_SYSTEM_BUS_ADDRESS
-#define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
+/* Note that we use the new /run prefix here (instead of /var/run) since we require them to be aliases and that way we
+ * become independent of /var being mounted */
+#define DEFAULT_SYSTEM_BUS_ADDRESS "unix:path=/run/dbus/system_bus_socket"
+#define DEFAULT_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
#define PLYMOUTH_SOCKET { \
.un.sun_family = AF_UNIX, \
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 4ca36faf09..16f97893c9 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -315,43 +315,60 @@ int fd_warn_permissions(const char *path, int fd) {
}
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
- _cleanup_close_ int fd;
- int r;
+ char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ _cleanup_close_ int fd = -1;
+ int r, ret = 0;
assert(path);
- if (parents)
- mkdir_parents(path, 0755);
-
- fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
- IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
- if (fd < 0)
- return -errno;
+ /* Note that touch_file() does not follow symlinks: if invoked on an existing symlink, then it is the symlink
+ * itself which is updated, not its target
+ *
+ * Returns the first error we encounter, but tries to apply as much as possible. */
- if (mode != MODE_INVALID) {
- r = fchmod(fd, mode);
- if (r < 0)
+ if (parents)
+ (void) mkdir_parents(path, 0755);
+
+ /* Initially, we try to open the node with O_PATH, so that we get a reference to the node. This is useful in
+ * case the path refers to an existing device or socket node, as we can open it successfully in all cases, and
+ * won't trigger any driver magic or so. */
+ fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+ if (fd < 0) {
+ if (errno != ENOENT)
return -errno;
- }
- if (uid != UID_INVALID || gid != GID_INVALID) {
- r = fchown(fd, uid, gid);
- if (r < 0)
+ /* if the node doesn't exist yet, we create it, but with O_EXCL, so that we only create a regular file
+ * here, and nothing else */
+ fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
+ if (fd < 0)
return -errno;
}
+ /* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
+ * ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
+ * something fchown(), fchmod(), futimensat() don't allow. */
+ xsprintf(fdpath, "/proc/self/fd/%i", fd);
+
+ if (mode != MODE_INVALID)
+ if (chmod(fdpath, mode) < 0)
+ ret = -errno;
+
+ if (uid_is_valid(uid) || gid_is_valid(gid))
+ if (chown(fdpath, uid, gid) < 0 && ret >= 0)
+ ret = -errno;
+
if (stamp != USEC_INFINITY) {
struct timespec ts[2];
timespec_store(&ts[0], stamp);
ts[1] = ts[0];
- r = futimens(fd, ts);
+ r = utimensat(AT_FDCWD, fdpath, ts, 0);
} else
- r = futimens(fd, NULL);
- if (r < 0)
+ r = utimensat(AT_FDCWD, fdpath, NULL, 0);
+ if (r < 0 && ret >= 0)
return -errno;
- return 0;
+ return ret;
}
int touch(const char *path) {
diff --git a/src/basic/io-util.c b/src/basic/io-util.c
index 77c9bdc739..08ad42ed95 100644
--- a/src/basic/io-util.c
+++ b/src/basic/io-util.c
@@ -33,6 +33,7 @@ int flush_fd(int fd) {
.fd = fd,
.events = POLLIN,
};
+ int count = 0;
/* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
* read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
@@ -52,7 +53,7 @@ int flush_fd(int fd) {
return -errno;
} else if (r == 0)
- return 0;
+ return count;
l = read(fd, buf, sizeof(buf));
if (l < 0) {
@@ -61,11 +62,13 @@ int flush_fd(int fd) {
continue;
if (errno == EAGAIN)
- return 0;
+ return count;
return -errno;
} else if (l == 0)
- return 0;
+ return count;
+
+ count += (int) l;
}
}
diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c
index 20be406371..97f3ebe2af 100644
--- a/src/basic/socket-label.c
+++ b/src/basic/socket-label.c
@@ -29,6 +29,7 @@
#include "alloc-util.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
@@ -51,6 +52,7 @@ int socket_address_listen(
const char *label) {
_cleanup_close_ int fd = -1;
+ const char *p;
int r, one;
assert(a);
@@ -112,19 +114,23 @@ int socket_address_listen(
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
return -errno;
- if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
+ p = socket_address_get_path(a);
+ if (p) {
/* Create parents */
- (void) mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
+ (void) mkdir_parents_label(p, directory_mode);
/* Enforce the right access mode for the socket */
RUN_WITH_UMASK(~socket_mode) {
r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
if (r == -EADDRINUSE) {
/* Unlink and try again */
- unlink(a->sockaddr.un.sun_path);
- if (bind(fd, &a->sockaddr.sa, a->size) < 0)
- return -errno;
- } else if (r < 0)
+
+ if (unlink(p) < 0)
+ return r; /* didn't work, return original error */
+
+ r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
+ }
+ if (r < 0)
return r;
}
} else {
@@ -136,6 +142,11 @@ int socket_address_listen(
if (listen(fd, backlog) < 0)
return -errno;
+ /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable
+ * gets notified */
+ if (p)
+ (void) touch(p);
+
r = fd;
fd = -1;
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index cb10a1dd07..d6371f833d 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -68,7 +68,6 @@ DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
- unsigned u;
int r;
assert(a);
@@ -78,6 +77,8 @@ int socket_address_parse(SocketAddress *a, const char *s) {
a->type = SOCK_STREAM;
if (*s == '[') {
+ uint16_t port;
+
/* IPv6 in [x:.....:z]:p notation */
e = strchr(s+1, ']');
@@ -95,15 +96,12 @@ int socket_address_parse(SocketAddress *a, const char *s) {
return -EINVAL;
e++;
- r = safe_atou(e, &u);
+ r = parse_ip_port(e, &port);
if (r < 0)
return r;
- if (u <= 0 || u > 0xFFFF)
- return -EINVAL;
-
a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16((uint16_t)u);
+ a->sockaddr.in6.sin6_port = htobe16(port);
a->size = sizeof(struct sockaddr_in6);
} else if (*s == '/') {
@@ -134,12 +132,13 @@ int socket_address_parse(SocketAddress *a, const char *s) {
} else if (startswith(s, "vsock:")) {
/* AF_VSOCK socket in vsock:cid:port notation */
const char *cid_start = s + STRLEN("vsock:");
+ unsigned port;
e = strchr(cid_start, ':');
if (!e)
return -EINVAL;
- r = safe_atou(e+1, &u);
+ r = safe_atou(e+1, &port);
if (r < 0)
return r;
@@ -152,19 +151,18 @@ int socket_address_parse(SocketAddress *a, const char *s) {
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
a->sockaddr.vm.svm_family = AF_VSOCK;
- a->sockaddr.vm.svm_port = u;
+ a->sockaddr.vm.svm_port = port;
a->size = sizeof(struct sockaddr_vm);
} else {
+ uint16_t port;
+
e = strchr(s, ':');
if (e) {
- r = safe_atou(e+1, &u);
+ r = parse_ip_port(e + 1, &port);
if (r < 0)
return r;
- if (u <= 0 || u > 0xFFFF)
- return -EINVAL;
-
n = strndupa(s, e-s);
/* IPv4 in w.x.y.z:p notation? */
@@ -175,7 +173,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (r > 0) {
/* Gotcha, it's a traditional IPv4 address */
a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htobe16((uint16_t)u);
+ a->sockaddr.in.sin_port = htobe16(port);
a->size = sizeof(struct sockaddr_in);
} else {
unsigned idx;
@@ -189,7 +187,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
return -EINVAL;
a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16((uint16_t)u);
+ a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_scope_id = idx;
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
@@ -197,21 +195,18 @@ int socket_address_parse(SocketAddress *a, const char *s) {
} else {
/* Just a port */
- r = safe_atou(s, &u);
+ r = parse_ip_port(s, &port);
if (r < 0)
return r;
- if (u <= 0 || u > 0xFFFF)
- return -EINVAL;
-
if (socket_ipv6_is_supported()) {
a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16((uint16_t)u);
+ a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
} else {
a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htobe16((uint16_t)u);
+ a->sockaddr.in.sin_port = htobe16(port);
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
a->size = sizeof(struct sockaddr_in);
}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 83af91dbef..49c937aef5 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -36,16 +36,26 @@
#include "util.h"
union sockaddr_union {
+ /* The minimal, abstract version */
struct sockaddr sa;
+
+ /* The libc provided version that allocates "enough room" for every protocol */
+ struct sockaddr_storage storage;
+
+ /* Protoctol-specific implementations */
struct sockaddr_in in;
struct sockaddr_in6 in6;
struct sockaddr_un un;
struct sockaddr_nl nl;
- struct sockaddr_storage storage;
struct sockaddr_ll ll;
struct sockaddr_vm vm;
+
/* Ensure there is enough space to store Infiniband addresses */
uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
+
+ /* Ensure there is enough space after the AF_UNIX sun_path for one more NUL byte, just to be sure that the path
+ * component is always followed by at least one NUL byte. */
+ uint8_t un_buffer[sizeof(struct sockaddr_un) + 1];
};
typedef struct SocketAddress {
diff --git a/src/basic/verbs.c b/src/basic/verbs.c
index d8ebf89d03..556acdcaa3 100644
--- a/src/basic/verbs.c
+++ b/src/basic/verbs.c
@@ -30,45 +30,36 @@
#include "verbs.h"
#include "virt.h"
-/* Wraps running_in_chroot() which is used in various places,
- * but also adds an environment variable check so external processes
- * can reliably force this on.
+/* Wraps running_in_chroot() which is used in various places, but also adds an environment variable check so external
+ * processes can reliably force this on.
*/
bool running_in_chroot_or_offline(void) {
int r;
- /* Added to support use cases like rpm-ostree, where from %post
- * scripts we only want to execute "preset", but not "start"/"restart"
- * for example.
+ /* Added to support use cases like rpm-ostree, where from %post scripts we only want to execute "preset", but
+ * not "start"/"restart" for example.
*
* See ENVIRONMENT.md for docs.
*/
r = getenv_bool("SYSTEMD_OFFLINE");
- if (r < 0)
- log_debug_errno(r, "Parsing SYSTEMD_OFFLINE: %m");
- else if (r == 0)
- return false;
- else
- return true;
-
- /* We've had this condition check for a long time which basically
- * checks for legacy chroot case like Fedora's
- * "mock", which is used for package builds. We don't want
- * to try to start systemd services there, since without --new-chroot
- * we don't even have systemd running, and even if we did, adding
- * a concept of background daemons to builds would be an enormous change,
- * requiring considering things like how the journal output is handled, etc.
- * And there's really not a use case today for a build talking to a service.
+ if (r < 0 && r != -ENXIO)
+ log_debug_errno(r, "Failed to parse $SYSTEMD_OFFLINE: %m");
+ else if (r >= 0)
+ return r > 0;
+
+ /* We've had this condition check for a long time which basically checks for legacy chroot case like Fedora's
+ * "mock", which is used for package builds. We don't want to try to start systemd services there, since
+ * without --new-chroot we don't even have systemd running, and even if we did, adding a concept of background
+ * daemons to builds would be an enormous change, requiring considering things like how the journal output is
+ * handled, etc. And there's really not a use case today for a build talking to a service.
*
* Note this call itself also looks for a different variable SYSTEMD_IGNORE_CHROOT=1.
*/
r = running_in_chroot();
if (r < 0)
log_debug_errno(r, "running_in_chroot(): %m");
- else if (r > 0)
- return true;
- return false;
+ return r > 0;
}
int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 7a8d6ba5ac..5623bb2ffa 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -62,6 +62,7 @@ static bool arg_expect_reply = true;
static bool arg_auto_start = true;
static bool arg_allow_interactive_authorization = true;
static bool arg_augment_creds = true;
+static bool arg_watch_bind = false;
static usec_t arg_timeout = 0;
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
@@ -1735,7 +1736,9 @@ static int help(void) {
" --allow-interactive-authorization=BOOL\n"
" Allow interactive authorization for operation\n"
" --timeout=SECS Maximum time to wait for method call completion\n"
- " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
+ " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
+ " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
+ " system\n\n"
"Commands:\n"
" list List bus names\n"
" status [SERVICE] Show bus service, process or bus owner credentials\n"
@@ -1777,6 +1780,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
ARG_TIMEOUT,
ARG_AUGMENT_CREDS,
+ ARG_WATCH_BIND,
};
static const struct option options[] = {
@@ -1803,6 +1807,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{ "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
+ { "watch-bind", required_argument, NULL, ARG_WATCH_BIND },
{},
};
@@ -1953,6 +1958,16 @@ static int parse_argv(int argc, char *argv[]) {
arg_augment_creds = !!r;
break;
+ case ARG_WATCH_BIND:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --watch-bind= parameter.");
+ return r;
+ }
+
+ arg_watch_bind = !!r;
+ break;
+
case '?':
return -EINVAL;
@@ -2051,6 +2066,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ r = sd_bus_set_watch_bind(bus, arg_watch_bind);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind));
+ goto finish;
+ }
+
if (arg_address)
r = sd_bus_set_address(bus, arg_address);
else {
diff --git a/src/core/dbus.c b/src/core/dbus.c
index b7d8af9396..5e8a299983 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -37,6 +37,7 @@
#include "dbus-unit.h"
#include "dbus.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "log.h"
#include "missing.h"
#include "mkdir.h"
@@ -603,18 +604,16 @@ static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
NULL,
- "sender='org.freedesktop.DBus.Local',"
- "type='signal',"
- "path='/org/freedesktop/DBus/Local',"
- "interface='org.freedesktop.DBus.Local',"
- "member='Disconnected'",
- signal_disconnected, m);
-
+ "org.freedesktop.DBus.Local",
+ "/org/freedesktop/DBus/Local",
+ "org.freedesktop.DBus.Local",
+ "Disconnected",
+ signal_disconnected, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to register match for Disconnected message: %m");
+ return log_error_errno(r, "Failed to request match for Disconnected message: %m");
return 0;
}
@@ -683,6 +682,12 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
+ r = sd_bus_set_sender(bus, "org.freedesktop.systemd1");
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set direct connection sender: %m");
+ return 0;
+ }
+
r = sd_bus_start(bus);
if (r < 0) {
log_warning_errno(r, "Failed to start new connection bus: %m");
@@ -813,26 +818,23 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
}
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
NULL,
- "type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.systemd1.Activator',"
- "member='ActivationRequest'",
- signal_activation_request, m);
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.systemd1.Activator",
+ "ActivationRequest",
+ signal_activation_request, NULL, m);
if (r < 0)
log_warning_errno(r, "Failed to subscribe to activation signal: %m");
- /* Allow replacing of our name, to ease implementation of
- * reexecution, where we keep the old connection open until
- * after the new connection is set up and the name installed
- * to allow clients to synchronously wait for reexecution to
- * finish */
- r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
+ /* Allow replacing of our name, to ease implementation of reexecution, where we keep the old connection open
+ * until after the new connection is set up and the name installed to allow clients to synchronously wait for
+ * reexecution to finish */
+ r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = manager_sync_bus_names(m, bus);
if (r < 0)
@@ -857,7 +859,6 @@ static int bus_init_api(Manager *m) {
r = sd_bus_open_system(&bus);
else
r = sd_bus_open_user(&bus);
-
if (r < 0) {
log_debug("Failed to connect to API bus, retrying later...");
return 0;
@@ -894,16 +895,16 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
/* if we are a user instance we get the Released message via the system bus */
if (MANAGER_IS_USER(m)) {
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
+ NULL,
+ "/org/freedesktop/systemd1/agent",
+ "org.freedesktop.systemd1.Agent",
+ "Released",
+ signal_agent_released, NULL, m);
if (r < 0)
- log_warning_errno(r, "Failed to register Released match on system bus: %m");
+ log_warning_errno(r, "Failed to request Released match on system bus: %m");
}
log_debug("Successfully connected to system bus.");
@@ -1005,6 +1006,9 @@ static int bus_init_private(Manager *m) {
if (r < 0)
return log_error_errno(errno, "Failed to make private socket listening: %m");
+ /* Generate an inotify event in case somebody waits for this socket to appear using inotify() */
+ (void) touch(sa.un.sun_path);
+
r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m);
if (r < 0)
return log_error_errno(r, "Failed to allocate event source: %m");
diff --git a/src/core/manager.c b/src/core/manager.c
index 15720ada24..860d58617f 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -263,7 +263,7 @@ static int manager_dispatch_ask_password_fd(sd_event_source *source,
assert(m);
- flush_fd(fd);
+ (void) flush_fd(fd);
m->have_ask_password = have_ask_password();
if (m->have_ask_password < 0)
diff --git a/src/core/unit.c b/src/core/unit.c
index 652587e6ad..d736d274de 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3042,7 +3042,7 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
"member='NameOwnerChanged',"
"arg0='", name, "'");
- return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
+ return sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
}
int unit_watch_bus_name(Unit *u, const char *name) {
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 5feaa60c99..1c8c76934c 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -680,9 +680,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
if (r < 0)
return log_error_errno(r, "Failed to register object: %m");
- r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
+ r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
diff --git a/src/import/importd.c b/src/import/importd.c
index 21af09fc45..98ee1a2fab 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -1149,9 +1149,9 @@ static int manager_add_bus_objects(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to add transfer enumerator: %m");
- r = sd_bus_request_name(m->bus, "org.freedesktop.import1", 0);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 1a29b03e85..5a07344175 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -530,3 +530,20 @@ global:
sd_bus_message_new;
sd_bus_message_seal;
} LIBSYSTEMD_234;
+
+LIBSYSTEMD_237 {
+global:
+ sd_bus_set_watch_bind;
+ sd_bus_get_watch_bind;
+ sd_bus_request_name_async;
+ sd_bus_release_name_async;
+ sd_bus_add_match_async;
+ sd_bus_match_signal;
+ sd_bus_match_signal_async;
+ sd_bus_is_ready;
+ sd_bus_set_connected_signal;
+ sd_bus_get_connected_signal;
+ sd_bus_set_sender;
+ sd_bus_get_sender;
+ sd_bus_message_set_sender;
+} LIBSYSTEMD_236;
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 0b39115d16..4adc996a86 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -57,13 +57,31 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
return 0;
}
-static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- uint32_t ret, param = 0;
- int r;
+static int validate_request_name_parameters(
+ sd_bus *bus,
+ const char *name,
+ uint64_t flags,
+ uint32_t *ret_param) {
+
+ uint32_t param = 0;
assert(bus);
assert(name);
+ assert(ret_param);
+
+ assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
+ assert_return(service_name_is_valid(name), -EINVAL);
+ assert_return(name[0] != ':', -EINVAL);
+
+ if (!bus->bus_client)
+ return -EINVAL;
+
+ /* Don't allow requesting the special driver and local names */
+ if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
+ return -EINVAL;
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
param |= BUS_NAME_ALLOW_REPLACEMENT;
@@ -72,6 +90,28 @@ static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags)
if (!(flags & SD_BUS_NAME_QUEUE))
param |= BUS_NAME_DO_NOT_QUEUE;
+ *ret_param = param;
+
+ return 0;
+}
+
+_public_ int sd_bus_request_name(
+ sd_bus *bus,
+ const char *name,
+ uint64_t flags) {
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ uint32_t ret, param = 0;
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(name, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ r = validate_request_name_parameters(bus, name, flags, &param);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
@@ -90,46 +130,143 @@ static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags)
if (r < 0)
return r;
- if (ret == BUS_NAME_ALREADY_OWNER)
+ switch (ret) {
+
+ case BUS_NAME_ALREADY_OWNER:
return -EALREADY;
- else if (ret == BUS_NAME_EXISTS)
+
+ case BUS_NAME_EXISTS:
return -EEXIST;
- else if (ret == BUS_NAME_IN_QUEUE)
+
+ case BUS_NAME_IN_QUEUE:
return 0;
- else if (ret == BUS_NAME_PRIMARY_OWNER)
+
+ case BUS_NAME_PRIMARY_OWNER:
return 1;
+ }
return -EIO;
}
-_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
+static int default_request_name_handler(
+ sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error) {
+
+ uint32_t ret;
+ int r;
+
+ assert(m);
+
+ if (sd_bus_message_is_method_error(m, NULL)) {
+ log_debug_errno(sd_bus_message_get_errno(m),
+ "Unable to request name, failing connection: %s",
+ sd_bus_message_get_error(m)->message);
+
+ bus_enter_closing(sd_bus_message_get_bus(m));
+ return 1;
+ }
+
+ r = sd_bus_message_read(m, "u", &ret);
+ if (r < 0)
+ return r;
+
+ switch (ret) {
+
+ case BUS_NAME_ALREADY_OWNER:
+ log_debug("Already owner of requested service name, ignoring.");
+ return 1;
+
+ case BUS_NAME_IN_QUEUE:
+ log_debug("In queue for requested service name.");
+ return 1;
+
+ case BUS_NAME_PRIMARY_OWNER:
+ log_debug("Successfully acquired requested service name.");
+ return 1;
+
+ case BUS_NAME_EXISTS:
+ log_debug("Requested service name already owned, failing connection.");
+ bus_enter_closing(sd_bus_message_get_bus(m));
+ return 1;
+ }
+
+ log_debug("Unexpected response from RequestName(), failing connection.");
+ bus_enter_closing(sd_bus_message_get_bus(m));
+ return 1;
+}
+
+_public_ int sd_bus_request_name_async(
+ sd_bus *bus,
+ sd_bus_slot **ret_slot,
+ const char *name,
+ uint64_t flags,
+ sd_bus_message_handler_t callback,
+ void *userdata) {
+
+ uint32_t param = 0;
+ int r;
+
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
+
+ r = validate_request_name_parameters(bus, name, flags, &param);
+ if (r < 0)
+ return r;
+
+ return sd_bus_call_method_async(
+ bus,
+ ret_slot,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "RequestName",
+ callback ?: default_request_name_handler,
+ userdata,
+ "su",
+ name,
+ param);
+}
+
+static int validate_release_name_parameters(
+ sd_bus *bus,
+ const char *name) {
+
+ assert(bus);
+ assert(name);
+
assert_return(service_name_is_valid(name), -EINVAL);
assert_return(name[0] != ':', -EINVAL);
if (!bus->bus_client)
return -EINVAL;
- /* Don't allow requesting the special driver and local names */
+ /* Don't allow releasing the special driver and local names */
if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
return -EINVAL;
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- return bus_request_name_dbus1(bus, name, flags);
+ return 0;
}
-static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
+_public_ int sd_bus_release_name(
+ sd_bus *bus,
+ const char *name) {
+
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
uint32_t ret;
int r;
- assert(bus);
- assert(name);
+ assert_return(bus, -EINVAL);
+ assert_return(name, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ r = validate_release_name_parameters(bus, name);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -147,41 +284,110 @@ static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
r = sd_bus_message_read(reply, "u", &ret);
if (r < 0)
return r;
- if (ret == BUS_NAME_NON_EXISTENT)
+
+ switch (ret) {
+
+ case BUS_NAME_NON_EXISTENT:
return -ESRCH;
- if (ret == BUS_NAME_NOT_OWNER)
+
+ case BUS_NAME_NOT_OWNER:
return -EADDRINUSE;
- if (ret == BUS_NAME_RELEASED)
+
+ case BUS_NAME_RELEASED:
return 0;
+ }
- return -EINVAL;
+ return -EIO;
}
-_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
+static int default_release_name_handler(
+ sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error) {
+
+ uint32_t ret;
+ int r;
+
+ assert(m);
+
+ if (sd_bus_message_is_method_error(m, NULL)) {
+ log_debug_errno(sd_bus_message_get_errno(m),
+ "Unable to release name, failing connection: %s",
+ sd_bus_message_get_error(m)->message);
+
+ bus_enter_closing(sd_bus_message_get_bus(m));
+ return 1;
+ }
+
+ r = sd_bus_message_read(m, "u", &ret);
+ if (r < 0)
+ return r;
+
+ switch (ret) {
+
+ case BUS_NAME_NON_EXISTENT:
+ log_debug("Name asked to release is not taken currently, ignoring.");
+ return 1;
+
+ case BUS_NAME_NOT_OWNER:
+ log_debug("Name asked to release is owned by somebody else, ignoring.");
+ return 1;
+
+ case BUS_NAME_RELEASED:
+ log_debug("Name successfully released.");
+ return 1;
+ }
+
+ log_debug("Unexpected response from ReleaseName(), failing connection.");
+ bus_enter_closing(sd_bus_message_get_bus(m));
+ return 1;
+}
+
+_public_ int sd_bus_release_name_async(
+ sd_bus *bus,
+ sd_bus_slot **ret_slot,
+ const char *name,
+ sd_bus_message_handler_t callback,
+ void *userdata) {
+
+ int r;
+
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(service_name_is_valid(name), -EINVAL);
- assert_return(name[0] != ':', -EINVAL);
-
- if (!bus->bus_client)
- return -EINVAL;
-
- /* Don't allow releasing the special driver and local names */
- if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
- return -EINVAL;
- if (!BUS_IS_OPEN(bus->state))
- return -ENOTCONN;
+ r = validate_release_name_parameters(bus, name);
+ if (r < 0)
+ return r;
- return bus_release_name_dbus1(bus, name);
+ return sd_bus_call_method_async(
+ bus,
+ ret_slot,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "ReleaseName",
+ callback ?: default_release_name_handler,
+ userdata,
+ "s",
+ name);
}
-static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
+_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_strv_free_ char **x = NULL, **y = NULL;
int r;
+ assert_return(bus, -EINVAL);
+ assert_return(acquired || activatable, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ if (!bus->bus_client)
+ return -EINVAL;
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
if (acquired) {
r = sd_bus_call_method(
bus,
@@ -231,21 +437,7 @@ static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatab
return 0;
}
-_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
- assert_return(bus, -EINVAL);
- assert_return(acquired || activatable, -EINVAL);
- assert_return(!bus_pid_changed(bus), -ECHILD);
-
- if (!bus->bus_client)
- return -EINVAL;
-
- if (!BUS_IS_OPEN(bus->state))
- return -ENOTCONN;
-
- return bus_list_names_dbus1(bus, acquired, activatable);
-}
-
-static int bus_get_name_creds_dbus1(
+_public_ int sd_bus_get_name_creds(
sd_bus *bus,
const char *name,
uint64_t mask,
@@ -257,6 +449,30 @@ static int bus_get_name_creds_dbus1(
pid_t pid = 0;
int r;
+ assert_return(bus, -EINVAL);
+ assert_return(name, -EINVAL);
+ assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+ assert_return(mask == 0 || creds, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+ assert_return(service_name_is_valid(name), -EINVAL);
+
+ if (!bus->bus_client)
+ return -EINVAL;
+
+ /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
+ * going to match. */
+ if (!bus->is_local)
+ mask &= ~SD_BUS_CREDS_AUGMENT;
+
+ if (streq(name, "org.freedesktop.DBus.Local"))
+ return -EINVAL;
+
+ if (streq(name, "org.freedesktop.DBus"))
+ return sd_bus_get_owner_creds(bus, mask, creds);
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
/* Only query the owner if the caller wants to know it or if
* the caller just wants to check whether a name exists */
if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
@@ -519,46 +735,22 @@ static int bus_get_name_creds_dbus1(
return 0;
}
-_public_ int sd_bus_get_name_creds(
- sd_bus *bus,
- const char *name,
- uint64_t mask,
- sd_bus_creds **creds) {
+_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
+ bool do_label, do_groups;
+ pid_t pid = 0;
+ int r;
assert_return(bus, -EINVAL);
- assert_return(name, -EINVAL);
assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
- assert_return(mask == 0 || creds, -EINVAL);
+ assert_return(ret, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(service_name_is_valid(name), -EINVAL);
-
- if (!bus->bus_client)
- return -EINVAL;
-
- /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
- * going to match. */
- if (!bus->is_local)
- mask &= ~SD_BUS_CREDS_AUGMENT;
-
- if (streq(name, "org.freedesktop.DBus.Local"))
- return -EINVAL;
-
- if (streq(name, "org.freedesktop.DBus"))
- return sd_bus_get_owner_creds(bus, mask, creds);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- return bus_get_name_creds_dbus1(bus, name, mask, creds);
-}
-
-static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- pid_t pid = 0;
- bool do_label, do_groups;
- int r;
-
- assert(bus);
+ if (!bus->is_local)
+ mask &= ~SD_BUS_CREDS_AUGMENT;
do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
@@ -615,36 +807,23 @@ static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **
return 0;
}
-_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
- assert_return(bus, -EINVAL);
- assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
- assert_return(ret, -EINVAL);
- assert_return(!bus_pid_changed(bus), -ECHILD);
-
- if (!BUS_IS_OPEN(bus->state))
- return -ENOTCONN;
-
- if (!bus->is_local)
- mask &= ~SD_BUS_CREDS_AUGMENT;
-
- return bus_get_owner_creds_dbus1(bus, mask, ret);
-}
-
-#define internal_match(bus, m) \
- ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
+#define append_eavesdrop(bus, m) \
+ ((bus)->is_monitor \
? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
: (m))
-static int bus_add_match_internal_dbus1(
+int bus_add_match_internal(
sd_bus *bus,
const char *match) {
const char *e;
assert(bus);
- assert(match);
- e = internal_match(bus, match);
+ if (!bus->bus_client)
+ return -EINVAL;
+
+ e = append_eavesdrop(bus, match);
return sd_bus_call_method(
bus,
@@ -657,22 +836,36 @@ static int bus_add_match_internal_dbus1(
"s",
e);
}
-
-int bus_add_match_internal(
+int bus_add_match_internal_async(
sd_bus *bus,
+ sd_bus_slot **ret_slot,
const char *match,
- struct bus_match_component *components,
- unsigned n_components) {
+ sd_bus_message_handler_t callback,
+ void *userdata) {
+
+ const char *e;
assert(bus);
if (!bus->bus_client)
return -EINVAL;
- return bus_add_match_internal_dbus1(bus, match);
+ e = append_eavesdrop(bus, match);
+
+ return sd_bus_call_method_async(
+ bus,
+ ret_slot,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "AddMatch",
+ callback,
+ userdata,
+ "s",
+ e);
}
-static int bus_remove_match_internal_dbus1(
+int bus_remove_match_internal(
sd_bus *bus,
const char *match) {
@@ -681,10 +874,16 @@ static int bus_remove_match_internal_dbus1(
assert(bus);
assert(match);
- e = internal_match(bus, match);
+ if (!bus->bus_client)
+ return -EINVAL;
- return sd_bus_call_method(
+ e = append_eavesdrop(bus, match);
+
+ /* Fire and forget */
+
+ return sd_bus_call_method_async(
bus,
+ NULL,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
@@ -695,18 +894,6 @@ static int bus_remove_match_internal_dbus1(
e);
}
-int bus_remove_match_internal(
- sd_bus *bus,
- const char *match) {
-
- assert(bus);
-
- if (!bus->bus_client)
- return -EINVAL;
-
- return bus_remove_match_internal_dbus1(bus, match);
-}
-
_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
const char *mid;
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
index c9d434c607..3d9acebaf6 100644
--- a/src/libsystemd/sd-bus/bus-control.h
+++ b/src/libsystemd/sd-bus/bus-control.h
@@ -22,7 +22,7 @@
#include "sd-bus.h"
-#include "bus-match.h"
+int bus_add_match_internal(sd_bus *bus, const char *match);
+int bus_add_match_internal_async(sd_bus *bus, sd_bus_slot **ret, const char *match, sd_bus_message_handler_t callback, void *userdata);
-int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components);
int bus_remove_match_internal(sd_bus *bus, const char *match);
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 9d3b596429..7d702e6376 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -615,3 +615,69 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability)
return 0;
}
+
+#define make_expression(sender, path, interface, member) \
+ strjoina( \
+ "type='signal'", \
+ sender ? ",sender='" : "", \
+ sender ?: "", \
+ sender ? "'" : "", \
+ path ? ",path='" : "", \
+ path ?: "", \
+ path ? "'" : "", \
+ interface ? ",interface='" : "", \
+ interface ?: "", \
+ interface ? "'" : "", \
+ member ? ",member='" : "", \
+ member ?: "", \
+ member ? "'" : "" \
+ )
+
+_public_ int sd_bus_match_signal(
+ sd_bus *bus,
+ sd_bus_slot **ret,
+ const char *sender,
+ const char *path,
+ const char *interface,
+ const char *member,
+ sd_bus_message_handler_t callback,
+ void *userdata) {
+
+ const char *expression;
+
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+ assert_return(!sender || service_name_is_valid(sender), -EINVAL);
+ assert_return(!path || object_path_is_valid(path), -EINVAL);
+ assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
+ assert_return(!member || member_name_is_valid(member), -EINVAL);
+
+ expression = make_expression(sender, path, interface, member);
+
+ return sd_bus_add_match(bus, ret, expression, callback, userdata);
+}
+
+_public_ int sd_bus_match_signal_async(
+ sd_bus *bus,
+ sd_bus_slot **ret,
+ const char *sender,
+ const char *path,
+ const char *interface,
+ const char *member,
+ sd_bus_message_handler_t callback,
+ sd_bus_message_handler_t install_callback,
+ void *userdata) {
+
+ const char *expression;
+
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+ assert_return(!sender || service_name_is_valid(sender), -EINVAL);
+ assert_return(!path || object_path_is_valid(path), -EINVAL);
+ assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
+ assert_return(!member || member_name_is_valid(member), -EINVAL);
+
+ expression = make_expression(sender, path, interface, member);
+
+ return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);
+}
diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c
index 3c381b0ffe..05a022fbf3 100644
--- a/src/libsystemd/sd-bus/bus-internal.c
+++ b/src/libsystemd/sd-bus/bus-internal.c
@@ -362,13 +362,18 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
} else
return r;
- log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
+ log_debug("Failed to process message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s: %s",
bus_message_type_to_string(m->header->type),
- strna(m->sender),
- strna(m->path),
- strna(m->interface),
- strna(m->member),
+ strna(sd_bus_message_get_sender(m)),
+ strna(sd_bus_message_get_destination(m)),
+ strna(sd_bus_message_get_path(m)),
+ strna(sd_bus_message_get_interface(m)),
+ strna(sd_bus_message_get_member(m)),
+ BUS_MESSAGE_COOKIE(m),
+ m->reply_cookie,
strna(m->root_container.signature),
+ strna(m->error.name),
+ strna(m->error.message),
bus_error_message(error, r));
return 1;
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 4175ca3efe..a28f5f06f4 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -38,7 +38,7 @@
struct reply_callback {
sd_bus_message_handler_t callback;
- usec_t timeout;
+ usec_t timeout_usec; /* this is a relative timeout until we reach the BUS_HELLO state, and an absolute one right after */
uint64_t cookie;
unsigned prioq_idx;
};
@@ -53,6 +53,9 @@ struct filter_callback {
struct match_callback {
sd_bus_message_handler_t callback;
+ sd_bus_message_handler_t install_callback;
+
+ sd_bus_slot *install_slot; /* The AddMatch() call */
unsigned last_iteration;
@@ -157,12 +160,14 @@ struct sd_bus_slot {
enum bus_state {
BUS_UNSET,
- BUS_OPENING,
- BUS_AUTHENTICATING,
- BUS_HELLO,
+ BUS_WATCH_BIND, /* waiting for the socket to appear via inotify */
+ BUS_OPENING, /* the kernel's connect() is still not ready */
+ BUS_AUTHENTICATING, /* we are currently in the "SASL" authorization phase of dbus */
+ BUS_HELLO, /* we are waiting for the Hello() response */
BUS_RUNNING,
BUS_CLOSING,
- BUS_CLOSED
+ BUS_CLOSED,
+ _BUS_STATE_MAX,
};
static inline bool BUS_IS_OPEN(enum bus_state state) {
@@ -188,6 +193,7 @@ struct sd_bus {
enum bus_state state;
int input_fd, output_fd;
+ int inotify_fd;
int message_version;
int message_endian;
@@ -210,6 +216,11 @@ struct sd_bus {
bool exited:1;
bool exit_triggered:1;
bool is_local:1;
+ bool watch_bind:1;
+ bool is_monitor:1;
+ bool accept_fd:1;
+ bool attach_timestamp:1;
+ bool connected_signal:1;
int use_memfd;
@@ -286,13 +297,11 @@ struct sd_bus {
pid_t original_pid;
- uint64_t hello_flags;
- uint64_t attach_flags;
-
sd_event_source *input_io_event_source;
sd_event_source *output_io_event_source;
sd_event_source *time_event_source;
sd_event_source *quit_event_source;
+ sd_event_source *inotify_event_source;
sd_event *event;
int event_priority;
@@ -307,11 +316,15 @@ struct sd_bus {
char *cgroup_root;
char *description;
+ char *patch_sender;
sd_bus_track *track_queue;
LIST_HEAD(sd_bus_slot, slots);
LIST_HEAD(sd_bus_track, tracks);
+
+ int *inotify_watches;
+ size_t n_inotify_watches;
};
/* For method calls we time-out at 25s, like in the D-Bus reference implementation */
@@ -367,6 +380,12 @@ bool bus_pid_changed(sd_bus *bus);
char *bus_address_escape(const char *v);
+int bus_attach_io_events(sd_bus *b);
+int bus_attach_inotify_event(sd_bus *b);
+
+void bus_close_inotify_fd(sd_bus *b);
+void bus_close_io_fds(sd_bus *b);
+
#define OBJECT_PATH_FOREACH_PREFIX(prefix, path) \
for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \
_slash && !(_slash[(_slash) == (prefix)] = 0); \
@@ -383,8 +402,6 @@ int bus_set_address_user(sd_bus *bus);
int bus_set_address_system_remote(sd_bus *b, const char *host);
int bus_set_address_system_machine(sd_bus *b, const char *machine);
-int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
-
int bus_get_root_path(sd_bus *bus);
int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
@@ -395,64 +412,6 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
return sd_bus_error_set_errno(error, r); \
} while (false)
-/**
- * enum kdbus_attach_flags - flags for metadata attachments
- * @KDBUS_ATTACH_TIMESTAMP: Timestamp
- * @KDBUS_ATTACH_CREDS: Credentials
- * @KDBUS_ATTACH_PIDS: PIDs
- * @KDBUS_ATTACH_AUXGROUPS: Auxiliary groups
- * @KDBUS_ATTACH_NAMES: Well-known names
- * @KDBUS_ATTACH_TID_COMM: The "comm" process identifier of the TID
- * @KDBUS_ATTACH_PID_COMM: The "comm" process identifier of the PID
- * @KDBUS_ATTACH_EXE: The path of the executable
- * @KDBUS_ATTACH_CMDLINE: The process command line
- * @KDBUS_ATTACH_CGROUP: The croup membership
- * @KDBUS_ATTACH_CAPS: The process capabilities
- * @KDBUS_ATTACH_SECLABEL: The security label
- * @KDBUS_ATTACH_AUDIT: The audit IDs
- * @KDBUS_ATTACH_CONN_DESCRIPTION: The human-readable connection name
- * @_KDBUS_ATTACH_ALL: All of the above
- * @_KDBUS_ATTACH_ANY: Wildcard match to enable any kind of
- * metatdata.
- */
-enum kdbus_attach_flags {
- KDBUS_ATTACH_TIMESTAMP = 1ULL << 0,
- KDBUS_ATTACH_CREDS = 1ULL << 1,
- KDBUS_ATTACH_PIDS = 1ULL << 2,
- KDBUS_ATTACH_AUXGROUPS = 1ULL << 3,
- KDBUS_ATTACH_NAMES = 1ULL << 4,
- KDBUS_ATTACH_TID_COMM = 1ULL << 5,
- KDBUS_ATTACH_PID_COMM = 1ULL << 6,
- KDBUS_ATTACH_EXE = 1ULL << 7,
- KDBUS_ATTACH_CMDLINE = 1ULL << 8,
- KDBUS_ATTACH_CGROUP = 1ULL << 9,
- KDBUS_ATTACH_CAPS = 1ULL << 10,
- KDBUS_ATTACH_SECLABEL = 1ULL << 11,
- KDBUS_ATTACH_AUDIT = 1ULL << 12,
- KDBUS_ATTACH_CONN_DESCRIPTION = 1ULL << 13,
- _KDBUS_ATTACH_ALL = (1ULL << 14) - 1,
- _KDBUS_ATTACH_ANY = ~0ULL
-};
+void bus_enter_closing(sd_bus *bus);
-/**
- * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello
- * @KDBUS_HELLO_ACCEPT_FD: The connection allows the reception of
- * any passed file descriptors
- * @KDBUS_HELLO_ACTIVATOR: Special-purpose connection which registers
- * a well-know name for a process to be started
- * when traffic arrives
- * @KDBUS_HELLO_POLICY_HOLDER: Special-purpose connection which registers
- * policy entries for a name. The provided name
- * is not activated and not registered with the
- * name database, it only allows unprivileged
- * connections to acquire a name, talk or discover
- * a service
- * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor
- * bus traffic
- */
-enum kdbus_hello_flags {
- KDBUS_HELLO_ACCEPT_FD = 1ULL << 0,
- KDBUS_HELLO_ACTIVATOR = 1ULL << 1,
- KDBUS_HELLO_POLICY_HOLDER = 1ULL << 2,
- KDBUS_HELLO_MONITOR = 1ULL << 3,
-};
+void bus_set_state(sd_bus *bus, enum bus_state state);
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index c6179b4d95..b27b9d7d86 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -66,49 +66,3 @@ void bus_flush_memfd(sd_bus *b) {
for (i = 0; i < b->n_memfd_cache; i++)
close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
}
-
-uint64_t attach_flags_to_kdbus(uint64_t mask) {
- uint64_t m = 0;
-
- if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
- SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID))
- m |= KDBUS_ATTACH_CREDS;
-
- if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID))
- m |= KDBUS_ATTACH_PIDS;
-
- if (mask & SD_BUS_CREDS_COMM)
- m |= KDBUS_ATTACH_PID_COMM;
-
- if (mask & SD_BUS_CREDS_TID_COMM)
- m |= KDBUS_ATTACH_TID_COMM;
-
- if (mask & SD_BUS_CREDS_EXE)
- m |= KDBUS_ATTACH_EXE;
-
- if (mask & SD_BUS_CREDS_CMDLINE)
- m |= KDBUS_ATTACH_CMDLINE;
-
- if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))
- m |= KDBUS_ATTACH_CGROUP;
-
- if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
- m |= KDBUS_ATTACH_CAPS;
-
- if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
- m |= KDBUS_ATTACH_SECLABEL;
-
- if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
- m |= KDBUS_ATTACH_AUDIT;
-
- if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
- m |= KDBUS_ATTACH_NAMES;
-
- if (mask & SD_BUS_CREDS_DESCRIPTION)
- m |= KDBUS_ATTACH_CONN_DESCRIPTION;
-
- if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS)
- m |= KDBUS_ATTACH_AUXGROUPS;
-
- return m;
-}
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
index d9f80935fe..fa78e5c80d 100644
--- a/src/libsystemd/sd-bus/bus-kernel.h
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -41,5 +41,3 @@ struct memfd_cache {
void close_and_munmap(int fd, void *address, size_t size);
void bus_flush_memfd(sd_bus *bus);
-
-uint64_t attach_flags_to_kdbus(uint64_t sd_bus_flags);
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 219cff1f6e..3fbb6dc306 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -127,7 +127,6 @@ static void message_free(sd_bus_message *m) {
if (m->iovec != m->iovec_fixed)
free(m->iovec);
- m->destination_ptr = mfree(m->destination_ptr);
message_reset_containers(m);
free(m->root_container.signature);
free(m->root_container.offsets);
@@ -5488,6 +5487,15 @@ _public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *desti
return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
}
+_public_ int sd_bus_message_set_sender(sd_bus_message *m, const char *sender) {
+ assert_return(m, -EINVAL);
+ assert_return(sender, -EINVAL);
+ assert_return(!m->sealed, -EPERM);
+ assert_return(!m->sender, -EEXIST);
+
+ return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
+}
+
int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
size_t total;
void *p, *e;
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
index 1e4b20926d..88998700d6 100644
--- a/src/libsystemd/sd-bus/bus-message.h
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -136,10 +136,6 @@ struct sd_bus_message {
usec_t timeout;
- char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
- char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
- char *destination_ptr;
-
size_t header_offsets[_BUS_MESSAGE_HEADER_MAX];
unsigned n_header_offsets;
};
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 121197bbcb..1237819b49 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1369,7 +1369,7 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) {
assert(bus);
assert(m);
- if (bus->hello_flags & KDBUS_HELLO_MONITOR)
+ if (bus->is_monitor)
return 0;
if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index 756761c3ed..9a56371715 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -81,7 +81,7 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
if (slot->reply_callback.cookie != 0)
ordered_hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
- if (slot->reply_callback.timeout != 0)
+ if (slot->reply_callback.timeout_usec != 0)
prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
break;
@@ -94,12 +94,17 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
case BUS_MATCH_CALLBACK:
if (slot->match_added)
- bus_remove_match_internal(slot->bus, slot->match_callback.match_string);
+ (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string);
+
+ if (slot->match_callback.install_slot) {
+ bus_slot_disconnect(slot->match_callback.install_slot);
+ slot->match_callback.install_slot = sd_bus_slot_unref(slot->match_callback.install_slot);
+ }
slot->bus->match_callbacks_modified = true;
bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
- free(slot->match_callback.match_string);
+ slot->match_callback.match_string = mfree(slot->match_callback.match_string);
break;
@@ -174,7 +179,7 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
}
}
- free(slot->node_vtable.interface);
+ slot->node_vtable.interface = mfree(slot->node_vtable.interface);
if (slot->node_vtable.node) {
LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 0a1d36a9d3..61539313bc 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -32,9 +32,12 @@
#include "bus-socket.h"
#include "fd-util.h"
#include "format-util.h"
+#include "fs-util.h"
#include "hexdecoct.h"
+#include "io-util.h"
#include "macro.h"
#include "missing.h"
+#include "path-util.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "stdio-util.h"
@@ -188,7 +191,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
if (!e)
return 0;
- if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) {
+ if (b->accept_fd) {
f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2);
if (!f)
return 0;
@@ -475,7 +478,7 @@ static int bus_socket_auth_verify_server(sd_bus *b) {
r = bus_socket_auth_write_ok(b);
}
} else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) {
- if (b->auth == _BUS_AUTH_INVALID || !(b->hello_flags & KDBUS_HELLO_ACCEPT_FD))
+ if (b->auth == _BUS_AUTH_INVALID || !b->accept_fd)
r = bus_socket_auth_write(b, "ERROR\r\n");
else {
b->can_fds = true;
@@ -592,8 +595,8 @@ void bus_socket_setup(sd_bus *b) {
assert(b);
/* Increase the buffers to 8 MB */
- fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
- fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
+ (void) fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
+ (void) fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
b->message_version = 1;
b->message_endian = 0;
@@ -652,7 +655,7 @@ static int bus_socket_start_auth_client(sd_bus *b) {
if (!b->auth_buffer)
return -ENOMEM;
- if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD)
+ if (b->accept_fd)
auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
else
auth_suffix = "\r\nBEGIN\r\n";
@@ -672,15 +675,15 @@ int bus_socket_start_auth(sd_bus *b) {
bus_get_peercred(b);
- b->state = BUS_AUTHENTICATING;
+ bus_set_state(b, BUS_AUTHENTICATING);
b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_AUTH_TIMEOUT;
if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0)
- b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
+ b->accept_fd = false;
if (b->output_fd != b->input_fd)
if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0)
- b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
+ b->accept_fd = false;
if (b->is_server)
return bus_socket_read_auth(b);
@@ -688,30 +691,249 @@ int bus_socket_start_auth(sd_bus *b) {
return bus_socket_start_auth_client(b);
}
+static int bus_socket_inotify_setup(sd_bus *b) {
+ _cleanup_free_ int *new_watches = NULL;
+ _cleanup_free_ char *absolute = NULL;
+ size_t n_allocated = 0, n = 0, done = 0, i;
+ unsigned max_follow = 32;
+ const char *p;
+ int wd, r;
+
+ assert(b);
+ assert(b->watch_bind);
+ assert(b->sockaddr.sa.sa_family == AF_UNIX);
+ assert(b->sockaddr.un.sun_path[0] != 0);
+
+ /* Sets up an inotify fd in case watch_bind is enabled: wait until the configured AF_UNIX file system socket
+ * appears before connecting to it. The implemented is pretty simplistic: we just subscribe to relevant changes
+ * to all prefix components of the path, and every time we get an event for that we try to reconnect again,
+ * without actually caring what precisely the event we got told us. If we still can't connect we re-subscribe
+ * to all relevant changes of anything in the path, so that our watches include any possibly newly created path
+ * components. */
+
+ if (b->inotify_fd < 0) {
+ b->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ if (b->inotify_fd < 0)
+ return -errno;
+ }
+
+ /* Make sure the path is NUL terminated */
+ p = strndupa(b->sockaddr.un.sun_path, sizeof(b->sockaddr.un.sun_path));
+
+ /* Make sure the path is absolute */
+ r = path_make_absolute_cwd(p, &absolute);
+ if (r < 0)
+ goto fail;
+
+ /* Watch all parent directories, and don't mind any prefix that doesn't exist yet. For the innermost directory
+ * that exists we want to know when files are created or moved into it. For all parents of it we just care if
+ * they are removed or renamed. */
+
+ if (!GREEDY_REALLOC(new_watches, n_allocated, n + 1)) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ /* Start with the top-level directory, which is a bit simpler than the rest, since it can't be a symlink, and
+ * always exists */
+ wd = inotify_add_watch(b->inotify_fd, "/", IN_CREATE|IN_MOVED_TO);
+ if (wd < 0) {
+ r = log_debug_errno(errno, "Failed to add inotify watch on /: %m");
+ goto fail;
+ } else
+ new_watches[n++] = wd;
+
+ for (;;) {
+ _cleanup_free_ char *component = NULL, *prefix = NULL, *destination = NULL;
+ size_t n_slashes, n_component;
+ char *c = NULL;
+
+ n_slashes = strspn(absolute + done, "/");
+ n_component = n_slashes + strcspn(absolute + done + n_slashes, "/");
+
+ if (n_component == 0) /* The end */
+ break;
+
+ component = strndup(absolute + done, n_component);
+ if (!component) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ /* A trailing slash? That's a directory, and not a socket then */
+ if (path_equal(component, "/")) {
+ r = -EISDIR;
+ goto fail;
+ }
+
+ /* A single dot? Let's eat this up */
+ if (path_equal(component, "/.")) {
+ done += n_component;
+ continue;
+ }
+
+ prefix = strndup(absolute, done + n_component);
+ if (!prefix) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (!GREEDY_REALLOC(new_watches, n_allocated, n + 1)) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ wd = inotify_add_watch(b->inotify_fd, prefix, IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO|IN_DONT_FOLLOW);
+ log_debug("Added inotify watch for %s on bus %s: %i", prefix, strna(b->description), wd);
+
+ if (wd < 0) {
+ if (IN_SET(errno, ENOENT, ELOOP))
+ break; /* This component doesn't exist yet, or the path contains a cyclic symlink right now */
+
+ r = log_debug_errno(errno, "Failed to add inotify watch on %s: %m", isempty(prefix) ? "/" : prefix);
+ goto fail;
+ } else
+ new_watches[n++] = wd;
+
+ /* Check if this is possibly a symlink. If so, let's follow it and watch it too. */
+ r = readlink_malloc(prefix, &destination);
+ if (r == -EINVAL) { /* not a symlink */
+ done += n_component;
+ continue;
+ }
+ if (r < 0)
+ goto fail;
+
+ if (isempty(destination)) { /* Empty symlink target? Yuck! */
+ r = -EINVAL;
+ goto fail;
+ }
+
+ if (max_follow <= 0) { /* Let's make sure we don't follow symlinks forever */
+ r = -ELOOP;
+ goto fail;
+ }
+
+ if (path_is_absolute(destination)) {
+ /* For absolute symlinks we build the new path and start anew */
+ c = strjoin(destination, absolute + done + n_component);
+ done = 0;
+ } else {
+ _cleanup_free_ char *t = NULL;
+
+ /* For relative symlinks we replace the last component, and try again */
+ t = strndup(absolute, done);
+ if (!t)
+ return -ENOMEM;
+
+ c = strjoin(t, "/", destination, absolute + done + n_component);
+ }
+ if (!c) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ free(absolute);
+ absolute = c;
+
+ max_follow--;
+ }
+
+ /* And now, let's remove all watches from the previous iteration we don't need anymore */
+ for (i = 0; i < b->n_inotify_watches; i++) {
+ bool found = false;
+ size_t j;
+
+ for (j = 0; j < n; j++)
+ if (new_watches[j] == b->inotify_watches[i]) {
+ found = true;
+ break;
+ }
+
+ if (found)
+ continue;
+
+ (void) inotify_rm_watch(b->inotify_fd, b->inotify_watches[i]);
+ }
+
+ free_and_replace(b->inotify_watches, new_watches);
+ b->n_inotify_watches = n;
+
+ return 0;
+
+fail:
+ bus_close_inotify_fd(b);
+ return r;
+}
+
int bus_socket_connect(sd_bus *b) {
+ bool inotify_done = false;
int r;
assert(b);
- assert(b->input_fd < 0);
- assert(b->output_fd < 0);
- assert(b->sockaddr.sa.sa_family != AF_UNSPEC);
- b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (b->input_fd < 0)
- return -errno;
+ for (;;) {
+ assert(b->input_fd < 0);
+ assert(b->output_fd < 0);
+ assert(b->sockaddr.sa.sa_family != AF_UNSPEC);
- b->output_fd = b->input_fd;
+ b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (b->input_fd < 0)
+ return -errno;
- bus_socket_setup(b);
+ b->output_fd = b->input_fd;
+ bus_socket_setup(b);
- r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
- if (r < 0) {
- if (errno == EINPROGRESS)
- return 1;
+ if (connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size) < 0) {
+ if (errno == EINPROGRESS) {
- return -errno;
+ /* If we have any inotify watches open, close them now, we don't need them anymore, as
+ * we have successfully initiated a connection */
+ bus_close_inotify_fd(b);
+
+ /* Note that very likely we are already in BUS_OPENING state here, as we enter it when
+ * we start parsing the address string. The only reason we set the state explicitly
+ * here, is to undo BUS_WATCH_BIND, in case we did the inotify magic. */
+ bus_set_state(b, BUS_OPENING);
+ return 1;
+ }
+
+ if (IN_SET(errno, ENOENT, ECONNREFUSED) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */
+ b->watch_bind &&
+ b->sockaddr.sa.sa_family == AF_UNIX &&
+ b->sockaddr.un.sun_path[0] != 0) {
+
+ /* This connection attempt failed, let's release the socket for now, and start with a
+ * fresh one when reconnecting. */
+ bus_close_io_fds(b);
+
+ if (inotify_done) {
+ /* inotify set up already, don't do it again, just return now, and remember
+ * that we are waiting for inotify events now. */
+ bus_set_state(b, BUS_WATCH_BIND);
+ return 1;
+ }
+
+ /* This is a file system socket, and the inotify logic is enabled. Let's create the necessary inotify fd. */
+ r = bus_socket_inotify_setup(b);
+ if (r < 0)
+ return r;
+
+ /* Let's now try to connect a second time, because in theory there's otherwise a race
+ * here: the socket might have been created in the time between our first connect() and
+ * the time we set up the inotify logic. But let's remember that we set up inotify now,
+ * so that we don't do the connect() more than twice. */
+ inotify_done = true;
+
+ } else
+ return -errno;
+ } else
+ break;
}
+ /* Yay, established, we don't need no inotify anymore! */
+ bus_close_inotify_fd(b);
+
return bus_socket_start_auth(b);
}
@@ -742,10 +964,10 @@ int bus_socket_exec(sd_bus *b) {
if (!IN_SET(s[1], STDIN_FILENO, STDOUT_FILENO))
safe_close(s[1]);
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_nonblock(STDIN_FILENO, false);
- fd_nonblock(STDOUT_FILENO, false);
+ (void) fd_cloexec(STDIN_FILENO, false);
+ (void) fd_cloexec(STDOUT_FILENO, false);
+ (void) fd_nonblock(STDIN_FILENO, false);
+ (void) fd_nonblock(STDOUT_FILENO, false);
if (b->exec_argv)
execvp(b->exec_path, b->exec_argv);
@@ -1069,3 +1291,34 @@ int bus_socket_process_authenticating(sd_bus *b) {
return bus_socket_read_auth(b);
}
+
+int bus_socket_process_watch_bind(sd_bus *b) {
+ int r, q;
+
+ assert(b);
+ assert(b->state == BUS_WATCH_BIND);
+ assert(b->inotify_fd >= 0);
+
+ r = flush_fd(b->inotify_fd);
+ if (r <= 0)
+ return r;
+
+ log_debug("Got inotify event on bus %s.", strna(b->description));
+
+ /* We flushed events out of the inotify fd. In that case, maybe the socket is valid now? Let's try to connect
+ * to it again */
+
+ r = bus_socket_connect(b);
+ if (r < 0)
+ return r;
+
+ q = bus_attach_io_events(b);
+ if (q < 0)
+ return q;
+
+ q = bus_attach_inotify_event(b);
+ if (q < 0)
+ return q;
+
+ return r;
+}
diff --git a/src/libsystemd/sd-bus/bus-socket.h b/src/libsystemd/sd-bus/bus-socket.h
index 915a283f5a..c180562f98 100644
--- a/src/libsystemd/sd-bus/bus-socket.h
+++ b/src/libsystemd/sd-bus/bus-socket.h
@@ -34,5 +34,6 @@ int bus_socket_read_message(sd_bus *bus);
int bus_socket_process_opening(sd_bus *b);
int bus_socket_process_authenticating(sd_bus *b);
+int bus_socket_process_watch_bind(sd_bus *b);
bool bus_socket_auth_needs_write(sd_bus *b);
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index ab22d6e4de..0dd06e9b99 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -48,25 +48,13 @@ struct sd_bus_track {
LIST_FIELDS(sd_bus_track, tracks);
};
-#define MATCH_PREFIX \
- "type='signal'," \
- "sender='org.freedesktop.DBus'," \
- "path='/org/freedesktop/DBus'," \
- "interface='org.freedesktop.DBus'," \
- "member='NameOwnerChanged'," \
- "arg0='"
-
-#define MATCH_SUFFIX \
- "'"
-
-#define MATCH_FOR_NAME(name) \
- ({ \
- char *_x; \
- size_t _l = strlen(name); \
- _x = alloca(STRLEN(MATCH_PREFIX)+_l+STRLEN(MATCH_SUFFIX)+1); \
- strcpy(stpcpy(stpcpy(_x, MATCH_PREFIX), name), MATCH_SUFFIX); \
- _x; \
- })
+#define MATCH_FOR_NAME(name) \
+ strjoina("type='signal'," \
+ "sender='org.freedesktop.DBus'," \
+ "path='/org/freedesktop/DBus'," \
+ "interface='org.freedesktop.DBus'," \
+ "member='NameOwnerChanged'," \
+ "arg0='", name, "'")
static struct track_item* track_item_free(struct track_item *i) {
@@ -259,9 +247,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */
- track->n_adding++; /* make sure we aren't dispatched while we synchronously add this match */
- r = sd_bus_add_match(track->bus, &n->slot, match, on_name_owner_changed, track);
- track->n_adding--;
+ r = sd_bus_add_match_async(track->bus, &n->slot, match, on_name_owner_changed, NULL, track);
if (r < 0) {
bus_track_add_to_queue(track);
return r;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 3cfc60fe86..8c8853c7ee 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -57,7 +57,7 @@
#define log_debug_bus_message(m) \
do { \
sd_bus_message *_mm = (m); \
- log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error-name=%s error-message=%s", \
+ log_debug("Got message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s", \
bus_message_type_to_string(_mm->header->type), \
strna(sd_bus_message_get_sender(_mm)), \
strna(sd_bus_message_get_destination(_mm)), \
@@ -66,28 +66,39 @@
strna(sd_bus_message_get_member(_mm)), \
BUS_MESSAGE_COOKIE(_mm), \
_mm->reply_cookie, \
+ strna(_mm->root_container.signature), \
strna(_mm->error.name), \
strna(_mm->error.message)); \
} while (false)
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
-static int attach_io_events(sd_bus *b);
-static void detach_io_events(sd_bus *b);
+static void bus_detach_io_events(sd_bus *b);
+static void bus_detach_inotify_event(sd_bus *b);
static thread_local sd_bus *default_system_bus = NULL;
static thread_local sd_bus *default_user_bus = NULL;
static thread_local sd_bus *default_starter_bus = NULL;
-static void bus_close_fds(sd_bus *b) {
+void bus_close_io_fds(sd_bus *b) {
assert(b);
- detach_io_events(b);
+ bus_detach_io_events(b);
if (b->input_fd != b->output_fd)
safe_close(b->output_fd);
b->output_fd = b->input_fd = safe_close(b->input_fd);
}
+void bus_close_inotify_fd(sd_bus *b) {
+ assert(b);
+
+ bus_detach_inotify_event(b);
+
+ b->inotify_fd = safe_close(b->inotify_fd);
+ b->inotify_watches = mfree(b->inotify_watches);
+ b->n_inotify_watches = 0;
+}
+
static void bus_reset_queues(sd_bus *b) {
assert(b);
@@ -131,7 +142,8 @@ static void bus_free(sd_bus *b) {
if (b->default_bus_ptr)
*b->default_bus_ptr = NULL;
- bus_close_fds(b);
+ bus_close_io_fds(b);
+ bus_close_inotify_fd(b);
free(b->label);
free(b->groups);
@@ -142,6 +154,7 @@ static void bus_free(sd_bus *b) {
free(b->machine);
free(b->cgroup_root);
free(b->description);
+ free(b->patch_sender);
free(b->exec_path);
strv_free(b->exec_argv);
@@ -181,10 +194,10 @@ _public_ int sd_bus_new(sd_bus **ret) {
r->n_ref = REFCNT_INIT;
r->input_fd = r->output_fd = -1;
+ r->inotify_fd = -1;
r->message_version = 1;
r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
- r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
- r->attach_flags |= KDBUS_ATTACH_NAMES;
+ r->accept_fd = true;
r->original_pid = getpid_cached();
r->n_groups = (size_t) -1;
@@ -262,6 +275,7 @@ _public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[])
_public_ int sd_bus_set_bus_client(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
assert_return(bus->state == BUS_UNSET, -EPERM);
+ assert_return(!bus->patch_sender, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
bus->bus_client = !!b;
@@ -273,7 +287,7 @@ _public_ int sd_bus_set_monitor(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- SET_FLAG(bus->hello_flags, KDBUS_HELLO_MONITOR, b);
+ bus->is_monitor = b;
return 0;
}
@@ -282,30 +296,23 @@ _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b);
+ bus->accept_fd = b;
return 0;
}
_public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
- uint64_t new_flags;
assert_return(bus, -EINVAL);
assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- new_flags = bus->attach_flags;
- SET_FLAG(new_flags, KDBUS_ATTACH_TIMESTAMP, b);
-
- if (bus->attach_flags == new_flags)
- return 0;
-
- bus->attach_flags = new_flags;
+ /* This is not actually supported by any of our transports these days, but we do honour it for synthetic
+ * replies, and maybe one day classic D-Bus learns this too */
+ bus->attach_timestamp = b;
return 0;
}
_public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
- uint64_t new_flags;
-
assert_return(bus, -EINVAL);
assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL);
assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM);
@@ -316,13 +323,6 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
/* The well knowns we need unconditionally, so that matches can work */
bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
- /* Make sure we don't lose the timestamp flag */
- new_flags = (bus->attach_flags & KDBUS_ATTACH_TIMESTAMP) | attach_flags_to_kdbus(bus->creds_mask);
- if (bus->attach_flags == new_flags)
- return 0;
-
- bus->attach_flags = new_flags;
-
return 0;
}
@@ -378,6 +378,105 @@ _public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) {
return bus->allow_interactive_authorization;
}
+_public_ int sd_bus_set_watch_bind(sd_bus *bus, int b) {
+ assert_return(bus, -EINVAL);
+ assert_return(bus->state == BUS_UNSET, -EPERM);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ bus->watch_bind = b;
+ return 0;
+}
+
+_public_ int sd_bus_get_watch_bind(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->watch_bind;
+}
+
+_public_ int sd_bus_set_connected_signal(sd_bus *bus, int b) {
+ assert_return(bus, -EINVAL);
+ assert_return(bus->state == BUS_UNSET, -EPERM);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ bus->connected_signal = b;
+ return 0;
+}
+
+_public_ int sd_bus_get_connected_signal(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->connected_signal;
+}
+
+static int synthesize_connected_signal(sd_bus *bus) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ int r;
+
+ assert(bus);
+
+ /* If enabled, synthesizes a local "Connected" signal mirroring the local "Disconnected" signal. This is called
+ * whenever we fully established a connection, i.e. after the authorization phase, and after receiving the
+ * Hello() reply. Or in other words, whenver we enter BUS_RUNNING state.
+ *
+ * This is useful so that clients can start doing stuff whenver the connection is fully established in a way
+ * that works independently from whether we connected to a full bus or just a direct connection. */
+
+ if (!bus->connected_signal)
+ return 0;
+
+ r = sd_bus_message_new_signal(
+ bus,
+ &m,
+ "/org/freedesktop/DBus/Local",
+ "org.freedesktop.DBus.Local",
+ "Connected");
+ if (r < 0)
+ return r;
+
+ bus_message_set_sender_local(bus, m);
+
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
+
+ r = bus_rqueue_make_room(bus);
+ if (r < 0)
+ return r;
+
+ /* Insert at the very front */
+ memmove(bus->rqueue + 1, bus->rqueue, sizeof(sd_bus_message*) * bus->rqueue_size);
+ bus->rqueue[0] = m;
+ m = NULL;
+ bus->rqueue_size++;
+
+ return 0;
+}
+
+void bus_set_state(sd_bus *bus, enum bus_state state) {
+
+ static const char * const table[_BUS_STATE_MAX] = {
+ [BUS_UNSET] = "UNSET",
+ [BUS_WATCH_BIND] = "WATCH_BIND",
+ [BUS_OPENING] = "OPENING",
+ [BUS_AUTHENTICATING] = "AUTHENTICATING",
+ [BUS_HELLO] = "HELLO",
+ [BUS_RUNNING] = "RUNNING",
+ [BUS_CLOSING] = "CLOSING",
+ [BUS_CLOSED] = "CLOSED",
+ };
+
+ assert(bus);
+ assert(state < _BUS_STATE_MAX);
+
+ if (state == bus->state)
+ return;
+
+ log_debug("Bus %s: changing state %s → %s", strna(bus->description), table[bus->state], table[state]);
+ bus->state = state;
+}
+
static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
const char *s;
sd_bus *bus;
@@ -403,8 +502,13 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e
if (!bus->unique_name)
return -ENOMEM;
- if (bus->state == BUS_HELLO)
- bus->state = BUS_RUNNING;
+ if (bus->state == BUS_HELLO) {
+ bus_set_state(bus, BUS_RUNNING);
+
+ r = synthesize_connected_signal(bus);
+ if (r < 0)
+ return r;
+ }
return 1;
}
@@ -432,14 +536,37 @@ static int bus_send_hello(sd_bus *bus) {
}
int bus_start_running(sd_bus *bus) {
+ struct reply_callback *c;
+ Iterator i;
+ usec_t n;
+ int r;
+
assert(bus);
+ assert(bus->state < BUS_HELLO);
+
+ /* We start all method call timeouts when we enter BUS_HELLO or BUS_RUNNING mode. At this point let's convert
+ * all relative to absolute timestamps. Note that we do not reshuffle the reply callback priority queue since
+ * adding a fixed value to all entries should not alter the internal order. */
+
+ n = now(CLOCK_MONOTONIC);
+ ORDERED_HASHMAP_FOREACH(c, bus->reply_callbacks, i) {
+ if (c->timeout_usec == 0)
+ continue;
+
+ c->timeout_usec = usec_add(n, c->timeout_usec);
+ }
if (bus->bus_client) {
- bus->state = BUS_HELLO;
+ bus_set_state(bus, BUS_HELLO);
return 1;
}
- bus->state = BUS_RUNNING;
+ bus_set_state(bus, BUS_RUNNING);
+
+ r = synthesize_connected_signal(bus);
+ if (r < 0)
+ return r;
+
return 1;
}
@@ -801,6 +928,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
b->nspid = 0;
b->sockaddr.un.sun_family = AF_UNIX;
+ /* Note that we use the old /var/run prefix here, to increase compatibility with really old containers */
strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);
b->is_local = false;
@@ -900,7 +1028,8 @@ static int bus_start_address(sd_bus *b) {
assert(b);
for (;;) {
- bus_close_fds(b);
+ bus_close_io_fds(b);
+ bus_close_inotify_fd(b);
/* If you provide multiple different bus-addresses, we
* try all of them in order and use the first one that
@@ -908,20 +1037,25 @@ static int bus_start_address(sd_bus *b) {
if (b->exec_path)
r = bus_socket_exec(b);
-
else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC)
r = bus_container_connect_socket(b);
-
else if (b->sockaddr.sa.sa_family != AF_UNSPEC)
r = bus_socket_connect(b);
-
else
goto next;
if (r >= 0) {
- r = attach_io_events(b);
- if (r >= 0)
- return r;
+ int q;
+
+ q = bus_attach_io_events(b);
+ if (q < 0)
+ return q;
+
+ q = bus_attach_inotify_event(b);
+ if (q < 0)
+ return q;
+
+ return r;
}
b->last_connect_error = -r;
@@ -981,7 +1115,7 @@ _public_ int sd_bus_start(sd_bus *bus) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- bus->state = BUS_OPENING;
+ bus_set_state(bus, BUS_OPENING);
if (bus->is_server && bus->bus_client)
return -EINVAL;
@@ -1042,7 +1176,6 @@ _public_ int sd_bus_open(sd_bus **ret) {
* be safe, and authenticate everything */
b->trusted = false;
b->is_local = false;
- b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS;
r = sd_bus_start(b);
@@ -1088,7 +1221,6 @@ _public_ int sd_bus_open_system(sd_bus **ret) {
/* Let's do per-method access control on the system bus. We
* need the caller's UID and capability set for that. */
b->trusted = false;
- b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS;
b->is_local = true;
@@ -1122,7 +1254,7 @@ int bus_set_address_user(sd_bus *b) {
if (!ee)
return -ENOMEM;
- if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, ee) < 0)
+ if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, ee) < 0)
return -ENOMEM;
b->address = s;
@@ -1296,7 +1428,7 @@ _public_ void sd_bus_close(sd_bus *bus) {
if (bus_pid_changed(bus))
return;
- bus->state = BUS_CLOSED;
+ bus_set_state(bus, BUS_CLOSED);
sd_bus_detach_event(bus);
@@ -1304,7 +1436,8 @@ _public_ void sd_bus_close(sd_bus *bus) {
* the bus object and the bus may be freed */
bus_reset_queues(bus);
- bus_close_fds(bus);
+ bus_close_io_fds(bus);
+ bus_close_inotify_fd(bus);
}
_public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
@@ -1318,13 +1451,13 @@ _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
return sd_bus_unref(bus);
}
-static void bus_enter_closing(sd_bus *bus) {
+void bus_enter_closing(sd_bus *bus) {
assert(bus);
- if (!IN_SET(bus->state, BUS_OPENING, BUS_AUTHENTICATING, BUS_HELLO, BUS_RUNNING))
+ if (!IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING, BUS_HELLO, BUS_RUNNING))
return;
- bus->state = BUS_CLOSING;
+ bus_set_state(bus, BUS_CLOSING);
}
_public_ sd_bus *sd_bus_ref(sd_bus *bus) {
@@ -1359,6 +1492,13 @@ _public_ int sd_bus_is_open(sd_bus *bus) {
return BUS_IS_OPEN(bus->state);
}
+_public_ int sd_bus_is_ready(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->state == BUS_RUNNING;
+}
+
_public_ int sd_bus_can_send(sd_bus *bus, char type) {
int r;
@@ -1366,11 +1506,11 @@ _public_ int sd_bus_can_send(sd_bus *bus, char type) {
assert_return(bus->state != BUS_UNSET, -ENOTCONN);
assert_return(!bus_pid_changed(bus), -ECHILD);
- if (bus->hello_flags & KDBUS_HELLO_MONITOR)
+ if (bus->is_monitor)
return 0;
if (type == SD_BUS_TYPE_UNIX_FD) {
- if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD))
+ if (!bus->accept_fd)
return 0;
r = bus_ensure_running(bus);
@@ -1399,6 +1539,8 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
}
static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
+ int r;
+
assert(b);
assert(m);
@@ -1413,6 +1555,12 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
if (timeout == 0)
timeout = BUS_DEFAULT_TIMEOUT;
+ if (!m->sender && b->patch_sender) {
+ r = sd_bus_message_set_sender(m, b->patch_sender);
+ if (r < 0)
+ return r;
+ }
+
return sd_bus_message_seal(m, ++b->cookie, timeout);
}
@@ -1438,7 +1586,7 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
/* Fake some timestamps, if they were requested, and not
* already initialized */
- if (b->attach_flags & KDBUS_ATTACH_TIMESTAMP) {
+ if (b->attach_timestamp) {
if (m->realtime <= 0)
m->realtime = now(CLOCK_REALTIME);
@@ -1456,7 +1604,7 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
return sd_bus_message_seal(m, 0xFFFFFFFFULL, 0);
}
-static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call, size_t *idx) {
+static int bus_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
int r;
assert(bus);
@@ -1467,7 +1615,7 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
return r;
if (*idx >= BUS_MESSAGE_SIZE(m))
- log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error-name=%s error-message=%s",
+ log_debug("Sent message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s",
bus_message_type_to_string(m->header->type),
strna(sd_bus_message_get_sender(m)),
strna(sd_bus_message_get_destination(m)),
@@ -1476,6 +1624,7 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
strna(sd_bus_message_get_member(m)),
BUS_MESSAGE_COOKIE(m),
m->reply_cookie,
+ strna(m->root_container.signature),
strna(m->error.name),
strna(m->error.message));
@@ -1490,7 +1639,7 @@ static int dispatch_wqueue(sd_bus *bus) {
while (bus->wqueue_size > 0) {
- r = bus_write_message(bus, bus->wqueue[0], false, &bus->windex);
+ r = bus_write_message(bus, bus->wqueue[0], &bus->windex);
if (r < 0)
return r;
else if (r == 0)
@@ -1569,7 +1718,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
}
}
-static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bool hint_sync_call) {
+_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
int r;
@@ -1614,7 +1763,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
if (IN_SET(bus->state, BUS_RUNNING, BUS_HELLO) && bus->wqueue_size <= 0) {
size_t idx = 0;
- r = bus_write_message(bus, m, hint_sync_call, &idx);
+ r = bus_write_message(bus, m, &idx);
if (r < 0) {
if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
@@ -1654,10 +1803,6 @@ finish:
return 1;
}
-_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) {
- return bus_send_internal(bus, m, cookie, false);
-}
-
_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
int r;
@@ -1684,26 +1829,35 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat
return sd_bus_send(bus, m, cookie);
}
-static usec_t calc_elapse(uint64_t usec) {
+static usec_t calc_elapse(sd_bus *bus, uint64_t usec) {
+ assert(bus);
+
if (usec == (uint64_t) -1)
return 0;
- return now(CLOCK_MONOTONIC) + usec;
+ /* We start all timeouts the instant we enter BUS_HELLO/BUS_RUNNING state, so that the don't run in parallel
+ * with any connection setup states. Hence, if a method callback is started earlier than that we just store the
+ * relative timestamp, and afterwards the absolute one. */
+
+ if (IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING))
+ return usec;
+ else
+ return now(CLOCK_MONOTONIC) + usec;
}
static int timeout_compare(const void *a, const void *b) {
const struct reply_callback *x = a, *y = b;
- if (x->timeout != 0 && y->timeout == 0)
+ if (x->timeout_usec != 0 && y->timeout_usec == 0)
return -1;
- if (x->timeout == 0 && y->timeout != 0)
+ if (x->timeout_usec == 0 && y->timeout_usec != 0)
return 1;
- if (x->timeout < y->timeout)
+ if (x->timeout_usec < y->timeout_usec)
return -1;
- if (x->timeout > y->timeout)
+ if (x->timeout_usec > y->timeout_usec)
return 1;
return 0;
@@ -1723,8 +1877,7 @@ _public_ int sd_bus_call_async(
assert_return(m, -EINVAL);
assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
- assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
- assert_return(callback, -EINVAL);
+ assert_return(!m->sealed || (!!callback == !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)), -EINVAL);
if (!bus)
bus = m->bus;
@@ -1734,6 +1887,10 @@ _public_ int sd_bus_call_async(
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
+ /* If no callback is specified and there's no interest in a slot, then there's no reason to ask for a reply */
+ if (!callback && !slot && !m->sealed)
+ m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+
r = ordered_hashmap_ensure_allocated(&bus->reply_callbacks, &uint64_hash_ops);
if (r < 0)
return r;
@@ -1750,29 +1907,31 @@ _public_ int sd_bus_call_async(
if (r < 0)
return r;
- s = bus_slot_allocate(bus, !slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata);
- if (!s)
- return -ENOMEM;
-
- s->reply_callback.callback = callback;
+ if (slot || callback) {
+ s = bus_slot_allocate(bus, !slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata);
+ if (!s)
+ return -ENOMEM;
- s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m);
- r = ordered_hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback);
- if (r < 0) {
- s->reply_callback.cookie = 0;
- return r;
- }
+ s->reply_callback.callback = callback;
- s->reply_callback.timeout = calc_elapse(m->timeout);
- if (s->reply_callback.timeout != 0) {
- r = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx);
+ s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m);
+ r = ordered_hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback);
if (r < 0) {
- s->reply_callback.timeout = 0;
+ s->reply_callback.cookie = 0;
return r;
}
+
+ s->reply_callback.timeout_usec = calc_elapse(bus, m->timeout);
+ if (s->reply_callback.timeout_usec != 0) {
+ r = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx);
+ if (r < 0) {
+ s->reply_callback.timeout_usec = 0;
+ return r;
+ }
+ }
}
- r = sd_bus_send(bus, m, &s->reply_callback.cookie);
+ r = sd_bus_send(bus, m, s ? &s->reply_callback.cookie : NULL);
if (r < 0)
return r;
@@ -1850,11 +2009,11 @@ _public_ int sd_bus_call(
if (r < 0)
goto fail;
- r = bus_send_internal(bus, m, &cookie, true);
+ r = sd_bus_send(bus, m, &cookie);
if (r < 0)
goto fail;
- timeout = calc_elapse(m->timeout);
+ timeout = calc_elapse(bus, m->timeout);
for (;;) {
usec_t left;
@@ -1873,7 +2032,7 @@ _public_ int sd_bus_call(
if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
- if (incoming->n_fds <= 0 || (bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) {
+ if (incoming->n_fds <= 0 || bus->accept_fd) {
if (reply)
*reply = incoming;
else
@@ -1971,7 +2130,16 @@ _public_ int sd_bus_get_fd(sd_bus *bus) {
assert_return(bus->input_fd == bus->output_fd, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- return bus->input_fd;
+ if (bus->state == BUS_CLOSED)
+ return -ENOTCONN;
+
+ if (bus->inotify_fd >= 0)
+ return bus->inotify_fd;
+
+ if (bus->input_fd >= 0)
+ return bus->input_fd;
+
+ return -ENOTCONN;
}
_public_ int sd_bus_get_events(sd_bus *bus) {
@@ -1980,23 +2148,40 @@ _public_ int sd_bus_get_events(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- if (!BUS_IS_OPEN(bus->state) && bus->state != BUS_CLOSING)
+ switch (bus->state) {
+
+ case BUS_UNSET:
+ case BUS_CLOSED:
return -ENOTCONN;
- if (bus->state == BUS_OPENING)
+ case BUS_WATCH_BIND:
+ flags |= POLLIN;
+ break;
+
+ case BUS_OPENING:
flags |= POLLOUT;
- else if (bus->state == BUS_AUTHENTICATING) {
+ break;
+ case BUS_AUTHENTICATING:
if (bus_socket_auth_needs_write(bus))
flags |= POLLOUT;
flags |= POLLIN;
+ break;
- } else if (IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)) {
+ case BUS_RUNNING:
+ case BUS_HELLO:
if (bus->rqueue_size <= 0)
flags |= POLLIN;
if (bus->wqueue_size > 0)
flags |= POLLOUT;
+ break;
+
+ case BUS_CLOSING:
+ break;
+
+ default:
+ assert_not_reached("Unknown state");
}
return flags;
@@ -2017,39 +2202,45 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
return 1;
}
- if (bus->state == BUS_CLOSING) {
- *timeout_usec = 0;
- return 1;
- }
+ switch (bus->state) {
- if (bus->state == BUS_AUTHENTICATING) {
+ case BUS_AUTHENTICATING:
*timeout_usec = bus->auth_timeout;
return 1;
- }
- if (!IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)) {
- *timeout_usec = (uint64_t) -1;
- return 0;
- }
+ case BUS_RUNNING:
+ case BUS_HELLO:
+ if (bus->rqueue_size > 0) {
+ *timeout_usec = 0;
+ return 1;
+ }
+
+ c = prioq_peek(bus->reply_callbacks_prioq);
+ if (!c) {
+ *timeout_usec = (uint64_t) -1;
+ return 0;
+ }
+
+ if (c->timeout_usec == 0) {
+ *timeout_usec = (uint64_t) -1;
+ return 0;
+ }
- if (bus->rqueue_size > 0) {
+ *timeout_usec = c->timeout_usec;
+ return 1;
+
+ case BUS_CLOSING:
*timeout_usec = 0;
return 1;
- }
- c = prioq_peek(bus->reply_callbacks_prioq);
- if (!c) {
+ case BUS_WATCH_BIND:
+ case BUS_OPENING:
*timeout_usec = (uint64_t) -1;
return 0;
- }
- if (c->timeout == 0) {
- *timeout_usec = (uint64_t) -1;
- return 0;
+ default:
+ assert_not_reached("Unknown or unexpected stat");
}
-
- *timeout_usec = c->timeout;
- return 1;
}
static int process_timeout(sd_bus *bus) {
@@ -2057,17 +2248,19 @@ static int process_timeout(sd_bus *bus) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message* m = NULL;
struct reply_callback *c;
sd_bus_slot *slot;
+ bool is_hello;
usec_t n;
int r;
assert(bus);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
c = prioq_peek(bus->reply_callbacks_prioq);
if (!c)
return 0;
n = now(CLOCK_MONOTONIC);
- if (c->timeout > n)
+ if (c->timeout_usec > n)
return 0;
r = bus_message_new_synthetic_error(
@@ -2083,7 +2276,7 @@ static int process_timeout(sd_bus *bus) {
return r;
assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
- c->timeout = 0;
+ c->timeout_usec = 0;
ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
c->cookie = 0;
@@ -2092,6 +2285,8 @@ static int process_timeout(sd_bus *bus) {
bus->iteration_counter++;
+ is_hello = bus->state == BUS_HELLO && c->callback == hello_callback;
+
bus->current_message = m;
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->callback;
@@ -2109,6 +2304,11 @@ static int process_timeout(sd_bus *bus) {
sd_bus_slot_unref(slot);
+ /* When this is the hello message and it timed out, then make sure to propagate the error up, don't just log
+ * and ignore the callback handler's return value. */
+ if (is_hello)
+ return r;
+
return bus_maybe_reply_error(m, r, &error_buffer);
}
@@ -2138,6 +2338,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
_cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
struct reply_callback *c;
sd_bus_slot *slot;
+ bool is_hello;
int r;
assert(bus);
@@ -2157,7 +2358,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
slot = container_of(c, sd_bus_slot, reply_callback);
- if (m->n_fds > 0 && !(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) {
+ if (m->n_fds > 0 && !bus->accept_fd) {
/* If the reply contained a file descriptor which we
* didn't want we pass an error instead. */
@@ -2186,11 +2387,13 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
return r;
}
- if (c->timeout != 0) {
+ if (c->timeout_usec != 0) {
prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
- c->timeout = 0;
+ c->timeout_usec = 0;
}
+ is_hello = bus->state == BUS_HELLO && c->callback == hello_callback;
+
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->callback;
bus->current_userdata = slot->userdata;
@@ -2206,6 +2409,11 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
sd_bus_slot_unref(slot);
+ /* When this is the hello message and it failed, then make sure to propagate the error up, don't just log and
+ * ignore the callback handler's return value. */
+ if (is_hello)
+ return r;
+
return bus_maybe_reply_error(m, r, &error_buffer);
}
@@ -2282,7 +2490,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
assert(bus);
assert(m);
- if (bus->hello_flags & KDBUS_HELLO_MONITOR)
+ if (bus->is_monitor)
return 0;
if (bus->manual_peer_interface)
@@ -2340,13 +2548,13 @@ static int process_fd_check(sd_bus *bus, sd_bus_message *m) {
* delivered to us later even though we ourselves did not
* negotiate it. */
- if (bus->hello_flags & KDBUS_HELLO_MONITOR)
+ if (bus->is_monitor)
return 0;
if (m->n_fds <= 0)
return 0;
- if (bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)
+ if (bus->accept_fd)
return 0;
if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
@@ -2517,9 +2725,9 @@ static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c)
if (r < 0)
return r;
- if (c->timeout != 0) {
+ if (c->timeout_usec != 0) {
prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
- c->timeout = 0;
+ c->timeout_usec = 0;
}
ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
@@ -2638,48 +2846,44 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_CLOSED:
return -ECONNRESET;
+ case BUS_WATCH_BIND:
+ r = bus_socket_process_watch_bind(bus);
+ break;
+
case BUS_OPENING:
r = bus_socket_process_opening(bus);
- if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
- bus_enter_closing(bus);
- r = 1;
- } else if (r < 0)
- return r;
- if (ret)
- *ret = NULL;
- return r;
+ break;
case BUS_AUTHENTICATING:
r = bus_socket_process_authenticating(bus);
- if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
- bus_enter_closing(bus);
- r = 1;
- } else if (r < 0)
- return r;
-
- if (ret)
- *ret = NULL;
-
- return r;
+ break;
case BUS_RUNNING:
case BUS_HELLO:
r = process_running(bus, hint_priority, priority, ret);
- if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
- bus_enter_closing(bus);
- r = 1;
-
- if (ret)
- *ret = NULL;
- }
+ if (r >= 0)
+ return r;
- return r;
+ /* This branch initializes *ret, hence we don't use the generic error checking below */
+ break;
case BUS_CLOSING:
return process_closing(bus, ret);
+
+ default:
+ assert_not_reached("Unknown state");
}
- assert_not_reached("Unknown state");
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+ bus_enter_closing(bus);
+ r = 1;
+ } else if (r < 0)
+ return r;
+
+ if (ret)
+ *ret = NULL;
+
+ return r;
}
_public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
@@ -2692,7 +2896,7 @@ _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_messa
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
struct pollfd p[2] = {};
- int r, e, n;
+ int r, n;
struct timespec ts;
usec_t m = USEC_INFINITY;
@@ -2704,45 +2908,52 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- e = sd_bus_get_events(bus);
- if (e < 0)
- return e;
-
- if (need_more)
- /* The caller really needs some more data, he doesn't
- * care about what's already read, or any timeouts
- * except its own. */
- e |= POLLIN;
- else {
- usec_t until;
- /* The caller wants to process if there's something to
- * process, but doesn't care otherwise */
-
- r = sd_bus_get_timeout(bus, &until);
- if (r < 0)
- return r;
- if (r > 0) {
- usec_t nw;
- nw = now(CLOCK_MONOTONIC);
- m = until > nw ? until - nw : 0;
- }
- }
-
- if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
- m = timeout_usec;
+ if (bus->state == BUS_WATCH_BIND) {
+ assert(bus->inotify_fd >= 0);
- p[0].fd = bus->input_fd;
- if (bus->output_fd == bus->input_fd) {
- p[0].events = e;
+ p[0].events = POLLIN;
+ p[0].fd = bus->inotify_fd;
n = 1;
} else {
- p[0].events = e & POLLIN;
- p[1].fd = bus->output_fd;
- p[1].events = e & POLLOUT;
- n = 2;
+ int e;
+
+ e = sd_bus_get_events(bus);
+ if (e < 0)
+ return e;
+
+ if (need_more)
+ /* The caller really needs some more data, he doesn't
+ * care about what's already read, or any timeouts
+ * except its own. */
+ e |= POLLIN;
+ else {
+ usec_t until;
+ /* The caller wants to process if there's something to
+ * process, but doesn't care otherwise */
+
+ r = sd_bus_get_timeout(bus, &until);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ m = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
+ }
+
+ p[0].fd = bus->input_fd;
+ if (bus->output_fd == bus->input_fd) {
+ p[0].events = e;
+ n = 1;
+ } else {
+ p[0].events = e & POLLIN;
+ p[1].fd = bus->output_fd;
+ p[1].events = e & POLLOUT;
+ n = 2;
+ }
}
- r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
+ if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m))
+ m = timeout_usec;
+
+ r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL);
if (r < 0)
return -errno;
@@ -2778,6 +2989,10 @@ _public_ int sd_bus_flush(sd_bus *bus) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
+ /* We never were connected? Don't hang in inotify for good, as there's no timeout set for it */
+ if (bus->state == BUS_WATCH_BIND)
+ return -EUNATCH;
+
r = bus_ensure_running(bus);
if (r < 0)
return r;
@@ -2832,11 +3047,78 @@ _public_ int sd_bus_add_filter(
return 0;
}
-_public_ int sd_bus_add_match(
+static int add_match_callback(
+ sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error) {
+
+ sd_bus_slot *match_slot = userdata;
+ bool failed = false;
+ int r;
+
+ assert(m);
+ assert(match_slot);
+
+ sd_bus_slot_ref(match_slot);
+
+ if (sd_bus_message_is_method_error(m, NULL)) {
+ log_debug_errno(sd_bus_message_get_errno(m),
+ "Unable to add match %s, failing connection: %s",
+ match_slot->match_callback.match_string,
+ sd_bus_message_get_error(m)->message);
+
+ failed = true;
+ } else
+ log_debug("Match %s successfully installed.", match_slot->match_callback.match_string);
+
+ if (match_slot->match_callback.install_callback) {
+ sd_bus *bus;
+
+ bus = sd_bus_message_get_bus(m);
+
+ /* This function has been called as slot handler, and we want to call another slot handler. Let's
+ * update the slot callback metadata temporarily with our own data, and then revert back to the old
+ * values. */
+
+ assert(bus->current_slot == match_slot->match_callback.install_slot);
+ assert(bus->current_handler == add_match_callback);
+ assert(bus->current_userdata == userdata);
+
+ bus->current_slot = match_slot;
+ bus->current_handler = match_slot->match_callback.install_callback;
+ bus->current_userdata = match_slot->userdata;
+
+ r = match_slot->match_callback.install_callback(m, match_slot->userdata, ret_error);
+
+ bus->current_slot = match_slot->match_callback.install_slot;
+ bus->current_handler = add_match_callback;
+ bus->current_userdata = userdata;
+
+ match_slot->match_callback.install_slot = sd_bus_slot_unref(match_slot->match_callback.install_slot);
+ } else {
+ if (failed) /* Generic failure handling: destroy the connection */
+ bus_enter_closing(sd_bus_message_get_bus(m));
+
+ r = 1;
+ }
+
+ if (failed && match_slot->floating) {
+ bus_slot_disconnect(match_slot);
+ sd_bus_slot_unref(match_slot);
+ }
+
+ sd_bus_slot_unref(match_slot);
+
+ return r;
+}
+
+static int bus_add_match_full(
sd_bus *bus,
sd_bus_slot **slot,
+ bool asynchronous,
const char *match,
sd_bus_message_handler_t callback,
+ sd_bus_message_handler_t install_callback,
void *userdata) {
struct bus_match_component *components = NULL;
@@ -2859,18 +3141,17 @@ _public_ int sd_bus_add_match(
}
s->match_callback.callback = callback;
+ s->match_callback.install_callback = install_callback;
if (bus->bus_client) {
enum bus_match_scope scope;
scope = bus_match_get_scope(components, n_components);
- /* Do not install server-side matches for matches
- * against the local service, interface or bus path. */
+ /* Do not install server-side matches for matches against the local service, interface or bus path. */
if (scope != BUS_MATCH_LOCAL) {
- /* We store the original match string, so that
- * we can use it to remove the match again. */
+ /* We store the original match string, so that we can use it to remove the match again. */
s->match_callback.match_string = strdup(match);
if (!s->match_callback.match_string) {
@@ -2878,7 +3159,14 @@ _public_ int sd_bus_add_match(
goto finish;
}
- r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components);
+ if (asynchronous)
+ r = bus_add_match_internal_async(bus,
+ &s->match_callback.install_slot,
+ s->match_callback.match_string,
+ add_match_callback,
+ s);
+ else
+ r = bus_add_match_internal(bus, s->match_callback.match_string);
if (r < 0)
goto finish;
@@ -2902,35 +3190,25 @@ finish:
return r;
}
-int bus_remove_match_by_string(
+_public_ int sd_bus_add_match(
sd_bus *bus,
+ sd_bus_slot **slot,
const char *match,
sd_bus_message_handler_t callback,
void *userdata) {
- struct bus_match_component *components = NULL;
- unsigned n_components = 0;
- struct match_callback *c;
- int r = 0;
-
- assert_return(bus, -EINVAL);
- assert_return(match, -EINVAL);
- assert_return(!bus_pid_changed(bus), -ECHILD);
-
- r = bus_match_parse(match, &components, &n_components);
- if (r < 0)
- goto finish;
-
- r = bus_match_find(&bus->match_callbacks, components, n_components, NULL, NULL, &c);
- if (r <= 0)
- goto finish;
-
- sd_bus_slot_unref(container_of(c, sd_bus_slot, match_callback));
+ return bus_add_match_full(bus, slot, false, match, callback, NULL, userdata);
+}
-finish:
- bus_match_parse_free(components, n_components);
+_public_ int sd_bus_add_match_async(
+ sd_bus *bus,
+ sd_bus_slot **slot,
+ const char *match,
+ sd_bus_message_handler_t callback,
+ sd_bus_message_handler_t install_callback,
+ void *userdata) {
- return r;
+ return bus_add_match_full(bus, slot, true, match, callback, install_callback, userdata);
}
bool bus_pid_changed(sd_bus *bus) {
@@ -2948,9 +3226,13 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd
assert(bus);
+ /* Note that this is called both on input_fd, output_fd as well as inotify_fd events */
+
r = sd_bus_process(bus, NULL);
- if (r < 0)
- return r;
+ if (r < 0) {
+ log_debug_errno(r, "Processing of bus failed, closing down: %m");
+ bus_enter_closing(bus);
+ }
return 1;
}
@@ -2962,8 +3244,10 @@ static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
assert(bus);
r = sd_bus_process(bus, NULL);
- if (r < 0)
- return r;
+ if (r < 0) {
+ log_debug_errno(r, "Processing of bus failed, closing down: %m");
+ bus_enter_closing(bus);
+ }
return 1;
}
@@ -2977,38 +3261,45 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
assert(bus);
e = sd_bus_get_events(bus);
- if (e < 0)
- return e;
+ if (e < 0) {
+ r = e;
+ goto fail;
+ }
if (bus->output_fd != bus->input_fd) {
r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN);
if (r < 0)
- return r;
+ goto fail;
r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT);
- if (r < 0)
- return r;
- } else {
+ } else
r = sd_event_source_set_io_events(bus->input_io_event_source, e);
- if (r < 0)
- return r;
- }
+ if (r < 0)
+ goto fail;
r = sd_bus_get_timeout(bus, &until);
if (r < 0)
- return r;
+ goto fail;
if (r > 0) {
int j;
j = sd_event_source_set_time(bus->time_event_source, until);
- if (j < 0)
- return j;
+ if (j < 0) {
+ r = j;
+ goto fail;
+ }
}
r = sd_event_source_set_enabled(bus->time_event_source, r > 0);
if (r < 0)
- return r;
+ goto fail;
+
+ return 1;
+
+fail:
+ log_debug_errno(r, "Preparing of bus events failed, closing down: %m");
+ bus_enter_closing(bus);
return 1;
}
@@ -3024,7 +3315,7 @@ static int quit_callback(sd_event_source *event, void *userdata) {
return 1;
}
-static int attach_io_events(sd_bus *bus) {
+int bus_attach_io_events(sd_bus *bus) {
int r;
assert(bus);
@@ -3078,7 +3369,7 @@ static int attach_io_events(sd_bus *bus) {
return 0;
}
-static void detach_io_events(sd_bus *bus) {
+static void bus_detach_io_events(sd_bus *bus) {
assert(bus);
if (bus->input_io_event_source) {
@@ -3092,6 +3383,44 @@ static void detach_io_events(sd_bus *bus) {
}
}
+int bus_attach_inotify_event(sd_bus *bus) {
+ int r;
+
+ assert(bus);
+
+ if (bus->inotify_fd < 0)
+ return 0;
+
+ if (!bus->event)
+ return 0;
+
+ if (!bus->inotify_event_source) {
+ r = sd_event_add_io(bus->event, &bus->inotify_event_source, bus->inotify_fd, EPOLLIN, io_callback, bus);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(bus->inotify_event_source, bus->event_priority);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_description(bus->inotify_event_source, "bus-inotify");
+ } else
+ r = sd_event_source_set_io_fd(bus->inotify_event_source, bus->inotify_fd);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static void bus_detach_inotify_event(sd_bus *bus) {
+ assert(bus);
+
+ if (bus->inotify_event_source) {
+ sd_event_source_set_enabled(bus->inotify_event_source, SD_EVENT_OFF);
+ bus->inotify_event_source = sd_event_source_unref(bus->inotify_event_source);
+ }
+}
+
_public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
int r;
@@ -3132,7 +3461,11 @@ _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
if (r < 0)
goto fail;
- r = attach_io_events(bus);
+ r = bus_attach_io_events(bus);
+ if (r < 0)
+ goto fail;
+
+ r = bus_attach_inotify_event(bus);
if (r < 0)
goto fail;
@@ -3149,7 +3482,8 @@ _public_ int sd_bus_detach_event(sd_bus *bus) {
if (!bus->event)
return 0;
- detach_io_events(bus);
+ bus_detach_io_events(bus);
+ bus_detach_inotify_event(bus);
if (bus->time_event_source) {
sd_event_source_set_enabled(bus->time_event_source, SD_EVENT_OFF);
@@ -3251,12 +3585,9 @@ _public_ int sd_bus_default(sd_bus **ret) {
/* No type is specified, so we have not other option than to
* use the starter address if it is set. */
-
e = secure_getenv("DBUS_STARTER_ADDRESS");
- if (e) {
-
+ if (e)
return bus_default(sd_bus_open, &default_starter_bus, ret);
- }
/* Finally, if nothing is set use the cached connection for
* the right scope */
@@ -3597,7 +3928,7 @@ _public_ int sd_bus_is_monitor(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- return !!(bus->hello_flags & KDBUS_HELLO_MONITOR);
+ return bus->is_monitor;
}
static void flush_close(sd_bus *bus) {
@@ -3634,3 +3965,22 @@ _public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) {
return bus->exit_on_disconnect;
}
+
+_public_ int sd_bus_set_sender(sd_bus *bus, const char *sender) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus->bus_client, -EPERM);
+ assert_return(!sender || service_name_is_valid(sender), -EINVAL);
+
+ return free_and_strdup(&bus->patch_sender, sender);
+}
+
+_public_ int sd_bus_get_sender(sd_bus *bus, const char **ret) {
+ assert_return(bus, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!bus->patch_sender)
+ return -ENODATA;
+
+ *ret = bus->patch_sender;
+ return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index 1b2efb9bb4..bd6721946a 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -102,9 +102,9 @@ static int server_init(sd_bus **_bus) {
goto fail;
}
- r = sd_bus_add_match(bus, NULL, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
+ r = sd_bus_match_signal(bus, NULL, NULL, NULL, "foo.bar", "Notify", match_callback, NULL);
if (r < 0) {
- log_error_errno(r, "Failed to add match: %m");
+ log_error_errno(r, "Failed to request match: %m");
goto fail;
}
diff --git a/src/libsystemd/sd-bus/test-bus-watch-bind.c b/src/libsystemd/sd-bus/test-bus-watch-bind.c
new file mode 100644
index 0000000000..aef5ba9486
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-watch-bind.c
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <pthread.h>
+
+#include "sd-bus.h"
+#include "sd-event.h"
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "random-util.h"
+#include "rm-rf.h"
+#include "socket-util.h"
+#include "string-util.h"
+
+static int method_foobar(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ log_info("Got Foobar() call.");
+
+ assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0) >= 0);
+ return sd_bus_reply_method_return(m, NULL);
+}
+
+static int method_exit(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ log_info("Got Exit() call");
+ assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 1) >= 0);
+ return sd_bus_reply_method_return(m, NULL);
+}
+
+static const sd_bus_vtable vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("Foobar", NULL, NULL, method_foobar, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Exit", NULL, NULL, method_exit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END,
+};
+
+static void* thread_server(void *p) {
+ _cleanup_free_ char *suffixed = NULL, *suffixed2 = NULL, *d = NULL;
+ _cleanup_close_ int fd = -1;
+ union sockaddr_union u = {
+ .un.sun_family = AF_UNIX,
+ };
+ const char *path = p;
+
+ log_debug("Initializing server");
+
+ /* Let's play some games, by slowly creating the socket directory, and renaming it in the middle */
+ (void) usleep(100 * USEC_PER_MSEC);
+
+ assert_se(mkdir_parents(path, 0755) >= 0);
+ (void) usleep(100 * USEC_PER_MSEC);
+
+ d = dirname_malloc(path);
+ assert_se(d);
+ assert_se(asprintf(&suffixed, "%s.%" PRIx64, d, random_u64()) >= 0);
+ assert_se(rename(d, suffixed) >= 0);
+ (void) usleep(100 * USEC_PER_MSEC);
+
+ assert_se(asprintf(&suffixed2, "%s.%" PRIx64, d, random_u64()) >= 0);
+ assert_se(symlink(suffixed2, d) >= 0);
+ (void) usleep(100 * USEC_PER_MSEC);
+
+ assert_se(symlink(basename(suffixed), suffixed2) >= 0);
+ (void) usleep(100 * USEC_PER_MSEC);
+
+ strncpy(u.un.sun_path, path, sizeof(u.un.sun_path));
+
+ fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ assert_se(fd >= 0);
+
+ assert_se(bind(fd, &u.sa, SOCKADDR_UN_LEN(u.un)) >= 0);
+ usleep(100 * USEC_PER_MSEC);
+
+ assert_se(listen(fd, SOMAXCONN) >= 0);
+ usleep(100 * USEC_PER_MSEC);
+
+ assert_se(touch(path) >= 0);
+ usleep(100 * USEC_PER_MSEC);
+
+ log_debug("Initialized server");
+
+ for (;;) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_event_unrefp) sd_event *event = NULL;
+ sd_id128_t id;
+ int bus_fd, code;
+
+ assert_se(sd_id128_randomize(&id) >= 0);
+
+ assert_se(sd_event_new(&event) >= 0);
+
+ bus_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
+ assert_se(bus_fd >= 0);
+
+ log_debug("Accepted server connection");
+
+ assert_se(sd_bus_new(&bus) >= 0);
+ assert_se(sd_bus_set_description(bus, "server") >= 0);
+ assert_se(sd_bus_set_fd(bus, bus_fd, bus_fd) >= 0);
+ assert_se(sd_bus_set_server(bus, true, id) >= 0);
+ /* assert_se(sd_bus_set_anonymous(bus, true) >= 0); */
+
+ assert_se(sd_bus_attach_event(bus, event, 0) >= 0);
+
+ assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "foo.TestInterface", vtable, NULL) >= 0);
+
+ assert_se(sd_bus_start(bus) >= 0);
+
+ assert_se(sd_event_loop(event) >= 0);
+
+ assert_se(sd_event_get_exit_code(event, &code) >= 0);
+
+ if (code > 0)
+ break;
+ }
+
+ log_debug("Server done");
+
+ return NULL;
+}
+
+static void* thread_client1(void *p) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ const char *path = p, *t;
+ int r;
+
+ log_debug("Initializing client1");
+
+ assert_se(sd_bus_new(&bus) >= 0);
+ assert_se(sd_bus_set_description(bus, "client1") >= 0);
+
+ t = strjoina("unix:path=", path);
+ assert_se(sd_bus_set_address(bus, t) >= 0);
+ assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
+ assert_se(sd_bus_start(bus) >= 0);
+
+ r = sd_bus_call_method(bus, "foo.bar", "/foo", "foo.TestInterface", "Foobar", &error, NULL, NULL);
+ assert_se(r >= 0);
+
+ log_debug("Client1 done");
+
+ return NULL;
+}
+
+static int client2_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ assert_se(sd_bus_message_is_method_error(m, NULL) == 0);
+ assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0) >= 0);
+ return 0;
+}
+
+static void* thread_client2(void *p) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_event_unrefp) sd_event *event = NULL;
+ const char *path = p, *t;
+
+ log_debug("Initializing client2");
+
+ assert_se(sd_event_new(&event) >= 0);
+ assert_se(sd_bus_new(&bus) >= 0);
+ assert_se(sd_bus_set_description(bus, "client2") >= 0);
+
+ t = strjoina("unix:path=", path);
+ assert_se(sd_bus_set_address(bus, t) >= 0);
+ assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
+ assert_se(sd_bus_attach_event(bus, event, 0) >= 0);
+ assert_se(sd_bus_start(bus) >= 0);
+
+ assert_se(sd_bus_call_method_async(bus, NULL, "foo.bar", "/foo", "foo.TestInterface", "Foobar", client2_callback, NULL, NULL) >= 0);
+
+ assert_se(sd_event_loop(event) >= 0);
+
+ log_debug("Client2 done");
+
+ return NULL;
+}
+
+static void request_exit(const char *path) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ const char *t;
+
+ assert_se(sd_bus_new(&bus) >= 0);
+
+ t = strjoina("unix:path=", path);
+ assert_se(sd_bus_set_address(bus, t) >= 0);
+ assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
+ assert_se(sd_bus_set_description(bus, "request-exit") >= 0);
+ assert_se(sd_bus_start(bus) >= 0);
+
+ assert_se(sd_bus_call_method(bus, "foo.bar", "/foo", "foo.TestInterface", "Exit", NULL, NULL, NULL) >= 0);
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
+ pthread_t server, client1, client2;
+ char *path;
+
+ log_set_max_level(LOG_DEBUG);
+
+ /* We use /dev/shm here rather than /tmp, since some weird distros might set up /tmp as some weird fs that
+ * doesn't support inotify properly. */
+ assert_se(mkdtemp_malloc("/dev/shm/systemd-watch-bind-XXXXXX", &d) >= 0);
+
+ path = strjoina(d, "/this/is/a/socket");
+
+ assert_se(pthread_create(&server, NULL, thread_server, path) == 0);
+ assert_se(pthread_create(&client1, NULL, thread_client1, path) == 0);
+ assert_se(pthread_create(&client2, NULL, thread_client2, path) == 0);
+
+ assert_se(pthread_join(client1, NULL) == 0);
+ assert_se(pthread_join(client2, NULL) == 0);
+
+ request_exit(path);
+
+ assert_se(pthread_join(server, NULL) == 0);
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index e8adaa6823..69572d1a51 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -1061,10 +1061,15 @@ _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
}
_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
+ int r;
assert_return(m, -EINVAL);
- return flush_fd(MONITOR_TO_FD(m));
+ r = flush_fd(MONITOR_TO_FD(m));
+ if (r < 0)
+ return r;
+
+ return 0;
}
_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c
index b941afb773..85ceb263a3 100644
--- a/src/libudev/libudev-queue.c
+++ b/src/libudev/libudev-queue.c
@@ -268,8 +268,16 @@ _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
* Returns: the result of clearing the watch for queue changes.
*/
_public_ int udev_queue_flush(struct udev_queue *udev_queue) {
+ int r;
+
+ assert(udev_queue);
+
if (udev_queue->fd < 0)
return -EINVAL;
- return flush_fd(udev_queue->fd);
+ r = flush_fd(udev_queue->fd);
+ if (r < 0)
+ return r;
+
+ return 0;
}
diff --git a/src/locale/localed.c b/src/locale/localed.c
index 3e3f03e046..02f5e8c656 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -652,9 +652,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
if (r < 0)
return log_error_errno(r, "Failed to register object: %m");
- r = sd_bus_request_name(bus, "org.freedesktop.locale1", 0);
+ r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.locale1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index 9fca5ce0cd..d5d086cfe0 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -288,13 +288,13 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
return 0;
r = parse_uid(p, &uid);
- }
- if (r < 0)
- return 0;
+ if (r < 0)
+ return 0;
- user = hashmap_get(m->users, UID_TO_PTR(uid));
- if (!user)
- return 0;
+ user = hashmap_get(m->users, UID_TO_PTR(uid));
+ if (!user)
+ return 0;
+ }
*found = user;
return 1;
diff --git a/src/login/logind.c b/src/login/logind.c
index 49ca367e18..cbaaa48e5a 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -658,7 +658,6 @@ static int manager_reserve_vt(Manager *m) {
}
static int manager_connect_bus(Manager *m) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(m);
@@ -696,65 +695,65 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to add user enumerator: %m");
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'",
- match_job_removed, m);
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "JobRemoved",
+ match_job_removed, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for JobRemoved: %m");
-
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='UnitRemoved',"
- "path='/org/freedesktop/systemd1'",
- match_unit_removed, m);
+ return log_error_errno(r, "Failed to request match for JobRemoved: %m");
+
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "UnitRemoved",
+ match_unit_removed, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
-
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged'",
- match_properties_changed, m);
+ return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
+
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ NULL,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ match_properties_changed, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
-
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='Reloading',"
- "path='/org/freedesktop/systemd1'",
- match_reloading, m);
+ return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
+
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Reloading",
+ match_reloading, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for Reloading: %m");
+ return log_error_errno(r, "Failed to request match for Reloading: %m");
- r = sd_bus_call_method(
+ r = sd_bus_call_method_async(
m->bus,
+ NULL,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Subscribe",
- &error,
- NULL, NULL);
- if (r < 0) {
- log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
- return r;
- }
+ NULL, NULL,
+ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable subscription: %m");
- r = sd_bus_request_name(m->bus, "org.freedesktop.login1", 0);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.login1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 246bbddeee..1c3ba33e23 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -197,7 +197,7 @@ static int export_legacy_dbus_address(
return PAM_SUCCESS;
s = mfree(s);
- if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0)
+ if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0)
goto error;
r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index c435bb9b5a..615db5afe8 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1568,9 +1568,9 @@ static int login_machine(int argc, char *argv[], void *userdata) {
"member='MachineRemoved',"
"arg0='", machine, "'");
- r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
+ r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
if (r < 0)
- return log_error_errno(r, "Failed to add machine removal match: %m");
+ return log_error_errno(r, "Failed to request machine removal match: %m");
r = sd_bus_call_method(
bus,
@@ -1643,9 +1643,9 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
"member='MachineRemoved',"
"arg0='", machine, "'");
- r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
+ r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
if (r < 0)
- return log_error_errno(r, "Failed to add machine removal match: %m");
+ return log_error_errno(r, "Failed to request machine removal match: %m");
r = sd_bus_message_new_method_call(
bus,
@@ -2087,28 +2087,27 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
&slot_job_removed,
- "type='signal',"
- "sender='org.freedesktop.import1',"
- "interface='org.freedesktop.import1.Manager',"
- "member='TransferRemoved',"
- "path='/org/freedesktop/import1'",
- match_transfer_removed, &path);
+ "org.freedesktop.import1",
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ "TransferRemoved",
+ match_transfer_removed, NULL, &path);
if (r < 0)
- return log_error_errno(r, "Failed to install match: %m");
+ return log_error_errno(r, "Failed to request match: %m");
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
&slot_log_message,
- "type='signal',"
- "sender='org.freedesktop.import1',"
- "interface='org.freedesktop.import1.Transfer',"
- "member='LogMessage'",
- match_log_message, &path);
+ "org.freedesktop.import1",
+ NULL,
+ "org.freedesktop.import1.Transfer",
+ "LogMessage",
+ match_log_message, NULL, &path);
if (r < 0)
- return log_error_errno(r, "Failed to install match: %m");
+ return log_error_errno(r, "Failed to request match: %m");
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
diff --git a/src/machine/machined.c b/src/machine/machined.c
index b5cb863e5d..34b2024043 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -186,7 +186,6 @@ int manager_enumerate_machines(Manager *m) {
}
static int manager_connect_bus(Manager *m) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(m);
@@ -216,70 +215,65 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to add image enumerator: %m");
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'",
- match_job_removed,
- m);
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "JobRemoved",
+ match_job_removed, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to add match for JobRemoved: %m");
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='UnitRemoved',"
- "path='/org/freedesktop/systemd1'",
- match_unit_removed,
- m);
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "UnitRemoved",
+ match_unit_removed, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
-
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged',"
- "arg0='org.freedesktop.systemd1.Unit'",
- match_properties_changed,
- m);
+ return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
+
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ NULL,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ match_properties_changed, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
-
- r = sd_bus_add_match(m->bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='Reloading',"
- "path='/org/freedesktop/systemd1'",
- match_reloading,
- m);
+ return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
+
+ r = sd_bus_match_signal_async(
+ m->bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Reloading",
+ match_reloading, NULL, m);
if (r < 0)
- return log_error_errno(r, "Failed to add match for Reloading: %m");
+ return log_error_errno(r, "Failed to request match for Reloading: %m");
- r = sd_bus_call_method(
+ r = sd_bus_call_method_async(
m->bus,
+ NULL,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Subscribe",
- &error,
- NULL, NULL);
- if (r < 0) {
- log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
- return r;
- }
+ NULL, NULL,
+ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable subscription: %m");
- r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.machine1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 7cf110672f..0bfe49006b 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -153,7 +153,15 @@ static void netdev_free(NetDev *netdev) {
condition_free_list(netdev->match_kernel_version);
condition_free_list(netdev->match_arch);
- if (NETDEV_VTABLE(netdev) &&
+ /* Invoke the per-kind done() destructor, but only if the state field is initialized. We conditionalize that
+ * because we parse .netdev files twice: once to determine the kind (with a short, minimal NetDev structure
+ * allocation, with no room for per-kind fields), and once to read the kind's properties (with a full,
+ * comprehensive NetDev structure allocation with enough space for whatever the specific kind needs). Now, in
+ * the first case we shouldn't try to destruct the per-kind NetDev fields on destruction, in the second case we
+ * should. We use the state field to discern the two cases: it's _NETDEV_STATE_INVALID on the first "raw"
+ * call. */
+ if (netdev->state != _NETDEV_STATE_INVALID &&
+ NETDEV_VTABLE(netdev) &&
NETDEV_VTABLE(netdev)->done)
NETDEV_VTABLE(netdev)->done(netdev);
@@ -615,8 +623,8 @@ static int netdev_load_one(Manager *manager, const char *filename) {
if (!file) {
if (errno == ENOENT)
return 0;
- else
- return -errno;
+
+ return -errno;
}
if (null_or_empty_fd(fileno(file))) {
@@ -630,7 +638,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
netdev_raw->n_ref = 1;
netdev_raw->kind = _NETDEV_KIND_INVALID;
- netdev_raw->state = _NETDEV_STATE_INVALID;
+ netdev_raw->state = _NETDEV_STATE_INVALID; /* an invalid state means done() of the implementation won't be called on destruction */
dropin_dirname = strjoina(basename(filename), ".d");
r = config_parse_many(filename, network_dirs, dropin_dirname,
@@ -669,7 +677,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
netdev->n_ref = 1;
netdev->manager = manager;
netdev->kind = netdev_raw->kind;
- netdev->state = _NETDEV_STATE_INVALID;
+ netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time, so that done() will be called on destruction */
if (NETDEV_VTABLE(netdev)->init)
NETDEV_VTABLE(netdev)->init(netdev);
diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h
index 507b86a078..7ae064ba8f 100644
--- a/src/network/netdev/netdev.h
+++ b/src/network/netdev/netdev.h
@@ -65,6 +65,7 @@ typedef enum NetDevKind {
} NetDevKind;
typedef enum NetDevState {
+ NETDEV_STATE_LOADING,
NETDEV_STATE_FAILED,
NETDEV_STATE_CREATING,
NETDEV_STATE_READY,
@@ -149,7 +150,9 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
/* For casting a netdev into the various netdev kinds */
#define DEFINE_NETDEV_CAST(UPPERCASE, MixedCase) \
static inline MixedCase* UPPERCASE(NetDev *n) { \
- if (_unlikely_(!n || n->kind != NETDEV_KIND_##UPPERCASE)) \
+ if (_unlikely_(!n || \
+ n->kind != NETDEV_KIND_##UPPERCASE) || \
+ n->state == _NETDEV_STATE_INVALID) \
return NULL; \
\
return (MixedCase*) n; \
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index e3c514c804..4733dd5177 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -82,19 +82,6 @@ static int setup_default_address_pool(Manager *m) {
return 0;
}
-static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
- Manager *m = userdata;
-
- assert(s);
- assert(m);
-
- m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
-
- manager_connect_bus(m);
-
- return 0;
-}
-
static int manager_reset_all(Manager *m) {
Link *link;
Iterator i;
@@ -116,6 +103,7 @@ static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_b
int b, r;
assert(message);
+ assert(m);
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
@@ -133,35 +121,32 @@ static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_b
return 0;
}
-int manager_connect_bus(Manager *m) {
- int r;
+static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
+ Manager *m = userdata;
+ assert(message);
assert(m);
- r = sd_bus_default_system(&m->bus);
- if (r < 0) {
- /* We failed to connect? Yuck, we must be in early
- * boot. Let's try in 5s again. */
+ /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */
+ if (m->dynamic_hostname)
+ (void) manager_set_hostname(m, m->dynamic_hostname);
+ if (m->dynamic_timezone)
+ (void) manager_set_timezone(m, m->dynamic_timezone);
- log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
+ return 0;
+}
- r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
- if (r < 0)
- return log_error_errno(r, "Failed to install bus reconnect time event: %m");
+int manager_connect_bus(Manager *m) {
+ int r;
+ assert(m);
+
+ if (m->bus)
return 0;
- }
- r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
- "type='signal',"
- "sender='org.freedesktop.login1',"
- "interface='org.freedesktop.login1.Manager',"
- "member='PrepareForSleep',"
- "path='/org/freedesktop/login1'",
- match_prepare_for_sleep,
- m);
+ r = bus_open_system_watch_bind(&m->bus);
if (r < 0)
- return log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
+ return log_error_errno(r, "Failed to connect to bus: %m");
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
if (r < 0)
@@ -183,25 +168,35 @@ int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to add network enumerator: %m");
- r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */
- if (m->dynamic_hostname) {
- r = manager_set_hostname(m, m->dynamic_hostname);
- if (r < 0)
- return r;
- }
- if (m->dynamic_timezone) {
- r = manager_set_timezone(m, m->dynamic_timezone);
- if (r < 0)
- return r;
- }
+ r = sd_bus_match_signal_async(
+ m->bus,
+ &m->connected_slot,
+ "org.freedesktop.DBus.Local",
+ NULL,
+ "org.freedesktop.DBus.Local",
+ "Connected",
+ on_connected, NULL, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to request match on Connected signal: %m");
+
+ r = sd_bus_match_signal_async(
+ m->bus,
+ &m->prepare_for_sleep_slot,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "PrepareForSleep",
+ match_prepare_for_sleep, NULL, m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
return 0;
}
@@ -1321,6 +1316,7 @@ void manager_free(Manager *m) {
sd_bus_unref(m->bus);
sd_bus_slot_unref(m->prepare_for_sleep_slot);
+ sd_bus_slot_unref(m->connected_slot);
sd_event_source_unref(m->bus_retry_event_source);
free(m->dynamic_timezone);
@@ -1595,12 +1591,12 @@ int manager_set_hostname(Manager *m, const char *hostname) {
int r;
log_debug("Setting transient hostname: '%s'", strna(hostname));
+
if (free_and_strdup(&m->dynamic_hostname, hostname) < 0)
return log_oom();
- if (!m->bus) {
- /* TODO: replace by assert when we can rely on kdbus */
- log_info("Not connected to system bus, ignoring transient hostname.");
+ if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
+ log_info("Not connected to system bus, not setting hostname.");
return 0;
}
@@ -1647,8 +1643,8 @@ int manager_set_timezone(Manager *m, const char *tz) {
if (free_and_strdup(&m->dynamic_timezone, tz) < 0)
return log_oom();
- if (!m->bus) {
- log_info("Not connected to system bus, ignoring timezone.");
+ if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
+ log_info("Not connected to system bus, not setting hostname.");
return 0;
}
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 186cb41891..1f7f306af9 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -43,6 +43,7 @@ struct Manager {
sd_event_source *bus_retry_event_source;
sd_bus *bus;
sd_bus_slot *prepare_for_sleep_slot;
+ sd_bus_slot *connected_slot;
struct udev *udev;
struct udev_monitor *udev_monitor;
sd_event_source *udev_event_source;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 383047acc7..f580b46f86 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3622,14 +3622,16 @@ static int run(int master,
* case PID 1 will send us a friendly RequestStop signal, when it is asked to terminate the
* scope. Let's hook into that, and cleanly shut down the container, and print a friendly message. */
- r = sd_bus_add_match(bus, NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Scope',"
- "member='RequestStop'",
- on_request_stop, PID_TO_PTR(*pid));
+ r = sd_bus_match_signal_async(
+ bus,
+ NULL,
+ "org.freedesktop.systemd1",
+ NULL,
+ "org.freedesktop.systemd1.Scope",
+ "RequestStop",
+ on_request_stop, NULL, PID_TO_PTR(*pid));
if (r < 0)
- return log_error_errno(r, "Failed to install request stop match: %m");
+ return log_error_errno(r, "Failed to request RequestStop match: %m");
}
if (arg_register) {
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 9157d9ea68..ffd7c4824e 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1844,18 +1844,6 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_END,
};
-static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
- Manager *m = userdata;
-
- assert(s);
- assert(m);
-
- m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
-
- manager_connect_bus(m);
- return 0;
-}
-
static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
int b, r;
@@ -1886,20 +1874,9 @@ int manager_connect_bus(Manager *m) {
if (m->bus)
return 0;
- r = sd_bus_default_system(&m->bus);
- if (r < 0) {
- /* We failed to connect? Yuck, we must be in early
- * boot. Let's try in 5s again. */
-
- log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
-
- r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
- if (r < 0)
- return log_error_errno(r, "Failed to install bus reconnect time event: %m");
-
- (void) sd_event_source_set_description(m->bus_retry_event_source, "bus-retry");
- return 0;
- }
+ r = bus_open_system_watch_bind(&m->bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
if (r < 0)
@@ -1921,24 +1898,26 @@ int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to register dnssd enumerator: %m");
- r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
+ r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.resolve1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
- "type='signal',"
- "sender='org.freedesktop.login1',"
- "interface='org.freedesktop.login1.Manager',"
- "member='PrepareForSleep',"
- "path='/org/freedesktop/login1'",
- match_prepare_for_sleep,
- m);
- if (r < 0)
- log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
+ r = sd_bus_match_signal_async(
+ m->bus,
+ &m->prepare_for_sleep_slot,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "PrepareForSleep",
+ match_prepare_for_sleep,
+ NULL,
+ m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
return 0;
}
diff --git a/src/run/run.c b/src/run/run.c
index 0ff8db6b3e..a30501169c 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -1059,7 +1059,6 @@ static int start_transient_service(
.inactive_enter_usec = USEC_INFINITY,
};
_cleanup_free_ char *path = NULL;
- const char *mt;
c.bus = sd_bus_ref(bus);
@@ -1089,18 +1088,20 @@ static int start_transient_service(
if (!path)
return log_oom();
- mt = strjoina("type='signal',"
- "sender='org.freedesktop.systemd1',"
- "path='", path, "',"
- "interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged'");
- r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c);
+ r = sd_bus_match_signal_async(
+ bus,
+ &c.match,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ on_properties_changed, NULL, &c);
if (r < 0)
- return log_error_errno(r, "Failed to add properties changed signal.");
+ return log_error_errno(r, "Failed to request properties changed signal match: %m");
r = sd_bus_attach_event(bus, c.event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
- return log_error_errno(r, "Failed to attach bus to event loop.");
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
r = run_context_update(&c, path);
if (r < 0)
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 346d8c9d24..99d6a9b143 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -316,7 +316,7 @@ int ask_password_tty(
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
- flush_fd(notify);
+ (void) flush_fd(notify);
if (pollfd[POLL_TTY].revents == 0)
continue;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index a46fa62c2c..94ee71697e 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -1730,31 +1730,25 @@ int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
/* When we are a bus client we match by sender. Direct
* connections OTOH have no initialized sender field, and
* hence we ignore the sender then */
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
&d->slot_job_removed,
- bus->bus_client ?
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'" :
- "type='signal',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'",
- match_job_removed, d);
+ bus->bus_client ? "org.freedesktop.systemd1" : NULL,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "JobRemoved",
+ match_job_removed, NULL, d);
if (r < 0)
return r;
- r = sd_bus_add_match(
+ r = sd_bus_match_signal_async(
bus,
&d->slot_disconnected,
- "type='signal',"
- "sender='org.freedesktop.DBus.Local',"
- "interface='org.freedesktop.DBus.Local',"
- "member='Disconnected'",
- match_disconnected, d);
+ "org.freedesktop.DBus.Local",
+ NULL,
+ "org.freedesktop.DBus.Local",
+ "Disconnected",
+ match_disconnected, NULL, d);
if (r < 0)
return r;
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 50731fa5ff..b6677e27f6 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -68,7 +68,7 @@ static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_
}
int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
- _cleanup_free_ char *match = NULL;
+ const char *match;
const char *unique;
int r;
@@ -85,23 +85,21 @@ int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
if (r < 0)
return r;
- r = asprintf(&match,
- "sender='org.freedesktop.DBus',"
- "type='signal',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "path='/org/freedesktop/DBus',"
- "arg0='%s',"
- "arg1='%s',"
- "arg2=''", name, unique);
- if (r < 0)
- return -ENOMEM;
-
- r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
+ match = strjoina(
+ "sender='org.freedesktop.DBus',"
+ "type='signal',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "path='/org/freedesktop/DBus',"
+ "arg0='", name, "',",
+ "arg1='", unique, "',",
+ "arg2=''");
+
+ r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
if (r < 0)
return r;
- r = sd_bus_release_name(bus, name);
+ r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
if (r < 0)
return r;
@@ -1600,3 +1598,54 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) {
return r;
}
+
+int bus_open_system_watch_bind(sd_bus **ret) {
+ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+ const char *e;
+ int r;
+
+ assert(ret);
+
+ /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
+
+ r = sd_bus_new(&bus);
+ if (r < 0)
+ return r;
+
+ e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
+ if (!e)
+ e = DEFAULT_SYSTEM_BUS_ADDRESS;
+
+ r = sd_bus_set_address(bus, e);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_set_bus_client(bus, true);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_set_trusted(bus, true);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_set_watch_bind(bus, true);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_set_connected_signal(bus, true);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_start(bus);
+ if (r < 0)
+ return r;
+
+ *ret = bus;
+ bus = NULL;
+
+ return 0;
+}
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index a9f4969d7d..cbd22a6cd6 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -162,3 +162,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send
int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
int bus_track_add_name_many(sd_bus_track *t, char **l);
+
+int bus_open_system_watch_bind(sd_bus **ret);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 1376497f8d..906eb1879a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2905,7 +2905,6 @@ static int start_unit_one(
if (wait_context) {
_cleanup_free_ char *unit_path = NULL;
- const char* mt;
log_debug("Watching for property changes of %s", name);
r = sd_bus_call_method(
@@ -2928,13 +2927,15 @@ static int start_unit_one(
if (r < 0)
return log_error_errno(r, "Failed to add unit path %s to set: %m", unit_path);
- mt = strjoina("type='signal',"
- "interface='org.freedesktop.DBus.Properties',"
- "path='", unit_path, "',"
- "member='PropertiesChanged'");
- r = sd_bus_add_match(bus, &wait_context->match, mt, on_properties_changed, wait_context);
+ r = sd_bus_match_signal_async(bus,
+ &wait_context->match,
+ NULL,
+ unit_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ on_properties_changed, NULL, wait_context);
if (r < 0)
- return log_error_errno(r, "Failed to add match for PropertiesChanged signal: %m");
+ return log_error_errno(r, "Failed to request match for PropertiesChanged signal: %m");
}
log_debug("%s manager for %s on %s, %s",
@@ -3150,22 +3151,21 @@ static int start_unit(int argc, char *argv[], void *userdata) {
}
if (arg_wait) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
wait_context.unit_paths = set_new(&string_hash_ops);
if (!wait_context.unit_paths)
return log_oom();
- r = sd_bus_call_method(
+ r = sd_bus_call_method_async(
bus,
+ NULL,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Subscribe",
- &error,
- NULL, NULL);
+ NULL, NULL,
+ NULL);
if (r < 0)
- return log_error_errno(r, "Failed to enable subscription: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to enable subscription: %m");
r = sd_event_default(&wait_context.event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index c5c7096d55..c30ac9e6ec 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -150,8 +150,14 @@ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b);
int sd_bus_get_allow_interactive_authorization(sd_bus *bus);
int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b);
int sd_bus_get_exit_on_disconnect(sd_bus *bus);
+int sd_bus_set_watch_bind(sd_bus *bus, int b);
+int sd_bus_get_watch_bind(sd_bus *bus);
+int sd_bus_set_connected_signal(sd_bus *bus, int b);
+int sd_bus_get_connected_signal(sd_bus *bus);
+int sd_bus_set_sender(sd_bus *bus, const char *sender);
+int sd_bus_get_sender(sd_bus *bus, const char **ret);
-int sd_bus_start(sd_bus *ret);
+int sd_bus_start(sd_bus *bus);
int sd_bus_try_close(sd_bus *bus);
void sd_bus_close(sd_bus *bus);
@@ -163,6 +169,7 @@ sd_bus *sd_bus_flush_close_unref(sd_bus *bus);
void sd_bus_default_flush_close(void);
int sd_bus_is_open(sd_bus *bus);
+int sd_bus_is_ready(sd_bus *bus);
int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id);
int sd_bus_get_scope(sd_bus *bus, const char **scope);
@@ -193,6 +200,7 @@ sd_event *sd_bus_get_event(sd_bus *bus);
int sd_bus_add_filter(sd_bus *bus, sd_bus_slot **slot, sd_bus_message_handler_t callback, void *userdata);
int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_match_async(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata);
int sd_bus_add_object(sd_bus *bus, sd_bus_slot **slot, const char *path, sd_bus_message_handler_t callback, void *userdata);
int sd_bus_add_fallback(sd_bus *bus, sd_bus_slot **slot, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
@@ -267,6 +275,7 @@ int sd_bus_message_set_auto_start(sd_bus_message *m, int b);
int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *m, int b);
int sd_bus_message_set_destination(sd_bus_message *m, const char *destination);
+int sd_bus_message_set_sender(sd_bus_message *m, const char *sender);
int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority);
int sd_bus_message_append(sd_bus_message *m, const char *types, ...);
@@ -300,7 +309,9 @@ int sd_bus_message_rewind(sd_bus_message *m, int complete);
int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags);
+int sd_bus_request_name_async(sd_bus *bus, sd_bus_slot **ret_slot, const char *name, uint64_t flags, sd_bus_message_handler_t callback, void *userdata);
int sd_bus_release_name(sd_bus *bus, const char *name);
+int sd_bus_release_name_async(sd_bus *bus, sd_bus_slot **ret_slot, const char *name, sd_bus_message_handler_t callback, void *userdata);
int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable); /* free the results */
int sd_bus_get_name_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds); /* unref the result! */
int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine);
@@ -336,6 +347,9 @@ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *in
int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
int sd_bus_query_sender_privilege(sd_bus_message *call, int capability);
+int sd_bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t match_callback, sd_bus_message_handler_t add_callback, void *userdata);
+
/* Credential handling */
int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t creds_mask);
diff --git a/src/test/meson.build b/src/test/meson.build
index 71b440637d..18e957ddc8 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -762,6 +762,10 @@ tests += [
[],
[threads]],
+ [['src/libsystemd/sd-bus/test-bus-watch-bind.c'],
+ [],
+ [threads], '', 'timeout=120'],
+
[['src/libsystemd/sd-bus/test-bus-chat.c'],
[],
[threads]],
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 8323a66ad3..ad64a2bb36 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -29,8 +29,8 @@
#include "apparmor-util.h"
#include "architecture.h"
#include "audit-util.h"
-#include "condition.h"
#include "cgroup-util.h"
+#include "condition.h"
#include "hostname-util.h"
#include "id128-util.h"
#include "ima-util.h"
@@ -187,12 +187,12 @@ static int test_condition_test_control_group_controller(void) {
/* Multiple valid controllers at the same time */
assert_se(cg_mask_to_string(system_mask, &controller_name) >= 0);
- condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, controller_name, false, false);
+ condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, false);
assert_se(condition);
assert_se(condition_test(condition));
condition_free(condition);
- condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, controller_name, false, true);
+ condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, true);
assert_se(condition);
assert_se(!condition_test(condition));
condition_free(condition);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 86d963c4c7..2ad9e71856 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -388,6 +388,92 @@ static void test_access_fd(void) {
}
}
+static void test_touch_file(void) {
+ uid_t test_uid, test_gid;
+ _cleanup_(rm_rf_physical_and_freep) char *p = NULL;
+ struct stat st;
+ const char *a;
+ usec_t test_mtime;
+
+ test_uid = geteuid() == 0 ? 65534 : getuid();
+ test_gid = geteuid() == 0 ? 65534 : getgid();
+
+ test_mtime = usec_sub_unsigned(now(CLOCK_REALTIME), USEC_PER_WEEK);
+
+ assert_se(mkdtemp_malloc("/dev/shm/touch-file-XXXXXX", &p) >= 0);
+
+ a = strjoina(p, "/regular");
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISREG(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+
+ a = strjoina(p, "/dir");
+ assert_se(mkdir(a, 0775) >= 0);
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISDIR(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+
+ a = strjoina(p, "/fifo");
+ assert_se(mkfifo(a, 0775) >= 0);
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISFIFO(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+
+ a = strjoina(p, "/sock");
+ assert_se(mknod(a, 0775 | S_IFSOCK, 0) >= 0);
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISSOCK(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+
+ if (geteuid() == 0) {
+ a = strjoina(p, "/cdev");
+ assert_se(mknod(a, 0775 | S_IFCHR, makedev(0, 0)) >= 0);
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISCHR(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+
+ a = strjoina(p, "/bdev");
+ assert_se(mknod(a, 0775 | S_IFBLK, makedev(0, 0)) >= 0);
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISBLK(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+ }
+
+ a = strjoina(p, "/lnk");
+ assert_se(symlink("target", a) >= 0);
+ assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
+ assert_se(lstat(a, &st) >= 0);
+ assert_se(st.st_uid == test_uid);
+ assert_se(st.st_gid == test_gid);
+ assert_se(S_ISLNK(st.st_mode));
+ assert_se((st.st_mode & 0777) == 0640);
+ assert_se(timespec_load(&st.st_mtim) == test_mtime);
+}
+
int main(int argc, char *argv[]) {
test_unlink_noerrno();
test_get_files_in_directory();
@@ -396,6 +482,7 @@ int main(int argc, char *argv[]) {
test_chase_symlinks();
test_dot_or_dot_dot();
test_access_fd();
+ test_touch_file();
return 0;
}
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index a55a929a49..822835cce9 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -675,9 +675,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
if (r < 0)
return log_error_errno(r, "Failed to register object: %m");
- r = sd_bus_request_name(bus, "org.freedesktop.timedate1", 0);
+ r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.timedate1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 6e9c10aeb0..d2648ead93 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -159,7 +159,7 @@ static int ask_password_plymouth(
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
- flush_fd(notify);
+ (void) flush_fd(notify);
if (pollfd[POLL_SOCKET].revents == 0)
continue;
diff --git a/tools/meson-check-api-docs.sh b/tools/meson-check-api-docs.sh
new file mode 100644
index 0000000000..5bc808c1e4
--- /dev/null
+++ b/tools/meson-check-api-docs.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -eu
+
+for symbol in `nm -g --defined-only "$@" | grep " T " | cut -d" " -f3 | sort -u` ; do
+ if test -f ${MESON_BUILD_ROOT}/man/$symbol.3 ; then
+ echo "✓ Symbol $symbol() is documented."
+ else
+ printf " \x1b[1;31mSymbol $symbol() lacks documentation.\x1b[0m\n"
+ fi
+done