Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include "bus-internal.h"
4 : : #include "bus-introspect.h"
5 : : #include "bus-objects.h"
6 : : #include "bus-protocol.h"
7 : : #include "bus-signature.h"
8 : : #include "fd-util.h"
9 : : #include "fileio.h"
10 : : #include "memory-util.h"
11 : : #include "string-util.h"
12 : :
13 : 36 : int introspect_begin(struct introspect *i, bool trusted) {
14 [ - + ]: 36 : assert(i);
15 : :
16 [ + - ]: 36 : zero(*i);
17 : 36 : i->trusted = trusted;
18 : :
19 : 36 : i->f = open_memstream_unlocked(&i->introspection, &i->size);
20 [ - + ]: 36 : if (!i->f)
21 : 0 : return -ENOMEM;
22 : :
23 : 36 : fputs(BUS_INTROSPECT_DOCTYPE
24 : : "<node>\n", i->f);
25 : :
26 : 36 : return 0;
27 : : }
28 : :
29 : 20 : int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
30 [ - + ]: 20 : assert(i);
31 : :
32 : 20 : fputs(BUS_INTROSPECT_INTERFACE_PEER
33 : : BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
34 : : BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
35 : :
36 [ + + ]: 20 : if (object_manager)
37 : 8 : fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
38 : :
39 : 20 : return 0;
40 : : }
41 : :
42 : 20 : int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
43 : : char *node;
44 : :
45 [ - + ]: 20 : assert(i);
46 [ - + ]: 20 : assert(prefix);
47 : :
48 [ + + ]: 52 : while ((node = set_steal_first(s))) {
49 : : const char *e;
50 : :
51 : 32 : e = object_path_startswith(node, prefix);
52 [ + - + - ]: 32 : if (e && e[0])
53 : 32 : fprintf(i->f, " <node name=\"%s\"/>\n", e);
54 : :
55 : 32 : free(node);
56 : : }
57 : :
58 : 20 : return 0;
59 : : }
60 : :
61 : 372 : static void introspect_write_flags(struct introspect *i, int type, uint64_t flags) {
62 [ + + ]: 372 : if (flags & SD_BUS_VTABLE_DEPRECATED)
63 : 16 : fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
64 : :
65 [ + + + + ]: 372 : if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
66 : 4 : fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
67 : :
68 [ + + + + ]: 372 : if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) {
69 [ + + ]: 160 : if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
70 : 20 : fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f);
71 : :
72 [ + + ]: 160 : if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
73 : 20 : fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
74 [ + + ]: 140 : else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
75 : 36 : fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
76 [ + + ]: 104 : else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
77 : 84 : fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
78 : : }
79 : :
80 [ + - ]: 372 : if (!i->trusted &&
81 [ + + + + ]: 372 : IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
82 [ + - ]: 232 : !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
83 : 232 : fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
84 : 372 : }
85 : :
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 : 624 : static int introspect_write_arguments(struct introspect *i, const char *signature, const char **names, const char *direction) {
89 : : int r;
90 : :
91 : 244 : for (;;) {
92 : : size_t l;
93 : :
94 [ + + ]: 624 : if (!*signature)
95 : 380 : return 0;
96 : :
97 : 244 : r = signature_element_length(signature, &l);
98 [ - + ]: 244 : if (r < 0)
99 : 0 : return r;
100 : :
101 : 244 : fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature);
102 : :
103 [ + + ]: 244 : if (**names != '\0') {
104 : 84 : fprintf(i->f, " name=\"%s\"", *names);
105 : 84 : *names += strlen(*names) + 1;
106 : : }
107 : :
108 [ + + ]: 244 : if (direction)
109 : 164 : fprintf(i->f, " direction=\"%s\"/>\n", direction);
110 : : else
111 : 80 : fputs("/>\n", i->f);
112 : :
113 : 244 : signature += l;
114 : : }
115 : : }
116 : :
117 : 40 : int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
118 : 40 : const sd_bus_vtable *vtable = v;
119 : 40 : const char *names = "";
120 : :
121 [ - + ]: 40 : assert(i);
122 [ - + ]: 40 : assert(v);
123 : :
124 [ + + ]: 452 : for (; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) {
125 : :
126 : : /* Ignore methods, signals and properties that are
127 : : * marked "hidden", but do show the interface
128 : : * itself */
129 : :
130 [ + + - + ]: 412 : if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
131 : 0 : continue;
132 : :
133 [ + + + + : 412 : switch (v->type) {
- ]
134 : :
135 : 40 : case _SD_BUS_VTABLE_START:
136 [ + + ]: 40 : if (v->flags & SD_BUS_VTABLE_DEPRECATED)
137 : 4 : fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
138 : 40 : break;
139 : :
140 : 168 : case _SD_BUS_VTABLE_METHOD:
141 : 168 : fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member);
142 [ + + ]: 168 : if (bus_vtable_has_names(vtable))
143 : 160 : names = strempty(v->x.method.names);
144 : 168 : introspect_write_arguments(i, strempty(v->x.method.signature), &names, "in");
145 : 168 : introspect_write_arguments(i, strempty(v->x.method.result), &names, "out");
146 : 168 : introspect_write_flags(i, v->type, v->flags);
147 : 168 : fputs(" </method>\n", i->f);
148 : 168 : break;
149 : :
150 : 160 : case _SD_BUS_VTABLE_PROPERTY:
151 : : case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
152 : 160 : fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
153 : : v->x.property.member,
154 : : v->x.property.signature,
155 [ + + ]: 160 : v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
156 : 160 : introspect_write_flags(i, v->type, v->flags);
157 : 160 : fputs(" </property>\n", i->f);
158 : 160 : break;
159 : :
160 : 44 : case _SD_BUS_VTABLE_SIGNAL:
161 : 44 : fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member);
162 [ + - ]: 44 : if (bus_vtable_has_names(vtable))
163 : 44 : names = strempty(v->x.method.names);
164 : 44 : introspect_write_arguments(i, strempty(v->x.signal.signature), &names, NULL);
165 : 44 : introspect_write_flags(i, v->type, v->flags);
166 : 44 : fputs(" </signal>\n", i->f);
167 : 44 : break;
168 : : }
169 : :
170 : 412 : }
171 : :
172 : 40 : return 0;
173 : : }
174 : :
175 : 36 : int introspect_finish(struct introspect *i, char **ret) {
176 : : int r;
177 : :
178 [ - + ]: 36 : assert(i);
179 : :
180 : 36 : fputs("</node>\n", i->f);
181 : :
182 : 36 : r = fflush_and_check(i->f);
183 [ - + ]: 36 : if (r < 0)
184 : 0 : return r;
185 : :
186 : 36 : i->f = safe_fclose(i->f);
187 : 36 : *ret = TAKE_PTR(i->introspection);
188 : :
189 : 36 : return 0;
190 : : }
191 : :
192 : 20 : void introspect_free(struct introspect *i) {
193 [ - + ]: 20 : assert(i);
194 : :
195 : : /* Normally introspect_finish() does all the work, this is just a backup for error paths */
196 : :
197 : 20 : safe_fclose(i->f);
198 : 20 : free(i->introspection);
199 : 20 : }
|