Skip to content

Commit a03e433

Browse files
committed
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.
1 parent 556089d commit a03e433

File tree

2 files changed

+165
-70
lines changed

2 files changed

+165
-70
lines changed

src/libsystemd-bus/bus-objects.c

Lines changed: 138 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,52 @@ static int property_get_set_callbacks_run(
617617
return 1;
618618
}
619619

620+
static int vtable_append_one_property(
621+
sd_bus *bus,
622+
sd_bus_message *reply,
623+
const char *path,
624+
struct node_vtable *c,
625+
const sd_bus_vtable *v,
626+
void *userdata,
627+
sd_bus_error *error) {
628+
629+
int r;
630+
631+
assert(bus);
632+
assert(reply);
633+
assert(path);
634+
assert(c);
635+
assert(v);
636+
637+
r = sd_bus_message_open_container(reply, 'e', "sv");
638+
if (r < 0)
639+
return r;
640+
641+
r = sd_bus_message_append(reply, "s", v->x.property.member);
642+
if (r < 0)
643+
return r;
644+
645+
r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
646+
if (r < 0)
647+
return r;
648+
649+
r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
650+
if (r < 0)
651+
return r;
652+
if (bus->nodes_modified)
653+
return 0;
654+
655+
r = sd_bus_message_close_container(reply);
656+
if (r < 0)
657+
return r;
658+
659+
r = sd_bus_message_close_container(reply);
660+
if (r < 0)
661+
return r;
662+
663+
return 0;
664+
}
665+
620666
static int vtable_append_all_properties(
621667
sd_bus *bus,
622668
sd_bus_message *reply,
@@ -643,31 +689,11 @@ static int vtable_append_all_properties(
643689
if (v->flags & SD_BUS_VTABLE_HIDDEN)
644690
continue;
645691

646-
r = sd_bus_message_open_container(reply, 'e', "sv");
647-
if (r < 0)
648-
return r;
649-
650-
r = sd_bus_message_append(reply, "s", v->x.property.member);
651-
if (r < 0)
652-
return r;
653-
654-
r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
655-
if (r < 0)
656-
return r;
657-
658-
r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
692+
r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
659693
if (r < 0)
660694
return r;
661695
if (bus->nodes_modified)
662696
return 0;
663-
664-
r = sd_bus_message_close_container(reply);
665-
if (r < 0)
666-
return r;
667-
668-
r = sd_bus_message_close_container(reply);
669-
if (r < 0)
670-
return r;
671697
}
672698

673699
return 1;
@@ -1996,57 +2022,75 @@ static int emit_properties_changed_on_interface(
19962022
if (r == 0)
19972023
continue;
19982024

1999-
STRV_FOREACH(property, names) {
2000-
struct vtable_member *v;
2025+
if (names) {
2026+
/* If the caller specified a list of
2027+
* properties we include exactly those in the
2028+
* PropertiesChanged message */
20012029

2002-
assert_return(member_name_is_valid(*property), -EINVAL);
2030+
STRV_FOREACH(property, names) {
2031+
struct vtable_member *v;
20032032

2004-
key.member = *property;
2005-
v = hashmap_get(bus->vtable_properties, &key);
2006-
if (!v)
2007-
return -ENOENT;
2033+
assert_return(member_name_is_valid(*property), -EINVAL);
20082034

2009-
/* If there are two vtables for the same
2010-
* interface, let's handle this property when
2011-
* we come to that vtable. */
2012-
if (c != v->parent)
2013-
continue;
2035+
key.member = *property;
2036+
v = hashmap_get(bus->vtable_properties, &key);
2037+
if (!v)
2038+
return -ENOENT;
2039+
2040+
/* If there are two vtables for the same
2041+
* interface, let's handle this property when
2042+
* we come to that vtable. */
2043+
if (c != v->parent)
2044+
continue;
20142045

2015-
assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
2016-
v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
2046+
assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
2047+
v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
20172048

2018-
if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2019-
has_invalidating = true;
2020-
continue;
2049+
assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
2050+
2051+
if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2052+
has_invalidating = true;
2053+
continue;
2054+
}
2055+
2056+
has_changing = true;
2057+
2058+
r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
2059+
if (r < 0)
2060+
return r;
2061+
if (bus->nodes_modified)
2062+
return 0;
20212063
}
2064+
} else {
2065+
const sd_bus_vtable *v;
20222066

2023-
has_changing = true;
2067+
/* If the caller specified no properties list
2068+
* we include all properties that are marked
2069+
* as changing in the message. */
20242070

2025-
r = sd_bus_message_open_container(m, 'e', "sv");
2026-
if (r < 0)
2027-
return r;
2071+
for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2072+
if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2073+
continue;
20282074

2029-
r = sd_bus_message_append(m, "s", *property);
2030-
if (r < 0)
2031-
return r;
2075+
if (v->flags & SD_BUS_VTABLE_HIDDEN)
2076+
continue;
20322077

2033-
r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
2034-
if (r < 0)
2035-
return r;
2078+
if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2079+
has_invalidating = true;
2080+
continue;
2081+
}
20362082

2037-
r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, vtable_property_convert_userdata(v->vtable, u), &error);
2038-
if (r < 0)
2039-
return r;
2040-
if (bus->nodes_modified)
2041-
return 0;
2083+
if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
2084+
continue;
20422085

2043-
r = sd_bus_message_close_container(m);
2044-
if (r < 0)
2045-
return r;
2086+
has_changing = true;
20462087

2047-
r = sd_bus_message_close_container(m);
2048-
if (r < 0)
2049-
return r;
2088+
r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
2089+
if (r < 0)
2090+
return r;
2091+
if (bus->nodes_modified)
2092+
return 0;
2093+
}
20502094
}
20512095
}
20522096

