Merge pull request #23702 from igo95862/fix-object-manager-interface-in-wrong-places

Fix ObjectManager interfaces for `GetManagedObjects`, `InerfacesAdded` and `InterfacesRemoved`
This commit is contained in:
Lennart Poettering
2022-07-26 11:24:02 +02:00
committed by GitHub
3 changed files with 159 additions and 20 deletions
+14
View File
@@ -95,6 +95,20 @@
_expr_; \
})
#define ASSERT_NONNEG(expr) \
({ \
typeof(expr) _expr_ = (expr), _zero = 0; \
assert(_expr_ >= _zero); \
_expr_; \
})
#define ASSERT_SE_NONNEG(expr) \
({ \
typeof(expr) _expr_ = (expr), _zero = 0; \
assert_se(_expr_ >= _zero); \
_expr_; \
})
#define assert_cc(expr) static_assert(expr, #expr)
+43 -20
View File
@@ -1044,6 +1044,7 @@ static int object_manager_serialize_path(
const char *prefix,
const char *path,
bool require_fallback,
bool *found_object_manager,
sd_bus_error *error) {
const char *previous_interface = NULL;
@@ -1055,12 +1056,16 @@ static int object_manager_serialize_path(
assert(reply);
assert(prefix);
assert(path);
assert(found_object_manager);
assert(error);
n = hashmap_get(bus->nodes, prefix);
if (!n)
return 0;
if (!require_fallback && n->object_managers)
*found_object_manager = true;
LIST_FOREACH(vtables, i, n->vtables) {
void *u;
@@ -1103,9 +1108,12 @@ static int object_manager_serialize_path(
if (r < 0)
return r;
r = sd_bus_message_append(reply, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
if (r < 0)
return r;
if (*found_object_manager) {
r = sd_bus_message_append(
reply, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
if (r < 0)
return r;
}
found_something = true;
}
@@ -1180,6 +1188,7 @@ static int object_manager_serialize_path_and_fallbacks(
_cleanup_free_ char *prefix = NULL;
size_t pl;
int r;
bool found_object_manager = false;
assert(bus);
assert(reply);
@@ -1187,7 +1196,7 @@ static int object_manager_serialize_path_and_fallbacks(
assert(error);
/* First, add all vtables registered for this path */
r = object_manager_serialize_path(bus, reply, path, path, false, error);
r = object_manager_serialize_path(bus, reply, path, path, false, &found_object_manager, error);
if (r < 0)
return r;
if (bus->nodes_modified)
@@ -1201,7 +1210,7 @@ static int object_manager_serialize_path_and_fallbacks(
return -ENOMEM;
OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
r = object_manager_serialize_path(bus, reply, prefix, path, true, &found_object_manager, error);
if (r < 0)
return r;
if (bus->nodes_modified)
@@ -1548,13 +1557,18 @@ void bus_node_gc(sd_bus *b, struct node *n) {
free(n);
}
static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) {
static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path, bool* path_has_object_manager) {
struct node *n;
assert(bus);
assert(path);
assert(path_has_object_manager);
n = hashmap_get(bus->nodes, path);
if (n)
*path_has_object_manager = n->object_managers;
if (!n) {
_cleanup_free_ char *prefix = NULL;
size_t pl;
@@ -2423,7 +2437,7 @@ static int object_added_append_all_prefix(
return 0;
}
static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path, bool path_has_object_manager) {
_cleanup_ordered_set_free_ OrderedSet *s = NULL;
_cleanup_free_ char *prefix = NULL;
size_t pl;
@@ -2461,9 +2475,11 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p
r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);
if (r < 0)
return r;
r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
if (r < 0)
return r;
if (path_has_object_manager){
r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
if (r < 0)
return r;
}
r = object_added_append_all_prefix(bus, m, s, path, path, false);
if (r < 0)
@@ -2512,7 +2528,8 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
r = bus_find_parent_object_manager(bus, &object_manager, path);
bool path_has_object_manager = false;
r = bus_find_parent_object_manager(bus, &object_manager, path, &path_has_object_manager);
if (r < 0)
return r;
if (r == 0)
@@ -2536,7 +2553,7 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
if (r < 0)
return r;
r = object_added_append_all(bus, m, path);
r = object_added_append_all(bus, m, path, path_has_object_manager);
if (r < 0)
return r;
@@ -2612,7 +2629,7 @@ static int object_removed_append_all_prefix(
return 0;
}
static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path, bool path_has_object_manager) {
_cleanup_ordered_set_free_ OrderedSet *s = NULL;
_cleanup_free_ char *prefix = NULL;
size_t pl;
@@ -2637,9 +2654,12 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char
r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Properties");
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
if (r < 0)
return r;
if (path_has_object_manager){
r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
if (r < 0)
return r;
}
r = object_removed_append_all_prefix(bus, m, s, path, path, false);
if (r < 0)
@@ -2688,7 +2708,8 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
r = bus_find_parent_object_manager(bus, &object_manager, path);
bool path_has_object_manager = false;
r = bus_find_parent_object_manager(bus, &object_manager, path, &path_has_object_manager);
if (r < 0)
return r;
if (r == 0)
@@ -2712,7 +2733,7 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
if (r < 0)
return r;
r = object_removed_append_all(bus, m, path);
r = object_removed_append_all(bus, m, path, path_has_object_manager);
if (r < 0)
return r;
@@ -2849,7 +2870,8 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch
if (strv_isempty(interfaces))
return 0;
r = bus_find_parent_object_manager(bus, &object_manager, path);
bool path_has_object_manager = false;
r = bus_find_parent_object_manager(bus, &object_manager, path, &path_has_object_manager);
if (r < 0)
return r;
if (r == 0)
@@ -2936,7 +2958,8 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path,
if (strv_isempty(interfaces))
return 0;
r = bus_find_parent_object_manager(bus, &object_manager, path);
bool path_has_object_manager = false;
r = bus_find_parent_object_manager(bus, &object_manager, path, &path_has_object_manager);
if (r < 0)
return r;
if (r == 0)
+102
View File
@@ -165,6 +165,12 @@ static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *er
return 1;
}
static int emit_object_with_manager_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), "/value/a") >= 0);
return ASSERT_SE_NONNEG(sd_bus_reply_method_return(m, NULL));
}
static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
@@ -187,6 +193,7 @@ static const sd_bus_vtable vtable[] = {
SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
SD_BUS_METHOD("EmitObjectAdded", NULL, NULL, emit_object_added, 0),
SD_BUS_METHOD("EmitObjectWithManagerAdded", NULL, NULL, emit_object_with_manager_added, 0),
SD_BUS_METHOD("EmitObjectRemoved", NULL, NULL, emit_object_removed, 0),
SD_BUS_VTABLE_END
};
@@ -463,6 +470,41 @@ static int client(struct context *c) {
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
/* Check that /value/b does not have ObjectManager interface but /value/a does */
assert_se(sd_bus_message_rewind(reply, 1) > 0);
assert_se(sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{oa{sa{sv}}}") > 0);
while (ASSERT_SE_NONNEG(sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "oa{sa{sv}}")) > 0) {
const char *path = NULL;
assert_se(sd_bus_message_read_basic(reply, 'o', &path) > 0);
if (STR_IN_SET(path, "/value/b", "/value/a")) {
/* Check that there is no object manager interface here */
bool found_object_manager_interface = false;
assert_se(sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sa{sv}}") > 0);
while (ASSERT_SE_NONNEG(sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sa{sv}")) > 0) {
const char *interface_name = NULL;
assert_se(sd_bus_message_read_basic(reply, 's', &interface_name) > 0);
if (streq(interface_name, "org.freedesktop.DBus.ObjectManager")) {
assert_se(!streq(path, "/value/b"));
found_object_manager_interface = true;
}
assert_se(sd_bus_message_skip(reply, "a{sv}") >= 0);
assert_se(sd_bus_message_exit_container(reply) >= 0);
}
assert_se(sd_bus_message_exit_container(reply) >= 0);
if (streq(path, "/value/a")) {
/* ObjectManager must be here */
assert_se(found_object_manager_interface);
}
} else
assert_se(sd_bus_message_skip(reply, "a{sa{sv}}") >= 0);
assert_se(sd_bus_message_exit_container(reply) >= 0);
}
reply = sd_bus_message_unref(reply);
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, NULL);
@@ -518,6 +560,54 @@ static int client(struct context *c) {
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
/* Check if /value/a/x does not have org.freedesktop.DBus.ObjectManager */
assert_se(sd_bus_message_rewind(reply, 1) >= 0);
const char* should_be_value_a_x = NULL;
assert_se(sd_bus_message_read_basic(reply, 'o', &should_be_value_a_x) > 0);
assert_se(streq(should_be_value_a_x, "/value/a/x"));
assert_se(sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sa{sv}}") > 0);
while (ASSERT_SE_NONNEG(sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sa{sv}")) > 0) {
const char* interface_name = NULL;
assert_se(sd_bus_message_read_basic(reply, 's', &interface_name) > 0);
assert(!streq(interface_name, "org.freedesktop.DBus.ObjectManager"));
assert_se(sd_bus_message_skip(reply, "a{sv}") >= 0);
assert_se(sd_bus_message_exit_container(reply) >= 0);
}
reply = sd_bus_message_unref(reply);
assert_se(sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectWithManagerAdded", &error, NULL, NULL) >= 0);
assert_se(sd_bus_process(bus, &reply) > 0);
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
/* Check if /value/a has org.freedesktop.DBus.ObjectManager */
assert_se(sd_bus_message_rewind(reply, 1) >= 0);
const char* should_be_value_a = NULL;
bool found_object_manager = false;
assert_se(sd_bus_message_read_basic(reply, 'o', &should_be_value_a) > 0);
assert_se(streq(should_be_value_a, "/value/a"));
assert_se(sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sa{sv}}") > 0);
while (ASSERT_SE_NONNEG(sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sa{sv}")) > 0) {
const char* interface_name = NULL;
assert_se(sd_bus_message_read_basic(reply, 's', &interface_name));
if (streq(interface_name, "org.freedesktop.DBus.ObjectManager")) {
found_object_manager = true;
break;
}
assert_se(sd_bus_message_skip(reply, "a{sv}") >= 0);
assert_se(sd_bus_message_exit_container(reply) >= 0);
}
assert_se(found_object_manager);
reply = sd_bus_message_unref(reply);
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, NULL);
@@ -529,6 +619,18 @@ static int client(struct context *c) {
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
/* Check if /value/a/x does not have org.freedesktop.DBus.ObjectManager */
assert_se(sd_bus_message_rewind(reply, 1) >= 0);
should_be_value_a_x = NULL;
assert_se(sd_bus_message_read_basic(reply, 'o', &should_be_value_a_x) > 0);
assert_se(streq(should_be_value_a_x, "/value/a/x"));
assert_se(sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s") > 0);
const char* deleted_interface_name = NULL;
while (ASSERT_SE_NONNEG(sd_bus_message_read_basic(reply, 's', &deleted_interface_name)) > 0) {
assert(!streq(deleted_interface_name, "org.freedesktop.DBus.ObjectManager"));
}
assert_se(sd_bus_message_exit_container(reply) >= 0);
reply = sd_bus_message_unref(reply);
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, NULL);