]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-util.c
terminal/idev: fix NULL terminator for bus-property mapping
[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
TG
22#include <sys/socket.h>
23
ebd011d9
LP
24#include "sd-daemon.h"
25#include "sd-event.h"
40ca29a1 26#include "util.h"
ffc06c35 27#include "strv.h"
40ca29a1
LP
28#include "macro.h"
29#include "def.h"
df31a6c0 30#include "path-util.h"
2bba9a57 31#include "missing.h"
ebd011d9 32#include "set.h"
40ca29a1 33
ffc06c35
KS
34#include "sd-bus.h"
35#include "bus-error.h"
36#include "bus-message.h"
40ca29a1 37#include "bus-util.h"
ebcf1f97 38#include "bus-internal.h"
40ca29a1 39
6203e07a 40static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
40ca29a1
LP
41 sd_event *e = userdata;
42
43 assert(bus);
44 assert(m);
45 assert(e);
46
b27adf35 47 sd_bus_close(bus);
6203e07a 48 sd_event_exit(e, 0);
b27adf35 49
40ca29a1
LP
50 return 1;
51}
52
6203e07a 53int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
40ca29a1 54 _cleanup_free_ char *match = NULL;
11846aa7 55 const char *unique;
40ca29a1
LP
56 int r;
57
58 assert(e);
59 assert(bus);
60 assert(name);
61
6203e07a
LP
62 /* We unregister the name here and then wait for the
63 * NameOwnerChanged signal for this event to arrive before we
64 * quit. We do this in order to make sure that any queued
65 * requests are still processed before we really exit. */
66
11846aa7 67 r = sd_bus_get_unique_name(bus, &unique);
40ca29a1
LP
68 if (r < 0)
69 return r;
70
11846aa7
LP
71 r = asprintf(&match,
72 "sender='org.freedesktop.DBus',"
73 "type='signal',"
74 "interface='org.freedesktop.DBus',"
75 "member='NameOwnerChanged',"
76 "path='/org/freedesktop/DBus',"
77 "arg0='%s',"
78 "arg1='%s',"
79 "arg2=''", name, unique);
80 if (r < 0)
81 return -ENOMEM;
82
19befb2d 83 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
40ca29a1
LP
84 if (r < 0)
85 return r;
86
87 r = sd_bus_release_name(bus, name);
88 if (r < 0)
89 return r;
90
40ca29a1
LP
91 return 0;
92}
93
37224a5f
LP
94int bus_event_loop_with_idle(
95 sd_event *e,
96 sd_bus *bus,
97 const char *name,
98 usec_t timeout,
99 check_idle_t check_idle,
100 void *userdata) {
40ca29a1 101 bool exiting = false;
6203e07a 102 int r, code;
40ca29a1
LP
103
104 assert(e);
105 assert(bus);
106 assert(name);
107
108 for (;;) {
37224a5f
LP
109 bool idle;
110
40ca29a1
LP
111 r = sd_event_get_state(e);
112 if (r < 0)
113 return r;
40ca29a1
LP
114 if (r == SD_EVENT_FINISHED)
115 break;
116
37224a5f
LP
117 if (check_idle)
118 idle = check_idle(userdata);
119 else
120 idle = true;
121
122 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
40ca29a1
LP
123 if (r < 0)
124 return r;
125
a8ba6cd1 126 if (r == 0 && !exiting && idle) {
b27adf35
LP
127
128 r = sd_bus_try_close(bus);
129 if (r == -EBUSY)
130 continue;
131
430e21c2
LP
132 /* Fallback for dbus1 connections: we
133 * unregister the name and wait for the
134 * response to come through for it */
15411c0c 135 if (r == -EOPNOTSUPP) {
430e21c2
LP
136
137 /* Inform the service manager that we
138 * are going down, so that it will
139 * queue all further start requests,
140 * instead of assuming we are already
141 * running. */
142 sd_notify(false, "STOPPING=1");
b27adf35
LP
143
144 r = bus_async_unregister_and_exit(e, bus, name);
145 if (r < 0)
146 return r;
147
148 exiting = true;
149 continue;
150 }
151
40ca29a1
LP
152 if (r < 0)
153 return r;
154
b27adf35
LP
155 sd_event_exit(e, 0);
156 break;
40ca29a1
LP
157 }
158 }
159
6203e07a
LP
160 r = sd_event_get_exit_code(e, &code);
161 if (r < 0)
162 return r;
163
164 return code;
40ca29a1
LP
165}
166
5fd38859
DH
167int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
168 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
169 int r, has_owner = 0;
170
171 assert(c);
172 assert(name);
173
174 r = sd_bus_call_method(c,
175 "org.freedesktop.DBus",
176 "/org/freedesktop/dbus",
177 "org.freedesktop.DBus",
178 "NameHasOwner",
179 error,
180 &rep,
181 "s",
182 name);
183 if (r < 0)
184 return r;
185
186 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
187 if (r < 0)
188 return sd_bus_error_set_errno(error, r);
189
190 return has_owner;
191}
192
c529695e
LP
193static int check_good_user(sd_bus_message *m, uid_t good_user) {
194 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
195 uid_t sender_uid;
196 int r;
197
198 assert(m);
199
200 if (good_user == UID_INVALID)
201 return 0;
202
203 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
204 if (r < 0)
205 return r;
206
207 r = sd_bus_creds_get_euid(creds, &sender_uid);
208 if (r < 0)
209 return r;
210
211 return sender_uid == good_user;
212}
213
ceb24229 214int bus_test_polkit(
f3885791 215 sd_bus_message *call,
def9a7aa 216 int capability,
40ca29a1 217 const char *action,
c529695e 218 uid_t good_user,
40ca29a1
LP
219 bool *_challenge,
220 sd_bus_error *e) {
221
40ca29a1
LP
222 int r;
223
f3885791 224 assert(call);
40ca29a1
LP
225 assert(action);
226
ceb24229
LP
227 /* Tests non-interactively! */
228
c529695e
LP
229 r = check_good_user(call, good_user);
230 if (r != 0)
231 return r;
232
f3885791 233 r = sd_bus_query_sender_privilege(call, capability);
5b12334d
LP
234 if (r < 0)
235 return r;
f3885791 236 else if (r > 0)
40ca29a1 237 return 1;
40ca29a1
LP
238#ifdef ENABLE_POLKIT
239 else {
240 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ceb24229 241 int authorized = false, challenge = false;
5b12334d
LP
242 const char *sender;
243
f3885791 244 sender = sd_bus_message_get_sender(call);
5b12334d
LP
245 if (!sender)
246 return -EBADMSG;
40ca29a1
LP
247
248 r = sd_bus_call_method(
f3885791 249 call->bus,
40ca29a1
LP
250 "org.freedesktop.PolicyKit1",
251 "/org/freedesktop/PolicyKit1/Authority",
252 "org.freedesktop.PolicyKit1.Authority",
253 "CheckAuthorization",
254 e,
255 &reply,
256 "(sa{sv})sa{ss}us",
257 "system-bus-name", 1, "name", "s", sender,
258 action,
259 0,
ceb24229 260 0,
40ca29a1
LP
261 "");
262
263 if (r < 0) {
264 /* Treat no PK available as access denied */
265 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
266 sd_bus_error_free(e);
267 return -EACCES;
268 }
269
270 return r;
271 }
272
313333b4 273 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
2b49a470
TA
274 if (r < 0)
275 return r;
276
277 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
278 if (r < 0)
279 return r;
40ca29a1
LP
280
281 if (authorized)
282 return 1;
283
284 if (_challenge) {
285 *_challenge = challenge;
286 return 0;
287 }
288 }
289#endif
290
291 return -EACCES;
292}
293
294#ifdef ENABLE_POLKIT
295
296typedef struct AsyncPolkitQuery {
297 sd_bus_message *request, *reply;
298 sd_bus_message_handler_t callback;
299 void *userdata;
19befb2d 300 sd_bus_slot *slot;
ebcf1f97 301 Hashmap *registry;
40ca29a1
LP
302} AsyncPolkitQuery;
303
19befb2d 304static void async_polkit_query_free(AsyncPolkitQuery *q) {
ebcf1f97
LP
305
306 if (!q)
307 return;
308
19befb2d 309 sd_bus_slot_unref(q->slot);
ebcf1f97
LP
310
311 if (q->registry && q->request)
312 hashmap_remove(q->registry, q->request);
313
314 sd_bus_message_unref(q->request);
315 sd_bus_message_unref(q->reply);
316
317 free(q);
318}
319
320static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
321 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
ebcf1f97 322 AsyncPolkitQuery *q = userdata;
40ca29a1
LP
323 int r;
324
325 assert(bus);
326 assert(reply);
327 assert(q);
328
19befb2d 329 q->slot = sd_bus_slot_unref(q->slot);
40ca29a1 330 q->reply = sd_bus_message_ref(reply);
40ca29a1 331
ebcf1f97
LP
332 r = sd_bus_message_rewind(q->request, true);
333 if (r < 0) {
334 r = sd_bus_reply_method_errno(q->request, r, NULL);
335 goto finish;
336 }
40ca29a1 337
ebcf1f97
LP
338 r = q->callback(bus, q->request, q->userdata, &error_buffer);
339 r = bus_maybe_reply_error(q->request, r, &error_buffer);
40ca29a1 340
ebcf1f97 341finish:
19befb2d
LP
342 async_polkit_query_free(q);
343
ebcf1f97 344 return r;
40ca29a1
LP
345}
346
347#endif
348
349int bus_verify_polkit_async(
f3885791 350 sd_bus_message *call,
def9a7aa 351 int capability,
40ca29a1
LP
352 const char *action,
353 bool interactive,
c529695e 354 uid_t good_user,
f3885791
LP
355 Hashmap **registry,
356 sd_bus_error *error) {
40ca29a1
LP
357
358#ifdef ENABLE_POLKIT
359 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
360 AsyncPolkitQuery *q;
40ca29a1 361 const char *sender;
f3885791
LP
362 sd_bus_message_handler_t callback;
363 void *userdata;
b911eb15 364 int c;
5b12334d 365#endif
40ca29a1
LP
366 int r;
367
f3885791 368 assert(call);
40ca29a1 369 assert(action);
f3885791 370 assert(registry);
40ca29a1 371
c529695e
LP
372 r = check_good_user(call, good_user);
373 if (r != 0)
374 return r;
375
40ca29a1 376#ifdef ENABLE_POLKIT
f3885791 377 q = hashmap_get(*registry, call);
40ca29a1 378 if (q) {
102d8f81 379 int authorized, challenge;
40ca29a1
LP
380
381 /* This is the second invocation of this function, and
382 * there's already a response from polkit, let's
383 * process it */
384 assert(q->reply);
385
386 if (sd_bus_message_is_method_error(q->reply, NULL)) {
387 const sd_bus_error *e;
388
ebcf1f97 389 /* Copy error from polkit reply */
40ca29a1
LP
390 e = sd_bus_message_get_error(q->reply);
391 sd_bus_error_copy(error, e);
40ca29a1 392
ebcf1f97
LP
393 /* Treat no PK available as access denied */
394 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
395 return -EACCES;
396
5958d089 397 return -sd_bus_error_get_errno(e);
40ca29a1
LP
398 }
399
400 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
401 if (r >= 0)
402 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
403
40ca29a1
LP
404 if (r < 0)
405 return r;
406
407 if (authorized)
408 return 1;
409
f2288cc6
LP
410 if (challenge)
411 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
412
40ca29a1
LP
413 return -EACCES;
414 }
415#endif
416
f3885791 417 r = sd_bus_query_sender_privilege(call, capability);
5b12334d
LP
418 if (r < 0)
419 return r;
f3885791 420 else if (r > 0)
40ca29a1 421 return 1;
5b12334d 422
40ca29a1 423#ifdef ENABLE_POLKIT
f3885791
LP
424 if (sd_bus_get_current_message(call->bus) != call)
425 return -EINVAL;
426
427 callback = sd_bus_get_current_handler(call->bus);
428 if (!callback)
429 return -EINVAL;
430
431 userdata = sd_bus_get_current_userdata(call->bus);
432
433 sender = sd_bus_message_get_sender(call);
5b12334d
LP
434 if (!sender)
435 return -EBADMSG;
40ca29a1 436
b911eb15
LP
437 c = sd_bus_message_get_allow_interactive_authorization(call);
438 if (c < 0)
439 return c;
440 if (c > 0)
441 interactive = true;
442
d5099efc 443 r = hashmap_ensure_allocated(registry, NULL);
40ca29a1
LP
444 if (r < 0)
445 return r;
446
447 r = sd_bus_message_new_method_call(
f3885791 448 call->bus,
151b9b96 449 &pk,
40ca29a1
LP
450 "org.freedesktop.PolicyKit1",
451 "/org/freedesktop/PolicyKit1/Authority",
452 "org.freedesktop.PolicyKit1.Authority",
151b9b96 453 "CheckAuthorization");
40ca29a1
LP
454 if (r < 0)
455 return r;
456
457 r = sd_bus_message_append(
458 pk,
459 "(sa{sv})sa{ss}us",
460 "system-bus-name", 1, "name", "s", sender,
461 action,
462 0,
b911eb15 463 !!interactive,
ebcf1f97 464 NULL);
40ca29a1
LP
465 if (r < 0)
466 return r;
467
468 q = new0(AsyncPolkitQuery, 1);
469 if (!q)
470 return -ENOMEM;
471
f3885791 472 q->request = sd_bus_message_ref(call);
40ca29a1
LP
473 q->callback = callback;
474 q->userdata = userdata;
475
f3885791 476 r = hashmap_put(*registry, call, q);
40ca29a1 477 if (r < 0) {
19befb2d 478 async_polkit_query_free(q);
40ca29a1
LP
479 return r;
480 }
481
ebcf1f97
LP
482 q->registry = *registry;
483
f3885791 484 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
ebcf1f97 485 if (r < 0) {
19befb2d 486 async_polkit_query_free(q);
40ca29a1 487 return r;
ebcf1f97 488 }
40ca29a1
LP
489
490 return 0;
491#endif
492
493 return -EACCES;
494}
495
36e34057 496void bus_verify_polkit_async_registry_free(Hashmap *registry) {
40ca29a1
LP
497#ifdef ENABLE_POLKIT
498 AsyncPolkitQuery *q;
499
500 while ((q = hashmap_steal_first(registry)))
19befb2d 501 async_polkit_query_free(q);
40ca29a1
LP
502
503 hashmap_free(registry);
504#endif
505}
0c842e0a 506
718db961 507int bus_check_peercred(sd_bus *c) {
0c842e0a
TG
508 struct ucred ucred;
509 socklen_t l;
0f8bd8de 510 int fd;
0c842e0a
TG
511
512 assert(c);
513
514 fd = sd_bus_get_fd(c);
0f8bd8de
LP
515 if (fd < 0)
516 return fd;
0c842e0a
TG
517
518 l = sizeof(struct ucred);
0f8bd8de 519 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
0c842e0a 520 return -errno;
0c842e0a 521
0f8bd8de 522 if (l != sizeof(struct ucred))
0c842e0a 523 return -E2BIG;
0c842e0a
TG
524
525 if (ucred.uid != 0 && ucred.uid != geteuid())
526 return -EPERM;
527
528 return 1;
529}
530
0f8bd8de
LP
531int bus_open_system_systemd(sd_bus **_bus) {
532 _cleanup_bus_unref_ sd_bus *bus = NULL;
0c842e0a 533 int r;
0c842e0a
TG
534
535 assert(_bus);
536
0f8bd8de
LP
537 if (geteuid() != 0)
538 return sd_bus_open_system(_bus);
a1da8583 539
a6aa8912
LP
540 /* If we are root and kdbus is not available, then let's talk
541 * directly to the system instance, instead of going via the
542 * bus */
a1da8583 543
a6aa8912 544#ifdef ENABLE_KDBUS
0f8bd8de
LP
545 r = sd_bus_new(&bus);
546 if (r < 0)
547 return r;
a1da8583 548
e3afaf6b 549 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
0f8bd8de
LP
550 if (r < 0)
551 return r;
a1da8583 552
a6aa8912
LP
553 bus->bus_client = true;
554
0f8bd8de 555 r = sd_bus_start(bus);
a6aa8912
LP
556 if (r >= 0) {
557 *_bus = bus;
558 bus = NULL;
559 return 0;
560 }
561
562 bus = sd_bus_unref(bus);
563#endif
564
565 r = sd_bus_new(&bus);
0f8bd8de
LP
566 if (r < 0)
567 return r;
a1da8583 568
a6aa8912
LP
569 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
570 if (r < 0)
571 return r;
572
573 r = sd_bus_start(bus);
574 if (r < 0)
575 return sd_bus_open_system(_bus);
576
0f8bd8de 577 r = bus_check_peercred(bus);
a1da8583
TG
578 if (r < 0)
579 return r;
580
581 *_bus = bus;
0f8bd8de
LP
582 bus = NULL;
583
a1da8583
TG
584 return 0;
585}
586
41dd15e4
LP
587int bus_open_user_systemd(sd_bus **_bus) {
588 _cleanup_bus_unref_ sd_bus *bus = NULL;
a6aa8912 589 _cleanup_free_ char *ee = NULL;
41dd15e4
LP
590 const char *e;
591 int r;
592
a6aa8912 593 /* Try via kdbus first, and then directly */
41dd15e4
LP
594
595 assert(_bus);
596
a6aa8912
LP
597#ifdef ENABLE_KDBUS
598 r = sd_bus_new(&bus);
599 if (r < 0)
600 return r;
601
e3afaf6b 602 if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
a6aa8912
LP
603 return -ENOMEM;
604
605 bus->bus_client = true;
606
607 r = sd_bus_start(bus);
608 if (r >= 0) {
609 *_bus = bus;
610 bus = NULL;
611 return 0;
612 }
613
614 bus = sd_bus_unref(bus);
615#endif
616
41dd15e4 617 e = secure_getenv("XDG_RUNTIME_DIR");
537220d9 618 if (!e)
3f78871b 619 return sd_bus_open_user(_bus);
537220d9 620
a6aa8912
LP
621 ee = bus_address_escape(e);
622 if (!ee)
537220d9 623 return -ENOMEM;
41dd15e4
LP
624
625 r = sd_bus_new(&bus);
626 if (r < 0)
627 return r;
628
a6aa8912
LP
629 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
630 if (!bus->address)
631 return -ENOMEM;
41dd15e4
LP
632
633 r = sd_bus_start(bus);
634 if (r < 0)
3f78871b 635 return sd_bus_open_user(_bus);
41dd15e4
LP
636
637 r = bus_check_peercred(bus);
638 if (r < 0)
639 return r;
640
641 *_bus = bus;
642 bus = NULL;
643
644 return 0;
645}
646
9f6eb1cd 647int bus_print_property(const char *name, sd_bus_message *property, bool all) {
a1da8583
TG
648 char type;
649 const char *contents;
9f6eb1cd 650 int r;
a1da8583
TG
651
652 assert(name);
653 assert(property);
654
9f6eb1cd
KS
655 r = sd_bus_message_peek_type(property, &type, &contents);
656 if (r < 0)
657 return r;
a1da8583
TG
658
659 switch (type) {
660
661 case SD_BUS_TYPE_STRING: {
662 const char *s;
9f6eb1cd
KS
663
664 r = sd_bus_message_read_basic(property, type, &s);
665 if (r < 0)
666 return r;
a1da8583 667
27e9c5af
LP
668 if (all || !isempty(s)) {
669 _cleanup_free_ char *escaped = NULL;
670
671 escaped = xescape(s, "\n");
672 if (!escaped)
673 return -ENOMEM;
674
675 printf("%s=%s\n", name, escaped);
676 }
a1da8583
TG
677
678 return 1;
679 }
680
681 case SD_BUS_TYPE_BOOLEAN: {
c2fa048c 682 int b;
a1da8583 683
9f6eb1cd
KS
684 r = sd_bus_message_read_basic(property, type, &b);
685 if (r < 0)
686 return r;
687
a1da8583
TG
688 printf("%s=%s\n", name, yes_no(b));
689
690 return 1;
691 }
692
693 case SD_BUS_TYPE_UINT64: {
694 uint64_t u;
695
9f6eb1cd
KS
696 r = sd_bus_message_read_basic(property, type, &u);
697 if (r < 0)
698 return r;
a1da8583
TG
699
700 /* Yes, heuristics! But we can change this check
701 * should it turn out to not be sufficient */
702
703 if (endswith(name, "Timestamp")) {
704 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
705
706 t = format_timestamp(timestamp, sizeof(timestamp), u);
707 if (t || all)
708 printf("%s=%s\n", name, strempty(t));
709
710 } else if (strstr(name, "USec")) {
711 char timespan[FORMAT_TIMESPAN_MAX];
712
713 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
714 } else
715 printf("%s=%llu\n", name, (unsigned long long) u);
716
717 return 1;
718 }
719
720 case SD_BUS_TYPE_UINT32: {
721 uint32_t u;
722
9f6eb1cd
KS
723 r = sd_bus_message_read_basic(property, type, &u);
724 if (r < 0)
725 return r;
a1da8583
TG
726
727 if (strstr(name, "UMask") || strstr(name, "Mode"))
728 printf("%s=%04o\n", name, u);
729 else
730 printf("%s=%u\n", name, (unsigned) u);
731
732 return 1;
733 }
734
735 case SD_BUS_TYPE_INT32: {
736 int32_t i;
737
9f6eb1cd
KS
738 r = sd_bus_message_read_basic(property, type, &i);
739 if (r < 0)
740 return r;
a1da8583
TG
741
742 printf("%s=%i\n", name, (int) i);
743 return 1;
744 }
745
746 case SD_BUS_TYPE_DOUBLE: {
747 double d;
748
9f6eb1cd
KS
749 r = sd_bus_message_read_basic(property, type, &d);
750 if (r < 0)
751 return r;
a1da8583
TG
752
753 printf("%s=%g\n", name, d);
754 return 1;
755 }
756
757 case SD_BUS_TYPE_ARRAY:
a1da8583 758 if (streq(contents, "s")) {
261afec5
MAP
759 bool first = true;
760 const char *str;
a1da8583 761
9f6eb1cd
KS
762 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
763 if (r < 0)
764 return r;
765
261afec5 766 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
27e9c5af
LP
767 _cleanup_free_ char *escaped = NULL;
768
261afec5
MAP
769 if (first)
770 printf("%s=", name);
771
27e9c5af
LP
772 escaped = xescape(str, "\n ");
773 if (!escaped)
774 return -ENOMEM;
775
776 printf("%s%s", first ? "" : " ", escaped);
261afec5
MAP
777
778 first = false;
779 }
9f6eb1cd
KS
780 if (r < 0)
781 return r;
a1da8583 782
261afec5 783 if (first && all)
a1da8583 784 printf("%s=", name);
261afec5 785 if (!first || all)
a1da8583 786 puts("");
a1da8583 787
9f6eb1cd
KS
788 r = sd_bus_message_exit_container(property);
789 if (r < 0)
790 return r;
a1da8583
TG
791
792 return 1;
793
794 } else if (streq(contents, "y")) {
795 const uint8_t *u;
796 size_t n;
797
9f6eb1cd
KS
798 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
799 if (r < 0)
800 return r;
801
a1da8583
TG
802 if (all || n > 0) {
803 unsigned int i;
804
805 printf("%s=", name);
806
807 for (i = 0; i < n; i++)
808 printf("%02x", u[i]);
809
810 puts("");
811 }
812
813 return 1;
814
815 } else if (streq(contents, "u")) {
816 uint32_t *u;
817 size_t n;
818
9f6eb1cd
KS
819 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
820 if (r < 0)
821 return r;
822
a1da8583
TG
823 if (all || n > 0) {
824 unsigned int i;
825
826 printf("%s=", name);
827
828 for (i = 0; i < n; i++)
829 printf("%08x", u[i]);
830
831 puts("");
832 }
833
834 return 1;
835 }
836
837 break;
838 }
839
840 return 0;
841}
d21ed1ea 842
27e72d6b 843int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
9f6eb1cd 844 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ffc06c35
KS
845 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
846 int r;
847
9f6eb1cd
KS
848 assert(bus);
849 assert(path);
850
851 r = sd_bus_call_method(bus,
27e72d6b 852 dest,
ffc06c35
KS
853 path,
854 "org.freedesktop.DBus.Properties",
855 "GetAll",
856 &error,
9f6eb1cd 857 &reply,
ffc06c35 858 "s", "");
9f6eb1cd 859 if (r < 0)
ffc06c35 860 return r;
ffc06c35 861
9f6eb1cd 862 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
ffc06c35
KS
863 if (r < 0)
864 return r;
865
9f6eb1cd 866 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
ffc06c35 867 const char *name;
ffc06c35 868 const char *contents;
ffc06c35 869
9f6eb1cd 870 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
ffc06c35
KS
871 if (r < 0)
872 return r;
873
9f6eb1cd
KS
874 if (!filter || strv_find(filter, name)) {
875 r = sd_bus_message_peek_type(reply, NULL, &contents);
876 if (r < 0)
877 return r;
878
879 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
880 if (r < 0)
881 return r;
ffc06c35 882
9f6eb1cd
KS
883 r = bus_print_property(name, reply, all);
884 if (r < 0)
885 return r;
27e72d6b
SP
886 if (r == 0) {
887 if (all)
888 printf("%s=[unprintable]\n", name);
889 /* skip what we didn't read */
890 r = sd_bus_message_skip(reply, contents);
891 if (r < 0)
892 return r;
893 }
9f6eb1cd
KS
894
895 r = sd_bus_message_exit_container(reply);
896 if (r < 0)
897 return r;
898 } else {
899 r = sd_bus_message_skip(reply, "v");
900 if (r < 0)
901 return r;
902 }
903
904 r = sd_bus_message_exit_container(reply);
ffc06c35
KS
905 if (r < 0)
906 return r;
9f6eb1cd
KS
907 }
908 if (r < 0)
909 return r;
ffc06c35 910
9f6eb1cd
KS
911 r = sd_bus_message_exit_container(reply);
912 if (r < 0)
913 return r;
ffc06c35 914
9f6eb1cd
KS
915 return 0;
916}
ffc06c35 917
9f6eb1cd
KS
918int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
919 sd_id128_t *p = userdata;
920 const void *v;
921 size_t n;
922 int r;
ffc06c35 923
9f6eb1cd
KS
924 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
925 if (r < 0)
926 return r;
ffc06c35 927
9f6eb1cd
KS
928 if (n == 0)
929 *p = SD_ID128_NULL;
930 else if (n == 16)
931 memcpy((*p).bytes, v, n);
932 else
933 return -EINVAL;
ffc06c35 934
9f6eb1cd
KS
935 return 0;
936}
ffc06c35 937
9f6eb1cd
KS
938static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
939 char type;
940 int r;
ffc06c35 941
9f6eb1cd
KS
942 r = sd_bus_message_peek_type(m, &type, NULL);
943 if (r < 0)
944 return r;
ffc06c35 945
9f6eb1cd
KS
946 switch (type) {
947 case SD_BUS_TYPE_STRING: {
948 const char *s;
949 char *str;
950 char **p = userdata;
ffc06c35 951
9f6eb1cd
KS
952 r = sd_bus_message_read_basic(m, type, &s);
953 if (r < 0)
954 break;
ffc06c35 955
9f6eb1cd
KS
956 if (isempty(s))
957 break;
ffc06c35 958
9f6eb1cd
KS
959 str = strdup(s);
960 if (!str) {
961 r = -ENOMEM;
ffc06c35
KS
962 break;
963 }
9f6eb1cd
KS
964 free(*p);
965 *p = str;
ffc06c35 966
9f6eb1cd
KS
967 break;
968 }
ffc06c35 969
9f6eb1cd
KS
970 case SD_BUS_TYPE_ARRAY: {
971 _cleanup_strv_free_ char **l = NULL;
972 char ***p = userdata;
ffc06c35 973
9f6eb1cd
KS
974 r = bus_message_read_strv_extend(m, &l);
975 if (r < 0)
976 break;
ffc06c35 977
9f6eb1cd
KS
978 strv_free(*p);
979 *p = l;
980 l = NULL;
ffc06c35 981
9f6eb1cd
KS
982 break;
983 }
ffc06c35 984
9f6eb1cd
KS
985 case SD_BUS_TYPE_BOOLEAN: {
986 unsigned b;
987 bool *p = userdata;
ffc06c35 988
9f6eb1cd
KS
989 r = sd_bus_message_read_basic(m, type, &b);
990 if (r < 0)
991 break;
ffc06c35 992
9f6eb1cd 993 *p = b;
ffc06c35 994
9f6eb1cd
KS
995 break;
996 }
ffc06c35 997
9f6eb1cd
KS
998 case SD_BUS_TYPE_UINT32: {
999 uint64_t u;
1000 uint32_t *p = userdata;
1001
1002 r = sd_bus_message_read_basic(m, type, &u);
1003 if (r < 0)
ffc06c35 1004 break;
ffc06c35 1005
9f6eb1cd
KS
1006 *p = u;
1007
1008 break;
1009 }
1010
1011 case SD_BUS_TYPE_UINT64: {
1012 uint64_t t;
1013 uint64_t *p = userdata;
1014
1015 r = sd_bus_message_read_basic(m, type, &t);
1016 if (r < 0)
ffc06c35 1017 break;
ffc06c35 1018
9f6eb1cd
KS
1019 *p = t;
1020
1021 break;
1022 }
1023
1024 default:
1025 break;
1026 }
1027
1028 return r;
1029}
1030
aae2b488
DH
1031int bus_message_map_all_properties(sd_bus *bus,
1032 sd_bus_message *m,
1033 const struct bus_properties_map *map,
1034 void *userdata) {
9f6eb1cd
KS
1035 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1036 int r;
1037
1038 assert(bus);
aae2b488 1039 assert(m);
9f6eb1cd
KS
1040 assert(map);
1041
9f6eb1cd
KS
1042 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1043 if (r < 0)
1044 return r;
1045
1046 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1047 const struct bus_properties_map *prop;
1048 const char *member;
1049 const char *contents;
1050 void *v;
1051 unsigned i;
1052
1053 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
ffc06c35
KS
1054 if (r < 0)
1055 return r;
1056
9f6eb1cd
KS
1057 for (i = 0, prop = NULL; map[i].member; i++)
1058 if (streq(map[i].member, member)) {
1059 prop = &map[i];
1060 break;
1061 }
1062
1063 if (prop) {
1064 r = sd_bus_message_peek_type(m, NULL, &contents);
1065 if (r < 0)
1066 return r;
1067
1068 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1069 if (r < 0)
1070 return r;
1071
1072 v = (uint8_t *)userdata + prop->offset;
27e72d6b 1073 if (map[i].set)
9f6eb1cd
KS
1074 r = prop->set(bus, member, m, &error, v);
1075 else
1076 r = map_basic(bus, member, m, &error, v);
2b49a470
TA
1077 if (r < 0)
1078 return r;
9f6eb1cd
KS
1079
1080 r = sd_bus_message_exit_container(m);
1081 if (r < 0)
1082 return r;
1083 } else {
1084 r = sd_bus_message_skip(m, "v");
1085 if (r < 0)
6c1508b8 1086 return r;
9f6eb1cd
KS
1087 }
1088
ffc06c35
KS
1089 r = sd_bus_message_exit_container(m);
1090 if (r < 0)
1091 return r;
1092 }
1093
aae2b488
DH
1094 return sd_bus_message_exit_container(m);
1095}
1096
1097int bus_message_map_properties_changed(sd_bus *bus,
1098 sd_bus_message *m,
1099 const struct bus_properties_map *map,
1100 void *userdata) {
1101 const char *member;
1102 int r, invalidated, i;
1103
1104 assert(bus);
1105 assert(m);
1106 assert(map);
1107
aae2b488
DH
1108 r = bus_message_map_all_properties(bus, m, map, userdata);
1109 if (r < 0)
1110 return r;
1111
1112 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1113 if (r < 0)
1114 return r;
1115
1116 invalidated = 0;
1117 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1118 for (i = 0; map[i].member; i++)
1119 if (streq(map[i].member, member)) {
1120 ++invalidated;
1121 break;
1122 }
1123
1124 r = sd_bus_message_exit_container(m);
1125 if (r < 0)
1126 return r;
1127
1128 return invalidated;
1129}
1130
1131int bus_map_all_properties(sd_bus *bus,
1132 const char *destination,
1133 const char *path,
1134 const struct bus_properties_map *map,
1135 void *userdata) {
1136 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1137 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1138 int r;
1139
1140 assert(bus);
1141 assert(destination);
1142 assert(path);
1143 assert(map);
1144
1145 r = sd_bus_call_method(
1146 bus,
1147 destination,
1148 path,
1149 "org.freedesktop.DBus.Properties",
1150 "GetAll",
1151 &error,
1152 &m,
1153 "s", "");
1154 if (r < 0)
1155 return r;
1156
1157 return bus_message_map_all_properties(bus, m, map, userdata);
ffc06c35
KS
1158}
1159
d21ed1ea
LP
1160int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1161 int r;
1162
1163 assert(transport >= 0);
1164 assert(transport < _BUS_TRANSPORT_MAX);
1165 assert(bus);
1166
1167 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1168 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
d21ed1ea
LP
1169
1170 switch (transport) {
1171
1172 case BUS_TRANSPORT_LOCAL:
1173 if (user)
76b54375 1174 r = sd_bus_default_user(bus);
d21ed1ea 1175 else
76b54375 1176 r = sd_bus_default_system(bus);
d21ed1ea
LP
1177
1178 break;
1179
1180 case BUS_TRANSPORT_REMOTE:
3db729cb 1181 r = sd_bus_open_system_remote(bus, host);
41dd15e4
LP
1182 break;
1183
de33fc62
LP
1184 case BUS_TRANSPORT_MACHINE:
1185 r = sd_bus_open_system_machine(bus, host);
41dd15e4
LP
1186 break;
1187
1188 default:
1189 assert_not_reached("Hmm, unknown transport type.");
1190 }
1191
1192 return r;
1193}
1194
1195int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1196 int r;
1197
1198 assert(transport >= 0);
1199 assert(transport < _BUS_TRANSPORT_MAX);
1200 assert(bus);
1201
1202 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
15411c0c 1203 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
41dd15e4
LP
1204
1205 switch (transport) {
1206
1207 case BUS_TRANSPORT_LOCAL:
1208 if (user)
1209 r = bus_open_user_systemd(bus);
1210 else
1211 r = bus_open_system_systemd(bus);
1212
1213 break;
1214
1215 case BUS_TRANSPORT_REMOTE:
3db729cb 1216 r = sd_bus_open_system_remote(bus, host);
d21ed1ea
LP
1217 break;
1218
de33fc62
LP
1219 case BUS_TRANSPORT_MACHINE:
1220 r = sd_bus_open_system_machine(bus, host);
d21ed1ea
LP
1221 break;
1222
1223 default:
1224 assert_not_reached("Hmm, unknown transport type.");
1225 }
1226
1227 return r;
1228}
e6504030
LP
1229
1230int bus_property_get_bool(
1231 sd_bus *bus,
1232 const char *path,
1233 const char *interface,
1234 const char *property,
1235 sd_bus_message *reply,
ebcf1f97
LP
1236 void *userdata,
1237 sd_bus_error *error) {
e6504030
LP
1238
1239 int b = *(bool*) userdata;
1240
1241 return sd_bus_message_append_basic(reply, 'b', &b);
1242}
1243
718db961
LP
1244#if __SIZEOF_SIZE_T__ != 8
1245int bus_property_get_size(
e6504030
LP
1246 sd_bus *bus,
1247 const char *path,
1248 const char *interface,
1249 const char *property,
1250 sd_bus_message *reply,
ebcf1f97
LP
1251 void *userdata,
1252 sd_bus_error *error) {
e6504030 1253
718db961 1254 uint64_t sz = *(size_t*) userdata;
e6504030 1255
718db961 1256 return sd_bus_message_append_basic(reply, 't', &sz);
e6504030 1257}
718db961
LP
1258#endif
1259
1260#if __SIZEOF_LONG__ != 8
1261int bus_property_get_long(
1262 sd_bus *bus,
1263 const char *path,
1264 const char *interface,
1265 const char *property,
1266 sd_bus_message *reply,
ebcf1f97
LP
1267 void *userdata,
1268 sd_bus_error *error) {
718db961
LP
1269
1270 int64_t l = *(long*) userdata;
1271
1272 return sd_bus_message_append_basic(reply, 'x', &l);
1273}
1274
1275int bus_property_get_ulong(
1276 sd_bus *bus,
1277 const char *path,
1278 const char *interface,
1279 const char *property,
1280 sd_bus_message *reply,
ebcf1f97
LP
1281 void *userdata,
1282 sd_bus_error *error) {
718db961
LP
1283
1284 uint64_t ul = *(unsigned long*) userdata;
1285
1286 return sd_bus_message_append_basic(reply, 't', &ul);
1287}
1288#endif
5b30bef8
LP
1289
1290int bus_log_parse_error(int r) {
23bbb0de 1291 return log_error_errno(r, "Failed to parse bus message: %m");
5b30bef8 1292}
f459b602
MAP
1293
1294int bus_log_create_error(int r) {
23bbb0de 1295 return log_error_errno(r, "Failed to create bus message: %m");
f459b602
MAP
1296}
1297
1298int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1299 assert(message);
1300 assert(u);
1301
1238ee09
LP
1302 u->machine = NULL;
1303
f459b602
MAP
1304 return sd_bus_message_read(
1305 message,
1306 "(ssssssouso)",
1307 &u->id,
1308 &u->description,
1309 &u->load_state,
1310 &u->active_state,
1311 &u->sub_state,
1312 &u->following,
1313 &u->unit_path,
1314 &u->job_id,
1315 &u->job_type,
1316 &u->job_path);
1317}
ebcf1f97
LP
1318
1319int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1320 assert(m);
1321
1322 if (r < 0) {
1323 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1324 sd_bus_reply_method_errno(m, r, error);
1325
1326 } else if (sd_bus_error_is_set(error)) {
1327 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1328 sd_bus_reply_method_error(m, error);
ebcf1f97
LP
1329 } else
1330 return r;
1331
1332 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1333 bus_message_type_to_string(m->header->type),
1334 strna(m->sender),
1335 strna(m->path),
1336 strna(m->interface),
1337 strna(m->member),
1338 strna(m->root_container.signature),
1339 bus_error_message(error, r));
1340
1341 return 1;
1342}
df31a6c0
LP
1343
1344int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1345 const char *eq, *field;
1346 int r;
1347
1348 assert(m);
1349 assert(assignment);
1350
1351 eq = strchr(assignment, '=');
1352 if (!eq) {
1353 log_error("Not an assignment: %s", assignment);
1354 return -EINVAL;
1355 }
1356
1357 field = strndupa(assignment, eq - assignment);
1358 eq ++;
1359
b2f8b02e
LP
1360 if (streq(field, "CPUQuota")) {
1361
1362 if (isempty(eq)) {
1363
1364 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1365 if (r < 0)
1366 return bus_log_create_error(r);
1367
3a43da28 1368 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
b2f8b02e
LP
1369
1370 } else if (endswith(eq, "%")) {
1371 double percent;
1372
1373 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1374 log_error("CPU quota '%s' invalid.", eq);
1375 return -EINVAL;
1376 }
1377
1378 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1379 if (r < 0)
1380 return bus_log_create_error(r);
1381
1382 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1383 } else {
9a054909 1384 log_error("CPU quota needs to be in percent.");
b2f8b02e
LP
1385 return -EINVAL;
1386 }
1387
b2f8b02e
LP
1388 if (r < 0)
1389 return bus_log_create_error(r);
1390
1391 return 0;
1392 }
1393
df31a6c0
LP
1394 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1395 if (r < 0)
1396 return bus_log_create_error(r);
1397
e567439e
LP
1398 if (STR_IN_SET(field,
1399 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
261420ba 1400 "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies")) {
df31a6c0
LP
1401
1402 r = parse_boolean(eq);
1403 if (r < 0) {
1404 log_error("Failed to parse boolean assignment %s.", assignment);
1405 return -EINVAL;
1406 }
1407
1408 r = sd_bus_message_append(m, "v", "b", r);
1409
1410 } else if (streq(field, "MemoryLimit")) {
1411 off_t bytes;
1412
1413 r = parse_size(eq, 1024, &bytes);
1414 if (r < 0) {
1415 log_error("Failed to parse bytes specification %s", assignment);
1416 return -EINVAL;
1417 }
1418
1419 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1420
1421 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1422 uint64_t u;
1423
1424 r = safe_atou64(eq, &u);
1425 if (r < 0) {
1426 log_error("Failed to parse %s value %s.", field, eq);
1427 return -EINVAL;
1428 }
1429
1430 r = sd_bus_message_append(m, "v", "t", u);
1431
e567439e 1432 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
df31a6c0
LP
1433 r = sd_bus_message_append(m, "v", "s", eq);
1434
1435 else if (streq(field, "DeviceAllow")) {
1436
1437 if (isempty(eq))
1438 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1439 else {
1440 const char *path, *rwm, *e;
1441
1442 e = strchr(eq, ' ');
1443 if (e) {
1444 path = strndupa(eq, e - eq);
1445 rwm = e+1;
1446 } else {
1447 path = eq;
1448 rwm = "";
1449 }
1450
1451 if (!path_startswith(path, "/dev")) {
1452 log_error("%s is not a device file in /dev.", path);
1453 return -EINVAL;
1454 }
1455
1456 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1457 }
1458
1459 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1460
1461 if (isempty(eq))
1462 r = sd_bus_message_append(m, "v", "a(st)", 0);
1463 else {
1464 const char *path, *bandwidth, *e;
1465 off_t bytes;
1466
1467 e = strchr(eq, ' ');
1468 if (e) {
1469 path = strndupa(eq, e - eq);
1470 bandwidth = e+1;
1471 } else {
1472 log_error("Failed to parse %s value %s.", field, eq);
1473 return -EINVAL;
1474 }
1475
1476 if (!path_startswith(path, "/dev")) {
1477 log_error("%s is not a device file in /dev.", path);
1478 return -EINVAL;
1479 }
1480
1481 r = parse_size(bandwidth, 1000, &bytes);
1482 if (r < 0) {
1483 log_error("Failed to parse byte value %s.", bandwidth);
1484 return -EINVAL;
1485 }
1486
1487 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1488 }
1489
1490 } else if (streq(field, "BlockIODeviceWeight")) {
1491
1492 if (isempty(eq))
1493 r = sd_bus_message_append(m, "v", "a(st)", 0);
1494 else {
1495 const char *path, *weight, *e;
1496 uint64_t u;
1497
1498 e = strchr(eq, ' ');
1499 if (e) {
1500 path = strndupa(eq, e - eq);
1501 weight = e+1;
1502 } else {
1503 log_error("Failed to parse %s value %s.", field, eq);
1504 return -EINVAL;
1505 }
1506
1507 if (!path_startswith(path, "/dev")) {
1508 log_error("%s is not a device file in /dev.", path);
1509 return -EINVAL;
1510 }
1511
1512 r = safe_atou64(weight, &u);
1513 if (r < 0) {
1514 log_error("Failed to parse %s value %s.", field, weight);
1515 return -EINVAL;
1516 }
1517 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1518 }
1519
d584f638
LP
1520 } else if (rlimit_from_string(field) >= 0) {
1521 uint64_t rl;
1522
1523 if (streq(eq, "infinity"))
1524 rl = (uint64_t) -1;
1525 else {
1526 r = safe_atou64(eq, &rl);
1527 if (r < 0) {
1528 log_error("Invalid resource limit: %s", eq);
1529 return -EINVAL;
1530 }
1531 }
1532
1533 r = sd_bus_message_append(m, "v", "t", rl);
1534
e567439e
LP
1535 } else if (streq(field, "Nice")) {
1536 int32_t i;
1537
1538 r = safe_atoi32(eq, &i);
1539 if (r < 0) {
1540 log_error("Failed to parse %s value %s.", field, eq);
1541 return -EINVAL;
1542 }
1543
1544 r = sd_bus_message_append(m, "v", "i", i);
1545
1546 } else if (streq(field, "Environment")) {
1547
1548 r = sd_bus_message_append(m, "v", "as", 1, eq);
1549
1550 } else if (streq(field, "KillSignal")) {
1551 int sig;
1552
1553 sig = signal_from_string_try_harder(eq);
1554 if (sig < 0) {
1555 log_error("Failed to parse %s value %s.", field, eq);
1556 return -EINVAL;
1557 }
1558
1559 r = sd_bus_message_append(m, "v", "i", sig);
1560
4c213d6c
WC
1561 } else if (streq(field, "AccuracySec")) {
1562 usec_t u;
1563
1564 r = parse_sec(eq, &u);
1565 if (r < 0) {
1566 log_error("Failed to parse %s value %s", field, eq);
1567 return -EINVAL;
1568 }
1569
1570 r = sd_bus_message_append(m, "v", "t", u);
1571
df31a6c0
LP
1572 } else {
1573 log_error("Unknown assignment %s.", assignment);
1574 return -EINVAL;
1575 }
1576
1577 if (r < 0)
1578 return bus_log_create_error(r);
1579
1580 return 0;
1581}
ebd011d9
LP
1582
1583typedef struct BusWaitForJobs {
1584 sd_bus *bus;
1585 Set *jobs;
1586
1587 char *name;
1588 char *result;
1589
1590 sd_bus_slot *slot_job_removed;
1591 sd_bus_slot *slot_disconnected;
1592} BusWaitForJobs;
1593
1594static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1595 assert(bus);
1596 assert(m);
1597
1598 log_error("Warning! D-Bus connection terminated.");
1599 sd_bus_close(bus);
1600
1601 return 0;
1602}
1603
1604static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1605 const char *path, *unit, *result;
1606 BusWaitForJobs *d = userdata;
1607 uint32_t id;
1608 char *found;
1609 int r;
1610
1611 assert(bus);
1612 assert(m);
1613 assert(d);
1614
1615 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1616 if (r < 0) {
1617 bus_log_parse_error(r);
1618 return 0;
1619 }
1620
1621 found = set_remove(d->jobs, (char*) path);
1622 if (!found)
1623 return 0;
1624
1625 free(found);
1626
1627 if (!isempty(result))
1628 d->result = strdup(result);
1629
1630 if (!isempty(unit))
1631 d->name = strdup(unit);
1632
1633 return 0;
1634}
1635
1636void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1637 if (!d)
1638 return;
1639
1640 set_free_free(d->jobs);
1641
1642 sd_bus_slot_unref(d->slot_disconnected);
1643 sd_bus_slot_unref(d->slot_job_removed);
1644
1645 sd_bus_unref(d->bus);
1646
1647 free(d->name);
1648 free(d->result);
1649
1650 free(d);
1651}
1652
1653int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1654 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1655 int r;
1656
1657 assert(bus);
1658 assert(ret);
1659
1660 d = new0(BusWaitForJobs, 1);
1661 if (!d)
1662 return -ENOMEM;
1663
1664 d->bus = sd_bus_ref(bus);
1665
b798e7ba
LP
1666 /* When we are a bus client we match by sender. Direct
1667 * connections OTOH have no initialized sender field, and
1668 * hence we ignore the sender then */
ebd011d9
LP
1669 r = sd_bus_add_match(
1670 bus,
1671 &d->slot_job_removed,
b798e7ba 1672 bus->bus_client ?
ebd011d9
LP
1673 "type='signal',"
1674 "sender='org.freedesktop.systemd1',"
1675 "interface='org.freedesktop.systemd1.Manager',"
1676 "member='JobRemoved',"
b798e7ba
LP
1677 "path='/org/freedesktop/systemd1'" :
1678 "type='signal',"
1679 "interface='org.freedesktop.systemd1.Manager',"
1680 "member='JobRemoved',"
ebd011d9
LP
1681 "path='/org/freedesktop/systemd1'",
1682 match_job_removed, d);
1683 if (r < 0)
1684 return r;
1685
1686 r = sd_bus_add_match(
1687 bus,
1688 &d->slot_disconnected,
1689 "type='signal',"
1690 "sender='org.freedesktop.DBus.Local',"
1691 "interface='org.freedesktop.DBus.Local',"
1692 "member='Disconnected'",
1693 match_disconnected, d);
1694 if (r < 0)
1695 return r;
1696
1697 *ret = d;
1698 d = NULL;
1699
1700 return 0;
1701}
1702
1703static int bus_process_wait(sd_bus *bus) {
1704 int r;
1705
1706 for (;;) {
1707 r = sd_bus_process(bus, NULL);
1708 if (r < 0)
1709 return r;
1710 if (r > 0)
1711 return 0;
1712
1713 r = sd_bus_wait(bus, (uint64_t) -1);
1714 if (r < 0)
1715 return r;
1716 }
1717}
1718
1719static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1720 int r = 0;
1721
1722 assert(d->result);
1723
1724 if (!quiet) {
1725 if (streq(d->result, "canceled"))
1726 log_error("Job for %s canceled.", strna(d->name));
1727 else if (streq(d->result, "timeout"))
1728 log_error("Job for %s timed out.", strna(d->name));
1729 else if (streq(d->result, "dependency"))
1730 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1731 else if (streq(d->result, "invalid"))
1732 log_error("Job for %s invalid.", strna(d->name));
1733 else if (streq(d->result, "assert"))
1734 log_error("Assertion failed on job for %s.", strna(d->name));
1735 else if (streq(d->result, "unsupported"))
1736 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1737 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
019c7fba 1738 _cleanup_free_ char *quoted = NULL;
ebd011d9 1739
019c7fba
LP
1740 if (d->name)
1741 quoted = shell_maybe_quote(d->name);
ebd011d9 1742
019c7fba
LP
1743 if (quoted)
1744 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xe' for details.", d->name, quoted);
1745 else
1746 log_error("Job failed. See 'journalctl -xe' for details.");
ebd011d9
LP
1747 }
1748 }
1749
1750 if (streq(d->result, "canceled"))
1751 r = -ECANCELED;
1752 else if (streq(d->result, "timeout"))
1753 r = -ETIME;
1754 else if (streq(d->result, "dependency"))
1755 r = -EIO;
1756 else if (streq(d->result, "invalid"))
1757 r = -ENOEXEC;
1758 else if (streq(d->result, "assert"))
1759 r = -EPROTO;
1760 else if (streq(d->result, "unsupported"))
15411c0c 1761 r = -EOPNOTSUPP;
ebd011d9
LP
1762 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1763 r = -EIO;
1764
1765 return r;
1766}
1767
1768int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1769 int r = 0;
1770
1771 assert(d);
1772
1773 while (!set_isempty(d->jobs)) {
1774 int q;
1775
1776 q = bus_process_wait(d->bus);
1777 if (q < 0)
1778 return log_error_errno(q, "Failed to wait for response: %m");
1779
1780 if (d->result) {
1781 q = check_wait_response(d, quiet);
1782 /* Return the first error as it is most likely to be
1783 * meaningful. */
1784 if (q < 0 && r == 0)
1785 r = q;
1786
1787 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1788 }
1789
1790 free(d->name);
1791 d->name = NULL;
1792
1793 free(d->result);
1794 d->result = NULL;
1795 }
1796
1797 return r;
1798}
1799
1800int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1801 int r;
1802
1803 assert(d);
1804
1805 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1806 if (r < 0)
1807 return r;
1808
1809 return set_put_strdup(d->jobs, path);
1810}
d8f52ed2
LP
1811
1812int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
1813 const char *type, *path, *source;
1814 int r;
1815
1816 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1817 if (r < 0)
1818 return bus_log_parse_error(r);
1819
1820 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1821 if (!quiet) {
1822 if (streq(type, "symlink"))
1823 log_info("Created symlink from %s to %s.", path, source);
1824 else
1825 log_info("Removed symlink %s.", path);
1826 }
1827 }
1828 if (r < 0)
1829 return bus_log_parse_error(r);
1830
1831 r = sd_bus_message_exit_container(m);
1832 if (r < 0)
1833 return bus_log_parse_error(r);
1834
1835 return 0;
1836}