Michal Schmidt e43452
From 6e1da63130bb563b5cce89c2a7d66e98e79c5ec4 Mon Sep 17 00:00:00 2001
Michal Schmidt e43452
From: Michal Schmidt <mschmidt@redhat.com>
Michal Schmidt e43452
Date: Sun, 18 Dec 2011 14:58:10 +0100
Michal Schmidt f1996e
Subject: [PATCH] dbus: register to DBus asynchronously
Michal Schmidt e43452
Michal Schmidt e43452
Chen Jie observed and analyzed a deadlock. Assuming systemd-kmsg-syslogd
Michal Schmidt e43452
is already stopped, but rsyslogd is not started yet:
Michal Schmidt e43452
 1. systemd makes a synchronous call to dbus-daemon.
Michal Schmidt e43452
 2. dbus-daemon wants to write something to syslog.
Michal Schmidt e43452
 3. syslog needs to be started by systemd.
Michal Schmidt e43452
   ... but cannot be, because systemd is waiting in 1.
Michal Schmidt e43452
Michal Schmidt e43452
Solve this by avoiding synchronous D-Bus calls. I had to write an async
Michal Schmidt e43452
bus registration call. Interestingly, D-Bus authors anticipated this, in
Michal Schmidt e43452
documentation to dbus_bus_set_unique_name():
Michal Schmidt e43452
> The only reason to use this function is to re-implement the equivalent
Michal Schmidt e43452
> of dbus_bus_register() yourself. One (probably unusual) reason to do
Michal Schmidt e43452
> that might be to do the bus registration call asynchronously instead
Michal Schmidt e43452
> of synchronously.
Michal Schmidt e43452
Michal Schmidt e43452
Lennart's comments from IRC:
Michal Schmidt e43452
> though I think this doesn't fix the problem in its entirety
Michal Schmidt e43452
> simply because dbus_connection_open_private() itself is still synchronous
Michal Schmidt e43452
> i.e. the connect() call behind it is not async
Michal Schmidt e43452
> I think I listed that issue actually on some D-Bus todo list
Michal Schmidt e43452
> i.e. to make dbus_connection_get() fully async
Michal Schmidt e43452
> but that's going to be hard
Michal Schmidt e43452
> so your patch looks good
Michal Schmidt e43452
Michal Schmidt e43452
So it may not be perfect, but it's clearly an improvement.
Michal Schmidt e43452
I did not manage to reproduce the original deadlock with the patch.
Michal Schmidt e43452
(cherry picked from commit cbd37330bcd039587121a767280fc9fee597af6e)
Michal Schmidt e43452
---
Michal Schmidt e43452
 src/dbus.c    |  378 +++++++++++++++++++++++++++++++++++++++------------------
Michal Schmidt e43452
 src/manager.c |    2 +-
Michal Schmidt e43452
 src/manager.h |    1 +
Michal Schmidt e43452
 3 files changed, 262 insertions(+), 119 deletions(-)
Michal Schmidt e43452
Michal Schmidt e43452
diff --git a/src/dbus.c b/src/dbus.c
Michal Schmidt e43452
index daa2c84..81b4f53 100644
Michal Schmidt e43452
--- a/src/dbus.c
Michal Schmidt e43452
+++ b/src/dbus.c
Michal Schmidt e43452
@@ -48,6 +48,11 @@
Michal Schmidt e43452
 
Michal Schmidt e43452
 #define CONNECTIONS_MAX 52
Michal Schmidt e43452
 
Michal Schmidt e43452
+/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
Michal Schmidt e43452
+#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
Michal Schmidt e43452
+/* Only used as a fallback */
Michal Schmidt e43452
+#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
Michal Schmidt e43452
+
Michal Schmidt e43452
 static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
Michal Schmidt e43452
 static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
Michal Schmidt e43452
 
