chiark / gitweb /
core: convert PID 1 to libsystemd-bus
[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
28 int introspect_begin(struct introspect *i) {
29         assert(i);
30
31         zero(*i);
32
33         i->f = open_memstream(&i->introspection, &i->size);
34         if (!i->f)
35                 return -ENOMEM;
36
37         fputs(SD_BUS_INTROSPECT_DOCTYPE
38               "<node>\n", i->f);
39
40         return 0;
41 }
42
43 int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
44         assert(i);
45
46         fputs(SD_BUS_INTROSPECT_INTERFACE_PEER
47               SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
48               SD_BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
49
50         if (object_manager)
51                 fputs(SD_BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
52
53         return 0;
54 }
55
56 int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
57         char *node;
58
59         assert(i);
60         assert(prefix);
61
62         while ((node = set_steal_first(s))) {
63                 const char *e;
64
65                 e = object_path_startswith(node, prefix);
66                 if (e && e[0])
67                         fprintf(i->f, " <node name=\"%s\"/>\n", e);
68
69                 free(node);
70         }
71
72         return 0;
73 }
74
75 static void introspect_write_flags(struct introspect *i, int type, int flags) {
76         if (flags & SD_BUS_VTABLE_DEPRECATED)
77                 fputs("   <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
78
79         if (type == _SD_BUS_VTABLE_METHOD && flags & SD_BUS_VTABLE_METHOD_NO_REPLY)
80                 fputs("   <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
81
82         if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
83                 if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
84                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
85                 else if (flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)
86                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
87         }
88 }
89
90 static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
91         int r;
92
93         for (;;) {
94                 size_t l;
95
96                 if (!*signature)
97                         return 0;
98
99                 r = signature_element_length(signature, &l);
100                 if (r < 0)
101                         return r;
102
103                 fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
104
105                 if (direction)
106                         fprintf(i->f, " direction=\"%s\"/>\n", direction);
107                 else
108                         fputs("/>\n", i->f);
109
110                 signature += l;
111         }
112 }
113
114 int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
115         assert(i);
116         assert(v);
117
118         for (; v->type != _SD_BUS_VTABLE_END; v++) {
119
120                 switch (v->type) {
121
122                 case _SD_BUS_VTABLE_START:
123                         if (v->flags & SD_BUS_VTABLE_DEPRECATED)
124                                 fputs("  <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
125                         break;
126
127                 case _SD_BUS_VTABLE_METHOD:
128                         fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
129                         introspect_write_arguments(i, strempty(v->x.method.signature), "in");
130                         introspect_write_arguments(i, strempty(v->x.method.result), "out");
131                         introspect_write_flags(i, v->type, v->flags);
132                         fputs("  </method>\n", i->f);
133                         break;
134
135                 case _SD_BUS_VTABLE_PROPERTY:
136                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
137                         fprintf(i->f, "  <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
138                                 v->x.property.member,
139                                 v->x.property.signature,
140                                 v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
141                         introspect_write_flags(i, v->type, v->flags);
142                         fputs("  </property>\n", i->f);
143                         break;
144
145                 case _SD_BUS_VTABLE_SIGNAL:
146                         fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
147                         introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
148                         introspect_write_flags(i, v->type, v->flags);
149                         fputs("  </signal>\n", i->f);
150                         break;
151                 }
152
153         }
154
155         return 0;
156 }
157
158 int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
159         sd_bus_message *q;
160         int r;
161
162         assert(i);
163         assert(m);
164         assert(reply);
165
166         fputs("</node>\n", i->f);
167         fflush(i->f);
168
169         if (ferror(i->f))
170                 return -ENOMEM;
171
172         r = sd_bus_message_new_method_return(bus, m, &q);
173         if (r < 0)
174                 return r;
175
176         r = sd_bus_message_append(q, "s", i->introspection);
177         if (r < 0) {
178                 sd_bus_message_unref(q);
179                 return r;
180         }
181
182         *reply = q;
183         return 0;
184 }
185
186 void introspect_free(struct introspect *i) {
187         assert(i);
188
189         if (i->f)
190                 fclose(i->f);
191
192         if (i->introspection)
193                 free(i->introspection);
194
195         zero(*i);
196 }