]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-util.c
tmpfiles: accurately report creation results
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-util.c
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
22 #include <sys/socket.h>
23
24 #include "sd-daemon.h"
25 #include "sd-event.h"
26 #include "util.h"
27 #include "strv.h"
28 #include "macro.h"
29 #include "def.h"
30 #include "path-util.h"
31 #include "missing.h"
32 #include "set.h"
33
34 #include "sd-bus.h"
35 #include "bus-error.h"
36 #include "bus-message.h"
37 #include "bus-util.h"
38 #include "bus-internal.h"
39
40 static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
41 sd_event *e = userdata;
42
43 assert(bus);
44 assert(m);
45 assert(e);
46
47 sd_bus_close(bus);
48 sd_event_exit(e, 0);
49
50 return 1;
51 }
52
53 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
54 _cleanup_free_ char *match = NULL;
55 const char *unique;
56 int r;
57
58 assert(e);
59 assert(bus);
60 assert(name);
61
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
67 r = sd_bus_get_unique_name(bus, &unique);
68 if (r < 0)
69 return r;
70
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
83 r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
84 if (r < 0)
85 return r;
86
87 r = sd_bus_release_name(bus, name);
88 if (r < 0)
89 return r;
90
91 return 0;
92 }
93
94 int 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) {
101 bool exiting = false;
102 int r, code;
103
104 assert(e);
105 assert(bus);
106 assert(name);
107
108 for (;;) {
109 bool idle;
110
111 r = sd_event_get_state(e);
112 if (r < 0)
113 return r;
114 if (r == SD_EVENT_FINISHED)
115 break;
116
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);
123 if (r < 0)
124 return r;
125
126 if (r == 0 && !exiting) {
127
128 r = sd_bus_try_close(bus);
129 if (r == -EBUSY)
130 continue;
131
132 /* Fallback for dbus1 connections: we
133 * unregister the name and wait for the
134 * response to come through for it */
135 if (r == -ENOTSUP) {
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");
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
152 if (r < 0)
153 return r;
154
155 sd_event_exit(e, 0);
156 break;
157 }
158 }
159
160 r = sd_event_get_exit_code(e, &code);
161 if (r < 0)
162 return r;
163
164 return code;
165 }
166
167 int 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
193 int bus_verify_polkit(
194 sd_bus_message *call,
195 int capability,
196 const char *action,
197 bool interactive,
198 bool *_challenge,
199 sd_bus_error *e) {
200
201 int r;
202
203 assert(call);
204 assert(action);
205
206 r = sd_bus_query_sender_privilege(call, capability);
207 if (r < 0)
208 return r;
209 else if (r > 0)
210 return 1;
211 #ifdef ENABLE_POLKIT
212 else {
213 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
214 int authorized = false, challenge = false, c;
215 const char *sender;
216
217 sender = sd_bus_message_get_sender(call);
218 if (!sender)
219 return -EBADMSG;
220
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
227 r = sd_bus_call_method(
228 call->bus,
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,
239 !!interactive,
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
252 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
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;
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
275 typedef struct AsyncPolkitQuery {
276 sd_bus_message *request, *reply;
277 sd_bus_message_handler_t callback;
278 void *userdata;
279 sd_bus_slot *slot;
280 Hashmap *registry;
281 } AsyncPolkitQuery;
282
283 static void async_polkit_query_free(AsyncPolkitQuery *q) {
284
285 if (!q)
286 return;
287
288 sd_bus_slot_unref(q->slot);
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
299 static 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;
301 AsyncPolkitQuery *q = userdata;
302 int r;
303
304 assert(bus);
305 assert(reply);
306 assert(q);
307
308 q->slot = sd_bus_slot_unref(q->slot);
309 q->reply = sd_bus_message_ref(reply);
310
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 }
316
317 r = q->callback(bus, q->request, q->userdata, &error_buffer);
318 r = bus_maybe_reply_error(q->request, r, &error_buffer);
319
320 finish:
321 async_polkit_query_free(q);
322
323 return r;
324 }
325
326 #endif
327
328 int bus_verify_polkit_async(
329 sd_bus_message *call,
330 int capability,
331 const char *action,
332 bool interactive,
333 Hashmap **registry,
334 sd_bus_error *error) {
335
336 #ifdef ENABLE_POLKIT
337 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
338 AsyncPolkitQuery *q;
339 const char *sender;
340 sd_bus_message_handler_t callback;
341 void *userdata;
342 int c;
343 #endif
344 int r;
345
346 assert(call);
347 assert(action);
348 assert(registry);
349
350 #ifdef ENABLE_POLKIT
351 q = hashmap_get(*registry, call);
352 if (q) {
353 int authorized, challenge;
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
363 /* Copy error from polkit reply */
364 e = sd_bus_message_get_error(q->reply);
365 sd_bus_error_copy(error, e);
366
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
371 return -sd_bus_error_get_errno(e);
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
378 if (r < 0)
379 return r;
380
381 if (authorized)
382 return 1;
383
384 if (challenge)
385 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
386
387 return -EACCES;
388 }
389 #endif
390
391 r = sd_bus_query_sender_privilege(call, capability);
392 if (r < 0)
393 return r;
394 else if (r > 0)
395 return 1;
396
397 #ifdef ENABLE_POLKIT
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);
408 if (!sender)
409 return -EBADMSG;
410
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
417 r = hashmap_ensure_allocated(registry, NULL);
418 if (r < 0)
419 return r;
420
421 r = sd_bus_message_new_method_call(
422 call->bus,
423 &pk,
424 "org.freedesktop.PolicyKit1",
425 "/org/freedesktop/PolicyKit1/Authority",
426 "org.freedesktop.PolicyKit1.Authority",
427 "CheckAuthorization");
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,
437 !!interactive,
438 NULL);
439 if (r < 0)
440 return r;
441
442 q = new0(AsyncPolkitQuery, 1);
443 if (!q)
444 return -ENOMEM;
445
446 q->request = sd_bus_message_ref(call);
447 q->callback = callback;
448 q->userdata = userdata;
449
450 r = hashmap_put(*registry, call, q);
451 if (r < 0) {
452 async_polkit_query_free(q);
453 return r;
454 }
455
456 q->registry = *registry;
457
458 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
459 if (r < 0) {
460 async_polkit_query_free(q);
461 return r;
462 }
463
464 return 0;
465 #endif
466
467 return -EACCES;
468 }
469
470 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
471 #ifdef ENABLE_POLKIT
472 AsyncPolkitQuery *q;
473
474 while ((q = hashmap_steal_first(registry)))
475 async_polkit_query_free(q);
476
477 hashmap_free(registry);
478 #endif
479 }
480
481 int bus_check_peercred(sd_bus *c) {
482 struct ucred ucred;
483 socklen_t l;
484 int fd;
485
486 assert(c);
487
488 fd = sd_bus_get_fd(c);
489 if (fd < 0)
490 return fd;
491
492 l = sizeof(struct ucred);
493 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
494 return -errno;
495
496 if (l != sizeof(struct ucred))
497 return -E2BIG;
498
499 if (ucred.uid != 0 && ucred.uid != geteuid())
500 return -EPERM;
501
502 return 1;
503 }
504
505 int bus_open_system_systemd(sd_bus **_bus) {
506 _cleanup_bus_unref_ sd_bus *bus = NULL;
507 int r;
508
509 assert(_bus);
510
511 if (geteuid() != 0)
512 return sd_bus_open_system(_bus);
513
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 */
517
518 #ifdef ENABLE_KDBUS
519 r = sd_bus_new(&bus);
520 if (r < 0)
521 return r;
522
523 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
524 if (r < 0)
525 return r;
526
527 bus->bus_client = true;
528
529 r = sd_bus_start(bus);
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);
540 if (r < 0)
541 return r;
542
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
551 r = bus_check_peercred(bus);
552 if (r < 0)
553 return r;
554
555 *_bus = bus;
556 bus = NULL;
557
558 return 0;
559 }
560
561 int bus_open_user_systemd(sd_bus **_bus) {
562 _cleanup_bus_unref_ sd_bus *bus = NULL;
563 _cleanup_free_ char *ee = NULL;
564 const char *e;
565 int r;
566
567 /* Try via kdbus first, and then directly */
568
569 assert(_bus);
570
571 #ifdef ENABLE_KDBUS
572 r = sd_bus_new(&bus);
573 if (r < 0)
574 return r;
575
576 if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
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
591 e = secure_getenv("XDG_RUNTIME_DIR");
592 if (!e)
593 return sd_bus_open_user(_bus);
594
595 ee = bus_address_escape(e);
596 if (!ee)
597 return -ENOMEM;
598
599 r = sd_bus_new(&bus);
600 if (r < 0)
601 return r;
602
603 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
604 if (!bus->address)
605 return -ENOMEM;
606
607 r = sd_bus_start(bus);
608 if (r < 0)
609 return sd_bus_open_user(_bus);
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
621 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
622 char type;
623 const char *contents;
624 int r;
625
626 assert(name);
627 assert(property);
628
629 r = sd_bus_message_peek_type(property, &type, &contents);
630 if (r < 0)
631 return r;
632
633 switch (type) {
634
635 case SD_BUS_TYPE_STRING: {
636 const char *s;
637
638 r = sd_bus_message_read_basic(property, type, &s);
639 if (r < 0)
640 return r;
641
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 }
651
652 return 1;
653 }
654
655 case SD_BUS_TYPE_BOOLEAN: {
656 int b;
657
658 r = sd_bus_message_read_basic(property, type, &b);
659 if (r < 0)
660 return r;
661
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
670 r = sd_bus_message_read_basic(property, type, &u);
671 if (r < 0)
672 return r;
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
697 r = sd_bus_message_read_basic(property, type, &u);
698 if (r < 0)
699 return r;
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
712 r = sd_bus_message_read_basic(property, type, &i);
713 if (r < 0)
714 return r;
715
716 printf("%s=%i\n", name, (int) i);
717 return 1;
718 }
719
720 case SD_BUS_TYPE_DOUBLE: {
721 double d;
722
723 r = sd_bus_message_read_basic(property, type, &d);
724 if (r < 0)
725 return r;
726
727 printf("%s=%g\n", name, d);
728 return 1;
729 }
730
731 case SD_BUS_TYPE_ARRAY:
732 if (streq(contents, "s")) {
733 bool first = true;
734 const char *str;
735
736 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
737 if (r < 0)
738 return r;
739
740 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
741 _cleanup_free_ char *escaped = NULL;
742
743 if (first)
744 printf("%s=", name);
745
746 escaped = xescape(str, "\n ");
747 if (!escaped)
748 return -ENOMEM;
749
750 printf("%s%s", first ? "" : " ", escaped);
751
752 first = false;
753 }
754 if (r < 0)
755 return r;
756
757 if (first && all)
758 printf("%s=", name);
759 if (!first || all)
760 puts("");
761
762 r = sd_bus_message_exit_container(property);
763 if (r < 0)
764 return r;
765
766 return 1;
767
768 } else if (streq(contents, "y")) {
769 const uint8_t *u;
770 size_t n;
771
772 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
773 if (r < 0)
774 return r;
775
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
793 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
794 if (r < 0)
795 return r;
796
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 }
816
817 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
818 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
819 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
820 int r;
821
822 assert(bus);
823 assert(path);
824
825 r = sd_bus_call_method(bus,
826 dest,
827 path,
828 "org.freedesktop.DBus.Properties",
829 "GetAll",
830 &error,
831 &reply,
832 "s", "");
833 if (r < 0)
834 return r;
835
836 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
837 if (r < 0)
838 return r;
839
840 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
841 const char *name;
842 const char *contents;
843
844 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
845 if (r < 0)
846 return r;
847
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;
856
857 r = bus_print_property(name, reply, all);
858 if (r < 0)
859 return r;
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 }
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);
879 if (r < 0)
880 return r;
881 }
882 if (r < 0)
883 return r;
884
885 r = sd_bus_message_exit_container(reply);
886 if (r < 0)
887 return r;
888
889 return 0;
890 }
891
892 int 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;
897
898 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
899 if (r < 0)
900 return r;
901
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;
908
909 return 0;
910 }
911
912 static 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;
915
916 r = sd_bus_message_peek_type(m, &type, NULL);
917 if (r < 0)
918 return r;
919
920 switch (type) {
921 case SD_BUS_TYPE_STRING: {
922 const char *s;
923 char *str;
924 char **p = userdata;
925
926 r = sd_bus_message_read_basic(m, type, &s);
927 if (r < 0)
928 break;
929
930 if (isempty(s))
931 break;
932
933 str = strdup(s);
934 if (!str) {
935 r = -ENOMEM;
936 break;
937 }
938 free(*p);
939 *p = str;
940
941 break;
942 }
943
944 case SD_BUS_TYPE_ARRAY: {
945 _cleanup_strv_free_ char **l = NULL;
946 char ***p = userdata;
947
948 r = bus_message_read_strv_extend(m, &l);
949 if (r < 0)
950 break;
951
952 strv_free(*p);
953 *p = l;
954 l = NULL;
955
956 break;
957 }
958
959 case SD_BUS_TYPE_BOOLEAN: {
960 unsigned b;
961 bool *p = userdata;
962
963 r = sd_bus_message_read_basic(m, type, &b);
964 if (r < 0)
965 break;
966
967 *p = b;
968
969 break;
970 }
971
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)
978 break;
979
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)
991 break;
992
993 *p = t;
994
995 break;
996 }
997
998 default:
999 break;
1000 }
1001
1002 return r;
1003 }
1004
1005 int bus_message_map_all_properties(sd_bus *bus,
1006 sd_bus_message *m,
1007 const struct bus_properties_map *map,
1008 void *userdata) {
1009 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1010 int r;
1011
1012 assert(bus);
1013 assert(m);
1014 assert(map);
1015
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);
1028 if (r < 0)
1029 return r;
1030
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;
1047 if (map[i].set)
1048 r = prop->set(bus, member, m, &error, v);
1049 else
1050 r = map_basic(bus, member, m, &error, v);
1051 if (r < 0)
1052 return r;
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)
1060 return r;
1061 }
1062
1063 r = sd_bus_message_exit_container(m);
1064 if (r < 0)
1065 return r;
1066 }
1067
1068 return sd_bus_message_exit_container(m);
1069 }
1070
1071 int 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
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
1105 int 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);
1132 }
1133
1134 int 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)
1148 r = sd_bus_default_user(bus);
1149 else
1150 r = sd_bus_default_system(bus);
1151
1152 break;
1153
1154 case BUS_TRANSPORT_REMOTE:
1155 r = sd_bus_open_system_remote(bus, host);
1156 break;
1157
1158 case BUS_TRANSPORT_MACHINE:
1159 r = sd_bus_open_system_machine(bus, host);
1160 break;
1161
1162 default:
1163 assert_not_reached("Hmm, unknown transport type.");
1164 }
1165
1166 return r;
1167 }
1168
1169 int 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:
1190 r = sd_bus_open_system_remote(bus, host);
1191 break;
1192
1193 case BUS_TRANSPORT_MACHINE:
1194 r = sd_bus_open_system_machine(bus, host);
1195 break;
1196
1197 default:
1198 assert_not_reached("Hmm, unknown transport type.");
1199 }
1200
1201 return r;
1202 }
1203
1204 int 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,
1210 void *userdata,
1211 sd_bus_error *error) {
1212
1213 int b = *(bool*) userdata;
1214
1215 return sd_bus_message_append_basic(reply, 'b', &b);
1216 }
1217
1218 #if __SIZEOF_SIZE_T__ != 8
1219 int bus_property_get_size(
1220 sd_bus *bus,
1221 const char *path,
1222 const char *interface,
1223 const char *property,
1224 sd_bus_message *reply,
1225 void *userdata,
1226 sd_bus_error *error) {
1227
1228 uint64_t sz = *(size_t*) userdata;
1229
1230 return sd_bus_message_append_basic(reply, 't', &sz);
1231 }
1232 #endif
1233
1234 #if __SIZEOF_LONG__ != 8
1235 int 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,
1241 void *userdata,
1242 sd_bus_error *error) {
1243
1244 int64_t l = *(long*) userdata;
1245
1246 return sd_bus_message_append_basic(reply, 'x', &l);
1247 }
1248
1249 int 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,
1255 void *userdata,
1256 sd_bus_error *error) {
1257
1258 uint64_t ul = *(unsigned long*) userdata;
1259
1260 return sd_bus_message_append_basic(reply, 't', &ul);
1261 }
1262 #endif
1263
1264 int bus_log_parse_error(int r) {
1265 return log_error_errno(r, "Failed to parse bus message: %m");
1266 }
1267
1268 int bus_log_create_error(int r) {
1269 return log_error_errno(r, "Failed to create bus message: %m");
1270 }
1271
1272 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1273 assert(message);
1274 assert(u);
1275
1276 u->machine = NULL;
1277
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 }
1292
1293 int 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);
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 }
1317
1318 int 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
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
1342 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
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 {
1358 log_error("CPU quota needs to be in percent.");
1359 return -EINVAL;
1360 }
1361
1362 if (r < 0)
1363 return bus_log_create_error(r);
1364
1365 return 0;
1366 }
1367
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
1372 if (STR_IN_SET(field,
1373 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1374 "SendSIGHUP", "SendSIGKILL",
1375 "WakeSystem")) {
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
1407 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
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
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
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
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
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 }
1557
1558 typedef 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
1569 static 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
1579 static 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
1611 void 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
1628 int 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
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 */
1644 r = sd_bus_add_match(
1645 bus,
1646 &d->slot_job_removed,
1647 bus->bus_client ?
1648 "type='signal',"
1649 "sender='org.freedesktop.systemd1',"
1650 "interface='org.freedesktop.systemd1.Manager',"
1651 "member='JobRemoved',"
1652 "path='/org/freedesktop/systemd1'" :
1653 "type='signal',"
1654 "interface='org.freedesktop.systemd1.Manager',"
1655 "member='JobRemoved',"
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
1678 static 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
1694 static 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
1744 int 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
1763 errno = 0;
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
1777 int 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 }
1788
1789 int 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 }