chiark / gitweb /
sd-bus,sd-event: unify error handling of object descriptions
[elogind.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 }