summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-08-06 11:25:31 +0300
committerLennart Poettering <lennart@poettering.net>2015-08-06 11:25:31 +0300
commita6b095186891e9c0fa61a191126977c5eea6f111 (patch)
treed667bb2afaaef914cbc262e3b6e4220325722bbf
parentd5972272d2b725ab6a2789899f8b6c1d2a8113e3 (diff)
parentbbc2908635ca3ded9162504683fa126809f0ec14 (diff)
Merge pull request #894 from zonque/name-owner-changed-v2
core: dbus: track bus names per unit (v2)
-rw-r--r--src/core/dbus.c50
-rw-r--r--src/core/manager.c18
-rw-r--r--src/core/manager.h2
-rw-r--r--src/core/unit.c65
-rw-r--r--src/core/unit.h4
5 files changed, 83 insertions, 56 deletions
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 057653a8b5..44bf5cab28 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -140,28 +140,6 @@ static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_e
return 0;
}
-static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *old_owner, *new_owner;
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- manager_dispatch_bus_name_owner_changed(
- m, name,
- isempty(old_owner) ? NULL : old_owner,
- isempty(new_owner) ? NULL : new_owner);
-
- return 0;
-}
-
static int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
@@ -762,13 +740,21 @@ static int bus_list_names(Manager *m, sd_bus *bus) {
/* This is a bit hacky, we say the owner of the name is the
* name itself, because we don't want the extra traffic to
* figure out the real owner. */
- STRV_FOREACH(i, names)
- manager_dispatch_bus_name_owner_changed(m, *i, NULL, *i);
+ STRV_FOREACH(i, names) {
+ Unit *u;
+
+ u = hashmap_get(m->watch_bus, *i);
+ if (u)
+ UNIT_VTABLE(u)->bus_name_owner_change(u, *i, NULL, *i);
+ }
return 0;
}
static int bus_setup_api(Manager *m, sd_bus *bus) {
+ Iterator i;
+ char *name;
+ Unit *u;
int r;
assert(m);
@@ -786,17 +772,11 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
if (r < 0)
return r;
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged'",
- signal_name_owner_changed, m);
- if (r < 0)
- log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
+ r = unit_install_bus_match(bus, u, name);
+ if (r < 0)
+ log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ }
r = sd_bus_add_match(
bus,
diff --git a/src/core/manager.c b/src/core/manager.c
index ba107d4615..ecea89c377 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2187,24 +2187,6 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
log_error_errno(errno, "Failed to write Plymouth message: %m");
}
-void manager_dispatch_bus_name_owner_changed(
- Manager *m,
- const char *name,
- const char* old_owner,
- const char *new_owner) {
-
- Unit *u;
-
- assert(m);
- assert(name);
-
- u = hashmap_get(m->watch_bus, name);
- if (!u)
- return;
-
- UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
-}
-
int manager_open_serialization(Manager *m, FILE **_f) {
const char *path;
int fd = -1;
diff --git a/src/core/manager.h b/src/core/manager.h
index 4ef869d14a..1e01f2bdef 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -329,8 +329,6 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
int manager_loop(Manager *m);
-void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
-
int manager_open_serialization(Manager *m, FILE **_f);
int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root);
diff --git a/src/core/unit.c b/src/core/unit.c
index dd5e801285..6cc5824eb2 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -48,6 +48,7 @@
#include "dropin.h"
#include "formats-util.h"
#include "process-util.h"
+#include "bus-util.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
@@ -477,6 +478,7 @@ void unit_free(Unit *u) {
if (u->manager->n_reloading <= 0)
unit_remove_transient(u);
+ sd_bus_slot_unref(u->match_bus_slot);
bus_unit_send_removed_signal(u);
unit_done(u);
@@ -2500,14 +2502,74 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
return r;
}
+static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *name, *old_owner, *new_owner;
+ Unit *u = userdata;
+ int r;
+
+ assert(message);
+ assert(u);
+
+ r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ if (UNIT_VTABLE(u)->bus_name_owner_change)
+ UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
+
+ return 0;
+}
+
+int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) {
+ _cleanup_free_ char *match = NULL;
+ Manager *m = u->manager;
+
+ assert(m);
+
+ if (u->match_bus_slot)
+ return -EBUSY;
+
+ match = strjoin("type='signal',"
+ "sender='org.freedesktop.DBus',"
+ "path='/org/freedesktop/DBus',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "arg0='",
+ name,
+ "'",
+ NULL);
+ if (!match)
+ return -ENOMEM;
+
+ return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
+}
+
int unit_watch_bus_name(Unit *u, const char *name) {
+ int r;
+
assert(u);
assert(name);
/* Watch a specific name on the bus. We only support one unit
* watching each name for now. */
- return hashmap_put(u->manager->watch_bus, name, u);
+ if (u->manager->api_bus) {
+ /* If the bus is already available, install the match directly.
+ * Otherwise, just put the name in the list. bus_setup_api() will take care later. */
+ r = unit_install_bus_match(u->manager->api_bus, u, name);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ }
+
+ r = hashmap_put(u->manager->watch_bus, name, u);
+ if (r < 0) {
+ u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
+ return log_warning_errno(r, "Failed to put bus name to hashmap: %m");
+ }
+
+ return 0;
}
void unit_unwatch_bus_name(Unit *u, const char *name) {
@@ -2515,6 +2577,7 @@ void unit_unwatch_bus_name(Unit *u, const char *name) {
assert(name);
hashmap_remove_value(u->manager->watch_bus, name, u);
+ u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
}
bool unit_can_serialize(Unit *u) {
diff --git a/src/core/unit.h b/src/core/unit.h
index e60168267f..9df5a7e6fb 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -115,6 +115,9 @@ struct Unit {
/* JOB_NOP jobs are special and can be installed without disturbing the real job. */
Job *nop_job;
+ /* The slot used for watching NameOwnerChanged signals */
+ sd_bus_slot *match_bus_slot;
+
/* Job timeout and action to take */
usec_t job_timeout;
FailureAction job_timeout_action;
@@ -522,6 +525,7 @@ void unit_unwatch_all_pids(Unit *u);
void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
+int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name);
int unit_watch_bus_name(Unit *u, const char *name);
void unit_unwatch_bus_name(Unit *u, const char *name);