]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-util.c
hostnamed: modernizations
[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"
2bba9a57 28#include "missing.h"
40ca29a1 29
ffc06c35
KS
30#include "sd-event.h"
31#include "sd-bus.h"
32#include "bus-error.h"
33#include "bus-message.h"
34
40ca29a1
LP
35#include "bus-util.h"
36
37static 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
48int 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
74int 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
abc5fe72 90 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
40ca29a1
LP
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
106int 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
125int 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;
102d8f81 155 int authorized = false, challenge = false;
40ca29a1
LP
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
313333b4
LP
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);
40ca29a1
LP
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
201typedef 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
208static 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
233static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
234
235 if (!q)
236 return;
237
238 if (q->serial > 0 && b)
c49b30a2 239 sd_bus_call_async_cancel(b, q->serial);
40ca29a1
LP
240
241 sd_bus_message_unref(q->request);
242 sd_bus_message_unref(q->reply);
243 free(q);
244}
245
246#endif
247
248int 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) {
102d8f81 274 int authorized, challenge;
40ca29a1
LP
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
c49b30a2 365 r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
40ca29a1
LP
366 if (r < 0)
367 return r;
368
369 return 0;
370#endif
371
372 return -EACCES;
373}
374
375void 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}
0c842e0a 385
718db961 386int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
387 struct ucred ucred;
388 socklen_t l;
0f8bd8de 389 int fd;
0c842e0a
TG
390
391 assert(c);
392
393 fd = sd_bus_get_fd(c);
0f8bd8de
LP
394 if (fd < 0)
395 return fd;
0c842e0a
TG
396
397 l = sizeof(struct ucred);
0f8bd8de 398 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 399 return -errno;
0c842e0a 400
0f8bd8de 401 if (l != sizeof(struct ucred))
0c842e0a 402 return -E2BIG;
0c842e0a
TG
403
404 if (ucred.uid != 0 && ucred.uid != geteuid())
405 return -EPERM;
406
407 return 1;
408}
409
0f8bd8de
LP
410int bus_open_system_systemd(sd_bus **_bus) {
411 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 412 int r;
0c842e0a
TG
413
414 assert(_bus);
415
0f8bd8de
LP
416 if (geteuid() != 0)
417 return sd_bus_open_system(_bus);
a1da8583 418
0f8bd8de
LP
419 /* If we are root, then let's talk directly to the system
420 * instance, instead of going via the bus */
a1da8583 421
0f8bd8de
LP
422 r = sd_bus_new(&bus);
423 if (r < 0)
424 return r;
a1da8583 425
0f8bd8de
LP
426 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
427 if (r < 0)
428 return r;
a1da8583 429
0f8bd8de
LP
430 r = sd_bus_start(bus);
431 if (r < 0)
432 return r;
a1da8583 433
0f8bd8de 434 r = bus_check_peercred(bus);
a1da8583
TG
435 if (r < 0)
436 return r;
437
438 *_bus = bus;
0f8bd8de
LP
439 bus = NULL;
440
a1da8583
TG
441 return 0;
442}
443
41dd15e4
LP
444int 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
9f6eb1cd 484int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
485 char type;
486 const char *contents;
9f6eb1cd 487 int r;
a1da8583
TG
488
489 assert(name);
490 assert(property);
491
9f6eb1cd
KS
492 r = sd_bus_message_peek_type(property, &type, &contents);
493 if (r < 0)
494 return r;
a1da8583
TG
495
496 switch (type) {
497
498 case SD_BUS_TYPE_STRING: {
499 const char *s;
9f6eb1cd
KS
500
501 r = sd_bus_message_read_basic(property, type, &s);
502 if (r < 0)
503 return r;
a1da8583
TG
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
9f6eb1cd
KS
514 r = sd_bus_message_read_basic(property, type, &b);
515 if (r < 0)
516 return r;
517
a1da8583
TG
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
9f6eb1cd
KS
526 r = sd_bus_message_read_basic(property, type, &u);
527 if (r < 0)
528 return r;
a1da8583
TG
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
9f6eb1cd
KS
553 r = sd_bus_message_read_basic(property, type, &u);
554 if (r < 0)
555 return r;
a1da8583
TG
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
9f6eb1cd
KS
568 r = sd_bus_message_read_basic(property, type, &i);
569 if (r < 0)
570 return r;
a1da8583
TG
571
572 printf("%s=%i\n", name, (int) i);
573 return 1;
574 }
575
576 case SD_BUS_TYPE_DOUBLE: {
577 double d;
578
9f6eb1cd
KS
579 r = sd_bus_message_read_basic(property, type, &d);
580 if (r < 0)
581 return r;
a1da8583
TG
582
583 printf("%s=%g\n", name, d);
584 return 1;
585 }
586
587 case SD_BUS_TYPE_ARRAY:
a1da8583 588 if (streq(contents, "s")) {
261afec5
MAP
589 bool first = true;
590 const char *str;
a1da8583 591
9f6eb1cd
KS
592 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
593 if (r < 0)
594 return r;
595
261afec5
MAP
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 }
9f6eb1cd
KS
604 if (r < 0)
605 return r;
a1da8583 606
261afec5 607 if (first && all)
a1da8583 608 printf("%s=", name);
261afec5 609 if (!first || all)
a1da8583 610 puts("");
a1da8583 611
9f6eb1cd
KS
612 r = sd_bus_message_exit_container(property);
613 if (r < 0)
614 return r;
a1da8583
TG
615
616 return 1;
617
618 } else if (streq(contents, "y")) {
619 const uint8_t *u;
620 size_t n;
621
9f6eb1cd
KS
622 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
623 if (r < 0)
624 return r;
625
a1da8583
TG
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
9f6eb1cd
KS
643 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
644 if (r < 0)
645 return r;
646
a1da8583
TG
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}
d21ed1ea 666
27e72d6b 667int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 668 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
669 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
670 int r;
671
9f6eb1cd
KS
672 assert(bus);
673 assert(path);
674
675 r = sd_bus_call_method(bus,
27e72d6b 676 dest,
ffc06c35
KS
677 path,
678 "org.freedesktop.DBus.Properties",
679 "GetAll",
680 &error,
9f6eb1cd 681 &reply,
ffc06c35 682 "s", "");
9f6eb1cd 683 if (r < 0)
ffc06c35 684 return r;
ffc06c35 685
9f6eb1cd 686 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
687 if (r < 0)
688 return r;
689
9f6eb1cd 690 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 691 const char *name;
ffc06c35 692 const char *contents;
ffc06c35 693
9f6eb1cd 694 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
695 if (r < 0)
696 return r;
697
9f6eb1cd
KS
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;
ffc06c35 706
9f6eb1cd
KS
707 r = bus_print_property(name, reply, all);
708 if (r < 0)
709 return r;
27e72d6b
SP
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 }
9f6eb1cd
KS
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);
ffc06c35
KS
729 if (r < 0)
730 return r;
9f6eb1cd
KS
731 }
732 if (r < 0)
733 return r;
ffc06c35 734
9f6eb1cd
KS
735 r = sd_bus_message_exit_container(reply);
736 if (r < 0)
737 return r;
ffc06c35 738
9f6eb1cd
KS
739 return 0;
740}
ffc06c35 741
9f6eb1cd
KS
742int 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;
ffc06c35 747
9f6eb1cd
KS
748 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
749 if (r < 0)
750 return r;
ffc06c35 751
9f6eb1cd
KS
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;
ffc06c35 758
9f6eb1cd
KS
759 return 0;
760}
ffc06c35 761
9f6eb1cd
KS
762static 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;
ffc06c35 765
9f6eb1cd
KS
766 r = sd_bus_message_peek_type(m, &type, NULL);
767 if (r < 0)
768 return r;
ffc06c35 769
9f6eb1cd
KS
770 switch (type) {
771 case SD_BUS_TYPE_STRING: {
772 const char *s;
773 char *str;
774 char **p = userdata;
ffc06c35 775
9f6eb1cd
KS
776 r = sd_bus_message_read_basic(m, type, &s);
777 if (r < 0)
778 break;
ffc06c35 779
9f6eb1cd
KS
780 if (isempty(s))
781 break;
ffc06c35 782
9f6eb1cd
KS
783 str = strdup(s);
784 if (!str) {
785 r = -ENOMEM;
ffc06c35
KS
786 break;
787 }
9f6eb1cd
KS
788 free(*p);
789 *p = str;
ffc06c35 790
9f6eb1cd
KS
791 break;
792 }
ffc06c35 793
9f6eb1cd
KS
794 case SD_BUS_TYPE_ARRAY: {
795 _cleanup_strv_free_ char **l = NULL;
796 char ***p = userdata;
ffc06c35 797
9f6eb1cd
KS
798 r = bus_message_read_strv_extend(m, &l);
799 if (r < 0)
800 break;
ffc06c35 801
9f6eb1cd
KS
802 strv_free(*p);
803 *p = l;
804 l = NULL;
ffc06c35 805
9f6eb1cd
KS
806 break;
807 }
ffc06c35 808
9f6eb1cd
KS
809 case SD_BUS_TYPE_BOOLEAN: {
810 unsigned b;
811 bool *p = userdata;
ffc06c35 812
9f6eb1cd
KS
813 r = sd_bus_message_read_basic(m, type, &b);
814 if (r < 0)
815 break;
ffc06c35 816
9f6eb1cd 817 *p = b;
ffc06c35 818
9f6eb1cd
KS
819 break;
820 }
ffc06c35 821
9f6eb1cd
KS
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)
ffc06c35 828 break;
ffc06c35 829
9f6eb1cd
KS
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)
ffc06c35 841 break;
ffc06c35 842
9f6eb1cd
KS
843 *p = t;
844
845 break;
846 }
847
848 default:
849 break;
850 }
851
852 return r;
853}
854
855int 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);
ffc06c35
KS
892 if (r < 0)
893 return r;
894
9f6eb1cd
KS
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;
27e72d6b 911 if (map[i].set)
9f6eb1cd
KS
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)
6c1508b8 922 return r;
9f6eb1cd
KS
923 }
924
ffc06c35
KS
925 r = sd_bus_message_exit_container(m);
926 if (r < 0)
927 return r;
928 }
929
ffc06c35
KS
930 return r;
931}
932
d21ed1ea
LP
933int 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)
76b54375 947 r = sd_bus_default_user(bus);
d21ed1ea 948 else
76b54375 949 r = sd_bus_default_system(bus);
d21ed1ea
LP
950
951 break;
952
953 case BUS_TRANSPORT_REMOTE:
954 r = sd_bus_open_system_remote(host, bus);
41dd15e4
LP
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
968int 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);
d21ed1ea
LP
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}
e6504030
LP
1002
1003int 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
718db961
LP
1017#if __SIZEOF_SIZE_T__ != 8
1018int bus_property_get_size(
e6504030
LP
1019 sd_bus *bus,
1020 const char *path,
1021 const char *interface,
1022 const char *property,
1023 sd_bus_message *reply,
1024 sd_bus_error *error,
1025 void *userdata) {
1026
718db961 1027 uint64_t sz = *(size_t*) userdata;
e6504030 1028
718db961 1029 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1030}
718db961
LP
1031#endif
1032
1033#if __SIZEOF_LONG__ != 8
1034int bus_property_get_long(
1035 sd_bus *bus,
1036 const char *path,
1037 const char *interface,
1038 const char *property,
1039 sd_bus_message *reply,
1040 sd_bus_error *error,
1041 void *userdata) {
1042
1043 int64_t l = *(long*) userdata;
1044
1045 return sd_bus_message_append_basic(reply, 'x', &l);
1046}
1047
1048int bus_property_get_ulong(
1049 sd_bus *bus,
1050 const char *path,
1051 const char *interface,
1052 const char *property,
1053 sd_bus_message *reply,
1054 sd_bus_error *error,
1055 void *userdata) {
1056
1057 uint64_t ul = *(unsigned long*) userdata;
1058
1059 return sd_bus_message_append_basic(reply, 't', &ul);
1060}
1061#endif
5b30bef8
LP
1062
1063int bus_log_parse_error(int r) {
1064 log_error("Failed to parse message: %s", strerror(-r));
1065 return r;
1066}
f459b602
MAP
1067
1068int bus_log_create_error(int r) {
1069 log_error("Failed to create message: %s", strerror(-r));
1070 return r;
1071}
1072
1073int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1074 assert(message);
1075 assert(u);
1076
1077 return sd_bus_message_read(
1078 message,
1079 "(ssssssouso)",
1080 &u->id,
1081 &u->description,
1082 &u->load_state,
1083 &u->active_state,
1084 &u->sub_state,
1085 &u->following,
1086 &u->unit_path,
1087 &u->job_id,
1088 &u->job_type,
1089 &u->job_path);
1090}