Merge pull request #7714 from poettering/sd-bus-watch-connect

many sd-bus improvements
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-01-05 19:46:38 +01:00 committed by GitHub
commit 2df4611205
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 3128 additions and 1066 deletions

7
TODO
View file

@ -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?

View file

@ -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" />

View file

@ -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', [], ''],

View file

@ -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>

View file

@ -45,14 +45,24 @@
<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>
<funcsynopsis>
<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>
@ -63,65 +73,122 @@
</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>
<paramdef>sd_bus_error *<parameter>ret_error</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>
</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>
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. 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>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>
<refsect1>
<title>Return Value</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.
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>Notes</title>
<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>
<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</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>

137
man/sd_bus_is_open.xml Normal file
View file

@ -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>

View file

@ -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>

View file

@ -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>
@ -61,71 +63,103 @@
<paramdef>uint64_t <parameter>flags</parameter></paramdef>
</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>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>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>

View file

@ -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>

136
man/sd_bus_set_sender.xml Normal file
View file

@ -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>

View file

@ -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>

View file

@ -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()),

View file

@ -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, \

View file

@ -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);
/* 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 (parents)
mkdir_parents(path, 0755);
(void) 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;
/* 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 (mode != MODE_INVALID) {
r = fchmod(fd, mode);
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;
}
if (uid != UID_INVALID || gid != GID_INVALID) {
r = fchown(fd, uid, gid);
if (r < 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) {

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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 {

View file

@ -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;
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.
/* 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) {

View file

@ -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 {

View file

@ -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");

View file

@ -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)

View file

@ -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) {

View file

@ -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)

View file

@ -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)

View file

@ -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;

View file

@ -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)
return -ESRCH;
if (ret == BUS_NAME_NOT_OWNER)
return -EADDRINUSE;
if (ret == BUS_NAME_RELEASED)
return 0;
return -EINVAL;
switch (ret) {
case BUS_NAME_NON_EXISTENT:
return -ESRCH;
case BUS_NAME_NOT_OWNER:
return -EADDRINUSE;
case BUS_NAME_RELEASED:
return 0;
}
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);
r = validate_release_name_parameters(bus, name);
if (r < 0)
return r;
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);
}
_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;
/* 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_release_name_dbus1(bus, name);
}
static int bus_list_names_dbus1(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;
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,40 +836,31 @@ 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);
static int bus_remove_match_internal_dbus1(
sd_bus *bus,
const char *match) {
const char *e;
assert(bus);
assert(match);
e = internal_match(bus, match);
return sd_bus_call_method(
return sd_bus_call_method_async(
bus,
ret_slot,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"RemoveMatch",
NULL,
NULL,
"AddMatch",
callback,
userdata,
"s",
e);
}
@ -699,12 +869,29 @@ int bus_remove_match_internal(
sd_bus *bus,
const char *match) {
const char *e;
assert(bus);
assert(match);
if (!bus->bus_client)
return -EINVAL;
return bus_remove_match_internal_dbus1(bus, match);
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",
"RemoveMatch",
NULL,
NULL,
"s",
e);
}
_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
};

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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)

View file

@ -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;

View file

@ -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);
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);
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);
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);
if (r < 0)
return log_error_errno(r, "Failed to add match for Reloading: %m");
r = sd_bus_call_method(
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 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 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 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 request match for Reloading: %m");
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;
}
r = sd_bus_request_name(m->bus, "org.freedesktop.login1", 0);
NULL, NULL,
NULL);
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
return log_error_errno(r, "Failed to enable subscription: %m");
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 request name: %m");
r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)

View file

@ -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);

View file

@ -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) {

View file

@ -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);
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);
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);
if (r < 0)
return log_error_errno(r, "Failed to add match for Reloading: %m");
r = sd_bus_call_method(
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 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 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 request match for Reloading: %m");
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;
}
r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
NULL, NULL,
NULL);
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
return log_error_errno(r, "Failed to enable subscription: %m");
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 request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)

View file

@ -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);

View file

@ -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; \

View file

@ -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;
}
static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
assert(message);
assert(m);
/* 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);
return 0;
}
int manager_connect_bus(Manager *m) {
int r;
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. */
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");
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;
}

View file

@ -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;

View file

@ -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) {

View file

@ -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);
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_error_errno(r, "Failed to add match for PrepareForSleep: %m");
log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
return 0;
}

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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;
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(bus, NULL, match, name_owner_change_callback, e);
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;
}

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -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]],

View file

@ -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);

View file

@ -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;
}

View file

@ -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)

View file

@ -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;

View file

@ -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