chiark / gitweb /
core: convert PID 1 to libsystemd-bus
authorLennart Poettering <lennart@poettering.net>
Tue, 19 Nov 2013 20:12:59 +0000 (21:12 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 20 Nov 2013 19:52:36 +0000 (20:52 +0100)
This patch converts PID 1 to libsystemd-bus and thus drops the
dependency on libdbus. The only remaining code using libdbus is a test
case that validates our bus marshalling against libdbus' marshalling,
and this dependency can be turned off.

This patch also adds a couple of things to libsystem-bus, that are
necessary to make the port work:

- Synthesizing of "Disconnected" messages when bus connections are
  severed.

- Support for attaching multiple vtables for the same interface on the
  same path.

This patch also fixes the SetDefaultTarget() and GetDefaultTarget() bus
calls which used an inappropriate signature.

As a side effect we will now generate PropertiesChanged messages which
carry property contents, rather than just invalidation information.

106 files changed:
Makefile.am
TODO
src/core/automount.c
src/core/automount.h
src/core/dbus-automount.c
src/core/dbus-automount.h
src/core/dbus-cgroup.c
src/core/dbus-cgroup.h
src/core/dbus-client-track.c [new file with mode: 0644]
src/core/dbus-client-track.h [new file with mode: 0644]
src/core/dbus-device.c
src/core/dbus-device.h
src/core/dbus-execute.c
src/core/dbus-execute.h
src/core/dbus-job.c
src/core/dbus-job.h
src/core/dbus-kill.c
src/core/dbus-kill.h
src/core/dbus-manager.c
src/core/dbus-manager.h
src/core/dbus-mount.c
src/core/dbus-mount.h
src/core/dbus-path.c
src/core/dbus-path.h
src/core/dbus-scope.c
src/core/dbus-scope.h
src/core/dbus-service.c
src/core/dbus-service.h
src/core/dbus-slice.c
src/core/dbus-slice.h
src/core/dbus-snapshot.c
src/core/dbus-snapshot.h
src/core/dbus-socket.c
src/core/dbus-socket.h
src/core/dbus-swap.c
src/core/dbus-swap.h
src/core/dbus-target.c
src/core/dbus-target.h
src/core/dbus-timer.c
src/core/dbus-timer.h
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/dbus.c
src/core/dbus.h
src/core/device.c
src/core/device.h
src/core/job.c
src/core/job.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/mount.c
src/core/mount.h
src/core/path.c
src/core/path.h
src/core/scope.c
src/core/scope.h
src/core/selinux-access.c
src/core/selinux-access.h
src/core/service.c
src/core/service.h
src/core/slice.c
src/core/snapshot.c
src/core/snapshot.h
src/core/socket.c
src/core/socket.h
src/core/swap.c
src/core/swap.h
src/core/target.c
src/core/timer.c
src/core/timer.h
src/core/transaction.c
src/core/transaction.h
src/core/unit.c
src/core/unit.h
src/libsystemd-bus/bus-error.h
src/libsystemd-bus/bus-internal.h
src/libsystemd-bus/bus-introspect.c
src/libsystemd-bus/bus-introspect.h
src/libsystemd-bus/bus-message.c
src/libsystemd-bus/bus-objects.c
src/libsystemd-bus/bus-signature.c
src/libsystemd-bus/bus-util.c
src/libsystemd-bus/bus-util.h
src/libsystemd-bus/sd-bus.c
src/libsystemd-bus/sd-event.c
src/libsystemd-bus/test-bus-introspect.c
src/libsystemd-bus/test-bus-marshal.c
src/login/logind-dbus.c
src/login/logind-inhibit.c
src/login/logind-seat-dbus.c
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind.c
src/machine/machined-dbus.c
src/shared/bus-errors.h [new file with mode: 0644]
src/shared/dbus-common.c [deleted file]
src/shared/dbus-common.h [deleted file]
src/shared/install.c
src/shared/install.h
src/shared/prioq.c
src/systemctl/systemctl.c
src/systemd/sd-bus.h
src/systemd/sd-event.h

index 82e46a9..f7fe96c 100644 (file)
@@ -662,16 +662,19 @@ libsystemd_shared_la_SOURCES = \
        src/shared/linux/fanotify.h \
        src/shared/linux/seccomp.h \
        src/shared/linux/seccomp-bpf.h \
+       src/shared/ioprio.h \
        src/shared/missing.h \
        src/shared/list.h \
        src/shared/macro.h \
        src/shared/def.h \
+       src/shared/sparse-endian.h \
+       src/shared/refcnt.h \
+       src/shared/udev-util.h \
+       src/shared/bus-errors.h \
        src/shared/device-nodes.c \
        src/shared/device-nodes.h \
-       src/shared/sparse-endian.h \
        src/shared/util.c \
        src/shared/util.h \
-       src/shared/udev-util.h \
        src/shared/virt.c \
        src/shared/virt.h \
        src/shared/efivars.c \
@@ -712,7 +715,6 @@ libsystemd_shared_la_SOURCES = \
        src/shared/gunicode.h \
        src/shared/pager.c \
        src/shared/pager.h \
-       src/shared/ioprio.h \
        src/shared/socket-util.c \
        src/shared/socket-util.h \
        src/shared/conf-files.c \
@@ -748,7 +750,6 @@ libsystemd_shared_la_SOURCES = \
        src/shared/acpi-fpdt.c \
        src/shared/boot-timestamps.h \
        src/shared/boot-timestamps.c \
-       src/shared/refcnt.h \
        src/shared/mkdir.c \
        src/shared/mkdir.h \
        src/shared/smack-util.c \
@@ -762,21 +763,6 @@ libsystemd_shared_la_SOURCES = \
        src/shared/net-util.c \
        src/shared/net-util.h
 
-#-------------------------------------------------------------------------------
-noinst_LTLIBRARIES += \
-       libsystemd-dbus.la
-
-libsystemd_dbus_la_SOURCES = \
-       src/shared/dbus-common.c \
-       src/shared/dbus-common.h
-
-libsystemd_dbus_la_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
-libsystemd_dbus_la_LIBADD = \
-       $(DBUS_LIBS)
-
 # ------------------------------------------------------------------------------
 noinst_LTLIBRARIES += \
        libsystemd-units.la
@@ -792,8 +778,7 @@ libsystemd_units_la_SOURCES = \
        src/shared/specifier.h
 
 libsystemd_units_la_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
+       $(AM_CFLAGS)
 
 # ------------------------------------------------------------------------------
 noinst_LTLIBRARIES += \
@@ -953,6 +938,8 @@ libsystemd_core_la_SOURCES = \
        src/core/dbus-kill.h \
        src/core/dbus-cgroup.c \
        src/core/dbus-cgroup.h \
+       src/core/dbus-client-track.c \
+       src/core/dbus-client-track.h \
        src/core/cgroup.c \
        src/core/cgroup.h \
        src/core/selinux-access.c \
@@ -982,7 +969,6 @@ libsystemd_core_la_SOURCES = \
        src/core/securebits.h \
        src/core/initreq.h \
        src/core/special.h \
-       src/core/bus-errors.h \
        src/core/build.h \
        src/core/sysfs-show.h \
        src/core/switch-root.h \
@@ -1010,7 +996,6 @@ nodist_libsystemd_core_la_SOURCES = \
 
 libsystemd_core_la_CFLAGS = \
        $(AM_CFLAGS) \
-       $(DBUS_CFLAGS) \
        $(LIBWRAP_CFLAGS) \
        $(PAM_CFLAGS) \
        $(AUDIT_CFLAGS) \
@@ -1021,13 +1006,13 @@ libsystemd_core_la_LIBADD = \
        libsystemd-capability.la \
        libsystemd-units.la \
        libsystemd-label.la \
-       libsystemd-dbus.la \
        libsystemd-audit.la \
        libsystemd-id128-internal.la \
        libsystemd-daemon-internal.la \
        libudev-internal.la \
        libsystemd-shared.la \
        libsystemd-rtnl.la \
+       libsystemd-bus-internal.la \
        $(LIBWRAP_LIBS) \
        $(PAM_LIBS) \
        $(AUDIT_LIBS) \
@@ -1072,10 +1057,6 @@ src/core/syscall-to-name.h: src/core/syscall-list.txt Makefile
 systemd_SOURCES = \
        src/core/main.c
 
-systemd_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 systemd_LDADD = \
        libsystemd-core.la \
        $(RT_LIBS)
@@ -1166,10 +1147,6 @@ test_device_nodes_LDADD = \
 test_engine_SOURCES = \
        src/test/test-engine.c
 
-test_engine_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_engine_LDADD = \
        libsystemd-core.la \
        $(RT_LIBS)
@@ -1177,10 +1154,6 @@ test_engine_LDADD = \
 test_job_type_SOURCES = \
        src/test/test-job-type.c
 
-test_job_type_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_job_type_LDADD = \
        libsystemd-core.la \
        $(RT_LIBS)
@@ -1191,10 +1164,6 @@ test_ns_SOURCES = \
 test_ns_LDADD = \
        libsystemd-core.la
 
-test_ns_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_loopback_SOURCES = \
        src/test/test-loopback.c
 
@@ -1221,10 +1190,6 @@ endif
 test_unit_name_SOURCES = \
        src/test/test-unit-name.c
 
-test_unit_name_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_unit_name_LDADD = \
        libsystemd-core.la \
        $(RT_LIBS)
@@ -1232,10 +1197,6 @@ test_unit_name_LDADD = \
 test_unit_file_SOURCES = \
        src/test/test-unit-file.c
 
-test_unit_file_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_unit_file_LDADD = \
        libsystemd-core.la \
        $(RT_LIBS)
@@ -1274,10 +1235,6 @@ test_tables_SOURCES = \
        src/test/test-tables.c \
        src/shared/test-tables.h
 
-test_tables_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_tables_LDADD = \
        libsystemd-logs.la \
        libsystemd-journal-internal.la \
@@ -1401,10 +1358,6 @@ test_strxcpyx_LDADD = \
 test_install_SOURCES = \
        src/test/test-install.c
 
-test_install_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 test_install_LDADD = \
        libsystemd-units.la \
        libsystemd-label.la \
@@ -1422,7 +1375,6 @@ test_sched_prio_SOURCES = \
 
 test_sched_prio_CFLAGS = \
        $(AM_CFLAGS) \
-       $(DBUS_CFLAGS) \
        -D"STR(s)=\#s" -D"TEST_DIR=STR($(abs_top_srcdir)/test/)"
 
 test_sched_prio_LDADD = \
@@ -2800,9 +2752,6 @@ mtd_probe_SOURCES =  \
        src/udev/mtd_probe/mtd_probe.h \
        src/udev/mtd_probe/probe_smartmedia.c
 
-mtd_probe_CPPFLAGS = \
-       $(AM_CPPFLAGS)
-
 dist_udevrules_DATA += \
        rules/75-probe_mtd.rules
 
@@ -3893,7 +3842,6 @@ systemd_logind_LDADD = \
 
 libsystemd_logind_core_la_SOURCES = \
        src/login/logind-core.c \
-       src/login/logind-dbus.c \
        src/login/logind-device.c \
        src/login/logind-device.h \
        src/login/logind-button.c \
@@ -3910,6 +3858,7 @@ libsystemd_logind_core_la_SOURCES = \
        src/login/logind-user.h \
        src/login/logind-inhibit.c \
        src/login/logind-inhibit.h \
+       src/login/logind-dbus.c \
        src/login/logind-session-dbus.c \
        src/login/logind-seat-dbus.c \
        src/login/logind-user-dbus.c \
diff --git a/TODO b/TODO
index efc7e2a..e387486 100644 (file)
--- a/TODO
+++ b/TODO
@@ -43,6 +43,53 @@ CGroup Rework Completion:
 
 Features:
 
+* sd-event: allow multiple signal handlers per signal
+
+* timer: expose accuracy as unit setting
+
+* sd-event: do per-minute coalescing of timer events too
+
+* when we detect low battery and no AC on boot, show pretty splash and refuse boot
+
+* move libasyncns into systemd as libsystemd-asyncns
+
+* calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1
+
+* pid1 porting:
+  - restore selinux access control on properties
+
+* sd-bus: when triggering property change events, allow a NULL strv indicate that all properties listed as such are send out as changed
+
+* sd-bus: enforce signatures on response messages
+
+* sd-bus: make message handlers take an sd_bus_error and generate error replies automatically if they are set
+
+* sd-bus: when replying to a bus message we should not need to specify the bus again
+
+* sd-bus: see if we can drop more message validation on the sending side
+
+* sd-bus: introduce sd_bus_creds object and attach it to messages as well as allow querying it for names
+
+* sd-bus: support "const" properties as flag
+
+* sd-bus: add api call to escape bus path components
+
+* sd-event: when a handler returns an error, just turn off its event
+  source, but do not return anything up to the event loop
+  caller. Instead add parameter to sd_event_request_quit() to take
+  retval. This way errors rippling upwards are the option, not the
+  default
+
+* sd-event: child pid handling: first invoke waitid(WNOHANG) and call event handler, only afterwards reap the process
+
+* sd-event: native support for watchdog stuff
+
+* machined, localed: when we try to kill an empty cgroup, generate an ESRCH call over the bus
+
+* sd-bus: SD_BUS_COMMENT() macro for inclusion in vtables, syntax inspired by gdbus
+
+* libsystemd-journal, libsystemd-login, libudev: add calls to easily attach these objects to sd-event event loops
+
 * be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1
 
 * check :no-sender logic after PID 1 conversion
index d1379e0..49a64b1 100644 (file)
 #include "load-fragment.h"
 #include "load-dropin.h"
 #include "unit-name.h"
-#include "dbus-automount.h"
-#include "bus-errors.h"
 #include "special.h"
 #include "label.h"
 #include "mkdir.h"
 #include "path-util.h"
-#include "dbus-common.h"
+#include "dbus-automount.h"
+#include "bus-util.h"
+#include "bus-error.h"
 
 static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
         [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
@@ -51,6 +51,7 @@ static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
 };
 
 static int open_dev_autofs(Manager *m);
+static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
 
 static void automount_init(Unit *u) {
         Automount *a = AUTOMOUNT(u);
@@ -58,11 +59,8 @@ static void automount_init(Unit *u) {
         assert(u);
         assert(u->load_state == UNIT_STUB);
 
-        a->pipe_watch.fd = a->pipe_fd = -1;
-        a->pipe_watch.type = WATCH_INVALID;
-
+        a->pipe_fd = -1;
         a->directory_mode = 0755;
-
         UNIT(a)->ignore_on_isolate = true;
 }
 
@@ -91,7 +89,8 @@ static void unmount_autofs(Automount *a) {
 
         automount_send_ready(a, -EHOSTDOWN);
 
-        unit_unwatch_fd(UNIT(a), &a->pipe_watch);
+        a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
+
         close_nointr_nofail(a->pipe_fd);
         a->pipe_fd = -1;
 
@@ -257,7 +256,7 @@ static int automount_coldplug(Unit *u) {
 
                         assert(a->pipe_fd >= 0);
 
-                        r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch);
+                        r = sd_event_add_io(u->manager->event, a->pipe_fd, EPOLLIN, automount_dispatch_io, u, &a->pipe_event_source);
                         if (r < 0)
                                 return r;
                 }
@@ -532,7 +531,7 @@ static void automount_enter_waiting(Automount *a) {
         close_nointr_nofail(ioctl_fd);
         ioctl_fd = -1;
 
-        r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch);
+        r = sd_event_add_io(UNIT(a)->manager->event, p[0], EPOLLIN, automount_dispatch_io, a, &a->pipe_event_source);
         if (r < 0)
                 goto fail;
 
@@ -558,14 +557,12 @@ fail:
 }
 
 static void automount_enter_runnning(Automount *a) {
-        _cleanup_dbus_error_free_ DBusError error;
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         struct stat st;
         int r;
 
         assert(a);
 
-        dbus_error_init(&error);
-
         /* We don't take mount requests anymore if we are supposed to
          * shut down anyway */
         if (unit_stop_pending(UNIT(a))) {
@@ -593,7 +590,7 @@ static void automount_enter_runnning(Automount *a) {
                 if (r < 0) {
                         log_warning_unit(UNIT(a)->id,
                                          "%s failed to queue mount startup job: %s",
-                                         UNIT(a)->id, bus_error(&error, r));
+                                         UNIT(a)->id, bus_error_message(&error, r));
                         goto fail;
                 }
         }
@@ -748,9 +745,9 @@ static bool automount_check_gc(Unit *u) {
         return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u));
 }
 
-static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
-        Automount *a = AUTOMOUNT(u);
+static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
         union autofs_v5_packet_union packet;
+        Automount *a = AUTOMOUNT(userdata);
         ssize_t l;
         int r;
 
