Line data Source code
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 5 : int introspect_begin(struct introspect *i, bool trusted) {
29 5 : assert(i);
30 :
31 5 : zero(*i);
32 5 : i->trusted = trusted;
33 :
34 5 : i->f = open_memstream(&i->introspection, &i->size);
35 5 : if (!i->f)
36 0 : return -ENOMEM;
37 :
38 5 : fputs(BUS_INTROSPECT_DOCTYPE
39 : "<node>\n", i->f);
40 :
41 5 : return 0;
42 : }
43 :
44 4 : int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
45 4 : assert(i);
46 :
47 4 : fputs(BUS_INTROSPECT_INTERFACE_PEER
48 : BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
49 : BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
50 :
51 4 : if (object_manager)
52 2 : fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
53 :
54 4 : return 0;
55 : }
56 :
57 4 : int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
58 : char *node;
59 :
60 4 : assert(i);
61 4 : assert(prefix);
62 :
63 25 : while ((node = set_steal_first(s))) {
64 : const char *e;
65 :
66 17 : e = object_path_startswith(node, prefix);
67 17 : if (e && e[0])
68 17 : fprintf(i->f, " <node name=\"%s\"/>\n", e);
69 :
70 17 : free(node);
71 : }
72 :
73 4 : return 0;
74 : }
75 :
76 36 : static void introspect_write_flags(struct introspect *i, int type, int flags) {
77 36 : if (flags & SD_BUS_VTABLE_DEPRECATED)
78 4 : fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
79 :
80 36 : if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
81 1 : fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
82 :
83 36 : if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
84 15 : if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
85 2 : fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
86 13 : else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
87 2 : fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
88 11 : else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
89 9 : fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
90 : }
91 :
92 36 : if (!i->trusted &&
93 43 : (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
94 26 : !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
95 26 : fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
96 36 : }
97 :
98 53 : 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 53 : if (!*signature)
105 80 : return 0;
106 :
107 13 : r = signature_element_length(signature, &l);
108 13 : if (r < 0)
109 0 : return r;
110 :
111 13 : fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature);
112 :
113 13 : if (direction)
114 8 : fprintf(i->f, " direction=\"%s\"/>\n", direction);
115 : else
116 5 : fputs("/>\n", i->f);
117 :
118 13 : signature += l;
119 13 : }
120 : }
121 :
122 4 : int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
123 4 : assert(i);
124 4 : assert(v);
125 :
126 44 : 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 40 : if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
133 0 : continue;
134 :
135 40 : switch (v->type) {
136 :
137 : case _SD_BUS_VTABLE_START:
138 4 : if (v->flags & SD_BUS_VTABLE_DEPRECATED)
139 0 : fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
140 4 : break;
141 :
142 : case _SD_BUS_VTABLE_METHOD:
143 19 : fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member);
144 19 : introspect_write_arguments(i, strempty(v->x.method.signature), "in");
145 19 : introspect_write_arguments(i, strempty(v->x.method.result), "out");
146 19 : introspect_write_flags(i, v->type, v->flags);
147 19 : fputs(" </method>\n", i->f);
148 19 : break;
149 :
150 : case _SD_BUS_VTABLE_PROPERTY:
151 : case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
152 15 : fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
153 : v->x.property.member,
154 : v->x.property.signature,
155 15 : v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
156 15 : introspect_write_flags(i, v->type, v->flags);
157 15 : fputs(" </property>\n", i->f);
158 15 : break;
159 :
160 : case _SD_BUS_VTABLE_SIGNAL:
161 2 : fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member);
162 2 : introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
163 2 : introspect_write_flags(i, v->type, v->flags);
164 2 : fputs(" </signal>\n", i->f);
165 2 : break;
166 : }
167 :
168 : }
169 :
170 4 : return 0;
171 : }
172 :
173 4 : 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 4 : assert(i);
178 4 : assert(m);
179 4 : assert(reply);
180 :
181 4 : fputs("</node>\n", i->f);
182 4 : fflush(i->f);
183 :
184 4 : if (ferror(i->f))
185 0 : return -ENOMEM;
186 :
187 4 : r = sd_bus_message_new_method_return(m, &q);
188 4 : if (r < 0)
189 0 : return r;
190 :
191 4 : r = sd_bus_message_append(q, "s", i->introspection);
192 4 : if (r < 0) {
193 0 : sd_bus_message_unref(q);
194 0 : return r;
195 : }
196 :
197 4 : *reply = q;
198 4 : return 0;
199 : }
200 :
201 5 : void introspect_free(struct introspect *i) {
202 5 : assert(i);
203 :
204 5 : if (i->f)
205 5 : fclose(i->f);
206 :
207 5 : if (i->introspection)
208 5 : free(i->introspection);
209 :
210 5 : zero(*i);
211 5 : }
|