]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
29ddb38f | 2 | |
0d536673 LP |
3 | #include <stdio_ext.h> |
4 | ||
29ddb38f | 5 | #include "bus-internal.h" |
3ffd4af2 | 6 | #include "bus-introspect.h" |
856ad2a8 | 7 | #include "bus-objects.h" |
0461f8cd | 8 | #include "bus-protocol.h" |
07630cea | 9 | #include "bus-signature.h" |
3ffd4af2 | 10 | #include "fd-util.h" |
0d39fa9c | 11 | #include "fileio.h" |
07630cea LP |
12 | #include "string-util.h" |
13 | #include "util.h" | |
29ddb38f | 14 | |
7fb411f0 | 15 | int introspect_begin(struct introspect *i, bool trusted) { |
29ddb38f LP |
16 | assert(i); |
17 | ||
18 | zero(*i); | |
7fb411f0 | 19 | i->trusted = trusted; |
29ddb38f LP |
20 | |
21 | i->f = open_memstream(&i->introspection, &i->size); | |
22 | if (!i->f) | |
23 | return -ENOMEM; | |
24 | ||
0d536673 LP |
25 | (void) __fsetlocking(i->f, FSETLOCKING_BYCALLER); |
26 | ||
27 | fputs(BUS_INTROSPECT_DOCTYPE | |
28 | "<node>\n", i->f); | |
29ddb38f LP |
29 | |
30 | return 0; | |
31 | } | |
32 | ||
33 | int introspect_write_default_interfaces(struct introspect *i, bool object_manager) { | |
34 | assert(i); | |
35 | ||
0d536673 LP |
36 | fputs(BUS_INTROSPECT_INTERFACE_PEER |
37 | BUS_INTROSPECT_INTERFACE_INTROSPECTABLE | |
38 | BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f); | |
29ddb38f LP |
39 | |
40 | if (object_manager) | |
0d536673 | 41 | fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f); |
29ddb38f LP |
42 | |
43 | return 0; | |
44 | } | |
45 | ||
46 | int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) { | |
47 | char *node; | |
48 | ||
49 | assert(i); | |
50 | assert(prefix); | |
51 | ||
52 | while ((node = set_steal_first(s))) { | |
53 | const char *e; | |
54 | ||
55 | e = object_path_startswith(node, prefix); | |
dd8243a3 | 56 | if (e && e[0]) |
29ddb38f LP |
57 | fprintf(i->f, " <node name=\"%s\"/>\n", e); |
58 | ||
59 | free(node); | |
60 | } | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
affaed1e | 65 | static void introspect_write_flags(struct introspect *i, int type, uint64_t flags) { |
29ddb38f | 66 | if (flags & SD_BUS_VTABLE_DEPRECATED) |
0d536673 | 67 | fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f); |
29ddb38f | 68 | |
adacb957 | 69 | if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY)) |
0d536673 | 70 | fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f); |
29ddb38f | 71 | |
945c2931 | 72 | if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) { |
33702051 | 73 | if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) |
0d536673 | 74 | fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f); |
33702051 | 75 | |
df98a87b | 76 | if (flags & SD_BUS_VTABLE_PROPERTY_CONST) |
0d536673 | 77 | fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f); |
df98a87b | 78 | else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) |
0d536673 | 79 | fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f); |
df98a87b | 80 | else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) |
0d536673 | 81 | fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f); |
29ddb38f | 82 | } |
adacb957 | 83 | |
7fb411f0 | 84 | if (!i->trusted && |
945c2931 | 85 | IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) && |
7fb411f0 | 86 | !(flags & SD_BUS_VTABLE_UNPRIVILEGED)) |
0d536673 | 87 | fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f); |
29ddb38f LP |
88 | } |
89 | ||
856ad2a8 GC |
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) { | |
29ddb38f LP |
93 | int r; |
94 | ||
95 | for (;;) { | |
96 | size_t l; | |
97 | ||
98 | if (!*signature) | |
99 | return 0; | |
100 | ||
101 | r = signature_element_length(signature, &l); | |
102 | if (r < 0) | |
103 | return r; | |
104 | ||
105 | fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature); | |
106 | ||
856ad2a8 GC |
107 | if (**names != '\0') { |
108 | fprintf(i->f, " name=\"%s\"", *names); | |
109 | *names += strlen(*names) + 1; | |
110 | } | |
111 | ||
29ddb38f | 112 | if (direction) |
6014597d | 113 | fprintf(i->f, " direction=\"%s\"/>\n", direction); |
29ddb38f | 114 | else |
0d536673 | 115 | fputs("/>\n", i->f); |
29ddb38f LP |
116 | |
117 | signature += l; | |
118 | } | |
119 | } | |
120 | ||
718db961 | 121 | int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) { |
856ad2a8 GC |
122 | const sd_bus_vtable *vtable = v; |
123 | const char *names = ""; | |
124 | ||
29ddb38f | 125 | assert(i); |
29ddb38f LP |
126 | assert(v); |
127 | ||
856ad2a8 | 128 | for (; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) { |
29ddb38f | 129 | |
7fb411f0 LP |
130 | /* Ignore methods, signals and properties that are |
131 | * marked "hidden", but do show the interface | |
132 | * itself */ | |
133 | ||
6e8df5f0 LP |
134 | if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN)) |
135 | continue; | |
136 | ||
29ddb38f LP |
137 | switch (v->type) { |
138 | ||
139 | case _SD_BUS_VTABLE_START: | |
140 | if (v->flags & SD_BUS_VTABLE_DEPRECATED) | |
0d536673 | 141 | fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f); |
29ddb38f LP |
142 | break; |
143 | ||
144 | case _SD_BUS_VTABLE_METHOD: | |
77a874a3 | 145 | fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member); |
856ad2a8 GC |
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"); | |
29ddb38f | 150 | introspect_write_flags(i, v->type, v->flags); |
0d536673 | 151 | fputs(" </method>\n", i->f); |
29ddb38f LP |
152 | break; |
153 | ||
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", | |
77a874a3 LP |
157 | v->x.property.member, |
158 | v->x.property.signature, | |
29ddb38f LP |
159 | v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read"); |
160 | introspect_write_flags(i, v->type, v->flags); | |
0d536673 | 161 | fputs(" </property>\n", i->f); |
29ddb38f LP |
162 | break; |
163 | ||
164 | case _SD_BUS_VTABLE_SIGNAL: | |
77a874a3 | 165 | fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member); |
856ad2a8 GC |
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); | |
29ddb38f | 169 | introspect_write_flags(i, v->type, v->flags); |
0d536673 | 170 | fputs(" </signal>\n", i->f); |
29ddb38f LP |
171 | break; |
172 | } | |
173 | ||
174 | } | |
175 | ||
29ddb38f LP |
176 | return 0; |
177 | } | |
178 | ||
179 | int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) { | |
180 | sd_bus_message *q; | |
181 | int r; | |
182 | ||
183 | assert(i); | |
184 | assert(m); | |
185 | assert(reply); | |
186 | ||
0d536673 | 187 | fputs("</node>\n", i->f); |
29ddb38f | 188 | |
dacd6cee LP |
189 | r = fflush_and_check(i->f); |
190 | if (r < 0) | |
191 | return r; | |
29ddb38f | 192 | |
df2d202e | 193 | r = sd_bus_message_new_method_return(m, &q); |
29ddb38f LP |
194 | if (r < 0) |
195 | return r; | |
196 | ||
197 | r = sd_bus_message_append(q, "s", i->introspection); | |
198 | if (r < 0) { | |
199 | sd_bus_message_unref(q); | |
200 | return r; | |
201 | } | |
202 | ||
203 | *reply = q; | |
204 | return 0; | |
205 | } | |
206 | ||
207 | void introspect_free(struct introspect *i) { | |
208 | assert(i); | |
209 | ||
74ca738f | 210 | safe_fclose(i->f); |
29ddb38f | 211 | |
dacd6cee | 212 | free(i->introspection); |
29ddb38f LP |
213 | zero(*i); |
214 | } |