diff options
Diffstat (limited to 'src/core/dbus.c')
-rw-r--r-- | src/core/dbus.c | 194 |
1 files changed, 137 insertions, 57 deletions
diff --git a/src/core/dbus.c b/src/core/dbus.c index 1c3fca353a..56b43adcda 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -139,9 +139,10 @@ static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_e assert_se(bus = sd_bus_message_get_bus(message)); if (bus == m->api_bus) - destroy_bus(m, &m->api_bus); + bus_done_api(m); if (bus == m->system_bus) - destroy_bus(m, &m->system_bus); + bus_done_system(m); + if (set_remove(m->private_buses, bus)) { log_debug("Got disconnect on private connection."); destroy_bus(m, &bus); @@ -652,6 +653,8 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } + (void) sd_bus_set_description(bus, "private-bus-connection"); + r = sd_bus_set_fd(bus, nfd, nfd); if (r < 0) { log_warning_errno(r, "Failed to set fd on new connection bus: %m"); @@ -724,17 +727,29 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } -int manager_sync_bus_names(Manager *m, sd_bus *bus) { +static int manager_dispatch_sync_bus_names(sd_event_source *es, void *userdata) { _cleanup_strv_free_ char **names = NULL; + Manager *m = userdata; const char *name; Iterator i; Unit *u; int r; + assert(es); assert(m); - assert(bus); + assert(m->sync_bus_names_event_source == es); + + /* First things first, destroy the defer event so that we aren't triggered again */ + m->sync_bus_names_event_source = sd_event_source_unref(m->sync_bus_names_event_source); - r = sd_bus_list_names(bus, &names, NULL); + /* Let's see if there's anything to do still? */ + if (!m->api_bus) + return 0; + if (hashmap_isempty(m->watch_bus)) + return 0; + + /* OK, let's sync up the names. Let's see which names are currently on the bus. */ + r = sd_bus_list_names(m->api_bus, &names, NULL); if (r < 0) return log_error_errno(r, "Failed to get initial list of names: %m"); @@ -758,7 +773,7 @@ int manager_sync_bus_names(Manager *m, sd_bus *bus) { const char *unique; /* If it is, determine its current owner */ - r = sd_bus_get_name_creds(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds); + r = sd_bus_get_name_creds(m->api_bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds); if (r < 0) { log_full_errno(r == -ENXIO ? LOG_DEBUG : LOG_ERR, r, "Failed to get bus name owner %s: %m", name); continue; @@ -792,6 +807,34 @@ int manager_sync_bus_names(Manager *m, sd_bus *bus) { return 0; } +int manager_enqueue_sync_bus_names(Manager *m) { + int r; + + assert(m); + + /* Enqueues a request to synchronize the bus names in a later event loop iteration. The callers generally don't + * want us to invoke ->bus_name_owner_change() unit calls from their stack frames as this might result in event + * dispatching on its own creating loops, hence we simply create a defer event for the event loop and exit. */ + + if (m->sync_bus_names_event_source) + return 0; + + r = sd_event_add_defer(m->event, &m->sync_bus_names_event_source, manager_dispatch_sync_bus_names, m); + if (r < 0) + return log_error_errno(r, "Failed to create bus name synchronization event: %m"); + + r = sd_event_source_set_priority(m->sync_bus_names_event_source, SD_EVENT_PRIORITY_IDLE); + if (r < 0) + return log_error_errno(r, "Failed to set event priority: %m"); + + r = sd_event_source_set_enabled(m->sync_bus_names_event_source, SD_EVENT_ONESHOT); + if (r < 0) + return log_error_errno(r, "Failed to set even to oneshot: %m"); + + (void) sd_event_source_set_description(m->sync_bus_names_event_source, "manager-sync-bus-names"); + return 0; +} + static int bus_setup_api(Manager *m, sd_bus *bus) { Iterator i; char *name; @@ -837,15 +880,12 @@ static int bus_setup_api(Manager *m, sd_bus *bus) { if (r < 0) return log_error_errno(r, "Failed to request name: %m"); - r = manager_sync_bus_names(m, bus); - if (r < 0) - return r; - log_debug("Successfully connected to API bus."); + return 0; } -static int bus_init_api(Manager *m) { +int bus_init_api(Manager *m) { _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int r; @@ -879,6 +919,10 @@ static int bus_init_api(Manager *m) { m->api_bus = bus; bus = NULL; + r = manager_enqueue_sync_bus_names(m); + if (r < 0) + return r; + return 0; } @@ -906,7 +950,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) { return 0; } -static int bus_init_system(Manager *m) { +int bus_init_system(Manager *m) { _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int r; @@ -914,22 +958,21 @@ static int bus_init_system(Manager *m) { return 0; /* The API and system bus is the same if we are running in system mode */ - if (MANAGER_IS_SYSTEM(m) && m->api_bus) { - m->system_bus = sd_bus_ref(m->api_bus); - return 0; - } - - r = sd_bus_open_system(&bus); - if (r < 0) - return log_error_errno(r, "Failed to connect to system bus: %m"); + if (MANAGER_IS_SYSTEM(m) && m->api_bus) + bus = sd_bus_ref(m->api_bus); + else { + r = sd_bus_open_system(&bus); + if (r < 0) + return log_error_errno(r, "Failed to connect to system bus: %m"); - r = bus_setup_disconnected_match(m, bus); - if (r < 0) - return r; + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) + return log_error_errno(r, "Failed to attach system bus to event loop: %m"); - r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); - if (r < 0) - return log_error_errno(r, "Failed to attach system bus to event loop: %m"); + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return r; + } r = bus_setup_system(m, bus); if (r < 0) @@ -941,7 +984,7 @@ static int bus_init_system(Manager *m) { return 0; } -static int bus_init_private(Manager *m) { +int bus_init_private(Manager *m) { _cleanup_close_ int fd = -1; union sockaddr_union sa = { .un.sun_family = AF_UNIX @@ -1013,26 +1056,6 @@ static int bus_init_private(Manager *m) { return 0; } -int bus_init(Manager *m, bool try_bus_connect) { - int r; - - if (try_bus_connect) { - r = bus_init_system(m); - if (r < 0) - return log_error_errno(r, "Failed to initialize D-Bus connection: %m"); - - r = bus_init_api(m); - if (r < 0) - return log_error_errno(r, "Error occured during D-Bus APIs initialization: %m"); - } - - r = bus_init_private(m); - if (r < 0) - return log_error_errno(r, "Failed to create private D-Bus server: %m"); - - return 0; -} - static void destroy_bus(Manager *m, sd_bus **bus) { Iterator i; Unit *u; @@ -1063,6 +1086,10 @@ static void destroy_bus(Manager *m, sd_bus **bus) { if (j->bus_track && sd_bus_track_get_bus(j->bus_track) == *bus) j->bus_track = sd_bus_track_unref(j->bus_track); + HASHMAP_FOREACH(u, m->units, i) + if (u->bus_track && sd_bus_track_get_bus(u->bus_track) == *bus) + u->bus_track = sd_bus_track_unref(u->bus_track); + /* Get rid of queued message on this bus */ if (m->queued_message && sd_bus_message_get_bus(m->queued_message) == *bus) m->queued_message = sd_bus_message_unref(m->queued_message); @@ -1077,28 +1104,44 @@ static void destroy_bus(Manager *m, sd_bus **bus) { *bus = sd_bus_unref(*bus); } -void bus_done(Manager *m) { - sd_bus *b; - +void bus_done_api(Manager *m) { assert(m); if (m->api_bus) destroy_bus(m, &m->api_bus); +} + +void bus_done_system(Manager *m) { + assert(m); + if (m->system_bus) destroy_bus(m, &m->system_bus); +} + +void bus_done_private(Manager *m) { + sd_bus *b; + + assert(m); + while ((b = set_steal_first(m->private_buses))) destroy_bus(m, &b); m->private_buses = set_free(m->private_buses); - m->subscribed = sd_bus_track_unref(m->subscribed); - m->deserialized_subscribed = strv_free(m->deserialized_subscribed); + m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source); + m->private_listen_fd = safe_close(m->private_listen_fd); +} - if (m->private_listen_event_source) - m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source); +void bus_done(Manager *m) { + assert(m); - m->private_listen_fd = safe_close(m->private_listen_fd); + bus_done_api(m); + bus_done_system(m); + bus_done_private(m); + assert(!m->subscribed); + + m->deserialized_subscribed = strv_free(m->deserialized_subscribed); bus_verify_polkit_async_registry_free(m->polkit_registry); } @@ -1154,14 +1197,20 @@ int bus_foreach_bus( /* Send to all direct buses, unconditionally */ SET_FOREACH(b, m->private_buses, i) { + + /* Don't bother with enqueing these messages to clients that haven't started yet */ + if (sd_bus_is_ready(b) <= 0) + continue; + r = send_message(b, userdata); if (r < 0) ret = r; } /* Send to API bus, but only if somebody is subscribed */ - if (sd_bus_track_count(m->subscribed) > 0 || - sd_bus_track_count(subscribed2) > 0) { + if (m->api_bus && + (sd_bus_track_count(m->subscribed) > 0 || + sd_bus_track_count(subscribed2) > 0)) { r = send_message(m->api_bus, userdata); if (r < 0) ret = r; @@ -1230,3 +1279,34 @@ int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_erro int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error); } + +uint64_t manager_bus_n_queued_write(Manager *m) { + uint64_t c = 0; + Iterator i; + sd_bus *b; + int r; + + /* Returns the total number of messages queued for writing on all our direct and API busses. */ + + SET_FOREACH(b, m->private_buses, i) { + uint64_t k; + + r = sd_bus_get_n_queued_write(b, &k); + if (r < 0) + log_debug_errno(r, "Failed to query queued messages for private bus: %m"); + else + c += k; + } + + if (m->api_bus) { + uint64_t k; + + r = sd_bus_get_n_queued_write(m->api_bus, &k); + if (r < 0) + log_debug_errno(r, "Failed to query queued messages for API bus: %m"); + else + c += k; + } + + return c; +} |