dbus: terminate mechanism daemons after a while
diff --git a/TODO b/TODO
index 677e1c9..4dda3f9 100644
--- a/TODO
+++ b/TODO
@@ -7,18 +7,14 @@
 
 * make anaconda write timeout=0 for encrypted devices
 
-* fix broken Sockets=syslog-ng.socket packaging
-
-* logind: ensure ACLs are updated on login and logout
-
-* fix CUPS .path unit for globbing
-
 * service: pid file reading after reload doesn't work, since we don't reset the pid variable
 
 * make sure timeouts are applied to Type=oneshot services.
 
 Features:
 
+* when a bus name of a service disappears from the bus make sure to queue further activation requests
+
 * something like ConditionExec= or ExecStartPre= without failure state
 
 * service restart retry configuration
@@ -106,7 +102,6 @@
 * move readahead files into /var, look for them with .path units
 
 * teach dbus to activate all services it finds in /etc/systemd/services/org-*.service
-* figure out what happened to bluez patch
 
 * support systemd.mask= on the kernel command line.
 
@@ -122,8 +117,6 @@
 
 * maybe introduce ExecRestartPre=
 
-* Patch systemd-fsck to use -C and pass console fd to it
-
 * configurable jitter for timer events
 
 * timer events with system resume
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 43729f0..40754e1 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -971,3 +971,77 @@
 
         return 0;
 }
+
+static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
+        DBusMessage *reply;
+        DBusConnection *bus = userdata;
+
+        assert_se(reply = dbus_pending_call_steal_reply(pending));
+        dbus_message_unref(reply);
+
+        dbus_connection_close(bus);
+}
+
+void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
+        DBusMessage *m = NULL;
+        DBusPendingCall *pending = NULL;
+
+        assert(bus);
+
+        /* We unregister the name here, but we continue to process
+         * requests, until we get the response for it, so that all
+         * requests are guaranteed to be processed. */
+
+        m = dbus_message_new_method_call(
+                        DBUS_SERVICE_DBUS,
+                        DBUS_PATH_DBUS,
+                        DBUS_INTERFACE_DBUS,
+                        "ReleaseName");
+        if (!m)
+                goto oom;
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_STRING,
+                            &name,
+                            DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
+                goto oom;
+
+        if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
+                goto oom;
+
+        dbus_message_unref(m);
+        dbus_pending_call_unref(pending);
+
+        return;
+
+oom:
+        log_error("Out of memory");
+
+        if (pending) {
+                dbus_pending_call_cancel(pending);
+                dbus_pending_call_unref(pending);
+        }
+
+        if (m)
+                dbus_message_unref(m);
+}
+
+DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
+        usec_t *remain_until = userdata;
+
+        assert(bus);
+        assert(m);
+        assert(remain_until);
+
+        /* Everytime we get a new message we reset out timeout */
+        *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
+
+        if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
+                dbus_connection_close(bus);
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
diff --git a/src/dbus-common.h b/src/dbus-common.h
index aab6563..acd9208 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -167,4 +167,8 @@
 
 int generic_print_property(const char *name, DBusMessageIter *iter, bool all);
 
+void bus_async_unregister_and_exit(DBusConnection *bus, const char *name);
+
+DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata);
+
 #endif
diff --git a/src/hostnamed.c b/src/hostnamed.c
index e3b89a4..9e8825d 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -30,6 +30,7 @@
 #include "strv.h"
 #include "dbus-common.h"
 #include "polkit.h"
+#include "def.h"
 
 #define INTERFACE \
         " <interface name=\"org.freedesktop.hostname1\">\n"             \
@@ -85,6 +86,8 @@
         NULL
 };
 
+static usec_t remain_until = 0;
+
 static void free_data(void) {
         int p;
 
@@ -518,7 +521,10 @@
                 goto fail;
         }
 
-        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) {
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL) ||
+            !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) {
                 log_error("Not enough memory");
                 r = -ENOMEM;
                 goto fail;
@@ -554,6 +560,7 @@
 int main(int argc, char *argv[]) {
         int r;
         DBusConnection *bus = NULL;
+        bool exiting = false;
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
@@ -588,8 +595,17 @@
         if (r < 0)
                 goto finish;
 
-        while (dbus_connection_read_write_dispatch(bus, -1))
-                ;
+        remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
+        for (;;) {
+
+                if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
+                        break;
+
+                if (!exiting && remain_until < now(CLOCK_MONOTONIC)) {
+                        exiting = true;
+                        bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1");
+                }
+        }
 
         r = 0;
 
diff --git a/src/localed.c b/src/localed.c
index d7dcc9e..f652110 100644
--- a/src/localed.c
+++ b/src/localed.c
@@ -29,6 +29,7 @@
 #include "strv.h"
 #include "dbus-common.h"
 #include "polkit.h"
+#include "def.h"
 
 #define INTERFACE                                                       \
         " <interface name=\"org.freedesktop.locale1\">\n"               \
@@ -108,6 +109,8 @@
         NULL
 };
 
+static usec_t remain_until = 0;
+
 static void free_data(void) {
         int p;
 
@@ -537,7 +540,10 @@
                 goto fail;
         }
 
-        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL)) {
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL) ||
+            !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) {
                 log_error("Not enough memory");
                 r = -ENOMEM;
                 goto fail;
@@ -573,6 +579,7 @@
 int main(int argc, char *argv[]) {
         int r;
         DBusConnection *bus = NULL;
+        bool exiting = false;
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
@@ -604,8 +611,17 @@
         if (r < 0)
                 goto finish;
 
-        while (dbus_connection_read_write_dispatch(bus, -1))
-                ;
+        remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
+        for (;;) {
+
+                if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
+                        break;
+
+                if (!exiting && remain_until < now(CLOCK_MONOTONIC)) {
+                        exiting = true;
+                        bus_async_unregister_and_exit(bus, "org.freedesktop.locale1");
+                }
+        }
 
         r = 0;
 
diff --git a/src/timedated.c b/src/timedated.c
index 7345388..b2a56e7 100644
--- a/src/timedated.c
+++ b/src/timedated.c
@@ -29,6 +29,7 @@
 #include "strv.h"
 #include "dbus-common.h"
 #include "polkit.h"
+#include "def.h"
 
 #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
 #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
@@ -77,6 +78,8 @@
 static bool local_rtc = false;
 static int use_ntp = -1;
 
+static usec_t remain_until = 0;
+
 static void free_data(void) {
         free(zone);
         zone = NULL;
@@ -788,7 +791,10 @@
                 goto fail;
         }
 
-        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL)) {
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL) ||
+            !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) {
                 log_error("Not enough memory");
                 r = -ENOMEM;
                 goto fail;
@@ -824,6 +830,7 @@
 int main(int argc, char *argv[]) {
         int r;
         DBusConnection *bus = NULL;
+        bool exiting = false;
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
@@ -861,8 +868,17 @@
                 goto finish;
         }
 
-        while (dbus_connection_read_write_dispatch(bus, -1))
-                ;
+        remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
+        for (;;) {
+
+                if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
+                        break;
+
+                if (!exiting && remain_until < now(CLOCK_MONOTONIC)) {
+                        exiting = true;
+                        bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1");
+                }
+        }
 
         r = 0;