summaryrefslogtreecommitdiff
path: root/src/libsystemd/sd-bus/bus-objects.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd/sd-bus/bus-objects.c')
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c187
1 files changed, 125 insertions, 62 deletions
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index cbdf6552f9..9bd07ffcab 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -19,16 +17,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "strv.h"
-#include "set.h"
+#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-introspect.h"
#include "bus-message.h"
-#include "bus-type.h"
+#include "bus-objects.h"
#include "bus-signature.h"
-#include "bus-introspect.h"
-#include "bus-util.h"
#include "bus-slot.h"
-#include "bus-objects.h"
+#include "bus-type.h"
+#include "bus-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
static int node_vtable_get_userdata(
sd_bus *bus,
@@ -68,6 +68,12 @@ static int node_vtable_get_userdata(
return 1;
}
+static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
+ assert(p);
+
+ return (uint8_t*) u + p->x.method.offset;
+}
+
static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
assert(p);
@@ -139,7 +145,7 @@ static int add_enumerated_to_set(
continue;
}
- if (!object_path_is_valid(*k)){
+ if (!object_path_is_valid(*k)) {
free(*k);
r = -EINVAL;
continue;
@@ -163,10 +169,18 @@ static int add_enumerated_to_set(
return 0;
}
+enum {
+ /* if set, add_subtree() works recursively */
+ CHILDREN_RECURSIVE = (1U << 1),
+ /* if set, add_subtree() scans object-manager hierarchies recursively */
+ CHILDREN_SUBHIERARCHIES = (1U << 0),
+};
+
static int add_subtree_to_set(
sd_bus *bus,
const char *prefix,
struct node *n,
+ unsigned int flags,
Set *s,
sd_bus_error *error) {
@@ -198,11 +212,14 @@ static int add_subtree_to_set(
if (r < 0 && r != -EEXIST)
return r;
- r = add_subtree_to_set(bus, prefix, i, s, error);
- if (r < 0)
- return r;
- if (bus->nodes_modified)
- return 0;
+ if ((flags & CHILDREN_RECURSIVE) &&
+ ((flags & CHILDREN_SUBHIERARCHIES) || !i->object_managers)) {
+ r = add_subtree_to_set(bus, prefix, i, flags, s, error);
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified)
+ return 0;
+ }
}
return 0;
@@ -212,6 +229,7 @@ static int get_child_nodes(
sd_bus *bus,
const char *prefix,
struct node *n,
+ unsigned int flags,
Set **_s,
sd_bus_error *error) {
@@ -227,7 +245,7 @@ static int get_child_nodes(
if (!s)
return -ENOMEM;
- r = add_subtree_to_set(bus, prefix, n, s, error);
+ r = add_subtree_to_set(bus, prefix, n, flags, s, error);
if (r < 0) {
set_free_free(s);
return r;
@@ -252,7 +270,7 @@ static int node_callbacks_run(
assert(found_object);
LIST_FOREACH(callbacks, c, first) {
- _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
sd_bus_slot *slot;
if (bus->nodes_modified)
@@ -319,7 +337,7 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c,
if (cap == 0)
cap = CAP_SYS_ADMIN;
else
- cap --;
+ cap--;
r = sd_bus_query_sender_privilege(m, cap);
if (r < 0)
@@ -337,7 +355,7 @@ static int method_callbacks_run(
bool require_fallback,
bool *found_object) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *signature;
void *u;
int r;
@@ -360,6 +378,8 @@ static int method_callbacks_run(
if (bus->nodes_modified)
return 0;
+ u = vtable_method_convert_userdata(c->vtable, u);
+
*found_object = true;
if (c->last_iteration == bus->iteration_counter)
@@ -558,8 +578,8 @@ static int property_get_set_callbacks_run(
bool is_get,
bool *found_object) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
sd_bus_slot *slot;
void *u = NULL;
int r;
@@ -738,6 +758,9 @@ static int vtable_append_all_properties(
if (v->flags & SD_BUS_VTABLE_HIDDEN)
continue;
+ if (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
+ continue;
+
r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
if (r < 0)
return r;
@@ -756,7 +779,7 @@ static int property_get_all_callbacks_run(
const char *iface,
bool *found_object) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
struct node_vtable *c;
bool found_interface;
int r;
@@ -779,7 +802,7 @@ static int property_get_all_callbacks_run(
streq(iface, "org.freedesktop.DBus.Introspectable");
LIST_FOREACH(vtables, c, first) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
void *u;
if (require_fallback && !c->is_fallback)
@@ -856,7 +879,7 @@ static int bus_node_exists(
}
LIST_FOREACH(vtables, c, n->vtables) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
if (require_fallback && !c->is_fallback)
continue;
@@ -878,8 +901,8 @@ static int process_introspect(
bool require_fallback,
bool *found_object) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_set_free_free_ Set *s = NULL;
const char *previous_interface = NULL;
struct introspect intro;
@@ -892,7 +915,7 @@ static int process_introspect(
assert(n);
assert(found_object);
- r = get_child_nodes(bus, m->path, n, &s, &error);
+ r = get_child_nodes(bus, m->path, n, 0, &s, &error);
if (r < 0)
return bus_maybe_reply_error(m, r, &error);
if (bus->nodes_modified)
@@ -1139,8 +1162,8 @@ static int process_get_managed_objects(
bool require_fallback,
bool *found_object) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_set_free_free_ Set *s = NULL;
Iterator i;
char *path;
@@ -1158,16 +1181,12 @@ static int process_get_managed_objects(
if (require_fallback || !n->object_managers)
return 0;
- r = get_child_nodes(bus, m->path, n, &s, &error);
+ r = get_child_nodes(bus, m->path, n, CHILDREN_RECURSIVE, &s, &error);
if (r < 0)
return r;
if (bus->nodes_modified)
return 0;
- r = set_put_strdup(s, m->path);
- if (r < 0)
- return r;
-
r = sd_bus_message_new_method_return(m, &reply);
if (r < 0)
return r;
@@ -1467,6 +1486,32 @@ 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) {
+ struct node *n;
+
+ assert(bus);
+ assert(path);
+
+ n = hashmap_get(bus->nodes, path);
+ if (!n) {
+ char *prefix;
+
+ prefix = alloca(strlen(path) + 1);
+ OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+ n = hashmap_get(bus->nodes, prefix);
+ if (n)
+ break;
+ }
+ }
+
+ while (n && !n->object_managers)
+ n = n->parent;
+
+ if (out)
+ *out = n;
+ return !!n;
+}
+
static int bus_add_object(
sd_bus *bus,
sd_bus_slot **slot,
@@ -1533,25 +1578,14 @@ _public_ int sd_bus_add_fallback(
return bus_add_object(bus, slot, true, prefix, callback, userdata);
}
-static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void vtable_member_hash_func(const void *a, struct siphash *state) {
const struct vtable_member *m = a;
- uint8_t hash_key2[HASH_KEY_SIZE];
- unsigned long ret;
assert(m);
- ret = string_hash_func(m->path, hash_key);
-
- /* Use a slightly different hash key for the interface */
- memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
- hash_key2[0]++;
- ret ^= string_hash_func(m->interface, hash_key2);
-
- /* And an even different one for the member */
- hash_key2[0]++;
- ret ^= string_hash_func(m->member, hash_key2);
-
- return ret;
+ string_hash_func(m->path, state);
+ string_hash_func(m->interface, state);
+ string_hash_func(m->member, state);
}
static int vtable_member_compare_func(const void *a, const void *b) {
@@ -1707,8 +1741,9 @@ static int add_object_vtable_internal(
if (!member_name_is_valid(v->x.property.member) ||
!signature_is_single(v->x.property.signature, false) ||
!(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
- v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
+ (v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ||
(!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
+ ((v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) && (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)) ||
(v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
r = -EINVAL;
goto fail;
@@ -1844,8 +1879,8 @@ static int emit_properties_changed_on_interface(
bool *found_interface,
char **names) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
bool has_invalidating = false, has_changing = false;
struct vtable_member key = {};
struct node_vtable *c;
@@ -2139,7 +2174,7 @@ static int object_added_append_all_prefix(
return 0;
LIST_FOREACH(vtables, c, n->vtables) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
void *u = NULL;
if (require_fallback && !c->is_fallback)
@@ -2268,7 +2303,8 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p
_public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
BUS_DONT_DESTROY(bus);
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ struct node *object_manager;
int r;
/*
@@ -2289,11 +2325,17 @@ _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);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
do {
bus->nodes_modified = false;
m = sd_bus_message_unref(m);
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
if (r < 0)
return r;
@@ -2345,7 +2387,7 @@ static int object_removed_append_all_prefix(
return 0;
LIST_FOREACH(vtables, c, n->vtables) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
void *u = NULL;
if (require_fallback && !c->is_fallback)
@@ -2431,7 +2473,8 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char
_public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
BUS_DONT_DESTROY(bus);
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ struct node *object_manager;
int r;
/*
@@ -2452,11 +2495,17 @@ _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);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
do {
bus->nodes_modified = false;
m = sd_bus_message_unref(m);
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
if (r < 0)
return r;
@@ -2492,7 +2541,7 @@ static int interfaces_added_append_one_prefix(
const char *interface,
bool require_fallback) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
bool found_interface = false;
struct node_vtable *c;
struct node *n;
@@ -2587,7 +2636,8 @@ static int interfaces_added_append_one(
_public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
BUS_DONT_DESTROY(bus);
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ struct node *object_manager;
char **i;
int r;
@@ -2601,11 +2651,17 @@ _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);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
do {
bus->nodes_modified = false;
m = sd_bus_message_unref(m);
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
if (r < 0)
return r;
@@ -2664,7 +2720,8 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c
}
_public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ struct node *object_manager;
int r;
assert_return(bus, -EINVAL);
@@ -2677,7 +2734,13 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path,
if (strv_isempty(interfaces))
return 0;
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
+ r = bus_find_parent_object_manager(bus, &object_manager, path);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
if (r < 0)
return r;