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.
This commit is contained in:
Lennart Poettering 2017-12-19 15:54:30 +01:00
parent b38cc8d563
commit d7afd945b5
6 changed files with 106 additions and 76 deletions

View file

@ -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;
}
static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
assert(message);
assert(m);
/* 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);
return 0;
}
int manager_connect_bus(Manager *m) {
int r;
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. */
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");
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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);