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