]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
29ddb38f LP |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2013 Lennart Poettering | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU Lesser General Public License as published by | |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Lesser General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Lesser General Public License | |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
19 | ***/ | |
20 | ||
29ddb38f | 21 | #include "bus-internal.h" |
3ffd4af2 | 22 | #include "bus-introspect.h" |
0461f8cd | 23 | #include "bus-protocol.h" |
07630cea | 24 | #include "bus-signature.h" |
3ffd4af2 | 25 | #include "fd-util.h" |
0d39fa9c | 26 | #include "fileio.h" |
07630cea LP |
27 | #include "string-util.h" |
28 | #include "util.h" | |
29ddb38f | 29 | |
7fb411f0 | 30 | int introspect_begin(struct introspect *i, bool trusted) { |
29ddb38f LP |
31 | assert(i); |
32 | ||
33 | zero(*i); | |
7fb411f0 | 34 | i->trusted = trusted; |
29ddb38f LP |
35 | |
36 | i->f = open_memstream(&i->introspection, &i->size); | |
37 | if (!i->f) | |
38 | return -ENOMEM; | |
39 | ||
4b61c875 LP |
40 | fputs_unlocked(BUS_INTROSPECT_DOCTYPE |
41 | "<node>\n", i->f); | |
29ddb38f LP |
42 | |
43 | return 0; | |
44 | } | |
45 | ||
46 | int introspect_write_default_interfaces(struct introspect *i, bool object_manager) { | |
47 | assert(i); | |
48 | ||
4b61c875 LP |
49 | fputs_unlocked(BUS_INTROSPECT_INTERFACE_PEER |
50 | BUS_INTROSPECT_INTERFACE_INTROSPECTABLE | |
51 | BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f); | |
29ddb38f LP |
52 | |
53 | if (object_manager) | |
4b61c875 | 54 | fputs_unlocked(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f); |
29ddb38f LP |
55 | |
56 | return 0; | |
57 | } | |
58 | ||
59 | int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) { | |
60 | char *node; | |
61 | ||
62 | assert(i); | |
63 | assert(prefix); | |
64 | ||
65 | while ((node = set_steal_first(s))) { | |
66 | const char *e; | |
67 | ||
68 | e = object_path_startswith(node, prefix); | |
dd8243a3 | 69 | if (e && e[0]) |
29ddb38f LP |
70 | fprintf(i->f, " <node name=\"%s\"/>\n", e); |
71 | ||
72 | free(node); | |
73 | } | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
78 | static void introspect_write_flags(struct introspect *i, int type, int flags) { | |
79 | if (flags & SD_BUS_VTABLE_DEPRECATED) | |
4b61c875 | 80 | fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f); |
29ddb38f | 81 | |
adacb957 | 82 | if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY)) |
4b61c875 | 83 | fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f); |
29ddb38f | 84 | |
945c2931 | 85 | if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) { |
33702051 | 86 | if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) |
4b61c875 | 87 | fputs_unlocked(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f); |
33702051 | 88 | |
df98a87b | 89 | if (flags & SD_BUS_VTABLE_PROPERTY_CONST) |
4b61c875 | 90 | fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f); |
df98a87b | 91 | else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) |
4b61c875 | 92 | fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f); |
df98a87b | 93 | else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) |
4b61c875 | 94 | fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f); |
29ddb38f | 95 | } |
adacb957 | 96 | |
7fb411f0 | 97 | if (!i->trusted && |
945c2931 | 98 | IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) && |
7fb411f0 | 99 | !(flags & SD_BUS_VTABLE_UNPRIVILEGED)) |
4b61c875 | 100 | fputs_unlocked(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f); |
29ddb38f LP |
101 | } |
102 | ||
103 | static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) { | |
104 | int r; | |
105 | ||
106 | for (;;) { | |
107 | size_t l; | |
108 | ||
109 | if (!*signature) | |
110 | return 0; | |
111 | ||
112 | r = signature_element_length(signature, &l); | |
113 | if (r < 0) | |
114 | return r; | |
115 | ||
116 | fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature); | |
117 | ||
118 | if (direction) | |
6014597d | 119 | fprintf(i->f, " direction=\"%s\"/>\n", direction); |
29ddb38f | 120 | else |
4b61c875 | 121 | fputs_unlocked("/>\n", i->f); |
29ddb38f LP |
122 | |
123 | signature += l; | |
124 | } | |
125 | } | |
126 | ||
718db961 | 127 | int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) { |
29ddb38f | 128 | assert(i); |
29ddb38f LP |
129 | assert(v); |
130 | ||
29ddb38f LP |
131 | for (; v->type != _SD_BUS_VTABLE_END; v++) { |
132 | ||
7fb411f0 LP |
133 | /* Ignore methods, signals and properties that are |
134 | * marked "hidden", but do show the interface | |
135 | * itself */ | |
136 | ||
6e8df5f0 LP |
137 | if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN)) |
138 | continue; | |
139 | ||
29ddb38f LP |
140 | switch (v->type) { |
141 | ||
142 | case _SD_BUS_VTABLE_START: | |
143 | if (v->flags & SD_BUS_VTABLE_DEPRECATED) | |
4b61c875 | 144 | fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f); |
29ddb38f LP |
145 | break; |
146 | ||
147 | case _SD_BUS_VTABLE_METHOD: | |
77a874a3 | 148 | fprintf(i->f, " <method name=\"%s\">\n", v->x.method.member); |
f11ca85a LP |
149 | introspect_write_arguments(i, strempty(v->x.method.signature), "in"); |
150 | introspect_write_arguments(i, strempty(v->x.method.result), "out"); | |
29ddb38f | 151 | introspect_write_flags(i, v->type, v->flags); |
4b61c875 | 152 | fputs_unlocked(" </method>\n", i->f); |
29ddb38f LP |
153 | break; |
154 | ||
155 | case _SD_BUS_VTABLE_PROPERTY: | |
156 | case _SD_BUS_VTABLE_WRITABLE_PROPERTY: | |
157 | fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n", | |
77a874a3 LP |
158 | v->x.property.member, |
159 | v->x.property.signature, | |
29ddb38f LP |
160 | v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read"); |
161 | introspect_write_flags(i, v->type, v->flags); | |
4b61c875 | 162 | fputs_unlocked(" </property>\n", i->f); |
29ddb38f LP |
163 | break; |
164 | ||
165 | case _SD_BUS_VTABLE_SIGNAL: | |
77a874a3 | 166 | fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member); |
f11ca85a | 167 | introspect_write_arguments(i, strempty(v->x.signal.signature), NULL); |
29ddb38f | 168 | introspect_write_flags(i, v->type, v->flags); |
4b61c875 | 169 | fputs_unlocked(" </signal>\n", i->f); |
29ddb38f LP |
170 | break; |
171 | } | |
172 | ||
173 | } | |
174 | ||
29ddb38f LP |
175 | return 0; |
176 | } | |
177 | ||
178 | int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) { | |
179 | sd_bus_message *q; | |
180 | int r; | |
181 | ||
182 | assert(i); | |
183 | assert(m); | |
184 | assert(reply); | |
185 | ||
4b61c875 | 186 | fputs_unlocked("</node>\n", i->f); |
29ddb38f | 187 | |
dacd6cee LP |
188 | r = fflush_and_check(i->f); |
189 | if (r < 0) | |
190 | return r; | |
29ddb38f | 191 | |
df2d202e | 192 | r = sd_bus_message_new_method_return(m, &q); |
29ddb38f LP |
193 | if (r < 0) |
194 | return r; | |
195 | ||
196 | r = sd_bus_message_append(q, "s", i->introspection); | |
197 | if (r < 0) { | |
198 | sd_bus_message_unref(q); | |
199 | return r; | |
200 | } | |
201 | ||
202 | *reply = q; | |
203 | return 0; | |
204 | } | |
205 | ||
206 | void introspect_free(struct introspect *i) { | |
207 | assert(i); | |
208 | ||
74ca738f | 209 | safe_fclose(i->f); |
29ddb38f | 210 | |
dacd6cee | 211 | free(i->introspection); |
29ddb38f LP |
212 | zero(*i); |
213 | } |