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