bus: properly implement logic for generating InterfacesAdded/InterfacesRemoved signals of ObjectManager
This commit is contained in:
@@ -1897,12 +1897,206 @@ int sd_bus_emit_properties_changed(
|
||||
return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
|
||||
}
|
||||
|
||||
int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interfaces, ...) {
|
||||
return -ENOSYS;
|
||||
static int interfaces_added_append_one_prefix(
|
||||
sd_bus *bus,
|
||||
sd_bus_message *m,
|
||||
const char *prefix,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
bool require_fallback) {
|
||||
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
struct node_vtable *c;
|
||||
struct node *n;
|
||||
void *u = NULL;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(m);
|
||||
assert(prefix);
|
||||
assert(path);
|
||||
assert(interface);
|
||||
|
||||
n = hashmap_get(bus->nodes, prefix);
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
LIST_FOREACH(vtables, c, n->vtables) {
|
||||
if (require_fallback && !c->is_fallback)
|
||||
continue;
|
||||
|
||||
if (streq(c->interface, interface))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
r = node_vtable_get_userdata(bus, path, c, &u);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append_basic(m, 's', interface);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "{sv}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = vtable_append_all_properties(bus, m,path, c, u, &error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_bus_error_is_set(&error))
|
||||
return bus_error_to_errno(&error);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interfaces, ...) {
|
||||
return -ENOSYS;
|
||||
static int interfaces_added_append_one(
|
||||
sd_bus *bus,
|
||||
sd_bus_message *m,
|
||||
const char *path,
|
||||
const char *interface) {
|
||||
|
||||
char *prefix;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(m);
|
||||
assert(path);
|
||||
assert(interface);
|
||||
|
||||
r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
prefix = alloca(strlen(path) + 1);
|
||||
OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
|
||||
r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
assert_return(bus, -EINVAL);
|
||||
assert_return(object_path_is_valid(path), -EINVAL);
|
||||
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
|
||||
assert_return(!bus_pid_changed(bus), -ECHILD);
|
||||
|
||||
if (strv_isempty(interfaces))
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append_basic(m, 'o', path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(i, interfaces) {
|
||||
assert_return(interface_name_is_valid(*i), -EINVAL);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'e', "sa{sv}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = interfaces_added_append_one(bus, m, path, *i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(bus, m, NULL);
|
||||
}
|
||||
|
||||
int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
|
||||
_cleanup_strv_free_ char **interfaces = NULL;
|
||||
va_list ap;
|
||||
|
||||
assert_return(bus, -EINVAL);
|
||||
assert_return(object_path_is_valid(path), -EINVAL);
|
||||
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
|
||||
assert_return(!bus_pid_changed(bus), -ECHILD);
|
||||
|
||||
va_start(ap, interface);
|
||||
interfaces = strv_new_ap(interface, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!interfaces)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
|
||||
}
|
||||
|
||||
int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(bus, -EINVAL);
|
||||
assert_return(object_path_is_valid(path), -EINVAL);
|
||||
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
|
||||
assert_return(!bus_pid_changed(bus), -ECHILD);
|
||||
|
||||
if (strv_isempty(interfaces))
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append_basic(m, 'o', path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append_strv(m, interfaces);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(bus, m, NULL);
|
||||
}
|
||||
|
||||
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
|
||||
_cleanup_strv_free_ char **interfaces = NULL;
|
||||
va_list ap;
|
||||
|
||||
assert_return(bus, -EINVAL);
|
||||
assert_return(object_path_is_valid(path), -EINVAL);
|
||||
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
|
||||
assert_return(!bus_pid_changed(bus), -ECHILD);
|
||||
|
||||
va_start(ap, interface);
|
||||
interfaces = strv_new_ap(interface, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!interfaces)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
|
||||
}
|
||||
|
||||
int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
* Add in:
|
||||
*
|
||||
* node hierarchy updates during dispatching
|
||||
* emit_interfaces_added/emit_interfaces_removed
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -147,6 +146,28 @@ static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata) {
|
||||
int r;
|
||||
|
||||
assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
|
||||
|
||||
r = sd_bus_reply_method_return(bus, m, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata) {
|
||||
int r;
|
||||
|
||||
assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
|
||||
|
||||
r = sd_bus_reply_method_return(bus, m, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
|
||||
@@ -154,7 +175,9 @@ static const sd_bus_vtable vtable[] = {
|
||||
SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
|
||||
SD_BUS_METHOD("NoOperation", "", "", NULL, 0),
|
||||
SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
|
||||
SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
|
||||
SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
@@ -385,6 +408,30 @@ static int client(struct context *c) {
|
||||
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);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
assert_se(r > 0);
|
||||
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
|
||||
bus_message_dump(reply);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &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.ObjectManager", "InterfacesRemoved"));
|
||||
bus_message_dump(reply);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
|
||||
assert_se(r >= 0);
|
||||
|
||||
|
||||
@@ -217,10 +217,10 @@ int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, con
|
||||
int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names);
|
||||
int sd_bus_emit_properties_changed(sd_bus *bus, const char *path, const char *interface, const char *name, ...) _sd_sentinel_attr_;
|
||||
|
||||
int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces); /* MISSING */
|
||||
int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_attr_; /* MISSING */
|
||||
int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces); /* MISSING */
|
||||
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_attr_; /* MISSING */
|
||||
int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces);
|
||||
int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_attr_;
|
||||
int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces);
|
||||
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_attr_;
|
||||
|
||||
/* Bus management */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user