Michal Schmidt e43452
@@ -767,37 +772,19 @@ static void bus_new_connection(
Michal Schmidt e43452
         dbus_connection_ref(new_connection);
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
-static int bus_init_system(Manager *m) {
Michal Schmidt e43452
-        DBusError error;
Michal Schmidt e43452
-        int r;
Michal Schmidt e43452
-
Michal Schmidt e43452
-        assert(m);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        dbus_error_init(&error);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (m->system_bus)
Michal Schmidt e43452
-                return 0;
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (m->running_as == MANAGER_SYSTEM && m->api_bus)
Michal Schmidt e43452
-                m->system_bus = m->api_bus;
Michal Schmidt e43452
-        else {
Michal Schmidt e43452
-                if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
Michal Schmidt e43452
-                        log_debug("Failed to get system D-Bus connection, retrying later: %s", bus_error_message(&error));
Michal Schmidt e43452
-                        r = 0;
Michal Schmidt e43452
-                        goto fail;
Michal Schmidt e43452
-                }
Michal Schmidt e43452
-
Michal Schmidt e43452
-                if ((r = bus_setup_loop(m, m->system_bus)) < 0)
Michal Schmidt e43452
-                        goto fail;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+static int init_registered_system_bus(Manager *m) {
Michal Schmidt e43452
+        char *id;
Michal Schmidt e43452
 
Michal Schmidt e43452
         if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
Michal Schmidt e43452
                 log_error("Not enough memory");
Michal Schmidt e43452
-                r = -ENOMEM;
Michal Schmidt e43452
-                goto fail;
Michal Schmidt e43452
+                return -ENOMEM;
Michal Schmidt e43452
         }
Michal Schmidt e43452
 
Michal Schmidt e43452
         if (m->running_as != MANAGER_SYSTEM) {
Michal Schmidt e43452
+                DBusError error;
Michal Schmidt e43452
+
Michal Schmidt e43452
+                dbus_error_init(&error);
Michal Schmidt e43452
+
Michal Schmidt e43452
                 dbus_bus_add_match(m->system_bus,
Michal Schmidt e43452
                                    "type='signal',"
Michal Schmidt e43452
                                    "interface='org.freedesktop.systemd1.Agent',"
Michal Schmidt e43452
@@ -807,59 +794,28 @@ static int bus_init_system(Manager *m) {
Michal Schmidt e43452
 
Michal Schmidt e43452
                 if (dbus_error_is_set(&error)) {
Michal Schmidt e43452
                         log_error("Failed to register match: %s", bus_error_message(&error));
Michal Schmidt e43452
-                        r = -EIO;
Michal Schmidt e43452
-                        goto fail;
Michal Schmidt e43452
+                        dbus_error_free(&error);
Michal Schmidt e43452
+                        return -1;
Michal Schmidt e43452
                 }
Michal Schmidt e43452
         }
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if (m->api_bus != m->system_bus) {
Michal Schmidt e43452
-                char *id;
Michal Schmidt e43452
-                log_debug("Successfully connected to system D-Bus bus %s as %s",
Michal Schmidt e43452
-                         strnull((id = dbus_connection_get_server_id(m->system_bus))),
Michal Schmidt e43452
-                         strnull(dbus_bus_get_unique_name(m->system_bus)));
Michal Schmidt e43452
-                dbus_free(id);
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+        log_debug("Successfully connected to system D-Bus bus %s as %s",
Michal Schmidt e43452
+                 strnull((id = dbus_connection_get_server_id(m->system_bus))),
Michal Schmidt e43452
+                 strnull(dbus_bus_get_unique_name(m->system_bus)));
Michal Schmidt e43452
+        dbus_free(id);
Michal Schmidt e43452
 
Michal Schmidt e43452
         return 0;
Michal Schmidt e43452
-
Michal Schmidt e43452
-fail:
Michal Schmidt e43452
-        bus_done_system(m);
Michal Schmidt e43452
-        dbus_error_free(&error);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        return r;
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
-static int bus_init_api(Manager *m) {
Michal Schmidt e43452
-        DBusError error;
Michal Schmidt e43452
+static int init_registered_api_bus(Manager *m) {
Michal Schmidt e43452
         int r;
Michal Schmidt e43452
 
Michal Schmidt e43452
-        assert(m);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        dbus_error_init(&error);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (m->api_bus)
Michal Schmidt e43452
-                return 0;
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (m->running_as == MANAGER_SYSTEM && m->system_bus)
Michal Schmidt e43452
-                m->api_bus = m->system_bus;
Michal Schmidt e43452
-        else {
Michal Schmidt e43452
-                if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_USER ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
Michal Schmidt e43452
-                        log_debug("Failed to get API D-Bus connection, retrying later: %s", bus_error_message(&error));
Michal Schmidt e43452
-                        r = 0;
Michal Schmidt e43452
-                        goto fail;
Michal Schmidt e43452
-                }
Michal Schmidt e43452
-
Michal Schmidt e43452
-                if ((r = bus_setup_loop(m, m->api_bus)) < 0)
Michal Schmidt e43452
-                        goto fail;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
-
Michal Schmidt e43452
         if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
Michal Schmidt e43452
             !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
Michal Schmidt e43452
             !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
Michal Schmidt e43452
             !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) {
Michal Schmidt e43452
                 log_error("Not enough memory");
Michal Schmidt e43452
-                r = -ENOMEM;
Michal Schmidt e43452
-                goto fail;
Michal Schmidt e43452
+                return -ENOMEM;
Michal Schmidt e43452
         }
Michal Schmidt e43452
 
Michal Schmidt e43452
         /* Get NameOwnerChange messages */
Michal Schmidt e43452
@@ -869,13 +825,7 @@ static int bus_init_api(Manager *m) {
Michal Schmidt e43452
                            "interface='"DBUS_INTERFACE_DBUS"',"
Michal Schmidt e43452
                            "member='NameOwnerChanged',"
Michal Schmidt e43452
                            "path='"DBUS_PATH_DBUS"'",
Michal Schmidt e43452
-                           &error);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (dbus_error_is_set(&error)) {
Michal Schmidt e43452
-                log_error("Failed to register match: %s", bus_error_message(&error));
Michal Schmidt e43452
-                r = -EIO;
Michal Schmidt e43452
-                goto fail;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+                           NULL);
Michal Schmidt e43452
 
Michal Schmidt e43452
         /* Get activation requests */
Michal Schmidt e43452
         dbus_bus_add_match(m->api_bus,
Michal Schmidt e43452
@@ -884,33 +834,225 @@ static int bus_init_api(Manager *m) {
Michal Schmidt e43452
                            "interface='org.freedesktop.systemd1.Activator',"
Michal Schmidt e43452
                            "member='ActivationRequest',"
Michal Schmidt e43452
                            "path='"DBUS_PATH_DBUS"'",
Michal Schmidt e43452
-                           &error);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (dbus_error_is_set(&error)) {
Michal Schmidt e43452
-                log_error("Failed to register match: %s", bus_error_message(&error));
Michal Schmidt e43452
-                r = -EIO;
Michal Schmidt e43452
-                goto fail;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+                           NULL);
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if ((r = request_name(m)) < 0)
Michal Schmidt e43452
-                goto fail;
Michal Schmidt e43452
+        r = request_name(m);
Michal Schmidt e43452
+        if (r < 0)
Michal Schmidt e43452
+                return r;
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if ((r = query_name_list(m)) < 0)
Michal Schmidt e43452
-                goto fail;
Michal Schmidt e43452
+        r = query_name_list(m);
Michal Schmidt e43452
+        if (r < 0)
Michal Schmidt e43452
+                return r;
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if (m->api_bus != m->system_bus) {
Michal Schmidt e43452
+        if (m->running_as == MANAGER_USER) {
Michal Schmidt e43452
                 char *id;
Michal Schmidt e43452
                 log_debug("Successfully connected to API D-Bus bus %s as %s",
Michal Schmidt e43452
                          strnull((id = dbus_connection_get_server_id(m->api_bus))),
Michal Schmidt e43452
                          strnull(dbus_bus_get_unique_name(m->api_bus)));
Michal Schmidt e43452
                 dbus_free(id);
Michal Schmidt e43452
+        } else
Michal Schmidt e43452
+                log_debug("Successfully initialized API on the system bus");
Michal Schmidt e43452
+
Michal Schmidt e43452
+        return 0;
Michal Schmidt e43452
+}
Michal Schmidt e43452
+
Michal Schmidt e43452
+static void bus_register_cb(DBusPendingCall *pending, void *userdata) {
Michal Schmidt e43452
+        Manager *m = userdata;
Michal Schmidt e43452
+        DBusConnection **conn;
Michal Schmidt e43452
+        DBusMessage *reply;
Michal Schmidt e43452
+        DBusError error;
Michal Schmidt e43452
+        const char *name;
Michal Schmidt e43452
+        int r = 0;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        dbus_error_init(&error);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        conn = dbus_pending_call_get_data(pending, m->conn_data_slot);
Michal Schmidt e43452
+        assert(conn == &m->system_bus || conn == &m->api_bus);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        reply = dbus_pending_call_steal_reply(pending);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        switch (dbus_message_get_type(reply)) {
Michal Schmidt e43452
+        case DBUS_MESSAGE_TYPE_ERROR:
Michal Schmidt e43452
+                assert_se(dbus_set_error_from_message(&error, reply));
Michal Schmidt e43452
+                log_warning("Failed to register to bus: %s", bus_error_message(&error));
Michal Schmidt e43452
+                r = -1;
Michal Schmidt e43452
+                break;
Michal Schmidt e43452
+        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
Michal Schmidt e43452
+                if (!dbus_message_get_args(reply, &error,
Michal Schmidt e43452
+                                           DBUS_TYPE_STRING, &name,
Michal Schmidt e43452
+                                           DBUS_TYPE_INVALID)) {
Michal Schmidt e43452
+                        log_error("Failed to parse Hello reply: %s", bus_error_message(&error));
Michal Schmidt e43452
+                        r = -1;
Michal Schmidt e43452
+                        break;
Michal Schmidt e43452
+                }
Michal Schmidt e43452
+
Michal Schmidt e43452
+                log_debug("Received name %s in reply to Hello", name);
Michal Schmidt e43452
+                if (!dbus_bus_set_unique_name(*conn, name)) {
Michal Schmidt e43452
+                        log_error("Failed to set unique name");
Michal Schmidt e43452
+                        r = -1;
Michal Schmidt e43452
+                        break;
Michal Schmidt e43452
+                }
Michal Schmidt e43452
+
Michal Schmidt e43452
+                if (conn == &m->system_bus) {
Michal Schmidt e43452
+                        r = init_registered_system_bus(m);
Michal Schmidt e43452
+                        if (r == 0 && m->running_as == MANAGER_SYSTEM)
Michal Schmidt e43452
+                                r = init_registered_api_bus(m);
Michal Schmidt e43452
+                } else
Michal Schmidt e43452
+                        r = init_registered_api_bus(m);
Michal Schmidt e43452
+
Michal Schmidt e43452
+                break;
Michal Schmidt e43452
+        default:
Michal Schmidt e43452
+                assert_not_reached("Invalid reply message");
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+
Michal Schmidt e43452
+        dbus_message_unref(reply);
Michal Schmidt e43452
+        dbus_error_free(&error);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (r < 0) {
Michal Schmidt e43452
+                if (conn == &m->system_bus) {
Michal Schmidt e43452
+                        log_debug("Failed setting up the system bus");
Michal Schmidt e43452
+                        bus_done_system(m);
Michal Schmidt e43452
+                } else {
Michal Schmidt e43452
+                        log_debug("Failed setting up the API bus");
Michal Schmidt e43452
+                        bus_done_api(m);
Michal Schmidt e43452
+                }
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+}
Michal Schmidt e43452
+
Michal Schmidt e43452
+static int manager_bus_async_register(Manager *m, DBusConnection **conn) {
Michal Schmidt e43452
+        DBusMessage *message = NULL;
Michal Schmidt e43452
+        DBusPendingCall *pending = NULL;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
Michal Schmidt e43452
+                                               DBUS_PATH_DBUS,
Michal Schmidt e43452
+                                               DBUS_INTERFACE_DBUS,
Michal Schmidt e43452
+                                               "Hello");
Michal Schmidt e43452
+        if (!message)
Michal Schmidt e43452
+                goto oom;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (!dbus_connection_send_with_reply(*conn, message, &pending, -1))
Michal Schmidt e43452
+                goto oom;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL))
Michal Schmidt e43452
+                goto oom;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL))
Michal Schmidt e43452
+                goto oom;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        dbus_message_unref(message);
Michal Schmidt e43452
+        dbus_pending_call_unref(pending);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        return 0;
Michal Schmidt e43452
+oom:
Michal Schmidt e43452
+        if (pending) {
Michal Schmidt e43452
+                dbus_pending_call_cancel(pending);
Michal Schmidt e43452
+                dbus_pending_call_unref(pending);
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (message)
Michal Schmidt e43452
+                dbus_message_unref(message);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        return -ENOMEM;
Michal Schmidt e43452
+}
Michal Schmidt e43452
+
Michal Schmidt e43452
+static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) {
Michal Schmidt e43452
+        const char *address;
Michal Schmidt e43452
+        DBusConnection *connection;
Michal Schmidt e43452
+        DBusError error;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        switch (type) {
Michal Schmidt e43452
+        case DBUS_BUS_SYSTEM:
Michal Schmidt e43452
+                address = getenv("DBUS_SYSTEM_BUS_ADDRESS");
Michal Schmidt e43452
+                if (!address || !address[0])
Michal Schmidt e43452
+                        address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
Michal Schmidt e43452
+                break;
Michal Schmidt e43452
+        case DBUS_BUS_SESSION:
Michal Schmidt e43452
+                address = getenv("DBUS_SESSION_BUS_ADDRESS");
Michal Schmidt e43452
+                if (!address || !address[0])
Michal Schmidt e43452
+                        address = DBUS_SESSION_BUS_DEFAULT_ADDRESS;
Michal Schmidt e43452
+                break;
Michal Schmidt e43452
+        default:
Michal Schmidt e43452
+                assert_not_reached("Invalid bus type");
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+
Michal Schmidt e43452
+        dbus_error_init(&error);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        connection = dbus_connection_open_private(address, &error);
Michal Schmidt e43452
+        if (!connection) {
Michal Schmidt e43452
+                log_warning("Failed to open private bus connection: %s", bus_error_message(&error));
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+
Michal Schmidt e43452
+        return connection;
Michal Schmidt e43452
+fail:
Michal Schmidt e43452
+        if (connection)
Michal Schmidt e43452
+                dbus_connection_close(connection);
Michal Schmidt e43452
+        dbus_error_free(&error);
Michal Schmidt e43452
+        return NULL;
Michal Schmidt e43452
+}
Michal Schmidt e43452
+
Michal Schmidt e43452
+static int bus_init_system(Manager *m) {
Michal Schmidt e43452
+        int r;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (m->system_bus)
Michal Schmidt e43452
+                return 0;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM);
Michal Schmidt e43452
+        if (!m->system_bus) {
Michal Schmidt e43452
+                log_debug("Failed to connect to system D-Bus, retrying later");
Michal Schmidt e43452
+                r = 0;
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
         }
Michal Schmidt e43452
 
Michal Schmidt e43452
+        r = bus_setup_loop(m, m->system_bus);
Michal Schmidt e43452
+        if (r < 0)
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        r = manager_bus_async_register(m, &m->system_bus);
Michal Schmidt e43452
+        if (r < 0)
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
+
Michal Schmidt e43452
         return 0;
Michal Schmidt e43452
+fail:
Michal Schmidt e43452
+        bus_done_system(m);
Michal Schmidt e43452
+
Michal Schmidt e43452
+        return r;
Michal Schmidt e43452
+}
Michal Schmidt e43452
+
Michal Schmidt e43452
+static int bus_init_api(Manager *m) {
Michal Schmidt e43452
+        int r;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (m->api_bus)
Michal Schmidt e43452
+                return 0;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (m->running_as == MANAGER_SYSTEM) {
Michal Schmidt e43452
+                m->api_bus = m->system_bus;
Michal Schmidt e43452
+                /* In this mode there is no distinct connection to the API bus,
Michal Schmidt e43452
+                 * the API is published on the system bus.
Michal Schmidt e43452
+                 * bus_register_cb() is aware of that and will init the API
Michal Schmidt e43452
+                 * when the system bus gets registered.
Michal Schmidt e43452
+                 * No need to setup anything here. */
Michal Schmidt e43452
+                return 0;
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+
Michal Schmidt e43452
+        m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION);
Michal Schmidt e43452
+        if (!m->api_bus) {
Michal Schmidt e43452
+                log_debug("Failed to connect to API D-Bus, retrying later");
Michal Schmidt e43452
+                r = 0;
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
+        }
Michal Schmidt e43452
+
Michal Schmidt e43452
+        r = bus_setup_loop(m, m->api_bus);
Michal Schmidt e43452
+        if (r < 0)
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
 
Michal Schmidt e43452
+        r = manager_bus_async_register(m, &m->api_bus);
Michal Schmidt e43452
+        if (r < 0)
Michal Schmidt e43452
+                goto fail;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        return 0;
Michal Schmidt e43452
 fail:
Michal Schmidt e43452
         bus_done_api(m);
Michal Schmidt e43452
-        dbus_error_free(&error);
Michal Schmidt e43452
 
Michal Schmidt e43452
         return r;
Michal Schmidt e43452
 }
Michal Schmidt e43452
@@ -989,22 +1131,20 @@ int bus_init(Manager *m, bool try_bus_connect) {
Michal Schmidt e43452
         int r;
Michal Schmidt e43452
 
Michal Schmidt e43452
         if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
Michal Schmidt e43452
-            set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0) {
Michal Schmidt e43452
-                log_error("Not enough memory");
Michal Schmidt e43452
-                return -ENOMEM;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+            set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
Michal Schmidt e43452
+                goto oom;
Michal Schmidt e43452
 
Michal Schmidt e43452
         if (m->name_data_slot < 0)
Michal Schmidt e43452
-                if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot)) {
Michal Schmidt e43452
-                        log_error("Not enough memory");
Michal Schmidt e43452
-                        return -ENOMEM;
Michal Schmidt e43452
-                }
Michal Schmidt e43452
+                if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
Michal Schmidt e43452
+                        goto oom;
Michal Schmidt e43452
+
Michal Schmidt e43452
+        if (m->conn_data_slot < 0)
Michal Schmidt e43452
+                if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot))
Michal Schmidt e43452
+                        goto oom;
Michal Schmidt e43452
 
Michal Schmidt e43452
         if (m->subscribed_data_slot < 0)
Michal Schmidt e43452
-                if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot)) {
Michal Schmidt e43452
-                        log_error("Not enough memory");
Michal Schmidt e43452
-                        return -ENOMEM;
Michal Schmidt e43452
-                }
Michal Schmidt e43452
+                if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot))
Michal Schmidt e43452
+                        goto oom;
Michal Schmidt e43452
 
