chiark / gitweb /
bus: use assert_return() for more API calls
[elogind.git] / src / libsystemd-bus / bus-objects.c
index 8302092f92e67fc783f3339c490e962cb06e8a55..cd56d13d6bf4575d37e2944f17eb567bc8285b09 100644 (file)
@@ -499,7 +499,7 @@ static int vtable_append_all_properties(
                 if (r < 0)
                         return r;
 
-                r = sd_bus_message_append(reply, "s", c->interface);
+                r = sd_bus_message_append(reply, "s", v->x.property.member);
                 if (r < 0)
                         return r;
 
@@ -742,9 +742,9 @@ static int object_manager_serialize_vtable(
                 sd_bus_message *reply,
                 const char *path,
                 struct node_vtable *c,
-                sd_bus_error *error) {
+                sd_bus_error *error,
+                void *userdata) {
 
-        void *u;
         int r;
 
         assert(bus);
@@ -753,10 +753,6 @@ static int object_manager_serialize_vtable(
         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;
@@ -769,7 +765,7 @@ static int object_manager_serialize_vtable(
         if (r < 0)
                 return r;
 
-        r = vtable_append_all_properties(bus, reply, path, c, u, error);
+        r = vtable_append_all_properties(bus, reply, path, c, userdata, error);
         if (r < 0)
                 return r;
 
@@ -794,6 +790,7 @@ static int object_manager_serialize_path(
 
         struct node_vtable *i;
         struct node *n;
+        bool found_something = false;
         int r;
 
         assert(bus);
@@ -806,37 +803,50 @@ static int object_manager_serialize_path(
         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) {
+                void *u;
 
                 if (require_fallback && !i->is_fallback)
                         continue;
 
-                r = object_manager_serialize_vtable(bus, reply, path, i, error);
+                r = node_vtable_get_userdata(bus, path, i, &u);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        continue;
+
+                if (!found_something) {
+                        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;
+
+                        found_something = true;
+                }
+
+                r = object_manager_serialize_vtable(bus, reply, path, i, error, u);
                 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;
+        if (found_something) {
+                r = sd_bus_message_close_container(reply);
+                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 1;
 }
@@ -847,7 +857,7 @@ static int object_manager_serialize_path_and_fallbacks(
                 const char *path,
                 sd_bus_error *error) {
 
-        size_t pl;
+        char *prefix;
         int r;
 
         assert(bus);
@@ -863,27 +873,14 @@ static int object_manager_serialize_path_and_fallbacks(
                 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;
+        prefix = alloca(strlen(path) + 1);
+        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
+                if (r < 0)
+                        return r;
 
-                        if (sd_bus_error_is_set(error))
-                                return 0;
-                }
+                if (sd_bus_error_is_set(error))
+                        return 0;
         }
 
         return 0;
@@ -1105,7 +1102,7 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) {
 
         pl = strlen(m->path);
         do {
-                char p[pl+1];
+                char prefix[pl+1];
 
                 bus->nodes_modified = false;
 
@@ -1114,24 +1111,12 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) {
                         return r;
 
                 /* Look for fallback prefixes */
-                strcpy(p, m->path);
-                for (;;) {
-                        char *e;
-
-                        if (streq(p, "/"))
-                                break;
+                OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
 
                         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);
+                        r = object_find_and_run(bus, m, prefix, true, &found_object);
                         if (r != 0)
                                 return r;
                 }
@@ -1211,7 +1196,7 @@ static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
         }
 
         if (parent)
-                LIST_PREPEND(struct node, siblings, parent->child, n);
+                LIST_PREPEND(siblings, parent->child, n);
 
         return n;
 }
@@ -1232,7 +1217,7 @@ static void bus_node_gc(sd_bus *b, struct node *n) {
         assert(hashmap_remove(b->nodes, n->path) == n);
 
         if (n->parent)
-                LIST_REMOVE(struct node, siblings, n->parent->child, n);
+                LIST_REMOVE(siblings, n->parent->child, n);
 
         free(n->path);
         bus_node_gc(b, n->parent);
@@ -1270,7 +1255,7 @@ static int bus_add_object(
         c->userdata = userdata;
         c->is_fallback = fallback;
 
-        LIST_PREPEND(struct node_callback, callbacks, n->callbacks, c);
+        LIST_PREPEND(callbacks, n->callbacks, c);
         return 0;
 
 fail:
@@ -1304,7 +1289,7 @@ static int bus_remove_object(
         if (!c)
                 return 0;
 
-        LIST_REMOVE(struct node_callback, callbacks, n->callbacks, c);
+        LIST_REMOVE(callbacks, n->callbacks, c);
         free(c);
 
         bus_node_gc(bus, n);
@@ -1561,7 +1546,7 @@ static int add_object_vtable_internal(
                 }
         }
 
-        LIST_PREPEND(struct node_vtable, vtables, n->vtables, c);
+        LIST_PREPEND(vtables, n->vtables, c);
         return 0;
 
 fail:
@@ -1597,7 +1582,7 @@ static int remove_object_vtable_internal(
         if (!c)
                 return 0;
 
-        LIST_REMOVE(struct node_vtable, vtables, n->vtables, c);
+        LIST_REMOVE(vtables, n->vtables, c);
 
         free_node_vtable(bus, c);
         bus_node_gc(bus, n);
@@ -1671,7 +1656,7 @@ int sd_bus_add_node_enumerator(
         c->callback = callback;
         c->userdata = userdata;
 
-        LIST_PREPEND(struct node_enumerator, enumerators, n->enumerators, c);
+        LIST_PREPEND(enumerators, n->enumerators, c);
         return 0;
 
 fail:
@@ -1705,7 +1690,7 @@ int sd_bus_remove_node_enumerator(
         if (!c)
                 return 0;
 
-        LIST_REMOVE(struct node_enumerator, enumerators, n->enumerators, c);
+        LIST_REMOVE(enumerators, n->enumerators, c);
         free(c);
 
         bus_node_gc(bus, n);
@@ -1858,7 +1843,7 @@ int sd_bus_emit_properties_changed_strv(
                 const char *interface,
                 char **names) {
 
-        size_t pl;
+        char *prefix;
         int r;
 
         assert_return(bus, -EINVAL);
@@ -1874,28 +1859,11 @@ int sd_bus_emit_properties_changed_strv(
         if (r != 0)
                 return r;
 
-        pl = strlen(path);
-        if (pl > 1 ) {
-                char p[pl+1];
-
-                strcpy(p, path);
-                for (;;) {
-                        char *e;
-
-                        if (streq(p, "/"))
-                                break;
-
-                        e = strrchr(p, '/');
-                        assert(e);
-                        if (e == p)
-                                *(e+1) = 0;
-                        else
-                                *e = 0;
-
-                        r = emit_properties_changed_on_interface(bus, p, path, interface, true, names);
-                        if (r != 0)
-                                return r;
-                }
+        prefix = alloca(strlen(path) + 1);
+        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, names);
+                if (r != 0)
+                        return r;
         }
 
         return -ENOENT;
@@ -1929,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;
+}
+
+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 *interfaces, ...) {
-        return -ENOSYS;
+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) {