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