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