chiark / gitweb /
getty: fix message
[elogind.git] / src / dbus.c
index af03c5746ca6dddfe4bf73fd9c443fe1d523083f..daa2c84a05925d9d5b51feeee972e7b823972580 100644 (file)
@@ -44,6 +44,7 @@
 #include "dbus-path.h"
 #include "bus-errors.h"
 #include "special.h"
+#include "dbus-common.h"
 
 #define CONNECTIONS_MAX 52
 
@@ -69,7 +70,6 @@ const char *const bus_interface_table[] = {
         NULL
 };
 
-static const char *error_to_dbus(int error);
 static void bus_done_api(Manager *m);
 static void bus_done_system(Manager *m);
 static void bus_done_private(Manager *m);
@@ -91,41 +91,6 @@ static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status,
                 set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
 }
 
-static uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
-        unsigned flags;
-        uint32_t events = 0;
-
-        assert(bus_watch);
-
-        /* no watch flags for disabled watches */
-        if (!dbus_watch_get_enabled(bus_watch))
-                return 0;
-
-        flags = dbus_watch_get_flags(bus_watch);
-
-        if (flags & DBUS_WATCH_READABLE)
-                events |= EPOLLIN;
-        if (flags & DBUS_WATCH_WRITABLE)
-                events |= EPOLLOUT;
-
-        return events | EPOLLHUP | EPOLLERR;
-}
-
-static unsigned events_to_bus_flags(uint32_t events) {
-        unsigned flags = 0;
-
-        if (events & EPOLLIN)
-                flags |= DBUS_WATCH_READABLE;
-        if (events & EPOLLOUT)
-                flags |= DBUS_WATCH_WRITABLE;
-        if (events & EPOLLHUP)
-                flags |= DBUS_WATCH_HANGUP;
-        if (events & EPOLLERR)
-                flags |= DBUS_WATCH_ERROR;
-
-        return flags;
-}
-
 void bus_watch_event(Manager *m, Watch *w, int events) {
         assert(m);
         assert(w);
@@ -136,7 +101,7 @@ void bus_watch_event(Manager *m, Watch *w, int events) {
         if (!dbus_watch_get_enabled(w->data.bus_watch))
                 return;
 
-        dbus_watch_handle(w->data.bus_watch, events_to_bus_flags(events));
+        dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
 }
 
 static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
@@ -176,8 +141,8 @@ static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
                 }
 
                 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
-                        free(w);
                         close_nointr_nofail(w->fd);
+                        free(w);
                         return FALSE;
                 }
 
@@ -196,7 +161,8 @@ static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
         assert(bus_watch);
         assert(m);
 
-        if (!(w = dbus_watch_get_data(bus_watch)))
+        w = dbus_watch_get_data(bus_watch);
+        if (!w)
                 return;
 
         assert(w->type == WATCH_DBUS_WATCH);
@@ -216,7 +182,10 @@ static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
         assert(bus_watch);
         assert(m);
 
-        assert_se(w = dbus_watch_get_data(bus_watch));
+        w = dbus_watch_get_data(bus_watch);
+        if (!w)
+                return;
+
         assert(w->type == WATCH_DBUS_WATCH);
 
         zero(ev);
@@ -236,7 +205,7 @@ static int bus_timeout_arm(Manager *m, Watch *w) {
 
         if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
                 timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
-                its.it_interval = its.it_interval;
+                its.it_interval = its.it_value;
         }
 
         if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
@@ -269,7 +238,7 @@ static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
         if (!(w = new0(Watch, 1)))
                 return FALSE;
 
