]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bus-util: add wrapper for interface introspection
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 15 Apr 2020 15:19:53 +0000 (17:19 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 5 May 2020 20:33:53 +0000 (22:33 +0200)
src/shared/bus-util.c
src/shared/bus-util.h

index 30d62d5fc7780cb94435b07ab90c7839607a1e30..4214aa340ea2cc979c48e36dd33c2743e1f7beb5 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "alloc-util.h"
 #include "bus-internal.h"
+#include "bus-introspect.h"
 #include "bus-label.h"
 #include "bus-message.h"
 #include "bus-util.h"
@@ -1598,3 +1599,106 @@ int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, voi
 
         return 0;
 }
+
+static const BusObjectImplementation* find_implementation(
+                const char *pattern,
+                const BusObjectImplementation* const* bus_objects) {
+
+        for (size_t i = 0; bus_objects && bus_objects[i]; i++) {
+                const BusObjectImplementation *impl = bus_objects[i];
+
+                if (STR_IN_SET(pattern, impl->path, impl->interface))
+                        return impl;
+
+                impl = find_implementation(pattern, impl->children);
+                if (impl)
+                        return impl;
+        }
+
+        return NULL;
+}
+
+static int bus_introspect_implementation(
+                struct introspect *intro,
+                const BusObjectImplementation *impl) {
+        int r;
+
+        for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
+                r = introspect_write_interface(intro, impl->interface, *p);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to write introspection data: %m");
+        }
+
+        for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
+                r = introspect_write_interface(intro, impl->interface, p->vtable);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to write introspection data: %m");
+        }
+
+        return 0;
+}
+
+int bus_introspect_implementations(
+                FILE *out,
+                const char *pattern,
+                const BusObjectImplementation* const* bus_objects) {
+
+        const BusObjectImplementation *impl, *main_impl = NULL;
+        _cleanup_free_ char *s = NULL;
+        int r;
+
+        struct introspect intro = {};
+        bool is_interface = interface_name_is_valid(pattern);
+
+        impl = find_implementation(pattern, bus_objects);
+        if (!impl)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "%s %s not found",
+                                       is_interface ? "Interface" : "Object path",
+                                       pattern);
+
+        /* We use trusted=false here to get all the @org.freedesktop.systemd1.Privileged annotations. */
+        r = introspect_begin(&intro, false);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write introspection data: %m");
+
+        r = introspect_write_default_interfaces(&intro, impl->manager);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write introspection data: %m");
+
+        /* Check if there is a non-fallback path that applies to the given interface, also
+         * print it. This is useful in the case of units: o.fd.systemd1.Service is declared
+         * as a fallback vtable for o/fd/systemd1/unit, and we also want to print
+         * o.fd.systemd1.Unit, which is the non-fallback implementation. */
+        if (impl->fallback_vtables && is_interface)
+                main_impl = find_implementation(impl->path, bus_objects);
+
+        if (main_impl)
+                bus_introspect_implementation(&intro, main_impl);
+
+        if (impl != main_impl)
+                bus_introspect_implementation(&intro, impl);
+
+        _cleanup_set_free_free_ Set *nodes = NULL;
+
+        for (size_t i = 0; impl->children && impl->children[i]; i++) {
+                r = set_ensure_allocated(&nodes, &string_hash_ops);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_put_strdup(nodes, impl->children[i]->path);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        r = introspect_write_child_nodes(&intro, nodes, impl->path);
+        if (r < 0)
+                return r;
+
+        r = introspect_finish(&intro, &s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write introspection data: %m");
+
+        fputs(s, out);
+        return 0;
+}
index a985523cd01711fb550496d23e69b07cde3b14e7..7678680daec674332bd7344a06cdd5b5bdb161f0 100644 (file)
@@ -222,3 +222,7 @@ int bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const BusLocator *loc
 int bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const BusLocator *locator, const char *member);
 
 int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata);
+int bus_introspect_implementations(
+                FILE *out,
+                const char *pattern,
+                const BusObjectImplementation* const* bus_objects);