1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-05 06:52:22 +03:00

Merge pull request #14424 from poettering/watch-bus-name-rework

pid1: simplify drastically how we watch bus names for service's BusName= setting
This commit is contained in:
Lennart Poettering 2020-01-15 11:46:11 +01:00 committed by GitHub
commit eea45a3399
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 174 deletions

View File

@ -719,114 +719,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
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(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);
/* 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");
/* We have to synchronize the current bus names with the
* list of active services. To do this, walk the list of
* all units with bus names. */
HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
Service *s = SERVICE(u);
assert(s);
if (!streq_ptr(s->bus_name, name)) {
log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
continue;
}
/* Check if a service's bus name is in the list of currently
* active names */
if (strv_contains(names, name)) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *unique;
/* If it is, determine its current owner */
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;
}
r = sd_bus_creds_get_unique_name(creds, &unique);
if (r < 0) {
log_full_errno(r == -ENXIO ? LOG_DEBUG : LOG_ERR, r, "Failed to get unique name for %s: %m", name);
continue;
}
/* Now, let's compare that to the previous bus owner, and
* if it's still the same, all is fine, so just don't
* bother the service. Otherwise, the name has apparently
* changed, so synthesize a name owner changed signal. */
if (!streq_ptr(unique, s->bus_name_owner))
UNIT_VTABLE(u)->bus_name_owner_change(u, s->bus_name_owner, unique);
} else {
/* So, the name we're watching is not on the bus.
* This either means it simply hasn't appeared yet,
* or it was lost during the daemon reload.
* Check if the service has a stored name owner,
* and synthesize a name loss signal in this case. */
if (s->bus_name_owner)
UNIT_VTABLE(u)->bus_name_owner_change(u, s->bus_name_owner, NULL);
}
}
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;
@ -910,10 +802,6 @@ int bus_init_api(Manager *m) {
m->api_bus = TAKE_PTR(bus);
r = manager_enqueue_sync_bus_names(m);
if (r < 0)
return r;
return 0;
}
@ -1051,13 +939,10 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
/* Make sure all bus slots watching names are released. */
HASHMAP_FOREACH(u, m->watch_bus, i) {
if (!u->match_bus_slot)
continue;
if (sd_bus_slot_get_bus(u->match_bus_slot) != *bus)
continue;
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
if (u->match_bus_slot && sd_bus_slot_get_bus(u->match_bus_slot) == *bus)
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
if (u->get_name_owner_slot && sd_bus_slot_get_bus(u->get_name_owner_slot) == *bus)
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
}
/* Get rid of tracked clients on this bus */

View File

@ -21,8 +21,6 @@ int bus_fdset_add_all(Manager *m, FDSet *fds);
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix);
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l);
int manager_enqueue_sync_bus_names(Manager *m);
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error);

View File

@ -1373,7 +1373,6 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->jobs_in_progress_event_source);
sd_event_source_unref(m->run_queue_event_source);
sd_event_source_unref(m->user_lookup_event_source);
sd_event_source_unref(m->sync_bus_names_event_source);
safe_close(m->signal_fd);
safe_close(m->notify_fd);
@ -1610,9 +1609,6 @@ static void manager_ready(Manager *m) {
manager_recheck_journal(m);
manager_recheck_dbus(m);
/* Sync current state of bus names with our set of listening units */
(void) manager_enqueue_sync_bus_names(m);
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);

View File