-        if (!(w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
+        if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
                 goto fail;
 
         w->type = WATCH_DBUS_TIMEOUT;
@@ -304,10 +273,12 @@ static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
         assert(timeout);
         assert(m);
 
-        if (!(w = dbus_timeout_get_data(timeout)))
+        w = dbus_timeout_get_data(timeout);
+        if (!w)
                 return;
 
         assert(w->type == WATCH_DBUS_TIMEOUT);
+
         assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
         close_nointr_nofail(w->fd);
         free(w);
@@ -321,7 +292,10 @@ static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
         assert(timeout);
         assert(m);
 
-        assert_se(w = dbus_timeout_get_data(timeout));
+        w = dbus_timeout_get_data(timeout);
+        if (!w)
+                return;
+
         assert(w->type == WATCH_DBUS_TIMEOUT);
 
         if ((r = bus_timeout_arm(m, w)) < 0)
@@ -358,7 +332,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
                                            DBUS_TYPE_STRING, &old_owner,
                                            DBUS_TYPE_STRING, &new_owner,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse NameOwnerChanged message: %s", error.message);
+                        log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
                 else  {
                         if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
                                 log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
@@ -377,7 +351,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
                 if (!dbus_message_get_args(message, &error,
                                            DBUS_TYPE_STRING, &name,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse ActivationRequest message: %s", error.message);
+                        log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
                 else  {
                         int r;
                         Unit *u;
@@ -406,7 +380,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
                                 if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
                                         goto oom;
 
-                                id = error.name ? error.name : error_to_dbus(r);
+                                id = error.name ? error.name : bus_errno_to_dbus(r);
                                 text = bus_error(&error, r);
 
                                 if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
@@ -472,7 +446,7 @@ static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, D
                 if (!dbus_message_get_args(message, &error,
                                            DBUS_TYPE_STRING, &cgroup,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse Released message: %s", error.message);
+                        log_error("Failed to parse Released message: %s", bus_error_message(&error));
                 else
                         cgroup_notify_empty(m, cgroup);
         }
@@ -508,7 +482,7 @@ static DBusHandlerResult private_bus_message_filter(DBusConnection *connection,
                 if (!dbus_message_get_args(message, &error,
                                            DBUS_TYPE_STRING, &cgroup,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse Released message: %s", error.message);
+                        log_error("Failed to parse Released message: %s", bus_error_message(&error));
                 else
                         cgroup_notify_empty(m, cgroup);
 
@@ -566,7 +540,7 @@ static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
         case DBUS_MESSAGE_TYPE_ERROR:
 
                 assert_se(dbus_set_error_from_message(&error, reply));
-                log_warning("RequestName() failed: %s", error.message);
+                log_warning("RequestName() failed: %s", bus_error_message(&error));
                 break;
 
         case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
@@ -576,7 +550,7 @@ static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
                                            &error,
                                            DBUS_TYPE_UINT32, &r,
                                            DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse RequestName() reply: %s", error.message);
+                        log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error));
                         break;
                 }
 
@@ -598,7 +572,12 @@ static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
 
 static int request_name(Manager *m) {
         const char *name = "org.freedesktop.systemd1";
-        uint32_t flags = 0;
+        /* Allow replacing of our name, to ease implementation of
+         * reexecution, where we keep the old connection open until
+         * after the new connection is set up and the name installed
+         * to allow clients to synchronously wait for reexecution to
+         * finish */
+        uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
         DBusMessage *message = NULL;
         DBusPendingCall *pending = NULL;
 
@@ -658,7 +637,7 @@ static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata)
         case DBUS_MESSAGE_TYPE_ERROR:
 
                 assert_se(dbus_set_error_from_message(&error, reply));
-                log_warning("ListNames() failed: %s", error.message);
+                log_warning("ListNames() failed: %s", bus_error_message(&error));
                 break;
 
         case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
@@ -752,8 +731,8 @@ static int bus_setup_loop(Manager *m, DBusConnection *bus) {
         return 0;
 }
 
-static dbus_bool_t allow_only_root(DBusConnection *connection, unsigned long uid, void *data) {
-        return uid == 0;
+static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
+        return uid == 0 || uid == geteuid();
 }
 
 static void bus_new_connection(
@@ -770,7 +749,7 @@ static void bus_new_connection(
                 return;
         }
 
-        dbus_connection_set_unix_user_function(new_connection, allow_only_root, NULL, NULL);
+        dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
 
         if (bus_setup_loop(m, new_connection) < 0)
                 return;
@@ -803,7 +782,7 @@ static int bus_init_system(Manager *m) {
                 m->system_bus = m->api_bus;
         else {
                 if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
-                        log_debug("Failed to get system D-Bus connection, retrying later: %s", error.message);
+                        log_debug("Failed to get system D-Bus connection, retrying later: %s", bus_error_message(&error));
                         r = 0;
                         goto fail;
                 }
@@ -814,7 +793,7 @@ static int bus_init_system(Manager *m) {
 
         if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
                 log_error("Not enough memory");
-                r = -EIO;
+                r = -ENOMEM;
                 goto fail;
         }
 
@@ -827,7 +806,7 @@ static int bus_init_system(Manager *m) {
                                    &error);
 
                 if (dbus_error_is_set(&error)) {
-                        log_error("Failed to register match: %s", error.message);
+                        log_error("Failed to register match: %s", bus_error_message(&error));
                         r = -EIO;
                         goto fail;
                 }
@@ -865,7 +844,7 @@ static int bus_init_api(Manager *m) {
                 m->api_bus = m->system_bus;
         else {
                 if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_USER ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
-                        log_debug("Failed to get API D-Bus connection, retrying later: %s", error.message);
+                        log_debug("Failed to get API D-Bus connection, retrying later: %s", bus_error_message(&error));
                         r = 0;
                         goto fail;
                 }
@@ -893,7 +872,7 @@ static int bus_init_api(Manager *m) {
                            &error);
 
         if (dbus_error_is_set(&error)) {
-                log_error("Failed to register match: %s", error.message);
+                log_error("Failed to register match: %s", bus_error_message(&error));
                 r = -EIO;
                 goto fail;
         }
@@ -908,7 +887,7 @@ static int bus_init_api(Manager *m) {
                            &error);
 
         if (dbus_error_is_set(&error)) {
-                log_error("Failed to register match: %s", error.message);
+                log_error("Failed to register match: %s", bus_error_message(&error));
                 r = -EIO;
                 goto fail;
         }
@@ -951,12 +930,36 @@ static int bus_init_private(Manager *m) {
         if (m->private_bus)
                 return 0;
 
-        /* We want the private bus only when running as init */
-        if (getpid() != 1)
-                return 0;
+        if (m->running_as == MANAGER_SYSTEM) {
+
+                /* We want the private bus only when running as init */
+                if (getpid() != 1)
+                        return 0;
+
+                unlink("/run/systemd/private");
+                m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
+        } else {
+                const char *e;
+                char *p;
+
+                e = getenv("XDG_RUNTIME_DIR");
+                if (!e)
+                        return 0;
 
-        if (!(m->private_bus = dbus_server_listen("unix:abstract=/org/freedesktop/systemd1/private", &error))) {
-                log_error("Failed to create private D-Bus server: %s", error.message);
+                if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) {
+                        log_error("Not enough memory");
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                mkdir_parents(p+10, 0755);
+                unlink(p+10);
+                m->private_bus = dbus_server_listen(p, &error);
+                free(p);
+        }
+
+        if (!m->private_bus) {
+                log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
                 r = -EIO;
                 goto fail;
         }
@@ -1133,7 +1136,7 @@ static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
         case DBUS_MESSAGE_TYPE_ERROR:
 
                 assert_se(dbus_set_error_from_message(&error, reply));
-                log_warning("GetConnectionUnixProcessID() failed: %s", error.message);
+                log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error));
                 break;
 
         case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
@@ -1143,7 +1146,7 @@ static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
                                            &error,
                                            DBUS_TYPE_UINT32, &r,
                                            DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", error.message);
+                        log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error));
                         break;
                 }
 
@@ -1213,289 +1216,6 @@ oom:
         return -ENOMEM;
 }
 
-DBusHandlerResult bus_default_message_handler(
-                Manager *m,
-                DBusConnection *c,
-                DBusMessage *message,
-                const char *introspection,
-                const char *interfaces,
-                const BusProperty *properties) {
-
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(message);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                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.DBus.Properties", "Get") && properties) {
-                const char *interface, *property;
-                const BusProperty *p;
-
-                if (!dbus_message_get_args(
-                            message,
-                            &error,
-                            DBUS_TYPE_STRING, &interface,
-                            DBUS_TYPE_STRING, &property,
-                            DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, c, message, &error, -EINVAL);
-
-                for (p = properties; p->property; p++)
-                        if (streq(p->interface, interface) && streq(p->property, property))
-                                break;
-
-                if (p->property) {
-                        DBusMessageIter iter, sub;
-
-                        if (!(reply = dbus_message_new_method_return(message)))
-                                goto oom;
-
-                        dbus_message_iter_init_append(reply, &iter);
-
-                        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
-                                goto oom;
-
-                        if ((r = p->append(m, &sub, property, (void*) p->data)) < 0) {
-
-                                if (r == -ENOMEM)
-                                        goto oom;
-
-                                dbus_message_unref(reply);
-                                return bus_send_error_reply(m, c, message, NULL, r);
-                        }
-
-                        if (!dbus_message_iter_close_container(&iter, &sub))
-                                goto oom;
-                } else {
-                        if (!nulstr_contains(interfaces, interface))
-                                dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                        else
-                                dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
-
-                        return bus_send_error_reply(m, c, message, &error, -EINVAL);
-                }
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
-                const char *interface;
-                const BusProperty *p;
-                DBusMessageIter iter, sub, sub2, sub3;
-
-                if (!dbus_message_get_args(
-                            message,
-                            &error,
-                            DBUS_TYPE_STRING, &interface,
-                            DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, c, message, &error, -EINVAL);
-
-                if (interface[0] && !nulstr_contains(interfaces, interface)) {
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                        return bus_send_error_reply(m, c, message, &error, -EINVAL);
-                }
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
-                        goto oom;
-
-                for (p = properties; p->property; p++) {
-                        if (interface[0] && !streq(p->interface, interface))
-                                continue;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
-                            !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
-                                goto oom;
-
-                        if ((r = p->append(m, &sub3, p->property, (void*) p->data)) < 0) {
-
-                                if (r == -ENOMEM)
-                                        goto oom;
-
-                                dbus_message_unref(reply);
-                                return bus_send_error_reply(m, c, message, NULL, r);
-                        }
-
-                        if (!dbus_message_iter_close_container(&sub2, &sub3) ||
-                            !dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && properties) {
-                const char *interface, *property;
-                DBusMessageIter iter;
-                const BusProperty *p;
-
-                if (!dbus_message_iter_init(message, &iter) ||
-                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                        return bus_send_error_reply(m, c, message, NULL, -EINVAL);
-
-                dbus_message_iter_get_basic(&iter, &interface);
-
-                if (!dbus_message_iter_next(&iter) ||
-                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                        return bus_send_error_reply(m, c, message, NULL, -EINVAL);
-
-                dbus_message_iter_get_basic(&iter, &property);
-
-                if (!dbus_message_iter_next(&iter) ||
-                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
-                    dbus_message_iter_has_next(&iter))
-                        return bus_send_error_reply(m, c, message, NULL, -EINVAL);
-
-                for (p = properties; p->property; p++)
-                        if (streq(p->interface, interface) && streq(p->property, property))
-                                break;
-
-                if (p->set) {
-                        DBusMessageIter sub;
-                        char *sig;
-
-                        dbus_message_iter_recurse(&iter, &sub);
-
-                        if (!(sig = dbus_message_iter_get_signature(&sub)))
-                                goto oom;
-
-                        if (!streq(sig, p->signature)) {
-                                dbus_free(sig);
-                                return bus_send_error_reply(m, c, message, NULL, -EINVAL);
-                        }
-
-                        dbus_free(sig);
-
-                        if ((r = p->set(m, &sub, property)) < 0) {
-                                if (r == -ENOMEM)
-                                        goto oom;
-                                return bus_send_error_reply(m, c, message, NULL, r);
-                        }
-
-                        if (!(reply = dbus_message_new_method_return(message)))
-                                goto oom;
-                } else {
-                        if (p->property)
-                                dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
-                        else if (!nulstr_contains(interfaces, interface))
-                                dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                        else
-                                dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
-
-                        return bus_send_error_reply(m, c, message, &error, -EINVAL);
-                }
-
-        } else if (!nulstr_contains(interfaces, dbus_message_get_interface(message))) {
-                dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                return bus_send_error_reply(m, c, message, &error, -EINVAL);
-        }
-
-        if (reply) {
-                if (!dbus_connection_send(c, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-                return DBUS_HANDLER_RESULT_HANDLED;
-        }
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-static const char *error_to_dbus(int error) {
-
-        switch(error) {
-
-        case -EINVAL:
-                return DBUS_ERROR_INVALID_ARGS;
-
-        case -ENOMEM:
-                return DBUS_ERROR_NO_MEMORY;
-
-        case -EPERM:
-        case -EACCES:
-                return DBUS_ERROR_ACCESS_DENIED;
-
-        case -ESRCH:
-                return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
-
-        case -ENOENT:
-                return DBUS_ERROR_FILE_NOT_FOUND;
-
-        case -EEXIST:
-                return DBUS_ERROR_FILE_EXISTS;
-
-        case -ETIMEDOUT:
-        case -ETIME:
-                return DBUS_ERROR_TIMEOUT;
-
-        case -EIO:
-                return DBUS_ERROR_IO_ERROR;
-
-        case -ENETRESET:
-        case -ECONNABORTED:
-        case -ECONNRESET:
-                return DBUS_ERROR_DISCONNECTED;
-        }
-
-        return DBUS_ERROR_FAILED;
-}
-
-DBusHandlerResult bus_send_error_reply(Manager *m, DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
-        DBusMessage *reply = NULL;
-        const char *name, *text;
-
-        if (berror && dbus_error_is_set(berror)) {
-                name = berror->name;
-                text = berror->message;
-        } else {
-                name = error_to_dbus(error);
-                text = strerror(-error);
-        }
-
-        if (!(reply = dbus_message_new_error(message, name, text)))
-                goto oom;
-
-        if (!dbus_connection_send(c, reply, NULL))
-                goto oom;
-
-        dbus_message_unref(reply);
-
-        if (berror)
-                dbus_error_free(berror);
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        if (berror)
-                dbus_error_free(berror);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
 int bus_broadcast(Manager *m, DBusMessage *message) {
         bool oom = false;
         Iterator i;
@@ -1515,247 +1235,104 @@ int bus_broadcast(Manager *m, DBusMessage *message) {
         return oom ? -ENOMEM : 0;
 }
 
-int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        const char *t = data;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        if (!t)
-                t = "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        DBusMessageIter sub;
-        char **t = data;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
-
-        STRV_FOREACH(t, t)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t))
-                        return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        bool *b = data;
-        dbus_bool_t db;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(b);
-
-        db = *b;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
-
-        /* Let's ensure that pid_t is actually 64bit, and hence this
-         * function can be used for usec_t */
-        assert_cc(sizeof(uint64_t) == sizeof(usec_t));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
-
-        /* Let's ensure that pid_t and mode_t is actually 32bit, and
-         * hence this function can be used for pid_t/mode_t */
-        assert_cc(sizeof(uint32_t) == sizeof(pid_t));
-        assert_cc(sizeof(uint32_t) == sizeof(mode_t));
-        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
-                return -ENOMEM;
-
-        return 0;
-}
+bool bus_has_subscriber(Manager *m) {
+        Iterator i;
+        DBusConnection *c;
 
-int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
         assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
 
-        assert_cc(sizeof(int32_t) == sizeof(int));
+        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
+                if (bus_connection_has_subscriber(m, c))
+                        return true;
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
-                return -ENOMEM;
+        SET_FOREACH(c, m->bus_connections, i)
+                if (bus_connection_has_subscriber(m, c))
+                        return true;
 
-        return 0;
+        return false;
 }
 
-int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        uint64_t u;
-
+bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
         assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
-
-        u = (uint64_t) *(size_t*) data;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
+        assert(c);
 
-        return 0;
+        return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
 }
 
-int bus_property_append_ul(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        uint64_t u;
+int bus_fdset_add_all(Manager *m, FDSet *fds) {
+        Iterator i;
+        DBusConnection *c;
 
         assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
+        assert(fds);
 
-        u = (uint64_t) *(unsigned long*) data;
+        /* When we are about to reexecute we add all D-Bus fds to the
+         * set to pass over to the newly executed systemd. They won't
+         * be used there however, except that they are closed at the
+         * very end of deserialization, those making it possible for
+         * clients to synchronously wait for systemd to reexec by
+         * simply waiting for disconnection */
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
+        SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
+                int fd;
 
-        return 0;
-}
+                if (dbus_connection_get_unix_fd(c, &fd)) {
+                        fd = fdset_put_dup(fds, fd);
 
-int bus_parse_strv(DBusMessage *m, char ***_l) {
-        DBusMessageIter iter, sub;
-        unsigned n = 0, i = 0;
-        char **l;
-
-        assert(m);
-        assert(_l);
-
-        if (!dbus_message_iter_init(m, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
-            return -EINVAL;
-
-        dbus_message_iter_recurse(&iter, &sub);
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                n++;
-                dbus_message_iter_next(&sub);
+                        if (fd < 0)
+                                return fd;
+                }
         }
 
-        if (!(l = new(char*, n+1)))
-                return -ENOMEM;
-
-        assert_se(dbus_message_iter_init(m, &iter));
-        dbus_message_iter_recurse(&iter, &sub);
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *s;
+        SET_FOREACH(c, m->bus_connections, i) {
+                int fd;
 
-                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
-                dbus_message_iter_get_basic(&sub, &s);
+                if (dbus_connection_get_unix_fd(c, &fd)) {
+                        fd = fdset_put_dup(fds, fd);
 
-                if (!(l[i++] = strdup(s))) {
-                        strv_free(l);
-                        return -ENOMEM;
+                        if (fd < 0)
+                                return fd;
                 }
-
-                dbus_message_iter_next(&sub);
         }
 
-        assert(i == n);
-        l[i] = NULL;
-
-        if (_l)
-                *_l = l;
-
         return 0;
 }
 
-bool bus_has_subscriber(Manager *m) {
-        Iterator i;
-        DBusConnection *c;
-
-        assert(m);
-
-        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
-                if (bus_connection_has_subscriber(m, c))
-                        return true;
-
-        SET_FOREACH(c, m->bus_connections, i)
-                if (bus_connection_has_subscriber(m, c))
-                        return true;
+void bus_broadcast_finished(
+                Manager *m,
+                usec_t kernel_usec,
+                usec_t initrd_usec,
+                usec_t userspace_usec,
+                usec_t total_usec) {
 
-        return false;
-}
+        DBusMessage *message;
 
-bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
         assert(m);
-        assert(c);
-
-        return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
-}
 
-DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
-        DBusMessage *m;
-        DBusMessageIter iter, sub;
-        const char *i;
-
-        assert(interface);
-        assert(properties);
-
-        if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
-                goto oom;
-
-        dbus_message_iter_init_append(m, &iter);
-
-        /* We won't send any property values, since they might be
-         * large and sometimes not cheap to generated */
-
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
-            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
-            !dbus_message_iter_close_container(&iter, &sub) ||
-            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
-                goto oom;
-
-        NULSTR_FOREACH(i, properties)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
-                        goto oom;
+        message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
+        if (!message) {
+                log_error("Out of memory.");
+                return;
+        }
 
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                goto oom;
+        assert_cc(sizeof(usec_t) == sizeof(uint64_t));
+        if (!dbus_message_append_args(message,
+                                      DBUS_TYPE_UINT64, &kernel_usec,
+                                      DBUS_TYPE_UINT64, &initrd_usec,
+                                      DBUS_TYPE_UINT64, &userspace_usec,
+                                      DBUS_TYPE_UINT64, &total_usec,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Out of memory.");
+                goto finish;
+        }
 
-        return m;
 
-oom:
-        if (m)
-                dbus_message_unref(m);
+        if (bus_broadcast(m, message) < 0) {
+                log_error("Out of memory.");
+                goto finish;
+        }
 
-        return NULL;
+finish:
+        if (message)
+                dbus_message_unref(message);
 }