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