]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-introspect.c
util: split out escaping code into escape.[ch]
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-introspect.c
CommitLineData
29ddb38f
LP
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"
29ddb38f
LP
23#include "bus-introspect.h"
24#include "bus-signature.h"
25#include "bus-internal.h"
0461f8cd 26#include "bus-protocol.h"
29ddb38f 27
7fb411f0 28int introspect_begin(struct introspect *i, bool trusted) {
29ddb38f
LP
29 assert(i);
30
31 zero(*i);
7fb411f0 32 i->trusted = trusted;
29ddb38f
LP
33
34 i->f = open_memstream(&i->introspection, &i->size);
35 if (!i->f)
36 return -ENOMEM;
37
0461f8cd 38 fputs(BUS_INTROSPECT_DOCTYPE
29ddb38f
LP
39 "<node>\n", i->f);
40
41 return 0;
42}
43
44int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
45 assert(i);
46
0461f8cd
LP
47 fputs(BUS_INTROSPECT_INTERFACE_PEER
48 BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
49 BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
29ddb38f
LP
50
51 if (object_manager)
0461f8cd 52 fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
29ddb38f
LP
53
54 return 0;
55}
56
57int 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);
dd8243a3 67 if (e && e[0])
29ddb38f
LP
68 fprintf(i->f, " <node name=\"%s\"/>\n", e);
69
70 free(node);
71 }
72
73 return 0;
74}
75
76static 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
adacb957 80 if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
29ddb38f
LP
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) {
33702051
LP
84 if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
85 fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f);
86
df98a87b
LP
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)
29ddb38f 90 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
df98a87b
LP
91 else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
92 fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
29ddb38f 93 }
adacb957 94
7fb411f0
LP
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);
29ddb38f
LP
99}
100
101static 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)
6014597d 117 fprintf(i->f, " direction=\"%s\"/>\n", direction);
29ddb38f 118 else
6014597d 119 fputs("/>\n", i->f);
29ddb38f
LP
120
121 signature += l;
122 }
123}
124
718db961 125int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
29ddb38f 126 assert(i);
29ddb38f
LP
127 assert(v);
128
29ddb38f
LP
129 for (; v->type != _SD_BUS_VTABLE_END; v++) {
130
7fb411f0
LP
131 /* Ignore methods, signals and properties that are
132 * marked "hidden", but do show the interface
133 * itself */
134
6e8df5f0
LP
135 if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
136 continue;
137
29ddb38f
LP
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:
77a874a3 146 fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member);
f11ca85a
LP
147 introspect_write_arguments(i, strempty(v->x.method.signature), "in");
148 introspect_write_arguments(i, strempty(v->x.method.result), "out");
29ddb38f
LP
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",
77a874a3
LP
156 v->x.property.member,
157 v->x.property.signature,
29ddb38f
LP
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:
77a874a3 164 fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member);
f11ca85a 165 introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
29ddb38f
LP
166 introspect_write_flags(i, v->type, v->flags);
167 fputs(" </signal>\n", i->f);
168 break;
169 }
170
171 }
172
29ddb38f
LP
173 return 0;
174}
175
176int 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);
29ddb38f 185
dacd6cee
LP
186 r = fflush_and_check(i->f);
187 if (r < 0)
188 return r;
29ddb38f 189
df2d202e 190 r = sd_bus_message_new_method_return(m, &q);
29ddb38f
LP
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
204void introspect_free(struct introspect *i) {
205 assert(i);
206
74ca738f 207 safe_fclose(i->f);
29ddb38f 208
dacd6cee 209 free(i->introspection);
29ddb38f
LP
210 zero(*i);
211}