@@ -758,13 +755,13 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
         assert(fd == a->pipe_fd);
 
         if (events != EPOLLIN) {
-                log_error_unit(u->id, "Got invalid poll event on pipe.");
+                log_error_unit(UNIT(a)->id, "Got invalid poll event on pipe.");
                 goto fail;
         }
 
         l = loop_read(a->pipe_fd, &packet, sizeof(packet), true);
         if (l != sizeof(packet)) {
-                log_error_unit(u->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
+                log_error_unit(UNIT(a)->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
                 goto fail;
         }
 
@@ -776,21 +773,21 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
                         _cleanup_free_ char *p = NULL;
 
                         get_process_comm(packet.v5_packet.pid, &p);
-                        log_debug_unit(u->id,
+                        log_debug_unit(UNIT(a)->id,
                                        "Got direct mount request on %s, triggered by %lu (%s)",
                                        a->where, (unsigned long) packet.v5_packet.pid, strna(p));
                 } else
-                        log_debug_unit(u->id, "Got direct mount request on %s", a->where);
+                        log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where);
 
                 r = set_ensure_allocated(&a->tokens, trivial_hash_func, trivial_compare_func);
                 if (r < 0) {
-                        log_error_unit(u->id, "Failed to allocate token set.");
+                        log_error_unit(UNIT(a)->id, "Failed to allocate token set.");
                         goto fail;
                 }
 
                 r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
                 if (r < 0) {
-                        log_error_unit(u->id, "Failed to remember token: %s", strerror(-r));
+                        log_error_unit(UNIT(a)->id, "Failed to remember token: %s", strerror(-r));
                         goto fail;
                 }
 
@@ -798,14 +795,15 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
                 break;
 
         default:
-                log_error_unit(u->id, "Received unknown automount request %i", packet.hdr.type);
+                log_error_unit(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type);
                 break;
         }
 
-        return;
+        return 0;
 
 fail:
         automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
+        return 0;
 }
 
 static void automount_shutdown(Manager *m) {
@@ -844,6 +842,7 @@ DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
 
 const UnitVTable automount_vtable = {
         .object_size = sizeof(Automount),
+
         .sections =
                 "Unit\0"
                 "Automount\0"
@@ -871,13 +870,11 @@ const UnitVTable automount_vtable = {
 
         .check_gc = automount_check_gc,
 
-        .fd_event = automount_fd_event,
-
         .reset_failed = automount_reset_failed,
 
         .bus_interface = "org.freedesktop.systemd1.Automount",
-        .bus_message_handler = bus_automount_message_handler,
-        .bus_invalidating_properties = bus_automount_invalidating_properties,
+        .bus_vtable = bus_automount_vtable,
+        .bus_changing_properties = bus_automount_changing_properties,
 
         .shutdown = automount_shutdown,
 
index a7a25d3..60f5522 100644 (file)
@@ -49,8 +49,8 @@ struct Automount {
         char *where;
 
         int pipe_fd;
+        sd_event_source *pipe_event_source;
         mode_t directory_mode;
-        Watch pipe_watch;
         dev_t dev_id;
 
         Set *tokens;
index 720f9ba..420cfaa 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <errno.h>
-
+#include "unit.h"
+#include "automount.h"
 #include "dbus-unit.h"
 #include "dbus-automount.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_AUTOMOUNT_INTERFACE                                      \
-        " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \
-        "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"
-
-#define INTROSPECTION                                                \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                    \
-        "<node>\n"                                                   \
-        BUS_UNIT_INTERFACE                                           \
-        BUS_AUTOMOUNT_INTERFACE                                      \
-        BUS_PROPERTIES_INTERFACE                                     \
-        BUS_PEER_INTERFACE                                           \
-        BUS_INTROSPECTABLE_INTERFACE                                 \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Automount\0"
-
-const char bus_automount_interface[] = BUS_AUTOMOUNT_INTERFACE;
+#include "bus-util.h"
 
-const char bus_automount_invalidating_properties[] =
-        "Result\0";
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult);
 
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_automount_append_automount_result, automount_result, AutomountResult);
-
-static const BusProperty bus_automount_properties[] = {
-        { "Where",         bus_property_append_string, "s", offsetof(Automount, where),    true },
-        { "DirectoryMode", bus_property_append_mode,   "u", offsetof(Automount, directory_mode) },
-        { "Result",        bus_automount_append_automount_result, "s", offsetof(Automount, result) },
-        { NULL, }
+const sd_bus_vtable bus_automount_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), 0),
+        SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), 0),
+        SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_VTABLE_END
 };
 
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Automount *am = AUTOMOUNT(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",      bus_unit_properties,      u  },
-                { "org.freedesktop.systemd1.Automount", bus_automount_properties, am },
-                { NULL, }
-        };
-
-        SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
+const char* const bus_automount_changing_properties[] = {
+        "Result",
+        NULL
+};
index b338e25..0b96183 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
+#include "sd-bus.h"
 
-#include "unit.h"
-
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_automount_interface[];
-extern const char bus_automount_invalidating_properties[];
+extern const sd_bus_vtable bus_automount_vtable[];
+extern const char* const bus_automount_changing_properties[];
index f198357..4dbb83a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
-
+#include "bus-util.h"
 #include "path-util.h"
+#include "cgroup-util.h"
+#include "cgroup.h"
 #include "dbus-cgroup.h"
 
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
+
+static int property_get_blockio_device_weight(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) {
-        DBusMessageIter sub, sub2;
-        CGroupContext *c = data;
+        CGroupContext *c = userdata;
         CGroupBlockIODeviceWeight *w;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
-                return -ENOMEM;
+        r = sd_bus_message_open_container(reply, 'a', "(st)");
+        if (r < 0)
+                return r;
 
         LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
-
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &w->path) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &w->weight) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
+                r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
+                if (r < 0)
+                        return r;
         }
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_close_container(reply);
 }
 
-static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) {
-        DBusMessageIter sub, sub2;
-        CGroupContext *c = data;
+static int property_get_blockio_device_bandwidths(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        CGroupContext *c = userdata;
         CGroupBlockIODeviceBandwidth *b;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
-                return -ENOMEM;
+        r = sd_bus_message_open_container(reply, 'a', "(st)");
+        if (r < 0)
+                return r;
 
         LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
 
                 if (streq(property, "BlockIOReadBandwidth") != b->read)
                         continue;
 
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &b->path) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &b->bandwidth) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
+                r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
+                if (r < 0)
+                        return r;
         }
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_close_container(reply);
 }
 
-static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) {
-        DBusMessageIter sub, sub2;
-        CGroupContext *c = data;
+static int property_get_device_allow(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        CGroupContext *c = userdata;
         CGroupDeviceAllow *a;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
-                return -ENOMEM;
+        r = sd_bus_message_open_container(reply, 'a', "(ss)");
+        if (r < 0)
+                return r;
 
         LIST_FOREACH(device_allow, a, c->device_allow) {
-                const char *rwm;
-                char buf[4];
                 unsigned k = 0;
+                char rwm[4];
 
                 if (a->r)
-                        buf[k++] = 'r';
+                        rwm[k++] = 'r';
                 if (a->w)
-                        buf[k++] = 'w';
+                        rwm[k++] = 'w';
                 if (a->m)
-                        buf[k++] = 'm';
+                        rwm[k++] = 'm';
 
-                buf[k] = 0;
-                rwm = buf;
+                rwm[k] = 0;
 
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->path) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &rwm) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
+                r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
+                if (r < 0)
+                        return r;
         }
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_close_container(reply);
 }
 
-const BusProperty bus_cgroup_context_properties[] = {
-        { "CPUAccounting",           bus_property_append_bool,            "b",     offsetof(CGroupContext, cpu_accounting)     },
-        { "CPUShares",               bus_property_append_ul,              "t",     offsetof(CGroupContext, cpu_shares)         },
-        { "BlockIOAccounting",       bus_property_append_bool,            "b",     offsetof(CGroupContext, blockio_accounting) },
-        { "BlockIOWeight",           bus_property_append_ul,              "t",     offsetof(CGroupContext, blockio_weight)     },
-        { "BlockIODeviceWeight",     bus_cgroup_append_device_weights,    "a(st)", 0                                           },
-        { "BlockIOReadBandwidth",    bus_cgroup_append_device_bandwidths, "a(st)", 0                                           },
-        { "BlockIOWriteBandwidth",   bus_cgroup_append_device_bandwidths, "a(st)", 0                                           },
-        { "MemoryAccounting",        bus_property_append_bool,            "b",     offsetof(CGroupContext, memory_accounting)  },
-        { "MemoryLimit",             bus_property_append_uint64,          "t",     offsetof(CGroupContext, memory_limit)       },
-        { "DevicePolicy",            bus_cgroup_append_device_policy,     "s",     offsetof(CGroupContext, device_policy)      },
-        { "DeviceAllow",             bus_cgroup_append_device_allow,      "a(ss)", 0                                           },
-        {}
+const sd_bus_vtable bus_cgroup_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
+        SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
+        SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
+        SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0),
+        SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
+        SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
+        SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
+        SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
+        SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
+        SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
+        SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
+        SD_BUS_VTABLE_END
 };
 
 int bus_cgroup_set_property(
                 Unit *u,
                 CGroupContext *c,
                 const char *name,
-                DBusMessageIter *i,
+                sd_bus_message *message,
                 UnitSetPropertiesMode mode,
-                DBusError *error) {
+                sd_bus_error *error) {
+
+        int r;
 
-        assert(name);
         assert(u);
         assert(c);
-        assert(i);
+        assert(name);
+        assert(message);
 
         if (streq(name, "CPUAccounting")) {
+                int b;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "b", &b);
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
-                        dbus_bool_t b;
-                        dbus_message_iter_get_basic(i, &b);
-
                         c->cpu_accounting = b;
                         unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
                 }
@@ -170,14 +182,13 @@ int bus_cgroup_set_property(
                 uint64_t u64;
                 unsigned long ul;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "t", &u64);
+                if (r < 0)
+                        return r;
 
-                dbus_message_iter_get_basic(i, &u64);
                 ul = (unsigned long) u64;
-
-                if (u64 <= 0 || u64 != (uint64_t) ul)
-                        return -EINVAL;
+                if (ul <= 0 || (uint64_t) ul != u64)
+                        return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
 
                 if (mode != UNIT_CHECK) {
                         c->cpu_shares = ul;
@@ -187,14 +198,13 @@ int bus_cgroup_set_property(
                 return 1;
 
         } else if (streq(name, "BlockIOAccounting")) {
+                int b;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "b", &b);
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
-                        dbus_bool_t b;
-                        dbus_message_iter_get_basic(i, &b);
-
                         c->blockio_accounting = b;
                         unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
                 }
@@ -205,14 +215,13 @@ int bus_cgroup_set_property(
                 uint64_t u64;
                 unsigned long ul;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "t", &u64);
+                if (r < 0)
+                        return r;
 
-                dbus_message_iter_get_basic(i, &u64);
                 ul = (unsigned long) u64;
-
-                if (u64 < 10 || u64 > 1000)
-                        return -EINVAL;
+                if (ul < 10 || ul > 1000)
+                        return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
 
                 if (mode != UNIT_CHECK) {
                         c->blockio_weight = ul;
@@ -222,42 +231,31 @@ int bus_cgroup_set_property(
                 return 1;
 
         } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
-                DBusMessageIter sub;
-                unsigned n = 0;
+                const char *path;
                 bool read = true;
+                unsigned n = 0;
+                uint64_t u64;
 
                 if (streq(name, "BlockIOWriteBandwidth"))
                         read = false;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
-                    dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
-                         return -EINVAL;
-
-                dbus_message_iter_recurse(i, &sub);
-                while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                        DBusMessageIter sub2;
-                        const char *path;
-                        uint64_t u64;
+                r = sd_bus_message_enter_container(message, 'a', "(st)");
+                if (r < 0)
+                        return r;
 
-                        dbus_message_iter_recurse(&sub, &sub2);
-                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
-                            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0)
-                                return -EINVAL;
+                while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
 
                         if (mode != UNIT_CHECK) {
-                                CGroupBlockIODeviceBandwidth *a = NULL;
-                                CGroupBlockIODeviceBandwidth *b;
-                                bool exist = false;
+                                CGroupBlockIODeviceBandwidth *a = NULL, *b;
 
                                 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
                                         if (path_equal(path, b->path) && read == b->read) {
                                                 a = b;
-                                                exist = true;
                                                 break;
                                         }
                                 }
 
-                                if (!exist) {
+                                if (!a) {
                                         a = new0(CGroupBlockIODeviceBandwidth, 1);
                                         if (!a)
                                                 return -ENOMEM;
@@ -268,23 +266,22 @@ int bus_cgroup_set_property(
                                                 free(a);
                                                 return -ENOMEM;
                                         }
+
+                                        LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
                                 }
 
                                 a->bandwidth = u64;
-
-                                if (!exist)
-                                        LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
                         }
 
                         n++;
-                        dbus_message_iter_next(&sub);
                 }
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
+                        CGroupBlockIODeviceBandwidth *a, *next;
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
-                        CGroupBlockIODeviceBandwidth *a;
-                        CGroupBlockIODeviceBandwidth *next;
                         size_t size = 0;
 
                         if (n == 0) {
@@ -316,44 +313,32 @@ int bus_cgroup_set_property(
                 return 1;
 
         } else if (streq(name, "BlockIODeviceWeight")) {
-                DBusMessageIter sub;
+                const char *path;
+                uint64_t u64;
                 unsigned n = 0;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
-                    dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
-                        return -EINVAL;
+                r = sd_bus_message_enter_container(message, 'a', "(st)");
+                if (r < 0)
+                        return r;
 
-                dbus_message_iter_recurse(i, &sub);
-                while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                        DBusMessageIter sub2;
-                        const char *path;
-                        uint64_t u64;
+                while (( r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
                         unsigned long ul;
 
-                        dbus_message_iter_recurse(&sub, &sub2);
-
-                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
-                            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0)
-                                return -EINVAL;
-
                         ul = (unsigned long) u64;
                         if (ul < 10 || ul > 1000)
-                                return -EINVAL;
+                                return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
 
                         if (mode != UNIT_CHECK) {
-                                CGroupBlockIODeviceWeight *a = NULL;
-                                CGroupBlockIODeviceWeight *b;
-                                bool exist = false;
+                                CGroupBlockIODeviceWeight *a = NULL, *b;
 
                                 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
                                         if (path_equal(b->path, path)) {
                                                 a = b;
-                                                exist = true;
                                                 break;
                                         }
                                 }
 
-                                if (!exist) {
+                                if (!a) {
                                         a = new0(CGroupBlockIODeviceWeight, 1);
                                         if (!a)
                                                 return -ENOMEM;
@@ -363,16 +348,13 @@ int bus_cgroup_set_property(
                                                 free(a);
                                                 return -ENOMEM;
                                         }
+                                        LIST_PREPEND(device_weights,c->blockio_device_weights, a);
                                 }
 
                                 a->weight = ul;
-
-                                if (!exist)
-                                        LIST_PREPEND(device_weights,c->blockio_device_weights, a);
                         }
 
                         n++;
-                        dbus_message_iter_next(&sub);
                 }
 
                 if (mode != UNIT_CHECK) {
@@ -401,14 +383,13 @@ int bus_cgroup_set_property(
                 return 1;
 
         } else if (streq(name, "MemoryAccounting")) {
+                int b;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "b", &b);
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
-                        dbus_bool_t b;
-                        dbus_message_iter_get_basic(i, &b);
-
                         c->memory_accounting = b;
                         unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
                 }
@@ -416,14 +397,13 @@ int bus_cgroup_set_property(
                 return 1;
 
         } else if (streq(name, "MemoryLimit")) {
+                uint64_t limit;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "t", &limit);
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
-                        uint64_t limit;
-                        dbus_message_iter_get_basic(i, &limit);
-
                         c->memory_limit = limit;
                         unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
                 }
@@ -434,10 +414,10 @@ int bus_cgroup_set_property(
                 const char *policy;
                 CGroupDevicePolicy p;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "s", &policy);
+                if (r < 0)
+                        return r;
 
-                dbus_message_iter_get_basic(i, &policy);
                 p = cgroup_device_policy_from_string(policy);
                 if (p < 0)
                         return -EINVAL;
@@ -454,51 +434,35 @@ int bus_cgroup_set_property(
                 return 1;
 
         } else if (streq(name, "DeviceAllow")) {
-                DBusMessageIter sub;
+                const char *path, *rwm;
                 unsigned n = 0;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
-                    dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT)
-                        return -EINVAL;
-
-                dbus_message_iter_recurse(i, &sub);
-                while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                        DBusMessageIter sub2;
-                        const char *path, *rwm;
+                r = sd_bus_message_enter_container(message, 'a', "(ss)");
+                if (r < 0)
+                        return r;
 
-                        dbus_message_iter_recurse(&sub, &sub2);
+                while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
 
-                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
-                            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0)
-                                return -EINVAL;
-
-                        if (!path_startswith(path, "/dev")) {
-                                dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
-                                return -EINVAL;
-                        }
+                        if (!path_startswith(path, "/dev"))
+                                return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
 
                         if (isempty(rwm))
                                 rwm = "rwm";
 
