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