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