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