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