chiark / gitweb /
4d5c25a23fdc34bddb5b230902140728bba6f5ac
[elogind.git] / src / libsystemd-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_EMITS_CHANGE))
86                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
87                 else if (flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)
88                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
89         }
90
91         if (!i->trusted &&
92             (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
93             !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
94                 fputs("   <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
95 }
96
97 static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
98         int r;
99
100         for (;;) {
101                 size_t l;
102
103                 if (!*signature)
104                         return 0;
105
106                 r = signature_element_length(signature, &l);
107                 if (r < 0)
108                         return r;
109
110                 fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
111
112                 if (direction)
113                         fprintf(i->f, " direction=\"%s\"/>\n", direction);
114                 else
115                         fputs("/>\n", i->f);
116
117                 signature += l;
118         }
119 }
120
121 int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
122         assert(i);
123         assert(v);
124
125         for (; v->type != _SD_BUS_VTABLE_END; v++) {
126
127                 /* Ignore methods, signals and properties that are
128                  * marked "hidden", but do show the interface
129                  * itself */
130
131                 if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
132                         continue;
133
134                 switch (v->type) {
135
136                 case _SD_BUS_VTABLE_START:
137                         if (v->flags & SD_BUS_VTABLE_DEPRECATED)
138                                 fputs("  <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
139                         break;
140
141                 case _SD_BUS_VTABLE_METHOD:
142                         fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
143                         introspect_write_arguments(i, strempty(v->x.method.signature), "in");
144                         introspect_write_arguments(i, strempty(v->x.method.result), "out");
145                         introspect_write_flags(i, v->type, v->flags);
146                         fputs("  </method>\n", i->f);
147                         break;
148
149                 case _SD_BUS_VTABLE_PROPERTY:
150                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
151                         fprintf(i->f, "  <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
152                                 v->x.property.member,
153                                 v->x.property.signature,
154                                 v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
155                         introspect_write_flags(i, v->type, v->flags);
156                         fputs("  </property>\n", i->f);
157                         break;
158
159                 case _SD_BUS_VTABLE_SIGNAL:
160                         fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
161                         introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
162                         introspect_write_flags(i, v->type, v->flags);
163                         fputs("  </signal>\n", i->f);
164                         break;
165                 }
166
167         }
168
169         return 0;
170 }
171
172 int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
173         sd_bus_message *q;
174         int r;
175
176         assert(i);
177         assert(m);
178         assert(reply);
179
180         fputs("</node>\n", i->f);
181         fflush(i->f);
182
183         if (ferror(i->f))
184                 return -ENOMEM;
185
186         r = sd_bus_message_new_method_return(m, &q);
187         if (r < 0)
188                 return r;
189
190         r = sd_bus_message_append(q, "s", i->introspection);
191         if (r < 0) {
192                 sd_bus_message_unref(q);
193                 return r;
194         }
195
196         *reply = q;
197         return 0;
198 }
199
200 void introspect_free(struct introspect *i) {
201         assert(i);
202
203         if (i->f)
204                 fclose(i->f);
205
206         if (i->introspection)
207                 free(i->introspection);
208
209         zero(*i);
210 }