[systemd-devel] [RFC] bus: add sd_bus_emit_object_{added, removed}()

David Herrmann dh.herrmann at gmail.com
Mon Feb 17 15:02:55 PST 2014


The ObjectManager dbus interface provides an InterfacesAdded signal to
notify others about new interfaces that are added to an object. The same
signal is also used to advertise new objects (by adding the first
interface to a given object path) and delete them.

However, our internal helpers sd_bus_emit_interfaces_{added,removed}()
cannot properly deal with built-in interfaces like DBus.Properties as
there's no vtable for it. Therefore, to avoid callers to track these
internal interfaces, we provide two separate helpers which explicitly add
these interfaces to the signal.

sd_bus_emit_object_added() traverses the list of all vtables and fallback
vtables (making sure a fallback never overwrites a real vtable!) and also
adds built-in interfaces.

sd_bus_emit_object_removed(): WIP
---
Hi

This is untested and I just wanted to get some feedback whether that's the way
to go. Given the previous discussion we decided on two new entry-points to add
and remove objects. For convenience, I now tried to omit any "char **interfaces"
argument to object_added() and just try to figure them out on my own.

However, on object_removed() I cannot do that as node_vtable_get_userdata() is
very likely to return "0" for all these objects. So there is no way to figure
out which interfaces actually existed on that thing. We would require users to
call it *before* destroying/unlinking the actual object. I don't know whether
that's ok to assume?

If not, we can just add a "char **interfaces" argument, but then it would differ
from object_added().. Not sure what sounds better..

Cheers
David

 src/libsystemd/sd-bus/bus-objects.c | 210 ++++++++++++++++++++++++++++++++++++
 src/systemd/sd-bus.h                |   2 +
 2 files changed, 212 insertions(+)

diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index b116a5d..0c099a3 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -2469,6 +2469,216 @@ _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const
         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
 }
 
+static int object_added_append_all_prefix(
+                sd_bus *bus,
+                sd_bus_message *m,
+                Set *s,
+                const char *prefix,
+                const char *path,
+                bool require_fallback) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *previous_interface = NULL;
+        struct node_vtable *c;
+        struct node *n;
+        void *u = NULL;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(s);
+        assert(prefix);
+        assert(path);
+
+        n = hashmap_get(bus->nodes, prefix);
+        if (!n)
+                return 0;
+
+        LIST_FOREACH(vtables, c, n->vtables) {
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                r = node_vtable_get_userdata(bus, path, c, &u, &error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+                if (r == 0)
+                        continue;
+
+                if (!streq_ptr(c->interface, previous_interface)) {
+                        /* interface already handled by a previous run? */
+                        if (set_get(s, c->interface))
+                                continue;
+
+                        /* prevent fallbacks from overwriting specific objs */
+                        r = set_put(s, c->interface);
+                        if (r < 0)
+                                return r;
+
+                        if (previous_interface) {
+                                r = sd_bus_message_close_container(m);
+                                if (r < 0)
+                                        return r;
+
+                                r = sd_bus_message_close_container(m);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        r = sd_bus_message_open_container(m, 'e', "sa{sv}");
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_append_basic(m, 's', c->interface);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_open_container(m, 'a', "{sv}");
+                        if (r < 0)
+                                return r;
+
+                        previous_interface = c->interface;
+                }
+
+                r = vtable_append_all_properties(bus, m, path, c, u, &error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        if (previous_interface) {
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int object_added_append_builtin(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *interface) {
+
+        int r;
+
+        r = sd_bus_message_open_container(m, 'e', "sa{sv}");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append_basic(m, 's', interface);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(m, 'a', "{sv}");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int object_added_append_all(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *path) {
+
+        _cleanup_set_free_ Set *s = NULL;
+        char *prefix;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(path);
+
+        s = set_new(string_hash_func, string_compare_func);
+        if (!s)
+                return -ENOMEM;
+
+        r = object_added_append_builtin(bus, m, "org.freedesktop.DBus.Properties");
+        if (r < 0)
+                return r;
+        r = object_added_append_builtin(bus, m, "org.freedesktop.DBus.Introspectable");
+        if (r < 0)
+                return r;
+        r = object_added_append_builtin(bus, m, "org.freedesktop.DBus.ObjectManager");
+        if (r < 0)
+                return r;
+        r = object_added_append_builtin(bus, m, "org.freedesktop.DBus.Peer");
+        if (r < 0)
+                return r;
+
+        r = object_added_append_all_prefix(bus, m, s, path, path, false);
+        if (r < 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        prefix = alloca(strlen(path) + 1);
+        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                r = object_added_append_all_prefix(bus, m, s, prefix, path, true);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
+        BUS_DONT_DESTROY(bus);
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        do {
+                bus->nodes_modified = false;
+                m = sd_bus_message_unref(m);
+
+                r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append_basic(m, 'o', path);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
+                if (r < 0)
+                        return r;
+
+                r = object_added_append_all(bus, m, path);
+                if (r != 0)
+                        return r;
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return r;
+
+        } while (bus->nodes_modified);
+
+        return sd_bus_send(bus, m, NULL);
+}
+
 _public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
         struct node *n;
 
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 34d4263..0236e53 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -279,6 +279,8 @@ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **inte
 int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
 int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces);
 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
+int sd_bus_emit_object_added(sd_bus *bus, const char *path);
+int sd_bus_emit_object_removed(sd_bus *bus, const char *path);
 
 int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
 
-- 
1.9.0



More information about the systemd-devel mailing list