]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-introspect.c
sd-bus: introduce new SD_BUS_VTABLE_PROPERTY_EXPLICIT flag
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-introspect.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "util.h"
23 #include "bus-introspect.h"
24 #include "bus-signature.h"
25 #include "bus-internal.h"
26 #include "bus-protocol.h"
27
28 int introspect_begin(struct introspect *i, bool trusted) {
29 assert(i);
30
31 zero(*i);
32 i->trusted = trusted;
33
34 i->f = open_memstream(&i->introspection, &i->size);
35 if (!i->f)
36 return -ENOMEM;
37
38 fputs(BUS_INTROSPECT_DOCTYPE
39 "<node>\n", i->f);
40
41 return 0;
42 }
43
44 int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
45 assert(i);
46
47 fputs(BUS_INTROSPECT_INTERFACE_PEER
48 BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
49 BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
50
51 if (object_manager)
52 fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
53
54 return 0;
55 }
56
57 int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
58 char *node;
59
60 assert(i);
61 assert(prefix);
62
63 while ((node = set_steal_first(s))) {
64 const char *e;
65
66 e = object_path_startswith(node, prefix);
67 if (e && e[0])
68 fprintf(i->f, " <node name=\"%s\"/>\n", e);
69
70 free(node);
71 }
72
73 return 0;
74 }
75
76 static void introspect_write_flags(struct introspect *i, int type, int flags) {
77 if (flags & SD_BUS_VTABLE_DEPRECATED)
78 fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
79
80 if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
81 fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
82
83 if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
84 if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
85 fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f);
86
87 if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
88 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
89 else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
90 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
91 else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
92 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
93 }
94
95 if (!i->trusted &&
96 (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
97 !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
98 fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
99 }
100
101 static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
102 int r;
103
104 for (;;) {
105 size_t l;
106
107 if (!*signature)
108 return 0;
109
110 r = signature_element_length(signature, &l);
111 if (r < 0)
112 return r;
113
114 fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature);
115
116 if (direction)
117 fprintf(i->f, " direction=\"%s\"/>\n", direction);
118 else
119 fputs("/>\n", i->f);
120
121 signature += l;
122 }
123 }
124
125 int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
126 assert(i);
127 assert(v);
128
129 for (; v->type != _SD_BUS_VTABLE_END; v++) {
130
131 /* Ignore methods, signals and properties that are
132 * marked "hidden", but do show the interface
133 * itself */
134
135 if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
136 continue;
137
138 switch (v->type) {
139
140 case _SD_BUS_VTABLE_START:
141 if (v->flags & SD_BUS_VTABLE_DEPRECATED)
142 fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
143 break;
144
145 case _SD_BUS_VTABLE_METHOD:
146 fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member);
147 introspect_write_arguments(i, strempty(v->x.method.signature), "in");
148 introspect_write_arguments(i, strempty(v->x.method.result), "out");
149 introspect_write_flags(i, v->type, v->flags);
150 fputs(" </method>\n", i->f);
151 break;
152
153 case _SD_BUS_VTABLE_PROPERTY:
154 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
155 fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
156 v->x.property.member,
157 v->x.property.signature,
158 v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
159 introspect_write_flags(i, v->type, v->flags);
160 fputs(" </property>\n", i->f);
161 break;
162
163 case _SD_BUS_VTABLE_SIGNAL:
164 fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member);
165 introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
166 introspect_write_flags(i, v->type, v->flags);
167 fputs(" </signal>\n", i->f);
168 break;
169 }
170
171 }
172
173 return 0;
174 }
175
176 int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
177 sd_bus_message *q;
178 int r;
179
180 assert(i);
181 assert(m);
182 assert(reply);
183
184 fputs("</node>\n", i->f);
185
186 r = fflush_and_check(i->f);
187 if (r < 0)
188 return r;
189
190 r = sd_bus_message_new_method_return(m, &q);
191 if (r < 0)
192 return r;
193
194 r = sd_bus_message_append(q, "s", i->introspection);
195 if (r < 0) {
196 sd_bus_message_unref(q);
197 return r;
198 }
199
200 *reply = q;
201 return 0;
202 }
203
204 void introspect_free(struct introspect *i) {
205 assert(i);
206
207 if (i->f)
208 fclose(i->f);
209
210 free(i->introspection);
211 zero(*i);
212 }