-                        if (!in_charset(rwm, "rwm")) {
-                                dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
-                                return -EINVAL;
-                        }
+                        if (!in_charset(rwm, "rwm"))
+                                return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
 
                         if (mode != UNIT_CHECK) {
-                                CGroupDeviceAllow *a = NULL;
-                                CGroupDeviceAllow *b;
-                                bool exist = false;
+                                CGroupDeviceAllow *a = NULL, *b;
 
                                 LIST_FOREACH(device_allow, b, c->device_allow) {
                                         if (path_equal(b->path, path)) {
                                                 a = b;
-                                                exist = true;
                                                 break;
                                         }
                                 }
 
-                                if (!exist) {
+                                if (!a) {
                                         a = new0(CGroupDeviceAllow, 1);
                                         if (!a)
                                                 return -ENOMEM;
@@ -508,18 +472,17 @@ int bus_cgroup_set_property(
                                                 free(a);
                                                 return -ENOMEM;
                                         }
+
+                                        LIST_PREPEND(device_allow, c->device_allow, a);
                                 }
 
                                 a->r = !!strchr(rwm, 'r');
                                 a->w = !!strchr(rwm, 'w');
                                 a->m = !!strchr(rwm, 'm');
 
-                                if (!exist)
-                                        LIST_PREPEND(device_allow, c->device_allow, a);
                         }
 
                         n++;
-                        dbus_message_iter_next(&sub);
                 }
 
                 if (mode != UNIT_CHECK) {
index e5ac4c3..c2a3910 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
-
-#include "manager.h"
-#include "dbus-common.h"
+#include "sd-bus.h"
 #include "cgroup.h"
 
-#define BUS_CGROUP_CONTEXT_INTERFACE                                    \
-        "  <property name=\"CPUAccounting\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"CPUShares\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"BlockIOAccounting\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"BlockIOWeight\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"BlockIODeviceWeight\" type=\"a(st)\" access=\"read\"/>\n" \
-        "  <property name=\"BlockIOReadBandwidth=\" type=\"a(st)\" access=\"read\"/>\n" \
-        "  <property name=\"BlockIOWriteBandwidth=\" type=\"a(st)\" access=\"read\"/>\n" \
-        "  <property name=\"MemoryAccounting\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"MemoryLimit\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"DevicePolicy\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"DeviceAllow\" type=\"a(ss)\" access=\"read\"/>\n"
-
-extern const BusProperty bus_cgroup_context_properties[];
-
-int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error);
+extern const sd_bus_vtable bus_cgroup_vtable[];
+
+int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/src/core/dbus-client-track.c b/src/core/dbus-client-track.c
new file mode 100644 (file)
index 0000000..ce514b5
--- /dev/null
@@ -0,0 +1,250 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 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 "dbus-client-track.h"
+
+static unsigned tracked_client_hash(const void *a) {
+        const BusTrackedClient *x = a;
+
+        return string_hash_func(x->name) ^ PTR_TO_UINT(x->bus);
+}
+
+static int tracked_client_compare(const void *a, const void *b) {
+        const BusTrackedClient *x = a, *y = b;
+        int r;
+
+        r = strcmp(x->name, y->name);
+        if (r != 0)
+                return r;
+
+        if (x->bus < y->bus)
+                return -1;
+        if (x->bus > y->bus)
+                return 1;
+
+        return 0;
+}
+
+static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        BusTrackedClient *c = userdata;
+        const char *name, *old, *new;
+        int r;
+
+        assert(bus);
+        assert(message);
+
+        r = sd_bus_message_read(message, "sss", &name, &old, &new);
+        if (r < 0) {
+                log_debug("Failed to parse NameOwnerChanged message.");
+                return 0;
+        }
+
+        bus_client_untrack(c->set, bus, name);
+        return 0;
+}
+
+static char *build_match(const char *name) {
+
+        return strjoin("type='signal',"
+                       "sender='org.freedesktop.DBus',"
+                       "path='/org/freedesktop/DBus',"
+                       "interface='org.freedesktop.DBus',"
+                       "member='NameOwnerChanged',"
+                       "arg0='", name, "'", NULL);
+}
+
+int bus_client_track(Set **s, sd_bus *bus, const char *name) {
+        BusTrackedClient *c, *found;
+        size_t l;
+        int r;
+
+        assert(s);
+        assert(bus);
+
+        r = set_ensure_allocated(s, tracked_client_hash, tracked_client_compare);
+        if (r < 0)
+                return r;
+
+        name = strempty(name);
+
+        l = strlen(name);
+
+        c = alloca(offsetof(BusTrackedClient, name) + l + 1);
+        c->set = *s;
+        c->bus = bus;
+        strcpy(c->name, name);
+
+        found = set_get(*s, c);
+        if (found)
+                return 0;
+
+        c = memdup(c, offsetof(BusTrackedClient, name) + l + 1);
+        if (!c)
+                return -ENOMEM;
+
+        r = set_put(*s, c);
+        if (r < 0) {
+                free(c);
+                return r;
+        }
+
+        if (!isempty(name)) {
+                _cleanup_free_ char *match = NULL;
+
+                match = build_match(name);
+                if (!match) {
+                        set_remove(*s, c);
+                        free(c);
+                        return -ENOMEM;
+                }
+
+                r = sd_bus_add_match(bus, match, on_name_owner_changed, c);
+                if (r < 0) {
+                        set_remove(*s, c);
+                        free(c);
+                        return r;
+                }
+        }
+
+        sd_bus_ref(c->bus);
+        return 1;
+}
+
+static void bus_client_free_one(Set *s, BusTrackedClient *c) {
+        assert(s);
+        assert(c);
+
+        if (!isempty(c->name)) {
+                _cleanup_free_ char *match = NULL;
+
+                match = build_match(c->name);
+                if (match)
+                        sd_bus_remove_match(c->bus, match, on_name_owner_changed, c);
+        }
+
+        sd_bus_unref(c->bus);
+        set_remove(s, c);
+        free(c);
+}
+
+int bus_client_untrack(Set *s, sd_bus *bus, const char *name) {
+        BusTrackedClient *c, *found;
+        size_t l;
+
+        assert(bus);
+        assert(s);
+        assert(name);
+
+        name = strempty(name);
+
+        l = strlen(name);
+
+        c = alloca(offsetof(BusTrackedClient, name) + l + 1);
+        c->bus = bus;
+        strcpy(c->name, name);
+
+        found = set_get(s, c);
+        if (!found)
+                return 0;
+
+        bus_client_free_one(s, found);
+        return 1;
+}
+
+void bus_client_track_free(Set *s) {
+        BusTrackedClient *c;
+
+        while ((c = set_first(s)))
+                bus_client_free_one(s, c);
+
+        set_free(s);
+}
+
+int bus_client_untrack_bus(Set *s, sd_bus *bus) {
+        BusTrackedClient *c;
+        Iterator i;
+        int r = 0;
+
+        SET_FOREACH(c, s, i)
+                if (c->bus == bus) {
+                        bus_client_free_one(s, c);
+                        r++;
+                }
+
+        return r;
+}
+
+void bus_client_track_serialize(Manager *m, FILE *f, Set *s) {
+        BusTrackedClient *c;
+        Iterator i;
+
+        assert(m);
+        assert(f);
+
+        SET_FOREACH(c, s, i) {
+                if (c->bus == m->api_bus)
+                        fprintf(f, "subscribed=%s", isempty(c->name) ? "*" : c->name);
+                else
+                        fprintf(f, "subscribed=%p %s", c->bus, isempty(c->name) ? "*" : c->name);
+        }
+}
+
+int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line) {
+        const char *e, *q, *name;
+        sd_bus *bus;
+        void *p;
+        int r;
+
+        e = startswith(line, "subscribed=");
+        if (!e)
+                return 0;
+
+        q = strpbrk(e, WHITESPACE);
+        if (!q) {
+                if (m->api_bus) {
+                        bus = m->api_bus;
+                        name = e;
+                        goto finish;
+                }
+
+                return 1;
+        }
+
+        if (sscanf(e, "%p", &p) != 1) {
+                log_debug("Failed to parse subscription pointer.");
+                return -EINVAL;
+        }
+
+        bus = set_get(m->private_buses, p);
+        if (!bus)
+                return 1;
+
+        name = q + strspn(q, WHITESPACE);
+
+finish:
+        r = bus_client_track(s, bus, streq(name, "*") ? NULL : name);
+        if (r < 0) {
+                log_debug("Failed to deserialize client subscription: %s", strerror(-r));
+                return r;
+        }
+
+        return 1;
+}
diff --git a/src/core/dbus-client-track.h b/src/core/dbus-client-track.h
new file mode 100644 (file)
index 0000000..0167647
--- /dev/null
@@ -0,0 +1,42 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 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 "set.h"
+#include "manager.h"
+
+typedef struct BusTrackedClient {
+        Set *set;
+        sd_bus *bus;
+        char name[0];
+} BusTrackedClient;
+
+int bus_client_track(Set **s, sd_bus *bus, const char *name);
+
+int bus_client_untrack(Set *s, sd_bus *bus, const char *name);
+int bus_client_untrack_bus(Set *s, sd_bus *bus);
+
+void bus_client_track_free(Set *s);
+
+void bus_client_track_serialize(Manager *m, FILE *f, Set *s);
+int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line);
index ef484a8..621bab0 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "unit.h"
+#include "device.h"
 #include "dbus-unit.h"
 #include "dbus-device.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
 
-#define BUS_DEVICE_INTERFACE                                            \
-        " <interface name=\"org.freedesktop.systemd1.Device\">\n"       \
-        "  <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>\n" \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_DEVICE_INTERFACE                                            \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Device\0"
-
-const char bus_device_interface[] = BUS_DEVICE_INTERFACE;
-
-const char bus_device_invalidating_properties[] =
-        "SysFSPath\0";
-
-static const BusProperty bus_device_properties[] = {
-        { "SysFSPath", bus_property_append_string, "s", offsetof(Device, sysfs), true },
-        { NULL, }
+const sd_bus_vtable bus_device_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("SysFSPath", "s", NULL, offsetof(Device, sysfs), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_VTABLE_END
 };
 
-
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Device *d = DEVICE(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",   bus_unit_properties,   u },
-                { "org.freedesktop.systemd1.Device", bus_device_properties, d },
-                { NULL, }
-        };
-
-        SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
+const char* const bus_device_changing_properties[] = {
+        "SysFSPath",
+        NULL
+};
index 311e068..f248c28 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
-
+#include "sd-bus.h"
 #include "unit.h"
 
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_device_interface[];
-extern const char bus_device_invalidating_properties[];
+extern const sd_bus_vtable bus_device_vtable[];
+extern const char* const bus_device_changing_properties[];
index 2402e8c..ca7ee5c 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <errno.h>
-#include <dbus/dbus.h>
 #include <sys/prctl.h>
 
-#include "dbus-execute.h"
+#include "bus-util.h"
 #include "missing.h"
 #include "ioprio.h"
 #include "strv.h"
-#include "dbus-common.h"
 #include "syscall-list.h"
 #include "fileio.h"
+#include "execute.h"
+#include "dbus-execute.h"
 
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
+BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
 
-static int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
-        char **env_files = data, **j;
-        DBusMessageIter sub, sub2;
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
 
-        assert(i);
-        assert(property);
+static int property_get_environment_files(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
-                return -ENOMEM;
+        ExecContext *c = userdata;
+        char **j;
+        int r;
 
-        STRV_FOREACH(j, env_files) {
-                dbus_bool_t b = false;
-                char *fn = *j;
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        r = sd_bus_message_open_container(reply, 'a', "(sb)");
+        if (r < 0)
+                return r;
 
-                if (fn[0] == '-') {
-                        b = true;
-                        fn++;
-                }
+        STRV_FOREACH(j, c->environment_files) {
+                const char *fn = *j;
 
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
+                r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
+                if (r < 0)
+                        return r;
         }
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
+        return sd_bus_message_close_container(reply);
+}
+
+static int property_get_rlimit(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        struct rlimit *rl;
+        uint64_t u;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
 
-        return 0;
+        rl = *(struct rlimit**) userdata;
+        if (rl)
+                u = (uint64_t) rl->rlim_max;
+        else {
+                struct rlimit buf = {};
+                int z;
+
+                z = rlimit_from_string(property);
+                assert(z >= 0);
+
+                getrlimit(z, &buf);
+
+                u = (uint64_t) buf.rlim_max;
+        }
+
+        return sd_bus_message_append(reply, "t", u);
 }
 
-static int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_oom_score_adjust(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+
+        ExecContext *c = userdata;
         int32_t n;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->oom_score_adjust_set)
@@ -80,80 +123,111 @@ static int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *p
                 _cleanup_free_ char *t = NULL;
 
                 n = 0;
-                if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
+                if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
                         safe_atoi(t, &n);
-                }
         }
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "i", n);
 }
 
-static int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_nice(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+
+        ExecContext *c = userdata;
         int32_t n;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->nice_set)
                 n = c->nice;
-        else
+        else {
+                errno = 0;
                 n = getpriority(PRIO_PROCESS, 0);
+                if (errno != 0)
+                        n = 0;
+        }
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "i", n);
 }
 
-static int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_ioprio(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+
+        ExecContext *c = userdata;
         int32_t n;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->ioprio_set)
                 n = c->ioprio;
-        else
+        else {
                 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
+                if (n < 0)
+                        n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
+        }
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "i", n);
 }
 
-static int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_cpu_sched_policy(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        ExecContext *c = userdata;
         int32_t n;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->cpu_sched_set)
                 n = c->cpu_sched_policy;
-        else
+        else {
                 n = sched_getscheduler(0);
+                if (n < 0)
+                        n = SCHED_OTHER;
+        }
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "i", n);
 }
 
-static int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_cpu_sched_priority(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        ExecContext *c = userdata;
         int32_t n;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->cpu_sched_set)
@@ -167,44 +241,44 @@ static int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char
                         n = 0;
         }
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "i", n);
 }
 
-static int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        dbus_bool_t b;
-        DBusMessageIter sub;
+static int property_get_cpu_affinity(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        assert(i);
-        assert(property);
-        assert(c);
+        ExecContext *c = userdata;
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
-                return -ENOMEM;
+        assert(bus);
+        assert(reply);
+        assert(c);
 
         if (c->cpuset)
-                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
+                return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
         else
-                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
-
-        if (!b)
-                return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+                return sd_bus_message_append_array(reply, 'y', NULL, 0);
 }
 
-static int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_timer_slack_nsec(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        ExecContext *c = userdata;
         uint64_t u;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->timer_slack_nsec != (nsec_t) -1)
@@ -212,37 +286,45 @@ static int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *p
         else
                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "t", u);
 }
 
-static int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        uint64_t normal, inverted;
+static int property_get_capability_bounding_set(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        assert(i);
-        assert(property);
+        ExecContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
         assert(c);
 
         /* We store this negated internally, to match the kernel, but
          * we expose it normalized. */
-
-        normal = *(uint64_t*) data;
-        inverted = ~normal;
-
-        return bus_property_append_uint64(i, property, &inverted);
+        return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
 }
 
-static int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
+static int property_get_capabilities(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        ExecContext *c = userdata;
         char *t = NULL;
         const char *s;
-        dbus_bool_t b;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(c);
 
         if (c->capabilities)
@@ -253,184 +335,150 @@ static int bus_execute_append_capabilities(DBusMessageIter *i, const char *prope
         if (!s)
                 return -ENOMEM;
 
-        b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
+        r = sd_bus_message_append(reply, "s", s);
 
         if (t)
                 cap_free(t);
 
-        if (!b)
-                return -ENOMEM;
-
-        return 0;
+        return r;
 }
 
-static int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int r;
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        assert_se((r = rlimit_from_string(property)) >= 0);
+static int property_get_syscall_filter(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        if (c->rlimit[r])
-                u = (uint64_t) c->rlimit[r]->rlim_max;
-        else {
-                struct rlimit rl = {};
+        ExecContext *c = userdata;
 
-                getrlimit(r, &rl);
+        assert(bus);
+        assert(reply);
+        assert(c);
 
-                u = (uint64_t) rl.rlim_max;
-        }
+        if (c->syscall_filter)
+                return sd_bus_message_append_array(reply, 'u', c->syscall_filter, (syscall_max() + 31) >> 4);
+        else
+                return sd_bus_message_append_array(reply, 'u', NULL, 0);
+}
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
+const sd_bus_vtable bus_exec_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), 0),
+        SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, 0),
+        SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), 0),
+        SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), 0),
+        SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), 0),
+        SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), 0),
+        SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), 0),
+        SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), 0),
+        SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), 0),
+        SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), 0),
+        SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), 0),
+        SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), 0),
+        SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), 0),
+        SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), 0),
+        SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), 0),
+        SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), 0),
+        SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), 0),
+        SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), 0),
+        SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), 0),
+        SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), 0),
+        SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), 0),
+        SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, 0),
+        SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, 0),
+        SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, 0),
+        SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, 0),
+        SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, 0),
+        SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, 0),
+        SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, 0),
+        SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), 0),
+        SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), 0),
+        SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), 0),
+        SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), 0),
+        SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), 0),
+        SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), 0),
+        SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), 0),
+        SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), 0),
+        SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), 0),
+        SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), 0),
+        SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), 0),
+        SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), 0),
+        SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, 0),
+        SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), 0),
+        SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, 0),
+        SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), 0),
+        SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), 0),
+        SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), 0),
+        SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), 0),
+        SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), 0),
+        SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), 0),
+        SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), 0),
+        SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), 0),
+        SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), 0),
+        SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), 0),
+        SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), 0),
+        SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), 0),
+        SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), 0),
+        SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), 0),
+        SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), 0),
+        SD_BUS_PROPERTY("SystemCallFilter", "au", property_get_syscall_filter, 0, 0),
+        SD_BUS_VTABLE_END
+};
 
