]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-util.c
udev: net-config - allow interface names to be set from the hwdb
[thirdparty/systemd.git] / src / libsystemd / sd-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
37224a5f
LP
90int 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) {
40ca29a1 97 bool exiting = false;
6203e07a 98 int r, code;
40ca29a1
LP
99
100 assert(e);
101 assert(bus);
102 assert(name);
103
104 for (;;) {
37224a5f
LP
105 bool idle;
106
40ca29a1
LP
107 r = sd_event_get_state(e);
108 if (r < 0)
109 return r;
40ca29a1
LP
110 if (r == SD_EVENT_FINISHED)
111 break;
112
37224a5f
LP
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);
40ca29a1
LP
119 if (r < 0)
120 return r;
121
122 if (r == 0 && !exiting) {
6203e07a 123 r = bus_async_unregister_and_exit(e, bus, name);
40ca29a1
LP
124 if (r < 0)
125 return r;
126
127 exiting = true;
128 }
129 }
130
6203e07a
LP
131 r = sd_event_get_exit_code(e, &code);
132 if (r < 0)
133 return r;
134
135 return code;
40ca29a1
LP
136}
137
5fd38859
DH
138int 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
40ca29a1
LP
164int 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
5b12334d 172 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
40ca29a1
LP
173 uid_t uid;
174 int r;
175
176 assert(bus);
177 assert(m);
178 assert(action);
179
5b12334d
LP
180 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
181 if (r < 0)
182 return r;
40ca29a1 183
5b12334d 184 r = sd_bus_creds_get_uid(creds, &uid);
40ca29a1
LP
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;
102d8f81 194 int authorized = false, challenge = false;
5b12334d
LP
195 const char *sender;
196
197 sender = sd_bus_message_get_sender(m);
198 if (!sender)
199 return -EBADMSG;
40ca29a1
LP
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
313333b4 226 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
2b49a470
TA
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;
40ca29a1
LP
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
249typedef struct AsyncPolkitQuery {
250 sd_bus_message *request, *reply;
251 sd_bus_message_handler_t callback;
252 void *userdata;
253 uint64_t serial;
ebcf1f97 254 Hashmap *registry;
40ca29a1
LP
255} AsyncPolkitQuery;
256
ebcf1f97
LP
257static 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
274static 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;
ebcf1f97 276 AsyncPolkitQuery *q = userdata;
40ca29a1
LP
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
ebcf1f97
LP
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 }
40ca29a1 291
ebcf1f97
LP
292 r = q->callback(bus, q->request, q->userdata, &error_buffer);
293 r = bus_maybe_reply_error(q->request, r, &error_buffer);
40ca29a1 294
ebcf1f97
LP
295finish:
296 async_polkit_query_free(bus, q);
297 return r;
40ca29a1
LP
298}
299
300#endif
301
302int 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;
40ca29a1 315 const char *sender;
5b12334d
LP
316#endif
317 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
40ca29a1
LP
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
ebcf1f97 327 q = hashmap_get(*registry, m);
40ca29a1 328 if (q) {
102d8f81 329 int authorized, challenge;
40ca29a1
LP
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
ebcf1f97 339 /* Copy error from polkit reply */
40ca29a1
LP
340 e = sd_bus_message_get_error(q->reply);
341 sd_bus_error_copy(error, e);
40ca29a1 342
ebcf1f97
LP
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
5958d089 347 return -sd_bus_error_get_errno(e);
40ca29a1
LP
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
40ca29a1
LP
354 if (r < 0)
355 return r;
356
357 if (authorized)
358 return 1;
359
360 return -EACCES;
361 }
362#endif
363
5b12334d
LP
364 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
365 if (r < 0)
366 return r;
40ca29a1 367
5b12334d 368 r = sd_bus_creds_get_uid(creds, &uid);
40ca29a1
LP
369 if (r < 0)
370 return r;
371
372 if (uid == 0)
373 return 1;
5b12334d 374
40ca29a1 375#ifdef ENABLE_POLKIT
5b12334d
LP
376 sender = sd_bus_message_get_sender(m);
377 if (!sender)
378 return -EBADMSG;
40ca29a1
LP
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,
ebcf1f97 401 NULL);
40ca29a1
LP
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
ebcf1f97
LP
419 q->registry = *registry;
420
c49b30a2 421 r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
ebcf1f97
LP
422 if (r < 0) {
423 async_polkit_query_free(bus, q);
40ca29a1 424 return r;
ebcf1f97 425 }
40ca29a1
LP
426
427 return 0;
428#endif
429
430 return -EACCES;
431}
432
433void 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}
0c842e0a 443
718db961 444int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
445 struct ucred ucred;
446 socklen_t l;
0f8bd8de 447 int fd;
0c842e0a
TG
448
449 assert(c);
450
451 fd = sd_bus_get_fd(c);
0f8bd8de
LP
452 if (fd < 0)
453 return fd;
0c842e0a
TG
454
455 l = sizeof(struct ucred);
0f8bd8de 456 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 457 return -errno;
0c842e0a 458
0f8bd8de 459 if (l != sizeof(struct ucred))
0c842e0a 460 return -E2BIG;
0c842e0a
TG
461
462 if (ucred.uid != 0 && ucred.uid != geteuid())
463 return -EPERM;
464
465 return 1;
466}
467
0f8bd8de
LP
468int bus_open_system_systemd(sd_bus **_bus) {
469 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 470 int r;
0c842e0a
TG
471
472 assert(_bus);
473
0f8bd8de
LP
474 if (geteuid() != 0)
475 return sd_bus_open_system(_bus);
a1da8583 476
a6aa8912
LP
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 */
a1da8583 480
a6aa8912 481#ifdef ENABLE_KDBUS
0f8bd8de
LP
482 r = sd_bus_new(&bus);
483 if (r < 0)
484 return r;
a1da8583 485
ab9001a1 486 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH);
0f8bd8de
LP
487 if (r < 0)
488 return r;
a1da8583 489
a6aa8912
LP
490 bus->bus_client = true;
491
0f8bd8de 492 r = sd_bus_start(bus);
a6aa8912
LP
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);
0f8bd8de
LP
503 if (r < 0)
504 return r;
a1da8583 505
a6aa8912
LP
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
0f8bd8de 514 r = bus_check_peercred(bus);
a1da8583
TG
515 if (r < 0)
516 return r;
517
518 *_bus = bus;
0f8bd8de
LP
519 bus = NULL;
520
a1da8583
TG
521 return 0;
522}
523
41dd15e4
LP
524int bus_open_user_systemd(sd_bus **_bus) {
525 _cleanup_bus_unref_ sd_bus *bus = NULL;
a6aa8912 526 _cleanup_free_ char *ee = NULL;
41dd15e4
LP
527 const char *e;
528 int r;
529
a6aa8912 530 /* Try via kdbus first, and then directly */
41dd15e4
LP
531
532 assert(_bus);
533
a6aa8912
LP
534#ifdef ENABLE_KDBUS
535 r = sd_bus_new(&bus);
536 if (r < 0)
537 return r;
538
ab9001a1 539 if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid()) < 0)
a6aa8912
LP
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
41dd15e4 554 e = secure_getenv("XDG_RUNTIME_DIR");
537220d9 555 if (!e)
3f78871b 556 return sd_bus_open_user(_bus);
537220d9 557
a6aa8912
LP
558 ee = bus_address_escape(e);
559 if (!ee)
537220d9 560 return -ENOMEM;
41dd15e4
LP
561
562 r = sd_bus_new(&bus);
563 if (r < 0)
564 return r;
565
a6aa8912
LP
566 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
567 if (!bus->address)
568 return -ENOMEM;
41dd15e4
LP
569
570 r = sd_bus_start(bus);
571 if (r < 0)
3f78871b 572 return sd_bus_open_user(_bus);
41dd15e4
LP
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
9f6eb1cd 584int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
585 char type;
586 const char *contents;
9f6eb1cd 587 int r;
a1da8583
TG
588
589 assert(name);
590 assert(property);
591
9f6eb1cd
KS
592 r = sd_bus_message_peek_type(property, &type, &contents);
593 if (r < 0)
594 return r;
a1da8583
TG
595
596 switch (type) {
597
598 case SD_BUS_TYPE_STRING: {
599 const char *s;
9f6eb1cd
KS
600
601 r = sd_bus_message_read_basic(property, type, &s);
602 if (r < 0)
603 return r;
a1da8583
TG
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
9f6eb1cd
KS
614 r = sd_bus_message_read_basic(property, type, &b);
615 if (r < 0)
616 return r;
617
a1da8583
TG
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
9f6eb1cd
KS
626 r = sd_bus_message_read_basic(property, type, &u);
627 if (r < 0)
628 return r;
a1da8583
TG
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
9f6eb1cd
KS
653 r = sd_bus_message_read_basic(property, type, &u);
654 if (r < 0)
655 return r;
a1da8583
TG
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
9f6eb1cd
KS
668 r = sd_bus_message_read_basic(property, type, &i);
669 if (r < 0)
670 return r;
a1da8583
TG
671
672 printf("%s=%i\n", name, (int) i);
673 return 1;
674 }
675
676 case SD_BUS_TYPE_DOUBLE: {
677 double d;
678
9f6eb1cd
KS
679 r = sd_bus_message_read_basic(property, type, &d);
680 if (r < 0)
681 return r;
a1da8583
TG
682
683 printf("%s=%g\n", name, d);
684 return 1;
685 }
686
687 case SD_BUS_TYPE_ARRAY:
a1da8583 688 if (streq(contents, "s")) {
261afec5
MAP
689 bool first = true;
690 const char *str;
a1da8583 691
9f6eb1cd
KS
692 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
693 if (r < 0)
694 return r;
695
261afec5
MAP
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 }
9f6eb1cd
KS
704 if (r < 0)
705 return r;
a1da8583 706
261afec5 707 if (first && all)
a1da8583 708 printf("%s=", name);
261afec5 709 if (!first || all)
a1da8583 710 puts("");
a1da8583 711
9f6eb1cd
KS
712 r = sd_bus_message_exit_container(property);
713 if (r < 0)
714 return r;
a1da8583
TG
715
716 return 1;
717
718 } else if (streq(contents, "y")) {
719 const uint8_t *u;
720 size_t n;
721
9f6eb1cd
KS
722 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
723 if (r < 0)
724 return r;
725
a1da8583
TG
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
9f6eb1cd
KS
743 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
744 if (r < 0)
745 return r;
746
a1da8583
TG
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}
d21ed1ea 766
27e72d6b 767int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 768 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
769 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
770 int r;
771
9f6eb1cd
KS
772 assert(bus);
773 assert(path);
774
775 r = sd_bus_call_method(bus,
27e72d6b 776 dest,
ffc06c35
KS
777 path,
778 "org.freedesktop.DBus.Properties",
779 "GetAll",
780 &error,
9f6eb1cd 781 &reply,
ffc06c35 782 "s", "");
9f6eb1cd 783 if (r < 0)
ffc06c35 784 return r;
ffc06c35 785
9f6eb1cd 786 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
787 if (r < 0)
788 return r;
789
9f6eb1cd 790 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 791 const char *name;
ffc06c35 792 const char *contents;
ffc06c35 793
9f6eb1cd 794 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
795 if (r < 0)
796 return r;
797
9f6eb1cd
KS
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;
ffc06c35 806
9f6eb1cd
KS
807 r = bus_print_property(name, reply, all);
808 if (r < 0)
809 return r;
27e72d6b
SP
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 }
9f6eb1cd
KS
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);
ffc06c35
KS
829 if (r < 0)
830 return r;
9f6eb1cd
KS
831 }
832 if (r < 0)
833 return r;
ffc06c35 834
9f6eb1cd
KS
835 r = sd_bus_message_exit_container(reply);
836 if (r < 0)
837 return r;
ffc06c35 838
9f6eb1cd
KS
839 return 0;
840}
ffc06c35 841
9f6eb1cd
KS
842int 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;
ffc06c35 847
9f6eb1cd
KS
848 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
849 if (r < 0)
850 return r;
ffc06c35 851
9f6eb1cd
KS
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;
ffc06c35 858
9f6eb1cd
KS
859 return 0;
860}
ffc06c35 861
9f6eb1cd
KS
862static 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;
ffc06c35 865
9f6eb1cd
KS
866 r = sd_bus_message_peek_type(m, &type, NULL);
867 if (r < 0)
868 return r;
ffc06c35 869
9f6eb1cd
KS
870 switch (type) {
871 case SD_BUS_TYPE_STRING: {
872 const char *s;
873 char *str;
874 char **p = userdata;
ffc06c35 875
9f6eb1cd
KS
876 r = sd_bus_message_read_basic(m, type, &s);
877 if (r < 0)
878 break;
ffc06c35 879
9f6eb1cd
KS
880 if (isempty(s))
881 break;
ffc06c35 882
9f6eb1cd
KS
883 str = strdup(s);
884 if (!str) {
885 r = -ENOMEM;
ffc06c35
KS
886 break;
887 }
9f6eb1cd
KS
888 free(*p);
889 *p = str;
ffc06c35 890
9f6eb1cd
KS
891 break;
892 }
ffc06c35 893
9f6eb1cd
KS
894 case SD_BUS_TYPE_ARRAY: {
895 _cleanup_strv_free_ char **l = NULL;
896 char ***p = userdata;
ffc06c35 897
9f6eb1cd
KS
898 r = bus_message_read_strv_extend(m, &l);
899 if (r < 0)
900 break;
ffc06c35 901
9f6eb1cd
KS
902 strv_free(*p);
903 *p = l;
904 l = NULL;
ffc06c35 905
9f6eb1cd
KS
906 break;
907 }
ffc06c35 908
9f6eb1cd
KS
909 case SD_BUS_TYPE_BOOLEAN: {
910 unsigned b;
911 bool *p = userdata;
ffc06c35 912
9f6eb1cd
KS
913 r = sd_bus_message_read_basic(m, type, &b);
914 if (r < 0)
915 break;
ffc06c35 916
9f6eb1cd 917 *p = b;
ffc06c35 918
9f6eb1cd
KS
919 break;
920 }
ffc06c35 921
9f6eb1cd
KS
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)
ffc06c35 928 break;
ffc06c35 929
9f6eb1cd
KS
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)
ffc06c35 941 break;
ffc06c35 942
9f6eb1cd
KS
943 *p = t;
944
945 break;
946 }
947
948 default:
949 break;
950 }
951
952 return r;
953}
954
955int 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
fe2b58a4
LP
969 r = sd_bus_call_method(
970 bus,
9f6eb1cd
KS
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);
ffc06c35
KS
993 if (r < 0)
994 return r;
995
9f6eb1cd
KS
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;
27e72d6b 1012 if (map[i].set)
9f6eb1cd
KS
1013 r = prop->set(bus, member, m, &error, v);
1014 else
1015 r = map_basic(bus, member, m, &error, v);
2b49a470
TA
1016 if (r < 0)
1017 return r;
9f6eb1cd
KS
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)
6c1508b8 1025 return r;
9f6eb1cd
KS
1026 }
1027
ffc06c35
KS
1028 r = sd_bus_message_exit_container(m);
1029 if (r < 0)
1030 return r;
1031 }
1032
ffc06c35
KS
1033 return r;
1034}
1035
d21ed1ea
LP
1036int 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)
76b54375 1050 r = sd_bus_default_user(bus);
d21ed1ea 1051 else
76b54375 1052 r = sd_bus_default_system(bus);
d21ed1ea
LP
1053
1054 break;
1055
1056 case BUS_TRANSPORT_REMOTE:
1057 r = sd_bus_open_system_remote(host, bus);
41dd15e4
LP
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
1071int 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);
d21ed1ea
LP
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}
e6504030 1105
ebcf1f97
LP
1106int 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
e6504030
LP
1120int 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,
ebcf1f97
LP
1126 void *userdata,
1127 sd_bus_error *error) {
e6504030
LP
1128
1129 int b = *(bool*) userdata;
1130
1131 return sd_bus_message_append_basic(reply, 'b', &b);
1132}
1133
718db961
LP
1134#if __SIZEOF_SIZE_T__ != 8
1135int bus_property_get_size(
e6504030
LP
1136 sd_bus *bus,
1137 const char *path,
1138 const char *interface,
1139 const char *property,
1140 sd_bus_message *reply,
ebcf1f97
LP
1141 void *userdata,
1142 sd_bus_error *error) {
e6504030 1143
718db961 1144 uint64_t sz = *(size_t*) userdata;
e6504030 1145
718db961 1146 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1147}
718db961
LP
1148#endif
1149
1150#if __SIZEOF_LONG__ != 8
1151int 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,
ebcf1f97
LP
1157 void *userdata,
1158 sd_bus_error *error) {
718db961
LP
1159
1160 int64_t l = *(long*) userdata;
1161
1162 return sd_bus_message_append_basic(reply, 'x', &l);
1163}
1164
1165int 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,
ebcf1f97
LP
1171 void *userdata,
1172 sd_bus_error *error) {
718db961
LP
1173
1174 uint64_t ul = *(unsigned long*) userdata;
1175
1176 return sd_bus_message_append_basic(reply, 't', &ul);
1177}
1178#endif
5b30bef8
LP
1179
1180int bus_log_parse_error(int r) {
1181 log_error("Failed to parse message: %s", strerror(-r));
1182 return r;
1183}
f459b602
MAP
1184
1185int bus_log_create_error(int r) {
1186 log_error("Failed to create message: %s", strerror(-r));
1187 return r;
1188}
1189
1190int 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}
ebcf1f97
LP
1208
1209int 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);
ebcf1f97
LP
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}