Merge pull request #15473 from keszybz/bus-introspection
This commit is contained in:
@@ -107,17 +107,8 @@ static const sd_bus_vtable log_control_vtable[] = {
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
int bus_log_control_api_register(sd_bus *bus) {
|
||||
int r;
|
||||
|
||||
r = sd_bus_add_object_vtable(
|
||||
bus,
|
||||
NULL,
|
||||
"/org/freedesktop/LogControl1",
|
||||
"org.freedesktop.LogControl1",
|
||||
log_control_vtable, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register service API object: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
const BusObjectImplementation log_control_object = {
|
||||
"/org/freedesktop/LogControl1",
|
||||
"org.freedesktop.LogControl1",
|
||||
.vtables = BUS_VTABLES(log_control_vtable),
|
||||
};
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
int bus_log_control_api_register(sd_bus *bus);
|
||||
#include "bus-util.h"
|
||||
|
||||
extern const BusObjectImplementation log_control_object;
|
||||
static inline int bus_log_control_api_register(sd_bus *bus) {
|
||||
return bus_add_implementation(bus, &log_control_object, NULL);
|
||||
}
|
||||
|
||||
int bus_property_get_log_level(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
|
||||
int bus_property_set_log_level(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error);
|
||||
|
||||
@@ -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"
|
||||
@@ -1549,3 +1550,171 @@ int bus_message_new_method_call(
|
||||
|
||||
return sd_bus_message_new_method_call(bus, m, locator->destination, locator->path, locator->interface, member);
|
||||
}
|
||||
|
||||
int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata) {
|
||||
int r;
|
||||
|
||||
log_debug("Registering bus object implementation for path=%s iface=%s", impl->path, impl->interface);
|
||||
|
||||
for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
|
||||
r = sd_bus_add_object_vtable(bus, NULL,
|
||||
impl->path,
|
||||
impl->interface,
|
||||
*p,
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
|
||||
impl->path,
|
||||
impl->interface);
|
||||
}
|
||||
|
||||
for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
|
||||
r = sd_bus_add_fallback_vtable(bus, NULL,
|
||||
impl->path,
|
||||
impl->interface,
|
||||
p->vtable,
|
||||
p->object_find,
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
|
||||
impl->path,
|
||||
impl->interface);
|
||||
}
|
||||
|
||||
if (impl->node_enumerator) {
|
||||
r = sd_bus_add_node_enumerator(bus, NULL,
|
||||
impl->path,
|
||||
impl->node_enumerator,
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add node enumerator for %s: %m",
|
||||
impl->path);
|
||||
}
|
||||
|
||||
for (size_t i = 0; impl->children && impl->children[i]; i++) {
|
||||
r = bus_add_implementation(bus, impl->children[i], userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void list_paths(
|
||||
FILE *out,
|
||||
const BusObjectImplementation* const* bus_objects) {
|
||||
|
||||
for (size_t i = 0; bus_objects[i]; i++) {
|
||||
fprintf(out, "%s\t%s\n", bus_objects[i]->path, bus_objects[i]->interface);
|
||||
if (bus_objects[i]->children)
|
||||
list_paths(out, bus_objects[i]->children);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (streq(pattern, "list")) {
|
||||
list_paths(out, bus_objects);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+30
-3
@@ -23,11 +23,32 @@ typedef enum BusTransport {
|
||||
} BusTransport;
|
||||
|
||||
typedef struct BusLocator {
|
||||
const char *destination;
|
||||
const char *path;
|
||||
const char *interface;
|
||||
const char *destination;
|
||||
const char *path;
|
||||
const char *interface;
|
||||
} BusLocator;
|
||||
|
||||
typedef struct BusObjectImplementation BusObjectImplementation;
|
||||
|
||||
typedef struct BusObjectVtablePair {
|
||||
const sd_bus_vtable *vtable;
|
||||
sd_bus_object_find_t object_find;
|
||||
} BusObjectVtablePair;
|
||||
|
||||
struct BusObjectImplementation {
|
||||
const char *path;
|
||||
const char *interface;
|
||||
const sd_bus_vtable **vtables;
|
||||
const BusObjectVtablePair *fallback_vtables;
|
||||
sd_bus_node_enumerator_t node_enumerator;
|
||||
bool manager;
|
||||
const BusObjectImplementation **children;
|
||||
};
|
||||
|
||||
#define BUS_VTABLES(...) ((const sd_bus_vtable* []){ __VA_ARGS__, NULL })
|
||||
#define BUS_FALLBACK_VTABLES(...) ((const BusObjectVtablePair[]) { __VA_ARGS__, {} })
|
||||
#define BUS_IMPLEMENTATIONS(...) ((const BusObjectImplementation* []) { __VA_ARGS__, NULL })
|
||||
|
||||
typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
|
||||
|
||||
struct bus_properties_map {
|
||||
@@ -199,3 +220,9 @@ int bus_set_property(sd_bus *bus, const BusLocator *locator, const char *member,
|
||||
int bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const BusLocator *locator, const char *member, sd_bus_message_handler_t callback, void *userdata);
|
||||
int bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const BusLocator *locator, const char *member, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata);
|
||||
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);
|
||||
|
||||
@@ -184,6 +184,8 @@ shared_sources = files('''
|
||||
securebits-util.h
|
||||
serialize.c
|
||||
serialize.h
|
||||
service-util.c
|
||||
service-util.h
|
||||
sleep-config.c
|
||||
sleep-config.h
|
||||
socket-netlink.c
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "service-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static int help(const char *program_path, const char *service, const char *description, bool bus_introspect) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
||||
r = terminal_urlify_man(service, "8", &link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"%s%s%s\n\n"
|
||||
"This program takes no positional arguments.\n\n"
|
||||
"%sOptions%s:\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --bus-introspect=PATH Write D-Bus XML introspection data\n"
|
||||
"\nSee the %s for details.\n"
|
||||
, program_path
|
||||
, ansi_highlight(), description, ansi_normal()
|
||||
, ansi_underline(), ansi_normal()
|
||||
, link
|
||||
);
|
||||
|
||||
return 0; /* No further action */
|
||||
}
|
||||
|
||||
int service_parse_argv(
|
||||
const char *service,
|
||||
const char *description,
|
||||
const BusObjectImplementation* const* bus_objects,
|
||||
int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_BUS_INTROSPECT,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
switch(c) {
|
||||
|
||||
case 'h':
|
||||
return help(argv[0], service, description, bus_objects);
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_BUS_INTROSPECT:
|
||||
return bus_introspect_implementations(
|
||||
stdout,
|
||||
optarg,
|
||||
bus_objects);
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unknown option code.");
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"This program takes no arguments.");
|
||||
|
||||
return 1; /* Further action */
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "bus-util.h"
|
||||
|
||||
int service_parse_argv(
|
||||
const char *service,
|
||||
const char *description,
|
||||
const BusObjectImplementation* const* bus_objects,
|
||||
int argc, char *argv[]);
|
||||
Reference in New Issue
Block a user