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