bus-util: add wrapper for interface introspection

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2020-05-05 22:33:53 +02:00
parent c2b178d3ca
commit 1e9bc92dba
2 changed files with 108 additions and 0 deletions
+104
View 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;
}
+4
View 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);