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