Merge pull request #3984 from poettering/refcnt
permit bus clients to pin units to avoid automatic GC
This commit is contained in:
commit
6afe14ff5b
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -152,6 +152,7 @@
|
|||
/test-bus-policy
|
||||
/test-bus-server
|
||||
/test-bus-signature
|
||||
/test-bus-track
|
||||
/test-bus-zero-copy
|
||||
/test-calendarspec
|
||||
/test-cap-list
|
||||
|
|
|
@ -52,6 +52,8 @@ MANPAGES += \
|
|||
man/sd_bus_path_encode.3 \
|
||||
man/sd_bus_process.3 \
|
||||
man/sd_bus_request_name.3 \
|
||||
man/sd_bus_track_add_name.3 \
|
||||
man/sd_bus_track_new.3 \
|
||||
man/sd_event_add_child.3 \
|
||||
man/sd_event_add_defer.3 \
|
||||
man/sd_event_add_io.3 \
|
||||
|
@ -332,6 +334,23 @@ MANPAGES_ALIAS += \
|
|||
man/sd_bus_path_encode_many.3 \
|
||||
man/sd_bus_ref.3 \
|
||||
man/sd_bus_release_name.3 \
|
||||
man/sd_bus_track_add_sender.3 \
|
||||
man/sd_bus_track_contains.3 \
|
||||
man/sd_bus_track_count.3 \
|
||||
man/sd_bus_track_count_name.3 \
|
||||
man/sd_bus_track_count_sender.3 \
|
||||
man/sd_bus_track_first.3 \
|
||||
man/sd_bus_track_get_bus.3 \
|
||||
man/sd_bus_track_get_recursive.3 \
|
||||
man/sd_bus_track_get_userdata.3 \
|
||||
man/sd_bus_track_next.3 \
|
||||
man/sd_bus_track_ref.3 \
|
||||
man/sd_bus_track_remove_name.3 \
|
||||
man/sd_bus_track_remove_sender.3 \
|
||||
man/sd_bus_track_set_recursive.3 \
|
||||
man/sd_bus_track_set_userdata.3 \
|
||||
man/sd_bus_track_unref.3 \
|
||||
man/sd_bus_track_unrefp.3 \
|
||||
man/sd_bus_unref.3 \
|
||||
man/sd_bus_unrefp.3 \
|
||||
man/sd_event.3 \
|
||||
|
@ -665,6 +684,23 @@ man/sd_bus_path_decode_many.3: man/sd_bus_path_encode.3
|
|||
man/sd_bus_path_encode_many.3: man/sd_bus_path_encode.3
|
||||
man/sd_bus_ref.3: man/sd_bus_new.3
|
||||
man/sd_bus_release_name.3: man/sd_bus_request_name.3
|
||||
man/sd_bus_track_add_sender.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_contains.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_count.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_count_name.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_count_sender.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_first.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_get_bus.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_get_recursive.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_get_userdata.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_next.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_ref.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_remove_name.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_remove_sender.3: man/sd_bus_track_add_name.3
|
||||
man/sd_bus_track_set_recursive.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_set_userdata.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_unref.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_track_unrefp.3: man/sd_bus_track_new.3
|
||||
man/sd_bus_unref.3: man/sd_bus_new.3
|
||||
man/sd_bus_unrefp.3: man/sd_bus_new.3
|
||||
man/sd_event.3: man/sd_event_new.3
|
||||
|
@ -1300,6 +1336,57 @@ man/sd_bus_ref.html: man/sd_bus_new.html
|
|||
man/sd_bus_release_name.html: man/sd_bus_request_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_add_sender.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_contains.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_count.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_count_name.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_count_sender.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_first.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_get_bus.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_get_recursive.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_get_userdata.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_next.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_ref.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_remove_name.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_remove_sender.html: man/sd_bus_track_add_name.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_set_recursive.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_set_userdata.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_unref.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_track_unrefp.html: man/sd_bus_track_new.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_bus_unref.html: man/sd_bus_new.html
|
||||
$(html-alias)
|
||||
|
||||
|
@ -2559,6 +2646,8 @@ EXTRA_DIST += \
|
|||
man/sd_bus_path_encode.xml \
|
||||
man/sd_bus_process.xml \
|
||||
man/sd_bus_request_name.xml \
|
||||
man/sd_bus_track_add_name.xml \
|
||||
man/sd_bus_track_new.xml \
|
||||
man/sd_event_add_child.xml \
|
||||
man/sd_event_add_defer.xml \
|
||||
man/sd_event_add_io.xml \
|
||||
|
|
11
Makefile.am
11
Makefile.am
|
@ -3323,6 +3323,7 @@ tests += \
|
|||
test-bus-error \
|
||||
test-bus-creds \
|
||||
test-bus-gvariant \
|
||||
test-bus-track \
|
||||
test-event \
|
||||
test-netlink \
|
||||
test-local-addresses \
|
||||
|
@ -3366,6 +3367,16 @@ test_bus_cleanup_CFLAGS = \
|
|||
test_bus_cleanup_LDADD = \
|
||||
libsystemd-shared.la
|
||||
|
||||
test_bus_track_SOURCES = \
|
||||
src/libsystemd/sd-bus/test-bus-track.c
|
||||
|
||||
test_bus_track_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(SECCOMP_CFLAGS)
|
||||
|
||||
test_bus_track_LDADD = \
|
||||
libsystemd-shared.la
|
||||
|
||||
test_bus_server_SOURCES = \
|
||||
src/libsystemd/sd-bus/test-bus-server.c
|
||||
|
||||
|
|
21
TODO
21
TODO
|
@ -33,7 +33,13 @@ Janitorial Clean-ups:
|
|||
|
||||
Features:
|
||||
|
||||
* RemoveIPC= in unit files for removing POSIX/SysV IPC objects
|
||||
* introduce an "invocation ID" for units, that is randomly generated, and
|
||||
identifies each runtime-cycle of a unit. It should be set freshly each time
|
||||
we traverse inactive → activating/active, and should be the primary key to
|
||||
map offline data (stored in the journal) with online bus objects. Let's pass
|
||||
this as $SYSTEMD_INVOCATION_ID to services, as well as set this as xattr on
|
||||
the cgroup of a services. The former is accessible without privileges, the
|
||||
latter ensures the ID cannot be faked.
|
||||
|
||||
* Introduce ProtectSystem=strict for making the entire OS hierarchy read-only
|
||||
except for a select few
|
||||
|
@ -58,6 +64,8 @@ Features:
|
|||
|
||||
* ProtectControlGroups= which mounts all of /sys/fs/cgroup read-only
|
||||
|
||||
* ProtectKernelTunables= which mounts /sys and /proc/sys read-only
|
||||
|
||||
* RemoveKeyRing= to remove all keyring entries of the specified user
|
||||
|
||||
* Add DataDirectory=, CacheDirectory= and LogDirectory= to match
|
||||
|
@ -76,6 +84,9 @@ Features:
|
|||
|
||||
* journalctl: make sure -f ends when the container indicated by -M terminates
|
||||
|
||||
* mount: automatically search for "main" partition of an image has multiple
|
||||
partitions
|
||||
|
||||
* expose the "privileged" flag of ExecCommand on the bus, and open it up to
|
||||
transient units
|
||||
|
||||
|
@ -86,6 +97,12 @@ Features:
|
|||
|
||||
* allow attaching additional journald log fields to cgroups
|
||||
|
||||
* add bus API for creating unit files in /etc, reusing the code for transient units
|
||||
|
||||
* add bus API to remove unit files from /etc
|
||||
|
||||
* add bus API to retrieve current unit file contents (i.e. implement "systemctl cat" on the bus only)
|
||||
|
||||
* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
|
||||
kernel doesn't support linkat() that replaces existing files, currently)
|
||||
|
||||
|
@ -112,8 +129,6 @@ Features:
|
|||
|
||||
* add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction
|
||||
|
||||
* Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC?
|
||||
|
||||
* PID1: find a way how we can reload unit file configuration for
|
||||
specific units only, without reloading the whole of systemd
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
<refnamediv>
|
||||
<refname>sd-bus</refname>
|
||||
<refpurpose>A lightweight D-Bus and kdbus client library</refpurpose>
|
||||
<refpurpose>A lightweight D-Bus IPC client library</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
|
@ -61,49 +61,40 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>sd-bus.h</filename> provides an implementation
|
||||
of a D-Bus client. It can interoperate both with the traditional
|
||||
<citerefentry project='man-pages'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
and with kdbus. See
|
||||
<para><filename>sd-bus.h</filename> provides an implementation of a D-Bus IPC client. See
|
||||
<ulink url="http://www.freedesktop.org/software/dbus/" />
|
||||
for more information about the big picture.
|
||||
for more information about D-Bus IPC.
|
||||
</para>
|
||||
|
||||
<important>
|
||||
<para>Interfaces described here have not been declared stable yet,
|
||||
and are not accessible from <filename>libsystemd.so</filename>.
|
||||
This documentation is provided in hope it might be useful for
|
||||
developers, without any guarantees of availability or stability.
|
||||
</para>
|
||||
</important>
|
||||
|
||||
<para>See
|
||||
<citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_creds_get_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_append_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_append_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_append_string_memfd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_append_strv</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_can_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_get_cookie</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_message_get_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_negotiate_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_path_encode</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_set_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>sd_bus_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_creds_get_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_negotiate_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_path_encode</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_set_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_track_add_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_bus_track_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
for more information about the functions available.</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -114,9 +105,9 @@
|
|||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>busctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<ulink url="https://developer.gnome.org/gio/stable/gdbus.html">gdbus</ulink>
|
||||
<citerefentry project='man-pages'><refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -66,12 +66,12 @@
|
|||
|
||||
<funcprototype>
|
||||
<funcdef>uint64_t <function>sd_bus_creds_get_mask</function></funcdef>
|
||||
<paramdef>const sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>uint64_t <function>sd_bus_creds_get_augmented_mask</function></funcdef>
|
||||
<paramdef>const sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
|
|
261
man/sd_bus_track_add_name.xml
Normal file
261
man/sd_bus_track_add_name.xml
Normal file
|
@ -0,0 +1,261 @@
|
|||
<?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">
|
||||
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 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_track_add_name">
|
||||
|
||||
<refentryinfo>
|
||||
<title>sd_bus_track_add_name</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_track_add_name</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>sd_bus_track_add_name</refname>
|
||||
<refname>sd_bus_track_add_sender</refname>
|
||||
<refname>sd_bus_track_remove_name</refname>
|
||||
<refname>sd_bus_track_remove_sender</refname>
|
||||
<refname>sd_bus_track_count</refname>
|
||||
<refname>sd_bus_track_count_sender</refname>
|
||||
<refname>sd_bus_track_count_name</refname>
|
||||
<refname>sd_bus_track_contains</refname>
|
||||
<refname>sd_bus_track_first</refname>
|
||||
<refname>sd_bus_track_next</refname>
|
||||
|
||||
<refpurpose>Add, remove and retrieve bus peers tracked in a bus peer tracking object</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_add_name</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>const char* <parameter>name</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_add_sender</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>sd_bus_message* <parameter>message</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_remove_name</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>const char* <parameter>name</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_remove_sender</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>sd_bus_message* <parameter>message</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>unsigned <function>sd_bus_track_count</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_count_name</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>const char* <parameter>name</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_count_sender</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>sd_bus_message* <parameter>message</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_contains</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
<paramdef>const char* <parameter>name</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>const char* <function>sd_bus_track_first</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>const char* <function>sd_bus_track_next</function></funcdef>
|
||||
<paramdef>sd_bus_track* <parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_bus_track_add_name()</function> adds a peer to track to a bus peer tracking object. The first
|
||||
argument should refer to a bus peer tracking object created with
|
||||
<citerefentry><refentrytitle>sd_bus_track_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, the second
|
||||
name should refer to a D-Bus peer name to track, either in unique or well-known service format. If the name is not
|
||||
tracked yet it will be added to the list of names to track. If it already is being tracked and non-recursive mode
|
||||
is enabled, no operation is executed by this call. If recursive mode is enabled a per-name counter is increased by
|
||||
one each time this call is invoked, and <function>sd_bus_track_remove_name()</function> has to be called as many
|
||||
times as <function>sd_bus_track_add_name()</function> was invoked before in order to stop tracking of the name. Use
|
||||
<citerefentry><refentrytitle>sd_bus_track_set_recursive</refentrytitle><manvolnum>3</manvolnum></citerefentry> to
|
||||
switch from the default non-recursive mode to recursive mode, or back. Note that the specified name is tracked as
|
||||
it is, well-known names are not resolved to unique names by this call. Note that multiple bus peer tracking objects
|
||||
may track the same name.</para>
|
||||
|
||||
<para><function>sd_bus_track_remove_name()</function> undoes the effect of
|
||||
<function>sd_bus_track_add_name()</function> and removes a bus peer name from the list of peers to watch. Depending
|
||||
on whether non-recursive or recursive mode is enabled for the bus peer tracking object this call will either remove
|
||||
the name fully from the tracking object, or will simply decrement the per-name counter by one, removing the name
|
||||
only when the counter reaches zero (see above). Note that a bus peer disconnecting from the bus will implicitly
|
||||
remove its names fully from the bus peer tracking object, regardless of the current per-name counter.</para>
|
||||
|
||||
<para><function>sd_bus_track_add_sender()</function> and <function>sd_bus_track_remove_sender()</function> are
|
||||
similar to <function>sd_bus_track_add_name()</function> and <function>sd_bus_track_remove_name()</function> but
|
||||
take a bus message as argument. The sender of this bus message is determined and added to/removed from the bus peer
|
||||
tracking object. As messages always originate from unique names, and never from well-known names this means that
|
||||
this call will effectively only add unique names to the bus peer tracking object.</para>
|
||||
|
||||
<para><function>sd_bus_track_count()</function> returns the number of names currently being tracked by the
|
||||
specified bus peer tracking object. Note that this function always returns the actual number of names tracked, and
|
||||
hence if <function>sd_bus_track_add_name()</function> has been invoked multiple times for the same name it is only
|
||||
counted as one, regardless if recursive mode is used or not.</para>
|
||||
|
||||
<para><function>sd_bus_track_count_name()</function> returns the current per-name counter for the specified
|
||||
name. If non-recursive mode is used this returns either 1 or 0, depending on whether the specified name has been
|
||||
added to the tracking object before, or not. If recursive mode has been enabled, values larger than 1 may be
|
||||
returned too, in case <function>sd_bus_track_add_name()</function> has been called multiple times for the same
|
||||
name.</para>
|
||||
|
||||
<para><function>sd_bus_track_count_sender()</function> is similar to
|
||||
<function>sd_bus_track_count_name()</function>, but takes a bus message object and returns the per-name counter
|
||||
matching the sender of the message.</para>
|
||||
|
||||
<para><function>sd_bus_track_contains()</function> may be used to determine whether the specified name has been
|
||||
added at least once to the specified bus peer tracking object.</para>
|
||||
|
||||
<para><function>sd_bus_track_first()</function> and <function>sd_bus_track_next()</function> may be used to
|
||||
enumerate all names currently being tracked by the passed bus peer tracking
|
||||
object. <function>sd_bus_track_first()</function> returns the first entry in the object, and resets an internally
|
||||
maintained read index. Each subsequent invocation of <function>sd_bus_track_next()</function> returns the next name
|
||||
contained in the bus object. If the end is reached <constant>NULL</constant> is returned. If no names have been
|
||||
added to the object yet <function>sd_bus_track_first()</function> will return <constant>NULL</constant>
|
||||
immediately. The order in which names are returned is undefined; in particular which name is considered the first
|
||||
returned is not defined. If recursive mode is enabled and the same name has been added multiple times to the bus
|
||||
peer tracking object it is only returned once by this enumeration. If new names are added to or existing names
|
||||
removed from the bus peer tracking object while it is being enumerated the enumeration ends on the next invocation
|
||||
of <function>sd_bus_track_next()</function> as <constant>NULL</constant> is returned.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>On success, <function>sd_bus_track_add_name()</function> and <function>sd_bus_track_add_sender()</function>
|
||||
return 0 if the specified name has already been added to the bus peer tracking object before and positive if it
|
||||
hasn't. On failure, they return a negative errno-style error code.</para>
|
||||
|
||||
<para><function>sd_bus_track_remove_name()</function> and <function>sd_bus_track_remove_sender()</function> return
|
||||
positive if the specified name was previously tracked by the bus peer tracking object and has now been removed. In
|
||||
non-recursive mode, 0 is returned if the specified name was not being tracked yet. In recursive mode
|
||||
<constant>-EUNATCH</constant> is returned in this case. On failure, they return a negative errno-style error
|
||||
code.</para>
|
||||
|
||||
<para><function>sd_bus_track_count()</function> returns the number of names currently being tracked, or 0 on
|
||||
failure.</para>
|
||||
|
||||
<para><function>sd_bus_track_count_name()</function> and <function>sd_bus_track_count_sender()</function> return
|
||||
the current per-name counter for the specified name or the sender of the specified message. Zero is returned for
|
||||
names that are not being tracked yet, a positive value for names added at least once. Larger values than 1 are only
|
||||
returned in recursive mode. On failure, a negative errno-style error code is returned.</para>
|
||||
|
||||
<para><function>sd_bus_track_contains()</function> returns the passed name if it exists in the bus peer tracking
|
||||
object. On failure, and if the name has not been added yet <constant>NULL</constant> is returned.</para>
|
||||
|
||||
<para><function>sd_bus_track_first()</function> and <function>sd_bus_track_next()</function> return the first/next
|
||||
name contained in the bus peer tracking object, and <constant>NULL</constant> if the end of the enumeration is
|
||||
reached and on error.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Errors</title>
|
||||
|
||||
<para>Returned errors may indicate the following problems:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EUNATCH</constant></term>
|
||||
|
||||
<listitem><para><function>sd_bus_track_remove_name()</function> or
|
||||
<function>sd_bus_track_remove_sender()</function> have been invoked for a name not previously added to the bus
|
||||
peer object.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EINVAL</constant></term>
|
||||
|
||||
<listitem><para>Specified parameter is invalid.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-ENOMEM</constant></term>
|
||||
|
||||
<listitem><para>Memory allocation failed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para><function>sd_bus_track_add_name()</function> and the other calls 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_track_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
263
man/sd_bus_track_new.xml
Normal file
263
man/sd_bus_track_new.xml
Normal file
|
@ -0,0 +1,263 @@
|
|||
<?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">
|
||||
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 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_track_new">
|
||||
|
||||
<refentryinfo>
|
||||
<title>sd_bus_track_new</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_track_new</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>sd_bus_track_new</refname>
|
||||
<refname>sd_bus_track_ref</refname>
|
||||
<refname>sd_bus_track_unref</refname>
|
||||
<refname>sd_bus_track_unrefp</refname>
|
||||
<refname>sd_bus_track_set_recursive</refname>
|
||||
<refname>sd_bus_track_get_recursive</refname>
|
||||
<refname>sd_bus_track_get_bus</refname>
|
||||
<refname>sd_bus_track_get_userdata</refname>
|
||||
<refname>sd_bus_track_set_userdata</refname>
|
||||
|
||||
<refpurpose>Track bus peers</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_new</function></funcdef>
|
||||
<paramdef>sd_bus* <parameter>bus</parameter></paramdef>
|
||||
<paramdef>sd_bus_track** <parameter>ret</parameter></paramdef>
|
||||
<paramdef>sd_bus_track_handler_t <parameter>handler</parameter></paramdef>
|
||||
<paramdef>void* <parameter>userdata</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>sd_bus_track *<function>sd_bus_track_ref</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>sd_bus_track *<function>sd_bus_track_unref</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>void <function>sd_bus_track_unrefp</function></funcdef>
|
||||
<paramdef>sd_bus_track **<parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_get_recursive</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_track_set_recursive</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
<paramdef>int <parameter>b</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>sd_bus* <function>sd_bus_track_get_bus</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>void* <function>sd_bus_track_get_userdata</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>void* <function>sd_bus_track_set_userdata</function></funcdef>
|
||||
<paramdef>sd_bus_track *<parameter>t</parameter></paramdef>
|
||||
<paramdef>void *userdata</paramdef>
|
||||
</funcprototype>
|
||||
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_bus_track_new()</function> creates a new bus peer tracking object. The object is allocated for
|
||||
the specified bus, and returned in the <parameter>*ret</parameter> parameter. After use, the object should be freed
|
||||
again by dropping the acquired reference with <function>sd_bus_track_unref()</function> (see below). A bus peer
|
||||
tracking object may be used to keep track of peers on a specific IPC bus, for cases where peers are making use of
|
||||
one or more local objects, in order to control the lifecycle of the local objects and ensure they stay around as
|
||||
long as the peers needing them are around, and unreferenced (and possibly destroyed) as soon as all relevant peers
|
||||
have vanished. Each bus peer tracking object may be used to track zero, one or more peers add a time. References to
|
||||
specific bus peers are added via
|
||||
<citerefentry><refentrytitle>sd_bus_track_add_name</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
|
||||
<function>sd_bus_track_add_sender()</function>. They may be dropped again via
|
||||
<function>sd_bus_track_remove_name()</function> and
|
||||
<function>sd_bus_track_remove_sender()</function>. Alternatively, references on peers are removed automatically
|
||||
when they disconnect from the bus. If non-NULL the <parameter>handler</parameter> may specify a function that is
|
||||
invoked whenever the last reference is dropped, regardless whether the reference is dropped explicitly via
|
||||
<function>sd_bus_track_remove_name()</function> or implicitly because the peer disconnected from the bus. The final
|
||||
argument <parameter>userdata</parameter> may be used to attach a generic user data pointer to the object. This
|
||||
pointer is passed to the handler callback when it is invoked.</para>
|
||||
|
||||
<para><function>sd_bus_track_ref()</function> creates a new reference to a bus peer tracking object. This object
|
||||
will not be destroyed until <function>sd_bus_track_unref()</function> has been called as many times plus once
|
||||
more. Once the reference count has dropped to zero, the specified object cannot be used anymore, further calls to
|
||||
<function>sd_bus_track_ref()</function> or <function>sd_bus_track_unref()</function> on the same object are
|
||||
illegal.</para>
|
||||
|
||||
<para><function>sd_bus_track_unref()</function> destroys a reference to a bus peer tracking object.</para>
|
||||
|
||||
<para><function>sd_bus_track_unrefp()</function> is similar to <function>sd_bus_track_unref()</function> but takes
|
||||
a pointer to a pointer to an <type>sd_bus_track</type> object. This call is useful in conjunction with GCC's and
|
||||
LLVM's <ulink url="https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html">Clean-up Variable
|
||||
Attribute</ulink>. Note that this function is defined as inline function.</para>
|
||||
|
||||
<para><function>sd_bus_track_ref()</function>, <function>sd_bus_track_unref()</function> and
|
||||
<function>sd_bus_track_unrefp()</function> execute no operation if the passed in bus peer tracking object is
|
||||
<constant>NULL</constant>.</para>
|
||||
|
||||
<para>Bus peer tracking objects may exist in two modes: by default they operate in non-recursive mode, but may
|
||||
optionally be switched into recursive mode. If operating in the default non-recursive mode a peer is either tracked
|
||||
or not tracked. In this mode invoking <function>sd_bus_track_add_name()</function> multiple times in a row for the
|
||||
same peer is fully equivalent to calling it just once, as the call adds the peer to the set of tracked peers if
|
||||
necessary, and executes no operation if the peer is already being tracked. A single invocation of
|
||||
<function>sd_bus_track_remove_name()</function> removes the reference on the peer again, regardless how many times
|
||||
<function>sd_bus_track_add_name()</function> was called before. If operating in recursive mode, the number of times
|
||||
<function>sd_bus_track_add_name()</function> is invoked for the same peer name is counted and
|
||||
<function>sd_bus_track_remove_name()</function> must be called the same number of times before the peer is not
|
||||
tracked anymore, with the exception when the tracked peer vanishes from the bus, in which case the count is
|
||||
irrelevant and the tracking of the specific peer is immediately
|
||||
removed. <function>sd_bus_track_get_recursive()</function> may be used to determine whether the bus peer tracking
|
||||
object is operating in recursive mode. <function>sd_bus_track_set_recursive()</function> may be used to enable or
|
||||
disable recursive mode. By default a bus peer tracking object operates in non-recursive mode, and
|
||||
<function>sd_bus_track_get_recursive()</function> for a newly allocated object hence returns a value equal to
|
||||
zero. Use <function>sd_bus_track_set_recursive()</function> to enable recursive mode, right after allocation. It
|
||||
takes a boolean argument to enable or disable recursive mode. Note that tracking objects for which
|
||||
<function>sd_bus_track_add_name()</function> was already invoked at least once (and which hence track already one
|
||||
or more peers) may not be switched from recursive to non-recursive mode anymore.</para>
|
||||
|
||||
<para><function>sd_bus_track_get_bus()</function> returns the bus object the bus peer tracking object belongs
|
||||
to. It returns the bus object initially passed to <function>sd_bus_track_new()</function> when the object was
|
||||
allocated.</para>
|
||||
|
||||
<para><function>sd_bus_track_get_userdata()</function> returns the generic user data pointer set on the bus peer
|
||||
tracking object at the time of creation using <function>sd_bus_track_new()</function> or at a later time, using
|
||||
<function>sd_bus_track_set_userdata()</function>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>On success, <function>sd_bus_track_new()</function> and <function>sd_bus_track_set_recursive()</function>
|
||||
return 0 or a positive integer. On failure, they return a negative errno-style error code.</para>
|
||||
|
||||
<para><function>sd_bus_track_ref()</function> always returns the argument.</para>
|
||||
|
||||
<para><function>sd_bus_track_unref()</function> always returns <constant>NULL</constant>.</para>
|
||||
|
||||
<para><function>sd_bus_track_get_recursive()</function> returns 0 if non-recursive mode is selected (default), and
|
||||
greater than 0 if recursive mode is selected. On failure a negative errno-style error code is returned.</para>
|
||||
|
||||
<para><function>sd_bus_track_get_bus()</function> returns the bus object associated to the bus peer tracking
|
||||
object.</para>
|
||||
|
||||
<para><function>sd_bus_track_get_userdata()</function> returns the generic user data pointer associated with the
|
||||
bus peer tracking object. <function>sd_bus_track_set_userdata()</function> returns the previous user data pointer
|
||||
set.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Reference ownership</title>
|
||||
|
||||
<para>The <function>sd_bus_track_new()</function> function creates a new object and the caller owns the sole
|
||||
reference. When not needed anymore, this reference should be destroyed with
|
||||
<function>sd_bus_track_unref()</function>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Errors</title>
|
||||
|
||||
<para>Returned errors may indicate the following problems:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EBUSY</constant></term>
|
||||
|
||||
<listitem><para>Bus peers have already been added to the bus peer tracking object and
|
||||
<function>sd_bus_track_set_recursive()</function> was called to change tracking mode.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EINVAL</constant></term>
|
||||
|
||||
<listitem><para>Specified parameter is invalid
|
||||
(<constant>NULL</constant> in case of output
|
||||
parameters).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-ENOMEM</constant></term>
|
||||
|
||||
<listitem><para>Memory allocation failed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para><function>sd_bus_track_new()</function> and the other calls 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_track_add_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
|
@ -642,13 +642,13 @@
|
|||
<term><command>list-units <optional><replaceable>PATTERN</replaceable>...</optional></command></term>
|
||||
|
||||
<listitem>
|
||||
<para>List units that <command>systemd</command> has loaded. This includes units that
|
||||
are either referenced directly or through a dependency, or units that were active in the
|
||||
past and have failed. By default only units which are active, have pending jobs, or have
|
||||
<para>List units that <command>systemd</command> has loaded. This includes units that are either referenced
|
||||
directly or through a dependency, units that are pinned by applications programmatically, or units that
|
||||
were active in the past and have failed. By default only units which are active, have pending jobs, or have
|
||||
failed are shown; this can be changed with option <option>--all</option>. If one or more
|
||||
<replaceable>PATTERN</replaceable>s are specified, only units matching one of them are
|
||||
shown. The units that are shown are additionally filtered by <option>--type=</option>
|
||||
and <option>--state=</option> if those options are specified.</para>
|
||||
<replaceable>PATTERN</replaceable>s are specified, only units matching one of them are shown. The units
|
||||
that are shown are additionally filtered by <option>--type=</option> and <option>--state=</option> if those
|
||||
options are specified.</para>
|
||||
|
||||
<para>This is the default command.</para>
|
||||
</listitem>
|
||||
|
|
|
@ -68,42 +68,30 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-run</command> may be used to create and
|
||||
start a transient <filename>.service</filename> or
|
||||
<filename>.scope</filename> unit and run the specified
|
||||
<replaceable>COMMAND</replaceable> in it. It may also be used to
|
||||
create and start transient <filename>.timer</filename>
|
||||
units.</para>
|
||||
<para><command>systemd-run</command> may be used to create and start a transient <filename>.service</filename> or
|
||||
<filename>.scope</filename> unit and run the specified <replaceable>COMMAND</replaceable> in it. It may also be
|
||||
used to create and start a transient <filename>.timer</filename> unit, that activates a
|
||||
<filename>.service</filename> unit when elapsing.</para>
|
||||
|
||||
<para>If a command is run as transient service unit, it will be
|
||||
started and managed by the service manager like any other service,
|
||||
and thus shows up in the output of <command>systemctl
|
||||
list-units</command> like any other unit. It will run in a clean
|
||||
and detached execution environment, with the service manager as
|
||||
its parent process. In this mode, <command>systemd-run</command>
|
||||
will start the service asynchronously in the background and return
|
||||
after the command has begun execution.</para>
|
||||
<para>If a command is run as transient service unit, it will be started and managed by the service manager like any
|
||||
other service, and thus shows up in the output of <command>systemctl list-units</command> like any other unit. It
|
||||
will run in a clean and detached execution environment, with the service manager as its parent process. In this
|
||||
mode, <command>systemd-run</command> will start the service asynchronously in the background and return after the
|
||||
command has begun execution (unless <option>--no-block</option> or <option>--watch</option> are specified, see
|
||||
below).</para>
|
||||
|
||||
<para>If a command is run as transient scope unit, it will be
|
||||
started by <command>systemd-run</command> itself as parent process
|
||||
and will thus inherit the execution environment of the
|
||||
caller. However, the processes of the command are managed by the
|
||||
service manager similar to normal services, and will show up in
|
||||
the output of <command>systemctl list-units</command>. Execution
|
||||
in this case is synchronous, and will return only when the command
|
||||
finishes. This mode is enabled via the <option>--scope</option>
|
||||
switch (see below). </para>
|
||||
<para>If a command is run as transient scope unit, it will be executed by <command>systemd-run</command> itself as
|
||||
parent process and will thus inherit the execution environment of the caller. However, the processes of the command
|
||||
are managed by the service manager similar to normal services, and will show up in the output of <command>systemctl
|
||||
list-units</command>. Execution in this case is synchronous, and will return only when the command finishes. This
|
||||
mode is enabled via the <option>--scope</option> switch (see below). </para>
|
||||
|
||||
<para>If a command is run with timer options such as
|
||||
<option>--on-calendar=</option> (see below), a transient timer
|
||||
unit is created alongside the service unit for the specified
|
||||
command. Only the transient timer unit is started immediately, the
|
||||
transient service unit will be started when the transient timer
|
||||
elapses. If the <option>--unit=</option> is specified, the
|
||||
<replaceable>COMMAND</replaceable> may be omitted. In this case,
|
||||
<command>systemd-run</command> only creates a
|
||||
<filename>.timer</filename> unit that invokes the specified unit
|
||||
when elapsing.</para>
|
||||
<para>If a command is run with timer options such as <option>--on-calendar=</option> (see below), a transient timer
|
||||
unit is created alongside the service unit for the specified command. Only the transient timer unit is started
|
||||
immediately, the transient service unit will be started when the timer elapses. If the <option>--unit=</option>
|
||||
option is specified, the <replaceable>COMMAND</replaceable> may be omitted. In this case,
|
||||
<command>systemd-run</command> creates only a <filename>.timer</filename> unit that invokes the specified unit when
|
||||
elapsing.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -123,8 +111,8 @@
|
|||
<term><option>--scope</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Create a transient <filename>.scope</filename> unit instead of
|
||||
the default transient <filename>.service</filename> unit.
|
||||
<para>Create a transient <filename>.scope</filename> unit instead of the default transient
|
||||
<filename>.service</filename> unit (see above).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -140,9 +128,8 @@
|
|||
<term><option>--property=</option></term>
|
||||
<term><option>-p</option></term>
|
||||
|
||||
<listitem><para>Sets a unit property for the scope or service
|
||||
unit that is created. This takes an assignment in the same
|
||||
format as
|
||||
<listitem><para>Sets a property on the scope or service unit that is created. This option takes an assignment
|
||||
in the same format as
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||
<command>set-property</command> command.</para>
|
||||
</listitem>
|
||||
|
@ -151,9 +138,8 @@
|
|||
<varlistentry>
|
||||
<term><option>--description=</option></term>
|
||||
|
||||
<listitem><para>Provide a description for the service or scope
|
||||
unit. If not specified, the command itself will be used as a
|
||||
description. See <varname>Description=</varname> in
|
||||
<listitem><para>Provide a description for the service, scope or timer unit. If not specified, the command
|
||||
itself will be used as a description. See <varname>Description=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
@ -161,19 +147,16 @@
|
|||
<varlistentry>
|
||||
<term><option>--slice=</option></term>
|
||||
|
||||
<listitem><para>Make the new <filename>.service</filename> or
|
||||
<filename>.scope</filename> unit part of the specified slice,
|
||||
instead of the <filename>system.slice</filename>.</para>
|
||||
<listitem><para>Make the new <filename>.service</filename> or <filename>.scope</filename> unit part of the
|
||||
specified slice, instead of <filename>system.slice</filename>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--remain-after-exit</option></term>
|
||||
|
||||
<listitem><para>After the service or scope process has
|
||||
terminated, keep the service around until it is explicitly
|
||||
stopped. This is useful to collect runtime information about
|
||||
the service after it finished running. Also see
|
||||
<listitem><para>After the service process has terminated, keep the service around until it is explicitly
|
||||
stopped. This is useful to collect runtime information about the service after it finished running. Also see
|
||||
<varname>RemainAfterExit=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
@ -183,10 +166,8 @@
|
|||
<varlistentry>
|
||||
<term><option>--send-sighup</option></term>
|
||||
|
||||
<listitem><para>When terminating the scope or service unit,
|
||||
send a SIGHUP immediately after SIGTERM. This is useful to
|
||||
indicate to shells and shell-like processes that the
|
||||
connection has been severed. Also see
|
||||
<listitem><para>When terminating the scope or service unit, send a SIGHUP immediately after SIGTERM. This is
|
||||
useful to indicate to shells and shell-like processes that the connection has been severed. Also see
|
||||
<varname>SendSIGHUP=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
@ -209,9 +190,8 @@
|
|||
<term><option>--uid=</option></term>
|
||||
<term><option>--gid=</option></term>
|
||||
|
||||
<listitem><para>Runs the service process under the UNIX user
|
||||
and group. Also see <varname>User=</varname> and
|
||||
<varname>Group=</varname> in
|
||||
<listitem><para>Runs the service process under the specified UNIX user and group. Also see
|
||||
<varname>User=</varname> and <varname>Group=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -239,11 +219,9 @@
|
|||
<term><option>--pty</option></term>
|
||||
<term><option>-t</option></term>
|
||||
|
||||
<listitem><para>When invoking a command, the service connects
|
||||
its standard input and output to the invoking tty via a
|
||||
pseudo TTY device. This allows invoking binaries as services
|
||||
that expect interactive user input, such as interactive
|
||||
command shells.</para></listitem>
|
||||
<listitem><para>When invoking the command, the transient service connects its standard input and output to the
|
||||
terminal <command>systemd-run</command> is invoked on, via a pseudo TTY device. This allows running binaries
|
||||
that expect interactive user input as services, such as interactive command shells.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -263,44 +241,32 @@
|
|||
<term><option>--on-unit-active=</option></term>
|
||||
<term><option>--on-unit-inactive=</option></term>
|
||||
|
||||
<listitem><para>Defines monotonic timers relative to different
|
||||
starting points. Also see <varname>OnActiveSec=</varname>,
|
||||
<varname>OnBootSec=</varname>,
|
||||
<varname>OnStartupSec=</varname>,
|
||||
<varname>OnUnitActiveSec=</varname> and
|
||||
<varname>OnUnitInactiveSec=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
|
||||
options have no effect in conjunction with
|
||||
<option>--scope</option>.</para>
|
||||
<listitem><para>Defines a monotonic timer relative to different starting points for starting the specified
|
||||
command. See <varname>OnActiveSec=</varname>, <varname>OnBootSec=</varname>, <varname>OnStartupSec=</varname>,
|
||||
<varname>OnUnitActiveSec=</varname> and <varname>OnUnitInactiveSec=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details. These options may not be combined with <option>--scope</option>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--on-calendar=</option></term>
|
||||
|
||||
<listitem><para>Defines realtime (i.e. wallclock) timers with
|
||||
calendar event expressions. Also see
|
||||
<varname>OnCalendar=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
|
||||
option has no effect in conjunction with
|
||||
<option>--scope</option>.</para>
|
||||
<listitem><para>Defines a calendar timer for starting the specified command. See <varname>OnCalendar=</varname>
|
||||
in <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
|
||||
option may not be combined with <option>--scope</option>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--timer-property=</option></term>
|
||||
|
||||
<listitem><para>Sets a timer unit property for the timer unit
|
||||
that is created. It is similar with
|
||||
<option>--property</option> but only for created timer
|
||||
unit. This option only has effect in conjunction with
|
||||
<option>--on-active=</option>, <option>--on-boot=</option>,
|
||||
<option>--on-startup=</option>,
|
||||
<option>--on-unit-active=</option>,
|
||||
<option>--on-unit-inactive=</option>,
|
||||
<option>--on-calendar=</option>. This takes an assignment in
|
||||
the same format as
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||
<listitem><para>Sets a property on the timer unit that is created. This option is similar to
|
||||
<option>--property=</option> but applies to the transient timer unit rather than the transient service unit
|
||||
created. This option only has an effect in conjunction with <option>--on-active=</option>,
|
||||
<option>--on-boot=</option>, <option>--on-startup=</option>, <option>--on-unit-active=</option>,
|
||||
<option>--on-unit-inactive=</option> or <option>--on-calendar=</option>. This option takes an assignment in the
|
||||
same format as <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||
<command>set-property</command> command.</para> </listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -308,14 +274,25 @@
|
|||
<term><option>--no-block</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Do not synchronously wait for the requested operation
|
||||
to finish. If this is not specified, the job will be
|
||||
verified, enqueued and <command>systemd-run</command> will
|
||||
wait until the unit's start-up is completed. By passing this
|
||||
argument, it is only verified and enqueued.</para>
|
||||
<para>Do not synchronously wait for the unit start operation to finish. If this option is not specified, the
|
||||
start request for the transient unit will be verified, enqueued and <command>systemd-run</command> will wait
|
||||
until the unit's start-up is completed. By passing this argument, it is only verified and enqueued. This
|
||||
option may not be combined with <option>--wait</option>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--wait</option></term>
|
||||
|
||||
<listitem><para>Synchronously wait for the transient service to terminate. If this option is specified, the
|
||||
start request for the transient unit is verified, enqueued, and waited for. Subsequently the invoked unit is
|
||||
monitored, and it is waited until it is deactivated again (most likely because the specified command
|
||||
completed). On exit, terse information about the unit's runtime is shown, including total runtime (as well as
|
||||
CPU usage, if <option>--property=CPUAccounting=1</option> was set) and the exit code and status of the main
|
||||
process. This output may be suppressed with <option>--quiet</option>. This option may not be combined with
|
||||
<option>--no-block</option>, <option>--scope</option> or the various timer options.</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" />
|
||||
|
|
|
@ -1524,6 +1524,8 @@ void unit_prune_cgroup(Unit *u) {
|
|||
if (!u->cgroup_path)
|
||||
return;
|
||||
|
||||
(void) unit_get_cpu_usage(u, NULL); /* Cache the last CPU usage value before we destroy the cgroup */
|
||||
|
||||
is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
|
||||
|
||||
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
|
||||
|
@ -2044,7 +2046,21 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
|
|||
nsec_t ns;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
/* Retrieve the current CPU usage counter. This will subtract the CPU counter taken when the unit was
|
||||
* started. If the cgroup has been removed already, returns the last cached value. To cache the value, simply
|
||||
* call this function with a NULL return value. */
|
||||
|
||||
r = unit_get_cpu_usage_raw(u, &ns);
|
||||
if (r == -ENODATA && u->cpu_usage_last != NSEC_INFINITY) {
|
||||
/* If we can't get the CPU usage anymore (because the cgroup was already removed, for example), use our
|
||||
* cached value. */
|
||||
|
||||
if (ret)
|
||||
*ret = u->cpu_usage_last;
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -2053,7 +2069,10 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
|
|||
else
|
||||
ns = 0;
|
||||
|
||||
*ret = ns;
|
||||
u->cpu_usage_last = ns;
|
||||
if (ret)
|
||||
*ret = ns;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2063,6 +2082,8 @@ int unit_reset_cpu_usage(Unit *u) {
|
|||
|
||||
assert(u);
|
||||
|
||||
u->cpu_usage_last = NSEC_INFINITY;
|
||||
|
||||
r = unit_get_cpu_usage_raw(u, &ns);
|
||||
if (r < 0) {
|
||||
u->cpu_usage_base = 0;
|
||||
|
|
|
@ -643,6 +643,54 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
|
|||
return bus_unit_method_set_properties(message, u, error);
|
||||
}
|
||||
|
||||
static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
const char *name;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_load_unit(m, name, NULL, error, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_unit_check_load_state(u, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return bus_unit_method_ref(message, u, error);
|
||||
}
|
||||
|
||||
static int method_unref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
const char *name;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_load_unit(m, name, NULL, error, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_unit_check_load_state(u, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return bus_unit_method_unref(message, u, error);
|
||||
}
|
||||
|
||||
static int reply_unit_info(sd_bus_message *reply, Unit *u) {
|
||||
_cleanup_free_ char *unit_path = NULL, *job_path = NULL;
|
||||
Unit *following;
|
||||
|
@ -781,6 +829,13 @@ static int transient_unit_from_message(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If the client asked for it, automatically add a reference to this unit. */
|
||||
if (u->bus_track_add) {
|
||||
r = bus_unit_track_add_sender(u, message);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to watch sender: %m");
|
||||
}
|
||||
|
||||
/* Now load the missing bits of the unit we just created */
|
||||
unit_add_to_load_queue(u);
|
||||
manager_dispatch_load_queue(m);
|
||||
|
@ -2211,6 +2266,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||
SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RefUnit", "s", NULL, method_ref_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("UnrefUnit", "s", NULL, method_unref_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
|
|
@ -418,6 +418,7 @@ static int bus_verify_manage_units_async_full(
|
|||
const char *verb,
|
||||
int capability,
|
||||
const char *polkit_message,
|
||||
bool interactive,
|
||||
sd_bus_message *call,
|
||||
sd_bus_error *error) {
|
||||
|
||||
|
@ -433,7 +434,15 @@ static int bus_verify_manage_units_async_full(
|
|||
details[7] = GETTEXT_PACKAGE;
|
||||
}
|
||||
|
||||
return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error);
|
||||
return bus_verify_polkit_async(
|
||||
call,
|
||||
capability,
|
||||
"org.freedesktop.systemd1.manage-units",
|
||||
details,
|
||||
interactive,
|
||||
UID_INVALID,
|
||||
&u->manager->polkit_registry,
|
||||
error);
|
||||
}
|
||||
|
||||
int bus_unit_method_start_generic(
|
||||
|
@ -486,6 +495,7 @@ int bus_unit_method_start_generic(
|
|||
verb,
|
||||
CAP_SYS_ADMIN,
|
||||
job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
|
||||
true,
|
||||
message,
|
||||
error);
|
||||
if (r < 0)
|
||||
|
@ -558,6 +568,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
|
|||
"kill",
|
||||
CAP_KILL,
|
||||
N_("Authentication is required to kill '$(unit)'."),
|
||||
true,
|
||||
message,
|
||||
error);
|
||||
if (r < 0)
|
||||
|
@ -588,6 +599,7 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
|
|||
"reset-failed",
|
||||
CAP_SYS_ADMIN,
|
||||
N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
|
||||
true,
|
||||
message,
|
||||
error);
|
||||
if (r < 0)
|
||||
|
@ -620,6 +632,7 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b
|
|||
"set-property",
|
||||
CAP_SYS_ADMIN,
|
||||
N_("Authentication is required to set properties on '$(unit)'."),
|
||||
true,
|
||||
message,
|
||||
error);
|
||||
if (r < 0)
|
||||
|
@ -634,6 +647,53 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b
|
|||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Unit *u = userdata;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(u);
|
||||
|
||||
r = mac_selinux_unit_access_check(u, message, "start", error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_verify_manage_units_async_full(
|
||||
u,
|
||||
"ref",
|
||||
CAP_SYS_ADMIN,
|
||||
NULL,
|
||||
false,
|
||||
message,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
r = bus_unit_track_add_sender(u, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Unit *u = userdata;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(u);
|
||||
|
||||
r = bus_unit_track_remove_sender(u, message);
|
||||
if (r == -EUNATCH)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet.");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
const sd_bus_vtable bus_unit_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
|
||||
|
@ -715,6 +775,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
|
|||
SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
/* Obsolete properties or obsolete alias names */
|
||||
SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
|
||||
|
@ -1318,6 +1380,29 @@ static int bus_unit_set_transient_property(
|
|||
return r;
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "AddRef")) {
|
||||
|
||||
int b;
|
||||
|
||||
/* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method
|
||||
* on the Unit interface, and it's probably not a good idea to expose a property and a method on the
|
||||
* same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for
|
||||
* transient units, but still). And "References" and "ReferencedBy" is already used as unit reference
|
||||
* dependency type, hence let's not confuse things with that.
|
||||
*
|
||||
* Note that we don't acually add the reference to the bus track. We do that only after the setup of
|
||||
* the transient unit is complete, so that setting this property multiple times in the same transient
|
||||
* unit creation call doesn't count as individual references. */
|
||||
|
||||
r = sd_bus_message_read(message, "b", &b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK)
|
||||
u->bus_track_add = b;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1422,3 +1507,71 @@ int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
|
|||
|
||||
return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id);
|
||||
}
|
||||
|
||||
static int bus_track_handler(sd_bus_track *t, void *userdata) {
|
||||
Unit *u = userdata;
|
||||
|
||||
assert(t);
|
||||
assert(u);
|
||||
|
||||
u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */
|
||||
|
||||
unit_add_to_gc_queue(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int allocate_bus_track(Unit *u) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
if (u->bus_track)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_track_handler, u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_track_set_recursive(u->bus_track, true);
|
||||
if (r < 0) {
|
||||
u->bus_track = sd_bus_track_unref(u->bus_track);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bus_unit_track_add_name(Unit *u, const char *name) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
r = allocate_bus_track(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_track_add_name(u->bus_track, name);
|
||||
}
|
||||
|
||||
int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
r = allocate_bus_track(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_track_add_sender(u->bus_track, m);
|
||||
}
|
||||
|
||||
int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) {
|
||||
assert(u);
|
||||
|
||||
/* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
|
||||
* error */
|
||||
if (!u->bus_track)
|
||||
return -EUNATCH;
|
||||
|
||||
return sd_bus_track_remove_sender(u->bus_track, m);
|
||||
}
|
||||
|
|
|
@ -33,9 +33,15 @@ int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_
|
|||
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
||||
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
|
||||
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
|
||||
int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
||||
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
|
||||
int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
|
||||
|
||||
int bus_unit_track_add_name(Unit *u, const char *name);
|
||||
int bus_unit_track_add_sender(Unit *u, sd_bus_message *m);
|
||||
int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m);
|
||||
|
|
|
@ -1168,60 +1168,57 @@ int bus_foreach_bus(
|
|||
return ret;
|
||||
}
|
||||
|
||||
void bus_track_serialize(sd_bus_track *t, FILE *f) {
|
||||
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) {
|
||||
const char *n;
|
||||
|
||||
assert(f);
|
||||
assert(prefix);
|
||||
|
||||
for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t))
|
||||
fprintf(f, "subscribed=%s\n", n);
|
||||
for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) {
|
||||
int c, j;
|
||||
|
||||
c = sd_bus_track_count_name(t, n);
|
||||
|
||||
for (j = 0; j < c; j++) {
|
||||
fputs(prefix, f);
|
||||
fputc('=', f);
|
||||
fputs(n, f);
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bus_track_deserialize_item(char ***l, const char *line) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(l);
|
||||
assert(line);
|
||||
|
||||
e = startswith(line, "subscribed=");
|
||||
if (!e)
|
||||
return 0;
|
||||
|
||||
r = strv_extend(l, e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
|
||||
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) {
|
||||
char **i;
|
||||
int r = 0;
|
||||
|
||||
assert(m);
|
||||
assert(t);
|
||||
assert(l);
|
||||
|
||||
if (!strv_isempty(*l) && m->api_bus) {
|
||||
char **i;
|
||||
if (strv_isempty(l))
|
||||
return 0;
|
||||
|
||||
if (!*t) {
|
||||
r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (!m->api_bus)
|
||||
return 0;
|
||||
|
||||
r = 0;
|
||||
STRV_FOREACH(i, *l) {
|
||||
int k;
|
||||
|
||||
k = sd_bus_track_add_name(*t, *i);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
if (!*t) {
|
||||
r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*l = strv_free(*l);
|
||||
r = sd_bus_track_set_recursive(*t, recursive);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = 0;
|
||||
STRV_FOREACH(i, l) {
|
||||
int k;
|
||||
|
||||
k = sd_bus_track_add_name(*t, *i);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -28,9 +28,8 @@ void bus_done(Manager *m);
|
|||
|
||||
int bus_fdset_add_all(Manager *m, FDSet *fds);
|
||||
|
||||
void bus_track_serialize(sd_bus_track *t, FILE *f);
|
||||
int bus_track_deserialize_item(char ***l, const char *line);
|
||||
int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l);
|
||||
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix);
|
||||
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l);
|
||||
|
||||
int manager_sync_bus_names(Manager *m, sd_bus *bus);
|
||||
|
||||
|
|
|
@ -997,7 +997,10 @@ char *job_dbus_path(Job *j) {
|
|||
return p;
|
||||
}
|
||||
|
||||
int job_serialize(Job *j, FILE *f, FDSet *fds) {
|
||||
int job_serialize(Job *j, FILE *f) {
|
||||
assert(j);
|
||||
assert(f);
|
||||
|
||||
fprintf(f, "job-id=%u\n", j->id);
|
||||
fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
|
||||
fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
|
||||
|
@ -1008,15 +1011,16 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
|
|||
if (j->begin_usec > 0)
|
||||
fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
|
||||
|
||||
bus_track_serialize(j->clients, f);
|
||||
bus_track_serialize(j->clients, f, "subscribed");
|
||||
|
||||
/* End marker */
|
||||
fputc('\n', f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int job_deserialize(Job *j, FILE *f, FDSet *fds) {
|
||||
int job_deserialize(Job *j, FILE *f) {
|
||||
assert(j);
|
||||
assert(f);
|
||||
|
||||
for (;;) {
|
||||
char line[LINE_MAX], *l, *v;
|
||||
|
@ -1106,7 +1110,7 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
|
|||
} else if (streq(l, "subscribed")) {
|
||||
|
||||
if (strv_extend(&j->deserialized_clients, v) < 0)
|
||||
return log_oom();
|
||||
log_oom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1118,9 +1122,8 @@ int job_coldplug(Job *j) {
|
|||
|
||||
/* After deserialization is complete and the bus connection
|
||||
* set up again, let's start watching our subscribers again */
|
||||
r = bus_track_coldplug(j->manager, &j->clients, &j->deserialized_clients);
|
||||
if (r < 0)
|
||||
return r;
|
||||
(void) bus_track_coldplug(j->manager, &j->clients, false, j->deserialized_clients);
|
||||
j->deserialized_clients = strv_free(j->deserialized_clients);
|
||||
|
||||
if (j->state == JOB_WAITING)
|
||||
job_add_to_run_queue(j);
|
||||
|
|
|
@ -177,8 +177,8 @@ Job* job_install(Job *j);
|
|||
int job_install_deserialized(Job *j);
|
||||
void job_uninstall(Job *j);
|
||||
void job_dump(Job *j, FILE*f, const char *prefix);
|
||||
int job_serialize(Job *j, FILE *f, FDSet *fds);
|
||||
int job_deserialize(Job *j, FILE *f, FDSet *fds);
|
||||
int job_serialize(Job *j, FILE *f);
|
||||
int job_deserialize(Job *j, FILE *f);
|
||||
int job_coldplug(Job *j);
|
||||
|
||||
JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);
|
||||
|
|
|
@ -1287,10 +1287,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
|||
if (q < 0 && r == 0)
|
||||
r = q;
|
||||
|
||||
/* We might have deserialized the kdbus control fd, but if we
|
||||
* didn't, then let's create the bus now. */
|
||||
manager_connect_bus(m, !!serialization);
|
||||
bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed);
|
||||
/* We might have deserialized the kdbus control fd, but if we didn't, then let's create the bus now. */
|
||||
(void) manager_connect_bus(m, !!serialization);
|
||||
|
||||
(void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
|
||||
m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
|
||||
|
||||
/* Third, fire things up! */
|
||||
manager_coldplug(m);
|
||||
|
@ -2490,7 +2491,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
|
|||
fprintf(f, "kdbus-fd=%i\n", copy);
|
||||
}
|
||||
|
||||
bus_track_serialize(m->subscribed, f);
|
||||
bus_track_serialize(m->subscribed, f, "subscribed");
|
||||
|
||||
r = dynamic_user_serialize(m, f, fds);
|
||||
if (r < 0)
|
||||
|
@ -2693,15 +2694,13 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
|||
manager_deserialize_uid_refs_one(m, l + 16);
|
||||
else if (startswith(l, "destroy-ipc-gid="))
|
||||
manager_deserialize_gid_refs_one(m, l + 16);
|
||||
else {
|
||||
int k;
|
||||
else if (startswith(l, "subscribed=")) {
|
||||
|
||||
k = bus_track_deserialize_item(&m->deserialized_subscribed, l);
|
||||
if (k < 0)
|
||||
log_debug_errno(k, "Failed to deserialize bus tracker object: %m");
|
||||
else if (k == 0)
|
||||
log_debug("Unknown serialization item '%s'", l);
|
||||
}
|
||||
if (strv_extend(&m->deserialized_subscribed, l+11) < 0)
|
||||
log_oom();
|
||||
|
||||
} else
|
||||
log_debug("Unknown serialization item '%s'", l);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
|
@ -182,6 +182,14 @@
|
|||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="Reexecute"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="RefUnit"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="UnrefUnit"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="EnableUnitFiles"/>
|
||||
|
|
|
@ -102,6 +102,7 @@ Unit *unit_new(Manager *m, size_t size) {
|
|||
u->job_timeout = USEC_INFINITY;
|
||||
u->ref_uid = UID_INVALID;
|
||||
u->ref_gid = GID_INVALID;
|
||||
u->cpu_usage_last = NSEC_INFINITY;
|
||||
|
||||
RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
|
||||
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
|
||||
|
@ -113,7 +114,7 @@ bool unit_has_name(Unit *u, const char *name) {
|
|||
assert(u);
|
||||
assert(name);
|
||||
|
||||
return !!set_get(u->names, (char*) name);
|
||||
return set_contains(u->names, (char*) name);
|
||||
}
|
||||
|
||||
static void unit_init(Unit *u) {
|
||||
|
@ -329,6 +330,9 @@ bool unit_check_gc(Unit *u) {
|
|||
if (u->refs)
|
||||
return true;
|
||||
|
||||
if (sd_bus_track_count(u->bus_track) > 0)
|
||||
return true;
|
||||
|
||||
if (UNIT_VTABLE(u)->check_gc)
|
||||
if (UNIT_VTABLE(u)->check_gc(u))
|
||||
return true;
|
||||
|
@ -509,6 +513,9 @@ void unit_free(Unit *u) {
|
|||
|
||||
sd_bus_slot_unref(u->match_bus_slot);
|
||||
|
||||
sd_bus_track_unref(u->bus_track);
|
||||
u->deserialized_refs = strv_free(u->deserialized_refs);
|
||||
|
||||
unit_free_requires_mounts_for(u);
|
||||
|
||||
SET_FOREACH(t, u->names, i)
|
||||
|
@ -897,6 +904,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
|||
Unit *following;
|
||||
_cleanup_set_free_ Set *following_set = NULL;
|
||||
int r;
|
||||
const char *n;
|
||||
|
||||
assert(u);
|
||||
assert(u->type >= 0);
|
||||
|
@ -1038,6 +1046,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
|||
else if (u->load_state == UNIT_ERROR)
|
||||
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
|
||||
|
||||
for (n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
|
||||
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
|
||||
|
||||
if (u->job)
|
||||
job_dump(u->job, f, prefix2);
|
||||
|
@ -2611,7 +2621,10 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
|||
unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result));
|
||||
|
||||
unit_serialize_item(u, f, "transient", yes_no(u->transient));
|
||||
|
||||
unit_serialize_item_format(u, f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
|
||||
if (u->cpu_usage_last != NSEC_INFINITY)
|
||||
unit_serialize_item_format(u, f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
|
||||
|
||||
if (u->cgroup_path)
|
||||
unit_serialize_item(u, f, "cgroup", u->cgroup_path);
|
||||
|
@ -2622,15 +2635,17 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
|||
if (gid_is_valid(u->ref_gid))
|
||||
unit_serialize_item_format(u, f, "ref-gid", GID_FMT, u->ref_gid);
|
||||
|
||||
bus_track_serialize(u->bus_track, f, "ref");
|
||||
|
||||
if (serialize_jobs) {
|
||||
if (u->job) {
|
||||
fprintf(f, "job\n");
|
||||
job_serialize(u->job, f, fds);
|
||||
job_serialize(u->job, f);
|
||||
}
|
||||
|
||||
if (u->nop_job) {
|
||||
fprintf(f, "job\n");
|
||||
job_serialize(u->nop_job, f, fds);
|
||||
job_serialize(u->nop_job, f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2760,7 +2775,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
|||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
r = job_deserialize(j, f, fds);
|
||||
r = job_deserialize(j, f);
|
||||
if (r < 0) {
|
||||
job_free(j);
|
||||
return r;
|
||||
|
@ -2832,11 +2847,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
|||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cpu-usage-base") || streq(l, "cpuacct-usage-base")) {
|
||||
} else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_base);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse CPU usage %s, ignoring.", v);
|
||||
log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cpu-usage-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
|
@ -2880,6 +2903,12 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
|||
else
|
||||
unit_ref_uid_gid(u, UID_INVALID, gid);
|
||||
|
||||
} else if (streq(l, "ref")) {
|
||||
|
||||
r = strv_extend(&u->deserialized_refs, v);
|
||||
if (r < 0)
|
||||
log_oom();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2955,7 +2984,8 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
|
|||
}
|
||||
|
||||
int unit_coldplug(Unit *u) {
|
||||
int r = 0, q = 0;
|
||||
int r = 0, q;
|
||||
char **i;
|
||||
|
||||
assert(u);
|
||||
|
||||
|
@ -2966,18 +2996,26 @@ int unit_coldplug(Unit *u) {
|
|||
|
||||
u->coldplugged = true;
|
||||
|
||||
if (UNIT_VTABLE(u)->coldplug)
|
||||
r = UNIT_VTABLE(u)->coldplug(u);
|
||||
STRV_FOREACH(i, u->deserialized_refs) {
|
||||
q = bus_unit_track_add_name(u, *i);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
u->deserialized_refs = strv_free(u->deserialized_refs);
|
||||
|
||||
if (u->job)
|
||||
if (UNIT_VTABLE(u)->coldplug) {
|
||||
q = UNIT_VTABLE(u)->coldplug(u);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
if (u->job) {
|
||||
q = job_coldplug(u->job);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (q < 0)
|
||||
return q;
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool fragment_mtime_newer(const char *path, usec_t mtime) {
|
||||
|
|
|
@ -108,6 +108,10 @@ struct Unit {
|
|||
/* The slot used for watching NameOwnerChanged signals */
|
||||
sd_bus_slot *match_bus_slot;
|
||||
|
||||
/* References to this unit from clients */
|
||||
sd_bus_track *bus_track;
|
||||
char **deserialized_refs;
|
||||
|
||||
/* Job timeout and action to take */
|
||||
usec_t job_timeout;
|
||||
FailureAction job_timeout_action;
|
||||
|
@ -190,6 +194,7 @@ struct Unit {
|
|||
|
||||
/* Where the cpu.stat or cpuacct.usage was at the time the unit was started */
|
||||
nsec_t cpu_usage_base;
|
||||
nsec_t cpu_usage_last; /* the most recently read value */
|
||||
|
||||
/* Counterparts in the cgroup filesystem */
|
||||
char *cgroup_path;
|
||||
|
@ -247,6 +252,9 @@ struct Unit {
|
|||
|
||||
/* Did we already invoke unit_coldplug() for this unit? */
|
||||
bool coldplugged:1;
|
||||
|
||||
/* For transient units: whether to add a bus track reference after creating the unit */
|
||||
bool bus_track_add:1;
|
||||
};
|
||||
|
||||
struct UnitStatusMessageFormats {
|
||||
|
|
|
@ -500,3 +500,13 @@ LIBSYSTEMD_231 {
|
|||
global:
|
||||
sd_event_get_iteration;
|
||||
} LIBSYSTEMD_230;
|
||||
|
||||
LIBSYSTEMD_232 {
|
||||
global:
|
||||
sd_bus_track_set_recursive;
|
||||
sd_bus_track_get_recursive;
|
||||
sd_bus_track_count_name;
|
||||
sd_bus_track_count_sender;
|
||||
sd_bus_set_exit_on_disconnect;
|
||||
sd_bus_get_exit_on_disconnect;
|
||||
} LIBSYSTEMD_231;
|
||||
|
|
|
@ -45,6 +45,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
|
|||
SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING, EHOSTDOWN),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER, ESRCH),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED, EUNATCH),
|
||||
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE, ENOENT),
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
|
||||
#define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning"
|
||||
#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser"
|
||||
#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced"
|
||||
|
||||
#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
|
||||
#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"
|
||||
|
|
|
@ -209,6 +209,9 @@ struct sd_bus {
|
|||
bool is_system:1;
|
||||
bool is_user:1;
|
||||
bool allow_interactive_authorization:1;
|
||||
bool exit_on_disconnect:1;
|
||||
bool exited:1;
|
||||
bool exit_triggered:1;
|
||||
|
||||
int use_memfd;
|
||||
|
||||
|
@ -320,6 +323,7 @@ struct sd_bus {
|
|||
sd_bus_track *track_queue;
|
||||
|
||||
LIST_HEAD(sd_bus_slot, slots);
|
||||
LIST_HEAD(sd_bus_track, tracks);
|
||||
};
|
||||
|
||||
#define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
|
||||
|
|
|
@ -24,16 +24,27 @@
|
|||
#include "bus-track.h"
|
||||
#include "bus-util.h"
|
||||
|
||||
struct track_item {
|
||||
unsigned n_ref;
|
||||
char *name;
|
||||
sd_bus_slot *slot;
|
||||
};
|
||||
|
||||
struct sd_bus_track {
|
||||
unsigned n_ref;
|
||||
unsigned n_adding; /* are we in the process of adding a new name? */
|
||||
sd_bus *bus;
|
||||
sd_bus_track_handler_t handler;
|
||||
void *userdata;
|
||||
Hashmap *names;
|
||||
LIST_FIELDS(sd_bus_track, queue);
|
||||
Iterator iterator;
|
||||
bool in_queue;
|
||||
bool modified;
|
||||
bool in_list:1; /* In bus->tracks? */
|
||||
bool in_queue:1; /* In bus->track_queue? */
|
||||
bool modified:1;
|
||||
bool recursive:1;
|
||||
|
||||
LIST_FIELDS(sd_bus_track, tracks);
|
||||
};
|
||||
|
||||
#define MATCH_PREFIX \
|
||||
|
@ -56,15 +67,47 @@ struct sd_bus_track {
|
|||
_x; \
|
||||
})
|
||||
|
||||
static struct track_item* track_item_free(struct track_item *i) {
|
||||
|
||||
if (!i)
|
||||
return NULL;
|
||||
|
||||
sd_bus_slot_unref(i->slot);
|
||||
free(i->name);
|
||||
free(i);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free);
|
||||
|
||||
static void bus_track_add_to_queue(sd_bus_track *track) {
|
||||
assert(track);
|
||||
|
||||
/* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of
|
||||
* conditions. */
|
||||
|
||||
/* Already in the queue? */
|
||||
if (track->in_queue)
|
||||
return;
|
||||
|
||||
/* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait
|
||||
* until the addition is complete. */
|
||||
if (track->n_adding > 0)
|
||||
return;
|
||||
|
||||
/* still referenced? */
|
||||
if (hashmap_size(track->names) > 0)
|
||||
return;
|
||||
|
||||
/* Nothing to call? */
|
||||
if (!track->handler)
|
||||
return;
|
||||
|
||||
/* Already closed? */
|
||||
if (!track->in_list)
|
||||
return;
|
||||
|
||||
LIST_PREPEND(queue, track->bus->track_queue, track);
|
||||
track->in_queue = true;
|
||||
}
|
||||
|
@ -79,6 +122,24 @@ static void bus_track_remove_from_queue(sd_bus_track *track) {
|
|||
track->in_queue = false;
|
||||
}
|
||||
|
||||
static int bus_track_remove_name_fully(sd_bus_track *track, const char *name) {
|
||||
struct track_item *i;
|
||||
|
||||
assert(track);
|
||||
assert(name);
|
||||
|
||||
i = hashmap_remove(track->names, name);
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
track_item_free(i);
|
||||
|
||||
bus_track_add_to_queue(track);
|
||||
|
||||
track->modified = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_new(
|
||||
sd_bus *bus,
|
||||
sd_bus_track **track,
|
||||
|
@ -102,6 +163,9 @@ _public_ int sd_bus_track_new(
|
|||
t->userdata = userdata;
|
||||
t->bus = sd_bus_ref(bus);
|
||||
|
||||
LIST_PREPEND(tracks, bus->tracks, t);
|
||||
t->in_list = true;
|
||||
|
||||
bus_track_add_to_queue(t);
|
||||
|
||||
*track = t;
|
||||
|
@ -121,7 +185,7 @@ _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) {
|
|||
}
|
||||
|
||||
_public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
|
||||
const char *n;
|
||||
struct track_item *i;
|
||||
|
||||
if (!track)
|
||||
return NULL;
|
||||
|
@ -133,8 +197,11 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
while ((n = hashmap_first_key(track->names)))
|
||||
sd_bus_track_remove_name(track, n);
|
||||
while ((i = hashmap_steal_first(track->names)))
|
||||
track_item_free(i);
|
||||
|
||||
if (track->in_list)
|
||||
LIST_REMOVE(tracks, track->bus->tracks, track);
|
||||
|
||||
bus_track_remove_from_queue(track);
|
||||
hashmap_free(track->names);
|
||||
|
@ -156,49 +223,76 @@ static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus
|
|||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
sd_bus_track_remove_name(track, name);
|
||||
bus_track_remove_name_fully(track, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
|
||||
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
|
||||
_cleanup_free_ char *n = NULL;
|
||||
_cleanup_(track_item_freep) struct track_item *n = NULL;
|
||||
struct track_item *i;
|
||||
const char *match;
|
||||
int r;
|
||||
|
||||
assert_return(track, -EINVAL);
|
||||
assert_return(service_name_is_valid(name), -EINVAL);
|
||||
|
||||
i = hashmap_get(track->names, name);
|
||||
if (i) {
|
||||
if (track->recursive) {
|
||||
unsigned k = track->n_ref + 1;
|
||||
|
||||
if (k < track->n_ref) /* Check for overflow */
|
||||
return -EOVERFLOW;
|
||||
|
||||
track->n_ref = k;
|
||||
}
|
||||
|
||||
bus_track_remove_from_queue(track);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(&track->names, &string_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n = strdup(name);
|
||||
n = new0(struct track_item, 1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
n->name = strdup(name);
|
||||
if (!n->name)
|
||||
return -ENOMEM;
|
||||
|
||||
/* First, subscribe to this name */
|
||||
match = MATCH_FOR_NAME(n);
|
||||
r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
|
||||
if (r < 0)
|
||||
return r;
|
||||
match = MATCH_FOR_NAME(name);
|
||||
|
||||
r = hashmap_put(track->names, n, slot);
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */
|
||||
|
||||
/* Second, check if it is currently existing, or maybe
|
||||
* doesn't, or maybe disappeared already. */
|
||||
r = sd_bus_get_name_creds(track->bus, n, 0, NULL);
|
||||
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--;
|
||||
if (r < 0) {
|
||||
hashmap_remove(track->names, n);
|
||||
bus_track_add_to_queue(track);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = hashmap_put(track->names, n->name, n);
|
||||
if (r < 0) {
|
||||
bus_track_add_to_queue(track);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */
|
||||
track->n_adding++; /* again, make sure this isn't dispatch while we are working in it */
|
||||
r = sd_bus_get_name_creds(track->bus, name, 0, NULL);
|
||||
track->n_adding--;
|
||||
if (r < 0) {
|
||||
hashmap_remove(track->names, name);
|
||||
bus_track_add_to_queue(track);
|
||||
return r;
|
||||
}
|
||||
|
||||
n->n_ref = 1;
|
||||
n = NULL;
|
||||
slot = NULL;
|
||||
|
||||
bus_track_remove_from_queue(track);
|
||||
track->modified = true;
|
||||
|
@ -207,37 +301,48 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
|
|||
}
|
||||
|
||||
_public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
|
||||
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
|
||||
_cleanup_free_ char *n = NULL;
|
||||
struct track_item *i;
|
||||
|
||||
assert_return(name, -EINVAL);
|
||||
|
||||
if (!track)
|
||||
if (!track) /* Treat a NULL track object as an empty track object */
|
||||
return 0;
|
||||
|
||||
slot = hashmap_remove2(track->names, (char*) name, (void**) &n);
|
||||
if (!slot)
|
||||
return 0;
|
||||
if (!track->recursive)
|
||||
return bus_track_remove_name_fully(track, name);
|
||||
|
||||
if (hashmap_isempty(track->names))
|
||||
bus_track_add_to_queue(track);
|
||||
i = hashmap_get(track->names, name);
|
||||
if (!i)
|
||||
return -EUNATCH;
|
||||
if (i->n_ref <= 0)
|
||||
return -EUNATCH;
|
||||
|
||||
track->modified = true;
|
||||
i->n_ref--;
|
||||
|
||||
if (i->n_ref <= 0)
|
||||
return bus_track_remove_name_fully(track, name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
_public_ unsigned sd_bus_track_count(sd_bus_track *track) {
|
||||
if (!track)
|
||||
|
||||
if (!track) /* Let's consider a NULL object equivalent to an empty object */
|
||||
return 0;
|
||||
|
||||
/* This signature really should have returned an int, so that we can propagate errors. But well, ... Also, note
|
||||
* that this returns the number of names being watched, and multiple references to the same name are not
|
||||
* counted. */
|
||||
|
||||
return hashmap_size(track->names);
|
||||
}
|
||||
|
||||
_public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
|
||||
assert_return(track, NULL);
|
||||
assert_return(name, NULL);
|
||||
|
||||
if (!track) /* Let's consider a NULL object equivalent to an empty object */
|
||||
return NULL;
|
||||
|
||||
return hashmap_get(track->names, (void*) name) ? name : NULL;
|
||||
}
|
||||
|
||||
|
@ -273,6 +378,9 @@ _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
|
|||
assert_return(track, -EINVAL);
|
||||
assert_return(m, -EINVAL);
|
||||
|
||||
if (sd_bus_message_get_bus(m) != track->bus)
|
||||
return -EINVAL;
|
||||
|
||||
sender = sd_bus_message_get_sender(m);
|
||||
if (!sender)
|
||||
return -EINVAL;
|
||||
|
@ -283,9 +391,14 @@ _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
|
|||
_public_ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) {
|
||||
const char *sender;
|
||||
|
||||
assert_return(track, -EINVAL);
|
||||
assert_return(m, -EINVAL);
|
||||
|
||||
if (!track) /* Treat a NULL track object as an empty track object */
|
||||
return 0;
|
||||
|
||||
if (sd_bus_message_get_bus(m) != track->bus)
|
||||
return -EINVAL;
|
||||
|
||||
sender = sd_bus_message_get_sender(m);
|
||||
if (!sender)
|
||||
return -EINVAL;
|
||||
|
@ -303,7 +416,6 @@ void bus_track_dispatch(sd_bus_track *track) {
|
|||
int r;
|
||||
|
||||
assert(track);
|
||||
assert(track->in_queue);
|
||||
assert(track->handler);
|
||||
|
||||
bus_track_remove_from_queue(track);
|
||||
|
@ -319,6 +431,34 @@ void bus_track_dispatch(sd_bus_track *track) {
|
|||
sd_bus_track_unref(track);
|
||||
}
|
||||
|
||||
void bus_track_close(sd_bus_track *track) {
|
||||
struct track_item *i;
|
||||
|
||||
assert(track);
|
||||
|
||||
/* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it
|
||||
* immediately, as we are closing now, but first flush out all names. */
|
||||
|
||||
if (!track->in_list)
|
||||
return; /* We already closed this one, don't close it again. */
|
||||
|
||||
/* Remember that this one is closed now */
|
||||
LIST_REMOVE(tracks, track->bus->tracks, track);
|
||||
track->in_list = false;
|
||||
|
||||
/* If there's no name in this one anyway, we don't have to dispatch */
|
||||
if (hashmap_isempty(track->names))
|
||||
return;
|
||||
|
||||
/* Let's flush out all names */
|
||||
while ((i = hashmap_steal_first(track->names)))
|
||||
track_item_free(i);
|
||||
|
||||
/* Invoke handler */
|
||||
if (track->handler)
|
||||
bus_track_dispatch(track);
|
||||
}
|
||||
|
||||
_public_ void *sd_bus_track_get_userdata(sd_bus_track *track) {
|
||||
assert_return(track, NULL);
|
||||
|
||||
|
@ -335,3 +475,55 @@ _public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) {
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_set_recursive(sd_bus_track *track, int b) {
|
||||
assert_return(track, -EINVAL);
|
||||
|
||||
if (track->recursive == !!b)
|
||||
return 0;
|
||||
|
||||
if (!hashmap_isempty(track->names))
|
||||
return -EBUSY;
|
||||
|
||||
track->recursive = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_get_recursive(sd_bus_track *track) {
|
||||
assert_return(track, -EINVAL);
|
||||
|
||||
return track->recursive;
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m) {
|
||||
const char *sender;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
|
||||
if (!track) /* Let's consider a NULL object equivalent to an empty object */
|
||||
return 0;
|
||||
|
||||
if (sd_bus_message_get_bus(m) != track->bus)
|
||||
return -EINVAL;
|
||||
|
||||
sender = sd_bus_message_get_sender(m);
|
||||
if (!sender)
|
||||
return -EINVAL;
|
||||
|
||||
return sd_bus_track_count_name(track, sender);
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_count_name(sd_bus_track *track, const char *name) {
|
||||
struct track_item *i;
|
||||
|
||||
assert_return(service_name_is_valid(name), -EINVAL);
|
||||
|
||||
if (!track) /* Let's consider a NULL object equivalent to an empty object */
|
||||
return 0;
|
||||
|
||||
i = hashmap_get(track->names, name);
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
return i->n_ref;
|
||||
}
|
||||
|
|
|
@ -20,3 +20,4 @@
|
|||
***/
|
||||
|
||||
void bus_track_dispatch(sd_bus_track *track);
|
||||
void bus_track_close(sd_bus_track *track);
|
||||
|
|
|
@ -107,6 +107,7 @@ static void bus_free(sd_bus *b) {
|
|||
|
||||
assert(b);
|
||||
assert(!b->track_queue);
|
||||
assert(!b->tracks);
|
||||
|
||||
b->state = BUS_CLOSED;
|
||||
|
||||
|
@ -2640,6 +2641,84 @@ null_message:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int bus_exit_now(sd_bus *bus) {
|
||||
assert(bus);
|
||||
|
||||
/* Exit due to close, if this is requested. If this is bus object is attached to an event source, invokes
|
||||
* sd_event_exit(), otherwise invokes libc exit(). */
|
||||
|
||||
if (bus->exited) /* did we already exit? */
|
||||
return 0;
|
||||
if (!bus->exit_triggered) /* was the exit condition triggered? */
|
||||
return 0;
|
||||
if (!bus->exit_on_disconnect) /* Shall we actually exit on disconnection? */
|
||||
return 0;
|
||||
|
||||
bus->exited = true; /* never exit more than once */
|
||||
|
||||
log_debug("Bus connection disconnected, exiting.");
|
||||
|
||||
if (bus->event)
|
||||
return sd_event_exit(bus->event, EXIT_FAILURE);
|
||||
else
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
assert_not_reached("exit() didn't exit?");
|
||||
}
|
||||
|
||||
static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
sd_bus_slot *slot;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(c);
|
||||
|
||||
r = bus_message_new_synthetic_error(
|
||||
bus,
|
||||
c->cookie,
|
||||
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_seal_synthetic_message(bus, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c->timeout != 0) {
|
||||
prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
|
||||
c->timeout = 0;
|
||||
}
|
||||
|
||||
ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
|
||||
c->cookie = 0;
|
||||
|
||||
slot = container_of(c, sd_bus_slot, reply_callback);
|
||||
|
||||
bus->iteration_counter++;
|
||||
|
||||
bus->current_message = m;
|
||||
bus->current_slot = sd_bus_slot_ref(slot);
|
||||
bus->current_handler = c->callback;
|
||||
bus->current_userdata = slot->userdata;
|
||||
r = c->callback(m, slot->userdata, &error_buffer);
|
||||
bus->current_userdata = NULL;
|
||||
bus->current_handler = NULL;
|
||||
bus->current_slot = NULL;
|
||||
bus->current_message = NULL;
|
||||
|
||||
if (slot->floating) {
|
||||
bus_slot_disconnect(slot);
|
||||
sd_bus_slot_unref(slot);
|
||||
}
|
||||
|
||||
sd_bus_slot_unref(slot);
|
||||
|
||||
return bus_maybe_reply_error(m, r, &error_buffer);
|
||||
}
|
||||
|
||||
static int process_closing(sd_bus *bus, sd_bus_message **ret) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
struct reply_callback *c;
|
||||
|
@ -2648,54 +2727,15 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
|
|||
assert(bus);
|
||||
assert(bus->state == BUS_CLOSING);
|
||||
|
||||
/* First, fail all outstanding method calls */
|
||||
c = ordered_hashmap_first(bus->reply_callbacks);
|
||||
if (c) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
|
||||
sd_bus_slot *slot;
|
||||
if (c)
|
||||
return process_closing_reply_callback(bus, c);
|
||||
|
||||
/* First, fail all outstanding method calls */
|
||||
r = bus_message_new_synthetic_error(
|
||||
bus,
|
||||
c->cookie,
|
||||
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_seal_synthetic_message(bus, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c->timeout != 0) {
|
||||
prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
|
||||
c->timeout = 0;
|
||||
}
|
||||
|
||||
ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
|
||||
c->cookie = 0;
|
||||
|
||||
slot = container_of(c, sd_bus_slot, reply_callback);
|
||||
|
||||
bus->iteration_counter++;
|
||||
|
||||
bus->current_message = m;
|
||||
bus->current_slot = sd_bus_slot_ref(slot);
|
||||
bus->current_handler = c->callback;
|
||||
bus->current_userdata = slot->userdata;
|
||||
r = c->callback(m, slot->userdata, &error_buffer);
|
||||
bus->current_userdata = NULL;
|
||||
bus->current_handler = NULL;
|
||||
bus->current_slot = NULL;
|
||||
bus->current_message = NULL;
|
||||
|
||||
if (slot->floating) {
|
||||
bus_slot_disconnect(slot);
|
||||
sd_bus_slot_unref(slot);
|
||||
}
|
||||
|
||||
sd_bus_slot_unref(slot);
|
||||
|
||||
return bus_maybe_reply_error(m, r, &error_buffer);
|
||||
/* Then, fake-drop all remaining bus tracking references */
|
||||
if (bus->tracks) {
|
||||
bus_track_close(bus->tracks);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Then, synthesize a Disconnected message */
|
||||
|
@ -2727,6 +2767,10 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
|
|||
if (r != 0)
|
||||
goto finish;
|
||||
|
||||
/* Nothing else to do, exit now, if the condition holds */
|
||||
bus->exit_triggered = true;
|
||||
(void) bus_exit_now(bus);
|
||||
|
||||
if (ret) {
|
||||
*ret = m;
|
||||
m = NULL;
|
||||
|
@ -3789,3 +3833,21 @@ _public_ void sd_bus_default_flush_close(void) {
|
|||
flush_close(default_user_bus);
|
||||
flush_close(default_system_bus);
|
||||
}
|
||||
|
||||
_public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) {
|
||||
assert_return(bus, -EINVAL);
|
||||
|
||||
/* Turns on exit-on-disconnect, and triggers it immediately if the bus connection was already
|
||||
* disconnected. Note that this is triggered exclusively on disconnections triggered by the server side, never
|
||||
* from the client side. */
|
||||
bus->exit_on_disconnect = b;
|
||||
|
||||
/* If the exit condition was triggered already, exit immediately. */
|
||||
return bus_exit_now(bus);
|
||||
}
|
||||
|
||||
_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) {
|
||||
assert_return(bus, -EINVAL);
|
||||
|
||||
return bus->exit_on_disconnect;
|
||||
}
|
||||
|
|
113
src/libsystemd/sd-bus/test-bus-track.c
Normal file
113
src/libsystemd/sd-bus/test-bus-track.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 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 <sd-bus.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
static bool track_cb_called_x = false;
|
||||
static bool track_cb_called_y = false;
|
||||
|
||||
static int track_cb_x(sd_bus_track *t, void *userdata) {
|
||||
|
||||
log_error("TRACK CB X");
|
||||
|
||||
assert_se(!track_cb_called_x);
|
||||
track_cb_called_x = true;
|
||||
|
||||
/* This means b's name disappeared. Let's now disconnect, to make sure the track handling on disconnect works
|
||||
* as it should. */
|
||||
|
||||
assert_se(shutdown(sd_bus_get_fd(sd_bus_track_get_bus(t)), SHUT_RDWR) >= 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int track_cb_y(sd_bus_track *t, void *userdata) {
|
||||
int r;
|
||||
|
||||
log_error("TRACK CB Y");
|
||||
|
||||
assert_se(!track_cb_called_y);
|
||||
track_cb_called_y = true;
|
||||
|
||||
/* We got disconnected, let's close everything */
|
||||
|
||||
r = sd_event_exit(sd_bus_get_event(sd_bus_track_get_bus(t)), EXIT_SUCCESS);
|
||||
assert_se(r >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
_cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL;
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL;
|
||||
const char *unique;
|
||||
int r;
|
||||
|
||||
r = sd_event_default(&event);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_open_system(&a);
|
||||
if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
|
||||
log_info("Failed to connect to bus, skipping tests.");
|
||||
return EXIT_TEST_SKIP;
|
||||
}
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_open_system(&b);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
/* Watch b's name from a */
|
||||
r = sd_bus_track_new(a, &x, track_cb_x, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_get_unique_name(b, &unique);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_track_add_name(x, unique);
|
||||
assert_se(r >= 0);
|
||||
|
||||
/* Watch's a's own name from a */
|
||||
r = sd_bus_track_new(a, &y, track_cb_y, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_get_unique_name(a, &unique);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_track_add_name(y, unique);
|
||||
assert_se(r >= 0);
|
||||
|
||||
/* Now make b's name disappear */
|
||||
sd_bus_close(b);
|
||||
|
||||
r = sd_event_loop(event);
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(track_cb_called_x);
|
||||
assert_se(track_cb_called_y);
|
||||
|
||||
return 0;
|
||||
}
|
231
src/run/run.c
231
src/run/run.c
|
@ -33,6 +33,7 @@
|
|||
#include "formats-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "ptyfwd.h"
|
||||
#include "signal-util.h"
|
||||
#include "spawn-polkit-agent.h"
|
||||
|
@ -45,6 +46,7 @@ static bool arg_ask_password = true;
|
|||
static bool arg_scope = false;
|
||||
static bool arg_remain_after_exit = false;
|
||||
static bool arg_no_block = false;
|
||||
static bool arg_wait = false;
|
||||
static const char *arg_unit = NULL;
|
||||
static const char *arg_description = NULL;
|
||||
static const char *arg_slice = NULL;
|
||||
|
@ -97,6 +99,7 @@ static void help(void) {
|
|||
" --slice=SLICE Run in the specified slice\n"
|
||||
" --no-block Do not wait until operation finished\n"
|
||||
" -r --remain-after-exit Leave service around until explicitly stopped\n"
|
||||
" --wait Wait until service stopped again\n"
|
||||
" --send-sighup Send SIGHUP when terminating\n"
|
||||
" --service-type=TYPE Service type\n"
|
||||
" --uid=USER Run as system user\n"
|
||||
|
@ -144,6 +147,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_TIMER_PROPERTY,
|
||||
ARG_NO_BLOCK,
|
||||
ARG_NO_ASK_PASSWORD,
|
||||
ARG_WAIT,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -160,6 +164,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "host", required_argument, NULL, 'H' },
|
||||
{ "machine", required_argument, NULL, 'M' },
|
||||
{ "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
|
||||
{ "wait", no_argument, NULL, ARG_WAIT },
|
||||
{ "uid", required_argument, NULL, ARG_EXEC_USER },
|
||||
{ "gid", required_argument, NULL, ARG_EXEC_GROUP },
|
||||
{ "nice", required_argument, NULL, ARG_NICE },
|
||||
|
@ -357,6 +362,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
arg_no_block = true;
|
||||
break;
|
||||
|
||||
case ARG_WAIT:
|
||||
arg_wait = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -404,6 +413,23 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_wait) {
|
||||
if (arg_no_block) {
|
||||
log_error("--wait may not be combined with --no-block.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (with_timer()) {
|
||||
log_error("--wait may not be combined with timer operations.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_scope) {
|
||||
log_error("--wait may not be combined with --scope.");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -466,6 +492,12 @@ static int transient_service_set_properties(sd_bus_message *m, char **argv, cons
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_wait) {
|
||||
r = sd_bus_message_append(m, "(sv)", "AddRef", "b", 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (arg_remain_after_exit) {
|
||||
r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
|
||||
if (r < 0)
|
||||
|
@ -723,9 +755,97 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef struct RunContext {
|
||||
sd_bus *bus;
|
||||
sd_event *event;
|
||||
PTYForward *forward;
|
||||
sd_bus_slot *match;
|
||||
|
||||
/* The exit data of the unit */
|
||||
char *active_state;
|
||||
uint64_t inactive_exit_usec;
|
||||
uint64_t inactive_enter_usec;
|
||||
char *result;
|
||||
uint64_t cpu_usage_nsec;
|
||||
uint32_t exit_code;
|
||||
uint32_t exit_status;
|
||||
} RunContext;
|
||||
|
||||
static void run_context_free(RunContext *c) {
|
||||
assert(c);
|
||||
|
||||
c->forward = pty_forward_free(c->forward);
|
||||
c->match = sd_bus_slot_unref(c->match);
|
||||
c->bus = sd_bus_unref(c->bus);
|
||||
c->event = sd_event_unref(c->event);
|
||||
|
||||
free(c->active_state);
|
||||
free(c->result);
|
||||
}
|
||||
|
||||
static void run_context_check_done(RunContext *c) {
|
||||
bool done = true;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (c->match)
|
||||
done = done && (c->active_state && STR_IN_SET(c->active_state, "inactive", "failed"));
|
||||
|
||||
if (c->forward)
|
||||
done = done && pty_forward_is_done(c->forward);
|
||||
|
||||
if (done)
|
||||
sd_event_exit(c->event, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
|
||||
static const struct bus_properties_map map[] = {
|
||||
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
|
||||
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_exit_usec) },
|
||||
{ "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_enter_usec) },
|
||||
{ "Result", "s", NULL, offsetof(RunContext, result) },
|
||||
{ "ExecMainCode", "i", NULL, offsetof(RunContext, exit_code) },
|
||||
{ "ExecMainStatus", "i", NULL, offsetof(RunContext, exit_status) },
|
||||
{ "CPUUsageNSec", "t", NULL, offsetof(RunContext, cpu_usage_nsec) },
|
||||
{}
|
||||
};
|
||||
|
||||
RunContext *c = userdata;
|
||||
int r;
|
||||
|
||||
r = bus_map_all_properties(c->bus,
|
||||
"org.freedesktop.systemd1",
|
||||
sd_bus_message_get_path(m),
|
||||
map,
|
||||
c);
|
||||
if (r < 0) {
|
||||
sd_event_exit(c->event, EXIT_FAILURE);
|
||||
return log_error_errno(r, "Failed to query unit state: %m");
|
||||
}
|
||||
|
||||
run_context_check_done(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
||||
RunContext *c = userdata;
|
||||
|
||||
assert(f);
|
||||
|
||||
if (rcode < 0) {
|
||||
sd_event_exit(c->event, EXIT_FAILURE);
|
||||
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
|
||||
}
|
||||
|
||||
run_context_check_done(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_transient_service(
|
||||
sd_bus *bus,
|
||||
char **argv) {
|
||||
char **argv,
|
||||
int *retval) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
@ -736,6 +856,7 @@ static int start_transient_service(
|
|||
|
||||
assert(bus);
|
||||
assert(argv);
|
||||
assert(retval);
|
||||
|
||||
if (arg_pty) {
|
||||
|
||||
|
@ -859,40 +980,95 @@ static int start_transient_service(
|
|||
return r;
|
||||
}
|
||||
|
||||
if (master >= 0) {
|
||||
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
char last_char = 0;
|
||||
if (!arg_quiet)
|
||||
log_info("Running as unit: %s", service);
|
||||
|
||||
r = sd_event_default(&event);
|
||||
if (arg_wait || master >= 0) {
|
||||
_cleanup_(run_context_free) RunContext c = {};
|
||||
|
||||
c.bus = sd_bus_ref(bus);
|
||||
|
||||
r = sd_event_default(&c.event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get event loop: %m");
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
|
||||
if (master >= 0) {
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
|
||||
(void) sd_event_add_signal(c.event, NULL, SIGINT, NULL, NULL);
|
||||
(void) sd_event_add_signal(c.event, NULL, SIGTERM, NULL, NULL);
|
||||
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
||||
if (!arg_quiet)
|
||||
log_info("Press ^] three times within 1s to disconnect TTY.");
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service);
|
||||
r = pty_forward_new(c.event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c.forward);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
||||
|
||||
r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
||||
pty_forward_set_handler(c.forward, pty_forward_handler, &c);
|
||||
}
|
||||
|
||||
r = sd_event_loop(event);
|
||||
if (arg_wait) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
const char *mt;
|
||||
|
||||
path = unit_dbus_path_from_name(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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add properties changed signal.");
|
||||
|
||||
r = sd_bus_attach_event(bus, c.event, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach bus to event loop.");
|
||||
}
|
||||
|
||||
r = sd_event_loop(c.event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to run event loop: %m");
|
||||
|
||||
pty_forward_get_last_char(forward, &last_char);
|
||||
if (c.forward) {
|
||||
char last_char = 0;
|
||||
|
||||
forward = pty_forward_free(forward);
|
||||
r = pty_forward_get_last_char(c.forward, &last_char);
|
||||
if (r >= 0 && !arg_quiet && last_char != '\n')
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
if (!arg_quiet && last_char != '\n')
|
||||
fputc('\n', stdout);
|
||||
if (!arg_quiet) {
|
||||
if (!isempty(c.result))
|
||||
log_info("Finished with result: %s", strna(c.result));
|
||||
|
||||
} else if (!arg_quiet)
|
||||
log_info("Running as unit: %s", service);
|
||||
if (c.exit_code == CLD_EXITED)
|
||||
log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c.exit_code), c.exit_status);
|
||||
else if (c.exit_code > 0)
|
||||
log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status));
|
||||
|
||||
if (c.inactive_enter_usec > 0 && c.inactive_enter_usec != USEC_INFINITY &&
|
||||
c.inactive_exit_usec > 0 && c.inactive_exit_usec != USEC_INFINITY &&
|
||||
c.inactive_enter_usec > c.inactive_exit_usec) {
|
||||
char ts[FORMAT_TIMESPAN_MAX];
|
||||
log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC));
|
||||
}
|
||||
|
||||
if (c.cpu_usage_nsec > 0 && c.cpu_usage_nsec != NSEC_INFINITY) {
|
||||
char ts[FORMAT_TIMESPAN_MAX];
|
||||
log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC));
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to propagate the service's return value */
|
||||
if (c.result && STR_IN_SET(c.result, "success", "exit-code") && c.exit_code == CLD_EXITED)
|
||||
*retval = c.exit_status;
|
||||
else
|
||||
*retval = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1197,7 +1373,7 @@ static int start_transient_timer(
|
|||
int main(int argc, char* argv[]) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_free_ char *description = NULL, *command = NULL;
|
||||
int r;
|
||||
int r, retval = EXIT_SUCCESS;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
@ -1234,7 +1410,12 @@ int main(int argc, char* argv[]) {
|
|||
arg_description = description;
|
||||
}
|
||||
|
||||
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
|
||||
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
|
||||
* connection */
|
||||
if (arg_wait)
|
||||
r = bus_connect_transport(arg_transport, arg_host, arg_user, &bus);
|
||||
else
|
||||
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to create bus connection: %m");
|
||||
goto finish;
|
||||
|
@ -1245,12 +1426,12 @@ int main(int argc, char* argv[]) {
|
|||
else if (with_timer())
|
||||
r = start_transient_timer(bus, argv + optind);
|
||||
else
|
||||
r = start_transient_service(bus, argv + optind);
|
||||
r = start_transient_service(bus, argv + optind, &retval);
|
||||
|
||||
finish:
|
||||
strv_free(arg_environment);
|
||||
strv_free(arg_property);
|
||||
strv_free(arg_timer_property);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
return r < 0 ? EXIT_FAILURE : retval;
|
||||
}
|
||||
|
|
|
@ -1016,19 +1016,19 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
|
|||
return r;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SD_BUS_TYPE_STRING: {
|
||||
const char *s;
|
||||
char **p = userdata;
|
||||
const char *s;
|
||||
|
||||
r = sd_bus_message_read_basic(m, type, &s);
|
||||
if (r < 0)
|
||||
break;
|
||||
return r;
|
||||
|
||||
if (isempty(s))
|
||||
break;
|
||||
s = NULL;
|
||||
|
||||
r = free_and_strdup(p, s);
|
||||
break;
|
||||
return free_and_strdup(p, s);
|
||||
}
|
||||
|
||||
case SD_BUS_TYPE_ARRAY: {
|
||||
|
@ -1037,13 +1037,12 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
|
|||
|
||||
r = bus_message_read_strv_extend(m, &l);
|
||||
if (r < 0)
|
||||
break;
|
||||
return r;
|
||||
|
||||
strv_free(*p);
|
||||
*p = l;
|
||||
l = NULL;
|
||||
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SD_BUS_TYPE_BOOLEAN: {
|
||||
|
@ -1052,57 +1051,48 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
|
|||
|
||||
r = sd_bus_message_read_basic(m, type, &b);
|
||||
if (r < 0)
|
||||
break;
|
||||
return r;
|
||||
|
||||
*p = b;
|
||||
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SD_BUS_TYPE_INT32:
|
||||
case SD_BUS_TYPE_UINT32: {
|
||||
uint32_t u;
|
||||
uint32_t *p = userdata;
|
||||
uint32_t u, *p = userdata;
|
||||
|
||||
r = sd_bus_message_read_basic(m, type, &u);
|
||||
if (r < 0)
|
||||
break;
|
||||
return r;
|
||||
|
||||
*p = u;
|
||||
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SD_BUS_TYPE_INT64:
|
||||
case SD_BUS_TYPE_UINT64: {
|
||||
uint64_t t;
|
||||
uint64_t *p = userdata;
|
||||
uint64_t t, *p = userdata;
|
||||
|
||||
r = sd_bus_message_read_basic(m, type, &t);
|
||||
if (r < 0)
|
||||
break;
|
||||
return r;
|
||||
|
||||
*p = t;
|
||||
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SD_BUS_TYPE_DOUBLE: {
|
||||
double d;
|
||||
double *p = userdata;
|
||||
double d, *p = userdata;
|
||||
|
||||
r = sd_bus_message_read_basic(m, type, &d);
|
||||
if (r < 0)
|
||||
break;
|
||||
return r;
|
||||
|
||||
*p = d;
|
||||
return 0;
|
||||
}}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int bus_message_map_all_properties(
|
||||
|
@ -1240,12 +1230,13 @@ int bus_map_all_properties(
|
|||
return bus_message_map_all_properties(m, map, userdata);
|
||||
}
|
||||
|
||||
int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
|
||||
int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
||||
assert(transport >= 0);
|
||||
assert(transport < _BUS_TRANSPORT_MAX);
|
||||
assert(bus);
|
||||
assert(ret);
|
||||
|
||||
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
|
||||
assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
|
||||
|
@ -1254,25 +1245,34 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
|
|||
|
||||
case BUS_TRANSPORT_LOCAL:
|
||||
if (user)
|
||||
r = sd_bus_default_user(bus);
|
||||
r = sd_bus_default_user(&bus);
|
||||
else
|
||||
r = sd_bus_default_system(bus);
|
||||
r = sd_bus_default_system(&bus);
|
||||
|
||||
break;
|
||||
|
||||
case BUS_TRANSPORT_REMOTE:
|
||||
r = sd_bus_open_system_remote(bus, host);
|
||||
r = sd_bus_open_system_remote(&bus, host);
|
||||
break;
|
||||
|
||||
case BUS_TRANSPORT_MACHINE:
|
||||
r = sd_bus_open_system_machine(bus, host);
|
||||
r = sd_bus_open_system_machine(&bus, host);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Hmm, unknown transport type.");
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return r;
|
||||
r = sd_bus_set_exit_on_disconnect(bus, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = bus;
|
||||
bus = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
|
||||
|
|
|
@ -68,6 +68,8 @@ struct PTYForward {
|
|||
|
||||
bool read_from_master:1;
|
||||
|
||||
bool done:1;
|
||||
|
||||
bool last_char_set:1;
|
||||
char last_char;
|
||||
|
||||
|
@ -76,10 +78,54 @@ struct PTYForward {
|
|||
|
||||
usec_t escape_timestamp;
|
||||
unsigned escape_counter;
|
||||
|
||||
PTYForwardHandler handler;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
#define ESCAPE_USEC (1*USEC_PER_SEC)
|
||||
|
||||
static void pty_forward_disconnect(PTYForward *f) {
|
||||
|
||||
if (f) {
|
||||
f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
|
||||
f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
|
||||
|
||||
f->master_event_source = sd_event_source_unref(f->master_event_source);
|
||||
f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
|
||||
f->event = sd_event_unref(f->event);
|
||||
|
||||
if (f->saved_stdout)
|
||||
tcsetattr(STDOUT_FILENO, TCSANOW, &f->saved_stdout_attr);
|
||||
if (f->saved_stdin)
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &f->saved_stdin_attr);
|
||||
|
||||
f->saved_stdout = f->saved_stdin = false;
|
||||
}
|
||||
|
||||
/* STDIN/STDOUT should not be nonblocking normally, so let's unconditionally reset it */
|
||||
fd_nonblock(STDIN_FILENO, false);
|
||||
fd_nonblock(STDOUT_FILENO, false);
|
||||
}
|
||||
|
||||
static int pty_forward_done(PTYForward *f, int rcode) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||
assert(f);
|
||||
|
||||
if (f->done)
|
||||
return 0;
|
||||
|
||||
e = sd_event_ref(f->event);
|
||||
|
||||
f->done = true;
|
||||
pty_forward_disconnect(f);
|
||||
|
||||
if (f->handler)
|
||||
return f->handler(f, rcode, f->userdata);
|
||||
else
|
||||
return sd_event_exit(e, rcode < 0 ? EXIT_FAILURE : rcode);
|
||||
}
|
||||
|
||||
static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
|
||||
const char *p;
|
||||
|
||||
|
@ -147,7 +193,7 @@ static int shovel(PTYForward *f) {
|
|||
f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
|
||||
} else {
|
||||
log_error_errno(errno, "read(): %m");
|
||||
return sd_event_exit(f->event, EXIT_FAILURE);
|
||||
return pty_forward_done(f, -errno);
|
||||
}
|
||||
} else if (k == 0) {
|
||||
/* EOF on stdin */
|
||||
|
@ -156,12 +202,10 @@ static int shovel(PTYForward *f) {
|
|||
|
||||
f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
|
||||
} else {
|
||||
/* Check if ^] has been
|
||||
* pressed three times within
|
||||
* one second. If we get this
|
||||
* we quite immediately. */
|
||||
/* Check if ^] has been pressed three times within one second. If we get this we quite
|
||||
* immediately. */
|
||||
if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k))
|
||||
return sd_event_exit(f->event, EXIT_FAILURE);
|
||||
return pty_forward_done(f, -ECANCELED);
|
||||
|
||||
f->in_buffer_full += (size_t) k;
|
||||
}
|
||||
|
@ -181,7 +225,7 @@ static int shovel(PTYForward *f) {
|
|||
f->master_event_source = sd_event_source_unref(f->master_event_source);
|
||||
} else {
|
||||
log_error_errno(errno, "write(): %m");
|
||||
return sd_event_exit(f->event, EXIT_FAILURE);
|
||||
return pty_forward_done(f, -errno);
|
||||
}
|
||||
} else {
|
||||
assert(f->in_buffer_full >= (size_t) k);
|
||||
|
@ -211,7 +255,7 @@ static int shovel(PTYForward *f) {
|
|||
f->master_event_source = sd_event_source_unref(f->master_event_source);
|
||||
} else {
|
||||
log_error_errno(errno, "read(): %m");
|
||||
return sd_event_exit(f->event, EXIT_FAILURE);
|
||||
return pty_forward_done(f, -errno);
|
||||
}
|
||||
} else {
|
||||
f->read_from_master = true;
|
||||
|
@ -232,7 +276,7 @@ static int shovel(PTYForward *f) {
|
|||
f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
|
||||
} else {
|
||||
log_error_errno(errno, "write(): %m");
|
||||
return sd_event_exit(f->event, EXIT_FAILURE);
|
||||
return pty_forward_done(f, -errno);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -255,7 +299,7 @@ static int shovel(PTYForward *f) {
|
|||
|
||||
if ((f->out_buffer_full <= 0 || f->stdout_hangup) &&
|
||||
(f->in_buffer_full <= 0 || f->master_hangup))
|
||||
return sd_event_exit(f->event, EXIT_SUCCESS);
|
||||
return pty_forward_done(f, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -418,27 +462,8 @@ int pty_forward_new(
|
|||
}
|
||||
|
||||
PTYForward *pty_forward_free(PTYForward *f) {
|
||||
|
||||
if (f) {
|
||||
sd_event_source_unref(f->stdin_event_source);
|
||||
sd_event_source_unref(f->stdout_event_source);
|
||||
sd_event_source_unref(f->master_event_source);
|
||||
sd_event_source_unref(f->sigwinch_event_source);
|
||||
sd_event_unref(f->event);
|
||||
|
||||
if (f->saved_stdout)
|
||||
tcsetattr(STDOUT_FILENO, TCSANOW, &f->saved_stdout_attr);
|
||||
if (f->saved_stdin)
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &f->saved_stdin_attr);
|
||||
|
||||
free(f);
|
||||
}
|
||||
|
||||
/* STDIN/STDOUT should not be nonblocking normally, so let's
|
||||
* unconditionally reset it */
|
||||
fd_nonblock(STDIN_FILENO, false);
|
||||
fd_nonblock(STDOUT_FILENO, false);
|
||||
|
||||
pty_forward_disconnect(f);
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -477,8 +502,21 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pty_forward_get_ignore_vhangup(PTYForward *f) {
|
||||
bool pty_forward_get_ignore_vhangup(PTYForward *f) {
|
||||
assert(f);
|
||||
|
||||
return !!(f->flags & PTY_FORWARD_IGNORE_VHANGUP);
|
||||
}
|
||||
|
||||
bool pty_forward_is_done(PTYForward *f) {
|
||||
assert(f);
|
||||
|
||||
return f->done;
|
||||
}
|
||||
|
||||
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata) {
|
||||
assert(f);
|
||||
|
||||
f->handler = cb;
|
||||
f->userdata = userdata;
|
||||
}
|
||||
|
|
|
@ -37,12 +37,18 @@ typedef enum PTYForwardFlags {
|
|||
PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4,
|
||||
} PTYForwardFlags;
|
||||
|
||||
typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void*userdata);
|
||||
|
||||
int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f);
|
||||
PTYForward *pty_forward_free(PTYForward *f);
|
||||
|
||||
int pty_forward_get_last_char(PTYForward *f, char *ch);
|
||||
|
||||
int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup);
|
||||
int pty_forward_get_ignore_vhangup(PTYForward *f);
|
||||
bool pty_forward_get_ignore_vhangup(PTYForward *f);
|
||||
|
||||
bool pty_forward_is_done(PTYForward *f);
|
||||
|
||||
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *userdata);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);
|
||||
|
|
|
@ -137,6 +137,7 @@ const SystemCallFilterSet syscall_filter_sets[] = {
|
|||
"execve\0"
|
||||
"exit\0"
|
||||
"exit_group\0"
|
||||
"getrlimit\0" /* make sure processes can query stack size and such */
|
||||
"rt_sigreturn\0"
|
||||
"sigreturn\0"
|
||||
}, {
|
||||
|
|
|
@ -147,6 +147,8 @@ int sd_bus_can_send(sd_bus *bus, char type);
|
|||
int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *creds_mask);
|
||||
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_start(sd_bus *ret);
|
||||
|
||||
|
@ -438,8 +440,14 @@ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m);
|
|||
int sd_bus_track_add_name(sd_bus_track *track, const char *name);
|
||||
int sd_bus_track_remove_name(sd_bus_track *track, const char *name);
|
||||
|
||||
int sd_bus_track_set_recursive(sd_bus_track *track, int b);
|
||||
int sd_bus_track_get_recursive(sd_bus_track *track);
|
||||
|
||||
unsigned sd_bus_track_count(sd_bus_track *track);
|
||||
const char* sd_bus_track_contains(sd_bus_track *track, const char *names);
|
||||
int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m);
|
||||
int sd_bus_track_count_name(sd_bus_track *track, const char *name);
|
||||
|
||||
const char* sd_bus_track_contains(sd_bus_track *track, const char *name);
|
||||
const char* sd_bus_track_first(sd_bus_track *track);
|
||||
const char* sd_bus_track_next(sd_bus_track *track);
|
||||
|
||||
|
|
Loading…
Reference in a new issue