-        return 0;
-}
+int bus_property_get_exec_command(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
-        ExecCommand *c = data;
-        DBusMessageIter sub, sub2, sub3;
+        ExecCommand *c = *(ExecCommand**) userdata;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
-                return -ENOMEM;
+        r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
+        if (r < 0)
+                return r;
 
         LIST_FOREACH(command, c, c) {
-                char **l;
-                uint32_t pid;
-                int32_t code, status;
-                dbus_bool_t b;
-
                 if (!c->path)
                         continue;
 
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
-                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
-                        return -ENOMEM;
-
-                STRV_FOREACH(l, c->argv)
-                        if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
-                                return -ENOMEM;
-
-                pid = (uint32_t) c->exec_status.pid;
-                code = (int32_t) c->exec_status.code;
-                status = (int32_t) c->exec_status.status;
-
-                b = !!c->ignore;
-
-                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
-                        return -ENOMEM;
-
-                if (!dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
+                r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(reply, "s", c->path);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append_strv(reply, c->argv);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(reply, "bttttuii",
+                                          c->ignore,
+                                          c->exec_status.start_timestamp.realtime,
+                                          c->exec_status.start_timestamp.monotonic,
+                                          c->exec_status.exit_timestamp.realtime,
+                                          c->exec_status.exit_timestamp.monotonic,
+                                          (uint32_t) c->exec_status.pid,
+                                          (int32_t) c->exec_status.code,
+                                          (int32_t) c->exec_status.status);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
         }
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        dbus_bool_t b;
-        DBusMessageIter sub;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "u", &sub))
-                return -ENOMEM;
-
-        if (c->syscall_filter)
-                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, (syscall_max() + 31) >> 4);
-        else
-                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, 0);
-
-        if (!b)
-                return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_close_container(reply);
 }
-
-const BusProperty bus_exec_context_properties[] = {
-        { "Environment",              bus_property_append_strv,             "as", offsetof(ExecContext, environment),            true },
-        { "EnvironmentFiles",         bus_execute_append_env_files,      "a(sb)", offsetof(ExecContext, environment_files),      true },
-        { "UMask",                    bus_property_append_mode,              "u", offsetof(ExecContext, umask)                        },
-        { "LimitCPU",                 bus_execute_append_rlimits,            "t", 0 },
-        { "LimitFSIZE",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitDATA",                bus_execute_append_rlimits,            "t", 0 },
-        { "LimitSTACK",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitCORE",                bus_execute_append_rlimits,            "t", 0 },
-        { "LimitRSS",                 bus_execute_append_rlimits,            "t", 0 },
-        { "LimitNOFILE",              bus_execute_append_rlimits,            "t", 0 },
-        { "LimitAS",                  bus_execute_append_rlimits,            "t", 0 },
-        { "LimitNPROC",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitMEMLOCK",             bus_execute_append_rlimits,            "t", 0 },
-        { "LimitLOCKS",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitSIGPENDING",          bus_execute_append_rlimits,            "t", 0 },
-        { "LimitMSGQUEUE",            bus_execute_append_rlimits,            "t", 0 },
-        { "LimitNICE",                bus_execute_append_rlimits,            "t", 0 },
-        { "LimitRTPRIO",              bus_execute_append_rlimits,            "t", 0 },
-        { "LimitRTTIME",              bus_execute_append_rlimits,            "t", 0 },
-        { "WorkingDirectory",         bus_property_append_string,            "s", offsetof(ExecContext, working_directory),      true },
-        { "RootDirectory",            bus_property_append_string,            "s", offsetof(ExecContext, root_directory),         true },
-        { "OOMScoreAdjust",           bus_execute_append_oom_score_adjust,   "i", 0 },
-        { "Nice",                     bus_execute_append_nice,               "i", 0 },
-        { "IOScheduling",             bus_execute_append_ioprio,             "i", 0 },
-        { "CPUSchedulingPolicy",      bus_execute_append_cpu_sched_policy,   "i", 0 },
-        { "CPUSchedulingPriority",    bus_execute_append_cpu_sched_priority, "i", 0 },
-        { "CPUAffinity",              bus_execute_append_affinity,          "ay", 0 },
-        { "TimerSlackNSec",           bus_execute_append_timer_slack_nsec,   "t", 0 },
-        { "CPUSchedulingResetOnFork", bus_property_append_bool,              "b", offsetof(ExecContext, cpu_sched_reset_on_fork)      },
-        { "NonBlocking",              bus_property_append_bool,              "b", offsetof(ExecContext, non_blocking)                 },
-        { "StandardInput",            bus_execute_append_input,              "s", offsetof(ExecContext, std_input)                    },
-        { "StandardOutput",           bus_execute_append_output,             "s", offsetof(ExecContext, std_output)                   },
-        { "StandardError",            bus_execute_append_output,             "s", offsetof(ExecContext, std_error)                    },
-        { "TTYPath",                  bus_property_append_string,            "s", offsetof(ExecContext, tty_path),               true },
-        { "TTYReset",                 bus_property_append_bool,              "b", offsetof(ExecContext, tty_reset)                    },
-        { "TTYVHangup",               bus_property_append_bool,              "b", offsetof(ExecContext, tty_vhangup)                  },
-        { "TTYVTDisallocate",         bus_property_append_bool,              "b", offsetof(ExecContext, tty_vt_disallocate)           },
-        { "SyslogPriority",           bus_property_append_int,               "i", offsetof(ExecContext, syslog_priority)              },
-        { "SyslogIdentifier",         bus_property_append_string,            "s", offsetof(ExecContext, syslog_identifier),      true },
-        { "SyslogLevelPrefix",        bus_property_append_bool,              "b", offsetof(ExecContext, syslog_level_prefix)          },
-        { "Capabilities",             bus_execute_append_capabilities,       "s", 0 },
-        { "SecureBits",               bus_property_append_int,               "i", offsetof(ExecContext, secure_bits)                  },
-        { "CapabilityBoundingSet",    bus_execute_append_capability_bs,      "t", offsetof(ExecContext, capability_bounding_set_drop) },
-        { "User",                     bus_property_append_string,            "s", offsetof(ExecContext, user),                   true },
-        { "Group",                    bus_property_append_string,            "s", offsetof(ExecContext, group),                  true },
-        { "SupplementaryGroups",      bus_property_append_strv,             "as", offsetof(ExecContext, supplementary_groups),   true },
-        { "TCPWrapName",              bus_property_append_string,            "s", offsetof(ExecContext, tcpwrap_name),           true },
-        { "PAMName",                  bus_property_append_string,            "s", offsetof(ExecContext, pam_name),               true },
-        { "ReadWriteDirectories",     bus_property_append_strv,             "as", offsetof(ExecContext, read_write_dirs),        true },
-        { "ReadOnlyDirectories",      bus_property_append_strv,             "as", offsetof(ExecContext, read_only_dirs),         true },
-        { "InaccessibleDirectories",  bus_property_append_strv,             "as", offsetof(ExecContext, inaccessible_dirs),      true },
-        { "MountFlags",               bus_property_append_ul,                "t", offsetof(ExecContext, mount_flags)                  },
-        { "PrivateTmp",               bus_property_append_bool,              "b", offsetof(ExecContext, private_tmp)                  },
-        { "PrivateNetwork",           bus_property_append_bool,              "b", offsetof(ExecContext, private_network)              },
-        { "SameProcessGroup",         bus_property_append_bool,              "b", offsetof(ExecContext, same_pgrp)                    },
-        { "UtmpIdentifier",           bus_property_append_string,            "s", offsetof(ExecContext, utmp_id),                true },
-        { "IgnoreSIGPIPE",            bus_property_append_bool,              "b", offsetof(ExecContext, ignore_sigpipe)               },
-        { "NoNewPrivileges",          bus_property_append_bool,              "b", offsetof(ExecContext, no_new_privileges)            },
-        { "SystemCallFilter",         bus_execute_append_syscall_filter,    "au", 0                                                   },
-        {}
-};
index 79bf308..957742b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
+#include "sd-bus.h"
+#include "execute.h"
 
-#include "manager.h"
-#include "dbus-common.h"
+#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags)                   \
+        BUS_PROPERTY_DUAL_TIMESTAMP(prefix "StartTimestamp", (offset) + offsetof(ExecStatus, start_timestamp), flags), \
+        BUS_PROPERTY_DUAL_TIMESTAMP(prefix "ExitTimestamp", (offset) + offsetof(ExecStatus, exit_timestamp), flags), \
+        SD_BUS_PROPERTY(prefix "PID", "u", bus_property_get_pid, (offset) + offsetof(ExecStatus, pid), flags), \
+        SD_BUS_PROPERTY(prefix "Code", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, code), flags), \
+        SD_BUS_PROPERTY(prefix "Status", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, status), flags)
 
-#define BUS_EXEC_STATUS_INTERFACE(prefix)                               \
-        "  <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "StartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "ExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n"
+#define BUS_EXEC_COMMAND_VTABLE(name, offset, flags)                    \
+        SD_BUS_PROPERTY(name, "a(sasbttttuii)", bus_property_get_exec_command, offset, flags)
 
-#define BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"EnvironmentFiles\" type=\"a(sb)\" access=\"read\"/>\n" \
-        "  <property name=\"UMask\" type=\"u\" access=\"read\"/>\n"     \
-        "  <property name=\"LimitCPU\" type=\"t\" access=\"read\"/>\n"  \
-        "  <property name=\"LimitFSIZE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitDATA\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitSTACK\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitCORE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitRSS\" type=\"t\" access=\"read\"/>\n"  \
-        "  <property name=\"LimitNOFILE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitAS\" type=\"t\" access=\"read\"/>\n"   \
-        "  <property name=\"LimitNPROC\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitMEMLOCK\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitLOCKS\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitSIGPENDING\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitMSGQUEUE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitNICE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitRTPRIO\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitRTTIME\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"OOMScoreAdjust\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"Nice\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"IOScheduling\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CPUSchedulingPolicy\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CPUSchedulingPriority\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CPUAffinity\" type=\"ay\" access=\"read\"/>\n" \
-        "  <property name=\"TimerSlackNSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"StandardInput\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"StandardError\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"TTYReset\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"TTYVHangup\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"TTYVTDisallocate\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SyslogLevelPrefix\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CapabilityBoundingSet\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"User\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Group\" type=\"s\" access=\"read\"/>\n"     \
-        "  <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"TCPWrapName\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"ReadWriteDirectories\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"ReadOnlyDirectories\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"PrivateNetwork\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"IgnoreSIGPIPE\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"NoNewPrivileges\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"SystemCallFilter\" type=\"au\" access=\"read\"/>\n"
+extern const sd_bus_vtable bus_exec_vtable[];
 
-#define BUS_EXEC_COMMAND_INTERFACE(name)                             \
-        "  <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
-
-extern const BusProperty bus_exec_context_properties[];
-
-#define BUS_EXEC_COMMAND_PROPERTY(name, command, indirect)             \
-        { name, bus_execute_append_command, "a(sasbttttuii)", (command), (indirect), NULL }
-
-int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data);
+int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
+int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
index e1d7504..e774383 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <errno.h>
-
-#include "dbus.h"
 #include "log.h"
-#include "dbus-job.h"
-#include "dbus-common.h"
+#include "sd-bus.h"
 #include "selinux-access.h"
+#include "job.h"
+#include "dbus-job.h"
+#include "dbus-client-track.h"
+
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
+
+static int property_get_unit(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-#define BUS_JOB_INTERFACE                                             \
-        " <interface name=\"org.freedesktop.systemd1.Job\">\n"        \
-        "  <method name=\"Cancel\"/>\n"                               \
-        "  <property name=\"Id\" type=\"u\" access=\"read\"/>\n"      \
-        "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>\n" \
-        "  <property name=\"JobType\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"   \
-        " </interface>\n"
-
-#define INTROSPECTION                                                 \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                     \
-        "<node>\n"                                                    \
-        BUS_JOB_INTERFACE                                             \
-        BUS_PROPERTIES_INTERFACE                                      \
-        BUS_PEER_INTERFACE                                            \
-        BUS_INTROSPECTABLE_INTERFACE                                  \
-        "</node>\n"
-
-const char bus_job_interface[] = BUS_JOB_INTERFACE;
-
-#define INTERFACES_LIST                              \
-        BUS_GENERIC_INTERFACES_LIST                  \
-        "org.freedesktop.systemd1.Job\0"
-
-#define INVALIDATING_PROPERTIES                 \
-        "State\0"
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType);
-
-static int bus_job_append_unit(DBusMessageIter *i, const char *property, void *data) {
-        Job *j = data;
-        DBusMessageIter sub;
         _cleanup_free_ char *p = NULL;
+        Job *j = userdata;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(j);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
-                return -ENOMEM;
-
         p = unit_dbus_path(j->unit);
         if (!p)
                 return -ENOMEM;
 
-        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->id) ||
-            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
-                return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "(so)", j->unit->id, p);
 }
 
-static const BusProperty bus_job_properties[] = {
-        { "Id",      bus_property_append_uint32, "u", offsetof(Job, id)    },
-        { "State",   bus_job_append_state,       "s", offsetof(Job, state) },
-        { "JobType", bus_job_append_type,        "s", offsetof(Job, type)  },
-        { "Unit",    bus_job_append_unit,     "(so)", 0 },
-        { NULL, }
-};
-
-static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connection, DBusMessage *message) {
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
-
-                SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
-                job_finish_and_invalidate(j, JOB_CANCELED, true);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-        } else {
-                const BusBoundProperties bps[] = {
-                        { "org.freedesktop.systemd1.Job", bus_job_properties, j },
-                        { NULL, }
-                };
-
-                SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
-                return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
-        }
-
-        if (!bus_maybe_send_reply(connection, message, reply))
-                return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBusMessage  *message, void *data) {
-        Manager *m = data;
-        Job *j;
-        int r;
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+static int method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Job *j = userdata;
 
-        assert(connection);
+        assert(bus);
         assert(message);
-        assert(m);
-
-        if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) {
-                /* Be nice to gdbus and return introspection data for our mid-level paths */
-
-                if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-                        _cleanup_free_ char *introspection = NULL;
-                        FILE *f;
-                        Iterator i;
-                        size_t size;
-
-                        SELINUX_ACCESS_CHECK(connection, message, "status");
-
-                        reply = dbus_message_new_method_return(message);
-                        if (!reply)
-                                goto oom;
-
-                        /* We roll our own introspection code here, instead of
-                         * relying on bus_default_message_handler() because we
-                         * need to generate our introspection string
-                         * dynamically. */
-
-                        f = open_memstream(&introspection, &size);
-                        if (!f)
-                                goto oom;
-
-                        fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-                              "<node>\n", f);
-
-                        fputs(BUS_INTROSPECTABLE_INTERFACE, f);
-                        fputs(BUS_PEER_INTERFACE, f);
-
-                        HASHMAP_FOREACH(j, m->jobs, i)
-                                fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
-
-                        fputs("</node>\n", f);
-
-                        if (ferror(f)) {
-                                fclose(f);
-                                goto oom;
-                        }
-
-                        fclose(f);
-
-                        if (!introspection)
-                                goto oom;
-
-                        if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
-                                goto oom;
-                        }
-
-                        if (!bus_maybe_send_reply(connection, message, reply))
-                                goto oom;
-
-                        return DBUS_HANDLER_RESULT_HANDLED;
-                }
-
-                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-        }
-
-        r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j);
-        if (r == -ENOMEM)
-                goto oom;
-        if (r == -ENOENT) {
-                DBusError e;
-
-                dbus_error_init(&e);
-                dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job");
-                return bus_send_error_reply(connection, message, &e, r);
-        }
-        if (r < 0)
-                return bus_send_error_reply(connection, message, NULL, r);
+        assert(j);
 
-        return bus_job_message_dispatch(j, connection, message);
+        SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "stop");
+        job_finish_and_invalidate(j, JOB_CANCELED, true);
 
-oom:
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+        return sd_bus_reply_method_return(bus, message, NULL);
 }
 
-const DBusObjectPathVTable bus_job_vtable = {
-        .message_function = bus_job_message_handler
+const sd_bus_vtable bus_job_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, 0),
+        SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), 0),
+        SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, 0),
+        SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), 0),
+        SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_VTABLE_END
 };
 
