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:
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user