@@ -2077,19 +2121,38 @@ static int emit_properties_changed_on_interface(
20772121
if (r == 0)
20782122
continue;
20792123

2080-
STRV_FOREACH(property, names) {
2081-
struct vtable_member *v;
2124+
if (names) {
2125+
STRV_FOREACH(property, names) {
2126+
struct vtable_member *v;
20822127

2083-
key.member = *property;
2084-
assert_se(v = hashmap_get(bus->vtable_properties, &key));
2085-
assert(c == v->parent);
2128+
key.member = *property;
2129+
assert_se(v = hashmap_get(bus->vtable_properties, &key));
2130+
assert(c == v->parent);
20862131

2087-
if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2088-
continue;
2132+
if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2133+
continue;
20892134

2090-
r = sd_bus_message_append(m, "s", *property);
2091-
if (r < 0)
2092-
return r;
2135+
r = sd_bus_message_append(m, "s", *property);
2136+
if (r < 0)
2137+
return r;
2138+
}
2139+
} else {
2140+
const sd_bus_vtable *v;
2141+
2142+
for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2143+
if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2144+
continue;
2145+
2146+
if (v->flags & SD_BUS_VTABLE_HIDDEN)
2147+
continue;
2148+
2149+
if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2150+
continue;
2151+
2152+
r = sd_bus_message_append(m, "s", v->x.property.member);
2153+
if (r < 0)
2154+
return r;
2155+
}
20932156
}
20942157
}
20952158
}
@@ -2121,7 +2184,12 @@ _public_ int sd_bus_emit_properties_changed_strv(
21212184
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
21222185
assert_return(!bus_pid_changed(bus), -ECHILD);
21232186

2124-
if (strv_isempty(names))
2187+
2188+
/* A non-NULL but empty names list means nothing needs to be
2189+
generated. A NULL list OTOH indicates that all properties
2190+
that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2191+
included in the PropertiesChanged message. */
2192+
if (names && names[0] == NULL)
21252193
return 0;
21262194

21272195
do {

src/libsystemd-bus/test-bus-objects.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,17 @@ static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_er
143143
return 1;
144144
}
145145

146+
static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
147+
int r;
148+
149+
assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
150+
151+
r = sd_bus_reply_method_return(m, NULL);
152+
assert_se(r >= 0);
153+
154+
return 1;
155+
}
156+
146157
static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
147158
int r;
148159

@@ -181,7 +192,11 @@ static const sd_bus_vtable vtable[] = {
181192
static const sd_bus_vtable vtable2[] = {
182193
SD_BUS_VTABLE_START(0),
183194
SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
195+
SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
184196
SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
197+
SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
198+
SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
199+
SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
185200
SD_BUS_VTABLE_END
186201
};
187202

@@ -405,6 +420,18 @@ static int client(struct context *c) {
405420
sd_bus_message_unref(reply);
406421
reply = NULL;
407422

423+
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
424+
assert_se(r >= 0);
425+
426+
r = sd_bus_process(bus, &reply);
427+
assert_se(r > 0);
428+
429+
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
430+
bus_message_dump(reply, stdout, true);
431+
432+
sd_bus_message_unref(reply);
433+
reply = NULL;
434+
408435
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
409436
assert_se(r >= 0);
410437

0 commit comments

Comments
 (0)