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