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