]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-util.c
tmpfiles: accurately report creation results
[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
126 if (r == 0 && !exiting) {
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",
4c213d6c
WC
1374 "SendSIGHUP", "SendSIGKILL",
1375 "WakeSystem")) {
df31a6c0
LP
1376
1377 r = parse_boolean(eq);
1378 if (r < 0) {
1379 log_error("Failed to parse boolean assignment %s.", assignment);
1380 return -EINVAL;
1381 }
1382
1383 r = sd_bus_message_append(m, "v", "b", r);
1384
1385 } else if (streq(field, "MemoryLimit")) {
1386 off_t bytes;
1387
1388 r = parse_size(eq, 1024, &bytes);
1389 if (r < 0) {
1390 log_error("Failed to parse bytes specification %s", assignment);
1391 return -EINVAL;
1392 }
1393
1394 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1395
1396 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1397 uint64_t u;
1398
1399 r = safe_atou64(eq, &u);
1400 if (r < 0) {
1401 log_error("Failed to parse %s value %s.", field, eq);
1402 return -EINVAL;
1403 }
1404
1405 r = sd_bus_message_append(m, "v", "t", u);
1406
e567439e 1407 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
df31a6c0
LP
1408 r = sd_bus_message_append(m, "v", "s", eq);
1409
1410 else if (streq(field, "DeviceAllow")) {
1411
1412 if (isempty(eq))
1413 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1414 else {
1415 const char *path, *rwm, *e;
1416
1417 e = strchr(eq, ' ');
1418 if (e) {
1419 path = strndupa(eq, e - eq);
1420 rwm = e+1;
1421 } else {
1422 path = eq;
1423 rwm = "";
1424 }
1425
1426 if (!path_startswith(path, "/dev")) {
1427 log_error("%s is not a device file in /dev.", path);
1428 return -EINVAL;
1429 }
1430
1431 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1432 }
1433
1434 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1435
1436 if (isempty(eq))
1437 r = sd_bus_message_append(m, "v", "a(st)", 0);
1438 else {
1439 const char *path, *bandwidth, *e;
1440 off_t bytes;
1441
1442 e = strchr(eq, ' ');
1443 if (e) {
1444 path = strndupa(eq, e - eq);
1445 bandwidth = e+1;
1446 } else {
1447 log_error("Failed to parse %s value %s.", field, eq);
1448 return -EINVAL;
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 = parse_size(bandwidth, 1000, &bytes);
1457 if (r < 0) {
1458 log_error("Failed to parse byte value %s.", bandwidth);
1459 return -EINVAL;
1460 }
1461
1462 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1463 }
1464
1465 } else if (streq(field, "BlockIODeviceWeight")) {
1466
1467 if (isempty(eq))
1468 r = sd_bus_message_append(m, "v", "a(st)", 0);
1469 else {
1470 const char *path, *weight, *e;
1471 uint64_t u;
1472
1473 e = strchr(eq, ' ');
1474 if (e) {
1475 path = strndupa(eq, e - eq);
1476 weight = e+1;
1477 } else {
1478 log_error("Failed to parse %s value %s.", field, eq);
1479 return -EINVAL;
1480 }
1481
1482 if (!path_startswith(path, "/dev")) {
1483 log_error("%s is not a device file in /dev.", path);
1484 return -EINVAL;
1485 }
1486
1487 r = safe_atou64(weight, &u);
1488 if (r < 0) {
1489 log_error("Failed to parse %s value %s.", field, weight);
1490 return -EINVAL;
1491 }
1492 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1493 }
1494
d584f638
LP
1495 } else if (rlimit_from_string(field) >= 0) {
1496 uint64_t rl;
1497
1498 if (streq(eq, "infinity"))
1499 rl = (uint64_t) -1;
1500 else {
1501 r = safe_atou64(eq, &rl);
1502 if (r < 0) {
1503 log_error("Invalid resource limit: %s", eq);
1504 return -EINVAL;
1505 }
1506 }
1507
1508 r = sd_bus_message_append(m, "v", "t", rl);
1509
e567439e
LP
1510 } else if (streq(field, "Nice")) {
1511 int32_t i;
1512
1513 r = safe_atoi32(eq, &i);
1514 if (r < 0) {
1515 log_error("Failed to parse %s value %s.", field, eq);
1516 return -EINVAL;
1517 }
1518
1519 r = sd_bus_message_append(m, "v", "i", i);
1520
1521 } else if (streq(field, "Environment")) {
1522
1523 r = sd_bus_message_append(m, "v", "as", 1, eq);
1524
1525 } else if (streq(field, "KillSignal")) {
1526 int sig;
1527
1528 sig = signal_from_string_try_harder(eq);
1529 if (sig < 0) {
1530 log_error("Failed to parse %s value %s.", field, eq);
1531 return -EINVAL;
1532 }
1533
1534 r = sd_bus_message_append(m, "v", "i", sig);
1535
4c213d6c
WC
1536 } else if (streq(field, "AccuracySec")) {
1537 usec_t u;
1538
1539 r = parse_sec(eq, &u);
1540 if (r < 0) {
1541 log_error("Failed to parse %s value %s", field, eq);
1542 return -EINVAL;
1543 }
1544
1545 r = sd_bus_message_append(m, "v", "t", u);
1546
df31a6c0
LP
1547 } else {
1548 log_error("Unknown assignment %s.", assignment);
1549 return -EINVAL;
1550 }
1551
1552 if (r < 0)
1553 return bus_log_create_error(r);
1554
1555 return 0;
1556}
ebd011d9
LP
1557
1558typedef struct BusWaitForJobs {
1559 sd_bus *bus;
1560 Set *jobs;
1561
1562 char *name;
1563 char *result;
1564
1565 sd_bus_slot *slot_job_removed;
1566 sd_bus_slot *slot_disconnected;
1567} BusWaitForJobs;
1568
1569static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1570 assert(bus);
1571 assert(m);
1572
1573 log_error("Warning! D-Bus connection terminated.");
1574 sd_bus_close(bus);
1575
1576 return 0;
1577}
1578
1579static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1580 const char *path, *unit, *result;
1581 BusWaitForJobs *d = userdata;
1582 uint32_t id;
1583 char *found;
1584 int r;
1585
1586 assert(bus);
1587 assert(m);
1588 assert(d);
1589
1590 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1591 if (r < 0) {
1592 bus_log_parse_error(r);
1593 return 0;
1594 }
1595
1596 found = set_remove(d->jobs, (char*) path);
1597 if (!found)
1598 return 0;
1599
1600 free(found);
1601
1602 if (!isempty(result))
1603 d->result = strdup(result);
1604
1605 if (!isempty(unit))
1606 d->name = strdup(unit);
1607
1608 return 0;
1609}
1610
1611void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1612 if (!d)
1613 return;
1614
1615 set_free_free(d->jobs);
1616
1617 sd_bus_slot_unref(d->slot_disconnected);
1618 sd_bus_slot_unref(d->slot_job_removed);
1619
1620 sd_bus_unref(d->bus);
1621
1622 free(d->name);
1623 free(d->result);
1624
1625 free(d);
1626}
1627
1628int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1629 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1630 int r;
1631
1632 assert(bus);
1633 assert(ret);
1634
1635 d = new0(BusWaitForJobs, 1);
1636 if (!d)
1637 return -ENOMEM;
1638
1639 d->bus = sd_bus_ref(bus);
1640
b798e7ba
LP
1641 /* When we are a bus client we match by sender. Direct
1642 * connections OTOH have no initialized sender field, and
1643 * hence we ignore the sender then */
ebd011d9
LP
1644 r = sd_bus_add_match(
1645 bus,
1646 &d->slot_job_removed,
b798e7ba 1647 bus->bus_client ?
ebd011d9
LP
1648 "type='signal',"
1649 "sender='org.freedesktop.systemd1',"
1650 "interface='org.freedesktop.systemd1.Manager',"
1651 "member='JobRemoved',"
b798e7ba
LP
1652 "path='/org/freedesktop/systemd1'" :
1653 "type='signal',"
1654 "interface='org.freedesktop.systemd1.Manager',"
1655 "member='JobRemoved',"
ebd011d9
LP
1656 "path='/org/freedesktop/systemd1'",
1657 match_job_removed, d);
1658 if (r < 0)
1659 return r;
1660
1661 r = sd_bus_add_match(
1662 bus,
1663 &d->slot_disconnected,
1664 "type='signal',"
1665 "sender='org.freedesktop.DBus.Local',"
1666 "interface='org.freedesktop.DBus.Local',"
1667 "member='Disconnected'",
1668 match_disconnected, d);
1669 if (r < 0)
1670 return r;
1671
1672 *ret = d;
1673 d = NULL;
1674
1675 return 0;
1676}
1677
1678static int bus_process_wait(sd_bus *bus) {
1679 int r;
1680
1681 for (;;) {
1682 r = sd_bus_process(bus, NULL);
1683 if (r < 0)
1684 return r;
1685 if (r > 0)
1686 return 0;
1687
1688 r = sd_bus_wait(bus, (uint64_t) -1);
1689 if (r < 0)
1690 return r;
1691 }
1692}
1693
1694static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1695 int r = 0;
1696
1697 assert(d->result);
1698
1699 if (!quiet) {
1700 if (streq(d->result, "canceled"))
1701 log_error("Job for %s canceled.", strna(d->name));
1702 else if (streq(d->result, "timeout"))
1703 log_error("Job for %s timed out.", strna(d->name));
1704 else if (streq(d->result, "dependency"))
1705 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1706 else if (streq(d->result, "invalid"))
1707 log_error("Job for %s invalid.", strna(d->name));
1708 else if (streq(d->result, "assert"))
1709 log_error("Assertion failed on job for %s.", strna(d->name));
1710 else if (streq(d->result, "unsupported"))
1711 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1712 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
1713 if (d->name) {
1714 bool quotes;
1715
1716 quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
1717
1718 log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
1719 d->name,
1720 quotes ? "'" : "", d->name, quotes ? "'" : "");
1721 } else
1722 log_error("Job failed. See \"journalctl -xe\" for details.");
1723 }
1724 }
1725
1726 if (streq(d->result, "canceled"))
1727 r = -ECANCELED;
1728 else if (streq(d->result, "timeout"))
1729 r = -ETIME;
1730 else if (streq(d->result, "dependency"))
1731 r = -EIO;
1732 else if (streq(d->result, "invalid"))
1733 r = -ENOEXEC;
1734 else if (streq(d->result, "assert"))
1735 r = -EPROTO;
1736 else if (streq(d->result, "unsupported"))
1737 r = -ENOTSUP;
1738 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1739 r = -EIO;
1740
1741 return r;
1742}
1743
1744int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1745 int r = 0;
1746
1747 assert(d);
1748
1749 while (!set_isempty(d->jobs)) {
1750 int q;
1751
1752 q = bus_process_wait(d->bus);
1753 if (q < 0)
1754 return log_error_errno(q, "Failed to wait for response: %m");
1755
1756 if (d->result) {
1757 q = check_wait_response(d, quiet);
1758 /* Return the first error as it is most likely to be
1759 * meaningful. */
1760 if (q < 0 && r == 0)
1761 r = q;
1762
2efe2438 1763 errno = 0;
ebd011d9
LP
1764 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1765 }
1766
1767 free(d->name);
1768 d->name = NULL;
1769
1770 free(d->result);
1771 d->result = NULL;
1772 }
1773
1774 return r;
1775}
1776
1777int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1778 int r;
1779
1780 assert(d);
1781
1782 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1783 if (r < 0)
1784 return r;
1785
1786 return set_put_strdup(d->jobs, path);
1787}
d8f52ed2
LP
1788
1789int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
1790 const char *type, *path, *source;
1791 int r;
1792
1793 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1794 if (r < 0)
1795 return bus_log_parse_error(r);
1796
1797 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1798 if (!quiet) {
1799 if (streq(type, "symlink"))
1800 log_info("Created symlink from %s to %s.", path, source);
1801 else
1802 log_info("Removed symlink %s.", path);
1803 }
1804 }
1805 if (r < 0)
1806 return bus_log_parse_error(r);
1807
1808 r = sd_bus_message_exit_container(m);
1809 if (r < 0)
1810 return bus_log_parse_error(r);
1811
1812 return 0;
1813}