chiark / gitweb /
Cleaned up more unneeded types and functions.
[elogind.git] / src / shared / 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 // #include "signal-util.h"
34 #include "unit-name.h"
35
36 // #include "sd-bus.h"
37 // #include "bus-error.h"
38 // #include "bus-label.h"
39 #include "bus-message.h"
40 #include "bus-util.h"
41 #include "bus-internal.h"
42
43 /// UNNEEDED by elogind
44 #if 0
45 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
46         sd_event *e = userdata;
47
48         assert(m);
49         assert(e);
50
51         sd_bus_close(sd_bus_message_get_bus(m));
52         sd_event_exit(e, 0);
53
54         return 1;
55 }
56
57 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
58         _cleanup_free_ char *match = NULL;
59         const char *unique;
60         int r;
61
62         assert(e);
63         assert(bus);
64         assert(name);
65
66         /* We unregister the name here and then wait for the
67          * NameOwnerChanged signal for this event to arrive before we
68          * quit. We do this in order to make sure that any queued
69          * requests are still processed before we really exit. */
70
71         r = sd_bus_get_unique_name(bus, &unique);
72         if (r < 0)
73                 return r;
74
75         r = asprintf(&match,
76                      "sender='org.freedesktop.DBus',"
77                      "type='signal',"
78                      "interface='org.freedesktop.DBus',"
79                      "member='NameOwnerChanged',"
80                      "path='/org/freedesktop/DBus',"
81                      "arg0='%s',"
82                      "arg1='%s',"
83                      "arg2=''", name, unique);
84         if (r < 0)
85                 return -ENOMEM;
86
87         r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
88         if (r < 0)
89                 return r;
90
91         r = sd_bus_release_name(bus, name);
92         if (r < 0)
93                 return r;
94
95         return 0;
96 }
97
98 int bus_event_loop_with_idle(
99                 sd_event *e,
100                 sd_bus *bus,
101                 const char *name,
102                 usec_t timeout,
103                 check_idle_t check_idle,
104                 void *userdata) {
105         bool exiting = false;
106         int r, code;
107
108         assert(e);
109         assert(bus);
110         assert(name);
111
112         for (;;) {
113                 bool idle;
114
115                 r = sd_event_get_state(e);
116                 if (r < 0)
117                         return r;
118                 if (r == SD_EVENT_FINISHED)
119                         break;
120
121                 if (check_idle)
122                         idle = check_idle(userdata);
123                 else
124                         idle = true;
125
126                 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
127                 if (r < 0)
128                         return r;
129
130                 if (r == 0 && !exiting && idle) {
131
132                         r = sd_bus_try_close(bus);
133                         if (r == -EBUSY)
134                                 continue;
135
136                         /* Fallback for dbus1 connections: we
137                          * unregister the name and wait for the
138                          * response to come through for it */
139                         if (r == -EOPNOTSUPP) {
140
141                                 /* Inform the service manager that we
142                                  * are going down, so that it will
143                                  * queue all further start requests,
144                                  * instead of assuming we are already
145                                  * running. */
146                                 sd_notify(false, "STOPPING=1");
147
148                                 r = bus_async_unregister_and_exit(e, bus, name);
149                                 if (r < 0)
150                                         return r;
151
152                                 exiting = true;
153                                 continue;
154                         }
155
156                         if (r < 0)
157                                 return r;
158
159                         sd_event_exit(e, 0);
160                         break;
161                 }
162         }
163
164         r = sd_event_get_exit_code(e, &code);
165         if (r < 0)
166                 return r;
167
168         return code;
169 }
170 #endif // 0
171
172 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
173         _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
174         int r, has_owner = 0;
175
176         assert(c);
177         assert(name);
178
179         r = sd_bus_call_method(c,
180                                "org.freedesktop.DBus",
181                                "/org/freedesktop/dbus",
182                                "org.freedesktop.DBus",
183                                "NameHasOwner",
184                                error,
185                                &rep,
186                                "s",
187                                name);
188         if (r < 0)
189                 return r;
190
191         r = sd_bus_message_read_basic(rep, 'b', &has_owner);
192         if (r < 0)
193                 return sd_bus_error_set_errno(error, r);
194
195         return has_owner;
196 }
197
198 static int check_good_user(sd_bus_message *m, uid_t good_user) {
199         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
200         uid_t sender_uid;
201         int r;
202
203         assert(m);
204
205         if (good_user == UID_INVALID)
206                 return 0;
207
208         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
209         if (r < 0)
210                 return r;
211
212         /* Don't trust augmented credentials for authorization */
213         assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
214
215         r = sd_bus_creds_get_euid(creds, &sender_uid);
216         if (r < 0)
217                 return r;
218
219         return sender_uid == good_user;
220 }
221
222 int bus_test_polkit(
223                 sd_bus_message *call,
224                 int capability,
225                 const char *action,
226                 const char **details,
227                 uid_t good_user,
228                 bool *_challenge,
229                 sd_bus_error *e) {
230
231         int r;
232
233         assert(call);
234         assert(action);
235
236         /* Tests non-interactively! */
237
238         r = check_good_user(call, good_user);
239         if (r != 0)
240                 return r;
241
242         r = sd_bus_query_sender_privilege(call, capability);
243         if (r < 0)
244                 return r;
245         else if (r > 0)
246                 return 1;
247 #ifdef ENABLE_POLKIT
248         else {
249                 _cleanup_bus_message_unref_ sd_bus_message *request = NULL;
250                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
251                 int authorized = false, challenge = false;
252                 const char *sender, **k, **v;
253
254                 sender = sd_bus_message_get_sender(call);
255                 if (!sender)
256                         return -EBADMSG;
257
258                 r = sd_bus_message_new_method_call(
259                                 call->bus,
260                                 &request,
261                                 "org.freedesktop.PolicyKit1",
262                                 "/org/freedesktop/PolicyKit1/Authority",
263                                 "org.freedesktop.PolicyKit1.Authority",
264                                 "CheckAuthorization");
265                 if (r < 0)
266                         return r;
267
268                 r = sd_bus_message_append(
269                                 request,
270                                 "(sa{sv})s",
271                                 "system-bus-name", 1, "name", "s", sender,
272                                 action);
273                 if (r < 0)
274                         return r;
275
276                 r = sd_bus_message_open_container(request, 'a', "{ss}");
277                 if (r < 0)
278                         return r;
279
280                 STRV_FOREACH_PAIR(k, v, details) {
281                         r = sd_bus_message_append(request, "{ss}", *k, *v);
282                         if (r < 0)
283                                 return r;
284                 }
285
286                 r = sd_bus_message_close_container(request);
287                 if (r < 0)
288                         return r;
289
290                 r = sd_bus_message_append(request, "us", 0, NULL);
291                 if (r < 0)
292                         return r;
293
294                 r = sd_bus_call(call->bus, request, 0, e, &reply);
295                 if (r < 0) {
296                         /* Treat no PK available as access denied */
297                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
298                                 sd_bus_error_free(e);
299                                 return -EACCES;
300                         }
301
302                         return r;
303                 }
304
305                 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
306                 if (r < 0)
307                         return r;
308
309                 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
310                 if (r < 0)
311                         return r;
312
313                 if (authorized)
314                         return 1;
315
316                 if (_challenge) {
317                         *_challenge = challenge;
318                         return 0;
319                 }
320         }
321 #endif
322
323         return -EACCES;
324 }
325
326 #ifdef ENABLE_POLKIT
327
328 typedef struct AsyncPolkitQuery {
329         sd_bus_message *request, *reply;
330         sd_bus_message_handler_t callback;
331         void *userdata;
332         sd_bus_slot *slot;
333         Hashmap *registry;
334 } AsyncPolkitQuery;
335
336 static void async_polkit_query_free(AsyncPolkitQuery *q) {
337
338         if (!q)
339                 return;
340
341         sd_bus_slot_unref(q->slot);
342
343         if (q->registry && q->request)
344                 hashmap_remove(q->registry, q->request);
345
346         sd_bus_message_unref(q->request);
347         sd_bus_message_unref(q->reply);
348
349         free(q);
350 }
351
352 static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
353         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
354         AsyncPolkitQuery *q = userdata;
355         int r;
356
357         assert(reply);
358         assert(q);
359
360         q->slot = sd_bus_slot_unref(q->slot);
361         q->reply = sd_bus_message_ref(reply);
362
363         r = sd_bus_message_rewind(q->request, true);
364         if (r < 0) {
365                 r = sd_bus_reply_method_errno(q->request, r, NULL);
366                 goto finish;
367         }
368
369         r = q->callback(q->request, q->userdata, &error_buffer);
370         r = bus_maybe_reply_error(q->request, r, &error_buffer);
371
372 finish:
373         async_polkit_query_free(q);
374
375         return r;
376 }
377
378 #endif
379
380 int bus_verify_polkit_async(
381                 sd_bus_message *call,
382                 int capability,
383                 const char *action,
384                 const char **details,
385                 bool interactive,
386                 uid_t good_user,
387                 Hashmap **registry,
388                 sd_bus_error *error) {
389
390 #ifdef ENABLE_POLKIT
391         _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
392         AsyncPolkitQuery *q;
393         const char *sender, **k, **v;
394         sd_bus_message_handler_t callback;
395         void *userdata;
396         int c;
397 #endif
398         int r;
399
400         assert(call);
401         assert(action);
402         assert(registry);
403
404         r = check_good_user(call, good_user);
405         if (r != 0)
406                 return r;
407
408 #ifdef ENABLE_POLKIT
409         q = hashmap_get(*registry, call);
410         if (q) {
411                 int authorized, challenge;
412
413                 /* This is the second invocation of this function, and
414                  * there's already a response from polkit, let's
415                  * process it */
416                 assert(q->reply);
417
418                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
419                         const sd_bus_error *e;
420
421                         /* Copy error from polkit reply */
422                         e = sd_bus_message_get_error(q->reply);
423                         sd_bus_error_copy(error, e);
424
425                         /* Treat no PK available as access denied */
426                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
427                                 return -EACCES;
428
429                         return -sd_bus_error_get_errno(e);
430                 }
431
432                 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
433                 if (r >= 0)
434                         r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
435
436                 if (r < 0)
437                         return r;
438
439                 if (authorized)
440                         return 1;
441
442                 if (challenge)
443                         return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
444
445                 return -EACCES;
446         }
447 #endif
448
449         r = sd_bus_query_sender_privilege(call, capability);
450         if (r < 0)
451                 return r;
452         else if (r > 0)
453                 return 1;
454
455 #ifdef ENABLE_POLKIT
456         if (sd_bus_get_current_message(call->bus) != call)
457                 return -EINVAL;
458
459         callback = sd_bus_get_current_handler(call->bus);
460         if (!callback)
461                 return -EINVAL;
462
463         userdata = sd_bus_get_current_userdata(call->bus);
464
465         sender = sd_bus_message_get_sender(call);
466         if (!sender)
467                 return -EBADMSG;
468
469         c = sd_bus_message_get_allow_interactive_authorization(call);
470         if (c < 0)
471                 return c;
472         if (c > 0)
473                 interactive = true;
474
475         r = hashmap_ensure_allocated(registry, NULL);
476         if (r < 0)
477                 return r;
478
479         r = sd_bus_message_new_method_call(
480                         call->bus,
481                         &pk,
482                         "org.freedesktop.PolicyKit1",
483                         "/org/freedesktop/PolicyKit1/Authority",
484                         "org.freedesktop.PolicyKit1.Authority",
485                         "CheckAuthorization");
486         if (r < 0)
487                 return r;
488
489         r = sd_bus_message_append(
490                         pk,
491                         "(sa{sv})s",
492                         "system-bus-name", 1, "name", "s", sender,
493                         action);
494         if (r < 0)
495                 return r;
496
497         r = sd_bus_message_open_container(pk, 'a', "{ss}");
498         if (r < 0)
499                 return r;
500
501         STRV_FOREACH_PAIR(k, v, details) {
502                 r = sd_bus_message_append(pk, "{ss}", *k, *v);
503                 if (r < 0)
504                         return r;
505         }
506
507         r = sd_bus_message_close_container(pk);
508         if (r < 0)
509                 return r;
510
511         r = sd_bus_message_append(pk, "us", !!interactive, NULL);
512         if (r < 0)
513                 return r;
514
515         q = new0(AsyncPolkitQuery, 1);
516         if (!q)
517                 return -ENOMEM;
518
519         q->request = sd_bus_message_ref(call);
520         q->callback = callback;
521         q->userdata = userdata;
522
523         r = hashmap_put(*registry, call, q);
524         if (r < 0) {
525                 async_polkit_query_free(q);
526                 return r;
527         }
528
529         q->registry = *registry;
530
531         r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
532         if (r < 0) {
533                 async_polkit_query_free(q);
534                 return r;
535         }
536
537         return 0;
538 #endif
539
540         return -EACCES;
541 }
542
543 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
544 #ifdef ENABLE_POLKIT
545         AsyncPolkitQuery *q;
546
547         while ((q = hashmap_steal_first(registry)))
548                 async_polkit_query_free(q);
549
550         hashmap_free(registry);
551 #endif
552 }
553
554 /// UNNEEDED by elogind
555 #if 0
556 int bus_check_peercred(sd_bus *c) {
557         struct ucred ucred;
558         socklen_t l;
559         int fd;
560
561         assert(c);
562
563         fd = sd_bus_get_fd(c);
564         if (fd < 0)
565                 return fd;
566
567         l = sizeof(struct ucred);
568         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
569                 return -errno;
570
571         if (l != sizeof(struct ucred))
572                 return -E2BIG;
573
574         if (ucred.uid != 0 && ucred.uid != geteuid())
575                 return -EPERM;
576
577         return 1;
578 }
579
580 int bus_open_system_systemd(sd_bus **_bus) {
581         _cleanup_bus_unref_ sd_bus *bus = NULL;
582         int r;
583
584         assert(_bus);
585
586         if (geteuid() != 0)
587                 return sd_bus_open_system(_bus);
588
589         /* If we are root and kdbus is not available, then let's talk
590          * directly to the system instance, instead of going via the
591          * bus */
592
593         r = sd_bus_new(&bus);
594         if (r < 0)
595                 return r;
596
597         r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
598         if (r < 0)
599                 return r;
600
601         bus->bus_client = true;
602
603         r = sd_bus_start(bus);
604         if (r >= 0) {
605                 *_bus = bus;
606                 bus = NULL;
607                 return 0;
608         }
609
610         bus = sd_bus_unref(bus);
611
612         r = sd_bus_new(&bus);
613         if (r < 0)
614                 return r;
615
616         r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
617         if (r < 0)
618                 return r;
619
620         r = sd_bus_start(bus);
621         if (r < 0)
622                 return sd_bus_open_system(_bus);
623
624         r = bus_check_peercred(bus);
625         if (r < 0)
626                 return r;
627
628         *_bus = bus;
629         bus = NULL;
630
631         return 0;
632 }
633
634 int bus_open_user_systemd(sd_bus **_bus) {
635         _cleanup_bus_unref_ sd_bus *bus = NULL;
636         _cleanup_free_ char *ee = NULL;
637         const char *e;
638         int r;
639
640         /* Try via kdbus first, and then directly */
641
642         assert(_bus);
643
644         r = sd_bus_new(&bus);
645         if (r < 0)
646                 return r;
647
648         if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
649                 return -ENOMEM;
650
651         bus->bus_client = true;
652
653         r = sd_bus_start(bus);
654         if (r >= 0) {
655                 *_bus = bus;
656                 bus = NULL;
657                 return 0;
658         }
659
660         bus = sd_bus_unref(bus);
661
662         e = secure_getenv("XDG_RUNTIME_DIR");
663         if (!e)
664                 return sd_bus_open_user(_bus);
665
666         ee = bus_address_escape(e);
667         if (!ee)
668                 return -ENOMEM;
669
670         r = sd_bus_new(&bus);
671         if (r < 0)
672                 return r;
673
674         bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
675         if (!bus->address)
676                 return -ENOMEM;
677
678         r = sd_bus_start(bus);
679         if (r < 0)
680                 return sd_bus_open_user(_bus);
681
682         r = bus_check_peercred(bus);
683         if (r < 0)
684                 return r;
685
686         *_bus = bus;
687         bus = NULL;
688
689         return 0;
690 }
691 #endif // 0
692
693 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
694         char type;
695         const char *contents;
696         int r;
697
698         assert(name);
699         assert(property);
700
701         r = sd_bus_message_peek_type(property, &type, &contents);
702         if (r < 0)
703                 return r;
704
705         switch (type) {
706
707         case SD_BUS_TYPE_STRING: {
708                 const char *s;
709
710                 r = sd_bus_message_read_basic(property, type, &s);
711                 if (r < 0)
712                         return r;
713
714                 if (all || !isempty(s)) {
715                         _cleanup_free_ char *escaped = NULL;
716
717                         escaped = xescape(s, "\n");
718                         if (!escaped)
719                                 return -ENOMEM;
720
721                         printf("%s=%s\n", name, escaped);
722                 }
723
724                 return 1;
725         }
726
727         case SD_BUS_TYPE_BOOLEAN: {
728                 int b;
729
730                 r = sd_bus_message_read_basic(property, type, &b);
731                 if (r < 0)
732                         return r;
733
734                 printf("%s=%s\n", name, yes_no(b));
735
736                 return 1;
737         }
738
739         case SD_BUS_TYPE_UINT64: {
740                 uint64_t u;
741
742                 r = sd_bus_message_read_basic(property, type, &u);
743                 if (r < 0)
744                         return r;
745
746                 /* Yes, heuristics! But we can change this check
747                  * should it turn out to not be sufficient */
748
749                 if (endswith(name, "Timestamp")) {
750                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
751
752                         t = format_timestamp(timestamp, sizeof(timestamp), u);
753                         if (t || all)
754                                 printf("%s=%s\n", name, strempty(t));
755
756                 } else if (strstr(name, "USec")) {
757                         char timespan[FORMAT_TIMESPAN_MAX];
758
759                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
760                 } else
761                         printf("%s=%llu\n", name, (unsigned long long) u);
762
763                 return 1;
764         }
765
766         case SD_BUS_TYPE_INT64: {
767                 int64_t i;
768
769                 r = sd_bus_message_read_basic(property, type, &i);
770                 if (r < 0)
771                         return r;
772
773                 printf("%s=%lld\n", name, (long long) i);
774
775                 return 1;
776         }
777
778         case SD_BUS_TYPE_UINT32: {
779                 uint32_t u;
780
781                 r = sd_bus_message_read_basic(property, type, &u);
782                 if (r < 0)
783                         return r;
784
785                 if (strstr(name, "UMask") || strstr(name, "Mode"))
786                         printf("%s=%04o\n", name, u);
787                 else
788                         printf("%s=%u\n", name, (unsigned) u);
789
790                 return 1;
791         }
792
793         case SD_BUS_TYPE_INT32: {
794                 int32_t i;
795
796                 r = sd_bus_message_read_basic(property, type, &i);
797                 if (r < 0)
798                         return r;
799
800                 printf("%s=%i\n", name, (int) i);
801                 return 1;
802         }
803
804         case SD_BUS_TYPE_DOUBLE: {
805                 double d;
806
807                 r = sd_bus_message_read_basic(property, type, &d);
808                 if (r < 0)
809                         return r;
810
811                 printf("%s=%g\n", name, d);
812                 return 1;
813         }
814
815         case SD_BUS_TYPE_ARRAY:
816                 if (streq(contents, "s")) {
817                         bool first = true;
818                         const char *str;
819
820                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
821                         if (r < 0)
822                                 return r;
823
824                         while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
825                                 _cleanup_free_ char *escaped = NULL;
826
827                                 if (first)
828                                         printf("%s=", name);
829
830                                 escaped = xescape(str, "\n ");
831                                 if (!escaped)
832                                         return -ENOMEM;
833
834                                 printf("%s%s", first ? "" : " ", escaped);
835
836                                 first = false;
837                         }
838                         if (r < 0)
839                                 return r;
840
841                         if (first && all)
842                                 printf("%s=", name);
843                         if (!first || all)
844                                 puts("");
845
846                         r = sd_bus_message_exit_container(property);
847                         if (r < 0)
848                                 return r;
849
850                         return 1;
851
852                 } else if (streq(contents, "y")) {
853                         const uint8_t *u;
854                         size_t n;
855
856                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
857                         if (r < 0)
858                                 return r;
859
860                         if (all || n > 0) {
861                                 unsigned int i;
862
863                                 printf("%s=", name);
864
865                                 for (i = 0; i < n; i++)
866                                         printf("%02x", u[i]);
867
868                                 puts("");
869                         }
870
871                         return 1;
872
873                 } else if (streq(contents, "u")) {
874                         uint32_t *u;
875                         size_t n;
876
877                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
878                         if (r < 0)
879                                 return r;
880
881                         if (all || n > 0) {
882                                 unsigned int i;
883
884                                 printf("%s=", name);
885
886                                 for (i = 0; i < n; i++)
887                                         printf("%08x", u[i]);
888
889                                 puts("");
890                         }
891
892                         return 1;
893                 }
894
895                 break;
896         }
897
898         return 0;
899 }
900
901 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
902         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
903         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
904         int r;
905
906         assert(bus);
907         assert(path);
908
909         r = sd_bus_call_method(bus,
910                         dest,
911                         path,
912                         "org.freedesktop.DBus.Properties",
913                         "GetAll",
914                         &error,
915                         &reply,
916                         "s", "");
917         if (r < 0)
918                 return r;
919
920         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
921         if (r < 0)
922                 return r;
923
924         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
925                 const char *name;
926                 const char *contents;
927
928                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
929                 if (r < 0)
930                         return r;
931
932                 if (!filter || strv_find(filter, name)) {
933                         r = sd_bus_message_peek_type(reply, NULL, &contents);
934                         if (r < 0)
935                                 return r;
936
937                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
938                         if (r < 0)
939                                 return r;
940
941                         r = bus_print_property(name, reply, all);
942                         if (r < 0)
943                                 return r;
944                         if (r == 0) {
945                                 if (all)
946                                         printf("%s=[unprintable]\n", name);
947                                 /* skip what we didn't read */
948                                 r = sd_bus_message_skip(reply, contents);
949                                 if (r < 0)
950                                         return r;
951                         }
952
953                         r = sd_bus_message_exit_container(reply);
954                         if (r < 0)
955                                 return r;
956                 } else {
957                         r = sd_bus_message_skip(reply, "v");
958                         if (r < 0)
959                                 return r;
960                 }
961
962                 r = sd_bus_message_exit_container(reply);
963                 if (r < 0)
964                         return r;
965         }
966         if (r < 0)
967                 return r;
968
969         r = sd_bus_message_exit_container(reply);
970         if (r < 0)
971                 return r;
972
973         return 0;
974 }
975
976 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
977         sd_id128_t *p = userdata;
978         const void *v;
979         size_t n;
980         int r;
981
982         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
983         if (r < 0)
984                 return r;
985
986         if (n == 0)
987                 *p = SD_ID128_NULL;
988         else if (n == 16)
989                 memcpy((*p).bytes, v, n);
990         else
991                 return -EINVAL;
992
993         return 0;
994 }
995
996 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
997         char type;
998         int r;
999
1000         r = sd_bus_message_peek_type(m, &type, NULL);
1001         if (r < 0)
1002                 return r;
1003
1004         switch (type) {
1005         case SD_BUS_TYPE_STRING: {
1006                 const char *s;
1007                 char **p = userdata;
1008
1009                 r = sd_bus_message_read_basic(m, type, &s);
1010                 if (r < 0)
1011                         break;
1012
1013                 if (isempty(s))
1014                         break;
1015
1016                 r = free_and_strdup(p, s);
1017                 break;
1018         }
1019
1020         case SD_BUS_TYPE_ARRAY: {
1021                _cleanup_strv_free_ char **l = NULL;
1022                char ***p = userdata;
1023
1024                 r = bus_message_read_strv_extend(m, &l);
1025                 if (r < 0)
1026                         break;
1027
1028                 strv_free(*p);
1029                 *p = l;
1030                 l = NULL;
1031
1032                 break;
1033         }
1034
1035         case SD_BUS_TYPE_BOOLEAN: {
1036                 unsigned b;
1037                 bool *p = userdata;
1038
1039                 r = sd_bus_message_read_basic(m, type, &b);
1040                 if (r < 0)
1041                         break;
1042
1043                 *p = b;
1044
1045                 break;
1046         }
1047
1048         case SD_BUS_TYPE_UINT32: {
1049                 uint64_t u;
1050                 uint32_t *p = userdata;
1051
1052                 r = sd_bus_message_read_basic(m, type, &u);
1053                 if (r < 0)
1054                         break;
1055
1056                 *p = u;
1057
1058                 break;
1059         }
1060
1061         case SD_BUS_TYPE_UINT64: {
1062                 uint64_t t;
1063                 uint64_t *p = userdata;
1064
1065                 r = sd_bus_message_read_basic(m, type, &t);
1066                 if (r < 0)
1067                         break;
1068
1069                 *p = t;
1070
1071                 break;
1072         }
1073
1074         default:
1075                 break;
1076         }
1077
1078         return r;
1079 }
1080
1081 int bus_message_map_all_properties(
1082                 sd_bus_message *m,
1083                 const struct bus_properties_map *map,
1084                 void *userdata) {
1085
1086         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1087         int r;
1088
1089         assert(m);
1090         assert(map);
1091
1092         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1093         if (r < 0)
1094                 return r;
1095
1096         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1097                 const struct bus_properties_map *prop;
1098                 const char *member;
1099                 const char *contents;
1100                 void *v;
1101                 unsigned i;
1102
1103                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1104                 if (r < 0)
1105                         return r;
1106
1107                 for (i = 0, prop = NULL; map[i].member; i++)
1108                         if (streq(map[i].member, member)) {
1109                                 prop = &map[i];
1110                                 break;
1111                         }
1112
1113                 if (prop) {
1114                         r = sd_bus_message_peek_type(m, NULL, &contents);
1115                         if (r < 0)
1116                                 return r;
1117
1118                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1119                         if (r < 0)
1120                                 return r;
1121
1122                         v = (uint8_t *)userdata + prop->offset;
1123                         if (map[i].set)
1124                                 r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v);
1125                         else
1126                                 r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v);
1127                         if (r < 0)
1128                                 return r;
1129
1130                         r = sd_bus_message_exit_container(m);
1131                         if (r < 0)
1132                                 return r;
1133                 } else {
1134                         r = sd_bus_message_skip(m, "v");
1135                         if (r < 0)
1136                                 return r;
1137                 }
1138
1139                 r = sd_bus_message_exit_container(m);
1140                 if (r < 0)
1141                         return r;
1142         }
1143         if (r < 0)
1144                 return r;
1145
1146         return sd_bus_message_exit_container(m);
1147 }
1148
1149 /// UNNEEDED by elogind
1150 #if 0
1151 int bus_message_map_properties_changed(
1152                 sd_bus_message *m,
1153                 const struct bus_properties_map *map,
1154                 void *userdata) {
1155
1156         const char *member;
1157         int r, invalidated, i;
1158
1159         assert(m);
1160         assert(map);
1161
1162         r = bus_message_map_all_properties(m, map, userdata);
1163         if (r < 0)
1164                 return r;
1165
1166         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1167         if (r < 0)
1168                 return r;
1169
1170         invalidated = 0;
1171         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1172                 for (i = 0; map[i].member; i++)
1173                         if (streq(map[i].member, member)) {
1174                                 ++invalidated;
1175                                 break;
1176                         }
1177         if (r < 0)
1178                 return r;
1179
1180         r = sd_bus_message_exit_container(m);
1181         if (r < 0)
1182                 return r;
1183
1184         return invalidated;
1185 }
1186 #endif // 0
1187
1188 int bus_map_all_properties(
1189                 sd_bus *bus,
1190                 const char *destination,
1191                 const char *path,
1192                 const struct bus_properties_map *map,
1193                 void *userdata) {
1194
1195         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1196         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1197         int r;
1198
1199         assert(bus);
1200         assert(destination);
1201         assert(path);
1202         assert(map);
1203
1204         r = sd_bus_call_method(
1205                         bus,
1206                         destination,
1207                         path,
1208                         "org.freedesktop.DBus.Properties",
1209                         "GetAll",
1210                         &error,
1211                         &m,
1212                         "s", "");
1213         if (r < 0)
1214                 return r;
1215
1216         return bus_message_map_all_properties(m, map, userdata);
1217 }
1218
1219 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1220         int r;
1221
1222         assert(transport >= 0);
1223         assert(transport < _BUS_TRANSPORT_MAX);
1224         assert(bus);
1225
1226         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1227         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1228
1229         switch (transport) {
1230
1231         case BUS_TRANSPORT_LOCAL:
1232 /// elogind does not support a user bus
1233 #if 0
1234                 if (user)
1235                         r = sd_bus_default_user(bus);
1236                 else
1237 #endif // 0
1238                         r = sd_bus_default_system(bus);
1239
1240                 break;
1241
1242         case BUS_TRANSPORT_REMOTE:
1243                 r = sd_bus_open_system_remote(bus, host);
1244                 break;
1245
1246         case BUS_TRANSPORT_MACHINE:
1247                 r = sd_bus_open_system_machine(bus, host);
1248                 break;
1249
1250         default:
1251                 assert_not_reached("Hmm, unknown transport type.");
1252         }
1253
1254         return r;
1255 }
1256
1257 /// UNNEEDED by elogind
1258 #if 0
1259 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1260         int r;
1261
1262         assert(transport >= 0);
1263         assert(transport < _BUS_TRANSPORT_MAX);
1264         assert(bus);
1265
1266         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1267         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1268
1269         switch (transport) {
1270
1271         case BUS_TRANSPORT_LOCAL:
1272                 if (user)
1273                         r = bus_open_user_systemd(bus);
1274                 else
1275                         r = bus_open_system_systemd(bus);
1276
1277                 break;
1278
1279         case BUS_TRANSPORT_REMOTE:
1280                 r = sd_bus_open_system_remote(bus, host);
1281                 break;
1282
1283         case BUS_TRANSPORT_MACHINE:
1284                 r = sd_bus_open_system_machine(bus, host);
1285                 break;
1286
1287         default:
1288                 assert_not_reached("Hmm, unknown transport type.");
1289         }
1290
1291         return r;
1292 }
1293 #endif // 0
1294
1295 int bus_property_get_bool(
1296                 sd_bus *bus,
1297                 const char *path,
1298                 const char *interface,
1299                 const char *property,
1300                 sd_bus_message *reply,
1301                 void *userdata,
1302                 sd_bus_error *error) {
1303
1304         int b = *(bool*) userdata;
1305
1306         return sd_bus_message_append_basic(reply, 'b', &b);
1307 }
1308
1309 #if __SIZEOF_SIZE_T__ != 8
1310 int bus_property_get_size(
1311                 sd_bus *bus,
1312                 const char *path,
1313                 const char *interface,
1314                 const char *property,
1315                 sd_bus_message *reply,
1316                 void *userdata,
1317                 sd_bus_error *error) {
1318
1319         uint64_t sz = *(size_t*) userdata;
1320
1321         return sd_bus_message_append_basic(reply, 't', &sz);
1322 }
1323 #endif
1324
1325 #if __SIZEOF_LONG__ != 8
1326 int bus_property_get_long(
1327                 sd_bus *bus,
1328                 const char *path,
1329                 const char *interface,
1330                 const char *property,
1331                 sd_bus_message *reply,
1332                 void *userdata,
1333                 sd_bus_error *error) {
1334
1335         int64_t l = *(long*) userdata;
1336
1337         return sd_bus_message_append_basic(reply, 'x', &l);
1338 }
1339
1340 int bus_property_get_ulong(
1341                 sd_bus *bus,
1342                 const char *path,
1343                 const char *interface,
1344                 const char *property,
1345                 sd_bus_message *reply,
1346                 void *userdata,
1347                 sd_bus_error *error) {
1348
1349         uint64_t ul = *(unsigned long*) userdata;
1350
1351         return sd_bus_message_append_basic(reply, 't', &ul);
1352 }
1353 #endif
1354
1355 int bus_log_parse_error(int r) {
1356         return log_error_errno(r, "Failed to parse bus message: %m");
1357 }
1358
1359 /// UNNEEDED by elogind
1360 #if 0
1361 int bus_log_create_error(int r) {
1362         return log_error_errno(r, "Failed to create bus message: %m");
1363 }
1364
1365 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1366         assert(message);
1367         assert(u);
1368
1369         u->machine = NULL;
1370
1371         return sd_bus_message_read(
1372                         message,
1373                         "(ssssssouso)",
1374                         &u->id,
1375                         &u->description,
1376                         &u->load_state,
1377                         &u->active_state,
1378                         &u->sub_state,
1379                         &u->following,
1380                         &u->unit_path,
1381                         &u->job_id,
1382                         &u->job_type,
1383                         &u->job_path);
1384 }
1385
1386 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1387         const char *eq, *field;
1388         int r;
1389
1390         assert(m);
1391         assert(assignment);
1392
1393         eq = strchr(assignment, '=');
1394         if (!eq) {
1395                 log_error("Not an assignment: %s", assignment);
1396                 return -EINVAL;
1397         }
1398
1399         field = strndupa(assignment, eq - assignment);
1400         eq ++;
1401
1402         if (streq(field, "CPUQuota")) {
1403
1404                 if (isempty(eq)) {
1405
1406                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1407                         if (r < 0)
1408                                 return bus_log_create_error(r);
1409
1410                         r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1411
1412                 } else if (endswith(eq, "%")) {
1413                         double percent;
1414
1415                         if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1416                                 log_error("CPU quota '%s' invalid.", eq);
1417                                 return -EINVAL;
1418                         }
1419
1420                         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1421                         if (r < 0)
1422                                 return bus_log_create_error(r);
1423
1424                         r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1425                 } else {
1426                         log_error("CPU quota needs to be in percent.");
1427                         return -EINVAL;
1428                 }
1429
1430                 if (r < 0)
1431                         return bus_log_create_error(r);
1432
1433                 return 0;
1434         }
1435
1436         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1437         if (r < 0)
1438                 return bus_log_create_error(r);
1439
1440         if (STR_IN_SET(field,
1441                        "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1442                        "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
1443                        "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit")) {
1444
1445                 r = parse_boolean(eq);
1446                 if (r < 0) {
1447                         log_error("Failed to parse boolean assignment %s.", assignment);
1448                         return -EINVAL;
1449                 }
1450
1451                 r = sd_bus_message_append(m, "v", "b", r);
1452
1453         } else if (streq(field, "MemoryLimit")) {
1454                 off_t bytes;
1455
1456                 r = parse_size(eq, 1024, &bytes);
1457                 if (r < 0) {
1458                         log_error("Failed to parse bytes specification %s", assignment);
1459                         return -EINVAL;
1460                 }
1461
1462                 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1463
1464         } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1465                 uint64_t u;
1466
1467                 r = safe_atou64(eq, &u);
1468                 if (r < 0) {
1469                         log_error("Failed to parse %s value %s.", field, eq);
1470                         return -EINVAL;
1471                 }
1472
1473                 r = sd_bus_message_append(m, "v", "t", u);
1474
1475         } else if (STR_IN_SET(field,
1476                               "User", "Group", "DevicePolicy", "KillMode",
1477                               "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
1478                               "StandardInput", "StandardOutput", "StandardError",
1479                               "Description", "Slice", "Type"))
1480                 r = sd_bus_message_append(m, "v", "s", eq);
1481
1482         else if (streq(field, "DeviceAllow")) {
1483
1484                 if (isempty(eq))
1485                         r = sd_bus_message_append(m, "v", "a(ss)", 0);
1486                 else {
1487                         const char *path, *rwm, *e;
1488
1489                         e = strchr(eq, ' ');
1490                         if (e) {
1491                                 path = strndupa(eq, e - eq);
1492                                 rwm = e+1;
1493                         } else {
1494                                 path = eq;
1495                                 rwm = "";
1496                         }
1497
1498                         if (!path_startswith(path, "/dev")) {
1499                                 log_error("%s is not a device file in /dev.", path);
1500                                 return -EINVAL;
1501                         }
1502
1503                         r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1504                 }
1505
1506         } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1507
1508                 if (isempty(eq))
1509                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1510                 else {
1511                         const char *path, *bandwidth, *e;
1512                         off_t bytes;
1513
1514                         e = strchr(eq, ' ');
1515                         if (e) {
1516                                 path = strndupa(eq, e - eq);
1517                                 bandwidth = e+1;
1518                         } else {
1519                                 log_error("Failed to parse %s value %s.", field, eq);
1520                                 return -EINVAL;
1521                         }
1522
1523                         if (!path_startswith(path, "/dev")) {
1524                                 log_error("%s is not a device file in /dev.", path);
1525                                 return -EINVAL;
1526                         }
1527
1528                         r = parse_size(bandwidth, 1000, &bytes);
1529                         if (r < 0) {
1530                                 log_error("Failed to parse byte value %s.", bandwidth);
1531                                 return -EINVAL;
1532                         }
1533
1534                         r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1535                 }
1536
1537         } else if (streq(field, "BlockIODeviceWeight")) {
1538
1539                 if (isempty(eq))
1540                         r = sd_bus_message_append(m, "v", "a(st)", 0);
1541                 else {
1542                         const char *path, *weight, *e;
1543                         uint64_t u;
1544
1545                         e = strchr(eq, ' ');
1546                         if (e) {
1547                                 path = strndupa(eq, e - eq);
1548                                 weight = e+1;
1549                         } else {
1550                                 log_error("Failed to parse %s value %s.", field, eq);
1551                                 return -EINVAL;
1552                         }
1553
1554                         if (!path_startswith(path, "/dev")) {
1555                                 log_error("%s is not a device file in /dev.", path);
1556                                 return -EINVAL;
1557                         }
1558
1559                         r = safe_atou64(weight, &u);
1560                         if (r < 0) {
1561                                 log_error("Failed to parse %s value %s.", field, weight);
1562                                 return -EINVAL;
1563                         }
1564                         r = sd_bus_message_append(m, "v", "a(st)", path, u);
1565                 }
1566
1567         } else if (rlimit_from_string(field) >= 0) {
1568                 uint64_t rl;
1569
1570                 if (streq(eq, "infinity"))
1571                         rl = (uint64_t) -1;
1572                 else {
1573                         r = safe_atou64(eq, &rl);
1574                         if (r < 0) {
1575                                 log_error("Invalid resource limit: %s", eq);
1576                                 return -EINVAL;
1577                         }
1578                 }
1579
1580                 r = sd_bus_message_append(m, "v", "t", rl);
1581
1582         } else if (streq(field, "Nice")) {
1583                 int32_t i;
1584
1585                 r = safe_atoi32(eq, &i);
1586                 if (r < 0) {
1587                         log_error("Failed to parse %s value %s.", field, eq);
1588                         return -EINVAL;
1589                 }
1590
1591                 r = sd_bus_message_append(m, "v", "i", i);
1592
1593         } else if (streq(field, "Environment")) {
1594
1595                 r = sd_bus_message_append(m, "v", "as", 1, eq);
1596
1597         } else if (streq(field, "KillSignal")) {
1598                 int sig;
1599
1600                 sig = signal_from_string_try_harder(eq);
1601                 if (sig < 0) {
1602                         log_error("Failed to parse %s value %s.", field, eq);
1603                         return -EINVAL;
1604                 }
1605
1606                 r = sd_bus_message_append(m, "v", "i", sig);
1607
1608         } else if (streq(field, "AccuracySec")) {
1609                 usec_t u;
1610
1611                 r = parse_sec(eq, &u);
1612                 if (r < 0) {
1613                         log_error("Failed to parse %s value %s", field, eq);
1614                         return -EINVAL;
1615                 }
1616
1617                 r = sd_bus_message_append(m, "v", "t", u);
1618
1619         } else {
1620                 log_error("Unknown assignment %s.", assignment);
1621                 return -EINVAL;
1622         }
1623
1624         if (r < 0)
1625                 return bus_log_create_error(r);
1626
1627         return 0;
1628 }
1629 #endif // 0
1630
1631 typedef struct BusWaitForJobs {
1632         sd_bus *bus;
1633         Set *jobs;
1634
1635         char *name;
1636         char *result;
1637
1638         sd_bus_slot *slot_job_removed;
1639         sd_bus_slot *slot_disconnected;
1640 } BusWaitForJobs;
1641
1642 /// UNNEEDED by elogind
1643 #if 0
1644 static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1645         assert(m);
1646
1647         log_error("Warning! D-Bus connection terminated.");
1648         sd_bus_close(sd_bus_message_get_bus(m));
1649
1650         return 0;
1651 }
1652
1653 static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1654         const char *path, *unit, *result;
1655         BusWaitForJobs *d = userdata;
1656         uint32_t id;
1657         char *found;
1658         int r;
1659
1660         assert(m);
1661         assert(d);
1662
1663         r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1664         if (r < 0) {
1665                 bus_log_parse_error(r);
1666                 return 0;
1667         }
1668
1669         found = set_remove(d->jobs, (char*) path);
1670         if (!found)
1671                 return 0;
1672
1673         free(found);
1674
1675         if (!isempty(result))
1676                 d->result = strdup(result);
1677
1678         if (!isempty(unit))
1679                 d->name = strdup(unit);
1680
1681         return 0;
1682 }
1683
1684 void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1685         if (!d)
1686                 return;
1687
1688         set_free_free(d->jobs);
1689
1690         sd_bus_slot_unref(d->slot_disconnected);
1691         sd_bus_slot_unref(d->slot_job_removed);
1692
1693         sd_bus_unref(d->bus);
1694
1695         free(d->name);
1696         free(d->result);
1697
1698         free(d);
1699 }
1700
1701 int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1702         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1703         int r;
1704
1705         assert(bus);
1706         assert(ret);
1707
1708         d = new0(BusWaitForJobs, 1);
1709         if (!d)
1710                 return -ENOMEM;
1711
1712         d->bus = sd_bus_ref(bus);
1713
1714         /* When we are a bus client we match by sender. Direct
1715          * connections OTOH have no initialized sender field, and
1716          * hence we ignore the sender then */
1717         r = sd_bus_add_match(
1718                         bus,
1719                         &d->slot_job_removed,
1720                         bus->bus_client ?
1721                         "type='signal',"
1722                         "sender='org.freedesktop.systemd1',"
1723                         "interface='org.freedesktop.systemd1.Manager',"
1724                         "member='JobRemoved',"
1725                         "path='/org/freedesktop/systemd1'" :
1726                         "type='signal',"
1727                         "interface='org.freedesktop.systemd1.Manager',"
1728                         "member='JobRemoved',"
1729                         "path='/org/freedesktop/systemd1'",
1730                         match_job_removed, d);
1731         if (r < 0)
1732                 return r;
1733
1734         r = sd_bus_add_match(
1735                         bus,
1736                         &d->slot_disconnected,
1737                         "type='signal',"
1738                         "sender='org.freedesktop.DBus.Local',"
1739                         "interface='org.freedesktop.DBus.Local',"
1740                         "member='Disconnected'",
1741                         match_disconnected, d);
1742         if (r < 0)
1743                 return r;
1744
1745         *ret = d;
1746         d = NULL;
1747
1748         return 0;
1749 }
1750
1751 static int bus_process_wait(sd_bus *bus) {
1752         int r;
1753
1754         for (;;) {
1755                 r = sd_bus_process(bus, NULL);
1756                 if (r < 0)
1757                         return r;
1758                 if (r > 0)
1759                         return 0;
1760
1761                 r = sd_bus_wait(bus, (uint64_t) -1);
1762                 if (r < 0)
1763                         return r;
1764         }
1765 }
1766
1767 static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
1768         _cleanup_free_ char *dbus_path = NULL;
1769
1770         assert(d);
1771         assert(d->name);
1772         assert(result);
1773
1774         dbus_path = unit_dbus_path_from_name(d->name);
1775         if (!dbus_path)
1776                 return -ENOMEM;
1777
1778         return sd_bus_get_property_string(d->bus,
1779                                           "org.freedesktop.systemd1",
1780                                           dbus_path,
1781                                           "org.freedesktop.systemd1.Service",
1782                                           "Result",
1783                                           NULL,
1784                                           result);
1785 }
1786
1787 static const struct {
1788         const char *result, *explanation;
1789 } explanations [] = {
1790         { "resources",   "a configured resource limit was exceeded" },
1791         { "timeout",     "a timeout was exceeded" },
1792         { "exit-code",   "the control process exited with error code" },
1793         { "signal",      "a fatal signal was delivered to the control process" },
1794         { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
1795         { "watchdog",    "the service failed to send watchdog ping" },
1796         { "start-limit", "start of the service was attempted too often" }
1797 };
1798
1799 static void log_job_error_with_service_result(const char* service, const char *result) {
1800         _cleanup_free_ char *service_shell_quoted = NULL;
1801
1802         assert(service);
1803
1804         service_shell_quoted = shell_maybe_quote(service);
1805
1806         if (!isempty(result)) {
1807                 unsigned i;
1808
1809                 for (i = 0; i < ELEMENTSOF(explanations); ++i)
1810                         if (streq(result, explanations[i].result))
1811                                 break;
1812
1813                 if (i < ELEMENTSOF(explanations)) {
1814                         log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1815                                   service,
1816                                   explanations[i].explanation,
1817                                   strna(service_shell_quoted));
1818
1819                         goto finish;
1820                 }
1821         }
1822
1823         log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
1824                   service,
1825                   strna(service_shell_quoted));
1826
1827 finish:
1828         /* For some results maybe additional explanation is required */
1829         if (streq_ptr(result, "start-limit"))
1830                 log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
1831                          strna(service_shell_quoted));
1832 }
1833
1834 static int check_wait_response(BusWaitForJobs *d, bool quiet) {
1835         int r = 0;
1836
1837         assert(d->result);
1838
1839         if (!quiet) {
1840                 if (streq(d->result, "canceled"))
1841                         log_error("Job for %s canceled.", strna(d->name));
1842                 else if (streq(d->result, "timeout"))
1843                         log_error("Job for %s timed out.", strna(d->name));
1844                 else if (streq(d->result, "dependency"))
1845                         log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1846                 else if (streq(d->result, "invalid"))
1847                         log_error("Job for %s invalid.", strna(d->name));
1848                 else if (streq(d->result, "assert"))
1849                         log_error("Assertion failed on job for %s.", strna(d->name));
1850                 else if (streq(d->result, "unsupported"))
1851                         log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1852                 else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
1853                         if (d->name) {
1854                                 int q;
1855                                 _cleanup_free_ char *result = NULL;
1856
1857                                 q = bus_job_get_service_result(d, &result);
1858                                 if (q < 0)
1859                                         log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
1860
1861                                 log_job_error_with_service_result(d->name, result);
1862                         } else
1863                                 log_error("Job failed. See \"journalctl -xe\" for details.");
1864                 }
1865         }
1866
1867         if (streq(d->result, "canceled"))
1868                 r = -ECANCELED;
1869         else if (streq(d->result, "timeout"))
1870                 r = -ETIME;
1871         else if (streq(d->result, "dependency"))
1872                 r = -EIO;
1873         else if (streq(d->result, "invalid"))
1874                 r = -ENOEXEC;
1875         else if (streq(d->result, "assert"))
1876                 r = -EPROTO;
1877         else if (streq(d->result, "unsupported"))
1878                 r = -EOPNOTSUPP;
1879         else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
1880                 r = -EIO;
1881
1882         return r;
1883 }
1884
1885 int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
1886         int r = 0;
1887
1888         assert(d);
1889
1890         while (!set_isempty(d->jobs)) {
1891                 int q;
1892
1893                 q = bus_process_wait(d->bus);
1894                 if (q < 0)
1895                         return log_error_errno(q, "Failed to wait for response: %m");
1896
1897                 if (d->result) {
1898                         q = check_wait_response(d, quiet);
1899                         /* Return the first error as it is most likely to be
1900                          * meaningful. */
1901                         if (q < 0 && r == 0)
1902                                 r = q;
1903
1904                         log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1905                 }
1906
1907                 free(d->name);
1908                 d->name = NULL;
1909
1910                 free(d->result);
1911                 d->result = NULL;
1912         }
1913
1914         return r;
1915 }
1916
1917 int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1918         int r;
1919
1920         assert(d);
1921
1922         r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1923         if (r < 0)
1924                 return r;
1925
1926         return set_put_strdup(d->jobs, path);
1927 }
1928
1929 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
1930         const char *type, *path, *source;
1931         int r;
1932
1933         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1934         if (r < 0)
1935                 return bus_log_parse_error(r);
1936
1937         while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1938                 if (!quiet) {
1939                         if (streq(type, "symlink"))
1940                                 log_info("Created symlink from %s to %s.", path, source);
1941                         else
1942                                 log_info("Removed symlink %s.", path);
1943                 }
1944
1945                 r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
1946                 if (r < 0)
1947                         return r;
1948         }
1949         if (r < 0)
1950                 return bus_log_parse_error(r);
1951
1952         r = sd_bus_message_exit_container(m);
1953         if (r < 0)
1954                 return bus_log_parse_error(r);
1955
1956         return 0;
1957 }
1958
1959 /**
1960  * bus_path_encode_unique() - encode unique object path
1961  * @b: bus connection or NULL
1962  * @prefix: object path prefix
1963  * @sender_id: unique-name of client, or NULL
1964  * @external_id: external ID to be chosen by client, or NULL
1965  * @ret_path: storage for encoded object path pointer
1966  *
1967  * Whenever we provide a bus API that allows clients to create and manage
1968  * server-side objects, we need to provide a unique name for these objects. If
1969  * we let the server choose the name, we suffer from a race condition: If a
1970  * client creates an object asynchronously, it cannot destroy that object until
1971  * it received the method reply. It cannot know the name of the new object,
1972  * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1973  *
1974  * Therefore, many APIs allow the client to choose the unique name for newly
1975  * created objects. There're two problems to solve, though:
1976  *    1) Object names are usually defined via dbus object paths, which are
1977  *       usually globally namespaced. Therefore, multiple clients must be able
1978  *       to choose unique object names without interference.
1979  *    2) If multiple libraries share the same bus connection, they must be
1980  *       able to choose unique object names without interference.
1981  * The first problem is solved easily by prefixing a name with the
1982  * unique-bus-name of a connection. The server side must enforce this and
1983  * reject any other name. The second problem is solved by providing unique
1984  * suffixes from within sd-bus.
1985  *
1986  * This helper allows clients to create unique object-paths. It uses the
1987  * template '/prefix/sender_id/external_id' and returns the new path in
1988  * @ret_path (must be freed by the caller).
1989  * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1990  * NULL, this function allocates a unique suffix via @b (by requesting a new
1991  * cookie). If both @sender_id and @external_id are given, @b can be passed as
1992  * NULL.
1993  *
1994  * Returns: 0 on success, negative error code on failure.
1995  */
1996 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1997         _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1998         char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1999         int r;
2000
2001         assert_return(b || (sender_id && external_id), -EINVAL);
2002         assert_return(object_path_is_valid(prefix), -EINVAL);
2003         assert_return(ret_path, -EINVAL);
2004
2005         if (!sender_id) {
2006                 r = sd_bus_get_unique_name(b, &sender_id);
2007                 if (r < 0)
2008                         return r;
2009         }
2010
2011         if (!external_id) {
2012                 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
2013                 external_id = external_buf;
2014         }
2015
2016         sender_label = bus_label_escape(sender_id);
2017         if (!sender_label)
2018                 return -ENOMEM;
2019
2020         external_label = bus_label_escape(external_id);
2021         if (!external_label)
2022                 return -ENOMEM;
2023
2024         p = strjoin(prefix, "/", sender_label, "/", external_label, NULL);
2025         if (!p)
2026                 return -ENOMEM;
2027
2028         *ret_path = p;
2029         return 0;
2030 }
2031
2032 /**
2033  * bus_path_decode_unique() - decode unique object path
2034  * @path: object path to decode
2035  * @prefix: object path prefix
2036  * @ret_sender: output parameter for sender-id label
2037  * @ret_external: output parameter for external-id label
2038  *
2039  * This does the reverse of bus_path_encode_unique() (see its description for
2040  * details). Both trailing labels, sender-id and external-id, are unescaped and
2041  * returned in the given output parameters (the caller must free them).
2042  *
2043  * Note that this function returns 0 if the path does not match the template
2044  * (see bus_path_encode_unique()), 1 if it matched.
2045  *
2046  * Returns: Negative error code on failure, 0 if the given object path does not
2047  *          match the template (return parameters are set to NULL), 1 if it was
2048  *          parsed successfully (return parameters contain allocated labels).
2049  */
2050 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
2051         const char *p, *q;
2052         char *sender, *external;
2053
2054         assert(object_path_is_valid(path));
2055         assert(object_path_is_valid(prefix));
2056         assert(ret_sender);
2057         assert(ret_external);
2058
2059         p = object_path_startswith(path, prefix);
2060         if (!p) {
2061                 *ret_sender = NULL;
2062                 *ret_external = NULL;
2063                 return 0;
2064         }
2065
2066         q = strchr(p, '/');
2067         if (!q) {
2068                 *ret_sender = NULL;
2069                 *ret_external = NULL;
2070                 return 0;
2071         }
2072
2073         sender = bus_label_unescape_n(p, q - p);
2074         external = bus_label_unescape(q + 1);
2075         if (!sender || !external) {
2076                 free(sender);
2077                 free(external);
2078                 return -ENOMEM;
2079         }
2080
2081         *ret_sender = sender;
2082         *ret_external = external;
2083         return 1;
2084 }
2085 #endif // 0
2086
2087 bool is_kdbus_wanted(void) {
2088         _cleanup_free_ char *value = NULL;
2089 #ifdef ENABLE_KDBUS
2090         const bool configured = true;
2091 #else
2092         const bool configured = false;
2093 #endif
2094
2095         int r;
2096
2097         if (get_proc_cmdline_key("kdbus", NULL) > 0)
2098                 return true;
2099
2100         r = get_proc_cmdline_key("kdbus=", &value);
2101         if (r <= 0)
2102                 return configured;
2103
2104         return parse_boolean(value) == 1;
2105 }
2106
2107 bool is_kdbus_available(void) {
2108         _cleanup_close_ int fd = -1;
2109         struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE };
2110
2111         if (!is_kdbus_wanted())
2112                 return false;
2113
2114         fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
2115         if (fd < 0)
2116                 return false;
2117
2118         return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
2119 }