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