]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-convenience.c
bus: add API calls to escape string components of objects paths
[thirdparty/systemd.git] / src / libsystemd-bus / bus-convenience.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 "bus-internal.h"
23 #include "bus-message.h"
24 #include "bus-signature.h"
25 #include "bus-util.h"
26 #include "bus-type.h"
27
28 _public_ int sd_bus_emit_signal(
29 sd_bus *bus,
30 const char *path,
31 const char *interface,
32 const char *member,
33 const char *types, ...) {
34
35 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
36 int r;
37
38 assert_return(bus, -EINVAL);
39 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
40 assert_return(!bus_pid_changed(bus), -ECHILD);
41
42 r = sd_bus_message_new_signal(bus, path, interface, member, &m);
43 if (r < 0)
44 return r;
45
46 if (!isempty(types)) {
47 va_list ap;
48
49 va_start(ap, types);
50 r = bus_message_append_ap(m, types, ap);
51 va_end(ap);
52 if (r < 0)
53 return r;
54 }
55
56 return sd_bus_send(bus, m, NULL);
57 }
58
59 _public_ int sd_bus_call_method(
60 sd_bus *bus,
61 const char *destination,
62 const char *path,
63 const char *interface,
64 const char *member,
65 sd_bus_error *error,
66 sd_bus_message **reply,
67 const char *types, ...) {
68
69 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
70 int r;
71
72 assert_return(bus, -EINVAL);
73 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
74 assert_return(!bus_pid_changed(bus), -ECHILD);
75
76 r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
77 if (r < 0)
78 return r;
79
80 if (!isempty(types)) {
81 va_list ap;
82
83 va_start(ap, types);
84 r = bus_message_append_ap(m, types, ap);
85 va_end(ap);
86 if (r < 0)
87 return r;
88 }
89
90 return sd_bus_call(bus, m, 0, error, reply);
91 }
92
93 _public_ int sd_bus_reply_method_return(
94 sd_bus *bus,
95 sd_bus_message *call,
96 const char *types, ...) {
97
98 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
99 int r;
100
101 assert_return(bus, -EINVAL);
102 assert_return(call, -EINVAL);
103 assert_return(call->sealed, -EPERM);
104 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
105 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
106 assert_return(!bus_pid_changed(bus), -ECHILD);
107
108 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
109 return 0;
110
111 r = sd_bus_message_new_method_return(bus, call, &m);
112 if (r < 0)
113 return r;
114
115 if (!isempty(types)) {
116 va_list ap;
117
118 va_start(ap, types);
119 r = bus_message_append_ap(m, types, ap);
120 va_end(ap);
121 if (r < 0)
122 return r;
123 }
124
125 return sd_bus_send(bus, m, NULL);
126 }
127
128 _public_ int sd_bus_reply_method_error(
129 sd_bus *bus,
130 sd_bus_message *call,
131 const sd_bus_error *e) {
132
133 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
134 int r;
135
136 assert_return(bus, -EINVAL);
137 assert_return(call, -EINVAL);
138 assert_return(call->sealed, -EPERM);
139 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
140 assert_return(sd_bus_error_is_set(e), -EINVAL);
141 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
142 assert_return(!bus_pid_changed(bus), -ECHILD);
143
144 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
145 return 0;
146
147 r = sd_bus_message_new_method_error(bus, call, e, &m);
148 if (r < 0)
149 return r;
150
151 return sd_bus_send(bus, m, NULL);
152 }
153
154 _public_ int sd_bus_reply_method_errorf(
155 sd_bus *bus,
156 sd_bus_message *call,
157 const char *name,
158 const char *format,
159 ...) {
160
161 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
162 va_list ap;
163 int r;
164
165 assert_return(bus, -EINVAL);
166 assert_return(call, -EINVAL);
167 assert_return(call->sealed, -EPERM);
168 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
169 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
170 assert_return(!bus_pid_changed(bus), -ECHILD);
171
172 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
173 return 0;
174
175 va_start(ap, format);
176 r = bus_error_setfv(&error, name, format, ap);
177 va_end(ap);
178
179 if (r < 0)
180 return r;
181
182 return sd_bus_reply_method_error(bus, call, &error);
183 }
184
185 _public_ int sd_bus_reply_method_errno(
186 sd_bus *bus,
187 sd_bus_message *call,
188 int error,
189 const sd_bus_error *p) {
190
191 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
192
193 assert_return(bus, -EINVAL);
194 assert_return(call, -EINVAL);
195 assert_return(call->sealed, -EPERM);
196 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
197 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
198 assert_return(!bus_pid_changed(bus), -ECHILD);
199
200 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
201 return 0;
202
203 if (sd_bus_error_is_set(p))
204 return sd_bus_reply_method_error(bus, call, p);
205
206 sd_bus_error_set_errno(&berror, error);
207
208 return sd_bus_reply_method_error(bus, call, &berror);
209 }
210
211 _public_ int sd_bus_reply_method_errnof(
212 sd_bus *bus,
213 sd_bus_message *call,
214 int error,
215 const char *format,
216 ...) {
217
218 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
219 va_list ap;
220
221 assert_return(bus, -EINVAL);
222 assert_return(call, -EINVAL);
223 assert_return(call->sealed, -EPERM);
224 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
225 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
226 assert_return(!bus_pid_changed(bus), -ECHILD);
227
228 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
229 return 0;
230
231 va_start(ap, format);
232 bus_error_set_errnofv(&berror, error, format, ap);
233 va_end(ap);
234
235 return sd_bus_reply_method_error(bus, call, &berror);
236 }
237
238 _public_ int sd_bus_get_property(
239 sd_bus *bus,
240 const char *destination,
241 const char *path,
242 const char *interface,
243 const char *member,
244 sd_bus_error *error,
245 sd_bus_message **reply,
246 const char *type) {
247
248 sd_bus_message *rep = NULL;
249 int r;
250
251 assert_return(bus, -EINVAL);
252 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
253 assert_return(member_name_is_valid(member), -EINVAL);
254 assert_return(reply, -EINVAL);
255 assert_return(signature_is_single(type, false), -EINVAL);
256 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
257 assert_return(!bus_pid_changed(bus), -ECHILD);
258
259 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
260 if (r < 0)
261 return r;
262
263 r = sd_bus_message_enter_container(rep, 'v', type);
264 if (r < 0) {
265 sd_bus_message_unref(rep);
266 return r;
267 }
268
269 *reply = rep;
270 return 0;
271 }
272
273 _public_ int sd_bus_get_property_trivial(
274 sd_bus *bus,
275 const char *destination,
276 const char *path,
277 const char *interface,
278 const char *member,
279 sd_bus_error *error,
280 char type, void *ptr) {
281
282 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
283 int r;
284
285 assert_return(bus, -EINVAL);
286 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
287 assert_return(member_name_is_valid(member), -EINVAL);
288 assert_return(bus_type_is_trivial(type), -EINVAL);
289 assert_return(ptr, -EINVAL);
290 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
291 assert_return(!bus_pid_changed(bus), -ECHILD);
292
293 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
294 if (r < 0)
295 return r;
296
297 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
298 if (r < 0)
299 return r;
300
301 r = sd_bus_message_read_basic(reply, type, ptr);
302 if (r < 0)
303 return r;
304
305 return 0;
306 }
307
308 _public_ int sd_bus_get_property_string(
309 sd_bus *bus,
310 const char *destination,
311 const char *path,
312 const char *interface,
313 const char *member,
314 sd_bus_error *error,
315 char **ret) {
316
317 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
318 const char *s;
319 char *n;
320 int r;
321
322 assert_return(bus, -EINVAL);
323 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
324 assert_return(member_name_is_valid(member), -EINVAL);
325 assert_return(ret, -EINVAL);
326 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
327 assert_return(!bus_pid_changed(bus), -ECHILD);
328
329 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
330 if (r < 0)
331 return r;
332
333 r = sd_bus_message_enter_container(reply, 'v', "s");
334 if (r < 0)
335 return r;
336
337 r = sd_bus_message_read_basic(reply, 's', &s);
338 if (r < 0)
339 return r;
340
341 n = strdup(s);
342 if (!n)
343 return -ENOMEM;
344
345 *ret = n;
346 return 0;
347 }
348
349 _public_ int sd_bus_get_property_strv(
350 sd_bus *bus,
351 const char *destination,
352 const char *path,
353 const char *interface,
354 const char *member,
355 sd_bus_error *error,
356 char ***ret) {
357
358 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
359 int r;
360
361 assert_return(bus, -EINVAL);
362 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
363 assert_return(member_name_is_valid(member), -EINVAL);
364 assert_return(ret, -EINVAL);
365 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
366 assert_return(!bus_pid_changed(bus), -ECHILD);
367
368 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
369 if (r < 0)
370 return r;
371
372 r = sd_bus_message_enter_container(reply, 'v', NULL);
373 if (r < 0)
374 return r;
375
376 r = sd_bus_message_read_strv(reply, ret);
377 if (r < 0)
378 return r;
379
380 return 0;
381 }
382
383 _public_ int sd_bus_set_property(
384 sd_bus *bus,
385 const char *destination,
386 const char *path,
387 const char *interface,
388 const char *member,
389 sd_bus_error *error,
390 const char *type, ...) {
391
392 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
393 va_list ap;
394 int r;
395
396 assert_return(bus, -EINVAL);
397 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
398 assert_return(member_name_is_valid(member), -EINVAL);
399 assert_return(signature_is_single(type, false), -EINVAL);
400 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
401 assert_return(!bus_pid_changed(bus), -ECHILD);
402
403 r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
404 if (r < 0)
405 return r;
406
407 r = sd_bus_message_append(m, "ss", strempty(interface), member);
408 if (r < 0)
409 return r;
410
411 r = sd_bus_message_open_container(m, 'v', type);
412 if (r < 0)
413 return r;
414
415 va_start(ap, type);
416 r = bus_message_append_ap(m, type, ap);
417 va_end(ap);
418 if (r < 0)
419 return r;
420
421 r = sd_bus_message_close_container(m);
422 if (r < 0)
423 return r;
424
425 return sd_bus_call(bus, m, 0, error, NULL);
426 }