-static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) {
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
+static int foreach_client(Job *j, int (*send_message)(sd_bus *bus, const char *name, Job *j)) {
+        BusTrackedClient *one_destination = NULL;
+        Iterator i;
+        sd_bus *b;
+        unsigned n, m;
         int r;
 
         assert(j);
-        assert(new_message);
+        assert(send_message);
 
-        if (bus_has_subscriber(j->manager) || j->forgot_bus_clients) {
-                m = new_message(j);
-                if (!m)
-                        return -ENOMEM;
+        n = set_size(j->manager->subscribed);
+        m = set_size(j->subscribed);
 
-                r = bus_broadcast(j->manager, m);
-                if (r < 0)
-                        return r;
-
-        } else {
-                /* If nobody is subscribed, we just send the message
-                 * to the client(s) which created the job */
-                JobBusClient *cl;
-                assert(j->bus_client_list);
-
-                LIST_FOREACH(client, cl, j->bus_client_list) {
-                        assert(cl->bus);
+        if (n <= 0 && m <= 0)
+                return 0;
 
-                        m = new_message(j);
-                        if (!m)
-                                return -ENOMEM;
+        if (n == 1 && m == 0)
+                one_destination = set_first(j->manager->subscribed);
+        else if (n == 0 && m == 1)
+                one_destination = set_first(j->subscribed);
+        else
+                one_destination = NULL;
 
-                        if (!dbus_message_set_destination(m, cl->name))
-                                return -ENOMEM;
+        if (one_destination)
+                return send_message(one_destination->bus, isempty(one_destination->name) ? NULL : one_destination->name, j);
 
-                        if (!dbus_connection_send(cl->bus, m, NULL))
-                                return -ENOMEM;
-
-                        dbus_message_unref(m);
-                        m = NULL;
-                }
+        /* Send to everybody */
+        SET_FOREACH(b, j->manager->private_buses, i) {
+                r = send_message(b, NULL, j);
+                if (r < 0)
+                        return r;
         }
 
+        if (j->manager->api_bus)
+                return send_message(j->manager->api_bus, NULL, j);
+
         return 0;
 }
 
-static DBusMessage* new_change_signal_message(Job *j) {
+static int send_new_signal(sd_bus *bus, const char *destination, Job *j) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         _cleanup_free_ char *p = NULL;
-        DBusMessage *m;
+        int r;
+
+        assert(bus);
+        assert(j);
 
         p = job_dbus_path(j);
         if (!p)
-                return NULL;
-
-        if (j->sent_dbus_new_signal) {
-                /* Send a properties changed signal */
-                m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES);
-                if (!m)
-                        return NULL;
-
-        } else {
-                /* Send a new signal */
-
-                m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew");
-                if (!m)
-                        return NULL;
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_UINT32, &j->id,
-                                              DBUS_TYPE_OBJECT_PATH, &p,
-                                              DBUS_TYPE_STRING, &j->unit->id,
-                                              DBUS_TYPE_INVALID)) {
-                        dbus_message_unref(m);
-                        return NULL;
-                }
-        }
+                return -ENOMEM;
 
-        return m;
+        r = sd_bus_message_new_signal(
+                        bus,
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "JobNew",
+                        &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(m, "uos", j->id, p, j->unit->id);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send_to(bus, m, destination, NULL);
 }
 
-static DBusMessage* new_removed_signal_message(Job *j) {
+static int send_changed_signal(sd_bus *bus, const char *destination, Job *j) {
         _cleanup_free_ char *p = NULL;
-        DBusMessage *m;
-        const char *r;
+
+        assert(bus);
+        assert(j);
 
         p = job_dbus_path(j);
         if (!p)
-                return NULL;
-
-        m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved");
-        if (!m)
-                return NULL;
-
-        r = job_result_to_string(j->result);
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_UINT32, &j->id,
-                                      DBUS_TYPE_OBJECT_PATH, &p,
-                                      DBUS_TYPE_STRING, &j->unit->id,
-                                      DBUS_TYPE_STRING, &r,
-                                      DBUS_TYPE_INVALID)) {
-                dbus_message_unref(m);
-                return NULL;
-        }
+                return -ENOMEM;
 
-        return m;
+        return sd_bus_emit_properties_changed(bus, p, "org.freedesktop.systemd1.Job", "State", NULL);
 }
 
 void bus_job_send_change_signal(Job *j) {
+        int r;
+
         assert(j);
 
         if (j->in_dbus_queue) {
@@ -323,36 +165,52 @@ void bus_job_send_change_signal(Job *j) {
                 j->in_dbus_queue = false;
         }
 
-        if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients) {
-                j->sent_dbus_new_signal = true;
-                return;
-        }
-
-        if (job_send_message(j, new_change_signal_message) < 0)
-                goto oom;
+        r = foreach_client(j, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal);
+        if (r < 0)
+                log_warning("Failed to send job change signal for %u/%s: %s", j->id, j->unit->id, strerror(-r));
 
         j->sent_dbus_new_signal = true;
+}
+
+static int send_removed_signal(sd_bus *bus, const char *destination, Job *j) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(bus);
+        assert(j);
+
+        p = job_dbus_path(j);
+        if (!p)
+                return -ENOMEM;
 
-        return;
 
-oom:
-        log_error("Failed to allocate job change signal.");
+        r = sd_bus_message_new_signal(
+                        bus,
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "JobRemoved",
+                        &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(m, "uoss", j->id, p, j->unit->id, job_result_to_string(j->result));
+        if (r < 0)
+                return r;
+
+        return sd_bus_send_to(bus, m, destination, NULL);
 }
 
 void bus_job_send_removed_signal(Job *j) {
-        assert(j);
+        int r;
 
-        if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients)
-                return;
+        assert(j);
 
         if (!j->sent_dbus_new_signal)
                 bus_job_send_change_signal(j);
 
-        if (job_send_message(j, new_removed_signal_message) < 0)
-                goto oom;
-
-        return;
-
-oom:
-        log_error("Failed to allocate job remove signal.");
+        r = foreach_client(j, send_removed_signal);
+        if (r < 0)
+                log_warning("Failed to send job removal signal for %u/%s: %s", j->id, j->unit->id, strerror(-r));
+                return;
 }
index a1b928f..d1d0f6d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
-
+#include "sd-bus.h"
 #include "job.h"
 
+extern const sd_bus_vtable bus_job_vtable[];
+
 void bus_job_send_change_signal(Job *j);
 void bus_job_send_removed_signal(Job *j);
-
-extern const DBusObjectPathVTable bus_job_vtable;
-
-extern const char bus_job_interface[];
index 811adb1..42488b1 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <errno.h>
-#include <dbus/dbus.h>
-
+#include "bus-util.h"
+#include "kill.h"
 #include "dbus-kill.h"
-#include "dbus-common.h"
+#include "bus-util.h"
 
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_kill_append_mode, kill_mode, KillMode);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
 
-const BusProperty bus_kill_context_properties[] = {
-        { "KillMode",    bus_kill_append_mode,     "s", offsetof(KillContext, kill_mode)    },
-        { "KillSignal",  bus_property_append_int,  "i", offsetof(KillContext, kill_signal)  },
-        { "SendSIGKILL", bus_property_append_bool, "b", offsetof(KillContext, send_sigkill) },
-        { "SendSIGHUP",  bus_property_append_bool, "b", offsetof(KillContext, send_sighup)  },
-        {}
+const sd_bus_vtable bus_kill_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), 0),
+        SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), 0),
+        SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), 0),
+        SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool,  offsetof(KillContext, send_sighup), 0),
+        SD_BUS_VTABLE_END
 };
 
 int bus_kill_context_set_transient_property(
                 Unit *u,
                 KillContext *c,
                 const char *name,
-                DBusMessageIter *i,
+                sd_bus_message *message,
                 UnitSetPropertiesMode mode,
-                DBusError *error) {
+                sd_bus_error *error) {
+
+        int r;
 
         assert(u);
         assert(c);
         assert(name);
-        assert(i);
+        assert(message);
 
         if (streq(name, "KillMode")) {
                 const char *m;
                 KillMode k;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
-                        return -EINVAL;
-
-                dbus_message_iter_get_basic(i, &m);
+                r = sd_bus_message_read(message, "s", &m);
+                if (r < 0)
+                        return r;
 
                 k = kill_mode_from_string(m);
                 if (k < 0)
@@ -70,14 +71,13 @@ int bus_kill_context_set_transient_property(
                 return 1;
 
         } else if (streq(name, "SendSIGHUP")) {
+                int b;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "b", &b);
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
-                        dbus_bool_t b;
-
-                        dbus_message_iter_get_basic(i, &b);
                         c->send_sighup = b;
 
                         unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s\n", yes_no(b));
@@ -86,14 +86,13 @@ int bus_kill_context_set_transient_property(
                 return 1;
 
         } else if (streq(name, "SendSIGKILL")) {
+                int b;
 
-                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "b", &b);
+                if (r < 0)
+                        return r;
 
                 if (mode != UNIT_CHECK) {
-                        dbus_bool_t b;
-
-                        dbus_message_iter_get_basic(i, &b);
                         c->send_sigkill = b;
 
                         unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s\n", yes_no(b));
index 7676d98..7c15f3a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
+#include "sd-bus.h"
+#include "unit.h"
+#include "kill.h"
 
-#include "manager.h"
-#include "dbus-common.h"
+extern const sd_bus_vtable bus_kill_vtable[];
 
-#define BUS_KILL_CONTEXT_INTERFACE                                      \
-        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"SendSIGKILL\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"SendSIGHUP\" type=\"b\" access=\"read\"/>\n"
-
-extern const BusProperty bus_kill_context_properties[];
-
-int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error);
+int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
index 747bcfc..2e4de2e 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 
-#include "dbus.h"
 #include "log.h"
-#include "dbus-manager.h"
 #include "strv.h"
-#include "bus-errors.h"
 #include "build.h"
-#include "dbus-common.h"
 #include "install.h"
 #include "selinux-access.h"
 #include "watchdog.h"
 #include "hwclock.h"
 #include "path-util.h"
-#include "dbus-unit.h"
 #include "virt.h"
 #include "env-util.h"
+#include "dbus.h"
+#include "dbus-manager.h"
+#include "dbus-unit.h"
+#include "dbus-snapshot.h"
+#include "dbus-client-track.h"
+#include "dbus-execute.h"
+#include "bus-errors.h"
 
-#define BUS_MANAGER_INTERFACE_BEGIN                                     \
-        " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
-
-#define BUS_MANAGER_INTERFACE_METHODS                                   \
-        "  <method name=\"GetUnit\">\n"                                 \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetUnitByPID\">\n"                            \
-        "   <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n"          \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"LoadUnit\">\n"                                \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"StartUnit\">\n"                               \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"StartUnitReplace\">\n"                        \
-        "   <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n"     \
-        "   <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n"     \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"StopUnit\">\n"                                \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadUnit\">\n"                              \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"RestartUnit\">\n"                             \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"TryRestartUnit\">\n"                          \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadOrRestartUnit\">\n"                     \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadOrTryRestartUnit\">\n"                  \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"KillUnit\">\n"                                \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
-        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"ResetFailedUnit\">\n"                         \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetJob\">\n"                                  \
-        "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"CancelJob\">\n"                               \
-        "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
-        "  </method>\n"                                                 \
-        "  <method name=\"ClearJobs\"/>\n"                              \
-        "  <method name=\"ResetFailed\"/>\n"                            \
-        "  <method name=\"ListUnits\">\n"                               \
-        "   <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"ListJobs\">\n"                                \
-        "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"Subscribe\"/>\n"                              \
-        "  <method name=\"Unsubscribe\"/>\n"                            \
-        "  <method name=\"Dump\">\n"                                    \
-        "   <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"CreateSnapshot\">\n"                          \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"RemoveSnapshot\">\n"                          \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"Reload\"/>\n"                                 \
-        "  <method name=\"Reexecute\"/>\n"                              \
-        "  <method name=\"Exit\"/>\n"                                   \
-        "  <method name=\"Reboot\"/>\n"                                 \
-        "  <method name=\"PowerOff\"/>\n"                               \
-        "  <method name=\"Halt\"/>\n"                                   \
-        "  <method name=\"KExec\"/>\n"                                  \
-        "  <method name=\"SwitchRoot\">\n"                              \
-        "   <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n"     \
-        "   <arg name=\"init\" type=\"s\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetEnvironment\">\n"                          \
-        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnsetEnvironment\">\n"                        \
-        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnsetAndSetEnvironment\">\n"                  \
-        "   <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"set\" type=\"as\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ListUnitFiles\">\n"                           \
-        "   <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n"   \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetUnitFileState\">\n"                        \
-        "   <arg name=\"file\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"state\" type=\"s\" direction=\"out\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"EnableUnitFiles\">\n"                         \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"DisableUnitFiles\">\n"                        \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReenableUnitFiles\">\n"                       \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"LinkUnitFiles\">\n"                           \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"PresetUnitFiles\">\n"                         \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"MaskUnitFiles\">\n"                           \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnmaskUnitFiles\">\n"                         \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetDefaultTarget\">\n"                        \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetDefaultTarget\">\n"                        \
-        "   <arg name=\"name\" type=\"s\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetUnitProperties\">\n"                       \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"StartTransientUnit\">\n"                      \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
-        "   <arg name=\"aux\" type=\"a(sa(sv))\" direction=\"in\"/>\n"  \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"
-
-#define BUS_MANAGER_INTERFACE_SIGNALS                                   \
-        "  <signal name=\"UnitNew\">\n"                                 \
-        "   <arg name=\"id\" type=\"s\"/>\n"                            \
-        "   <arg name=\"unit\" type=\"o\"/>\n"                          \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"UnitRemoved\">\n"                             \
-        "   <arg name=\"id\" type=\"s\"/>\n"                            \
-        "   <arg name=\"unit\" type=\"o\"/>\n"                          \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"JobNew\">\n"                                  \
-        "   <arg name=\"id\" type=\"u\"/>\n"                            \
-        "   <arg name=\"job\" type=\"o\"/>\n"                           \
-        "   <arg name=\"unit\" type=\"s\"/>\n"                          \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"JobRemoved\">\n"                              \
-        "   <arg name=\"id\" type=\"u\"/>\n"                            \
-        "   <arg name=\"job\" type=\"o\"/>\n"                           \
-        "   <arg name=\"unit\" type=\"s\"/>\n"                          \
-        "   <arg name=\"result\" type=\"s\"/>\n"                        \
-        "  </signal>"                                                   \
-        "  <signal name=\"StartupFinished\">\n"                         \
-        "   <arg name=\"firmware\" type=\"t\"/>\n"                      \
-        "   <arg name=\"loader\" type=\"t\"/>\n"                        \
-        "   <arg name=\"kernel\" type=\"t\"/>\n"                        \
-        "   <arg name=\"initrd\" type=\"t\"/>\n"                        \
-        "   <arg name=\"userspace\" type=\"t\"/>\n"                     \
-        "   <arg name=\"total\" type=\"t\"/>\n"                         \
-        "  </signal>"                                                   \
-        "  <signal name=\"UnitFilesChanged\"/>\n"                       \
-        "  <signal name=\"Reloading\">\n"                               \
-        "   <arg name=\"active\" type=\"b\"/>\n"                        \
-        "  </signal>"
-
-#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
-        "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"Features\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"SecurityStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"SecurityStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"SecurityFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"SecurityFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n"  \
-        "  <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
-        "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
-        "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
-        "  <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Progress\" type=\"d\" access=\"read\"/>\n"  \
-        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
-        "  <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
-        "  <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
-
-#define BUS_MANAGER_INTERFACE_END                                       \
-        " </interface>\n"
-
-#define BUS_MANAGER_INTERFACE                                           \
-        BUS_MANAGER_INTERFACE_BEGIN                                     \
-        BUS_MANAGER_INTERFACE_METHODS                                   \
-        BUS_MANAGER_INTERFACE_SIGNALS                                   \
-        BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
-        BUS_MANAGER_INTERFACE_END
-
-#define INTROSPECTION_BEGIN                                             \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_MANAGER_INTERFACE                                           \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE
-
-#define INTROSPECTION_END                                               \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_GENERIC_INTERFACES_LIST                  \
-        "org.freedesktop.systemd1.Manager\0"
-
-const char bus_manager_interface[] = BUS_MANAGER_INTERFACE;
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
-
-static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-        Manager *m = data;
-        char buf[LINE_MAX] = "", *e = buf, *p = NULL;
+static int property_get_version(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "s", PACKAGE_VERSION);
+}
 
-        assert(i);
-        assert(property);
+static int property_get_features(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "s", SYSTEMD_FEATURES);
+}
+
+static int property_get_virtualization(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        const char *id = NULL;
+
+        assert(bus);
+        assert(reply);
+
+        detect_virtualization(&id);
+
+        return sd_bus_message_append(reply, "s", id);
+}
+
+static int property_get_tainted(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        char buf[LINE_MAX] = "", *e = buf;
+        _cleanup_free_ char *p = NULL;
+        Manager *m = userdata;
+
+        assert(bus);
+        assert(reply);
         assert(m);
 
         if (m->taint_usr)
@@ -343,8 +111,6 @@ static int bus_manager_append_tainted(DBusMessageIter *i, const char *property,
 
         if (readlink_malloc("/etc/mtab", &p) < 0)
                 e = stpcpy(e, "mtab-not-symlink:");
-        else
-                free(p);
 
         if (access("/proc/cgroups", F_OK) < 0)
                 e = stpcpy(e, "cgroups-missing:");
@@ -356,105 +122,140 @@ static int bus_manager_append_tainted(DBusMessageIter *i, const char *property,
         if (e != buf)
                 e[-1] = 0;
 
-        t = buf;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_append(reply, "s", buf);
 }
 
-static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        assert(i);
-        assert(property);
-
-        t = log_target_to_string(log_get_target());
+static int property_get_log_target(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
+        assert(bus);
+        assert(reply);
 
-        return 0;
+        return sd_bus_message_append(reply, "s", log_target_to_string(log_get_target()));
 }
 
-static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
+static int property_set_log_target(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                sd_bus_error *error,
+                void *userdata) {
+
         const char *t;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(value);
 
-        dbus_message_iter_get_basic(i, &t);
+        r = sd_bus_message_read(value, "s", &t);
+        if (r < 0)
+                return r;
 
         return log_set_target_from_string(t);
 }
 
-static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
+static int property_get_log_level(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
         _cleanup_free_ char *t = NULL;
         int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
 
         r = log_level_to_string_alloc(log_get_max_level(), &t);
         if (r < 0)
                 return r;
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                r = -ENOMEM;
-
-        return r;
+        return sd_bus_message_append(reply, "s", t);
 }
 
-static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
+static int property_set_log_level(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                sd_bus_error *error,
+                void *userdata) {
+
         const char *t;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(value);
 
-        dbus_message_iter_get_basic(i, &t);
+        r = sd_bus_message_read(value, "s", &t);
+        if (r < 0)
+                return r;
 
         return log_set_max_level_from_string(t);
 }
 
-static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        uint32_t u;
+static int property_get_n_names(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        assert(i);
-        assert(property);
-        assert(m);
+        Manager *m = userdata;
 
-        u = hashmap_size(m->units);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
-                return -ENOMEM;
+        assert(bus);
+        assert(reply);
+        assert(m);
 
-        return 0;
+        return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units));
 }
 
