X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-objects.c;h=68437f1e37f86ac6de035b30262948fdd079c4cd;hp=54ed7542d27473dce8222e4af3191d390a5fd151;hb=a03e4337fd2ae1cc90989e9b7b5f160b42cdb021;hpb=8e050193e17ed002f7608ba1b1fe3371a8bb182c diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c index 54ed7542d..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; @@ -831,7 +857,7 @@ static int process_introspect( if (bus->nodes_modified) return 0; - r = introspect_begin(&intro); + r = introspect_begin(&intro, bus->trusted); if (r < 0) return r; @@ -1680,7 +1706,7 @@ static int add_object_vtable_internal( !signature_is_valid(strempty(v->x.method.signature), false) || !signature_is_valid(strempty(v->x.method.result), false) || !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) || - v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) { + v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) { r = -EINVAL; goto fail; } @@ -1722,13 +1748,12 @@ static int add_object_vtable_internal( !signature_is_single(v->x.property.signature, false) || !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) || v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY || - (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) || + (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 || (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) { r = -EINVAL; goto fail; } - m = new0(struct vtable_member, 1); if (!m) { r = -ENOMEM; @@ -1997,56 +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, -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_INVALIDATE_ONLY) { - 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_INVALIDATE_ONLY)) - 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 {