1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "bus-internal.h"
6 #include "bus-introspect.h"
7 #include "bus-objects.h"
8 #include "bus-protocol.h"
9 #include "bus-signature.h"
12 #include "memory-util.h"
13 #include "string-util.h"
15 int introspect_begin(struct introspect
*i
, bool trusted
) {
21 i
->f
= open_memstream(&i
->introspection
, &i
->size
);
25 (void) __fsetlocking(i
->f
, FSETLOCKING_BYCALLER
);
27 fputs(BUS_INTROSPECT_DOCTYPE
33 int introspect_write_default_interfaces(struct introspect
*i
, bool object_manager
) {
36 fputs(BUS_INTROSPECT_INTERFACE_PEER
37 BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
38 BUS_INTROSPECT_INTERFACE_PROPERTIES
, i
->f
);
41 fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER
, i
->f
);
46 int introspect_write_child_nodes(struct introspect
*i
, Set
*s
, const char *prefix
) {
52 while ((node
= set_steal_first(s
))) {
55 e
= object_path_startswith(node
, prefix
);
57 fprintf(i
->f
, " <node name=\"%s\"/>\n", e
);
65 static void introspect_write_flags(struct introspect
*i
, int type
, uint64_t flags
) {
66 if (flags
& SD_BUS_VTABLE_DEPRECATED
)
67 fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i
->f
);
69 if (type
== _SD_BUS_VTABLE_METHOD
&& (flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
))
70 fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i
->f
);
72 if (IN_SET(type
, _SD_BUS_VTABLE_PROPERTY
, _SD_BUS_VTABLE_WRITABLE_PROPERTY
)) {
73 if (flags
& SD_BUS_VTABLE_PROPERTY_EXPLICIT
)
74 fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i
->f
);
76 if (flags
& SD_BUS_VTABLE_PROPERTY_CONST
)
77 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i
->f
);
78 else if (flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
)
79 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i
->f
);
80 else if (!(flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
))
81 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i
->f
);
85 IN_SET(type
, _SD_BUS_VTABLE_METHOD
, _SD_BUS_VTABLE_WRITABLE_PROPERTY
) &&
86 !(flags
& SD_BUS_VTABLE_UNPRIVILEGED
))
87 fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i
->f
);
90 /* Note that "names" is both an input and an output parameter. It initially points to the first argument name in a
91 NULL-separated list of strings, and is then advanced with each argument, and the resulting pointer is returned. */
92 static int introspect_write_arguments(struct introspect
*i
, const char *signature
, const char **names
, const char *direction
) {
101 r
= signature_element_length(signature
, &l
);
105 fprintf(i
->f
, " <arg type=\"%.*s\"", (int) l
, signature
);
107 if (**names
!= '\0') {
108 fprintf(i
->f
, " name=\"%s\"", *names
);
109 *names
+= strlen(*names
) + 1;
113 fprintf(i
->f
, " direction=\"%s\"/>\n", direction
);
121 int introspect_write_interface(struct introspect
*i
, const sd_bus_vtable
*v
) {
122 const sd_bus_vtable
*vtable
= v
;
123 const char *names
= "";
128 for (; v
->type
!= _SD_BUS_VTABLE_END
; v
= bus_vtable_next(vtable
, v
)) {
130 /* Ignore methods, signals and properties that are
131 * marked "hidden", but do show the interface
134 if (v
->type
!= _SD_BUS_VTABLE_START
&& (v
->flags
& SD_BUS_VTABLE_HIDDEN
))
139 case _SD_BUS_VTABLE_START
:
140 if (v
->flags
& SD_BUS_VTABLE_DEPRECATED
)
141 fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i
->f
);
144 case _SD_BUS_VTABLE_METHOD
:
145 fprintf(i
->f
, " <method name=\"%s\">\n", v
->x
.method
.member
);
146 if (bus_vtable_has_names(vtable
))
147 names
= strempty(v
->x
.method
.names
);
148 introspect_write_arguments(i
, strempty(v
->x
.method
.signature
), &names
, "in");
149 introspect_write_arguments(i
, strempty(v
->x
.method
.result
), &names
, "out");
150 introspect_write_flags(i
, v
->type
, v
->flags
);
151 fputs(" </method>\n", i
->f
);
154 case _SD_BUS_VTABLE_PROPERTY
:
155 case _SD_BUS_VTABLE_WRITABLE_PROPERTY
:
156 fprintf(i
->f
, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
157 v
->x
.property
.member
,
158 v
->x
.property
.signature
,
159 v
->type
== _SD_BUS_VTABLE_WRITABLE_PROPERTY
? "readwrite" : "read");
160 introspect_write_flags(i
, v
->type
, v
->flags
);
161 fputs(" </property>\n", i
->f
);
164 case _SD_BUS_VTABLE_SIGNAL
:
165 fprintf(i
->f
, " <signal name=\"%s\">\n", v
->x
.signal
.member
);
166 if (bus_vtable_has_names(vtable
))
167 names
= strempty(v
->x
.method
.names
);
168 introspect_write_arguments(i
, strempty(v
->x
.signal
.signature
), &names
, NULL
);
169 introspect_write_flags(i
, v
->type
, v
->flags
);
170 fputs(" </signal>\n", i
->f
);
179 int introspect_finish(struct introspect
*i
, sd_bus
*bus
, sd_bus_message
*m
, sd_bus_message
**reply
) {
187 fputs("</node>\n", i
->f
);
189 r
= fflush_and_check(i
->f
);
193 r
= sd_bus_message_new_method_return(m
, &q
);
197 r
= sd_bus_message_append(q
, "s", i
->introspection
);
199 sd_bus_message_unref(q
);
207 void introspect_free(struct introspect
*i
) {
212 free(i
->introspection
);