-static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        uint32_t u;
+static int property_get_n_jobs(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
 
-        assert(i);
-        assert(property);
-        assert(m);
+        Manager *m = userdata;
 
-        u = hashmap_size(m->jobs);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
-                return -ENOMEM;
+        assert(bus);
+        assert(reply);
+        assert(m);
 
-        return 0;
+        return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs));
 }
 
-static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
+static int property_get_progress(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        Manager *m = userdata;
         double d;
-        Manager *m = data;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(m);
 
         if (dual_timestamp_is_set(&m->finish_timestamp))
@@ -462,1416 +263,1375 @@ static int bus_manager_append_progress(DBusMessageIter *i, const char *property,
         else
                 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
-                return -ENOMEM;
+        return sd_bus_message_append(reply, "d", d);
+}
+
+static int property_set_runtime_watchdog(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                sd_bus_error *error,
+                void *userdata) {
 
-        return 0;
+        usec_t *t = userdata;
+        int r;
+
+        assert(bus);
+        assert(value);
+
+        assert_cc(sizeof(usec_t) == sizeof(uint64_t));
+
+        r = sd_bus_message_read(value, "t", t);
+        if (r < 0)
+                return r;
+
+        return watchdog_set_timeout(t);
 }
 
-static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        const char *id = NULL;
+static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_free_ char *path = NULL;
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(message);
         assert(m);
 
-        detect_virtualization(&id);
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-        if (!id)
-                id = "";
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
-                return -ENOMEM;
+        u = manager_get_unit(m, name);
+        if (!u)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
 
-        return 0;
-}
+        SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status");
 
-static DBusMessage *message_from_file_changes(
-                DBusMessage *m,
-                UnitFileChange *changes,
-                unsigned n_changes,
-                int carries_install_info) {
+        path = unit_dbus_path(u);
+        if (!path)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
-        DBusMessageIter iter, sub, sub2;
-        DBusMessage *reply;
-        unsigned i;
+        return sd_bus_reply_method_return(bus, message, "o", path);
+}
 
-        reply = dbus_message_new_method_return(m);
-        if (!reply)
-                return NULL;
+static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_free_ char *path = NULL;
+        Manager *m = userdata;
+        pid_t pid;
+        Unit *u;
+        int r;
 
-        dbus_message_iter_init_append(reply, &iter);
+        assert(bus);
+        assert(message);
+        assert(m);
 
-        if (carries_install_info >= 0) {
-                dbus_bool_t b;
+        assert_cc(sizeof(pid_t) == sizeof(uint32_t));
 
-                b = !!carries_install_info;
-                if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
-                        goto oom;
+        r = sd_bus_message_read(message, "u", &pid);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        if (pid == 0) {
+                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                if (r < 0)
+                        return sd_bus_reply_method_errno(bus, message, r, NULL);
         }
 
-        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
-                goto oom;
+        u = manager_get_unit_by_pid(m, pid);
+        if (!u)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_UNIT_FOR_PID, "PID %u does not belong to any loaded unit.", pid);
 
-        for (i = 0; i < n_changes; i++) {
-                const char *type, *path, *source;
-
-                type = unit_file_change_type_to_string(changes[i].type);
-                path = strempty(changes[i].path);
-                source = strempty(changes[i].source);
-
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        goto oom;
-        }
+        SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status");
+
+        path = unit_dbus_path(u);
+        if (!path)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+        return sd_bus_reply_method_return(bus, message, "o", path);
+}
+
+static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *path = NULL;
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
 
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                goto oom;
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-        return reply;
+        r = manager_load_unit(m, name, NULL, &error, &u);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, &error);
+
+        SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status");
 
-oom:
-        dbus_message_unref(reply);
-        return NULL;
+        path = unit_dbus_path(u);
+        if (!path)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+        return sd_bus_reply_method_return(bus, message, "o", path);
 }
 
-static int bus_manager_send_unit_files_changed(Manager *m) {
-        DBusMessage *s;
+static int method_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *name;
+        Unit *u;
         int r;
 
-        s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
-        if (!s)
-                return -ENOMEM;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-        r = bus_broadcast(m, s);
-        dbus_message_unref(s);
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-        return r;
+        r = manager_load_unit(m, name, NULL, &error, &u);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, &error);
+
+        return bus_unit_method_start_generic(bus, message, u, job_type, reload_if_possible);
 }
 
-static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
-        uint64_t *t = data;
+static int method_start_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_START, false);
+}
 
-        assert(i);
-        assert(property);
+static int method_stop_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_STOP, false);
+}
 
-        dbus_message_iter_get_basic(i, t);
+static int method_reload_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_RELOAD, false);
+}
 
-        return watchdog_set_timeout(t);
+static int method_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_RESTART, false);
 }
 
-static const char systemd_property_string[] =
-        PACKAGE_STRING "\0"
-        SYSTEMD_FEATURES;
+static int method_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, false);
+}
 
-static const BusProperty bus_systemd_properties[] = {
-        { "Version",       bus_property_append_string,    "s",  0                      },
-        { "Features",      bus_property_append_string,    "s",  sizeof(PACKAGE_STRING) },
-        { NULL, }
-};
+static int method_reload_or_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_RESTART, true);
+}
 
-static const BusProperty bus_manager_properties[] = {
-        { "Tainted",                     bus_manager_append_tainted,     "s",  0                                                },
-        { "FirmwareTimestamp",           bus_property_append_uint64,     "t",  offsetof(Manager, firmware_timestamp.realtime)   },
-        { "FirmwareTimestampMonotonic",  bus_property_append_uint64,     "t",  offsetof(Manager, firmware_timestamp.monotonic)  },
-        { "LoaderTimestamp",             bus_property_append_uint64,     "t",  offsetof(Manager, loader_timestamp.realtime)     },
-        { "LoaderTimestampMonotonic",    bus_property_append_uint64,     "t",  offsetof(Manager, loader_timestamp.monotonic)    },
-        { "KernelTimestamp",             bus_property_append_uint64,     "t",  offsetof(Manager, kernel_timestamp.realtime)     },
-        { "KernelTimestampMonotonic",    bus_property_append_uint64,     "t",  offsetof(Manager, kernel_timestamp.monotonic)    },
-        { "InitRDTimestamp",             bus_property_append_uint64,     "t",  offsetof(Manager, initrd_timestamp.realtime)     },
-        { "InitRDTimestampMonotonic",    bus_property_append_uint64,     "t",  offsetof(Manager, initrd_timestamp.monotonic)    },
-        { "UserspaceTimestamp",          bus_property_append_uint64,     "t",  offsetof(Manager, userspace_timestamp.realtime)  },
-        { "UserspaceTimestampMonotonic", bus_property_append_uint64,     "t",  offsetof(Manager, userspace_timestamp.monotonic) },
-        { "FinishTimestamp",             bus_property_append_uint64,     "t",  offsetof(Manager, finish_timestamp.realtime)     },
-        { "FinishTimestampMonotonic",    bus_property_append_uint64,     "t",  offsetof(Manager, finish_timestamp.monotonic)    },
-        { "SecurityStartTimestamp",             bus_property_append_uint64,     "t",  offsetof(Manager, security_start_timestamp.realtime)     },
-        { "SecurityStartTimestampMonotonic",    bus_property_append_uint64,     "t",  offsetof(Manager, security_start_timestamp.monotonic)    },
-        { "SecurityFinishTimestamp",            bus_property_append_uint64,     "t",  offsetof(Manager, security_finish_timestamp.realtime)    },
-        { "SecurityFinishTimestampMonotonic",   bus_property_append_uint64,     "t",  offsetof(Manager, security_finish_timestamp.monotonic)   },
-        { "GeneratorsStartTimestamp",           bus_property_append_uint64,     "t",  offsetof(Manager, generators_start_timestamp.realtime)   },
-        { "GeneratorsStartTimestampMonotonic",  bus_property_append_uint64,     "t",  offsetof(Manager, generators_start_timestamp.monotonic)  },
-        { "GeneratorsFinishTimestamp",          bus_property_append_uint64,     "t",  offsetof(Manager, generators_finish_timestamp.realtime)  },
-        { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64,     "t",  offsetof(Manager, generators_finish_timestamp.monotonic) },
-        { "UnitsLoadStartTimestamp",            bus_property_append_uint64,     "t",  offsetof(Manager, unitsload_start_timestamp.realtime)    },
-        { "UnitsLoadStartTimestampMonotonic",   bus_property_append_uint64,     "t",  offsetof(Manager, unitsload_start_timestamp.monotonic)   },
-        { "UnitsLoadFinishTimestamp",           bus_property_append_uint64,     "t",  offsetof(Manager, unitsload_finish_timestamp.realtime)   },
-        { "UnitsLoadFinishTimestampMonotonic",  bus_property_append_uint64,     "t",  offsetof(Manager, unitsload_finish_timestamp.monotonic)  },
-        { "LogLevel",                    bus_manager_append_log_level,   "s",  0,                                               false, bus_manager_set_log_level },
-        { "LogTarget",                   bus_manager_append_log_target,  "s",  0,                                               false, bus_manager_set_log_target },
-        { "NNames",                      bus_manager_append_n_names,     "u",  0                                                },
-        { "NJobs",                       bus_manager_append_n_jobs,      "u",  0                                                },
-        { "NInstalledJobs",              bus_property_append_uint32,     "u",  offsetof(Manager, n_installed_jobs)              },
-        { "NFailedJobs",                 bus_property_append_uint32,     "u",  offsetof(Manager, n_failed_jobs)                 },
-        { "Progress",                    bus_manager_append_progress,    "d",  0                                                },
-        { "Environment",                 bus_property_append_strv,       "as", offsetof(Manager, environment),                  true },
-        { "ConfirmSpawn",                bus_property_append_bool,       "b",  offsetof(Manager, confirm_spawn)                 },
-        { "ShowStatus",                  bus_property_append_bool,       "b",  offsetof(Manager, show_status)                   },
-        { "UnitPath",                    bus_property_append_strv,       "as", offsetof(Manager, lookup_paths.unit_path),       true },
-        { "DefaultStandardOutput",       bus_manager_append_exec_output, "s",  offsetof(Manager, default_std_output)            },
-        { "DefaultStandardError",        bus_manager_append_exec_output, "s",  offsetof(Manager, default_std_error)             },
-        { "RuntimeWatchdogUSec",         bus_property_append_usec,       "t",  offsetof(Manager, runtime_watchdog),             false, bus_manager_set_runtime_watchdog_usec },
-        { "ShutdownWatchdogUSec",        bus_property_append_usec,       "t",  offsetof(Manager, shutdown_watchdog),            false, bus_property_set_usec },
-        { "Virtualization",              bus_manager_append_virt,        "s",  0,                                               },
-        { NULL, }
-};
+static int method_reload_or_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, true);
+}
 
-static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
-        _cleanup_free_ char * path = NULL;
-        Manager *m = data;
+static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        const char *old_name;
+        Unit *u;
         int r;
-        DBusError error;
-        JobType job_type = _JOB_TYPE_INVALID;
-        bool reload_if_possible = false;
-        const char *member;
 
-        assert(connection);
+        assert(bus);
         assert(message);
         assert(m);
 
-        dbus_error_init(&error);
+        r = sd_bus_message_read(message, "s", &old_name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-        member = dbus_message_get_member(message);
+        u = manager_get_unit(m, old_name);
+        if (!u || !u->job || u->job->type != JOB_START)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
 
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
-                const char *name;
-                Unit *u;
+        return method_start_unit_generic(bus, message, m, JOB_START, false);
+}
 
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
 
-                u = manager_get_unit(m, name);
-                if (!u) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                path = unit_dbus_path(u);
-                if (!path)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
-                Unit *u;
-                uint32_t pid;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &pid,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                u = manager_get_unit_by_pid(m, (pid_t) pid);
-                if (!u) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                path = unit_dbus_path(u);
-                if (!path)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
-                const char *name;
-                Unit *u;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                r = manager_load_unit(m, name, NULL, &error, &u);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                path = unit_dbus_path(u);
-                if (!path)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
-                job_type = JOB_START;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
-                job_type = JOB_START;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
-                job_type = JOB_STOP;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
-                job_type = JOB_RELOAD;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
-                job_type = JOB_RESTART;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
-                job_type = JOB_TRY_RESTART;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
-                reload_if_possible = true;
-                job_type = JOB_RESTART;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
-                reload_if_possible = true;
-                job_type = JOB_TRY_RESTART;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
-                const char *name, *swho;
-                int32_t signo;
-                Unit *u;
-                KillWho who;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_STRING, &swho,
-                                    DBUS_TYPE_INT32, &signo,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (isempty(swho))
-                        who = KILL_ALL;
-                else {
-                        who = kill_who_from_string(swho);
-                        if (who < 0)
-                                return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
+        u = manager_get_unit(m, name);
+        if (!u)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
 
-                if (signo <= 0 || signo >= _NSIG)
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+        return bus_unit_method_kill(bus, message, u);
+}
 
-                u = manager_get_unit(m, name);
-                if (!u) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                r = unit_kill(u, who, signo, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
-                uint32_t id;
-                Job *j;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &id,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                j = manager_get_job(m, id);
-                if (!j) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                path = job_dbus_path(j);
-                if (!path)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
-                uint32_t id;
-                Job *j;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &id,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                j = manager_get_job(m, id);
-                if (!j) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        u = manager_get_unit(m, name);
+        if (!u)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
 
-                SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
-                job_finish_and_invalidate(j, JOB_CANCELED, true);
+        return bus_unit_method_reset_failed(bus, message, u);
+}
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        u = manager_get_unit(m, name);
+        if (!u)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
 
-                SELINUX_ACCESS_CHECK(connection, message, "reboot");
-                manager_clear_jobs(m);
+        return bus_unit_method_set_properties(bus, message, u);
+}
+
+static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *name, *smode;
+        Manager *m = userdata;
+        JobMode mode;
+        UnitType t;
+        Unit *u;
+        int r;
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
+        r = sd_bus_message_read(message, "ss", &name, &smode);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                SELINUX_ACCESS_CHECK(connection, message, "reload");
+        t = unit_name_to_type(name);
+        if (t < 0)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type.");
 
-                manager_reset_failed(m);
+        if (!unit_vtable[t]->can_transient)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        mode = job_mode_from_string(smode);
+        if (mode < 0)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
-                const char *name;
-                Unit *u;
+        r = manager_load_unit(m, name, NULL, &error, &u);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, &error);
 
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+        SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "start");
 
-                u = manager_get_unit(m, name);
-                if (!u) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
-
-                unit_reset_failed(u);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
-                DBusMessageIter iter, sub;
-                Iterator i;
-                Unit *u;
-                const char *k;
-
-                SELINUX_ACCESS_CHECK(connection, message, "status");
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
-                        goto oom;
-
-                HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-                        char *u_path, *j_path;
-                        const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
-                        DBusMessageIter sub2;
-                        uint32_t job_id;
-                        Unit *f;
-
-                        if (k != u->id)
-                                continue;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
-
-                        description = unit_description(u);
-                        load_state = unit_load_state_to_string(u->load_state);
-                        active_state = unit_active_state_to_string(unit_active_state(u));
-                        sub_state = unit_sub_state_to_string(u);
-
-                        f = unit_following(u);
-                        following = f ? f->id : "";
-
-                        u_path = unit_dbus_path(u);
-                        if (!u_path)
-                                goto oom;
-
-                        if (u->job) {
-                                job_id = (uint32_t) u->job->id;
-
-                                if (!(j_path = job_dbus_path(u->job))) {
-                                        free(u_path);
-                                        goto oom;
-                                }
-
-                                sjob_type = job_type_to_string(u->job->type);
-                        } else {
-                                job_id = 0;
-                                j_path = u_path;
-                                sjob_type = "";
-                        }
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
-                                free(u_path);
-                                if (u->job)
-                                        free(j_path);
-                                goto oom;
-                        }
-
-                        free(u_path);
-                        if (u->job)
-                                free(j_path);
-
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
+        /* OK, the unit failed to load and is unreferenced, now let's
+         * fill in the transient data instead */
+        r = unit_make_transient(u);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
+        /* Set our properties */
+        r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, &error);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, &error);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
-                DBusMessageIter iter, sub;
-                Iterator i;
-                Job *j;
+        /* And load this stub fully */
+        r = unit_load(u);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, &error);
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+        manager_dispatch_load_queue(m);
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        /* Finally, start it */
+        return bus_unit_queue_job(bus, message, u, JOB_START, mode, false);
+}
 
