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