Michal Schmidt e43452
         if (try_bus_connect) {
Michal Schmidt e43452
                 if ((r = bus_init_system(m)) < 0 ||
Michal Schmidt e43452
@@ -1016,6 +1156,9 @@ int bus_init(Manager *m, bool try_bus_connect) {
Michal Schmidt e43452
                 return r;
Michal Schmidt e43452
 
Michal Schmidt e43452
         return 0;
Michal Schmidt e43452
+oom:
Michal Schmidt e43452
+        log_error("Not enough memory");
Michal Schmidt e43452
+        return -ENOMEM;
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
 static void shutdown_connection(Manager *m, DBusConnection *c) {
Michal Schmidt e43452
@@ -1059,42 +1202,38 @@ static void shutdown_connection(Manager *m, DBusConnection *c) {
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
 static void bus_done_api(Manager *m) {
Michal Schmidt e43452
-        assert(m);
Michal Schmidt e43452
-
Michal Schmidt e43452
-        if (m->api_bus) {
Michal Schmidt e43452
-                if (m->system_bus == m->api_bus)
Michal Schmidt e43452
-                        m->system_bus = NULL;
Michal Schmidt e43452
+        if (!m->api_bus)
Michal Schmidt e43452
+                return;
Michal Schmidt e43452
 
Michal Schmidt e43452
+        if (m->running_as == MANAGER_USER)
Michal Schmidt e43452
                 shutdown_connection(m, m->api_bus);
Michal Schmidt e43452
-                m->api_bus = NULL;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
 
Michal Schmidt e43452
+        m->api_bus = NULL;
Michal Schmidt e43452
 
Michal Schmidt e43452
-       if (m->queued_message) {
Michal Schmidt e43452
-               dbus_message_unref(m->queued_message);
Michal Schmidt e43452
-               m->queued_message = NULL;
Michal Schmidt e43452
-       }
Michal Schmidt e43452
+        if (m->queued_message) {
Michal Schmidt e43452
+                dbus_message_unref(m->queued_message);
Michal Schmidt e43452
+                m->queued_message = NULL;
Michal Schmidt e43452
+        }
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
 static void bus_done_system(Manager *m) {
Michal Schmidt e43452
-        assert(m);
Michal Schmidt e43452
+        if (!m->system_bus)
Michal Schmidt e43452
+                return;
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if (m->system_bus == m->api_bus)
Michal Schmidt e43452
+        if (m->running_as == MANAGER_SYSTEM)
Michal Schmidt e43452
                 bus_done_api(m);
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if (m->system_bus) {
Michal Schmidt e43452
-                shutdown_connection(m, m->system_bus);
Michal Schmidt e43452
-                m->system_bus = NULL;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+        shutdown_connection(m, m->system_bus);
Michal Schmidt e43452
+        m->system_bus = NULL;
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
 static void bus_done_private(Manager *m) {
Michal Schmidt e43452
+        if (!m->private_bus)
Michal Schmidt e43452
+                return;
Michal Schmidt e43452
 
Michal Schmidt e43452
-        if (m->private_bus) {
Michal Schmidt e43452
-                dbus_server_disconnect(m->private_bus);
Michal Schmidt e43452
-                dbus_server_unref(m->private_bus);
Michal Schmidt e43452
-                m->private_bus = NULL;
Michal Schmidt e43452
-        }
Michal Schmidt e43452
+        dbus_server_disconnect(m->private_bus);
Michal Schmidt e43452
+        dbus_server_unref(m->private_bus);
Michal Schmidt e43452
+        m->private_bus = NULL;
Michal Schmidt e43452
 }
Michal Schmidt e43452
 
Michal Schmidt e43452
 void bus_done(Manager *m) {
Michal Schmidt e43452
@@ -1116,6 +1255,9 @@ void bus_done(Manager *m) {
Michal Schmidt e43452
         if (m->name_data_slot >= 0)
Michal Schmidt e43452
                dbus_pending_call_free_data_slot(&m->name_data_slot);
Michal Schmidt e43452
 
Michal Schmidt e43452
+        if (m->conn_data_slot >= 0)
Michal Schmidt e43452
+               dbus_pending_call_free_data_slot(&m->conn_data_slot);
Michal Schmidt e43452
+
Michal Schmidt e43452
         if (m->subscribed_data_slot >= 0)
Michal Schmidt e43452
                 dbus_connection_free_data_slot(&m->subscribed_data_slot);
Michal Schmidt e43452
 }
Michal Schmidt e43452
diff --git a/src/manager.c b/src/manager.c
Michal Schmidt e43452
index 111167a..6acc821 100644
Michal Schmidt e43452
--- a/src/manager.c
Michal Schmidt e43452
+++ b/src/manager.c
Michal Schmidt e43452
@@ -231,7 +231,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
Michal Schmidt e43452
         dual_timestamp_get(&m->startup_timestamp);
Michal Schmidt e43452
 
Michal Schmidt e43452
         m->running_as = running_as;
Michal Schmidt e43452
-        m->name_data_slot = m->subscribed_data_slot = -1;
Michal Schmidt e43452
+        m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
Michal Schmidt e43452
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
Michal Schmidt e43452
         m->pin_cgroupfs_fd = -1;
Michal Schmidt e43452
 
Michal Schmidt e43452
diff --git a/src/manager.h b/src/manager.h
Michal Schmidt e43452
index 5deb569..6e7558e 100644
Michal Schmidt e43452
--- a/src/manager.h
Michal Schmidt e43452
+++ b/src/manager.h
Michal Schmidt e43452
@@ -179,6 +179,7 @@ struct Manager {
Michal Schmidt e43452
 
Michal Schmidt e43452
         Hashmap *watch_bus;  /* D-Bus names => Unit object n:1 */
Michal Schmidt e43452
         int32_t name_data_slot;
Michal Schmidt e43452
+        int32_t conn_data_slot;
Michal Schmidt e43452
         int32_t subscribed_data_slot;
Michal Schmidt e43452
 
Michal Schmidt e43452
         uint32_t current_job_id;