From d7afd945b5aad5b262a3de97614f486d63d94612 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Dec 2017 15:54:30 +0100 Subject: [PATCH] networkd,resolved: make use of watch_bind feature to connect to the bus The changes both networkd and resolved to make use of the watch_bind feature of sd-bus to connect to the system bus. This way, both daemons can be started during early boot, and automatically and instantly connect to the system bus as it becomes available. This replaces prior code that used a time-based retry logic to connect to the bus. --- src/network/networkd-manager.c | 93 ++++++++++++++++++++---------------------- src/network/networkd-manager.h | 1 + src/resolve/resolved-bus.c | 31 ++------------ src/shared/bus-util.c | 51 +++++++++++++++++++++++ src/shared/bus-util.h | 2 + src/systemd/sd-bus.h | 2 + 6 files changed, 105 insertions(+), 75 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 79d58dd..4733dd5 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -82,19 +82,6 @@ static int setup_default_address_pool(Manager *m) { return 0; } -static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) { - Manager *m = userdata; - - assert(s); - assert(m); - - m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source); - - manager_connect_bus(m); - - return 0; -} - static int manager_reset_all(Manager *m) { Link *link; Iterator i; @@ -116,6 +103,7 @@ static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_b int b, r; assert(message); + assert(m); r = sd_bus_message_read(message, "b", &b); if (r < 0) { @@ -133,34 +121,32 @@ static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_b return 0; } -int manager_connect_bus(Manager *m) { - int r; +static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { + Manager *m = userdata; + assert(message); assert(m); - r = sd_bus_default_system(&m->bus); - if (r < 0) { - /* We failed to connect? Yuck, we must be in early - * boot. Let's try in 5s again. */ + /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ + if (m->dynamic_hostname) + (void) manager_set_hostname(m, m->dynamic_hostname); + if (m->dynamic_timezone) + (void) manager_set_timezone(m, m->dynamic_timezone); - log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m"); + return 0; +} - r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m); - if (r < 0) - return log_error_errno(r, "Failed to install bus reconnect time event: %m"); +int manager_connect_bus(Manager *m) { + int r; + + assert(m); + if (m->bus) return 0; - } - r = sd_bus_match_signal_async( - m->bus, &m->prepare_for_sleep_slot, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "PrepareForSleep", - match_prepare_for_sleep, NULL, m); + r = bus_open_system_watch_bind(&m->bus); if (r < 0) - return log_error_errno(r, "Failed to request match for PrepareForSleep: %m"); + return log_error_errno(r, "Failed to connect to bus: %m"); r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m); if (r < 0) @@ -190,17 +176,27 @@ int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); - /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ - if (m->dynamic_hostname) { - r = manager_set_hostname(m, m->dynamic_hostname); - if (r < 0) - return r; - } - if (m->dynamic_timezone) { - r = manager_set_timezone(m, m->dynamic_timezone); - if (r < 0) - return r; - } + r = sd_bus_match_signal_async( + m->bus, + &m->connected_slot, + "org.freedesktop.DBus.Local", + NULL, + "org.freedesktop.DBus.Local", + "Connected", + on_connected, NULL, m); + if (r < 0) + return log_error_errno(r, "Failed to request match on Connected signal: %m"); + + r = sd_bus_match_signal_async( + m->bus, + &m->prepare_for_sleep_slot, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "PrepareForSleep", + match_prepare_for_sleep, NULL, m); + if (r < 0) + log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m"); return 0; } @@ -1320,6 +1316,7 @@ void manager_free(Manager *m) { sd_bus_unref(m->bus); sd_bus_slot_unref(m->prepare_for_sleep_slot); + sd_bus_slot_unref(m->connected_slot); sd_event_source_unref(m->bus_retry_event_source); free(m->dynamic_timezone); @@ -1594,12 +1591,12 @@ int manager_set_hostname(Manager *m, const char *hostname) { int r; log_debug("Setting transient hostname: '%s'", strna(hostname)); + if (free_and_strdup(&m->dynamic_hostname, hostname) < 0) return log_oom(); - if (!m->bus) { - /* TODO: replace by assert when we can rely on kdbus */ - log_info("Not connected to system bus, ignoring transient hostname."); + if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { + log_info("Not connected to system bus, not setting hostname."); return 0; } @@ -1646,8 +1643,8 @@ int manager_set_timezone(Manager *m, const char *tz) { if (free_and_strdup(&m->dynamic_timezone, tz) < 0) return log_oom(); - if (!m->bus) { - log_info("Not connected to system bus, ignoring timezone."); + if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { + log_info("Not connected to system bus, not setting hostname."); return 0; } diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 186cb41..1f7f306 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -43,6 +43,7 @@ struct Manager { sd_event_source *bus_retry_event_source; sd_bus *bus; sd_bus_slot *prepare_for_sleep_slot; + sd_bus_slot *connected_slot; struct udev *udev; struct udev_monitor *udev_monitor; sd_event_source *udev_event_source; diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index ff629ea..ffd7c48 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1844,18 +1844,6 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_END, }; -static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) { - Manager *m = userdata; - - assert(s); - assert(m); - - m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source); - - manager_connect_bus(m); - return 0; -} - static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { Manager *m = userdata; int b, r; @@ -1886,20 +1874,9 @@ int manager_connect_bus(Manager *m) { if (m->bus) return 0; - r = sd_bus_default_system(&m->bus); - if (r < 0) { - /* We failed to connect? Yuck, we must be in early - * boot. Let's try in 5s again. */ - - log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m"); - - r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m); - if (r < 0) - return log_error_errno(r, "Failed to install bus reconnect time event: %m"); - - (void) sd_event_source_set_description(m->bus_retry_event_source, "bus-retry"); - return 0; - } + r = bus_open_system_watch_bind(&m->bus); + if (r < 0) + return log_error_errno(r, "Failed to connect to system bus: %m"); r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m); if (r < 0) @@ -1940,7 +1917,7 @@ int manager_connect_bus(Manager *m) { NULL, m); if (r < 0) - log_error_errno(r, "Failed to request match for PrepareForSleep: %m"); + log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m"); return 0; } diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index b9e25a0..b6677e2 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1598,3 +1598,54 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) { return r; } + +int bus_open_system_watch_bind(sd_bus **ret) { + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + const char *e; + int r; + + assert(ret); + + /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */ + + r = sd_bus_new(&bus); + if (r < 0) + return r; + + e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS"); + if (!e) + e = DEFAULT_SYSTEM_BUS_ADDRESS; + + r = sd_bus_set_address(bus, e); + if (r < 0) + return r; + + r = sd_bus_set_bus_client(bus, true); + if (r < 0) + return r; + + r = sd_bus_set_trusted(bus, true); + if (r < 0) + return r; + + r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS); + if (r < 0) + return r; + + r = sd_bus_set_watch_bind(bus, true); + if (r < 0) + return r; + + r = sd_bus_set_connected_signal(bus, true); + if (r < 0) + return r; + + r = sd_bus_start(bus); + if (r < 0) + return r; + + *ret = bus; + bus = NULL; + + return 0; +} diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index a9f4969..cbd22a6 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -162,3 +162,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int bus_track_add_name_many(sd_bus_track *t, char **l); + +int bus_open_system_watch_bind(sd_bus **ret); diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 76bd5ef..df21b3f 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -152,6 +152,8 @@ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b); int sd_bus_get_exit_on_disconnect(sd_bus *bus); int sd_bus_set_watch_bind(sd_bus *bus, int b); int sd_bus_get_watch_bind(sd_bus *bus); +int sd_bus_set_connected_signal(sd_bus *bus, int b); +int sd_bus_get_connected_signal(sd_bus *bus); int sd_bus_start(sd_bus *bus); -- 2.7.4