- r = sd_bus_send(bus, reply, NULL);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int vtable_append_all_properties(
- sd_bus *bus,
- sd_bus_message *reply,
- const char *path,
- struct node_vtable *c,
- void *userdata,
- sd_bus_error *error) {
-
- const sd_bus_vtable *v;
- int r;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
- if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
- continue;
-
- r = sd_bus_message_open_container(reply, 'e', "sv");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "s", c->interface);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'v', v->property.signature);
- if (r < 0)
- return r;
-
- r = invoke_property_get(bus, v, path, c->interface, v->property.member, reply, error, vtable_property_convert_userdata(v, userdata));
- if (r < 0)
- return r;
-
- if (sd_bus_error_is_set(error))
- return 0;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
- }
-
- return 1;
-}
-
-static int property_get_all_callbacks_run(
- sd_bus *bus,
- sd_bus_message *m,
- struct node_vtable *first,
- bool require_fallback,
- const char *iface,
- bool *found_object) {
-
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- struct node_vtable *c;
- bool found_interface = false;
- int r;
-
- assert(bus);
- assert(m);
- assert(found_object);
-
- r = sd_bus_message_new_method_return(bus, m, &reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "{sv}");
- if (r < 0)
- return r;
-
- LIST_FOREACH(vtables, c, first) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- void *u;
-
- if (require_fallback && !c->is_fallback)
- continue;
-
- r = node_vtable_get_userdata(bus, m->path, c, &u);
- if (r < 0)
- return r;
- if (r == 0)
- continue;
-
- *found_object = true;
-
- if (iface && !streq(c->interface, iface))
- continue;
- found_interface = true;
-
- c->last_iteration = bus->iteration_counter;
-
- r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
- if (r < 0)
- return r;
-
- if (sd_bus_error_is_set(&error)) {
- r = sd_bus_reply_method_error(bus, m, &error);
- if (r < 0)
- return r;
-
- return 1;
- }
- }
-
- if (!found_interface) {
- r = sd_bus_reply_method_errorf(
- bus, m,
- "org.freedesktop.DBus.Error.UnknownInterface",
- "Unknown interface '%s'.", iface);
- if (r < 0)
- return r;
-
- return 1;
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- r = sd_bus_send(bus, reply, NULL);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
- assert(bus);
-
- if (n->object_manager)
- return true;
-
- if (n->parent)
- return bus_node_with_object_manager(bus, n->parent);
-
- return false;
-}
-
-static bool bus_node_exists(sd_bus *bus, struct node *n, const char *path, bool require_fallback) {
- struct node_vtable *c;
- struct node_callback *k;
-
- assert(bus);
- assert(n);
-
- /* Tests if there's anything attached directly to this node
- * for the specified path */
-
- LIST_FOREACH(callbacks, k, n->callbacks) {
- if (require_fallback && !k->is_fallback)
- continue;
-
- return true;
- }
-
- LIST_FOREACH(vtables, c, n->vtables) {
-
- if (require_fallback && !c->is_fallback)
- continue;
-
- if (node_vtable_get_userdata(bus, path, c, NULL) > 0)
- return true;
- }
-
- return !require_fallback && (n->enumerators || n->object_manager);
-}
-
-static int process_introspect(
- sd_bus *bus,
- sd_bus_message *m,
- struct node *n,
- bool require_fallback,
- bool *found_object) {
-
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_set_free_free_ Set *s = NULL;
- struct introspect intro;
- struct node_vtable *c;
- bool empty;
- int r;
-
- assert(bus);
- assert(m);
- assert(n);
- assert(found_object);
-
- r = get_child_nodes(bus, m->path, n, &s);
- if (r < 0)
- return r;
-
- r = introspect_begin(&intro);
- if (r < 0)
- return r;
-
- r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
- if (r < 0)
- return r;
-
- empty = set_isempty(s);
-
- LIST_FOREACH(vtables, c, n->vtables) {
- if (require_fallback && !c->is_fallback)
- continue;
-
- r = node_vtable_get_userdata(bus, m->path, c, NULL);
- if (r < 0)
- return r;
- if (r == 0)
- continue;
-
- empty = false;
-
- r = introspect_write_interface(&intro, c->interface, c->vtable);
- if (r < 0)
- goto finish;
- }
-
- if (empty) {
- /* Nothing?, let's see if we exist at all, and if not
- * refuse to do anything */
- r = bus_node_exists(bus, n, m->path, require_fallback);
- if (r < 0)
- return r;
-
- if (r == 0)
- goto finish;
- }
-
- *found_object = true;
-
- r = introspect_write_child_nodes(&intro, s, m->path);
- if (r < 0)
- goto finish;
-
- r = introspect_finish(&intro, bus, m, &reply);
- if (r < 0)
- goto finish;
-
- r = sd_bus_send(bus, reply, NULL);
- if (r < 0)
- goto finish;
-
- r = 1;
-
-finish:
- introspect_free(&intro);
- return r;
-}
-
-static int object_manager_serialize_vtable(
- sd_bus *bus,
- sd_bus_message *reply,
- const char *path,
- struct node_vtable *c,
- sd_bus_error *error) {
-
- void *u;
- int r;
-
- assert(bus);
- assert(reply);
- assert(path);
- assert(c);
- assert(error);
-
- r = node_vtable_get_userdata(bus, path, c, &u);
- if (r <= 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "s", c->interface);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "{sv}");
- if (r < 0)
- return r;
-
- r = vtable_append_all_properties(bus, reply, path, c, u, error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int object_manager_serialize_path(
- sd_bus *bus,
- sd_bus_message *reply,
- const char *prefix,
- const char *path,
- bool require_fallback,
- sd_bus_error *error) {
-
- struct node_vtable *i;
- struct node *n;
- int r;
-
- assert(bus);
- assert(reply);
- assert(prefix);
- assert(path);
- assert(error);
-
- n = hashmap_get(bus->nodes, prefix);
- if (!n)
- return 0;
-
- r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "o", path);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
- if (r < 0)
- return r;
-
- LIST_FOREACH(vtables, i, n->vtables) {
-
- if (require_fallback && !i->is_fallback)
- continue;
-
- r = object_manager_serialize_vtable(bus, reply, path, i, error);
- if (r < 0)
- return r;
- if (sd_bus_error_is_set(error))
- return 0;
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int object_manager_serialize_path_and_fallbacks(
- sd_bus *bus,
- sd_bus_message *reply,
- const char *path,
- sd_bus_error *error) {
-
- size_t pl;
- int r;
-
- assert(bus);
- assert(reply);
- assert(path);
- assert(error);
-
- /* First, add all vtables registered for this path */
- r = object_manager_serialize_path(bus, reply, path, path, false, error);
- if (r < 0)
- return r;
- if (sd_bus_error_is_set(error))
- return 0;
-
- /* Second, add fallback vtables registered for any of the prefixes */
- pl = strlen(path);
- if (pl > 1) {
- char p[pl + 1];
- strcpy(p, path);
-
- for (;;) {
- char *e;
-
- e = strrchr(p, '/');
- if (e == p || !e)
- break;
-
- *e = 0;
-
- r = object_manager_serialize_path(bus, reply, p, path, true, error);
- if (r < 0)
- return r;
-
- if (sd_bus_error_is_set(error))
- return 0;
- }
- }
-
- return 0;
-}
-
-static int process_get_managed_objects(
- sd_bus *bus,
- sd_bus_message *m,
- struct node *n,
- bool require_fallback,
- bool *found_object) {
-
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_set_free_free_ Set *s = NULL;
- bool empty;
- int r;
-
- assert(bus);
- assert(m);
- assert(n);
- assert(found_object);
-
- if (!bus_node_with_object_manager(bus, n))
- return 0;
-
- r = get_child_nodes(bus, m->path, n, &s);
- if (r < 0)
- return r;
-
- r = sd_bus_message_new_method_return(bus, m, &reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
- if (r < 0)
- return r;
-
- empty = set_isempty(s);
- if (empty) {
- struct node_vtable *c;
-
- /* Hmm, so we have no children? Then let's check
- * whether we exist at all, i.e. whether at least one
- * vtable exists. */
-
- LIST_FOREACH(vtables, c, n->vtables) {
-
- if (require_fallback && !c->is_fallback)
- continue;
-
- if (r < 0)
- return r;
- if (r == 0)
- continue;
-
- empty = false;
- break;
- }
-
- if (empty)
- return 0;
- } else {
- Iterator i;
- char *path;
-
- SET_FOREACH(path, s, i) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
- r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
- if (r < 0)
- return -ENOMEM;
-
- if (sd_bus_error_is_set(&error)) {
- r = sd_bus_reply_method_error(bus, m, &error);
- if (r < 0)
- return r;
-
- return 1;
- }
- }
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- r = sd_bus_send(bus, reply, NULL);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int object_find_and_run(
- sd_bus *bus,
- sd_bus_message *m,
- const char *p,
- bool require_fallback,
- bool *found_object) {
-
- struct node *n;
- struct vtable_member vtable_key, *v;
- int r;
-
- assert(bus);
- assert(m);
- assert(p);
- assert(found_object);
-
- n = hashmap_get(bus->nodes, p);
- if (!n)
- return 0;
-
- /* First, try object callbacks */
- r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
- if (r != 0)
- return r;
-
- if (!m->interface || !m->member)
- return 0;
-
- /* Then, look for a known method */
- vtable_key.path = (char*) p;
- vtable_key.interface = m->interface;
- vtable_key.member = m->member;
-
- v = hashmap_get(bus->vtable_methods, &vtable_key);
- if (v) {
- r = method_callbacks_run(bus, m, v, require_fallback, found_object);
- if (r != 0)
- return r;
- }
-
- /* Then, look for a known property */
- if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
- bool get = false;
-
- get = streq(m->member, "Get");
-
- if (get || streq(m->member, "Set")) {
-
- r = sd_bus_message_rewind(m, true);
- if (r < 0)
- return r;
-
- vtable_key.path = (char*) p;
-
- r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
- if (r < 0)
- return r;
-
- v = hashmap_get(bus->vtable_properties, &vtable_key);
- if (v) {
- r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
- if (r != 0)
- return r;
- }
-
- } else if (streq(m->member, "GetAll")) {
- const char *iface;
-
- r = sd_bus_message_rewind(m, true);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(m, "s", &iface);
- if (r < 0)
- return r;
-
- if (iface[0] == 0)
- iface = NULL;
-
- r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
- if (r != 0)
- return r;
- }
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-
- r = process_introspect(bus, m, n, require_fallback, found_object);
- if (r != 0)
- return r;
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
-
- r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
- if (r != 0)
- return r;
- }
-
- if (!*found_object) {
- r = bus_node_exists(bus, n, m->path, require_fallback);
- if (r < 0)
- return r;
-
- if (r > 0)
- *found_object = true;
- }
-
- return 0;
-}
-
-static int process_object(sd_bus *bus, sd_bus_message *m) {
- int r;
- size_t pl;
- bool found_object = false;
-
- assert(bus);
- assert(m);
-
- if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
- return 0;
-
- if (!m->path)
- return 0;
-
- if (hashmap_isempty(bus->nodes))
- return 0;
-
- pl = strlen(m->path);
- do {
- char p[pl+1];
-
- bus->nodes_modified = false;
-
- r = object_find_and_run(bus, m, m->path, false, &found_object);
- if (r != 0)
- return r;
-
- /* Look for fallback prefixes */
- strcpy(p, m->path);
- for (;;) {
- char *e;
-
- if (streq(p, "/"))
- break;
-
- if (bus->nodes_modified)
- break;
-
- e = strrchr(p, '/');
- assert(e);
- if (e == p)
- *(e+1) = 0;
- else
- *e = 0;
-
- r = object_find_and_run(bus, m, p, true, &found_object);
- if (r != 0)
- return r;
- }
-
- } while (bus->nodes_modified);
-
- if (!found_object)
- return 0;
-
- if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
- sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
- r = sd_bus_reply_method_errorf(
- bus, m,
- "org.freedesktop.DBus.Error.UnknownProperty",
- "Unknown property or interface.");
- else
- r = sd_bus_reply_method_errorf(
- bus, m,
- "org.freedesktop.DBus.Error.UnknownMethod",
- "Unknown method '%s' or interface '%s'.", m->member, m->interface);
-
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int process_message(sd_bus *bus, sd_bus_message *m) {
- int r;
-
- assert(bus);
- assert(m);
-
- bus->iteration_counter++;
-
- r = process_hello(bus, m);
- if (r != 0)
- return r;
-
- r = process_reply(bus, m);
- if (r != 0)
- return r;
-
- r = process_filter(bus, m);
- if (r != 0)
- return r;
-
- r = process_match(bus, m);
- if (r != 0)
- return r;
-
- r = process_builtin(bus, m);
- if (r != 0)
- return r;
-
- return process_object(bus, m);
-}
-
-static int process_running(sd_bus *bus, sd_bus_message **ret) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- int r;
-
- assert(bus);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
- r = process_timeout(bus);
- if (r != 0)
- goto null_message;
-
- r = dispatch_wqueue(bus);
- if (r != 0)
- goto null_message;
-
- r = dispatch_rqueue(bus, &m);
- if (r < 0)
- return r;
- if (!m)
- goto null_message;
-
- r = process_message(bus, m);
- if (r != 0)
- goto null_message;
-
- if (ret) {
- r = sd_bus_message_rewind(m, true);
- if (r < 0)
- return r;
-
- *ret = m;
- m = NULL;
- return 1;
- }
-
- if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
-
- r = sd_bus_reply_method_errorf(
- bus, m,
- "org.freedesktop.DBus.Error.UnknownObject",
- "Unknown object '%s'.", m->path);
- if (r < 0)
- return r;
- }