]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-util.c
bus: add forgotten _public_
[thirdparty/systemd.git] / src / libsystemd-bus / bus-util.c
CommitLineData
40ca29a1
LP
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
0c842e0a
TG
22#include <sys/socket.h>
23
40ca29a1 24#include "util.h"
ffc06c35 25#include "strv.h"
40ca29a1
LP
26#include "macro.h"
27#include "def.h"
28
ffc06c35
KS
29#include "sd-event.h"
30#include "sd-bus.h"
31#include "bus-error.h"
32#include "bus-message.h"
33
40ca29a1
LP
34#include "bus-util.h"
35
36static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
37 sd_event *e = userdata;
38
39 assert(bus);
40 assert(m);
41 assert(e);
42
43 sd_event_request_quit(e);
44 return 1;
45}
46
47int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
48 _cleanup_free_ char *match = NULL;
49 int r;
50
51 assert(e);
52 assert(bus);
53 assert(name);
54
55 r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
56 if (r < 0)
57 return r;
58
59 r = sd_bus_add_match(bus, match, quit_callback, e);
60 if (r < 0)
61 return r;
62
63 r = sd_bus_release_name(bus, name);
64 if (r < 0)
65 return r;
66
67 if (r != SD_BUS_NAME_RELEASED)
68 return -EIO;
69
70 return 0;
71}
72
73int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
74 bool exiting = false;
75 int r;
76
77 assert(e);
78 assert(bus);
79 assert(name);
80
81 for (;;) {
82 r = sd_event_get_state(e);
83 if (r < 0)
84 return r;
85
86 if (r == SD_EVENT_FINISHED)
87 break;
88
abc5fe72 89 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
40ca29a1
LP
90 if (r < 0)
91 return r;
92
93 if (r == 0 && !exiting) {
94 r = bus_async_unregister_and_quit(e, bus, name);
95 if (r < 0)
96 return r;
97
98 exiting = true;
99 }
100 }
101
102 return 0;
103}
104
105int bus_property_get_tristate(
106 sd_bus *bus,
107 const char *path,
108 const char *interface,
109 const char *property,
110 sd_bus_message *reply,
111 sd_bus_error *error,
112 void *userdata) {
113
114 int *tristate = userdata;
115 int r;
116
117 r = sd_bus_message_append(reply, "b", *tristate > 0);
118 if (r < 0)
119 return r;
120
121 return 1;
122}
123
124int bus_verify_polkit(
125 sd_bus *bus,
126 sd_bus_message *m,
127 const char *action,
128 bool interactive,
129 bool *_challenge,
130 sd_bus_error *e) {
131
132 const char *sender;
133 uid_t uid;
134 int r;
135
136 assert(bus);
137 assert(m);
138 assert(action);
139
140 sender = sd_bus_message_get_sender(m);
141 if (!sender)
142 return -EBADMSG;
143
144 r = sd_bus_get_owner_uid(bus, sender, &uid);
145 if (r < 0)
146 return r;
147
148 if (uid == 0)
149 return 1;
150
151#ifdef ENABLE_POLKIT
152 else {
153 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
9bcbce42 154 unsigned authorized = false, challenge = false;
40ca29a1
LP
155
156 r = sd_bus_call_method(
157 bus,
158 "org.freedesktop.PolicyKit1",
159 "/org/freedesktop/PolicyKit1/Authority",
160 "org.freedesktop.PolicyKit1.Authority",
161 "CheckAuthorization",
162 e,
163 &reply,
164 "(sa{sv})sa{ss}us",
165 "system-bus-name", 1, "name", "s", sender,
166 action,
167 0,
168 interactive ? 1 : 0,
169 "");
170
171 if (r < 0) {
172 /* Treat no PK available as access denied */
173 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
174 sd_bus_error_free(e);
175 return -EACCES;
176 }
177
178 return r;
179 }
180
313333b4
LP
181 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
182 if (r >= 0)
183 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
40ca29a1
LP
184
185 if (authorized)
186 return 1;
187
188 if (_challenge) {
189 *_challenge = challenge;
190 return 0;
191 }
192 }
193#endif
194
195 return -EACCES;
196}
197
198#ifdef ENABLE_POLKIT
199
200typedef struct AsyncPolkitQuery {
201 sd_bus_message *request, *reply;
202 sd_bus_message_handler_t callback;
203 void *userdata;
204 uint64_t serial;
205} AsyncPolkitQuery;
206
207static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
208 AsyncPolkitQuery *q = userdata;
209 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
210 int r;
211
212 assert(bus);
213 assert(reply);
214 assert(q);
215
216 q->reply = sd_bus_message_ref(reply);
217 q->serial = 0;
218
219 m = sd_bus_message_ref(q->request);
220
221 r = sd_bus_message_rewind(m, true);
222 if (r < 0)
223 return r;
224
225 r = q->callback(bus, m, q->userdata);
226 if (r < 0)
227 return r;
228
229 return 1;
230}
231
232static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
233
234 if (!q)
235 return;
236
237 if (q->serial > 0 && b)
238 sd_bus_send_with_reply_cancel(b, q->serial);
239
240 sd_bus_message_unref(q->request);
241 sd_bus_message_unref(q->reply);
242 free(q);
243}
244
245#endif
246
247int bus_verify_polkit_async(
248 sd_bus *bus,
249 Hashmap **registry,
250 sd_bus_message *m,
251 const char *action,
252 bool interactive,
253 sd_bus_error *error,
254 sd_bus_message_handler_t callback,
255 void *userdata) {
256
257#ifdef ENABLE_POLKIT
258 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
259 AsyncPolkitQuery *q;
260#endif
261 const char *sender;
262 uid_t uid;
263 int r;
264
265 assert(bus);
266 assert(registry);
267 assert(m);
268 assert(action);
269
270#ifdef ENABLE_POLKIT
271 q = hashmap_remove(*registry, m);
272 if (q) {
9bcbce42 273 unsigned authorized, challenge;
40ca29a1
LP
274
275 /* This is the second invocation of this function, and
276 * there's already a response from polkit, let's
277 * process it */
278 assert(q->reply);
279
280 if (sd_bus_message_is_method_error(q->reply, NULL)) {
281 const sd_bus_error *e;
282
283 /* Treat no PK available as access denied */
284 if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
285 async_polkit_query_free(bus, q);
286 return -EACCES;
287 }
288
289 e = sd_bus_message_get_error(q->reply);
290 sd_bus_error_copy(error, e);
291 r = sd_bus_error_get_errno(e);
292
293 async_polkit_query_free(bus, q);
294 return r;
295 }
296
297 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
298 if (r >= 0)
299 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
300
301 async_polkit_query_free(bus, q);
302
303 if (r < 0)
304 return r;
305
306 if (authorized)
307 return 1;
308
309 return -EACCES;
310 }
311#endif
312
313 sender = sd_bus_message_get_sender(m);
314 if (!sender)
315 return -EBADMSG;
316
317 r = sd_bus_get_owner_uid(bus, sender, &uid);
318 if (r < 0)
319 return r;
320
321 if (uid == 0)
322 return 1;
323#ifdef ENABLE_POLKIT
324
325 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
326 if (r < 0)
327 return r;
328
329 r = sd_bus_message_new_method_call(
330 bus,
331 "org.freedesktop.PolicyKit1",
332 "/org/freedesktop/PolicyKit1/Authority",
333 "org.freedesktop.PolicyKit1.Authority",
334 "CheckAuthorization",
335 &pk);
336 if (r < 0)
337 return r;
338
339 r = sd_bus_message_append(
340 pk,
341 "(sa{sv})sa{ss}us",
342 "system-bus-name", 1, "name", "s", sender,
343 action,
344 0,
345 interactive ? 1 : 0,
346 "");
347 if (r < 0)
348 return r;
349
350 q = new0(AsyncPolkitQuery, 1);
351 if (!q)
352 return -ENOMEM;
353
354 q->request = sd_bus_message_ref(m);
355 q->callback = callback;
356 q->userdata = userdata;
357
358 r = hashmap_put(*registry, m, q);
359 if (r < 0) {
360 async_polkit_query_free(bus, q);
361 return r;
362 }
363
364 r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
365 if (r < 0)
366 return r;
367
368 return 0;
369#endif
370
371 return -EACCES;
372}
373
374void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
375#ifdef ENABLE_POLKIT
376 AsyncPolkitQuery *q;
377
378 while ((q = hashmap_steal_first(registry)))
379 async_polkit_query_free(bus, q);
380
381 hashmap_free(registry);
382#endif
383}
0c842e0a
TG
384
385static int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
386 struct ucred ucred;
387 socklen_t l;
0f8bd8de 388 int fd;
0c842e0a
TG
389
390 assert(c);
391
392 fd = sd_bus_get_fd(c);
0f8bd8de
LP
393 if (fd < 0)
394 return fd;
0c842e0a
TG
395
396 l = sizeof(struct ucred);
0f8bd8de 397 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 398 return -errno;
0c842e0a 399
0f8bd8de 400 if (l != sizeof(struct ucred))
0c842e0a 401 return -E2BIG;
0c842e0a
TG
402
403 if (ucred.uid != 0 && ucred.uid != geteuid())
404 return -EPERM;
405
406 return 1;
407}
408
0f8bd8de
LP
409int bus_open_system_systemd(sd_bus **_bus) {
410 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 411 int r;
0c842e0a
TG
412
413 assert(_bus);
414
0f8bd8de
LP
415 if (geteuid() != 0)
416 return sd_bus_open_system(_bus);
a1da8583 417
0f8bd8de
LP
418 /* If we are root, then let's talk directly to the system
419 * instance, instead of going via the bus */
a1da8583 420
0f8bd8de
LP
421 r = sd_bus_new(&bus);
422 if (r < 0)
423 return r;
a1da8583 424
0f8bd8de
LP
425 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
426 if (r < 0)
427 return r;
a1da8583 428
0f8bd8de
LP
429 r = sd_bus_start(bus);
430 if (r < 0)
431 return r;
a1da8583 432
0f8bd8de 433 r = bus_check_peercred(bus);
a1da8583
TG
434 if (r < 0)
435 return r;
436
437 *_bus = bus;
0f8bd8de
LP
438 bus = NULL;
439
a1da8583
TG
440 return 0;
441}
442
9f6eb1cd 443int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
444 char type;
445 const char *contents;
9f6eb1cd 446 int r;
a1da8583
TG
447
448 assert(name);
449 assert(property);
450
9f6eb1cd
KS
451 r = sd_bus_message_peek_type(property, &type, &contents);
452 if (r < 0)
453 return r;
a1da8583
TG
454
455 switch (type) {
456
457 case SD_BUS_TYPE_STRING: {
458 const char *s;
9f6eb1cd
KS
459
460 r = sd_bus_message_read_basic(property, type, &s);
461 if (r < 0)
462 return r;
a1da8583
TG
463
464 if (all || !isempty(s))
465 printf("%s=%s\n", name, s);
466
467 return 1;
468 }
469
470 case SD_BUS_TYPE_BOOLEAN: {
471 bool b;
472
9f6eb1cd
KS
473 r = sd_bus_message_read_basic(property, type, &b);
474 if (r < 0)
475 return r;
476
a1da8583
TG
477 printf("%s=%s\n", name, yes_no(b));
478
479 return 1;
480 }
481
482 case SD_BUS_TYPE_UINT64: {
483 uint64_t u;
484
9f6eb1cd
KS
485 r = sd_bus_message_read_basic(property, type, &u);
486 if (r < 0)
487 return r;
a1da8583
TG
488
489 /* Yes, heuristics! But we can change this check
490 * should it turn out to not be sufficient */
491
492 if (endswith(name, "Timestamp")) {
493 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
494
495 t = format_timestamp(timestamp, sizeof(timestamp), u);
496 if (t || all)
497 printf("%s=%s\n", name, strempty(t));
498
499 } else if (strstr(name, "USec")) {
500 char timespan[FORMAT_TIMESPAN_MAX];
501
502 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
503 } else
504 printf("%s=%llu\n", name, (unsigned long long) u);
505
506 return 1;
507 }
508
509 case SD_BUS_TYPE_UINT32: {
510 uint32_t u;
511
9f6eb1cd
KS
512 r = sd_bus_message_read_basic(property, type, &u);
513 if (r < 0)
514 return r;
a1da8583
TG
515
516 if (strstr(name, "UMask") || strstr(name, "Mode"))
517 printf("%s=%04o\n", name, u);
518 else
519 printf("%s=%u\n", name, (unsigned) u);
520
521 return 1;
522 }
523
524 case SD_BUS_TYPE_INT32: {
525 int32_t i;
526
9f6eb1cd
KS
527 r = sd_bus_message_read_basic(property, type, &i);
528 if (r < 0)
529 return r;
a1da8583
TG
530
531 printf("%s=%i\n", name, (int) i);
532 return 1;
533 }
534
535 case SD_BUS_TYPE_DOUBLE: {
536 double d;
537
9f6eb1cd
KS
538 r = sd_bus_message_read_basic(property, type, &d);
539 if (r < 0)
540 return r;
a1da8583
TG
541
542 printf("%s=%g\n", name, d);
543 return 1;
544 }
545
546 case SD_BUS_TYPE_ARRAY:
a1da8583
TG
547 if (streq(contents, "s")) {
548 bool space = false;
549 char tp;
550 const char *cnt;
551
9f6eb1cd
KS
552 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
553 if (r < 0)
554 return r;
555
556 r = sd_bus_message_peek_type(property, &tp, &cnt);
557 if (r < 0)
558 return r;
a1da8583 559
a1da8583 560 if (all || cnt) {
4d7859d1 561 const char *str;
a1da8583
TG
562
563 printf("%s=", name);
564
9f6eb1cd 565 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) >= 0) {
a1da8583
TG
566 printf("%s%s", space ? " " : "", str);
567
568 space = true;
569 }
9f6eb1cd
KS
570 if (r < 0)
571 return r;
a1da8583
TG
572
573 puts("");
574 }
575
9f6eb1cd
KS
576 r = sd_bus_message_exit_container(property);
577 if (r < 0)
578 return r;
a1da8583
TG
579
580 return 1;
581
582 } else if (streq(contents, "y")) {
583 const uint8_t *u;
584 size_t n;
585
9f6eb1cd
KS
586 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
587 if (r < 0)
588 return r;
589
a1da8583
TG
590 if (all || n > 0) {
591 unsigned int i;
592
593 printf("%s=", name);
594
595 for (i = 0; i < n; i++)
596 printf("%02x", u[i]);
597
598 puts("");
599 }
600
601 return 1;
602
603 } else if (streq(contents, "u")) {
604 uint32_t *u;
605 size_t n;
606
9f6eb1cd
KS
607 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
608 if (r < 0)
609 return r;
610
a1da8583
TG
611 if (all || n > 0) {
612 unsigned int i;
613
614 printf("%s=", name);
615
616 for (i = 0; i < n; i++)
617 printf("%08x", u[i]);
618
619 puts("");
620 }
621
622 return 1;
623 }
624
625 break;
626 }
627
628 return 0;
629}
d21ed1ea 630
9f6eb1cd
KS
631int bus_print_all_properties(sd_bus *bus, const char *path, char **filter, bool all) {
632 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
633 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
634 int r;
635
9f6eb1cd
KS
636 assert(bus);
637 assert(path);
638
639 r = sd_bus_call_method(bus,
640 "org.freedesktop.machine1",
ffc06c35
KS
641 path,
642 "org.freedesktop.DBus.Properties",
643 "GetAll",
644 &error,
9f6eb1cd 645 &reply,
ffc06c35 646 "s", "");
9f6eb1cd 647 if (r < 0)
ffc06c35 648 return r;
ffc06c35 649
9f6eb1cd 650 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
651 if (r < 0)
652 return r;
653
9f6eb1cd 654 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 655 const char *name;
ffc06c35 656 const char *contents;
ffc06c35 657
9f6eb1cd 658 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
659 if (r < 0)
660 return r;
661
9f6eb1cd
KS
662 if (!filter || strv_find(filter, name)) {
663 r = sd_bus_message_peek_type(reply, NULL, &contents);
664 if (r < 0)
665 return r;
666
667 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
668 if (r < 0)
669 return r;
ffc06c35 670
9f6eb1cd
KS
671 r = bus_print_property(name, reply, all);
672 if (r < 0)
673 return r;
674 if (r == 0 && all)
675 printf("%s=[unprintable]\n", name);
676
677 r = sd_bus_message_exit_container(reply);
678 if (r < 0)
679 return r;
680 } else {
681 r = sd_bus_message_skip(reply, "v");
682 if (r < 0)
683 return r;
684 }
685
686 r = sd_bus_message_exit_container(reply);
ffc06c35
KS
687 if (r < 0)
688 return r;
9f6eb1cd
KS
689 }
690 if (r < 0)
691 return r;
ffc06c35 692
9f6eb1cd
KS
693 r = sd_bus_message_exit_container(reply);
694 if (r < 0)
695 return r;
ffc06c35 696
9f6eb1cd
KS
697 return 0;
698}
ffc06c35 699
9f6eb1cd
KS
700int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
701 sd_id128_t *p = userdata;
702 const void *v;
703 size_t n;
704 int r;
ffc06c35 705
9f6eb1cd
KS
706 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
707 if (r < 0)
708 return r;
ffc06c35 709
9f6eb1cd
KS
710 if (n == 0)
711 *p = SD_ID128_NULL;
712 else if (n == 16)
713 memcpy((*p).bytes, v, n);
714 else
715 return -EINVAL;
ffc06c35 716
9f6eb1cd
KS
717 return 0;
718}
ffc06c35 719
9f6eb1cd
KS
720static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
721 char type;
722 int r;
ffc06c35 723
9f6eb1cd
KS
724 r = sd_bus_message_peek_type(m, &type, NULL);
725 if (r < 0)
726 return r;
ffc06c35 727
9f6eb1cd
KS
728 switch (type) {
729 case SD_BUS_TYPE_STRING: {
730 const char *s;
731 char *str;
732 char **p = userdata;
ffc06c35 733
9f6eb1cd
KS
734 r = sd_bus_message_read_basic(m, type, &s);
735 if (r < 0)
736 break;
ffc06c35 737
9f6eb1cd
KS
738 if (isempty(s))
739 break;
ffc06c35 740
9f6eb1cd
KS
741 str = strdup(s);
742 if (!str) {
743 r = -ENOMEM;
ffc06c35
KS
744 break;
745 }
9f6eb1cd
KS
746 free(*p);
747 *p = str;
ffc06c35 748
9f6eb1cd
KS
749 break;
750 }
ffc06c35 751
9f6eb1cd
KS
752 case SD_BUS_TYPE_ARRAY: {
753 _cleanup_strv_free_ char **l = NULL;
754 char ***p = userdata;
ffc06c35 755
9f6eb1cd
KS
756 r = bus_message_read_strv_extend(m, &l);
757 if (r < 0)
758 break;
ffc06c35 759
9f6eb1cd
KS
760 strv_free(*p);
761 *p = l;
762 l = NULL;
ffc06c35 763
9f6eb1cd
KS
764 break;
765 }
ffc06c35 766
9f6eb1cd
KS
767 case SD_BUS_TYPE_BOOLEAN: {
768 unsigned b;
769 bool *p = userdata;
ffc06c35 770
9f6eb1cd
KS
771 r = sd_bus_message_read_basic(m, type, &b);
772 if (r < 0)
773 break;
ffc06c35 774
9f6eb1cd 775 *p = b;
ffc06c35 776
9f6eb1cd
KS
777 break;
778 }
ffc06c35 779
9f6eb1cd
KS
780 case SD_BUS_TYPE_UINT32: {
781 uint64_t u;
782 uint32_t *p = userdata;
783
784 r = sd_bus_message_read_basic(m, type, &u);
785 if (r < 0)
ffc06c35 786 break;
ffc06c35 787
9f6eb1cd
KS
788 *p = u;
789
790 break;
791 }
792
793 case SD_BUS_TYPE_UINT64: {
794 uint64_t t;
795 uint64_t *p = userdata;
796
797 r = sd_bus_message_read_basic(m, type, &t);
798 if (r < 0)
ffc06c35 799 break;
ffc06c35 800
9f6eb1cd
KS
801 *p = t;
802
803 break;
804 }
805
806 default:
807 break;
808 }
809
810 return r;
811}
812
813int bus_map_all_properties(sd_bus *bus,
814 const char *destination,
815 const char *path,
816 const struct bus_properties_map *map,
817 void *userdata) {
818 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
819 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
820 int r;
821
822 assert(bus);
823 assert(destination);
824 assert(path);
825 assert(map);
826
827 r = sd_bus_call_method( bus,
828 destination,
829 path,
830 "org.freedesktop.DBus.Properties",
831 "GetAll",
832 &error,
833 &m,
834 "s", "");
835 if (r < 0)
836 return r;
837
838 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
839 if (r < 0)
840 return r;
841
842 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
843 const struct bus_properties_map *prop;
844 const char *member;
845 const char *contents;
846 void *v;
847 unsigned i;
848
849 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
850 if (r < 0)
851 return r;
852
9f6eb1cd
KS
853 for (i = 0, prop = NULL; map[i].member; i++)
854 if (streq(map[i].member, member)) {
855 prop = &map[i];
856 break;
857 }
858
859 if (prop) {
860 r = sd_bus_message_peek_type(m, NULL, &contents);
861 if (r < 0)
862 return r;
863
864 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
865 if (r < 0)
866 return r;
867
868 v = (uint8_t *)userdata + prop->offset;
869 if (map[i].set)
870 r = prop->set(bus, member, m, &error, v);
871 else
872 r = map_basic(bus, member, m, &error, v);
873
874 r = sd_bus_message_exit_container(m);
875 if (r < 0)
876 return r;
877 } else {
878 r = sd_bus_message_skip(m, "v");
879 if (r < 0)
880 return -r;
881 }
882
ffc06c35
KS
883 r = sd_bus_message_exit_container(m);
884 if (r < 0)
885 return r;
886 }
887
ffc06c35
KS
888 return r;
889}
890
d21ed1ea
LP
891int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
892 int r;
893
894 assert(transport >= 0);
895 assert(transport < _BUS_TRANSPORT_MAX);
896 assert(bus);
897
898 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
899 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
900
901 switch (transport) {
902
903 case BUS_TRANSPORT_LOCAL:
904 if (user)
905 r = sd_bus_open_user(bus);
906 else
907 r = sd_bus_open_system(bus);
908
909 break;
910
911 case BUS_TRANSPORT_REMOTE:
912 r = sd_bus_open_system_remote(host, bus);
913 break;
914
915 case BUS_TRANSPORT_CONTAINER:
916 r = sd_bus_open_system_container(host, bus);
917 break;
918
919 default:
920 assert_not_reached("Hmm, unknown transport type.");
921 }
922
923 return r;
924}
e6504030
LP
925
926int bus_property_get_bool(
927 sd_bus *bus,
928 const char *path,
929 const char *interface,
930 const char *property,
931 sd_bus_message *reply,
932 sd_bus_error *error,
933 void *userdata) {
934
935 int b = *(bool*) userdata;
936
937 return sd_bus_message_append_basic(reply, 'b', &b);
938}
939
940int bus_property_get_uid(
941 sd_bus *bus,
942 const char *path,
943 const char *interface,
944 const char *property,
945 sd_bus_message *reply,
946 sd_bus_error *error,
947 void *userdata) {
948
949 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
950 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
951 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
952
953 return sd_bus_message_append_basic(reply, 'u', userdata);
954}