]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-introspect.c
tmpfiles: accurately report creation results
[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 "sd-bus-protocol.h"
24 #include "bus-introspect.h"
25 #include "bus-signature.h"
26 #include "bus-internal.h"
27 #include "bus-protocol.h"
28
29 int introspect_begin(struct introspect *i, bool trusted) {
30 assert(i);
31
32 zero(*i);
33 i->trusted = trusted;
34
35 i->f = open_memstream(&i->introspection, &i->size);
36 if (!i->f)
37 return -ENOMEM;
38
39 fputs(BUS_INTROSPECT_DOCTYPE
40 "<node>\n", i->f);
41
42 return 0;
43 }
44
45 int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
46 assert(i);
47
48 fputs(BUS_INTROSPECT_INTERFACE_PEER
49 BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
50 BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
51
52 if (object_manager)
53 fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
54
55 return 0;
56 }
57
58 int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
59 char *node;
60
61 assert(i);
62 assert(prefix);
63
64 while ((node = set_steal_first(s))) {
65 const char *e;
66
67 e = object_path_startswith(node, prefix);
68 if (e && e[0])
69 fprintf(i->f, " <node name=\"%s\"/>\n", e);
70
71 free(node);
72 }
73
74 return 0;
75 }
76
77 static void introspect_write_flags(struct introspect *i, int type, int flags) {
78 if (flags & SD_BUS_VTABLE_DEPRECATED)
79 fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
80
81 if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
82 fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
83
84 if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
85 if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
86 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
87 else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
88 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
89 else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
90 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
91 }
92
93 if (!i->trusted &&
94 (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
95 !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
96 fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
97 }
98
99 static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
100 int r;
101
102 for (;;) {
103 size_t l;
104
105 if (!*signature)
106 return 0;
107
108 r = signature_element_length(signature, &l);
109 if (r < 0)
110 return r;
111
112 fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature);
113
114 if (direction)
115 fprintf(i->f, " direction=\"%s\"/>\n", direction);
116 else
117 fputs("/>\n", i->f);
118
119 signature += l;
120 }
121 }
122
123 int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
124 assert(i);
125 assert(v);
126
127 for (; v->type != _SD_BUS_VTABLE_END; v++) {
128
129 /* Ignore methods, signals and properties that are
130 * marked "hidden", but do show the interface
131 * itself */
132
133 if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
134 continue;
135
136 switch (v->type) {
137
138 case _SD_BUS_VTABLE_START:
139 if (v->flags & SD_BUS_VTABLE_DEPRECATED)
140 fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
141 break;
142
143 case _SD_BUS_VTABLE_METHOD:
144 fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member);
145 introspect_write_arguments(i, strempty(v->x.method.signature), "in");
146 introspect_write_arguments(i, strempty(v->x.method.result), "out");
147 introspect_write_flags(i, v->type, v->flags);
148 fputs(" </method>\n", i->f);
149 break;
150
151 case _SD_BUS_VTABLE_PROPERTY:
152 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
153 fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
154 v->x.property.member,
155 v->x.property.signature,
156 v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
157 introspect_write_flags(i, v->type, v->flags);
158 fputs(" </property>\n", i->f);
159 break;
160
161 case _SD_BUS_VTABLE_SIGNAL:
162 fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member);
163 introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
164 introspect_write_flags(i, v->type, v->flags);
165 fputs(" </signal>\n", i->f);
166 break;
167 }
168
169 }
170
171 return 0;
172 }
173
174 int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
175 sd_bus_message *q;
176 int r;
177
178 assert(i);
179 assert(m);
180 assert(reply);
181
182 fputs("</node>\n", i->f);
183 fflush(i->f);
184
185 if (ferror(i->f))
186 return -ENOMEM;
187
188 r = sd_bus_message_new_method_return(m, &q);
189 if (r < 0)
190 return r;
191
192 r = sd_bus_message_append(q, "s", i->introspection);
193 if (r < 0) {
194 sd_bus_message_unref(q);
195 return r;
196 }
197
198 *reply = q;
199 return 0;
200 }
201
202 void introspect_free(struct introspect *i) {
203 assert(i);
204
205 if (i->f)
206 fclose(i->f);
207
208 if (i->introspection)
209 free(i->introspection);
210
211 zero(*i);
212 }