chiark / gitweb /
logind: add infrastructure to watch busnames
authorDavid Herrmann <dh.herrmann@gmail.com>
Tue, 17 Sep 2013 15:39:55 +0000 (17:39 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 17 Sep 2013 16:30:44 +0000 (11:30 -0500)
If we want to track bus-names to allow exclusive resource-access, we need
a way to get notified when a bus-name is gone. We make logind watch for
NameOwnerChanged dbus events and check whether the name is currently
watched. If it is, we remove it from the watch-list (notification for
other objects can be added in follow-up patches).

src/login/logind-dbus.c
src/login/logind.c
src/login/logind.h

index d052e74789eab5db4d5b51d854afcb9ccd97cf3b..5decf8114c9c9f3f1e39ab71531e6cfd110cd3ec 100644 (file)
@@ -2459,6 +2459,23 @@ DBusHandlerResult bus_message_filter(
                         HASHMAP_FOREACH(session, m->sessions, i)
                                 session_add_to_gc_queue(session);
                 }
+
+        } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
+                const char *name, *old, *new;
+                char *key;
+
+                if (!dbus_message_get_args(message, &error,
+                                           DBUS_TYPE_STRING, &name,
+                                           DBUS_TYPE_STRING, &old,
+                                           DBUS_TYPE_STRING, &new,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
+                        goto finish;
+                }
+
+                if (*old && !*new && (key = hashmap_remove(m->busnames, old))) {
+                        free(key);
+                }
         }
 
 finish:
index 29019c214b28209d69deee1c2ff8c32b4142e90f..89e4eeea16db1dbdcd8121bc32ff241d48bea839 100644 (file)
@@ -74,6 +74,7 @@ Manager *manager_new(void) {
         m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->inhibitors = hashmap_new(string_hash_func, string_compare_func);
         m->buttons = hashmap_new(string_hash_func, string_compare_func);
+        m->busnames = hashmap_new(string_hash_func, string_compare_func);
 
         m->user_units = hashmap_new(string_hash_func, string_compare_func);
         m->session_units = hashmap_new(string_hash_func, string_compare_func);
@@ -82,7 +83,7 @@ Manager *manager_new(void) {
         m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
 
-        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons ||
+        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames ||
             !m->user_units || !m->session_units ||
             !m->session_fds || !m->inhibitor_fds || !m->button_fds) {
                 manager_free(m);
@@ -111,6 +112,7 @@ void manager_free(Manager *m) {
         Seat *s;
         Inhibitor *i;
         Button *b;
+        char *n;
 
         assert(m);
 
@@ -132,12 +134,16 @@ void manager_free(Manager *m) {
         while ((b = hashmap_first(m->buttons)))
                 button_free(b);
 
+        while ((n = hashmap_first(m->busnames)))
+                free(hashmap_remove(m->busnames, n));
+
         hashmap_free(m->devices);
         hashmap_free(m->seats);
         hashmap_free(m->sessions);
         hashmap_free(m->users);
         hashmap_free(m->inhibitors);
         hashmap_free(m->buttons);
+        hashmap_free(m->busnames);
 
         hashmap_free(m->user_units);
         hashmap_free(m->session_units);
@@ -361,6 +367,40 @@ int manager_add_button(Manager *m, const char *name, Button **_button) {
         return 0;
 }
 
+int manager_watch_busname(Manager *m, const char *name) {
+        char *n;
+        int r;
+
+        assert(m);
+        assert(name);
+
+        if (hashmap_get(m->busnames, name))
+                return 0;
+
+        n = strdup(name);
+        if (!n)
+                return -ENOMEM;
+
+        r = hashmap_put(m->busnames, n, n);
+        if (r < 0) {
+                free(n);
+                return r;
+        }
+
+        return 0;
+}
+
+void manager_drop_busname(Manager *m, const char *name) {
+        char *key;
+
+        assert(m);
+        assert(name);
+
+        key = hashmap_remove(m->busnames, name);
+        if (key)
+                free(key);
+}
+
 int manager_process_seat_device(Manager *m, struct udev_device *d) {
         Device *device;
         int r;
@@ -1043,6 +1083,18 @@ static int manager_connect_bus(Manager *m) {
                 goto fail;
         }
 
+        dbus_bus_add_match(m->bus,
+                           "type='signal',"
+                           "sender='"DBUS_SERVICE_DBUS"',"
+                           "interface='"DBUS_INTERFACE_DBUS"',"
+                           "member='NameOwnerChanged',"
+                           "path='"DBUS_PATH_DBUS"'",
+                           &error);
+        if (dbus_error_is_set(&error)) {
+                log_error("Failed to add match for NameOwnerChanged: %s", bus_error_message(&error));
+                dbus_error_free(&error);
+        }
+
         dbus_bus_add_match(m->bus,
                            "type='signal',"
                            "sender='org.freedesktop.systemd1',"
index 1a97351fffe0de5ea28b4b366a39bdf465b1e2c7..a76936da17698fdefe417119aeacba30335fe8f2 100644 (file)
@@ -51,6 +51,7 @@ struct Manager {
         Hashmap *users;
         Hashmap *inhibitors;
         Hashmap *buttons;
+        Hashmap *busnames;
 
         LIST_HEAD(Seat, seat_gc_queue);
         LIST_HEAD(Session, session_gc_queue);
@@ -190,3 +191,6 @@ int manager_unit_is_active(Manager *manager, const char *unit);
 
 /* gperf lookup function */
 const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length);
+
+int manager_watch_busname(Manager *manager, const char *name);
+void manager_drop_busname(Manager *manager, const char *name);