chiark / gitweb /
macro: introduce TAKE_PTR() macro
[elogind.git] / src / shared / bus-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2013 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/resource.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31
32 #include "sd-bus-protocol.h"
33 #include "sd-bus.h"
34 #include "sd-daemon.h"
35 #include "sd-event.h"
36 #include "sd-id128.h"
37
38 #include "alloc-util.h"
39 #include "bus-internal.h"
40 #include "bus-label.h"
41 #include "bus-message.h"
42 #include "bus-util.h"
43 #include "cap-list.h"
44 #include "cgroup-util.h"
45 #include "def.h"
46 #include "escape.h"
47 #include "fd-util.h"
48 #include "missing.h"
49 #include "mount-util.h"
50 #include "nsflags.h"
51 #include "parse-util.h"
52 #include "proc-cmdline.h"
53 //#include "rlimit-util.h"
54 #include "stdio-util.h"
55 #include "strv.h"
56 #include "user-util.h"
57
58 #if 0 /// UNNEEDED by elogind
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         const char *match;
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         match = strjoina(
90                         "sender='org.freedesktop.DBus',"
91                         "type='signal',"
92                         "interface='org.freedesktop.DBus',"
93                         "member='NameOwnerChanged',"
94                         "path='/org/freedesktop/DBus',"
95                         "arg0='", name, "',",
96                         "arg1='", unique, "',",
97                         "arg2=''");
98
99         r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
100         if (r < 0)
101                 return r;
102
103         r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
104         if (r < 0)
105                 return r;
106
107         return 0;
108 }
109
110 int bus_event_loop_with_idle(
111                 sd_event *e,
112                 sd_bus *bus,
113                 const char *name,
114                 usec_t timeout,
115                 check_idle_t check_idle,
116                 void *userdata) {
117         bool exiting = false;
118         int r, code;
119
120         assert(e);
121         assert(bus);
122         assert(name);
123
124         for (;;) {
125                 bool idle;
126
127                 r = sd_event_get_state(e);
128                 if (r < 0)
129                         return r;
130                 if (r == SD_EVENT_FINISHED)
131                         break;
132
133                 if (check_idle)
134                         idle = check_idle(userdata);
135                 else
136                         idle = true;
137
138                 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
139                 if (r < 0)
140                         return r;
141
142                 if (r == 0 && !exiting && idle) {
143
144                         r = sd_bus_try_close(bus);
145                         if (r == -EBUSY)
146                                 continue;
147
148                         /* Fallback for dbus1 connections: we
149                          * unregister the name and wait for the
150                          * response to come through for it */
151                         if (r == -EOPNOTSUPP) {
152
153                                 /* Inform the service manager that we
154                                  * are going down, so that it will
155                                  * queue all further start requests,
156                                  * instead of assuming we are already
157                                  * running. */
158                                 sd_notify(false, "STOPPING=1");
159
160                                 r = bus_async_unregister_and_exit(e, bus, name);
161                                 if (r < 0)
162                                         return r;
163
164                                 exiting = true;
165                                 continue;
166                         }
167
168                         if (r < 0)
169                                 return r;
170
171                         sd_event_exit(e, 0);
172                         break;
173                 }
174         }
175
176         r = sd_event_get_exit_code(e, &code);
177         if (r < 0)
178                 return r;
179
180         return code;
181 }
182 #endif // 0
183
184 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
185         _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
186         int r, has_owner = 0;
187
188         assert(c);
189         assert(name);
190
191         r = sd_bus_call_method(c,
192                                "org.freedesktop.DBus",
193                                "/org/freedesktop/dbus",
194                                "org.freedesktop.DBus",
195                                "NameHasOwner",
196                                error,
197                                &rep,
198                                "s",
199                                name);
200         if (r < 0)
201                 return r;
202
203         r = sd_bus_message_read_basic(rep, 'b', &has_owner);
204         if (r < 0)
205                 return sd_bus_error_set_errno(error, r);
206
207         return has_owner;
208 }
209
210 static int check_good_user(sd_bus_message *m, uid_t good_user) {
211         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
212         uid_t sender_uid;
213         int r;
214
215         assert(m);
216
217         if (good_user == UID_INVALID)
218                 return 0;
219
220         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
221         if (r < 0)
222                 return r;
223
224         /* Don't trust augmented credentials for authorization */
225         assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
226
227         r = sd_bus_creds_get_euid(creds, &sender_uid);
228         if (r < 0)
229                 return r;
230
231         return sender_uid == good_user;
232 }
233
234 int bus_test_polkit(
235                 sd_bus_message *call,
236                 int capability,
237                 const char *action,
238                 const char **details,
239                 uid_t good_user,
240                 bool *_challenge,
241                 sd_bus_error *e) {
242
243         int r;
244
245         assert(call);
246         assert(action);
247
248         /* Tests non-interactively! */
249
250         r = check_good_user(call, good_user);
251         if (r != 0)
252                 return r;
253
254         r = sd_bus_query_sender_privilege(call, capability);
255         if (r < 0)
256                 return r;
257         else if (r > 0)
258                 return 1;
259 #if ENABLE_POLKIT
260         else {
261                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
262                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
263                 int authorized = false, challenge = false;
264                 const char *sender, **k, **v;
265
266                 sender = sd_bus_message_get_sender(call);
267                 if (!sender)
268                         return -EBADMSG;
269
270                 r = sd_bus_message_new_method_call(
271                                 call->bus,
272                                 &request,
273                                 "org.freedesktop.PolicyKit1",
274                                 "/org/freedesktop/PolicyKit1/Authority",
275                                 "org.freedesktop.PolicyKit1.Authority",
276                                 "CheckAuthorization");
277                 if (r < 0)
278                         return r;
279
280                 r = sd_bus_message_append(
281                                 request,
282                                 "(sa{sv})s",
283                                 "system-bus-name", 1, "name", "s", sender,
284                                 action);
285                 if (r < 0)
286                         return r;
287
288                 r = sd_bus_message_open_container(request, 'a', "{ss}");
289                 if (r < 0)
290                         return r;
291
292                 STRV_FOREACH_PAIR(k, v, details) {
293                         r = sd_bus_message_append(request, "{ss}", *k, *v);
294                         if (r < 0)
295                                 return r;
296                 }
297
298                 r = sd_bus_message_close_container(request);
299                 if (r < 0)
300                         return r;
301
302                 r = sd_bus_message_append(request, "us", 0, NULL);
303                 if (r < 0)
304                         return r;
305
306                 r = sd_bus_call(call->bus, request, 0, e, &reply);
307                 if (r < 0) {
308                         /* Treat no PK available as access denied */
309                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
310                                 sd_bus_error_free(e);
311                                 return -EACCES;
312                         }
313
314                         return r;
315                 }
316
317                 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
318                 if (r < 0)
319                         return r;
320
321                 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
322                 if (r < 0)
323                         return r;
324
325                 if (authorized)
326                         return 1;
327
328                 if (_challenge) {
329                         *_challenge = challenge;
330                         return 0;
331                 }
332         }
333 #endif
334
335         return -EACCES;
336 }
337
338 #if ENABLE_POLKIT
339
340 typedef struct AsyncPolkitQuery {
341         sd_bus_message *request, *reply;
342         sd_bus_message_handler_t callback;
343         void *userdata;
344         sd_bus_slot *slot;
345         Hashmap *registry;
346 } AsyncPolkitQuery;
347
348 static void async_polkit_query_free(AsyncPolkitQuery *q) {
349
350         if (!q)
351                 return;
352
353         sd_bus_slot_unref(q->slot);
354
355         if (q->registry && q->request)
356                 hashmap_remove(q->registry, q->request);
357
358         sd_bus_message_unref(q->request);
359         sd_bus_message_unref(q->reply);
360
361         free(q);
362 }
363
364 static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
365         _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
366         AsyncPolkitQuery *q = userdata;
367         int r;
368
369         assert(reply);
370         assert(q);
371
372         q->slot = sd_bus_slot_unref(q->slot);
373         q->reply = sd_bus_message_ref(reply);
374
375         r = sd_bus_message_rewind(q->request, true);
376         if (r < 0) {
377                 r = sd_bus_reply_method_errno(q->request, r, NULL);
378                 goto finish;
379         }
380
381         r = q->callback(q->request, q->userdata, &error_buffer);
382         r = bus_maybe_reply_error(q->request, r, &error_buffer);
383
384 finish:
385         async_polkit_query_free(q);
386
387         return r;
388 }
389
390 #endif
391
392 int bus_verify_polkit_async(
393                 sd_bus_message *call,
394                 int capability,
395                 const char *action,
396                 const char **details,
397                 bool interactive,
398                 uid_t good_user,
399                 Hashmap **registry,
400                 sd_bus_error *error) {
401
402 #if ENABLE_POLKIT
403         _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
404         AsyncPolkitQuery *q;
405         const char *sender, **k, **v;
406         sd_bus_message_handler_t callback;
407         void *userdata;
408         int c;
409 #endif
410         int r;
411
412         assert(call);
413         assert(action);
414         assert(registry);
415
416         r = check_good_user(call, good_user);
417         if (r != 0)
418                 return r;
419
420 #if ENABLE_POLKIT
421         q = hashmap_get(*registry, call);
422         if (q) {
423                 int authorized, challenge;
424
425                 /* This is the second invocation of this function, and
426                  * there's already a response from polkit, let's
427                  * process it */
428                 assert(q->reply);
429
430                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
431                         const sd_bus_error *e;
432
433                         /* Copy error from polkit reply */
434                         e = sd_bus_message_get_error(q->reply);
435                         sd_bus_error_copy(error, e);
436
437                         /* Treat no PK available as access denied */
438                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
439                                 return -EACCES;
440
441                         return -sd_bus_error_get_errno(e);
442                 }
443
444                 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
445                 if (r >= 0)
446                         r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
447
448                 if (r < 0)
449                         return r;
450
451                 if (authorized)
452                         return 1;
453
454                 if (challenge)
455                         return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
456
457                 return -EACCES;
458         }
459 #endif
460
461         r = sd_bus_query_sender_privilege(call, capability);
462         if (r < 0)
463                 return r;
464         else if (r > 0)
465                 return 1;
466
467 #if ENABLE_POLKIT
468         if (sd_bus_get_current_message(call->bus) != call)
469                 return -EINVAL;
470
471         callback = sd_bus_get_current_handler(call->bus);
472         if (!callback)
473                 return -EINVAL;
474
475         userdata = sd_bus_get_current_userdata(call->bus);
476
477         sender = sd_bus_message_get_sender(call);
478         if (!sender)
479                 return -EBADMSG;
480
481         c = sd_bus_message_get_allow_interactive_authorization(call);
482         if (c < 0)
483                 return c;
484         if (c > 0)
485                 interactive = true;
486
487         r = hashmap_ensure_allocated(registry, NULL);
488         if (r < 0)
489                 return r;
490
491         r = sd_bus_message_new_method_call(
492                         call->bus,
493                         &pk,
494                         "org.freedesktop.PolicyKit1",
495                         "/org/freedesktop/PolicyKit1/Authority",
496                         "org.freedesktop.PolicyKit1.Authority",
497                         "CheckAuthorization");
498         if (r < 0)
499                 return r;
500
501         r = sd_bus_message_append(
502                         pk,
503                         "(sa{sv})s",
504                         "system-bus-name", 1, "name", "s", sender,
505                         action);
506         if (r < 0)
507                 return r;
508
509         r = sd_bus_message_open_container(pk, 'a', "{ss}");
510         if (r < 0)
511                 return r;
512
513         STRV_FOREACH_PAIR(k, v, details) {
514                 r = sd_bus_message_append(pk, "{ss}", *k, *v);
515                 if (r < 0)
516                         return r;
517         }
518
519         r = sd_bus_message_close_container(pk);
520         if (r < 0)
521                 return r;
522
523         r = sd_bus_message_append(pk, "us", !!interactive, NULL);
524         if (r < 0)
525                 return r;
526
527         q = new0(AsyncPolkitQuery, 1);
528         if (!q)
529                 return -ENOMEM;
530
531         q->request = sd_bus_message_ref(call);
532         q->callback = callback;
533         q->userdata = userdata;
534
535         r = hashmap_put(*registry, call, q);
536         if (r < 0) {
537                 async_polkit_query_free(q);
538                 return r;
539         }
540
541         q->registry = *registry;
542
543         r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
544         if (r < 0) {
545                 async_polkit_query_free(q);
546                 return r;
547         }
548
549         return 0;
550 #endif
551
552         return -EACCES;
553 }
554
555 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
556 #if ENABLE_POLKIT
557         hashmap_free_with_destructor(registry, async_polkit_query_free);
558 #endif
559 }
560
561 #if 0 /// UNNEEDED by elogind
562 int bus_check_peercred(sd_bus *c) {
563         struct ucred ucred;
564         int fd, r;
565
566         assert(c);
567
568         fd = sd_bus_get_fd(c);
569         if (fd < 0)
570                 return fd;
571
572         r = getpeercred(fd, &ucred);
573         if (r < 0)
574                 return r;
575
576         if (ucred.uid != 0 && ucred.uid != geteuid())
577                 return -EPERM;
578
579         return 1;
580 }
581
582 int bus_connect_system_systemd(sd_bus **_bus) {
583         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
584         int r;
585
586         assert(_bus);
587
588         if (geteuid() != 0)
589                 return sd_bus_default_system(_bus);
590
591         /* If we are root then let's talk directly to the system
592          * instance, instead of going via the bus */
593
594         r = sd_bus_new(&bus);
595         if (r < 0)
596                 return r;
597
598         r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
599         if (r < 0)
600                 return r;
601
602         r = sd_bus_start(bus);
603         if (r < 0)
604                 return sd_bus_default_system(_bus);
605
606         r = bus_check_peercred(bus);
607         if (r < 0)
608                 return r;
609
610         *_bus = bus;
611         bus = NULL;
612
613         return 0;
614 }
615
616 int bus_connect_user_systemd(sd_bus **_bus) {
617         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
618         _cleanup_free_ char *ee = NULL;
619         const char *e;
620         int r;
621
622         assert(_bus);
623
624         e = secure_getenv("XDG_RUNTIME_DIR");
625         if (!e)
626                 return sd_bus_default_user(_bus);
627
628         ee = bus_address_escape(e);
629         if (!ee)
630                 return -ENOMEM;
631
632         r = sd_bus_new(&bus);
633         if (r < 0)
634                 return r;
635
636         bus->address = strjoin("unix:path=", ee, "/systemd/private");
637         if (!bus->address)
638                 return -ENOMEM;
639
640         r = sd_bus_start(bus);
641         if (r < 0)
642                 return sd_bus_default_user(_bus);
643
644         r = bus_check_peercred(bus);
645         if (r < 0)
646                 return r;
647
648         *_bus = bus;
649         bus = NULL;
650
651         return 0;
652 }
653 #endif // 0
654
655 #define print_property(name, fmt, ...)                                  \
656         do {                                                            \
657                 if (value)                                              \
658                         printf(fmt "\n", __VA_ARGS__);                  \
659                 else                                                    \
660                         printf("%s=" fmt "\n", name, __VA_ARGS__);      \
661         } while (0)
662
663 int bus_print_property(const char *name, sd_bus_message *m, bool value, bool all) {
664         char type;
665         const char *contents;
666         int r;
667
668         assert(name);
669         assert(m);
670
671         r = sd_bus_message_peek_type(m, &type, &contents);
672         if (r < 0)
673                 return r;
674
675         switch (type) {
676
677         case SD_BUS_TYPE_STRING: {
678                 const char *s;
679
680                 r = sd_bus_message_read_basic(m, type, &s);
681                 if (r < 0)
682                         return r;
683
684                 if (all || !isempty(s)) {
685                         bool good;
686
687                         /* This property has a single value, so we need to take
688                          * care not to print a new line, everything else is OK. */
689                         good = !strchr(s, '\n');
690                         print_property(name, "%s", good ? s : "[unprintable]");
691                 }
692
693                 return 1;
694         }
695
696         case SD_BUS_TYPE_BOOLEAN: {
697                 int b;
698
699                 r = sd_bus_message_read_basic(m, type, &b);
700                 if (r < 0)
701                         return r;
702
703                 print_property(name, "%s", yes_no(b));
704
705                 return 1;
706         }
707
708         case SD_BUS_TYPE_UINT64: {
709                 uint64_t u;
710
711                 r = sd_bus_message_read_basic(m, type, &u);
712                 if (r < 0)
713                         return r;
714
715                 /* Yes, heuristics! But we can change this check
716                  * should it turn out to not be sufficient */
717
718                 if (endswith(name, "Timestamp") || STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec")) {
719                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
720
721                         t = format_timestamp(timestamp, sizeof(timestamp), u);
722                         if (t || all)
723                                 print_property(name, "%s", strempty(t));
724
725                 } else if (strstr(name, "USec")) {
726                         char timespan[FORMAT_TIMESPAN_MAX];
727
728                         print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
729                 } else if (streq(name, "RestrictNamespaces")) {
730                         _cleanup_free_ char *s = NULL;
731                         const char *result;
732
733                         if ((u & NAMESPACE_FLAGS_ALL) == 0)
734                                 result = "yes";
735                         else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
736                                 result = "no";
737                         else {
738                                 r = namespace_flag_to_string_many(u, &s);
739                                 if (r < 0)
740                                         return r;
741
742                                 result = s;
743                         }
744
745                         print_property(name, "%s", result);
746
747                 } else if (streq(name, "MountFlags")) {
748                         const char *result;
749
750                         result = mount_propagation_flags_to_string(u);
751                         if (!result)
752                                 return -EINVAL;
753
754                         print_property(name, "%s", result);
755
756                 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
757                         _cleanup_free_ char *s = NULL;
758
759                         r = capability_set_to_string_alloc(u, &s);
760                         if (r < 0)
761                                 return r;
762
763                         print_property(name, "%s", s);
764
765                 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
766                            (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
767                            (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
768                            (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
769                            (endswith(name, "NSec") && u == (uint64_t) -1))
770
771                         print_property(name, "%s", "[not set]");
772
773                 else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
774                          (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
775                          (startswith(name, "Limit") && u == (uint64_t) -1) ||
776                          (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
777
778                         print_property(name, "%s", "infinity");
779                 else
780                         print_property(name, "%"PRIu64, u);
781
782                 return 1;
783         }
784
785         case SD_BUS_TYPE_INT64: {
786                 int64_t i;
787
788                 r = sd_bus_message_read_basic(m, type, &i);
789                 if (r < 0)
790                         return r;
791
792                 print_property(name, "%"PRIi64, i);
793
794                 return 1;
795         }
796
797         case SD_BUS_TYPE_UINT32: {
798                 uint32_t u;
799
800                 r = sd_bus_message_read_basic(m, type, &u);
801                 if (r < 0)
802                         return r;
803
804                 if (strstr(name, "UMask") || strstr(name, "Mode"))
805                         print_property(name, "%04o", u);
806                 else if (streq(name, "UID")) {
807                         if (u == UID_INVALID)
808                                 print_property(name, "%s", "[not set]");
809                         else
810                                 print_property(name, "%"PRIu32, u);
811                 } else if (streq(name, "GID")) {
812                         if (u == GID_INVALID)
813                                 print_property(name, "%s", "[not set]");
814                         else
815                                 print_property(name, "%"PRIu32, u);
816                 } else
817                         print_property(name, "%"PRIu32, u);
818
819                 return 1;
820         }
821
822         case SD_BUS_TYPE_INT32: {
823                 int32_t i;
824
825                 r = sd_bus_message_read_basic(m, type, &i);
826                 if (r < 0)
827                         return r;
828
829                 print_property(name, "%"PRIi32, i);
830                 return 1;
831         }
832
833         case SD_BUS_TYPE_DOUBLE: {
834                 double d;
835
836                 r = sd_bus_message_read_basic(m, type, &d);
837                 if (r < 0)
838                         return r;
839
840                 print_property(name, "%g", d);
841                 return 1;
842         }
843
844         case SD_BUS_TYPE_ARRAY:
845                 if (streq(contents, "s")) {
846                         bool first = true;
847                         const char *str;
848
849                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents);
850                         if (r < 0)
851                                 return r;
852
853                         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
854                                 bool good;
855
856                                 if (first && !value)
857                                         printf("%s=", name);
858
859                                 /* This property has multiple space-separated values, so
860                                  * neither spaces not newlines can be allowed in a value. */
861                                 good = str[strcspn(str, " \n")] == '\0';
862
863                                 printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
864
865                                 first = false;
866                         }
867                         if (r < 0)
868                                 return r;
869
870                         if (first && all && !value)
871                                 printf("%s=", name);
872                         if (!first || all)
873                                 puts("");
874
875                         r = sd_bus_message_exit_container(m);
876                         if (r < 0)
877                                 return r;
878
879                         return 1;
880
881                 } else if (streq(contents, "y")) {
882                         const uint8_t *u;
883                         size_t n;
884
885                         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
886                         if (r < 0)
887                                 return r;
888
889                         if (all || n > 0) {
890                                 unsigned int i;
891
892                                 if (!value)
893                                         printf("%s=", name);
894
895                                 for (i = 0; i < n; i++)
896                                         printf("%02x", u[i]);
897
898                                 puts("");
899                         }
900
901                         return 1;
902
903                 } else if (streq(contents, "u")) {
904                         uint32_t *u;
905                         size_t n;
906
907                         r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
908                         if (r < 0)
909                                 return r;
910
911                         if (all || n > 0) {
912                                 unsigned int i;
913
914                                 if (!value)
915                                         printf("%s=", name);
916
917                                 for (i = 0; i < n; i++)
918                                         printf("%08x", u[i]);
919
920                                 puts("");
921                         }
922
923                         return 1;
924                 }
925
926                 break;
927         }
928
929         return 0;
930 }
931
932 int bus_message_print_all_properties(
933                 sd_bus_message *m,
934                 bus_message_print_t func,
935                 char **filter,
936                 bool value,
937                 bool all,
938                 Set **found_properties) {
939
940         int r;
941
942         assert(m);
943
944         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
945         if (r < 0)
946                 return r;
947
948         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
949                 const char *name;
950                 const char *contents;
951
952                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
953                 if (r < 0)
954                         return r;
955
956                 if (found_properties) {
957                         r = set_ensure_allocated(found_properties, &string_hash_ops);
958                         if (r < 0)
959                                 return log_oom();
960
961                         r = set_put(*found_properties, name);
962                         if (r < 0 && r != EEXIST)
963                                 return log_oom();
964                 }
965
966                 if (!filter || strv_find(filter, name)) {
967                         r = sd_bus_message_peek_type(m, NULL, &contents);
968                         if (r < 0)
969                                 return r;
970
971                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
972                         if (r < 0)
973                                 return r;
974
975                         if (func)
976                                 r = func(name, m, value, all);
977                         if (!func || r == 0)
978                                 r = bus_print_property(name, m, value, all);
979                         if (r < 0)
980                                 return r;
981                         if (r == 0) {
982                                 if (all)
983                                         printf("%s=[unprintable]\n", name);
984                                 /* skip what we didn't read */
985                                 r = sd_bus_message_skip(m, contents);
986                                 if (r < 0)
987                                         return r;
988                         }
989
990                         r = sd_bus_message_exit_container(m);
991                         if (r < 0)
992                                 return r;
993                 } else {
994                         r = sd_bus_message_skip(m, "v");
995                         if (r < 0)
996                                 return r;
997                 }
998
999                 r = sd_bus_message_exit_container(m);
1000                 if (r < 0)
1001                         return r;
1002         }
1003         if (r < 0)
1004                 return r;
1005
1006         r = sd_bus_message_exit_container(m);
1007         if (r < 0)
1008                 return r;
1009
1010         return 0;
1011 }
1012
1013 int bus_print_all_properties(
1014                 sd_bus *bus,
1015                 const char *dest,
1016                 const char *path,
1017                 bus_message_print_t func,
1018                 char **filter,
1019                 bool value,
1020                 bool all,
1021                 Set **found_properties) {
1022
1023         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1024         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1025         int r;
1026
1027         assert(bus);
1028         assert(path);
1029
1030         r = sd_bus_call_method(bus,
1031                         dest,
1032                         path,
1033                         "org.freedesktop.DBus.Properties",
1034                         "GetAll",
1035                         &error,
1036                         &reply,
1037                         "s", "");
1038         if (r < 0)
1039                 return r;
1040
1041         return bus_message_print_all_properties(reply, func, filter, value, all, found_properties);
1042 }
1043
1044 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1045         sd_id128_t *p = userdata;
1046         const void *v;
1047         size_t n;
1048         int r;
1049
1050         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1051         if (r < 0)
1052                 return r;
1053
1054         if (n == 0)
1055                 *p = SD_ID128_NULL;
1056         else if (n == 16)
1057                 memcpy((*p).bytes, v, n);
1058         else
1059                 return -EINVAL;
1060
1061         return 0;
1062 }
1063
1064 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool copy_string) {
1065         char type;
1066         int r;
1067
1068         r = sd_bus_message_peek_type(m, &type, NULL);
1069         if (r < 0)
1070                 return r;
1071
1072         switch (type) {
1073
1074         case SD_BUS_TYPE_STRING: {
1075                 const char **p = userdata;
1076                 const char *s;
1077
1078                 r = sd_bus_message_read_basic(m, type, &s);
1079                 if (r < 0)
1080                         return r;
1081
1082                 if (isempty(s))
1083                         s = NULL;
1084
1085                 if (copy_string)
1086                         return free_and_strdup((char **) userdata, s);
1087
1088                 *p = s;
1089                 return 0;
1090         }
1091
1092         case SD_BUS_TYPE_ARRAY: {
1093                 _cleanup_strv_free_ char **l = NULL;
1094                 char ***p = userdata;
1095
1096                 r = bus_message_read_strv_extend(m, &l);
1097                 if (r < 0)
1098                         return r;
1099
1100                 strv_free(*p);
1101                 *p = TAKE_PTR(l);
1102                 return 0;
1103         }
1104
1105         case SD_BUS_TYPE_BOOLEAN: {
1106                 unsigned b;
1107                 bool *p = userdata;
1108
1109                 r = sd_bus_message_read_basic(m, type, &b);
1110                 if (r < 0)
1111                         return r;
1112
1113                 *p = !!b;
1114                 return 0;
1115         }
1116
1117         case SD_BUS_TYPE_INT32:
1118         case SD_BUS_TYPE_UINT32: {
1119                 uint32_t u, *p = userdata;
1120
1121                 r = sd_bus_message_read_basic(m, type, &u);
1122                 if (r < 0)
1123                         return r;
1124
1125                 *p = u;
1126                 return 0;
1127         }
1128
1129         case SD_BUS_TYPE_INT64:
1130         case SD_BUS_TYPE_UINT64: {
1131                 uint64_t t, *p = userdata;
1132
1133                 r = sd_bus_message_read_basic(m, type, &t);
1134                 if (r < 0)
1135                         return r;
1136
1137                 *p = t;
1138                 return 0;
1139         }
1140
1141         case SD_BUS_TYPE_DOUBLE: {
1142                 double d, *p = userdata;
1143
1144                 r = sd_bus_message_read_basic(m, type, &d);
1145                 if (r < 0)
1146                         return r;
1147
1148                 *p = d;
1149                 return 0;
1150         }}
1151
1152         return -EOPNOTSUPP;
1153 }
1154
1155 int bus_message_map_all_properties(
1156                 sd_bus_message *m,
1157                 const struct bus_properties_map *map,
1158                 bool copy_string,
1159                 sd_bus_error *error,
1160                 void *userdata) {
1161
1162         int r;
1163
1164         assert(m);
1165         assert(map);
1166
1167         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1168         if (r < 0)
1169                 return r;
1170
1171         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1172                 const struct bus_properties_map *prop;
1173                 const char *member;
1174                 const char *contents;
1175                 void *v;
1176                 unsigned i;
1177
1178                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1179                 if (r < 0)
1180                         return r;
1181
1182                 for (i = 0, prop = NULL; map[i].member; i++)
1183                         if (streq(map[i].member, member)) {
1184                                 prop = &map[i];
1185                                 break;
1186                         }
1187
1188                 if (prop) {
1189                         r = sd_bus_message_peek_type(m, NULL, &contents);
1190                         if (r < 0)
1191                                 return r;
1192
1193                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1194                         if (r < 0)
1195                                 return r;
1196
1197                         v = (uint8_t *)userdata + prop->offset;
1198                         if (map[i].set)
1199                                 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1200                         else
1201                                 r = map_basic(sd_bus_message_get_bus(m), member, m, error, v, copy_string);
1202                         if (r < 0)
1203                                 return r;
1204
1205                         r = sd_bus_message_exit_container(m);
1206                         if (r < 0)
1207                                 return r;
1208                 } else {
1209                         r = sd_bus_message_skip(m, "v");
1210                         if (r < 0)
1211                                 return r;
1212                 }
1213
1214                 r = sd_bus_message_exit_container(m);
1215                 if (r < 0)
1216                         return r;
1217         }
1218         if (r < 0)
1219                 return r;
1220
1221         return sd_bus_message_exit_container(m);
1222 }
1223
1224 #if 0 /// UNNEEDED by elogind
1225 int bus_message_map_properties_changed(
1226                 sd_bus_message *m,
1227                 const struct bus_properties_map *map,
1228                 bool copy_string,
1229                 sd_bus_error *error,
1230                 void *userdata) {
1231
1232         const char *member;
1233         int r, invalidated, i;
1234
1235         assert(m);
1236         assert(map);
1237
1238         r = bus_message_map_all_properties(m, map, copy_string, error, userdata);
1239         if (r < 0)
1240                 return r;
1241
1242         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1243         if (r < 0)
1244                 return r;
1245
1246         invalidated = 0;
1247         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1248                 for (i = 0; map[i].member; i++)
1249                         if (streq(map[i].member, member)) {
1250                                 ++invalidated;
1251                                 break;
1252                         }
1253         if (r < 0)
1254                 return r;
1255
1256         r = sd_bus_message_exit_container(m);
1257         if (r < 0)
1258                 return r;
1259
1260         return invalidated;
1261 }
1262 #endif // 0
1263
1264 int bus_map_all_properties(
1265                 sd_bus *bus,
1266                 const char *destination,
1267                 const char *path,
1268                 const struct bus_properties_map *map,
1269                 sd_bus_error *error,
1270                 sd_bus_message **reply,
1271                 void *userdata) {
1272
1273         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1274         int r;
1275
1276         assert(bus);
1277         assert(destination);
1278         assert(path);
1279         assert(map);
1280
1281         r = sd_bus_call_method(
1282                         bus,
1283                         destination,
1284                         path,
1285                         "org.freedesktop.DBus.Properties",
1286                         "GetAll",
1287                         error,
1288                         &m,
1289                         "s", "");
1290         if (r < 0)
1291                 return r;
1292
1293         r = bus_message_map_all_properties(m, map, !reply, error, userdata);
1294         if (r < 0)
1295                 return r;
1296
1297         if (reply)
1298                 *reply = sd_bus_message_ref(m);
1299
1300         return r;
1301 }
1302
1303 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1304         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1305         int r;
1306
1307         assert(transport >= 0);
1308         assert(transport < _BUS_TRANSPORT_MAX);
1309         assert(ret);
1310
1311         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1312         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1313
1314         switch (transport) {
1315
1316         case BUS_TRANSPORT_LOCAL:
1317 #if 0 /// elogind does not support a user bus
1318                 if (user)
1319                         r = sd_bus_default_user(&bus);
1320                 else
1321 #endif // 0
1322                         r = sd_bus_default_system(&bus);
1323
1324                 break;
1325
1326         case BUS_TRANSPORT_REMOTE:
1327                 r = sd_bus_open_system_remote(&bus, host);
1328                 break;
1329
1330         case BUS_TRANSPORT_MACHINE:
1331                 r = sd_bus_open_system_machine(&bus, host);
1332                 break;
1333
1334         default:
1335                 assert_not_reached("Hmm, unknown transport type.");
1336         }
1337         if (r < 0)
1338                 return r;
1339
1340         r = sd_bus_set_exit_on_disconnect(bus, true);
1341         if (r < 0)
1342                 return r;
1343
1344         *ret = bus;
1345         bus = NULL;
1346
1347         return 0;
1348 }
1349
1350 #if 0 /// UNNEEDED by elogind
1351 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1352         int r;
1353
1354         assert(transport >= 0);
1355         assert(transport < _BUS_TRANSPORT_MAX);
1356         assert(bus);
1357
1358         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1359         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1360
1361         switch (transport) {
1362
1363         case BUS_TRANSPORT_LOCAL:
1364                 if (user)
1365                         r = bus_connect_user_systemd(bus);
1366                 else
1367                         r = bus_connect_system_systemd(bus);
1368
1369                 break;
1370
1371         case BUS_TRANSPORT_REMOTE:
1372                 r = sd_bus_open_system_remote(bus, host);
1373                 break;
1374
1375         case BUS_TRANSPORT_MACHINE:
1376                 r = sd_bus_open_system_machine(bus, host);
1377                 break;
1378
1379         default:
1380                 assert_not_reached("Hmm, unknown transport type.");
1381         }
1382
1383         return r;
1384 }
1385 #endif // 0
1386
1387 int bus_property_get_bool(
1388                 sd_bus *bus,
1389                 const char *path,
1390                 const char *interface,
1391                 const char *property,
1392                 sd_bus_message *reply,
1393                 void *userdata,
1394                 sd_bus_error *error) {
1395
1396         int b = *(bool*) userdata;
1397
1398         return sd_bus_message_append_basic(reply, 'b', &b);
1399 }
1400
1401 int bus_property_set_bool(
1402                 sd_bus *bus,
1403                 const char *path,
1404                 const char *interface,
1405                 const char *property,
1406                 sd_bus_message *value,
1407                 void *userdata,
1408                 sd_bus_error *error) {
1409
1410         int b, r;
1411
1412         r = sd_bus_message_read(value, "b", &b);
1413         if (r < 0)
1414                 return r;
1415
1416         *(bool *) userdata = !!b;
1417         return 0;
1418 }
1419
1420 #if 0 /// UNNEEDED by elogind
1421 int bus_property_get_id128(
1422                 sd_bus *bus,
1423                 const char *path,
1424                 const char *interface,
1425                 const char *property,
1426                 sd_bus_message *reply,
1427                 void *userdata,
1428                 sd_bus_error *error) {
1429
1430         sd_id128_t *id = userdata;
1431
1432         if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1433                 return sd_bus_message_append(reply, "ay", 0);
1434         else
1435                 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1436 }
1437 #endif // 0
1438
1439 #if __SIZEOF_SIZE_T__ != 8
1440 int bus_property_get_size(
1441                 sd_bus *bus,
1442                 const char *path,
1443                 const char *interface,
1444                 const char *property,
1445                 sd_bus_message *reply,
1446                 void *userdata,
1447                 sd_bus_error *error) {
1448
1449         uint64_t sz = *(size_t*) userdata;
1450
1451         return sd_bus_message_append_basic(reply, 't', &sz);
1452 }
1453 #endif
1454
1455 #if __SIZEOF_LONG__ != 8
1456 int bus_property_get_long(
1457                 sd_bus *bus,
1458                 const char *path,
1459                 const char *interface,
1460                 const char *property,
1461                 sd_bus_message *reply,
1462                 void *userdata,
1463                 sd_bus_error *error) {
1464
1465         int64_t l = *(long*) userdata;
1466
1467         return sd_bus_message_append_basic(reply, 'x', &l);
1468 }
1469
1470 int bus_property_get_ulong(
1471                 sd_bus *bus,
1472                 const char *path,
1473                 const char *interface,
1474                 const char *property,
1475                 sd_bus_message *reply,
1476                 void *userdata,
1477                 sd_bus_error *error) {
1478
1479         uint64_t ul = *(unsigned long*) userdata;
1480
1481         return sd_bus_message_append_basic(reply, 't', &ul);
1482 }
1483 #endif
1484
1485 int bus_log_parse_error(int r) {
1486         return log_error_errno(r, "Failed to parse bus message: %m");
1487 }
1488
1489 #if 0 /// UNNEEDED by elogind
1490 int bus_log_create_error(int r) {
1491         return log_error_errno(r, "Failed to create bus message: %m");
1492 }
1493
1494 #endif // 0
1495 #if 0 /// UNNEEDED by elogind
1496 /**
1497  * bus_path_encode_unique() - encode unique object path
1498  * @b: bus connection or NULL
1499  * @prefix: object path prefix
1500  * @sender_id: unique-name of client, or NULL
1501  * @external_id: external ID to be chosen by client, or NULL
1502  * @ret_path: storage for encoded object path pointer
1503  *
1504  * Whenever we provide a bus API that allows clients to create and manage
1505  * server-side objects, we need to provide a unique name for these objects. If
1506  * we let the server choose the name, we suffer from a race condition: If a
1507  * client creates an object asynchronously, it cannot destroy that object until
1508  * it received the method reply. It cannot know the name of the new object,
1509  * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1510  *
1511  * Therefore, many APIs allow the client to choose the unique name for newly
1512  * created objects. There're two problems to solve, though:
1513  *    1) Object names are usually defined via dbus object paths, which are
1514  *       usually globally namespaced. Therefore, multiple clients must be able
1515  *       to choose unique object names without interference.
1516  *    2) If multiple libraries share the same bus connection, they must be
1517  *       able to choose unique object names without interference.
1518  * The first problem is solved easily by prefixing a name with the
1519  * unique-bus-name of a connection. The server side must enforce this and
1520  * reject any other name. The second problem is solved by providing unique
1521  * suffixes from within sd-bus.
1522  *
1523  * This helper allows clients to create unique object-paths. It uses the
1524  * template '/prefix/sender_id/external_id' and returns the new path in
1525  * @ret_path (must be freed by the caller).
1526  * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1527  * NULL, this function allocates a unique suffix via @b (by requesting a new
1528  * cookie). If both @sender_id and @external_id are given, @b can be passed as
1529  * NULL.
1530  *
1531  * Returns: 0 on success, negative error code on failure.
1532  */
1533 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1534         _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1535         char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1536         int r;
1537
1538         assert_return(b || (sender_id && external_id), -EINVAL);
1539         assert_return(object_path_is_valid(prefix), -EINVAL);
1540         assert_return(ret_path, -EINVAL);
1541
1542         if (!sender_id) {
1543                 r = sd_bus_get_unique_name(b, &sender_id);
1544                 if (r < 0)
1545                         return r;
1546         }
1547
1548         if (!external_id) {
1549                 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1550                 external_id = external_buf;
1551         }
1552
1553         sender_label = bus_label_escape(sender_id);
1554         if (!sender_label)
1555                 return -ENOMEM;
1556
1557         external_label = bus_label_escape(external_id);
1558         if (!external_label)
1559                 return -ENOMEM;
1560
1561         p = strjoin(prefix, "/", sender_label, "/", external_label);
1562         if (!p)
1563                 return -ENOMEM;
1564
1565         *ret_path = p;
1566         return 0;
1567 }
1568
1569 /**
1570  * bus_path_decode_unique() - decode unique object path
1571  * @path: object path to decode
1572  * @prefix: object path prefix
1573  * @ret_sender: output parameter for sender-id label
1574  * @ret_external: output parameter for external-id label
1575  *
1576  * This does the reverse of bus_path_encode_unique() (see its description for
1577  * details). Both trailing labels, sender-id and external-id, are unescaped and
1578  * returned in the given output parameters (the caller must free them).
1579  *
1580  * Note that this function returns 0 if the path does not match the template
1581  * (see bus_path_encode_unique()), 1 if it matched.
1582  *
1583  * Returns: Negative error code on failure, 0 if the given object path does not
1584  *          match the template (return parameters are set to NULL), 1 if it was
1585  *          parsed successfully (return parameters contain allocated labels).
1586  */
1587 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1588         const char *p, *q;
1589         char *sender, *external;
1590
1591         assert(object_path_is_valid(path));
1592         assert(object_path_is_valid(prefix));
1593         assert(ret_sender);
1594         assert(ret_external);
1595
1596         p = object_path_startswith(path, prefix);
1597         if (!p) {
1598                 *ret_sender = NULL;
1599                 *ret_external = NULL;
1600                 return 0;
1601         }
1602
1603         q = strchr(p, '/');
1604         if (!q) {
1605                 *ret_sender = NULL;
1606                 *ret_external = NULL;
1607                 return 0;
1608         }
1609
1610         sender = bus_label_unescape_n(p, q - p);
1611         external = bus_label_unescape(q + 1);
1612         if (!sender || !external) {
1613                 free(sender);
1614                 free(external);
1615                 return -ENOMEM;
1616         }
1617
1618         *ret_sender = sender;
1619         *ret_external = external;
1620         return 1;
1621 }
1622 #endif // 0
1623
1624 #if 0 /// UNNEEDED by elogind
1625 int bus_property_get_rlimit(
1626                 sd_bus *bus,
1627                 const char *path,
1628                 const char *interface,
1629                 const char *property,
1630                 sd_bus_message *reply,
1631                 void *userdata,
1632                 sd_bus_error *error) {
1633
1634         struct rlimit *rl;
1635         uint64_t u;
1636         rlim_t x;
1637         const char *is_soft;
1638
1639         assert(bus);
1640         assert(reply);
1641         assert(userdata);
1642
1643         is_soft = endswith(property, "Soft");
1644         rl = *(struct rlimit**) userdata;
1645         if (rl)
1646                 x = is_soft ? rl->rlim_cur : rl->rlim_max;
1647         else {
1648                 struct rlimit buf = {};
1649                 int z;
1650                 const char *s;
1651
1652                 s = is_soft ? strndupa(property, is_soft - property) : property;
1653
1654                 z = rlimit_from_string(strstr(s, "Limit"));
1655                 assert(z >= 0);
1656
1657                 getrlimit(z, &buf);
1658                 x = is_soft ? buf.rlim_cur : buf.rlim_max;
1659         }
1660
1661         /* rlim_t might have different sizes, let's map
1662          * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
1663          * all archs */
1664         u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1665
1666         return sd_bus_message_append(reply, "t", u);
1667 }
1668
1669 int bus_track_add_name_many(sd_bus_track *t, char **l) {
1670         int r = 0;
1671         char **i;
1672
1673         assert(t);
1674
1675         /* Continues adding after failure, and returns the first failure. */
1676
1677         STRV_FOREACH(i, l) {
1678                 int k;
1679
1680                 k = sd_bus_track_add_name(t, *i);
1681                 if (k < 0 && r >= 0)
1682                         r = k;
1683         }
1684
1685         return r;
1686 }
1687 #endif // 0
1688
1689 int bus_open_system_watch_bind(sd_bus **ret) {
1690         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1691         const char *e;
1692         int r;
1693
1694         assert(ret);
1695
1696         /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
1697
1698         r = sd_bus_new(&bus);
1699         if (r < 0)
1700                 return r;
1701
1702         e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1703         if (!e)
1704                 e = DEFAULT_SYSTEM_BUS_ADDRESS;
1705
1706         r = sd_bus_set_address(bus, e);
1707         if (r < 0)
1708                 return r;
1709
1710         r = sd_bus_set_bus_client(bus, true);
1711         if (r < 0)
1712                 return r;
1713
1714         r = sd_bus_set_trusted(bus, true);
1715         if (r < 0)
1716                 return r;
1717
1718         r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1719         if (r < 0)
1720                 return r;
1721
1722         r = sd_bus_set_watch_bind(bus, true);
1723         if (r < 0)
1724                 return r;
1725
1726         r = sd_bus_set_connected_signal(bus, true);
1727         if (r < 0)
1728                 return r;
1729
1730         r = sd_bus_start(bus);
1731         if (r < 0)
1732                 return r;
1733
1734         *ret = bus;
1735         bus = NULL;
1736
1737         return 0;
1738 }