diff --git a/man/busctl.xml b/man/busctl.xml
index e4c7fcb283..328c101622 100644
--- a/man/busctl.xml
+++ b/man/busctl.xml
@@ -140,6 +140,16 @@
+
+
+
+
+ When used with the introspect call, dump the XML description received from
+ the D-Bus org.freedesktop.DBus.Introspectable.Introspect call instead of the
+ normal output.
+
+
+
MODE
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 9674cbb30b..6894158466 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -115,6 +115,21 @@ manpages = [
'sd_bus_match_signal',
'sd_bus_match_signal_async'],
''],
+ ['sd_bus_add_object_vtable',
+ '3',
+ ['SD_BUS_METHOD',
+ 'SD_BUS_METHOD_WITH_NAMES',
+ 'SD_BUS_METHOD_WITH_NAMES_OFFSET',
+ 'SD_BUS_METHOD_WITH_OFFSET',
+ 'SD_BUS_PARAM',
+ 'SD_BUS_PROPERTY',
+ 'SD_BUS_SIGNAL',
+ 'SD_BUS_SIGNAL_WITH_NAMES',
+ 'SD_BUS_VTABLE_END',
+ 'SD_BUS_VTABLE_START',
+ 'SD_BUS_WRITABLE_PROPERTY',
+ 'sd_bus_add_fallback_vtable'],
+ ''],
['sd_bus_attach_event', '3', ['sd_bus_detach_event', 'sd_bus_get_event'], ''],
['sd_bus_close', '3', ['sd_bus_flush'], ''],
['sd_bus_creds_get_pid',
diff --git a/man/sd-bus.xml b/man/sd-bus.xml
index 6c925e3161..e9a66d87dd 100644
--- a/man/sd-bus.xml
+++ b/man/sd-bus.xml
@@ -41,6 +41,7 @@
See
sd_bus_add_match3,
+sd_bus_add_object_vtable3,
sd_bus_attach_event3,
sd_bus_creds_get_pid3,
sd_bus_creds_new_from_pid3,
diff --git a/man/sd_bus_add_object_vtable.xml b/man/sd_bus_add_object_vtable.xml
new file mode 100644
index 0000000000..92be236afd
--- /dev/null
+++ b/man/sd_bus_add_object_vtable.xml
@@ -0,0 +1,473 @@
+
+
+
+
+
+
+
+ sd_bus_add_object_vtable
+ systemd
+
+
+
+ sd_bus_add_object_vtable
+ 3
+
+
+
+ sd_bus_add_object_vtable
+ sd_bus_add_fallback_vtable
+ SD_BUS_VTABLE_START
+ SD_BUS_VTABLE_END
+ SD_BUS_METHOD_WITH_NAMES_OFFSET
+ SD_BUS_METHOD_WITH_NAMES
+ SD_BUS_METHOD_WITH_OFFSET
+ SD_BUS_METHOD
+ SD_BUS_SIGNAL_WITH_NAMES
+ SD_BUS_SIGNAL
+ SD_BUS_WRITABLE_PROPERTY
+ SD_BUS_PROPERTY
+ SD_BUS_PARAM
+
+ Declare properties and methods for a D-Bus path
+
+
+
+
+ #include <systemd/sd-bus-vtable.h>
+
+
+ typedef int (*sd_bus_message_handler_t)
+ sd_bus_message *m
+ void *userdata
+ sd_bus_error *ret_error
+
+
+
+ typedef int (*sd_bus_property_get_t)
+ sd_bus *bus
+ const char *path
+ const char *interface
+ const char *property
+ sd_bus_message *reply
+ void *userdata
+ sd_bus_error *ret_error
+
+
+
+ typedef int (*sd_bus_property_set_t)
+ sd_bus *bus
+ const char *path
+ const char *interface
+ const char *property
+ sd_bus_message *value
+ void *userdata
+ sd_bus_error *ret_error
+
+
+
+ typedef int (*sd_bus_object_find_t)
+ const char *path
+ const char *interface
+ void *userdata
+ void **ret_found
+ sd_bus_error *ret_error
+
+
+
+ int sd_bus_add_object_vtable
+ sd_bus *bus
+ sd_bus_slot **slot
+ const char *path
+ const char *interface
+ const sd_bus_vtable *vtable
+ void *userdata
+
+
+
+ int sd_bus_add_fallback_vtable
+ sd_bus *bus
+ sd_bus_slot **slot
+ const char *prefix
+ const char *interface
+ const sd_bus_vtable *vtable
+ sd_bus_object_find_t find
+ void *userdata
+
+
+
+ SD_BUS_VTABLE_START(flags)
+
+
+ SD_BUS_VTABLE_END
+
+
+ SD_BUS_METHOD_WITH_NAMES_OFFSET(
+ member,
+ signature,
+ in_names,
+ result,
+ out_names,
+ handler,
+ offset,
+ flags)
+
+
+
+ SD_BUS_METHOD_WITH_NAMES(
+ member,
+ signature,
+ in_names,
+ result,
+ out_names,
+ handler,
+ flags)
+
+
+
+ SD_BUS_METHOD_WITH_OFFSET(
+ member,
+ signature,
+ result,
+ handler,
+ offset,
+ flags)
+
+
+
+ SD_BUS_METHOD(
+ member,
+ signature,
+ result,
+ handler,
+ flags)
+
+
+
+ SD_BUS_SIGNAL_WITH_NAMES(
+ member,
+ signature,
+ names,
+ flags)
+
+
+
+ SD_BUS_SIGNAL(
+ member,
+ signature,
+ flags)
+
+
+
+ SD_BUS_WRITABLE_PROPERTY(
+ member,
+ signature,
+ get,
+ set,
+ offset,
+ flags)
+
+
+
+ SD_BUS_PROPERTY(
+ member,
+ signature,
+ get,
+ offset,
+ flags)
+
+
+
+ SD_BUS_PARAM(name)
+
+
+
+
+
+ Description
+
+ sd_bus_add_object_vtable() is used to declare attributes for the path object
+ path path connected to the bus connection bus under the
+ interface interface. The table vtable may contain property
+ declarations using SD_BUS_PROPERTY() or
+ SD_BUS_WRITABLE_PROPERTY(), method declarations using
+ SD_BUS_METHOD(), SD_BUS_METHOD_WITH_NAMES(),
+ SD_BUS_METHOD_WITH_OFFSET(), or
+ SD_BUS_METHOD_WITH_NAMES_OFFSET(), and signal declarations using
+ SD_BUS_SIGNAL_WITH_NAMES() or SD_BUS_SIGNAL(), see below. The
+ userdata parameter contains a pointer that will be passed to various callback
+ functions. It may be specified as NULL if no value is necessary.
+
+ sd_bus_add_object_vtable() is similar to
+ sd_bus_add_object_vtable(), but is used to register "fallback" attributes. When
+ looking for an attribute declaration, bus object paths registered with
+ sd_bus_add_object_vtable() are checked first. If no match is found, the fallback
+ vtables are checked for each prefix of the bus object path, i.e. with the last slash-separated components
+ successively removed. This allows the vtable to be used for an arbitrary number of dynamically created
+ objects.
+
+ Parameter find is a function which is used to locate the target object
+ based on the bus object path path. It must return 1 and
+ set the ret_found output parameter if the object is found, return
+ 0 if the object was not found, and return a negative errno-style error code or
+ initialize the error structure ret_error on error. The pointer passed in
+ ret_found will be used as the userdata parameter for the
+ callback functions (offset by the offset offsets as specified in the vtable
+ entries).
+
+ For both functions, a match slot is created internally. If the output parameter
+ slot is NULL, a "floating" slot object is created, see
+ sd_bus_slot_set_floating3.
+ Otherwise, a pointer to the slot object is returned. In that case, the reference to the slot object
+ should be dropped when the vtable is not needed anymore, see
+ sd_bus_slot_unref3.
+
+
+
+ The sd_bus_vtable array
+
+ The array consists of the structures of type sd_bus_vtable, but it
+ should never be filled in manually, but through one of the following macros:
+
+
+
+ SD_BUS_VTABLE_START()
+ SD_BUS_VTABLE_END
+
+ Those must always be the first and last element.
+
+
+
+ SD_BUS_METHOD_WITH_NAMES_OFFSET()
+ SD_BUS_METHOD_WITH_NAMES()
+ SD_BUS_METHOD_WITH_OFFSET()
+ SD_BUS_METHOD()
+
+ Declare a D-Bus method with the name member, parameter
+ signature signature, result signature result.
+ Parameters in_names and out_names specify the
+ argument names of the input and output arguments in the function signature. The handler function
+ handler must be of type sd_bus_message_handler_t.
+ It will be called to handle the incoming messages that call this method. It receives a pointer that
+ is the userdata parameter passed to the registration function offset by
+ offset bytes. This may be used to pass pointers to different fields in
+ the same data structure to different methods in the same
+ vtable. in_names and out_names should be
+ created using the SD_BUS_PARAM() macro, see below. Parameter
+ flags is a combination of flags, see below.
+
+ SD_BUS_METHOD_WITH_NAMES(),
+ SD_BUS_METHOD_WITH_OFFSET(), and SD_BUS_METHOD() are
+ variants which specify zero offset (userdata parameter is passed with
+ no change), leave the names unset (i.e. no parameter names), or both.
+
+
+
+
+ SD_BUS_SIGNAL_WITH_NAMES()
+ SD_BUS_SIGNAL()
+
+ Declare a D-Bus signal with the name member,
+ parameter signature signature, and argument names
+ names. names should be
+ created using the SD_BUS_PARAM() macro, see below.
+ Parameter flags is a combination of flags, see below.
+
+
+ Equivalent to SD_BUS_SIGNAL_WITH_NAMES() with the
+ names paramater unset (i.e. no parameter names).
+
+
+
+
+ SD_BUS_WRITABLE_PROPERTY()
+ SD_BUS_PROPERTY()
+
+ Declare a D-Bus property with the name member and value
+ signature signature. Parameters get and
+ set are the getter and setter methods. They are called with a pointer
+ that is the userdata parameter passed to the registration function
+ offset by offset bytes. This may be used pass pointers to different
+ fields in the same data structure to different setters and getters in the same vtable. Parameter
+ flags is a combination of flags, see below.
+
+ The setter and getter methods may be omitted (specified as NULL), if the
+ property has one of the basic types or as in case of read-only properties. In
+ those cases, the userdata and offset
+ parameters must together point to valid variable of the corresponding type. A default setter and
+ getters will be provided, which simply copy the argument between this variable and the message.
+
+
+ SD_BUS_PROPERTY() is used to define a read-only property.
+
+
+
+
+ SD_BUS_PARAM()
+ Parameter names should be wrapped in this macro, see the example below.
+
+
+
+
+
+
+ Flags
+
+ The flags parameter is used to specify a combination of
+ D-Bus annotations.
+
+
+
+
+ SD_BUS_VTABLE_DEPRECATED
+
+ Mark this vtable entry as deprecated using the
+ org.freedesktop.DBus.Deprecated annotation in introspection data. If
+ specified for SD_BUS_VTABLE_START(), the annotation is applied to the
+ enclosing interface.
+
+
+
+ SD_BUS_VTABLE_HIDDEN
+
+ Make this vtable entry hidden. It will not be shown in introspection data. If
+ specified for SD_BUS_VTABLE_START(), all entries in the array are hidden.
+
+
+
+
+
+ SD_BUS_VTABLE_UNPRIVILEGED
+
+ Mark this vtable entry as unprivileged. If not specified, the
+ org.freedesktop.systemd1.Privileged annotation with value
+ true will be shown in introspection data.
+
+
+
+
+ SD_BUS_VTABLE_METHOD_NO_REPLY
+
+ Mark his vtable entry as a method that will not return a reply using the
+ org.freedesktop.DBus.Method.NoReply annotation in introspection data.
+
+
+
+
+ SD_BUS_VTABLE_CONST
+ SD_BUS_VTABLE_EMITS_CHANGE
+ SD_BUS_VTABLE_EMITS_INVALIDATION
+
+ Those three flags correspond to different values of the
+ org.freedesktop.DBus.Property.EmitsChangedSignal annotation, which specifies
+ whether the org.freedesktop.DBus.Properties.PropertiesChanged signal is
+ emitted whenever the property changes. SD_BUS_VTABLE_CONST corresponds to
+ const and means that the property never changes during the lifetime of the
+ object it belongs to, so no signal needs to be emitted.
+ SD_BUS_VTABLE_EMITS_CHANGE corresponds to true and means
+ that the signal is emitted. SD_BUS_VTABLE_EMITS_INVALIDATION corresponds to
+ invalides and means that the signal is emitted, but the value is not included
+ in the signal.
+
+
+
+
+ SD_BUS_VTABLE_PROPERTY_EXPLICIT
+
+ Mark this vtable property entry as requiring explicit request to for the value to
+ be shown (generally because the value is large or slow to calculate). This entry cannot be combined
+ with SD_BUS_VTABLE_EMITS_CHANGE, and will not be shown in property listings by
+ default (e.g. busctl introspect). This corresponds to the
+ org.freedesktop.systemd1.Explicit annotation in introspection data.
+
+
+
+
+
+
+
+ Examples
+
+
+ Create a simple listener on the bus
+
+
+
+ This creates a simple client on the bus (the user bus, when run as normal user).
+ We may use the D-Bus org.freedesktop.DBus.Introspectable.Introspect
+ call to acquire the XML description of the interface:
+
+
+
+
+
+
+ Return Value
+
+ On success, sd_bus_add_object_vtable and
+ sd_bus_add_fallback_vtable calls return 0 or a positive integer. On failure, they
+ return a negative errno-style error code.
+
+
+ Errors
+
+ Returned errors may indicate the following problems:
+
+
+
+ -EINVAL
+
+ One of the required parameters is NULL or invalid. A reserved
+ D-Bus interface was passed as the interface parameter.
+
+
+
+ -ENOPKG
+
+ The bus cannot be resolved.
+
+
+
+ -ECHILD
+
+ The bus was created in a different process.
+
+
+
+ -ENOMEM
+
+ Memory allocation failed.
+
+
+
+ -EPROTOTYPE
+
+ sd_bus_add_object_vtable and
+ sd_bus_add_fallback_vtable have been both called
+ for the same bus object path, which is not allowed.
+
+
+
+ -EEXIST
+
+ This vtable has already been registered for this
+ interface and path.
+
+
+
+
+
+
+
+
+
+ See Also
+
+
+ sd-bus3,
+ busctl1
+
+
+
diff --git a/man/vtable-example.c b/man/vtable-example.c
new file mode 100644
index 0000000000..a2a6cd18d7
--- /dev/null
+++ b/man/vtable-example.c
@@ -0,0 +1,70 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define _cleanup_(f) __attribute__((cleanup(f)))
+
+typedef struct object {
+ char *name;
+ uint32_t number;
+} object;
+
+static int method(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ printf("Got called with userdata=%p\n", userdata);
+ return 1;
+}
+
+static const sd_bus_vtable vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD(
+ "Method1", "s", "s", method, 0),
+ SD_BUS_METHOD_WITH_NAMES_OFFSET(
+ "Method2",
+ "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+ "s", SD_BUS_PARAM(returnstring),
+ method, offsetof(object, number),
+ SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_WRITABLE_PROPERTY(
+ "AutomaticStringProperty", "s", NULL, NULL,
+ offsetof(object, name),
+ SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_WRITABLE_PROPERTY(
+ "AutomaticIntegerProperty", "u", NULL, NULL,
+ offsetof(object, number),
+ SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_VTABLE_END
+};
+
+#define check(x) ({ \
+ int r = x; \
+ errno = r < 0 ? -r : 0; \
+ printf(#x ": %m\n"); \
+ if (r < 0) \
+ return EXIT_FAILURE; \
+ })
+
+int main(int argc, char **argv) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+
+ sd_bus_default(&bus);
+
+ object object = { .number = 666 };
+ check((object.name = strdup("name")) != NULL);
+
+ check(sd_bus_add_object_vtable(bus, NULL, "/object",
+ "org.freedesktop.systemd.VtableExample",
+ vtable,
+ &object));
+
+ while (true) {
+ check(sd_bus_wait(bus, UINT64_MAX));
+ check(sd_bus_process(bus, NULL));
+ }
+
+ free(object.name);
+
+ return 0;
+}
diff --git a/man/vtable-example.xml b/man/vtable-example.xml
new file mode 100644
index 0000000000..a3cdeae704
--- /dev/null
+++ b/man/vtable-example.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 02f12dc701..86efc02bd8 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -50,6 +50,7 @@ static size_t arg_snaplen = 4096;
static bool arg_list = false;
static bool arg_quiet = false;
static bool arg_verbose = false;
+static bool arg_xml_interface = false;
static bool arg_expect_reply = true;
static bool arg_auto_start = true;
static bool arg_allow_interactive_authorization = true;
@@ -948,6 +949,12 @@ static int introspect(int argc, char **argv, void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
+ if (arg_xml_interface) {
+ /* Just dump the received XML and finish */
+ puts(xml);
+ return 0;
+ }
+
/* First, get list of all properties */
r = parse_xml_introspect(argv[2], xml, &ops, members);
if (r < 0)
@@ -2255,6 +2262,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SIZE,
ARG_LIST,
ARG_VERBOSE,
+ ARG_XML_INTERFACE,
ARG_EXPECT_REPLY,
ARG_AUTO_START,
ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
@@ -2284,6 +2292,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "list", no_argument, NULL, ARG_LIST },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, ARG_VERBOSE },
+ { "xml-interface", no_argument, NULL, ARG_XML_INTERFACE },
{ "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
{ "auto-start", required_argument, NULL, ARG_AUTO_START },
{ "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
@@ -2388,6 +2397,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_verbose = true;
break;
+ case ARG_XML_INTERFACE:
+ arg_xml_interface = true;
+ break;
+
case ARG_EXPECT_REPLY:
r = parse_boolean(optarg);
if (r < 0)
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index a6748ceb20..a9ab0605ce 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -676,3 +676,8 @@ LIBSYSTEMD_241 {
global:
sd_bus_close_unref;
} LIBSYSTEMD_240;
+
+LIBSYSTEMD_243 {
+global:
+ sd_bus_object_vtable_format;
+} LIBSYSTEMD_241;
diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c
index 022eddb10f..beab80687d 100644
--- a/src/libsystemd/sd-bus/bus-introspect.c
+++ b/src/libsystemd/sd-bus/bus-introspect.c
@@ -172,13 +172,10 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
return 0;
}
-int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
- sd_bus_message *q;
+int introspect_finish(struct introspect *i, char **ret) {
int r;
assert(i);
- assert(m);
- assert(reply);
fputs("\n", i->f);
@@ -186,25 +183,17 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b
if (r < 0)
return r;
- r = sd_bus_message_new_method_return(m, &q);
- if (r < 0)
- return r;
+ i->f = safe_fclose(i->f);
+ *ret = TAKE_PTR(i->introspection);
- r = sd_bus_message_append(q, "s", i->introspection);
- if (r < 0) {
- sd_bus_message_unref(q);
- return r;
- }
-
- *reply = q;
return 0;
}
void introspect_free(struct introspect *i) {
assert(i);
- safe_fclose(i->f);
+ /* Normally introspect_finish() does all the work, this is just a backup for error paths */
+ safe_fclose(i->f);
free(i->introspection);
- zero(*i);
}
diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h
index bb2dd7ef7b..ccbb543d0c 100644
--- a/src/libsystemd/sd-bus/bus-introspect.h
+++ b/src/libsystemd/sd-bus/bus-introspect.h
@@ -18,5 +18,5 @@ int introspect_begin(struct introspect *i, bool trusted);
int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
-int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
+int introspect_finish(struct introspect *i, char **ret);
void introspect_free(struct introspect *i);
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index d9fc25605a..fe3b9feea6 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -22,7 +22,7 @@ static int node_vtable_get_userdata(
sd_bus_error *error) {
sd_bus_slot *s;
- void *u, *found_u;
+ void *u, *found_u = NULL;
int r;
assert(bus);
@@ -883,31 +883,33 @@ static int bus_node_exists(
return 0;
}
-static int process_introspect(
+int introspect_path(
sd_bus *bus,
- sd_bus_message *m,
+ const char *path,
struct node *n,
bool require_fallback,
- bool *found_object) {
+ bool ignore_nodes_modified,
+ bool *found_object,
+ char **ret,
+ sd_bus_error *error) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_set_free_free_ Set *s = NULL;
const char *previous_interface = NULL;
- struct introspect intro;
+ _cleanup_(introspect_free) struct introspect intro = {};
struct node_vtable *c;
bool empty;
int r;
- assert(bus);
- assert(m);
- assert(n);
- assert(found_object);
+ if (!n) {
+ n = hashmap_get(bus->nodes, path);
+ if (!n)
+ return -ENOENT;
+ }
- r = get_child_nodes(bus, m->path, n, 0, &s, &error);
+ r = get_child_nodes(bus, path, n, 0, &s, error);
if (r < 0)
- return bus_maybe_reply_error(m, r, &error);
- if (bus->nodes_modified)
+ return r;
+ if (bus->nodes_modified && !ignore_nodes_modified)
return 0;
r = introspect_begin(&intro, bus->trusted);
@@ -924,15 +926,11 @@ static int process_introspect(
if (require_fallback && !c->is_fallback)
continue;
- r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
- if (r < 0) {
- r = bus_maybe_reply_error(m, r, &error);
- goto finish;
- }
- if (bus->nodes_modified) {
- r = 0;
- goto finish;
- }
+ r = node_vtable_get_userdata(bus, path, c, NULL, error);
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified && !ignore_nodes_modified)
+ return 0;
if (r == 0)
continue;
@@ -942,7 +940,6 @@ static int process_introspect(
continue;
if (!streq_ptr(previous_interface, c->interface)) {
-
if (previous_interface)
fputs(" \n", intro.f);
@@ -951,7 +948,7 @@ static int process_introspect(
r = introspect_write_interface(&intro, c->vtable);
if (r < 0)
- goto finish;
+ return r;
previous_interface = c->interface;
}
@@ -962,36 +959,64 @@ static int process_introspect(
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) {
- r = bus_maybe_reply_error(m, r, &error);
- goto finish;
- }
- if (bus->nodes_modified) {
- r = 0;
- goto finish;
- }
+ r = bus_node_exists(bus, n, path, require_fallback);
+ if (r <= 0)
+ return r;
+ if (bus->nodes_modified && !ignore_nodes_modified)
+ return 0;
}
- *found_object = true;
+ if (found_object)
+ *found_object = true;
- r = introspect_write_child_nodes(&intro, s, m->path);
+ r = introspect_write_child_nodes(&intro, s, path);
if (r < 0)
- goto finish;
+ return r;
- r = introspect_finish(&intro, bus, m, &reply);
+ r = introspect_finish(&intro, ret);
if (r < 0)
- goto finish;
+ return r;
+
+ return 1;
+}
+
+static int process_introspect(
+ sd_bus *bus,
+ sd_bus_message *m,
+ struct node *n,
+ bool require_fallback,
+ bool *found_object) {
+
+ _cleanup_free_ char *s = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ int r;
+
+ assert(bus);
+ assert(m);
+ assert(n);
+ assert(found_object);
+
+ r = introspect_path(bus, m->path, n, require_fallback, false, found_object, &s, &error);
+ if (r < 0)
+ return bus_maybe_reply_error(m, r, &error);
+ if (r == 0)
+ /* nodes_modified == true */
+ return 0;
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "s", s);
+ if (r < 0)
+ return r;
r = sd_bus_send(bus, reply, NULL);
if (r < 0)
- goto finish;
+ return r;
- r = 1;
-
-finish:
- introspect_free(&intro);
- return r;
+ return 1;
}
static int object_manager_serialize_path(
@@ -1668,7 +1693,7 @@ static bool names_are_valid(const char *signature, const char **names, names_fla
/* the current version of this struct is defined in sd-bus-vtable.h, but we need to list here the historical versions
to make sure the calling code is compatible with one of these */
-struct sd_bus_vtable_original {
+struct sd_bus_vtable_221 {
uint8_t type:8;
uint64_t flags:56;
union {
@@ -1696,12 +1721,16 @@ struct sd_bus_vtable_original {
} x;
};
/* Structure size up to v241 */
-#define VTABLE_ELEMENT_SIZE_ORIGINAL sizeof(struct sd_bus_vtable_original)
-/* Current structure size */
-#define VTABLE_ELEMENT_SIZE sizeof(struct sd_bus_vtable)
+#define VTABLE_ELEMENT_SIZE_221 sizeof(struct sd_bus_vtable_221)
+
+/* Size of the structure when "features" field was added. If the structure definition is augmented, a copy of
+ * the structure definition will need to be made (similarly to the sd_bus_vtable_221 above), and this
+ * definition updated to refer to it. */
+#define VTABLE_ELEMENT_SIZE_242 sizeof(struct sd_bus_vtable)
static int vtable_features(const sd_bus_vtable *vtable) {
- if (vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL)
+ if (vtable[0].x.start.element_size < VTABLE_ELEMENT_SIZE_242 ||
+ !vtable[0].x.start.vtable_format_reference)
return 0;
return vtable[0].x.start.features;
}
@@ -1711,13 +1740,7 @@ bool bus_vtable_has_names(const sd_bus_vtable *vtable) {
}
const sd_bus_vtable* bus_vtable_next(const sd_bus_vtable *vtable, const sd_bus_vtable *v) {
- if (vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL) {
- const struct sd_bus_vtable_original *v2 = (const struct sd_bus_vtable_original *)v;
- v2++;
- v = (const sd_bus_vtable*)v2;
- } else /* current version */
- v++;
- return v;
+ return (const sd_bus_vtable*) ((char*) v + vtable[0].x.start.element_size);
}
static int add_object_vtable_internal(
@@ -1744,8 +1767,8 @@ static int add_object_vtable_internal(
assert_return(interface_name_is_valid(interface), -EINVAL);
assert_return(vtable, -EINVAL);
assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
- assert_return(vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL ||
- vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE,
+ assert_return(vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_221 ||
+ vtable[0].x.start.element_size >= VTABLE_ELEMENT_SIZE_242,
-EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
@@ -1928,6 +1951,9 @@ fail:
return r;
}
+/* This symbol exists solely to tell the linker that the "new" vtable format is used. */
+_public_ const unsigned sd_bus_object_vtable_format = 242;
+
_public_ int sd_bus_add_object_vtable(
sd_bus *bus,
sd_bus_slot **slot,
diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h
index b45fe6323e..f650196a54 100644
--- a/src/libsystemd/sd-bus/bus-objects.h
+++ b/src/libsystemd/sd-bus/bus-objects.h
@@ -2,8 +2,19 @@
#pragma once
#include "bus-internal.h"
+#include "bus-introspect.h"
const sd_bus_vtable* bus_vtable_next(const sd_bus_vtable *vtable, const sd_bus_vtable *v);
bool bus_vtable_has_names(const sd_bus_vtable *vtable);
int bus_process_object(sd_bus *bus, sd_bus_message *m);
void bus_node_gc(sd_bus *b, struct node *n);
+
+int introspect_path(
+ sd_bus *bus,
+ const char *path,
+ struct node *n,
+ bool require_fallback,
+ bool ignore_nodes_modified,
+ bool *found_object,
+ char **ret,
+ sd_bus_error *error);
diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c
index 9c8e93e897..9c8d1434b1 100644
--- a/src/libsystemd/sd-bus/test-bus-introspect.c
+++ b/src/libsystemd/sd-bus/test-bus-introspect.c
@@ -4,33 +4,13 @@
#include "log.h"
#include "tests.h"
-static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return -EINVAL;
-}
+#include "test-vtable-data.h"
-static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return -EINVAL;
-}
+static void test_manual_introspection(const sd_bus_vtable vtable[]) {
+ struct introspect intro = {};
+ _cleanup_free_ char *s = NULL;
-static const sd_bus_vtable vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0),
- SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED),
- SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY),
- SD_BUS_SIGNAL("Wowza", "sss", 0),
- SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
- SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0),
- SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED),
- SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EXPLICIT),
- SD_BUS_VTABLE_END
-};
-
-int main(int argc, char *argv[]) {
- struct introspect intro;
-
- test_setup_logging(LOG_DEBUG);
+ log_info("/* %s */", __func__);
assert_se(introspect_begin(&intro, false) >= 0);
@@ -38,10 +18,18 @@ int main(int argc, char *argv[]) {
assert_se(introspect_write_interface(&intro, vtable) >= 0);
fputs(" \n", intro.f);
- fflush(intro.f);
- fputs(intro.introspection, stdout);
+ assert_se(introspect_finish(&intro, &s) == 0);
+ fputs(s, stdout);
+ fputs("\n", stdout);
+}
- introspect_free(&intro);
+int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_DEBUG);
+
+ test_manual_introspection(test_vtable_1);
+ test_manual_introspection(test_vtable_2);
+ test_manual_introspection(test_vtable_deprecated);
+ test_manual_introspection((const sd_bus_vtable *) vtable_format_221);
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-vtable.c b/src/libsystemd/sd-bus/test-bus-vtable.c
index b278094fad..d69ca6ac97 100644
--- a/src/libsystemd/sd-bus/test-bus-vtable.c
+++ b/src/libsystemd/sd-bus/test-bus-vtable.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
#include
#include
@@ -5,120 +7,18 @@
#undef NDEBUG
#include
#include
+#include
#include "sd-bus-vtable.h"
+#ifndef __cplusplus
+# include "bus-objects.h"
+#endif
+
+#include "test-vtable-data.h"
+
#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
-struct context {
- bool quit;
- char *something;
- char *automatic_string_property;
- uint32_t automatic_integer_property;
-};
-
-static int handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return 1;
-}
-
-static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return 1;
-}
-
-static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return 1;
-}
-
-static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
- return 1;
-}
-
-static const sd_bus_vtable vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("AlterSomething", "s", "s", handler, 0),
- SD_BUS_METHOD("Exit", "", "", handler, 0),
- SD_BUS_METHOD_WITH_OFFSET("AlterSomething2", "s", "s", handler, 200, 0),
- SD_BUS_METHOD_WITH_OFFSET("Exit2", "", "", handler, 200, 0),
- SD_BUS_METHOD_WITH_NAMES_OFFSET("AlterSomething3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
- "s", SD_BUS_PARAM(returnstring), handler, 200, 0),
- SD_BUS_METHOD_WITH_NAMES("Exit3", "bx", SD_BUS_PARAM(with_confirmation) SD_BUS_PARAM(after_msec),
- "bb", SD_BUS_PARAM(accepted) SD_BUS_PARAM(scheduled), handler, 0),
- SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
- SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL, offsetof(struct context, something),
- SD_BUS_VTABLE_PROPERTY_EXPLICIT|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
- SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL,
- offsetof(struct context, automatic_string_property), 0),
- SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL,
- offsetof(struct context, automatic_integer_property), 0),
- SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
- SD_BUS_SIGNAL("DummySignal", "b", 0),
- SD_BUS_SIGNAL("DummySignal2", "so", 0),
- SD_BUS_SIGNAL_WITH_NAMES("DummySignal3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path), 0),
- SD_BUS_VTABLE_END
-};
-
-struct sd_bus_vtable_original {
- uint8_t type:8;
- uint64_t flags:56;
- union {
- struct {
- size_t element_size;
- } start;
- struct {
- const char *member;
- const char *signature;
- const char *result;
- sd_bus_message_handler_t handler;
- size_t offset;
- } method;
- struct {
- const char *member;
- const char *signature;
- } signal;
- struct {
- const char *member;
- const char *signature;
- sd_bus_property_get_t get;
- sd_bus_property_set_t set;
- size_t offset;
- } property;
- } x;
-};
-
-static const struct sd_bus_vtable_original vtable_format_original[] = {
- {
- .type = _SD_BUS_VTABLE_START,
- .flags = 0,
- .x = {
- .start = {
- .element_size = sizeof(struct sd_bus_vtable_original)
- },
- },
- },
- {
- .type = _SD_BUS_VTABLE_METHOD,
- .flags = 0,
- .x = {
- .method = {
- .member = "Exit",
- .signature = "",
- .result = "",
- .handler = handler,
- .offset = 0,
- },
- },
- },
- {
- .type = _SD_BUS_VTABLE_END,
- .flags = 0,
- .x = { { 0 } },
- }
-};
-
static void test_vtable(void) {
sd_bus *bus = NULL;
struct context c = {};
@@ -126,16 +26,24 @@ static void test_vtable(void) {
assert(sd_bus_new(&bus) >= 0);
- assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable", vtable, &c) >= 0);
- assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable2", vtable, &c) >= 0);
+ assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable", test_vtable_2, &c) >= 0);
+ assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable2", test_vtable_2, &c) >= 0);
/* the cast on the line below is needed to test with the old version of the table */
- assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtableOriginal", (const sd_bus_vtable *)vtable_format_original, &c) >= 0);
+ assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable221",
+ (const sd_bus_vtable *)vtable_format_221, &c) >= 0);
assert(sd_bus_set_address(bus, DEFAULT_BUS_PATH) >= 0);
r = sd_bus_start(bus);
assert(r == 0 || /* success */
r == -ENOENT /* dbus is inactive */ );
+#ifndef __cplusplus
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(introspect_path(bus, "/foo", NULL, false, true, NULL, &s, NULL) == 1);
+ fputs(s, stdout);
+#endif
+
sd_bus_unref(bus);
}
diff --git a/src/libsystemd/sd-bus/test-vtable-data.h b/src/libsystemd/sd-bus/test-vtable-data.h
new file mode 100644
index 0000000000..333dbd5b12
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-vtable-data.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+/* This is meant to be included in other files, hence no headers */
+
+struct context {
+ bool quit;
+ char *something;
+ char *automatic_string_property;
+ uint32_t automatic_integer_property;
+};
+
+static int handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static const sd_bus_vtable test_vtable_1[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0),
+ SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY),
+ SD_BUS_SIGNAL("Wowza", "sss", 0),
+ SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_WRITABLE_PROPERTY("AProperty", "s", get_handler, set_handler, 0, 0),
+ SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", get_handler, 0, SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_PROPERTY("ChangingProperty", "t", get_handler, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Invalidating", "t", get_handler, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_PROPERTY("Constant", "t", get_handler, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EXPLICIT),
+ SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable test_vtable_2[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("AlterSomething", "s", "s", handler, 0),
+ SD_BUS_METHOD("Exit", "", "", handler, 0),
+ SD_BUS_METHOD_WITH_OFFSET("AlterSomething2", "s", "s", handler, 200, 0),
+ SD_BUS_METHOD_WITH_OFFSET("Exit2", "", "", handler, 200, 0),
+ SD_BUS_METHOD_WITH_NAMES_OFFSET("AlterSomething3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+ "s", SD_BUS_PARAM(returnstring), handler, 200, 0),
+ SD_BUS_METHOD_WITH_NAMES("Exit3", "bx", SD_BUS_PARAM(with_confirmation) SD_BUS_PARAM(after_msec),
+ "bb", SD_BUS_PARAM(accepted) SD_BUS_PARAM(scheduled), handler, 0),
+ SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
+ SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL, offsetof(struct context, something),
+ SD_BUS_VTABLE_PROPERTY_EXPLICIT|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
+ SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL,
+ offsetof(struct context, automatic_string_property), 0),
+ SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL,
+ offsetof(struct context, automatic_integer_property), 0),
+ SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
+ SD_BUS_SIGNAL("DummySignal", "b", 0),
+ SD_BUS_SIGNAL("DummySignal2", "so", 0),
+ SD_BUS_SIGNAL_WITH_NAMES("DummySignal3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path), 0),
+ SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable test_vtable_deprecated[] = {
+ SD_BUS_VTABLE_START(SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_VTABLE_END
+};
+
+struct sd_bus_vtable_221 {
+ uint8_t type:8;
+ uint64_t flags:56;
+ union {
+ struct {
+ size_t element_size;
+ } start;
+ struct {
+ const char *member;
+ const char *signature;
+ const char *result;
+ sd_bus_message_handler_t handler;
+ size_t offset;
+ } method;
+ struct {
+ const char *member;
+ const char *signature;
+ } signal;
+ struct {
+ const char *member;
+ const char *signature;
+ sd_bus_property_get_t get;
+ sd_bus_property_set_t set;
+ size_t offset;
+ } property;
+ } x;
+};
+
+static const struct sd_bus_vtable_221 vtable_format_221[] = {
+ {
+ .type = _SD_BUS_VTABLE_START,
+ .flags = 0,
+ .x = {
+ .start = {
+ .element_size = sizeof(struct sd_bus_vtable_221)
+ },
+ },
+ },
+ {
+ .type = _SD_BUS_VTABLE_METHOD,
+ .flags = 0,
+ .x = {
+ .method = {
+ .member = "Exit",
+ .signature = "",
+ .result = "",
+ .handler = handler,
+ .offset = 0,
+ },
+ },
+ },
+ {
+ .type = _SD_BUS_VTABLE_END,
+ .flags = 0,
+ .x = { { 0 } },
+ }
+};
diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h
index 8a73ef0503..e3804e203c 100644
--- a/src/systemd/sd-bus-vtable.h
+++ b/src/systemd/sd-bus-vtable.h
@@ -52,6 +52,15 @@ enum {
_SD_BUS_VTABLE_PARAM_NAMES = 1 << 0,
};
+extern const unsigned sd_bus_object_vtable_format;
+
+/* Note: unused areas in the sd_bus_vtable[] array must be initalized to 0. The stucture contains an embedded
+ * union, and the compiler is NOT required to initalize the unused areas of the union when the rest of the
+ * structure is initalized. Normally the array is defined as read-only data, in which case the linker places
+ * it in the BSS section, which is always fully initalized, so this is not a concern. But if the array is
+ * created on the stack or on the heap, care must be taken to initalize the unused areas, for examply by
+ * first memsetting the whole region to zero before filling the data in. */
+
struct sd_bus_vtable {
/* Please do not initialize this structure directly, use the
* macros below instead */
@@ -62,6 +71,7 @@ struct sd_bus_vtable {
struct {
size_t element_size;
uint64_t features;
+ const unsigned *vtable_format_reference;
} start;
struct {
const char *member;
@@ -93,7 +103,8 @@ struct sd_bus_vtable {
.x = { \
.start = { \
.element_size = sizeof(sd_bus_vtable), \
- .features = _SD_BUS_VTABLE_PARAM_NAMES \
+ .features = _SD_BUS_VTABLE_PARAM_NAMES, \
+ .vtable_format_reference = &sd_bus_object_vtable_format, \
}, \
}, \
}
diff --git a/src/test/generate-sym-test.py b/src/test/generate-sym-test.py
index 357cce8e44..4d358b8e34 100755
--- a/src/test/generate-sym-test.py
+++ b/src/test/generate-sym-test.py
@@ -6,18 +6,22 @@ for header in sys.argv[2:]:
print('#include "{}"'.format(header.split('/')[-1]))
print('''
-void* functions[] = {''')
+const void* symbols[] = {''')
for line in open(sys.argv[1]):
match = re.search('^ +([a-zA-Z0-9_]+);', line)
if match:
- print(' {},'.format(match.group(1)))
+ s = match.group(1)
+ if s == 'sd_bus_object_vtable_format':
+ print(' &{},'.format(s))
+ else:
+ print(' {},'.format(s))
print('''};
int main(void) {
unsigned i;
- for (i = 0; i < sizeof(functions)/sizeof(void*); i++)
- printf("%p\\n", functions[i]);
+ for (i = 0; i < sizeof(symbols)/sizeof(void*); i++)
+ printf("%p\\n", symbols[i]);
return 0;
}''')
diff --git a/src/test/meson.build b/src/test/meson.build
index 521985b927..e58e1cc73d 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -911,7 +911,8 @@ tests += [
[],
[threads]],
- [['src/libsystemd/sd-bus/test-bus-vtable.c'],
+ [['src/libsystemd/sd-bus/test-bus-vtable.c',
+ 'src/libsystemd/sd-bus/test-vtable-data.h'],
[],
[]],
@@ -934,7 +935,8 @@ tests += [
[threads],
'', 'manual'],
- [['src/libsystemd/sd-bus/test-bus-introspect.c'],
+ [['src/libsystemd/sd-bus/test-bus-introspect.c',
+ 'src/libsystemd/sd-bus/test-vtable-data.h'],
[],
[]],