chiark / gitweb /
exit-on-idle: only exit if actually idle
[elogind.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 && idle) {
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", "WakeSystem", "DefaultDependencies")) {
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
1406         } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
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
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
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
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
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 }
1556
1557 typedef 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
1568 static 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
1578 static 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
1610 void 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
1627 int 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
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 */
1643         r = sd_bus_add_match(
1644                         bus,
1645                         &d->slot_job_removed,
1646                         bus->bus_client ?
1647                         "type='signal',"
1648                         "sender='org.freedesktop.systemd1',"
1649                         "interface='org.freedesktop.systemd1.Manager',"
1650                         "member='JobRemoved',"
1651                         "path='/org/freedesktop/systemd1'" :
1652                         "type='signal',"
1653                         "interface='org.freedesktop.systemd1.Manager',"
1654                         "member='JobRemoved',"
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
1677 static 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
1693 static 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
1743 int 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
1762                         errno = 0;
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
1776 int 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 }
1787
1788 int 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 }