[systemd-devel] [RFC] bus: add sd_bus_emit_object_{added, removed}()
David Herrmann
dh.herrmann at gmail.com
Mon Mar 3 11:21:16 PST 2014
ping?
On Tue, Feb 18, 2014 at 12:02 AM, David Herrmann <dh.herrmann at gmail.com> wrote:
> 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