chiark / gitweb /
bus-util: do not print (uint64_t) -1 as is (#6522)
[elogind.git] / src / shared / bus-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/ioctl.h>
27 #include <sys/resource.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30
31 #include "sd-bus-protocol.h"
32 #include "sd-bus.h"
33 #include "sd-daemon.h"
34 #include "sd-event.h"
35 #include "sd-id128.h"
36
37 #include "alloc-util.h"
38 #include "bus-internal.h"
39 #include "bus-label.h"
40 #include "bus-message.h"
41 #include "bus-util.h"
42 #include "cgroup-util.h"
43 #include "def.h"
44 #include "escape.h"
45 #include "fd-util.h"
46 #include "missing.h"
47 #include "mount-util.h"
48 #include "nsflags.h"
49 #include "parse-util.h"
50 #include "proc-cmdline.h"
51 //#include "rlimit-util.h"
52 #include "stdio-util.h"
53 #include "strv.h"
54 #include "user-util.h"
55
56 #if 0 /// UNNEEDED by elogind
57 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
58         sd_event *e = userdata;
59
60         assert(m);
61         assert(e);
62
63         sd_bus_close(sd_bus_message_get_bus(m));
64         sd_event_exit(e, 0);
65
66         return 1;
67 }
68
69 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
70         _cleanup_free_ char *match = NULL;
71         const char *unique;
72         int r;
73
74         assert(e);
75         assert(bus);
76         assert(name);
77
78         /* We unregister the name here and then wait for the
79          * NameOwnerChanged signal for this event to arrive before we
80          * quit. We do this in order to make sure that any queued
81          * requests are still processed before we really exit. */
82
83         r = sd_bus_get_unique_name(bus, &unique);
84         if (r < 0)
85                 return r;
86
87         r = asprintf(&match,
88                      "sender='org.freedesktop.DBus',"
89                      "type='signal',"
90                      "interface='org.freedesktop.DBus',"
91                      "member='NameOwnerChanged',"
92                      "path='/org/freedesktop/DBus',"
93                      "arg0='%s',"
94                      "arg1='%s',"
95                      "arg2=''", name, unique);
96         if (r < 0)
97                 return -ENOMEM;
98
99         r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
100         if (r < 0)
101                 return r;
102
103         r = sd_bus_release_name(bus, name);
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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef ENABLE_POLKIT
557         AsyncPolkitQuery *q;
558
559         while ((q = hashmap_steal_first(registry)))
560                 async_polkit_query_free(q);
561
562         hashmap_free(registry);
563 #endif
564 }
565
566 #if 0 /// UNNEEDED by elogind
567 int bus_check_peercred(sd_bus *c) {
568         struct ucred ucred;
569         socklen_t l;
570         int fd;
571
572         assert(c);
573
574         fd = sd_bus_get_fd(c);
575         if (fd < 0)
576                 return fd;
577
578         l = sizeof(struct ucred);
579         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
580                 return -errno;
581
582         if (l != sizeof(struct ucred))
583                 return -E2BIG;
584
585         if (ucred.uid != 0 && ucred.uid != geteuid())
586                 return -EPERM;
587
588         return 1;
589 }
590
591 int bus_connect_system_systemd(sd_bus **_bus) {
592         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
593         int r;
594
595         assert(_bus);
596
597         if (geteuid() != 0)
598                 return sd_bus_default_system(_bus);
599
600         /* If we are root and kdbus is not available, then let's talk
601          * directly to the system instance, instead of going via the
602          * bus */
603
604         r = sd_bus_new(&bus);
605         if (r < 0)
606                 return r;
607
608         r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
609         if (r < 0)
610                 return r;
611
612         bus->bus_client = true;
613
614         r = sd_bus_start(bus);
615         if (r >= 0) {
616                 *_bus = bus;
617                 bus = NULL;
618                 return 0;
619         }
620
621         bus = sd_bus_unref(bus);
622
623         r = sd_bus_new(&bus);
624         if (r < 0)
625                 return r;
626
627         r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
628         if (r < 0)
629                 return r;
630
631         r = sd_bus_start(bus);
632         if (r < 0)
633                 return sd_bus_default_system(_bus);
634
635         r = bus_check_peercred(bus);
636         if (r < 0)
637                 return r;
638
639         *_bus = bus;
640         bus = NULL;
641
642         return 0;
643 }
644
645 int bus_connect_user_systemd(sd_bus **_bus) {
646         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
647         _cleanup_free_ char *ee = NULL;
648         const char *e;
649         int r;
650
651         /* Try via kdbus first, and then directly */
652
653         assert(_bus);
654
655         r = sd_bus_new(&bus);
656         if (r < 0)
657                 return r;
658
659         if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
660                 return -ENOMEM;
661
662         bus->bus_client = true;
663
664         r = sd_bus_start(bus);
665         if (r >= 0) {
666                 *_bus = bus;
667                 bus = NULL;
668                 return 0;
669         }
670
671         bus = sd_bus_unref(bus);
672
673         e = secure_getenv("XDG_RUNTIME_DIR");
674         if (!e)
675                 return sd_bus_default_user(_bus);
676
677         ee = bus_address_escape(e);
678         if (!ee)
679                 return -ENOMEM;
680
681         r = sd_bus_new(&bus);
682         if (r < 0)
683                 return r;
684
685         bus->address = strjoin("unix:path=", ee, "/systemd/private");
686         if (!bus->address)
687                 return -ENOMEM;
688
689         r = sd_bus_start(bus);
690         if (r < 0)
691                 return sd_bus_default_user(_bus);
692
693         r = bus_check_peercred(bus);
694         if (r < 0)
695                 return r;
696
697         *_bus = bus;
698         bus = NULL;
699
700         return 0;
701 }
702 #endif // 0
703
704 #define print_property(name, fmt, ...)                                  \
705         do {                                                            \
706                 if (value)                                              \
707                         printf(fmt "\n", __VA_ARGS__);                  \
708                 else                                                    \
709                         printf("%s=" fmt "\n", name, __VA_ARGS__);      \
710         } while(0)
711
712 int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) {
713         char type;
714         const char *contents;
715         int r;
716
717         assert(name);
718         assert(property);
719
720         r = sd_bus_message_peek_type(property, &type, &contents);
721         if (r < 0)
722                 return r;
723
724         switch (type) {
725
726         case SD_BUS_TYPE_STRING: {
727                 const char *s;
728
729                 r = sd_bus_message_read_basic(property, type, &s);
730                 if (r < 0)
731                         return r;
732
733                 if (all || !isempty(s)) {
734                         bool good;
735
736                         /* This property has a single value, so we need to take
737                          * care not to print a new line, everything else is OK. */
738                         good = !strchr(s, '\n');
739                         print_property(name, "%s", good ? s : "[unprintable]");
740                 }
741
742                 return 1;
743         }
744
745         case SD_BUS_TYPE_BOOLEAN: {
746                 int b;
747
748                 r = sd_bus_message_read_basic(property, type, &b);
749                 if (r < 0)
750                         return r;
751
752                 print_property(name, "%s", yes_no(b));
753
754                 return 1;
755         }
756
757         case SD_BUS_TYPE_UINT64: {
758                 uint64_t u;
759
760                 r = sd_bus_message_read_basic(property, type, &u);
761                 if (r < 0)
762                         return r;
763
764                 /* Yes, heuristics! But we can change this check
765                  * should it turn out to not be sufficient */
766
767                 if (endswith(name, "Timestamp")) {
768                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
769
770                         t = format_timestamp(timestamp, sizeof(timestamp), u);
771                         if (t || all)
772                                 print_property(name, "%s", strempty(t));
773
774                 } else if (strstr(name, "USec")) {
775                         char timespan[FORMAT_TIMESPAN_MAX];
776
777                         print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
778                 } else if (streq(name, "RestrictNamespaces")) {
779                         _cleanup_free_ char *s = NULL;
780                         const char *result = NULL;
781
782                         if ((u & NAMESPACE_FLAGS_ALL) == 0)
783                                 result = "yes";
784                         else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
785                                 result = "no";
786                         else {
787                                 r = namespace_flag_to_string_many(u, &s);
788                                 if (r < 0)
789                                         return r;
790
791                                 result = s;
792                         }
793
794                         print_property(name, "%s", result);
795
796                 } else if (streq(name, "MountFlags")) {
797                         const char *result = NULL;
798
799                         result = mount_propagation_flags_to_string(u);
800                         if (!result)
801                                 return -EINVAL;
802
803                         print_property(name, "%s", result);
804
805                 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
806                            (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
807                            (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
808                            (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
809                            (endswith(name, "NSec") && u == (uint64_t) -1))
810
811                         print_property(name, "%s", "[not set]");
812
813                 else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
814                          (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
815                          (startswith(name, "Limit") && u == (uint64_t) -1) ||
816                          (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
817
818                         print_property(name, "%s", "infinity");
819                 else
820                         print_property(name, "%"PRIu64, u);
821
822                 return 1;
823         }
824
825         case SD_BUS_TYPE_INT64: {
826                 int64_t i;
827
828                 r = sd_bus_message_read_basic(property, type, &i);
829                 if (r < 0)
830                         return r;
831
832                 print_property(name, "%"PRIi64, i);
833
834                 return 1;
835         }
836
837         case SD_BUS_TYPE_UINT32: {
838                 uint32_t u;
839
840                 r = sd_bus_message_read_basic(property, type, &u);
841                 if (r < 0)
842                         return r;
843
844                 if (strstr(name, "UMask") || strstr(name, "Mode"))
845                         print_property(name, "%04o", u);
846                 else
847                         print_property(name, "%"PRIu32, u);
848
849                 return 1;
850         }
851
852         case SD_BUS_TYPE_INT32: {
853                 int32_t i;
854
855                 r = sd_bus_message_read_basic(property, type, &i);
856                 if (r < 0)
857                         return r;
858
859                 print_property(name, "%"PRIi32, i);
860                 return 1;
861         }
862
863         case SD_BUS_TYPE_DOUBLE: {
864                 double d;
865
866                 r = sd_bus_message_read_basic(property, type, &d);
867                 if (r < 0)
868                         return r;
869
870                 print_property(name, "%g", d);
871                 return 1;
872         }
873
874         case SD_BUS_TYPE_ARRAY:
875                 if (streq(contents, "s")) {
876                         bool first = true;
877                         const char *str;
878
879                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
880                         if (r < 0)
881                                 return r;
882
883                         while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
884                                 bool good;
885
886                                 if (first && !value)
887                                         printf("%s=", name);
888
889                                 /* This property has multiple space-seperated values, so
890                                  * neither spaces not newlines can be allowed in a value. */
891                                 good = str[strcspn(str, " \n")] == '\0';
892
893                                 printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
894
895                                 first = false;
896                         }
897                         if (r < 0)
898                                 return r;
899
900                         if (first && all && !value)
901                                 printf("%s=", name);
902                         if (!first || all)
903                                 puts("");
904
905                         r = sd_bus_message_exit_container(property);
906                         if (r < 0)
907                                 return r;
908
909                         return 1;
910
911                 } else if (streq(contents, "y")) {
912                         const uint8_t *u;
913                         size_t n;
914
915                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
916                         if (r < 0)
917                                 return r;
918
919                         if (all || n > 0) {
920                                 unsigned int i;
921
922                                 if (!value)
923                                         printf("%s=", name);
924
925                                 for (i = 0; i < n; i++)
926                                         printf("%02x", u[i]);
927
928                                 puts("");
929                         }
930
931                         return 1;
932
933                 } else if (streq(contents, "u")) {
934                         uint32_t *u;
935                         size_t n;
936
937                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
938                         if (r < 0)
939                                 return r;
940
941                         if (all || n > 0) {
942                                 unsigned int i;
943
944                                 if (!value)
945                                         printf("%s=", name);
946
947                                 for (i = 0; i < n; i++)
948                                         printf("%08x", u[i]);
949
950                                 puts("");
951                         }
952
953                         return 1;
954                 }
955
956                 break;
957         }
958
959         return 0;
960 }
961
962 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all) {
963         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
964         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
965         int r;
966
967         assert(bus);
968         assert(path);
969
970         r = sd_bus_call_method(bus,
971                         dest,
972                         path,
973                         "org.freedesktop.DBus.Properties",
974                         "GetAll",
975                         &error,
976                         &reply,
977                         "s", "");
978         if (r < 0)
979                 return r;
980
981         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
982         if (r < 0)
983                 return r;
984
985         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
986                 const char *name;
987                 const char *contents;
988
989                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
990                 if (r < 0)
991                         return r;
992
993                 if (!filter || strv_find(filter, name)) {
994                         r = sd_bus_message_peek_type(reply, NULL, &contents);
995                         if (r < 0)
996                                 return r;
997
998                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
999                         if (r < 0)
1000                                 return r;
1001
1002                         r = bus_print_property(name, reply, value, all);
1003                         if (r < 0)
1004                                 return r;
1005                         if (r == 0) {
1006                                 if (all)
1007                                         printf("%s=[unprintable]\n", name);
1008                                 /* skip what we didn't read */
1009                                 r = sd_bus_message_skip(reply, contents);
1010                                 if (r < 0)
1011                                         return r;
1012                         }
1013
1014                         r = sd_bus_message_exit_container(reply);
1015                         if (r < 0)
1016                                 return r;
1017                 } else {
1018                         r = sd_bus_message_skip(reply, "v");
1019                         if (r < 0)
1020                                 return r;
1021                 }
1022
1023                 r = sd_bus_message_exit_container(reply);
1024                 if (r < 0)
1025                         return r;
1026         }
1027         if (r < 0)
1028                 return r;
1029
1030         r = sd_bus_message_exit_container(reply);
1031         if (r < 0)
1032                 return r;
1033
1034         return 0;
1035 }
1036
1037 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1038         sd_id128_t *p = userdata;
1039         const void *v;
1040         size_t n;
1041         int r;
1042
1043         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1044         if (r < 0)
1045                 return r;
1046
1047         if (n == 0)
1048                 *p = SD_ID128_NULL;
1049         else if (n == 16)
1050                 memcpy((*p).bytes, v, n);
1051         else
1052                 return -EINVAL;
1053
1054         return 0;
1055 }
1056
1057 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1058         char type;
1059         int r;
1060
1061         r = sd_bus_message_peek_type(m, &type, NULL);
1062         if (r < 0)
1063                 return r;
1064
1065         switch (type) {
1066
1067         case SD_BUS_TYPE_STRING: {
1068                 char **p = userdata;
1069                 const char *s;
1070
1071                 r = sd_bus_message_read_basic(m, type, &s);
1072                 if (r < 0)
1073                         return r;
1074
1075                 if (isempty(s))
1076                         s = NULL;
1077
1078                 return free_and_strdup(p, s);
1079         }
1080
1081         case SD_BUS_TYPE_ARRAY: {
1082                 _cleanup_strv_free_ char **l = NULL;
1083                 char ***p = userdata;
1084
1085                 r = bus_message_read_strv_extend(m, &l);
1086                 if (r < 0)
1087                         return r;
1088
1089                 strv_free(*p);
1090                 *p = l;
1091                 l = NULL;
1092                 return 0;
1093         }
1094
1095         case SD_BUS_TYPE_BOOLEAN: {
1096                 unsigned b;
1097                 int *p = userdata;
1098
1099                 r = sd_bus_message_read_basic(m, type, &b);
1100                 if (r < 0)
1101                         return r;
1102
1103                 *p = b;
1104                 return 0;
1105         }
1106
1107         case SD_BUS_TYPE_INT32:
1108         case SD_BUS_TYPE_UINT32: {
1109                 uint32_t u, *p = userdata;
1110
1111                 r = sd_bus_message_read_basic(m, type, &u);
1112                 if (r < 0)
1113                         return r;
1114
1115                 *p = u;
1116                 return 0;
1117         }
1118
1119         case SD_BUS_TYPE_INT64:
1120         case SD_BUS_TYPE_UINT64: {
1121                 uint64_t t, *p = userdata;
1122
1123                 r = sd_bus_message_read_basic(m, type, &t);
1124                 if (r < 0)
1125                         return r;
1126
1127                 *p = t;
1128                 return 0;
1129         }
1130
1131         case SD_BUS_TYPE_DOUBLE: {
1132                 double d, *p = userdata;
1133
1134                 r = sd_bus_message_read_basic(m, type, &d);
1135                 if (r < 0)
1136                         return r;
1137
1138                 *p = d;
1139                 return 0;
1140         }}
1141
1142         return -EOPNOTSUPP;
1143 }
1144
1145 int bus_message_map_all_properties(
1146                 sd_bus_message *m,
1147                 const struct bus_properties_map *map,
1148                 sd_bus_error *error,
1149                 void *userdata) {
1150
1151         int r;
1152
1153         assert(m);
1154         assert(map);
1155
1156         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1157         if (r < 0)
1158                 return r;
1159
1160         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1161                 const struct bus_properties_map *prop;
1162                 const char *member;
1163                 const char *contents;
1164                 void *v;
1165                 unsigned i;
1166
1167                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1168                 if (r < 0)
1169                         return r;
1170
1171                 for (i = 0, prop = NULL; map[i].member; i++)
1172                         if (streq(map[i].member, member)) {
1173                                 prop = &map[i];
1174                                 break;
1175                         }
1176
1177                 if (prop) {
1178                         r = sd_bus_message_peek_type(m, NULL, &contents);
1179                         if (r < 0)
1180                                 return r;
1181
1182                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1183                         if (r < 0)
1184                                 return r;
1185
1186                         v = (uint8_t *)userdata + prop->offset;
1187                         if (map[i].set)
1188                                 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1189                         else
1190                                 r = map_basic(sd_bus_message_get_bus(m), member, m, error, v);
1191                         if (r < 0)
1192                                 return r;
1193
1194                         r = sd_bus_message_exit_container(m);
1195                         if (r < 0)
1196                                 return r;
1197                 } else {
1198                         r = sd_bus_message_skip(m, "v");
1199                         if (r < 0)
1200                                 return r;
1201                 }
1202
1203                 r = sd_bus_message_exit_container(m);
1204                 if (r < 0)
1205                         return r;
1206         }
1207         if (r < 0)
1208                 return r;
1209
1210         return sd_bus_message_exit_container(m);
1211 }
1212
1213 #if 0 /// UNNEEDED by elogind
1214 int bus_message_map_properties_changed(
1215                 sd_bus_message *m,
1216                 const struct bus_properties_map *map,
1217                 sd_bus_error *error,
1218                 void *userdata) {
1219
1220         const char *member;
1221         int r, invalidated, i;
1222
1223         assert(m);
1224         assert(map);
1225
1226         r = bus_message_map_all_properties(m, map, error, userdata);
1227         if (r < 0)
1228                 return r;
1229
1230         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1231         if (r < 0)
1232                 return r;
1233
1234         invalidated = 0;
1235         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1236                 for (i = 0; map[i].member; i++)
1237                         if (streq(map[i].member, member)) {
1238                                 ++invalidated;
1239                                 break;
1240                         }
1241         if (r < 0)
1242                 return r;
1243
1244         r = sd_bus_message_exit_container(m);
1245         if (r < 0)
1246                 return r;
1247
1248         return invalidated;
1249 }
1250 #endif // 0
1251
1252 int bus_map_all_properties(
1253                 sd_bus *bus,
1254                 const char *destination,
1255                 const char *path,
1256                 const struct bus_properties_map *map,
1257                 sd_bus_error *error,
1258                 void *userdata) {
1259
1260         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1261         int r;
1262
1263         assert(bus);
1264         assert(destination);
1265         assert(path);
1266         assert(map);
1267
1268         r = sd_bus_call_method(
1269                         bus,
1270                         destination,
1271                         path,
1272                         "org.freedesktop.DBus.Properties",
1273                         "GetAll",
1274                         error,
1275                         &m,
1276                         "s", "");
1277         if (r < 0)
1278                 return r;
1279
1280         return bus_message_map_all_properties(m, map, error, userdata);
1281 }
1282
1283 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1284         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1285         int r;
1286
1287         assert(transport >= 0);
1288         assert(transport < _BUS_TRANSPORT_MAX);
1289         assert(ret);
1290
1291         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1292         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1293
1294         switch (transport) {
1295
1296         case BUS_TRANSPORT_LOCAL:
1297 #if 0 /// elogind does not support a user bus
1298                 if (user)
1299                         r = sd_bus_default_user(&bus);
1300                 else
1301 #endif // 0
1302                         r = sd_bus_default_system(&bus);
1303
1304                 break;
1305
1306         case BUS_TRANSPORT_REMOTE:
1307                 r = sd_bus_open_system_remote(&bus, host);
1308                 break;
1309
1310         case BUS_TRANSPORT_MACHINE:
1311                 r = sd_bus_open_system_machine(&bus, host);
1312                 break;
1313
1314         default:
1315                 assert_not_reached("Hmm, unknown transport type.");
1316         }
1317         if (r < 0)
1318                 return r;
1319
1320         r = sd_bus_set_exit_on_disconnect(bus, true);
1321         if (r < 0)
1322                 return r;
1323
1324         *ret = bus;
1325         bus = NULL;
1326
1327         return 0;
1328 }
1329
1330 #if 0 /// UNNEEDED by elogind
1331 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1332         int r;
1333
1334         assert(transport >= 0);
1335         assert(transport < _BUS_TRANSPORT_MAX);
1336         assert(bus);
1337
1338         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1339         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1340
1341         switch (transport) {
1342
1343         case BUS_TRANSPORT_LOCAL:
1344                 if (user)
1345                         r = bus_connect_user_systemd(bus);
1346                 else
1347                         r = bus_connect_system_systemd(bus);
1348
1349                 break;
1350
1351         case BUS_TRANSPORT_REMOTE:
1352                 r = sd_bus_open_system_remote(bus, host);
1353                 break;
1354
1355         case BUS_TRANSPORT_MACHINE:
1356                 r = sd_bus_open_system_machine(bus, host);
1357                 break;
1358
1359         default:
1360                 assert_not_reached("Hmm, unknown transport type.");
1361         }
1362
1363         return r;
1364 }
1365 #endif // 0
1366
1367 int bus_property_get_bool(
1368                 sd_bus *bus,
1369                 const char *path,
1370                 const char *interface,
1371                 const char *property,
1372                 sd_bus_message *reply,
1373                 void *userdata,
1374                 sd_bus_error *error) {
1375
1376         int b = *(bool*) userdata;
1377
1378         return sd_bus_message_append_basic(reply, 'b', &b);
1379 }
1380
1381 #if 0 /// UNNEEDED by elogind
1382 int bus_property_get_id128(
1383                 sd_bus *bus,
1384                 const char *path,
1385                 const char *interface,
1386                 const char *property,
1387                 sd_bus_message *reply,
1388                 void *userdata,
1389                 sd_bus_error *error) {
1390
1391         sd_id128_t *id = userdata;
1392
1393         if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1394                 return sd_bus_message_append(reply, "ay", 0);
1395         else
1396                 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1397 }
1398 #endif // 0
1399
1400 #if __SIZEOF_SIZE_T__ != 8
1401 int bus_property_get_size(
1402                 sd_bus *bus,
1403                 const char *path,
1404                 const char *interface,
1405                 const char *property,
1406                 sd_bus_message *reply,
1407                 void *userdata,
1408                 sd_bus_error *error) {
1409
1410         uint64_t sz = *(size_t*) userdata;
1411
1412         return sd_bus_message_append_basic(reply, 't', &sz);
1413 }
1414 #endif
1415
1416 #if __SIZEOF_LONG__ != 8
1417 int bus_property_get_long(
1418                 sd_bus *bus,
1419                 const char *path,
1420                 const char *interface,
1421                 const char *property,
1422                 sd_bus_message *reply,
1423                 void *userdata,
1424                 sd_bus_error *error) {
1425
1426         int64_t l = *(long*) userdata;
1427
1428         return sd_bus_message_append_basic(reply, 'x', &l);
1429 }
1430
1431 int bus_property_get_ulong(
1432                 sd_bus *bus,
1433                 const char *path,
1434                 const char *interface,
1435                 const char *property,
1436                 sd_bus_message *reply,
1437                 void *userdata,
1438                 sd_bus_error *error) {
1439
1440         uint64_t ul = *(unsigned long*) userdata;
1441
1442         return sd_bus_message_append_basic(reply, 't', &ul);
1443 }
1444 #endif
1445
1446 int bus_log_parse_error(int r) {
1447         return log_error_errno(r, "Failed to parse bus message: %m");
1448 }
1449
1450 #if 0 /// UNNEEDED by elogind
1451 int bus_log_create_error(int r) {
1452         return log_error_errno(r, "Failed to create bus message: %m");
1453 }
1454
1455 #endif // 0
1456 #if 0 /// UNNEEDED by elogind
1457 /**
1458  * bus_path_encode_unique() - encode unique object path
1459  * @b: bus connection or NULL
1460  * @prefix: object path prefix
1461  * @sender_id: unique-name of client, or NULL
1462  * @external_id: external ID to be chosen by client, or NULL
1463  * @ret_path: storage for encoded object path pointer
1464  *
1465  * Whenever we provide a bus API that allows clients to create and manage
1466  * server-side objects, we need to provide a unique name for these objects. If
1467  * we let the server choose the name, we suffer from a race condition: If a
1468  * client creates an object asynchronously, it cannot destroy that object until
1469  * it received the method reply. It cannot know the name of the new object,
1470  * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1471  *
1472  * Therefore, many APIs allow the client to choose the unique name for newly
1473  * created objects. There're two problems to solve, though:
1474  *    1) Object names are usually defined via dbus object paths, which are
1475  *       usually globally namespaced. Therefore, multiple clients must be able
1476  *       to choose unique object names without interference.
1477  *    2) If multiple libraries share the same bus connection, they must be
1478  *       able to choose unique object names without interference.
1479  * The first problem is solved easily by prefixing a name with the
1480  * unique-bus-name of a connection. The server side must enforce this and
1481  * reject any other name. The second problem is solved by providing unique
1482  * suffixes from within sd-bus.
1483  *
1484  * This helper allows clients to create unique object-paths. It uses the
1485  * template '/prefix/sender_id/external_id' and returns the new path in
1486  * @ret_path (must be freed by the caller).
1487  * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1488  * NULL, this function allocates a unique suffix via @b (by requesting a new
1489  * cookie). If both @sender_id and @external_id are given, @b can be passed as
1490  * NULL.
1491  *
1492  * Returns: 0 on success, negative error code on failure.
1493  */
1494 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1495         _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1496         char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1497         int r;
1498
1499         assert_return(b || (sender_id && external_id), -EINVAL);
1500         assert_return(object_path_is_valid(prefix), -EINVAL);
1501         assert_return(ret_path, -EINVAL);
1502
1503         if (!sender_id) {
1504                 r = sd_bus_get_unique_name(b, &sender_id);
1505                 if (r < 0)
1506                         return r;
1507         }
1508
1509         if (!external_id) {
1510                 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1511                 external_id = external_buf;
1512         }
1513
1514         sender_label = bus_label_escape(sender_id);
1515         if (!sender_label)
1516                 return -ENOMEM;
1517
1518         external_label = bus_label_escape(external_id);
1519         if (!external_label)
1520                 return -ENOMEM;
1521
1522         p = strjoin(prefix, "/", sender_label, "/", external_label);
1523         if (!p)
1524                 return -ENOMEM;
1525
1526         *ret_path = p;
1527         return 0;
1528 }
1529
1530 /**
1531  * bus_path_decode_unique() - decode unique object path
1532  * @path: object path to decode
1533  * @prefix: object path prefix
1534  * @ret_sender: output parameter for sender-id label
1535  * @ret_external: output parameter for external-id label
1536  *
1537  * This does the reverse of bus_path_encode_unique() (see its description for
1538  * details). Both trailing labels, sender-id and external-id, are unescaped and
1539  * returned in the given output parameters (the caller must free them).
1540  *
1541  * Note that this function returns 0 if the path does not match the template
1542  * (see bus_path_encode_unique()), 1 if it matched.
1543  *
1544  * Returns: Negative error code on failure, 0 if the given object path does not
1545  *          match the template (return parameters are set to NULL), 1 if it was
1546  *          parsed successfully (return parameters contain allocated labels).
1547  */
1548 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1549         const char *p, *q;
1550         char *sender, *external;
1551
1552         assert(object_path_is_valid(path));
1553         assert(object_path_is_valid(prefix));
1554         assert(ret_sender);
1555         assert(ret_external);
1556
1557         p = object_path_startswith(path, prefix);
1558         if (!p) {
1559                 *ret_sender = NULL;
1560                 *ret_external = NULL;
1561                 return 0;
1562         }
1563
1564         q = strchr(p, '/');
1565         if (!q) {
1566                 *ret_sender = NULL;
1567                 *ret_external = NULL;
1568                 return 0;
1569         }
1570
1571         sender = bus_label_unescape_n(p, q - p);
1572         external = bus_label_unescape(q + 1);
1573         if (!sender || !external) {
1574                 free(sender);
1575                 free(external);
1576                 return -ENOMEM;
1577         }
1578
1579         *ret_sender = sender;
1580         *ret_external = external;
1581         return 1;
1582 }
1583 #endif // 0
1584
1585 #if 0 /// UNNEEDED by elogind
1586 int bus_property_get_rlimit(
1587                 sd_bus *bus,
1588                 const char *path,
1589                 const char *interface,
1590                 const char *property,
1591                 sd_bus_message *reply,
1592                 void *userdata,
1593                 sd_bus_error *error) {
1594
1595         struct rlimit *rl;
1596         uint64_t u;
1597         rlim_t x;
1598         const char *is_soft;
1599
1600         assert(bus);
1601         assert(reply);
1602         assert(userdata);
1603
1604         is_soft = endswith(property, "Soft");
1605         rl = *(struct rlimit**) userdata;
1606         if (rl)
1607                 x = is_soft ? rl->rlim_cur : rl->rlim_max;
1608         else {
1609                 struct rlimit buf = {};
1610                 int z;
1611                 const char *s;
1612
1613                 s = is_soft ? strndupa(property, is_soft - property) : property;
1614
1615                 z = rlimit_from_string(strstr(s, "Limit"));
1616                 assert(z >= 0);
1617
1618                 getrlimit(z, &buf);
1619                 x = is_soft ? buf.rlim_cur : buf.rlim_max;
1620         }
1621
1622         /* rlim_t might have different sizes, let's map
1623          * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
1624          * all archs */
1625         u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1626
1627         return sd_bus_message_append(reply, "t", u);
1628 }
1629
1630 int bus_track_add_name_many(sd_bus_track *t, char **l) {
1631         int r = 0;
1632         char **i;
1633
1634         assert(t);
1635
1636         /* Continues adding after failure, and returns the first failure. */
1637
1638         STRV_FOREACH(i, l) {
1639                 int k;
1640
1641                 k = sd_bus_track_add_name(t, *i);
1642                 if (k < 0 && r >= 0)
1643                         r = k;
1644         }
1645
1646         return r;
1647 }
1648 #endif // 0