From a03e4337fd2ae1cc90989e9b7b5f160b42cdb021 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 22 Dec 2013 03:22:34 +0100 Subject: [PATCH] bus: allow invocation of sd_bus_emit_properties_changed_strv() with NULL list When NULL is passed this shall indicate that a PropertiesChanged message for all properties marked as EMITS_CHANGE or EMITS_INVALIDATION should be generated. --- src/libsystemd-bus/bus-objects.c | 208 +++++++++++++++++--------- src/libsystemd-bus/test-bus-objects.c | 27 ++++ 2 files changed, 165 insertions(+), 70 deletions(-) diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c index e468025a8..68437f1e3 100644 --- a/src/libsystemd-bus/bus-objects.c +++ b/src/libsystemd-bus/bus-objects.c @@ -617,6 +617,52 @@ static int property_get_set_callbacks_run( return 1; } +static int vtable_append_one_property( + sd_bus *bus, + sd_bus_message *reply, + const char *path, + struct node_vtable *c, + const sd_bus_vtable *v, + void *userdata, + sd_bus_error *error) { + + int r; + + assert(bus); + assert(reply); + assert(path); + assert(c); + assert(v); + + r = sd_bus_message_open_container(reply, 'e', "sv"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", v->x.property.member); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'v', v->x.property.signature); + if (r < 0) + return r; + + r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return 0; +} + static int vtable_append_all_properties( sd_bus *bus, sd_bus_message *reply, @@ -643,31 +689,11 @@ static int vtable_append_all_properties( if (v->flags & SD_BUS_VTABLE_HIDDEN) continue; - r = sd_bus_message_open_container(reply, 'e', "sv"); - if (r < 0) - return r; - - r = sd_bus_message_append(reply, "s", v->x.property.member); - if (r < 0) - return r; - - r = sd_bus_message_open_container(reply, 'v', v->x.property.signature); - if (r < 0) - return r; - - r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error); + r = vtable_append_one_property(bus, reply, path, c, v, userdata, error); if (r < 0) return r; if (bus->nodes_modified) return 0; - - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; - - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; } return 1; @@ -1996,57 +2022,75 @@ static int emit_properties_changed_on_interface( if (r == 0) continue; - STRV_FOREACH(property, names) { - struct vtable_member *v; + if (names) { + /* If the caller specified a list of + * properties we include exactly those in the + * PropertiesChanged message */ - assert_return(member_name_is_valid(*property), -EINVAL); + STRV_FOREACH(property, names) { + struct vtable_member *v; - key.member = *property; - v = hashmap_get(bus->vtable_properties, &key); - if (!v) - return -ENOENT; + assert_return(member_name_is_valid(*property), -EINVAL); - /* If there are two vtables for the same - * interface, let's handle this property when - * we come to that vtable. */ - if (c != v->parent) - continue; + key.member = *property; + v = hashmap_get(bus->vtable_properties, &key); + if (!v) + return -ENOENT; + + /* If there are two vtables for the same + * interface, let's handle this property when + * we come to that vtable. */ + if (c != v->parent) + continue; - assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE || - v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM); + assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE || + v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM); - if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) { - has_invalidating = true; - continue; + assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM); + + if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) { + has_invalidating = true; + continue; + } + + has_changing = true; + + r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; } + } else { + const sd_bus_vtable *v; - has_changing = true; + /* If the caller specified no properties list + * we include all properties that are marked + * as changing in the message. */ - r = sd_bus_message_open_container(m, 'e', "sv"); - if (r < 0) - return r; + for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { + if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + continue; - r = sd_bus_message_append(m, "s", *property); - if (r < 0) - return r; + if (v->flags & SD_BUS_VTABLE_HIDDEN) + continue; - r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature); - if (r < 0) - return r; + if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) { + has_invalidating = true; + continue; + } - r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, vtable_property_convert_userdata(v->vtable, u), &error); - if (r < 0) - return r; - if (bus->nodes_modified) - return 0; + if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) + continue; - r = sd_bus_message_close_container(m); - if (r < 0) - return r; + has_changing = true; - r = sd_bus_message_close_container(m); - if (r < 0) - return r; + r = vtable_append_one_property(bus, m, m->path, c, v, u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } } } @@ -2077,19 +2121,38 @@ static int emit_properties_changed_on_interface( if (r == 0) continue; - STRV_FOREACH(property, names) { - struct vtable_member *v; + if (names) { + STRV_FOREACH(property, names) { + struct vtable_member *v; - key.member = *property; - assert_se(v = hashmap_get(bus->vtable_properties, &key)); - assert(c == v->parent); + key.member = *property; + assert_se(v = hashmap_get(bus->vtable_properties, &key)); + assert(c == v->parent); - if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) - continue; + if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) + continue; - r = sd_bus_message_append(m, "s", *property); - if (r < 0) - return r; + r = sd_bus_message_append(m, "s", *property); + if (r < 0) + return r; + } + } else { + const sd_bus_vtable *v; + + for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { + if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + continue; + + if (v->flags & SD_BUS_VTABLE_HIDDEN) + continue; + + if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) + continue; + + r = sd_bus_message_append(m, "s", v->x.property.member); + if (r < 0) + return r; + } } } } @@ -2121,7 +2184,12 @@ _public_ int sd_bus_emit_properties_changed_strv( assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); - if (strv_isempty(names)) + + /* A non-NULL but empty names list means nothing needs to be + generated. A NULL list OTOH indicates that all properties + that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be + included in the PropertiesChanged message. */ + if (names && names[0] == NULL) return 0; do { diff --git a/src/libsystemd-bus/test-bus-objects.c b/src/libsystemd-bus/test-bus-objects.c index 0ab7a148d..e2423c7f6 100644 --- a/src/libsystemd-bus/test-bus-objects.c +++ b/src/libsystemd-bus/test-bus-objects.c @@ -143,6 +143,17 @@ static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_er return 1; } +static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int r; + + assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0); + + r = sd_bus_reply_method_return(m, NULL); + assert_se(r >= 0); + + return 1; +} + static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; @@ -181,7 +192,11 @@ static const sd_bus_vtable vtable[] = { static const sd_bus_vtable vtable2[] = { SD_BUS_VTABLE_START(0), SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0), + SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0), SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0), SD_BUS_VTABLE_END }; @@ -405,6 +420,18 @@ static int client(struct context *c) { sd_bus_message_unref(reply); reply = NULL; + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, ""); + assert_se(r >= 0); + + r = sd_bus_process(bus, &reply); + assert_se(r > 0); + + assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, ""); assert_se(r >= 0); -- 2.30.2