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