summaryrefslogtreecommitdiff
path: root/src/libsystemd-bus
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r--src/libsystemd-bus/bus-objects.c208
-rw-r--r--src/libsystemd-bus/test-bus-objects.c27
2 files changed, 165 insertions, 70 deletions
diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c
index e468025a81..68437f1e37 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 0ab7a148d3..e2423c7f67 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);