chiark / gitweb /
tree-wide: remove Lennart's copyright lines
[elogind.git] / src / libelogind / sd-bus / bus-introspect.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 ***/
4
5 #include <stdio_ext.h>
6
7 #include "bus-internal.h"
8 #include "bus-introspect.h"
9 #include "bus-protocol.h"
10 #include "bus-signature.h"
11 #include "fd-util.h"
12 #include "fileio.h"
13 #include "string-util.h"
14 #include "util.h"
15
16 int introspect_begin(struct introspect *i, bool trusted) {
17         assert(i);
18
19         zero(*i);
20         i->trusted = trusted;
21
22         i->f = open_memstream(&i->introspection, &i->size);
23         if (!i->f)
24                 return -ENOMEM;
25
26         (void) __fsetlocking(i->f, FSETLOCKING_BYCALLER);
27
28         fputs(BUS_INTROSPECT_DOCTYPE
29               "<node>\n", i->f);
30
31         return 0;
32 }
33
34 int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
35         assert(i);
36
37         fputs(BUS_INTROSPECT_INTERFACE_PEER
38               BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
39               BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
40
41         if (object_manager)
42                 fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
43
44         return 0;
45 }
46
47 int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
48         char *node;
49
50         assert(i);
51         assert(prefix);
52
53         while ((node = set_steal_first(s))) {
54                 const char *e;
55
56                 e = object_path_startswith(node, prefix);
57                 if (e && e[0])
58                         fprintf(i->f, " <node name=\"%s\"/>\n", e);
59
60                 free(node);
61         }
62
63         return 0;
64 }
65
66 static void introspect_write_flags(struct introspect *i, int type, int flags) {
67         if (flags & SD_BUS_VTABLE_DEPRECATED)
68                 fputs("   <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
69
70         if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
71                 fputs("   <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
72
73         if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) {
74                 if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
75                         fputs("   <annotation name=\"org.freedesktop.elogind1.Explicit\" value=\"true\"/>\n", i->f);
76
77                 if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
78                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
79                 else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
80                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
81                 else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
82                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
83         }
84
85         if (!i->trusted &&
86             IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
87             !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
88                 fputs("   <annotation name=\"org.freedesktop.elogind1.Privileged\" value=\"true\"/>\n", i->f);
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                 /* Ignore methods, signals and properties that are
122                  * marked "hidden", but do show the interface
123                  * itself */
124
125                 if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
126                         continue;
127
128                 switch (v->type) {
129
130                 case _SD_BUS_VTABLE_START:
131                         if (v->flags & SD_BUS_VTABLE_DEPRECATED)
132                                 fputs("  <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
133                         break;
134
135                 case _SD_BUS_VTABLE_METHOD:
136                         fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
137                         introspect_write_arguments(i, strempty(v->x.method.signature), "in");
138                         introspect_write_arguments(i, strempty(v->x.method.result), "out");
139                         introspect_write_flags(i, v->type, v->flags);
140                         fputs("  </method>\n", i->f);
141                         break;
142
143                 case _SD_BUS_VTABLE_PROPERTY:
144                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
145                         fprintf(i->f, "  <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
146                                 v->x.property.member,
147                                 v->x.property.signature,
148                                 v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
149                         introspect_write_flags(i, v->type, v->flags);
150                         fputs("  </property>\n", i->f);
151                         break;
152
153                 case _SD_BUS_VTABLE_SIGNAL:
154                         fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
155                         introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
156                         introspect_write_flags(i, v->type, v->flags);
157                         fputs("  </signal>\n", i->f);
158                         break;
159                 }
160
161         }
162
163         return 0;
164 }
165
166 int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
167         sd_bus_message *q;
168         int r;
169
170         assert(i);
171         assert(m);
172         assert(reply);
173
174         fputs("</node>\n", i->f);
175
176         r = fflush_and_check(i->f);
177         if (r < 0)
178                 return r;
179
180         r = sd_bus_message_new_method_return(m, &q);
181         if (r < 0)
182                 return r;
183
184         r = sd_bus_message_append(q, "s", i->introspection);
185         if (r < 0) {
186                 sd_bus_message_unref(q);
187                 return r;
188         }
189
190         *reply = q;
191         return 0;
192 }
193
194 void introspect_free(struct introspect *i) {
195         assert(i);
196
197         safe_fclose(i->f);
198
199         free(i->introspection);
200         zero(*i);
201 }