@ -219,8 +219,6 @@ struct Manager {
int user_lookup_fds[2];
sd_event_source *user_lookup_event_source;
sd_event_source *sync_bus_names_event_source;
UnitFileScope unit_file_scope;
LookupPaths lookup_paths;
Hashmap *unit_id_map;

View File

@ -4062,24 +4062,17 @@ static int service_get_timeout(Unit *u, usec_t *timeout) {
return 1;
}
static void service_bus_name_owner_change(
Unit *u,
const char *old_owner,
const char *new_owner) {
static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
Service *s = SERVICE(u);
int r;
assert(s);
assert(old_owner || new_owner);
if (old_owner && new_owner)
log_unit_debug(u, "D-Bus name %s changed owner from %s to %s", s->bus_name, old_owner, new_owner);
else if (old_owner)
log_unit_debug(u, "D-Bus name %s no longer registered by %s", s->bus_name, old_owner);
if (new_owner)
log_unit_debug(u, "D-Bus name %s now owned by %s", s->bus_name, new_owner);
else
log_unit_debug(u, "D-Bus name %s now registered by %s", s->bus_name, new_owner);
log_unit_debug(u, "D-Bus name %s now not owned by anyone.", s->bus_name);
s->bus_name_good = !!new_owner;

View File

@ -3201,24 +3201,21 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
}
static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name, *old_owner, *new_owner;
const char *new_owner;
Unit *u = userdata;
int r;
assert(message);
assert(u);
r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
r = sd_bus_message_read(message, "sss", NULL, NULL, &new_owner);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
old_owner = empty_to_null(old_owner);
new_owner = empty_to_null(new_owner);
if (UNIT_VTABLE(u)->bus_name_owner_change)
UNIT_VTABLE(u)->bus_name_owner_change(u, old_owner, new_owner);
UNIT_VTABLE(u)->bus_name_owner_change(u, empty_to_null(new_owner));
return 0;
}
@ -3234,42 +3231,35 @@ static int get_name_owner_handler(sd_bus_message *message, void *userdata, sd_bu
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
if (sd_bus_error_is_set(error)) {
log_error("Failed to get name owner from bus: %s", error->message);
return 0;
}
e = sd_bus_message_get_error(message);
if (sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner"))
return 0;
if (e) {
log_error("Unexpected error response from GetNameOwner: %s", e->message);
return 0;
}
if (!sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner"))
log_unit_error(u, "Unexpected error response from GetNameOwner(): %s", e->message);
r = sd_bus_message_read(message, "s", &new_owner);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
new_owner = NULL;
} else {
r = sd_bus_message_read(message, "s", &new_owner);
if (r < 0)
return bus_log_parse_error(r);
new_owner = empty_to_null(new_owner);
assert(!isempty(new_owner));
}
if (UNIT_VTABLE(u)->bus_name_owner_change)
UNIT_VTABLE(u)->bus_name_owner_change(u, NULL, new_owner);
UNIT_VTABLE(u)->bus_name_owner_change(u, new_owner);
return 0;
}
int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
const char *match;
int r;
assert(u);
assert(bus);
assert(name);
if (u->match_bus_slot)
if (u->match_bus_slot || u->get_name_owner_slot)
return -EBUSY;
match = strjoina("type='signal',"
@ -3279,19 +3269,27 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
"member='NameOwnerChanged',"
"arg0='", name, "'");
int r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
if (r < 0)
return r;
return sd_bus_call_method_async(bus,
&u->get_name_owner_slot,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetNameOwner",
get_name_owner_handler,
u,
"s", name);
r = sd_bus_call_method_async(
bus,
&u->get_name_owner_slot,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetNameOwner",
get_name_owner_handler,
u,
"s", name);
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
return r;
}
log_unit_debug(u, "Watching D-Bus name '%s'.", name);
return 0;
}
int unit_watch_bus_name(Unit *u, const char *name) {
@ -3314,6 +3312,7 @@ int unit_watch_bus_name(Unit *u, const char *name) {
r = hashmap_put(u->manager->watch_bus, name, u);
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
return log_warning_errno(r, "Failed to put bus name to hashmap: %m");
}

View File

@ -530,7 +530,7 @@ typedef struct UnitVTable {
void (*notify_message)(Unit *u, const struct ucred *ucred, char **tags, FDSet *fds);
/* Called whenever a name this Unit registered for comes or goes away. */
void (*bus_name_owner_change)(Unit *u, const char *old_owner, const char *new_owner);
void (*bus_name_owner_change)(Unit *u, const char *new_owner);
/* Called for each property that is being set */
int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);