-                dbus_message_iter_init_append(reply, &iter);
+static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_free_ char *path = NULL;
+        Manager *m = userdata;
+        uint32_t id;
+        Job *j;
+        int r;
 
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
-                        goto oom;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                HASHMAP_FOREACH(j, m->jobs, i) {
-                        char *u_path, *j_path;
-                        const char *state, *type;
-                        uint32_t id;
-                        DBusMessageIter sub2;
+        r = sd_bus_message_read(message, "u", &id);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
+        j = manager_get_job(m, id);
+        if (!j)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
 
-                        id = (uint32_t) j->id;
-                        state = job_state_to_string(j->state);
-                        type = job_type_to_string(j->type);
+        SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "status");
 
-                        j_path = job_dbus_path(j);
-                        if (!j_path)
-                                goto oom;
+        path = job_dbus_path(j);
+        if (!path)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
-                        u_path = unit_dbus_path(j->unit);
-                        if (!u_path) {
-                                free(j_path);
-                                goto oom;
-                        }
+        return sd_bus_reply_method_return(bus, message, "o", path);
+}
 
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
-                                free(j_path);
-                                free(u_path);
-                                goto oom;
-                        }
+static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        uint32_t id;
+        Job *j;
+        int r;
 
-                        free(j_path);
-                        free(u_path);
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
+        r = sd_bus_message_read(message, "u", &id);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
+        j = manager_get_job(m, id);
+        if (!j)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
-                char *client;
-                Set *s;
+        SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "stop");
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+        job_finish_and_invalidate(j, JOB_CANCELED, true);
 
-                s = bus_acquire_subscribed(m, connection);
-                if (!s)
-                        goto oom;
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                client = strdup(bus_message_get_sender_with_fallback(message));
-                if (!client)
-                        goto oom;
+static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-                r = set_consume(s, client);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        SELINUX_ACCESS_CHECK(bus, message, "reboot");
+        manager_clear_jobs(m);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
-                char *client;
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-                client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
-                if (!client) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, "reload");
+        manager_reset_failed(m);
 
-                free(client);
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        Manager *m = userdata;
+        const char *k;
+        Iterator i;
+        Unit *u;
+        int r;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
-                FILE *f;
-                char *dump = NULL;
-                size_t size;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+        SELINUX_ACCESS_CHECK(bus, message, "status");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        r = sd_bus_message_new_method_return(bus, message, &reply);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                f = open_memstream(&dump, &size);
-                if (!f)
-                        goto oom;
+        r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)");
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                manager_dump_units(m, f, NULL);
-                manager_dump_jobs(m, f, NULL);
+        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+                _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
+                Unit *following;
 
-                if (ferror(f)) {
-                        fclose(f);
-                        free(dump);
-                        goto oom;
-                }
+                if (k != u->id)
+                        continue;
 
-                fclose(f);
+                following = unit_following(u);
 
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
-                        free(dump);
-                        goto oom;
+                unit_path = unit_dbus_path(u);
+                if (!unit_path)
+                        return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+                if (u->job) {
+                        job_path = job_dbus_path(u->job);
+                        if (!job_path)
+                                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
                 }
 
-                free(dump);
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
-                const char *name;
-                dbus_bool_t cleanup;
-                Snapshot *s;
+                r = sd_bus_message_append(
+                                reply, "(ssssssouso)",
+                                u->id,
+                                unit_description(u),
+                                unit_load_state_to_string(u->load_state),
+                                unit_active_state_to_string(unit_active_state(u)),
+                                unit_sub_state_to_string(u),
+                                following ? following->id : "",
+                                unit_path,
+                                u->job ? u->job->id : 0,
+                                u->job ? job_type_to_string(u->job->type) : "",
+                                job_path ? job_path : "/");
+                if (r < 0)
+                        return sd_bus_reply_method_errno(bus, message, r, NULL);
+        }
 
-                SELINUX_ACCESS_CHECK(connection, message, "start");
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_BOOLEAN, &cleanup,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+        return sd_bus_send(bus, reply, NULL);
+}
 
-                if (isempty(name))
-                        name = NULL;
+static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        Manager *m = userdata;
+        Iterator i;
+        Job *j;
+        int r;
 
-                r = snapshot_create(m, name, cleanup, &error, &s);
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, "status");
+
+        r = sd_bus_message_new_method_return(bus, message, &reply);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        r = sd_bus_message_open_container(reply, 'a', "(usssoo)");
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        HASHMAP_FOREACH(j, m->jobs, i) {
+                _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
+
+                job_path = job_dbus_path(j);
+                if (!job_path)
+                        return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+                unit_path = unit_dbus_path(j->unit);
+                if (!unit_path)
+                        return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+                r = sd_bus_message_append(
+                                reply, "(usssoo)",
+                                j->id,
+                                job_state_to_string(j->state),
+                                job_type_to_string(j->type),
+                                job_path,
+                                unit_path);
                 if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                path = unit_dbus_path(UNIT(s));
-                if (!path)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
-                const char *name;
-                Unit *u;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                u = manager_get_unit(m, name);
-                if (!u) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+                        return sd_bus_reply_method_errno(bus, message, r, NULL);
+        }
 
-                if (u->type != UNIT_SNAPSHOT) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-                snapshot_remove(SNAPSHOT(u));
+        return sd_bus_send(bus, reply, NULL);
+}
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        int r;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-                _cleanup_free_ char *introspection = NULL;
-                FILE *f;
-                Iterator i;
-                Unit *u;
-                Job *j;
-                const char *k;
-                size_t size;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+        SELINUX_ACCESS_CHECK(bus, message, "status");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        r = bus_client_track(&m->subscribed, bus, sd_bus_message_get_sender(message));
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+        if (r == 0)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed.");
 
-                /* We roll our own introspection code here, instead of
-                 * relying on bus_default_message_handler() because we
-                 * need to generate our introspection string
-                 * dynamically. */
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                f = open_memstream(&introspection, &size);
-                if (!f)
-                        goto oom;
+static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        int r;
 
-                fputs(INTROSPECTION_BEGIN, f);
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-                        _cleanup_free_ char *p = NULL;
+        SELINUX_ACCESS_CHECK(bus, message, "status");
 
-                        if (k != u->id)
-                                continue;
+        r = bus_client_untrack(m->subscribed, bus, sd_bus_message_get_sender(message));
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+        if (r == 0)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
 
-                        p = bus_path_escape(k);
-                        if (!p) {
-                                fclose(f);
-                                goto oom;
-                        }
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                        fprintf(f, "<node name=\"unit/%s\"/>", p);
-                }
+static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_free_ char *dump = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        Manager *m = userdata;
+        size_t size;
 
-                HASHMAP_FOREACH(j, m->jobs, i)
-                        fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                fputs(INTROSPECTION_END, f);
+        SELINUX_ACCESS_CHECK(bus, message, "status");
 
-                if (ferror(f)) {
-                        fclose(f);
-                        goto oom;
-                }
+        f = open_memstream(&dump, &size);
+        if (!f)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
-                fclose(f);
+        manager_dump_units(m, f, NULL);
+        manager_dump_jobs(m, f, NULL);
 
-                if (!introspection)
-                        goto oom;
+        fflush(f);
 
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
-                        goto oom;
-                }
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
+        if (ferror(f))
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
-                SELINUX_ACCESS_CHECK(connection, message, "reload");
+        return sd_bus_reply_method_return(bus, message, "s", dump);
+}
 
-                assert(!m->queued_message);
+static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *path = NULL;
+        Manager *m = userdata;
+        const char *name;
+        int cleanup;
+        Snapshot *s;
+        int r;
 
-                /* Instead of sending the reply back right away, we
-                 * just remember that we need to and then send it
-                 * after the reload is finished. That way the caller
-                 * knows when the reload finished. */
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                m->queued_message = dbus_message_new_method_return(message);
-                if (!m->queued_message)
-                        goto oom;
+        SELINUX_ACCESS_CHECK(bus, message, "start");
 
-                m->queued_message_connection = connection;
-                m->exit_code = MANAGER_RELOAD;
+        r = sd_bus_message_read(message, "sb", &name, &cleanup);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
+        if (isempty(name))
+                name = NULL;
 
-                SELINUX_ACCESS_CHECK(connection, message, "reload");
+        r = snapshot_create(m, name, cleanup, &error, &s);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, &error);
 
-                /* We don't send a reply back here, the client should
-                 * just wait for us disconnecting. */
+        path = unit_dbus_path(UNIT(s));
+        if (!path)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
-                m->exit_code = MANAGER_REEXECUTE;
+        return sd_bus_reply_method_return(bus, message, "o", path);
+}
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
+static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
 
-                SELINUX_ACCESS_CHECK(connection, message, "halt");
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                if (m->running_as == SYSTEMD_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
+        SELINUX_ACCESS_CHECK(bus, message, "start");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                m->exit_code = MANAGER_EXIT;
+        u = manager_get_unit(m, name);
+        if (!u)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
+        if (u->type != UNIT_SNAPSHOT)
+                return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
 
-                SELINUX_ACCESS_CHECK(connection, message, "reboot");
+        return bus_snapshot_method_remove(bus, message, u);
+}
 
-                if (m->running_as != SYSTEMD_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
+static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        int r;
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                m->exit_code = MANAGER_REBOOT;
+        SELINUX_ACCESS_CHECK(bus, message, "reload");
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
+        /* Instead of sending the reply back right away, we just
+         * remember that we need to and then send it after the reload
+         * is finished. That way the caller knows when the reload
+         * finished. */
 
-                SELINUX_ACCESS_CHECK(connection, message, "halt");
+        assert(!m->queued_message);
+        r = sd_bus_message_new_method_return(bus, message, &m->queued_message);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                if (m->running_as != SYSTEMD_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
+        m->queued_message_bus = sd_bus_ref(bus);
+        m->exit_code = MANAGER_RELOAD;
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        return 1;
+}
 
-                m->exit_code = MANAGER_POWEROFF;
+static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_ACCESS_CHECK(connection, message, "halt");
+        SELINUX_ACCESS_CHECK(bus, message, "reload");
 
-                if (m->running_as != SYSTEMD_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
+        /* We don't send a reply back here, the client should
+         * just wait for us disconnecting. */
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        m->exit_code = MANAGER_REEXECUTE;
+        return 1;
+}
 
-                m->exit_code = MANAGER_HALT;
+static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_ACCESS_CHECK(connection, message, "reboot");
+        SELINUX_ACCESS_CHECK(bus, message, "halt");
 
-                if (m->running_as != SYSTEMD_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
+        if (m->running_as == SYSTEMD_SYSTEM)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        m->exit_code = MANAGER_EXIT;
 
-                m->exit_code = MANAGER_KEXEC;
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
-                const char *switch_root, *switch_root_init;
-                char *u, *v;
-                bool good;
+static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-                SELINUX_ACCESS_CHECK(connection, message, "reboot");
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &switch_root,
-                                    DBUS_TYPE_STRING, &switch_root_init,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+        SELINUX_ACCESS_CHECK(bus, message, "reboot");
 
-                if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+        if (m->running_as != SYSTEMD_SYSTEM)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
 
-                if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+        m->exit_code = MANAGER_REBOOT;
 
-                if (m->running_as != SYSTEMD_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                /* Safety check */
-                if (isempty(switch_root_init)) {
-                        good = path_is_os_tree(switch_root);
-                        if (!good)
-                                log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
-                }
-                else {
-                        _cleanup_free_ char *p = NULL;
 
-                        p = strjoin(switch_root, "/", switch_root_init, NULL);
-                        if (!p)
-                                goto oom;
+static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-                        good = access(p, X_OK) >= 0;
-                        if (!good)
-                                log_error("Not switching root: cannot execute new init %s", p);
-                }
-                if (!good)
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                u = strdup(switch_root);
-                if (!u)
-                        goto oom;
-
-                if (!isempty(switch_root_init)) {
-                        v = strdup(switch_root_init);
-                        if (!v) {
-                                free(u);
-                                goto oom;
-                        }
-                } else
-                        v = NULL;
-
-                free(m->switch_root);
-                free(m->switch_root_init);
-                m->switch_root = u;
-                m->switch_root_init = v;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                m->exit_code = MANAGER_SWITCH_ROOT;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
-                _cleanup_strv_free_ char **l = NULL;
-                char **e = NULL;
-
-                SELINUX_ACCESS_CHECK(connection, message, "reload");
-
-                r = bus_parse_strv(message, &l);
-                if (r == -ENOMEM)
-                        goto oom;
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
-                if (!strv_env_is_valid(l))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                e = strv_env_merge(2, m->environment, l);
-                if (!e)
-                        goto oom;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply) {
-                        strv_free(e);
-                        goto oom;
-                }
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                strv_free(m->environment);
-                m->environment = e;
+        SELINUX_ACCESS_CHECK(bus, message, "halt");
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
-                _cleanup_strv_free_ char **l = NULL;
-                char **e = NULL;
+        if (m->running_as != SYSTEMD_SYSTEM)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
 
-                SELINUX_ACCESS_CHECK(connection, message, "reload");
+        m->exit_code = MANAGER_POWEROFF;
 
-                r = bus_parse_strv(message, &l);
-                if (r == -ENOMEM)
-                        goto oom;
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
-                if (!strv_env_name_or_assignment_is_valid(l))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                e = strv_env_delete(m->environment, 1, l);
-                if (!e)
-                        goto oom;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply) {
-                        strv_free(e);
-                        goto oom;
-                }
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                strv_free(m->environment);
-                m->environment = e;
+static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
-                _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
-                char **f = NULL;
-                DBusMessageIter iter;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_ACCESS_CHECK(connection, message, "reload");
+        SELINUX_ACCESS_CHECK(bus, message, "halt");
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+        if (m->running_as != SYSTEMD_SYSTEM)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
 
-                r = bus_parse_strv_iter(&iter, &l_unset);
-                if (r == -ENOMEM)
-                        goto oom;
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
-                if (!strv_env_name_or_assignment_is_valid(l_unset))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+        m->exit_code = MANAGER_HALT;
 
-                if (!dbus_message_iter_next(&iter))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                r = bus_parse_strv_iter(&iter, &l_set);
-                if (r == -ENOMEM)
-                        goto oom;
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
-                if (!strv_env_is_valid(l_set))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                e = strv_env_delete(m->environment, 1, l_unset);
-                if (!e)
-                        goto oom;
-
-                f = strv_env_merge(2, e, l_set);
-                if (!f)
-                        goto oom;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply) {
-                        strv_free(f);
-                        goto oom;
-                }
+static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
 
-                strv_free(m->environment);
-                m->environment = f;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
-                DBusMessageIter iter, sub, sub2;
-                Hashmap *h;
-                Iterator i;
-                UnitFileList *item;
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+        SELINUX_ACCESS_CHECK(bus, message, "reboot");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        if (m->running_as != SYSTEMD_SYSTEM)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
 
-                h = hashmap_new(string_hash_func, string_compare_func);
-                if (!h)
-                        goto oom;
+        m->exit_code = MANAGER_KEXEC;
 
-                r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
-                if (r < 0) {
-                        unit_file_list_free(h);
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                dbus_message_iter_init_append(reply, &iter);
+static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        char *ri = NULL, *rt = NULL;
+        const char *root, *init;
+        Manager *m = userdata;
+        int r;
 
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
-                        unit_file_list_free(h);
-                        goto oom;
-                }
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                HASHMAP_FOREACH(item, h, i) {
-                        const char *state;
+        SELINUX_ACCESS_CHECK(bus, message, "reboot");
 
-                        state = unit_file_state_to_string(item->state);
-                        assert(state);
+        if (m->running_as != SYSTEMD_SYSTEM)
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
 
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
-                            !dbus_message_iter_close_container(&sub, &sub2)) {
-                                unit_file_list_free(h);
-                                goto oom;
-                        }
-                }
+        r = sd_bus_message_read(message, "ss", &root, &init);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                unit_file_list_free(h);
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
-                const char *name;
-                UnitFileState state;
-                const char *s;
-
-                SELINUX_ACCESS_CHECK(connection, message, "status");
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
-                if (state < 0)
-                        return bus_send_error_reply(connection, message, NULL, state);
-
-                s = unit_file_state_to_string(state);
-                assert(s);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_STRING, &s,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
-
-                char **l = NULL;
-                DBusMessageIter iter;
-                UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-                UnitFileChange *changes = NULL;
-                unsigned n_changes = 0;
-                dbus_bool_t runtime, force;
-                int carries_install_info = -1;
-
-                SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
-
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
-
-                r = bus_parse_strv_iter(&iter, &l);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
+        if (path_equal(root, "/") || !path_is_absolute(root))
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root);
 
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
+        /* Safety check */
+        if (isempty(init)) {
+                if (! path_is_os_tree(root))
+                        return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. /etc/os-release is missing.", root);
+        } else {
+                _cleanup_free_ char *p = NULL;
 
-                if (!dbus_message_iter_next(&iter) ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
-                        strv_free(l);
-                        return bus_send_error_reply(connection, message, NULL, -EIO);
-                }
+                if (!path_is_absolute(init))
+                        return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init);
 
