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