]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-util.c
systemctl: make sure daemon-reload returns success
[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;
102d8f81 154 int 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) {
102d8f81 273 int 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
41dd15e4
LP
443int bus_open_user_systemd(sd_bus **_bus) {
444 _cleanup_bus_unref_ sd_bus *bus = NULL;
445 _cleanup_free_ char *p = NULL;
446 const char *e;
447 int r;
448
449 /* If we are supposed to talk to the instance, try via
450 * XDG_RUNTIME_DIR first, then fallback to normal bus
451 * access */
452
453 assert(_bus);
454
455 e = secure_getenv("XDG_RUNTIME_DIR");
456 if (e) {
457 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
458 return -ENOMEM;
459 }
460
461 r = sd_bus_new(&bus);
462 if (r < 0)
463 return r;
464
465 r = sd_bus_set_address(bus, p);
466 if (r < 0)
467 return r;
468
469 r = sd_bus_start(bus);
470 if (r < 0)
471 return r;
472
473 r = bus_check_peercred(bus);
474 if (r < 0)
475 return r;
476
477 *_bus = bus;
478 bus = NULL;
479
480 return 0;
481}
482
9f6eb1cd 483int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
484 char type;
485 const char *contents;
9f6eb1cd 486 int r;
a1da8583
TG
487
488 assert(name);
489 assert(property);
490
9f6eb1cd
KS
491 r = sd_bus_message_peek_type(property, &type, &contents);
492 if (r < 0)
493 return r;
a1da8583
TG
494
495 switch (type) {
496
497 case SD_BUS_TYPE_STRING: {
498 const char *s;
9f6eb1cd
KS
499
500 r = sd_bus_message_read_basic(property, type, &s);
501 if (r < 0)
502 return r;
a1da8583
TG
503
504 if (all || !isempty(s))
505 printf("%s=%s\n", name, s);
506
507 return 1;
508 }
509
510 case SD_BUS_TYPE_BOOLEAN: {
511 bool b;
512
9f6eb1cd
KS
513 r = sd_bus_message_read_basic(property, type, &b);
514 if (r < 0)
515 return r;
516
a1da8583
TG
517 printf("%s=%s\n", name, yes_no(b));
518
519 return 1;
520 }
521
522 case SD_BUS_TYPE_UINT64: {
523 uint64_t u;
524
9f6eb1cd
KS
525 r = sd_bus_message_read_basic(property, type, &u);
526 if (r < 0)
527 return r;
a1da8583
TG
528
529 /* Yes, heuristics! But we can change this check
530 * should it turn out to not be sufficient */
531
532 if (endswith(name, "Timestamp")) {
533 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
534
535 t = format_timestamp(timestamp, sizeof(timestamp), u);
536 if (t || all)
537 printf("%s=%s\n", name, strempty(t));
538
539 } else if (strstr(name, "USec")) {
540 char timespan[FORMAT_TIMESPAN_MAX];
541
542 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
543 } else
544 printf("%s=%llu\n", name, (unsigned long long) u);
545
546 return 1;
547 }
548
549 case SD_BUS_TYPE_UINT32: {
550 uint32_t u;
551
9f6eb1cd
KS
552 r = sd_bus_message_read_basic(property, type, &u);
553 if (r < 0)
554 return r;
a1da8583
TG
555
556 if (strstr(name, "UMask") || strstr(name, "Mode"))
557 printf("%s=%04o\n", name, u);
558 else
559 printf("%s=%u\n", name, (unsigned) u);
560
561 return 1;
562 }
563
564 case SD_BUS_TYPE_INT32: {
565 int32_t i;
566
9f6eb1cd
KS
567 r = sd_bus_message_read_basic(property, type, &i);
568 if (r < 0)
569 return r;
a1da8583
TG
570
571 printf("%s=%i\n", name, (int) i);
572 return 1;
573 }
574
575 case SD_BUS_TYPE_DOUBLE: {
576 double d;
577
9f6eb1cd
KS
578 r = sd_bus_message_read_basic(property, type, &d);
579 if (r < 0)
580 return r;
a1da8583
TG
581
582 printf("%s=%g\n", name, d);
583 return 1;
584 }
585
586 case SD_BUS_TYPE_ARRAY:
a1da8583 587 if (streq(contents, "s")) {
261afec5
MAP
588 bool first = true;
589 const char *str;
a1da8583 590
9f6eb1cd
KS
591 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
592 if (r < 0)
593 return r;
594
261afec5
MAP
595 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
596 if (first)
597 printf("%s=", name);
598
599 printf("%s%s", first ? "" : " ", str);
600
601 first = false;
602 }
9f6eb1cd
KS
603 if (r < 0)
604 return r;
a1da8583 605
261afec5 606 if (first && all)
a1da8583 607 printf("%s=", name);
261afec5 608 if (!first || all)
a1da8583 609 puts("");
a1da8583 610
9f6eb1cd
KS
611 r = sd_bus_message_exit_container(property);
612 if (r < 0)
613 return r;
a1da8583
TG
614
615 return 1;
616
617 } else if (streq(contents, "y")) {
618 const uint8_t *u;
619 size_t n;
620
9f6eb1cd
KS
621 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
622 if (r < 0)
623 return r;
624
a1da8583
TG
625 if (all || n > 0) {
626 unsigned int i;
627
628 printf("%s=", name);
629
630 for (i = 0; i < n; i++)
631 printf("%02x", u[i]);
632
633 puts("");
634 }
635
636 return 1;
637
638 } else if (streq(contents, "u")) {
639 uint32_t *u;
640 size_t n;
641
9f6eb1cd
KS
642 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
643 if (r < 0)
644 return r;
645
a1da8583
TG
646 if (all || n > 0) {
647 unsigned int i;
648
649 printf("%s=", name);
650
651 for (i = 0; i < n; i++)
652 printf("%08x", u[i]);
653
654 puts("");
655 }
656
657 return 1;
658 }
659
660 break;
661 }
662
663 return 0;
664}
d21ed1ea 665
27e72d6b 666int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 667 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
668 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
669 int r;
670
9f6eb1cd
KS
671 assert(bus);
672 assert(path);
673
674 r = sd_bus_call_method(bus,
27e72d6b 675 dest,
ffc06c35
KS
676 path,
677 "org.freedesktop.DBus.Properties",
678 "GetAll",
679 &error,
9f6eb1cd 680 &reply,
ffc06c35 681 "s", "");
9f6eb1cd 682 if (r < 0)
ffc06c35 683 return r;
ffc06c35 684
9f6eb1cd 685 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
686 if (r < 0)
687 return r;
688
9f6eb1cd 689 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 690 const char *name;
ffc06c35 691 const char *contents;
ffc06c35 692
9f6eb1cd 693 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
694 if (r < 0)
695 return r;
696
9f6eb1cd
KS
697 if (!filter || strv_find(filter, name)) {
698 r = sd_bus_message_peek_type(reply, NULL, &contents);
699 if (r < 0)
700 return r;
701
702 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
703 if (r < 0)
704 return r;
ffc06c35 705
9f6eb1cd
KS
706 r = bus_print_property(name, reply, all);
707 if (r < 0)
708 return r;
27e72d6b
SP
709 if (r == 0) {
710 if (all)
711 printf("%s=[unprintable]\n", name);
712 /* skip what we didn't read */
713 r = sd_bus_message_skip(reply, contents);
714 if (r < 0)
715 return r;
716 }
9f6eb1cd
KS
717
718 r = sd_bus_message_exit_container(reply);
719 if (r < 0)
720 return r;
721 } else {
722 r = sd_bus_message_skip(reply, "v");
723 if (r < 0)
724 return r;
725 }
726
727 r = sd_bus_message_exit_container(reply);
ffc06c35
KS
728 if (r < 0)
729 return r;
9f6eb1cd
KS
730 }
731 if (r < 0)
732 return r;
ffc06c35 733
9f6eb1cd
KS
734 r = sd_bus_message_exit_container(reply);
735 if (r < 0)
736 return r;
ffc06c35 737
9f6eb1cd
KS
738 return 0;
739}
ffc06c35 740
9f6eb1cd
KS
741int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
742 sd_id128_t *p = userdata;
743 const void *v;
744 size_t n;
745 int r;
ffc06c35 746
9f6eb1cd
KS
747 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
748 if (r < 0)
749 return r;
ffc06c35 750
9f6eb1cd
KS
751 if (n == 0)
752 *p = SD_ID128_NULL;
753 else if (n == 16)
754 memcpy((*p).bytes, v, n);
755 else
756 return -EINVAL;
ffc06c35 757
9f6eb1cd
KS
758 return 0;
759}
ffc06c35 760
9f6eb1cd
KS
761static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
762 char type;
763 int r;
ffc06c35 764
9f6eb1cd
KS
765 r = sd_bus_message_peek_type(m, &type, NULL);
766 if (r < 0)
767 return r;
ffc06c35 768
9f6eb1cd
KS
769 switch (type) {
770 case SD_BUS_TYPE_STRING: {
771 const char *s;
772 char *str;
773 char **p = userdata;
ffc06c35 774
9f6eb1cd
KS
775 r = sd_bus_message_read_basic(m, type, &s);
776 if (r < 0)
777 break;
ffc06c35 778
9f6eb1cd
KS
779 if (isempty(s))
780 break;
ffc06c35 781
9f6eb1cd
KS
782 str = strdup(s);
783 if (!str) {
784 r = -ENOMEM;
ffc06c35
KS
785 break;
786 }
9f6eb1cd
KS
787 free(*p);
788 *p = str;
ffc06c35 789
9f6eb1cd
KS
790 break;
791 }
ffc06c35 792
9f6eb1cd
KS
793 case SD_BUS_TYPE_ARRAY: {
794 _cleanup_strv_free_ char **l = NULL;
795 char ***p = userdata;
ffc06c35 796
9f6eb1cd
KS
797 r = bus_message_read_strv_extend(m, &l);
798 if (r < 0)
799 break;
ffc06c35 800
9f6eb1cd
KS
801 strv_free(*p);
802 *p = l;
803 l = NULL;
ffc06c35 804
9f6eb1cd
KS
805 break;
806 }
ffc06c35 807
9f6eb1cd
KS
808 case SD_BUS_TYPE_BOOLEAN: {
809 unsigned b;
810 bool *p = userdata;
ffc06c35 811
9f6eb1cd
KS
812 r = sd_bus_message_read_basic(m, type, &b);
813 if (r < 0)
814 break;
ffc06c35 815
9f6eb1cd 816 *p = b;
ffc06c35 817
9f6eb1cd
KS
818 break;
819 }
ffc06c35 820
9f6eb1cd
KS
821 case SD_BUS_TYPE_UINT32: {
822 uint64_t u;
823 uint32_t *p = userdata;
824
825 r = sd_bus_message_read_basic(m, type, &u);
826 if (r < 0)
ffc06c35 827 break;
ffc06c35 828
9f6eb1cd
KS
829 *p = u;
830
831 break;
832 }
833
834 case SD_BUS_TYPE_UINT64: {
835 uint64_t t;
836 uint64_t *p = userdata;
837
838 r = sd_bus_message_read_basic(m, type, &t);
839 if (r < 0)
ffc06c35 840 break;
ffc06c35 841
9f6eb1cd
KS
842 *p = t;
843
844 break;
845 }
846
847 default:
848 break;
849 }
850
851 return r;
852}
853
854int bus_map_all_properties(sd_bus *bus,
855 const char *destination,
856 const char *path,
857 const struct bus_properties_map *map,
858 void *userdata) {
859 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
860 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
861 int r;
862
863 assert(bus);
864 assert(destination);
865 assert(path);
866 assert(map);
867
868 r = sd_bus_call_method( bus,
869 destination,
870 path,
871 "org.freedesktop.DBus.Properties",
872 "GetAll",
873 &error,
874 &m,
875 "s", "");
876 if (r < 0)
877 return r;
878
879 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
880 if (r < 0)
881 return r;
882
883 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
884 const struct bus_properties_map *prop;
885 const char *member;
886 const char *contents;
887 void *v;
888 unsigned i;
889
890 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
891 if (r < 0)
892 return r;
893
9f6eb1cd
KS
894 for (i = 0, prop = NULL; map[i].member; i++)
895 if (streq(map[i].member, member)) {
896 prop = &map[i];
897 break;
898 }
899
900 if (prop) {
901 r = sd_bus_message_peek_type(m, NULL, &contents);
902 if (r < 0)
903 return r;
904
905 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
906 if (r < 0)
907 return r;
908
909 v = (uint8_t *)userdata + prop->offset;
27e72d6b 910 if (map[i].set)
9f6eb1cd
KS
911 r = prop->set(bus, member, m, &error, v);
912 else
913 r = map_basic(bus, member, m, &error, v);
914
915 r = sd_bus_message_exit_container(m);
916 if (r < 0)
917 return r;
918 } else {
919 r = sd_bus_message_skip(m, "v");
920 if (r < 0)
921 return -r;
922 }
923
ffc06c35
KS
924 r = sd_bus_message_exit_container(m);
925 if (r < 0)
926 return r;
927 }
928
ffc06c35
KS
929 return r;
930}
931
d21ed1ea
LP
932int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
933 int r;
934
935 assert(transport >= 0);
936 assert(transport < _BUS_TRANSPORT_MAX);
937 assert(bus);
938
939 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
940 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
941
942 switch (transport) {
943
944 case BUS_TRANSPORT_LOCAL:
945 if (user)
946 r = sd_bus_open_user(bus);
947 else
948 r = sd_bus_open_system(bus);
949
950 break;
951
952 case BUS_TRANSPORT_REMOTE:
953 r = sd_bus_open_system_remote(host, bus);
41dd15e4
LP
954 break;
955
956 case BUS_TRANSPORT_CONTAINER:
957 r = sd_bus_open_system_container(host, bus);
958 break;
959
960 default:
961 assert_not_reached("Hmm, unknown transport type.");
962 }
963
964 return r;
965}
966
967int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
968 int r;
969
970 assert(transport >= 0);
971 assert(transport < _BUS_TRANSPORT_MAX);
972 assert(bus);
973
974 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
975 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
976
977 switch (transport) {
978
979 case BUS_TRANSPORT_LOCAL:
980 if (user)
981 r = bus_open_user_systemd(bus);
982 else
983 r = bus_open_system_systemd(bus);
984
985 break;
986
987 case BUS_TRANSPORT_REMOTE:
988 r = sd_bus_open_system_remote(host, bus);
d21ed1ea
LP
989 break;
990
991 case BUS_TRANSPORT_CONTAINER:
992 r = sd_bus_open_system_container(host, bus);
993 break;
994
995 default:
996 assert_not_reached("Hmm, unknown transport type.");
997 }
998
999 return r;
1000}
e6504030
LP
1001
1002int bus_property_get_bool(
1003 sd_bus *bus,
1004 const char *path,
1005 const char *interface,
1006 const char *property,
1007 sd_bus_message *reply,
1008 sd_bus_error *error,
1009 void *userdata) {
1010
1011 int b = *(bool*) userdata;
1012
1013 return sd_bus_message_append_basic(reply, 'b', &b);
1014}
1015
1016int bus_property_get_uid(
1017 sd_bus *bus,
1018 const char *path,
1019 const char *interface,
1020 const char *property,
1021 sd_bus_message *reply,
1022 sd_bus_error *error,
1023 void *userdata) {
1024
1025 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
1026 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
1027 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
1028
1029 return sd_bus_message_append_basic(reply, 'u', userdata);
1030}
5b30bef8
LP
1031
1032int bus_log_parse_error(int r) {
1033 log_error("Failed to parse message: %s", strerror(-r));
1034 return r;
1035}
f459b602
MAP
1036
1037int bus_log_create_error(int r) {
1038 log_error("Failed to create message: %s", strerror(-r));
1039 return r;
1040}
1041
1042int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1043 assert(message);
1044 assert(u);
1045
1046 return sd_bus_message_read(
1047 message,
1048 "(ssssssouso)",
1049 &u->id,
1050 &u->description,
1051 &u->load_state,
1052 &u->active_state,
1053 &u->sub_state,
1054 &u->following,
1055 &u->unit_path,
1056 &u->job_id,
1057 &u->job_type,
1058 &u->job_path);
1059}