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