-                if (streq(member, "EnableUnitFiles")) {
-                        r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(member, "ReenableUnitFiles")) {
-                        r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(member, "LinkUnitFiles"))
-                        r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
-                else if (streq(member, "PresetUnitFiles")) {
-                        r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(member, "MaskUnitFiles"))
-                        r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
-                else if (streq(member, "SetDefaultTarget"))
-                        r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
-                else
-                        assert_not_reached("Uh? Wrong method");
-
-                strv_free(l);
-                bus_manager_send_unit_files_changed(m);
+                p = strappend(root, init);
+                if (!p)
+                        return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
-                if (r < 0) {
-                        unit_file_changes_free(changes, n_changes);
-                        return bus_send_error_reply(connection, message, NULL, r);
+                if (access(p, X_OK) < 0)
+                        return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p);
+        }
+
+        rt = strdup(root);
+        if (!rt)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+        if (!isempty(init)) {
+                ri = strdup(init);
+                if (!ri) {
+                        free(ri);
+                        return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
                 }
+        }
 
-                reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
-                unit_file_changes_free(changes, n_changes);
+        free(m->switch_root);
+        m->switch_root = rt;
 
-                if (!reply)
-                        goto oom;
+        free(m->switch_root_init);
+        m->switch_root_init = ri;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
 
-                char **l = NULL;
-                DBusMessageIter iter;
-                UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-                UnitFileChange *changes = NULL;
-                unsigned n_changes = 0;
-                dbus_bool_t runtime;
+static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_strv_free_ char **plus = NULL;
+        Manager *m = userdata;
+        int r;
 
-                SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+        SELINUX_ACCESS_CHECK(bus, message, "reload");
 
-                r = bus_parse_strv_iter(&iter, &l);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
+        r = sd_bus_message_read_strv(message, &plus);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+        if (!strv_env_is_valid(plus))
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
 
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
+        r = manager_environment_add(m, NULL, plus);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                if (!dbus_message_iter_next(&iter) ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
-                        strv_free(l);
-                        return bus_send_error_reply(connection, message, NULL, -EIO);
-                }
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_strv_free_ char **minus = NULL;
+        Manager *m = userdata;
+        int r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, "reload");
 
-                if (streq(member, "DisableUnitFiles"))
-                        r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
-                else if (streq(member, "UnmaskUnitFiles"))
-                        r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
-                else
-                        assert_not_reached("Uh? Wrong method");
+        r = sd_bus_message_read_strv(message, &minus);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        if (!strv_env_name_or_assignment_is_valid(minus))
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
+
+        r = manager_environment_add(m, minus, NULL);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_strv_free_ char **minus = NULL, **plus = NULL;
+        Manager *m = userdata;
+        int r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, "reload");
+
+        r = sd_bus_message_read_strv(message, &plus);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        r = sd_bus_message_read_strv(message, &minus);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        if (!strv_env_is_valid(plus))
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
+        if (!strv_env_name_or_assignment_is_valid(minus))
+                return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
+
+        r = manager_environment_add(m, minus, plus);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        Manager *m = userdata;
+        UnitFileList *item;
+        Hashmap *h;
+        Iterator i;
+        int r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, "status");
+
+        r = sd_bus_message_new_method_return(bus, message, &reply);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                strv_free(l);
-                bus_manager_send_unit_files_changed(m);
+        h = hashmap_new(string_hash_func, string_compare_func);
+        if (!h)
+                return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
 
+        r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
+        if (r < 0) {
+                r = sd_bus_reply_method_errno(bus, message, r, NULL);
+                goto fail;
+        }
+
+        r = sd_bus_message_open_container(reply, 'a', "(ss)");
+        if (r < 0) {
+                r = sd_bus_reply_method_errno(bus, message, r, NULL);
+                goto fail;
+        }
+
+        HASHMAP_FOREACH(item, h, i) {
+
+                r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state));
                 if (r < 0) {
-                        unit_file_changes_free(changes, n_changes);
-                        return bus_send_error_reply(connection, message, NULL, r);
+                        r = sd_bus_reply_method_errno(bus, message, r, NULL);
+                        goto fail;
                 }
+        }
 
-                reply = message_from_file_changes(message, changes, n_changes, -1);
-                unit_file_changes_free(changes, n_changes);
+        unit_file_list_free(h);
 
-                if (!reply)
-                        goto oom;
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
-                UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-                _cleanup_free_ char *default_target = NULL;
+        return sd_bus_send(bus, reply, NULL);
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+fail:
+        unit_file_list_free(h);
+        return r;
+}
 
-                r = unit_file_get_default(scope, NULL, &default_target);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
+static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        Manager *m = userdata;
+        const char *name;
+        UnitFileState state;
+        UnitFileScope scope;
+        int r;
 
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
-                        goto oom;
-                }
+        assert(bus);
+        assert(message);
+        assert(m);
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
-                DBusMessageIter iter;
-                dbus_bool_t runtime;
-                const char *name;
-                Unit *u;
+        SELINUX_ACCESS_CHECK(bus, message, "status");
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+        scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
 
-                u = manager_get_unit(m, name);
-                if (!u) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
+        state = unit_file_get_state(scope, NULL, name);
+        if (state < 0)
+                return sd_bus_reply_method_errno(bus, message, state, NULL);
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
+        return sd_bus_reply_method_return(bus, message, "s", unit_file_state_to_string(state));
+}
 
-                r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
-                const char *name, *smode;
-                DBusMessageIter iter;
-                JobMode mode;
-                UnitType t;
-                Unit *u;
-
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
-
-                if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                t = unit_name_to_type(name);
-                if (t < 0)
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-                if (!unit_vtable[t]->can_transient) {
-                        dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
+static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        _cleanup_free_ char *default_target = NULL;
+        Manager *m = userdata;
+        UnitFileScope scope;
+        int r;
 
-                mode = job_mode_from_string(smode);
-                if (mode < 0) {
-                        dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                r = manager_load_unit(m, name, NULL, NULL, &u);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+        SELINUX_ACCESS_CHECK(bus, message, "status");
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
+        scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
 
-                if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
-                        dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
-                        return bus_send_error_reply(connection, message, &error, -EEXIST);
-                }
+        r = unit_file_get_default(scope, NULL, &default_target);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                /* OK, the unit failed to load and is unreferenced,
-                 * now let's fill in the transient data instead */
-                r = unit_make_transient(u);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+        return sd_bus_reply_method_return(bus, message, "s", default_target);
+}
 
-                /* Set our properties */
-                r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
+static int send_unit_files_changed(sd_bus *bus, const char *destination, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
+        int r;
+
+        assert(bus);
+
+        r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged", &message);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send_to(bus, message, destination, NULL);
+}
+
+static int reply_unit_file_changes_and_free(
+                Manager *m,
+                sd_bus *bus,
+                sd_bus_message *message,
+                int carries_install_info,
+                UnitFileChange *changes,
+                unsigned n_changes) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        unsigned i;
+        int r;
+
+        if (n_changes > 0)
+                bus_manager_foreach_client(m, send_unit_files_changed, NULL);
+
+        r = sd_bus_message_new_method_return(bus, message, &reply);
+        if (r < 0)
+                goto fail;
+
+        if (carries_install_info >= 0) {
+                r = sd_bus_message_append(reply, "b", carries_install_info);
                 if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+                        goto fail;
+        }
+
+        r = sd_bus_message_open_container(reply, 'a', "(sss)");
+        if (r < 0)
+                goto fail;
 
-                /* And load this stub fully */
-                r = unit_load(u);
+        for (i = 0; i < n_changes; i++) {
+                r = sd_bus_message_append(
+                                message, "(sss)",
+                                unit_file_change_type_to_string(changes[i].type),
+                                changes[i].path,
+                                changes[i].source);
                 if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+                        goto fail;
+        }
 
-                manager_dispatch_load_queue(m);
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                goto fail;
 
-                /* Finally, start it */
-                return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
+        return sd_bus_send(bus, message, NULL);
 
-        } else {
-                const BusBoundProperties bps[] = {
-                        { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
-                        { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
-                        { NULL, }
-                };
+fail:
+        unit_file_changes_free(changes, n_changes);
+        return sd_bus_reply_method_errno(bus, message, r, NULL);
+}
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+static int method_enable_unit_files_generic(
+                sd_bus *bus,
+                sd_bus_message *message,
+                Manager *m, const
+                char *verb,
+                int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
+                bool carries_install_info) {
+
+        _cleanup_strv_free_ char **l = NULL;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        UnitFileScope scope;
+        int runtime, force, r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
 
-                return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
-        }
+        SELINUX_ACCESS_CHECK(bus, message, verb);
 
-        if (job_type != _JOB_TYPE_INVALID) {
-                const char *name, *smode, *old_name = NULL;
-                JobMode mode;
-                Unit *u;
-                dbus_bool_t b;
-
-                if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
-                        b = dbus_message_get_args(
-                                        message,
-                                        &error,
-                                        DBUS_TYPE_STRING, &old_name,
-                                        DBUS_TYPE_STRING, &name,
-                                        DBUS_TYPE_STRING, &smode,
-                                        DBUS_TYPE_INVALID);
-                else
-                        b = dbus_message_get_args(
-                                        message,
-                                        &error,
-                                        DBUS_TYPE_STRING, &name,
-                                        DBUS_TYPE_STRING, &smode,
-                                        DBUS_TYPE_INVALID);
-                if (!b)
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (old_name) {
-                        u = manager_get_unit(m, old_name);
-                        if (!u || !u->job || u->job->type != JOB_START) {
-                                dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
-                                return bus_send_error_reply(connection, message, &error, -ENOENT);
-                        }
-                }
+        r = sd_bus_message_read_strv(message, &l);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                mode = job_mode_from_string(smode);
-                if (mode < 0) {
-                        dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
+        r = sd_bus_message_read(message, "bb", &runtime, &force);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
 
-                r = manager_load_unit(m, name, NULL, &error, &u);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+        scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
 
-                return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
-        }
+        r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        return reply_unit_file_changes_and_free(m, bus, message, carries_install_info ? r : -1, changes, n_changes);
+}
 
-        if (reply)
-                if (!bus_maybe_send_reply(connection, message, reply))
-                        goto oom;
+static int method_enable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_enable, true);
+}
 
-        return DBUS_HANDLER_RESULT_HANDLED;
+static int method_reenable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_reenable, true);
+}
+
+static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false);
+}
+
+static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_preset, true);
+}
+
+static int method_mask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_enable_unit_files_generic(bus, message, userdata, "disable", unit_file_mask, false);
+}
 
-oom:
-        dbus_error_free(&error);
+static int method_disable_unit_files_generic(
+                sd_bus *bus,
+                sd_bus_message *message,
+                Manager *m, const
+                char *verb,
+                int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes)) {
+
+        _cleanup_strv_free_ char **l = NULL;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        UnitFileScope scope;
+        int r, runtime;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, verb);
+
+        r = sd_bus_message_read_strv(message, &l);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        r = sd_bus_message_read(message, "b", &runtime);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+
+        r = call(scope, runtime, NULL, l, &changes, &n_changes);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+}
 
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+static int method_disable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_disable_unit_files_generic(bus, message, userdata, "disable", unit_file_disable);
 }
 
-const DBusObjectPathVTable bus_manager_vtable = {
-        .message_function = bus_manager_message_handler
+static int method_unmask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        return method_disable_unit_files_generic(bus, message, userdata, "enable", unit_file_unmask);
+}
+
+static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void *userdata) {
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        Manager *m = userdata;
+        UnitFileScope scope;
+        const char *name;
+        int force, r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        SELINUX_ACCESS_CHECK(bus, message, "enable");
+
+        r = sd_bus_message_read(message, "sb", &name, &force);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+
+        r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+        return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+}
+
+const sd_bus_vtable bus_manager_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("Version", "s", property_get_version, 0, 0),
+        SD_BUS_PROPERTY("Features", "s", property_get_features, 0, 0),
+        SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, 0),
+        SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, firmware_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("LoaderTimestamp", offsetof(Manager, loader_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("KernelTimestamp", offsetof(Manager, firmware_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, initrd_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, userspace_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, finish_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, security_start_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, security_finish_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, generators_start_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, generators_finish_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, units_load_start_timestamp), 0),
+        BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, units_load_finish_timestamp), 0),
+        SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
+        SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
+        SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0),
+        SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0),
+        SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
+        SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
+        SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
+        SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
+        SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), 0),
+        SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), 0),
+        SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), 0),
+        SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), 0),
+        SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), 0),
+        SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
+        SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
+
+        SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, 0),
+        SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, 0),
+        SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, 0),
+        SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, 0),
+        SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, 0),
+        SD_BUS_METHOD("StopUnit", "ss", "o", method_stop_unit, 0),
+        SD_BUS_METHOD("ReloadUnit", "ss", "o", method_reload_unit, 0),
+        SD_BUS_METHOD("RestartUnit", "ss", "o", method_restart_unit, 0),
+        SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, 0),
+        SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, 0),
+        SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, 0),
+        SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, 0),
+        SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, 0),
+        SD_BUS_METHOD("SetUnitProperties", "sb", "a(sv)", method_set_unit_properties, 0),
+        SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, 0),
+        SD_BUS_METHOD("GetJob", "u", "o", method_get_job, 0),
+        SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, 0),
+        SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, 0),
+        SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, 0),
+        SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, 0),
+        SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, 0),
+        SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, 0),
+        SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, 0),
+        SD_BUS_METHOD("Dump", NULL, "s", method_dump, 0),
+        SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0),
+        SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),
+        SD_BUS_METHOD("Reload", NULL, NULL, method_reload, 0),
+        SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, 0),
+        SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
+        SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, 0),
+        SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, 0),
+        SD_BUS_METHOD("Halt", NULL, NULL, method_halt, 0),
+        SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, 0),
+        SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, 0),
+        SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, 0),
+        SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, 0),
+        SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, 0),
+        SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, 0),
+        SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, 0),
+        SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, 0),
+        SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, 0),
+        SD_BUS_METHOD("ReenableUnitFiles", "asbb", "ba(sss)", method_reenable_unit_files, 0),
+        SD_BUS_METHOD("LinkUnitFiles", "asbb", "a(sss)", method_link_unit_files, 0),
+        SD_BUS_METHOD("PresetUnitFiles", "asbb", "ba(sss)", method_preset_unit_files, 0),
+        SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, 0),
+        SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, 0),
+        SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, 0),
+        SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, 0),
+
+        SD_BUS_SIGNAL("UnitNew", "so", 0),
+        SD_BUS_SIGNAL("UnitRemoved", "so", 0),
+        SD_BUS_SIGNAL("JobNew", "uos", 0),
+        SD_BUS_SIGNAL("JobRemoved", "uoss", 0),
+        SD_BUS_SIGNAL("StartupFinished", "tttttt", 0),
+        SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0),
+        SD_BUS_SIGNAL("Reloading", "b", 0),
+
+        SD_BUS_VTABLE_END
 };
+
+int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata) {
+        Iterator i;
+        sd_bus *b;
+        unsigned n;
+        int r;
+
+        n = set_size(m->subscribed);
+        if (n <= 0)
+                return 0;
+        if (n == 1) {
+                BusTrackedClient *d;
+
+                assert_se(d = set_first(m->subscribed));
+                return send_message(d->bus, isempty(d->name) ? NULL : d->name, userdata);
+        }
+
+        /* Send to everybody */
+        SET_FOREACH(b, m->private_buses, i) {
+                r = send_message(b, NULL, userdata);
+                if (r < 0)
+                        return r;
+        }
+
+        if (m->api_bus)
+                return send_message(m->api_bus, NULL, userdata);
+
+        return 0;
+}
+
+static int send_finished(sd_bus *bus, const char *destination, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
+        usec_t *times = userdata;
+        int r;
+
+        assert(bus);
+        assert(times);
+
+        r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished", &message);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(message, "tttttt", times[0], times[1], times[2], times[3], times[4], times[5]);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send_to(bus, message, destination, NULL);
+}
+
+int bus_manager_send_finished(
+                Manager *m,
+                usec_t firmware_usec,
+                usec_t loader_usec,
+                usec_t kernel_usec,
+                usec_t initrd_usec,
+                usec_t userspace_usec,
+                usec_t total_usec) {
+
+        assert(m);
+
+        return bus_manager_foreach_client(m, send_finished,
+                        (usec_t[6]) { firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec });
+}
+
+static int send_reloading(sd_bus *bus, const char *destination, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
+        int r;
+
+        assert(bus);
+
+        r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading", &message);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(message, "b", PTR_TO_INT(userdata));
+        if (r < 0)
+                return r;
+
+        return sd_bus_send_to(bus, message, destination, NULL);
+}
+
+int bus_manager_send_reloading(Manager *m, bool active) {
+        assert(m);
+
+        return bus_manager_foreach_client(m, send_reloading, INT_TO_PTR(active));
+}
index f0dce5a..ad451eb 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
+#include "sd-bus.h"
+#include "manager.h"
 
-extern const DBusObjectPathVTable bus_manager_vtable;
+extern const sd_bus_vtable bus_manager_vtable[];
 
-extern const char bus_manager_interface[];
+int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata);
+
+int bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec);
+int bus_manager_send_reloading(Manager *m, bool active);
index 70b2d48..2056eab 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <errno.h>
-
+#include "unit.h"
+#include "mount.h"
 #include "dbus-unit.h"
 #include "dbus-execute.h"
 #include "dbus-kill.h"
 #include "dbus-cgroup.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
 #include "dbus-mount.h"
-
-#define BUS_MOUNT_INTERFACE                                             \
-        " <interface name=\"org.freedesktop.systemd1.Mount\">\n"        \
-        "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"     \
-        "  <property name=\"What\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Options\" type=