chiark / gitweb /
timedated: make sure GetAll() succeeds in systems lacking /dev/rtc (such as containers)
[elogind.git] / src / libsystemd-bus / bus-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/capability.h>
24
25 #include "util.h"
26 #include "strv.h"
27 #include "macro.h"
28 #include "def.h"
29 #include "missing.h"
30
31 #include "sd-event.h"
32 #include "sd-bus.h"
33 #include "bus-error.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36 #include "bus-internal.h"
37
38 static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
39         sd_event *e = userdata;
40
41         assert(bus);
42         assert(m);
43         assert(e);
44
45         sd_event_request_quit(e);
46         return 1;
47 }
48
49 int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
50         _cleanup_free_ char *match = NULL;
51         int r;
52
53         assert(e);
54         assert(bus);
55         assert(name);
56
57         r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
58         if (r < 0)
59                 return r;
60
61         r = sd_bus_add_match(bus, match, quit_callback, e);
62         if (r < 0)
63                 return r;
64
65         r = sd_bus_release_name(bus, name);
66         if (r < 0)
67                 return r;
68
69         if (r != BUS_NAME_RELEASED)
70                 return -EIO;
71
72         return 0;
73 }
74
75 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
76         bool exiting = false;
77         int r;
78
79         assert(e);
80         assert(bus);
81         assert(name);
82
83         for (;;) {
84                 r = sd_event_get_state(e);
85                 if (r < 0)
86                         return r;
87
88                 if (r == SD_EVENT_FINISHED)
89                         break;
90
91                 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
92                 if (r < 0)
93                         return r;
94
95                 if (r == 0 && !exiting) {
96                         r = bus_async_unregister_and_quit(e, bus, name);
97                         if (r < 0)
98                                 return r;
99
100                         exiting = true;
101                 }
102         }
103
104         return 0;
105 }
106
107 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
108         _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
109         int r, has_owner = 0;
110
111         assert(c);
112         assert(name);
113
114         r = sd_bus_call_method(c,
115                                "org.freedesktop.DBus",
116                                "/org/freedesktop/dbus",
117                                "org.freedesktop.DBus",
118                                "NameHasOwner",
119                                error,
120                                &rep,
121                                "s",
122                                name);
123         if (r < 0)
124                 return r;
125
126         r = sd_bus_message_read_basic(rep, 'b', &has_owner);
127         if (r < 0)
128                 return sd_bus_error_set_errno(error, r);
129
130         return has_owner;
131 }
132
133 int bus_verify_polkit(
134                 sd_bus *bus,
135                 sd_bus_message *m,
136                 const char *action,
137                 bool interactive,
138                 bool *_challenge,
139                 sd_bus_error *e) {
140
141         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
142         uid_t uid;
143         int r;
144
145         assert(bus);
146         assert(m);
147         assert(action);
148
149         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
150         if (r < 0)
151                 return r;
152
153         r = sd_bus_creds_get_uid(creds, &uid);
154         if (r < 0)
155                 return r;
156
157         if (uid == 0)
158                 return 1;
159
160 #ifdef ENABLE_POLKIT
161         else {
162                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
163                 int authorized = false, challenge = false;
164                 const char *sender;
165
166                 sender = sd_bus_message_get_sender(m);
167                 if (!sender)
168                         return -EBADMSG;
169
170                 r = sd_bus_call_method(
171                                 bus,
172                                 "org.freedesktop.PolicyKit1",
173                                 "/org/freedesktop/PolicyKit1/Authority",
174                                 "org.freedesktop.PolicyKit1.Authority",
175                                 "CheckAuthorization",
176                                 e,
177                                 &reply,
178                                 "(sa{sv})sa{ss}us",
179                                 "system-bus-name", 1, "name", "s", sender,
180                                 action,
181                                 0,
182                                 interactive ? 1 : 0,
183                                 "");
184
185                 if (r < 0) {
186                         /* Treat no PK available as access denied */
187                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
188                                 sd_bus_error_free(e);
189                                 return -EACCES;
190                         }
191
192                         return r;
193                 }
194
195                 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
196                 if (r >= 0)
197                         r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
198
199                 if (authorized)
200                         return 1;
201
202                 if (_challenge) {
203                         *_challenge = challenge;
204                         return 0;
205                 }
206         }
207 #endif
208
209         return -EACCES;
210 }
211
212 #ifdef ENABLE_POLKIT
213
214 typedef struct AsyncPolkitQuery {
215         sd_bus_message *request, *reply;
216         sd_bus_message_handler_t callback;
217         void *userdata;
218         uint64_t serial;
219         Hashmap *registry;
220 } AsyncPolkitQuery;
221
222 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
223
224         if (!q)
225                 return;
226
227         if (q->serial > 0 && b)
228                 sd_bus_call_async_cancel(b, q->serial);
229
230         if (q->registry && q->request)
231                 hashmap_remove(q->registry, q->request);
232
233         sd_bus_message_unref(q->request);
234         sd_bus_message_unref(q->reply);
235
236         free(q);
237 }
238
239 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
240         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
241         AsyncPolkitQuery *q = userdata;
242         int r;
243
244         assert(bus);
245         assert(reply);
246         assert(q);
247
248         q->reply = sd_bus_message_ref(reply);
249         q->serial = 0;
250
251         r = sd_bus_message_rewind(q->request, true);
252         if (r < 0) {
253                 r = sd_bus_reply_method_errno(q->request, r, NULL);
254                 goto finish;
255         }
256
257         r = q->callback(bus, q->request, q->userdata, &error_buffer);
258         r = bus_maybe_reply_error(q->request, r, &error_buffer);
259
260 finish:
261         async_polkit_query_free(bus, q);
262         return r;
263 }
264
265 #endif
266
267 int bus_verify_polkit_async(
268                 sd_bus *bus,
269                 Hashmap **registry,
270                 sd_bus_message *m,
271                 const char *action,
272                 bool interactive,
273                 sd_bus_error *error,
274                 sd_bus_message_handler_t callback,
275                 void *userdata) {
276
277 #ifdef ENABLE_POLKIT
278         _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
279         AsyncPolkitQuery *q;
280         const char *sender;
281 #endif
282         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
283         uid_t uid;
284         int r;
285
286         assert(bus);
287         assert(registry);
288         assert(m);
289         assert(action);
290
291 #ifdef ENABLE_POLKIT
292         q = hashmap_get(*registry, m);
293         if (q) {
294                 int authorized, challenge;
295
296                 /* This is the second invocation of this function, and
297                  * there's already a response from polkit, let's
298                  * process it */
299                 assert(q->reply);
300
301                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
302                         const sd_bus_error *e;
303
304                         /* Copy error from polkit reply */
305                         e = sd_bus_message_get_error(q->reply);
306                         sd_bus_error_copy(error, e);
307
308                         /* Treat no PK available as access denied */
309                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
310                                 return -EACCES;
311
312                         return sd_bus_error_get_errno(e);
313                 }
314
315                 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
316                 if (r >= 0)
317                         r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
318
319                 if (r < 0)
320                         return r;
321
322                 if (authorized)
323                         return 1;
324
325                 return -EACCES;
326         }
327 #endif
328
329         r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
330         if (r < 0)
331                 return r;
332
333         r = sd_bus_creds_get_uid(creds, &uid);
334         if (r < 0)
335                 return r;
336
337         if (uid == 0)
338                 return 1;
339
340 #ifdef ENABLE_POLKIT
341         sender = sd_bus_message_get_sender(m);
342         if (!sender)
343                 return -EBADMSG;
344
345         r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
346         if (r < 0)
347                 return r;
348
349         r = sd_bus_message_new_method_call(
350                         bus,
351                         "org.freedesktop.PolicyKit1",
352                         "/org/freedesktop/PolicyKit1/Authority",
353                         "org.freedesktop.PolicyKit1.Authority",
354                         "CheckAuthorization",
355                         &pk);
356         if (r < 0)
357                 return r;
358
359         r = sd_bus_message_append(
360                         pk,
361                         "(sa{sv})sa{ss}us",
362                         "system-bus-name", 1, "name", "s", sender,
363                         action,
364                         0,
365                         interactive ? 1 : 0,
366                         NULL);
367         if (r < 0)
368                 return r;
369
370         q = new0(AsyncPolkitQuery, 1);
371         if (!q)
372                 return -ENOMEM;
373
374         q->request = sd_bus_message_ref(m);
375         q->callback = callback;
376         q->userdata = userdata;
377
378         r = hashmap_put(*registry, m, q);
379         if (r < 0) {
380                 async_polkit_query_free(bus, q);
381                 return r;
382         }
383
384         q->registry = *registry;
385
386         r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
387         if (r < 0) {
388                 async_polkit_query_free(bus, q);
389                 return r;
390         }
391
392         return 0;
393 #endif
394
395         return -EACCES;
396 }
397
398 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
399 #ifdef ENABLE_POLKIT
400         AsyncPolkitQuery *q;
401
402         while ((q = hashmap_steal_first(registry)))
403                 async_polkit_query_free(bus, q);
404
405         hashmap_free(registry);
406 #endif
407 }
408
409 int bus_check_peercred(sd_bus *c) {
410         struct ucred ucred;
411         socklen_t l;
412         int fd;
413
414         assert(c);
415
416         fd = sd_bus_get_fd(c);
417         if (fd < 0)
418                 return fd;
419
420         l = sizeof(struct ucred);
421         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
422                 return -errno;
423
424         if (l != sizeof(struct ucred))
425                 return -E2BIG;
426
427         if (ucred.uid != 0 && ucred.uid != geteuid())
428                 return -EPERM;
429
430         return 1;
431 }
432
433 int bus_open_system_systemd(sd_bus **_bus) {
434         _cleanup_bus_unref_ sd_bus *bus = NULL;
435         int r;
436
437         assert(_bus);
438
439         if (geteuid() != 0)
440                 return sd_bus_open_system(_bus);
441
442         /* If we are root and kdbus is not available, then let's talk
443          * directly to the system instance, instead of going via the
444          * bus */
445
446 #ifdef ENABLE_KDBUS
447         r = sd_bus_new(&bus);
448         if (r < 0)
449                 return r;
450
451         r = sd_bus_set_address(bus, "kernel:path=/dev/kdbus/0-system/bus");
452         if (r < 0)
453                 return r;
454
455         bus->bus_client = true;
456
457         r = sd_bus_start(bus);
458         if (r >= 0) {
459                 *_bus = bus;
460                 bus = NULL;
461                 return 0;
462         }
463
464         bus = sd_bus_unref(bus);
465 #endif
466
467         r = sd_bus_new(&bus);
468         if (r < 0)
469                 return r;
470
471         r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
472         if (r < 0)
473                 return r;
474
475         r = sd_bus_start(bus);
476         if (r < 0)
477                 return sd_bus_open_system(_bus);
478
479         r = bus_check_peercred(bus);
480         if (r < 0)
481                 return r;
482
483         *_bus = bus;
484         bus = NULL;
485
486         return 0;
487 }
488
489 int bus_open_user_systemd(sd_bus **_bus) {
490         _cleanup_bus_unref_ sd_bus *bus = NULL;
491         _cleanup_free_ char *ee = NULL;
492         const char *e;
493         int r;
494
495         /* Try via kdbus first, and then directly */
496
497         assert(_bus);
498
499 #ifdef ENABLE_KDBUS
500         r = sd_bus_new(&bus);
501         if (r < 0)
502                 return r;
503
504         if (asprintf(&bus->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid()) < 0)
505                 return -ENOMEM;
506
507         bus->bus_client = true;
508
509         r = sd_bus_start(bus);
510         if (r >= 0) {
511                 *_bus = bus;
512                 bus = NULL;
513                 return 0;
514         }
515
516         bus = sd_bus_unref(bus);
517 #endif
518
519         e = secure_getenv("XDG_RUNTIME_DIR");
520         if (!e)
521                 return sd_bus_open_system(_bus);
522
523         ee = bus_address_escape(e);
524         if (!ee)
525                 return -ENOMEM;
526
527         r = sd_bus_new(&bus);
528         if (r < 0)
529                 return r;
530
531         bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
532         if (!bus->address)
533                 return -ENOMEM;
534
535         r = sd_bus_start(bus);
536         if (r < 0)
537                 return sd_bus_open_system(_bus);
538
539         r = bus_check_peercred(bus);
540         if (r < 0)
541                 return r;
542
543         *_bus = bus;
544         bus = NULL;
545
546         return 0;
547 }
548
549 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
550         char type;
551         const char *contents;
552         int r;
553
554         assert(name);
555         assert(property);
556
557         r = sd_bus_message_peek_type(property, &type, &contents);
558         if (r < 0)
559                 return r;
560
561         switch (type) {
562
563         case SD_BUS_TYPE_STRING: {
564                 const char *s;
565
566                 r = sd_bus_message_read_basic(property, type, &s);
567                 if (r < 0)
568                         return r;
569
570                 if (all || !isempty(s))
571                         printf("%s=%s\n", name, s);
572
573                 return 1;
574         }
575
576         case SD_BUS_TYPE_BOOLEAN: {
577                 bool b;
578
579                 r = sd_bus_message_read_basic(property, type, &b);
580                 if (r < 0)
581                         return r;
582
583                 printf("%s=%s\n", name, yes_no(b));
584
585                 return 1;
586         }
587
588         case SD_BUS_TYPE_UINT64: {
589                 uint64_t u;
590
591                 r = sd_bus_message_read_basic(property, type, &u);
592                 if (r < 0)
593                         return r;
594
595                 /* Yes, heuristics! But we can change this check
596                  * should it turn out to not be sufficient */
597
598                 if (endswith(name, "Timestamp")) {
599                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
600
601                         t = format_timestamp(timestamp, sizeof(timestamp), u);
602                         if (t || all)
603                                 printf("%s=%s\n", name, strempty(t));
604
605                 } else if (strstr(name, "USec")) {
606                         char timespan[FORMAT_TIMESPAN_MAX];
607
608                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
609                 } else
610                         printf("%s=%llu\n", name, (unsigned long long) u);
611
612                 return 1;
613         }
614
615         case SD_BUS_TYPE_UINT32: {
616                 uint32_t u;
617
618                 r = sd_bus_message_read_basic(property, type, &u);
619                 if (r < 0)
620                         return r;
621
622                 if (strstr(name, "UMask") || strstr(name, "Mode"))
623                         printf("%s=%04o\n", name, u);
624                 else
625                         printf("%s=%u\n", name, (unsigned) u);
626
627                 return 1;
628         }
629
630         case SD_BUS_TYPE_INT32: {
631                 int32_t i;
632
633                 r = sd_bus_message_read_basic(property, type, &i);
634                 if (r < 0)
635                         return r;
636
637                 printf("%s=%i\n", name, (int) i);
638                 return 1;
639         }
640
641         case SD_BUS_TYPE_DOUBLE: {
642                 double d;
643
644                 r = sd_bus_message_read_basic(property, type, &d);
645                 if (r < 0)
646                         return r;
647
648                 printf("%s=%g\n", name, d);
649                 return 1;
650         }
651
652         case SD_BUS_TYPE_ARRAY:
653                 if (streq(contents, "s")) {
654                         bool first = true;
655                         const char *str;
656
657                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
658                         if (r < 0)
659                                 return r;
660
661                         while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
662                                 if (first)
663                                         printf("%s=", name);
664
665                                 printf("%s%s", first ? "" : " ", str);
666
667                                 first = false;
668                         }
669                         if (r < 0)
670                                 return r;
671
672                         if (first && all)
673                                 printf("%s=", name);
674                         if (!first || all)
675                                 puts("");
676
677                         r = sd_bus_message_exit_container(property);
678                         if (r < 0)
679                                 return r;
680
681                         return 1;
682
683                 } else if (streq(contents, "y")) {
684                         const uint8_t *u;
685                         size_t n;
686
687                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
688                         if (r < 0)
689                                 return r;
690
691                         if (all || n > 0) {
692                                 unsigned int i;
693
694                                 printf("%s=", name);
695
696                                 for (i = 0; i < n; i++)
697                                         printf("%02x", u[i]);
698
699                                 puts("");
700                         }
701
702                         return 1;
703
704                 } else if (streq(contents, "u")) {
705                         uint32_t *u;
706                         size_t n;
707
708                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
709                         if (r < 0)
710                                 return r;
711
712                         if (all || n > 0) {
713                                 unsigned int i;
714
715                                 printf("%s=", name);
716
717                                 for (i = 0; i < n; i++)
718                                         printf("%08x", u[i]);
719
720                                 puts("");
721                         }
722
723                         return 1;
724                 }
725
726                 break;
727         }
728
729         return 0;
730 }
731
732 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
733         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
734         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
735         int r;
736
737         assert(bus);
738         assert(path);
739
740         r = sd_bus_call_method(bus,
741                         dest,
742                         path,
743                         "org.freedesktop.DBus.Properties",
744                         "GetAll",
745                         &error,
746                         &reply,
747                         "s", "");
748         if (r < 0)
749                 return r;
750
751         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
752         if (r < 0)
753                 return r;
754
755         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
756                 const char *name;
757                 const char *contents;
758
759                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
760                 if (r < 0)
761                         return r;
762
763                 if (!filter || strv_find(filter, name)) {
764                         r = sd_bus_message_peek_type(reply, NULL, &contents);
765                         if (r < 0)
766                                 return r;
767
768                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
769                         if (r < 0)
770                                 return r;
771
772                         r = bus_print_property(name, reply, all);
773                         if (r < 0)
774                                 return r;
775                         if (r == 0) {
776                                 if (all)
777                                         printf("%s=[unprintable]\n", name);
778                                 /* skip what we didn't read */
779                                 r = sd_bus_message_skip(reply, contents);
780                                 if (r < 0)
781                                         return r;
782                         }
783
784                         r = sd_bus_message_exit_container(reply);
785                         if (r < 0)
786                                 return r;
787                 } else {
788                         r = sd_bus_message_skip(reply, "v");
789                         if (r < 0)
790                                 return r;
791                 }
792
793                 r = sd_bus_message_exit_container(reply);
794                 if (r < 0)
795                         return r;
796         }
797         if (r < 0)
798                 return r;
799
800         r = sd_bus_message_exit_container(reply);
801         if (r < 0)
802                 return r;
803
804         return 0;
805 }
806
807 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
808         sd_id128_t *p = userdata;
809         const void *v;
810         size_t n;
811         int r;
812
813         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
814         if (r < 0)
815                 return r;
816
817         if (n == 0)
818                 *p = SD_ID128_NULL;
819         else if (n == 16)
820                 memcpy((*p).bytes, v, n);
821         else
822                 return -EINVAL;
823
824         return 0;
825 }
826
827 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
828         char type;
829         int r;
830
831         r = sd_bus_message_peek_type(m, &type, NULL);
832         if (r < 0)
833                 return r;
834
835         switch (type) {
836         case SD_BUS_TYPE_STRING: {
837                 const char *s;
838                 char *str;
839                 char **p = userdata;
840
841                 r = sd_bus_message_read_basic(m, type, &s);
842                 if (r < 0)
843                         break;
844
845                 if (isempty(s))
846                         break;
847
848                 str = strdup(s);
849                 if (!str) {
850                         r = -ENOMEM;
851                         break;
852                 }
853                 free(*p);
854                 *p = str;
855
856                 break;
857         }
858
859         case SD_BUS_TYPE_ARRAY: {
860                _cleanup_strv_free_ char **l = NULL;
861                char ***p = userdata;
862
863                 r = bus_message_read_strv_extend(m, &l);
864                 if (r < 0)
865                         break;
866
867                 strv_free(*p);
868                 *p = l;
869                 l = NULL;
870
871                 break;
872         }
873
874         case SD_BUS_TYPE_BOOLEAN: {
875                 unsigned b;
876                 bool *p = userdata;
877
878                 r = sd_bus_message_read_basic(m, type, &b);
879                 if (r < 0)
880                         break;
881
882                 *p = b;
883
884                 break;
885         }
886
887         case SD_BUS_TYPE_UINT32: {
888                 uint64_t u;
889                 uint32_t *p = userdata;
890
891                 r = sd_bus_message_read_basic(m, type, &u);
892                 if (r < 0)
893                         break;
894
895                 *p = u;
896
897                 break;
898         }
899
900         case SD_BUS_TYPE_UINT64: {
901                 uint64_t t;
902                 uint64_t *p = userdata;
903
904                 r = sd_bus_message_read_basic(m, type, &t);
905                 if (r < 0)
906                         break;
907
908                 *p = t;
909
910                 break;
911         }
912
913         default:
914                 break;
915         }
916
917         return r;
918 }
919
920 int bus_map_all_properties(sd_bus *bus,
921                            const char *destination,
922                            const char *path,
923                            const struct bus_properties_map *map,
924                            void *userdata) {
925         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
926         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
927         int r;
928
929         assert(bus);
930         assert(destination);
931         assert(path);
932         assert(map);
933
934         r = sd_bus_call_method(
935                         bus,
936                         destination,
937                         path,
938                         "org.freedesktop.DBus.Properties",
939                         "GetAll",
940                         &error,
941                         &m,
942                         "s", "");
943         if (r < 0)
944                 return r;
945
946         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
947         if (r < 0)
948                 return r;
949
950         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
951                 const struct bus_properties_map *prop;
952                 const char *member;
953                 const char *contents;
954                 void *v;
955                 unsigned i;
956
957                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
958                 if (r < 0)
959                         return r;
960
961                 for (i = 0, prop = NULL; map[i].member; i++)
962                         if (streq(map[i].member, member)) {
963                                 prop = &map[i];
964                                 break;
965                         }
966
967                 if (prop) {
968                         r = sd_bus_message_peek_type(m, NULL, &contents);
969                         if (r < 0)
970                                 return r;
971
972                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
973                         if (r < 0)
974                                 return r;
975
976                         v = (uint8_t *)userdata + prop->offset;
977                         if (map[i].set)
978                                 r = prop->set(bus, member, m, &error, v);
979                         else
980                                 r = map_basic(bus, member, m, &error, v);
981
982                         r = sd_bus_message_exit_container(m);
983                         if (r < 0)
984                                 return r;
985                 } else {
986                         r = sd_bus_message_skip(m, "v");
987                         if (r < 0)
988                                 return r;
989                 }
990
991                 r = sd_bus_message_exit_container(m);
992                 if (r < 0)
993                         return r;
994         }
995
996         return r;
997 }
998
999 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1000         int r;
1001
1002         assert(transport >= 0);
1003         assert(transport < _BUS_TRANSPORT_MAX);
1004         assert(bus);
1005
1006         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1007         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1008
1009         switch (transport) {
1010
1011         case BUS_TRANSPORT_LOCAL:
1012                 if (user)
1013                         r = sd_bus_default_user(bus);
1014                 else
1015                         r = sd_bus_default_system(bus);
1016
1017                 break;
1018
1019         case BUS_TRANSPORT_REMOTE:
1020                 r = sd_bus_open_system_remote(host, bus);
1021                 break;
1022
1023         case BUS_TRANSPORT_CONTAINER:
1024                 r = sd_bus_open_system_container(host, bus);
1025                 break;
1026
1027         default:
1028                 assert_not_reached("Hmm, unknown transport type.");
1029         }
1030
1031         return r;
1032 }
1033
1034 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1035         int r;
1036
1037         assert(transport >= 0);
1038         assert(transport < _BUS_TRANSPORT_MAX);
1039         assert(bus);
1040
1041         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1042         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1043
1044         switch (transport) {
1045
1046         case BUS_TRANSPORT_LOCAL:
1047                 if (user)
1048                         r = bus_open_user_systemd(bus);
1049                 else
1050                         r = bus_open_system_systemd(bus);
1051
1052                 break;
1053
1054         case BUS_TRANSPORT_REMOTE:
1055                 r = sd_bus_open_system_remote(host, bus);
1056                 break;
1057
1058         case BUS_TRANSPORT_CONTAINER:
1059                 r = sd_bus_open_system_container(host, bus);
1060                 break;
1061
1062         default:
1063                 assert_not_reached("Hmm, unknown transport type.");
1064         }
1065
1066         return r;
1067 }
1068
1069 int bus_property_get_tristate(
1070                 sd_bus *bus,
1071                 const char *path,
1072                 const char *interface,
1073                 const char *property,
1074                 sd_bus_message *reply,
1075                 void *userdata,
1076                 sd_bus_error *error) {
1077
1078         int *tristate = userdata;
1079
1080         return sd_bus_message_append(reply, "b", *tristate > 0);
1081 }
1082
1083 int bus_property_get_bool(
1084                 sd_bus *bus,
1085                 const char *path,
1086                 const char *interface,
1087                 const char *property,
1088                 sd_bus_message *reply,
1089                 void *userdata,
1090                 sd_bus_error *error) {
1091
1092         int b = *(bool*) userdata;
1093
1094         return sd_bus_message_append_basic(reply, 'b', &b);
1095 }
1096
1097 #if __SIZEOF_SIZE_T__ != 8
1098 int bus_property_get_size(
1099                 sd_bus *bus,
1100                 const char *path,
1101                 const char *interface,
1102                 const char *property,
1103                 sd_bus_message *reply,
1104                 void *userdata,
1105                 sd_bus_error *error) {
1106
1107         uint64_t sz = *(size_t*) userdata;
1108
1109         return sd_bus_message_append_basic(reply, 't', &sz);
1110 }
1111 #endif
1112
1113 #if __SIZEOF_LONG__ != 8
1114 int bus_property_get_long(
1115                 sd_bus *bus,
1116                 const char *path,
1117                 const char *interface,
1118                 const char *property,
1119                 sd_bus_message *reply,
1120                 void *userdata,
1121                 sd_bus_error *error) {
1122
1123         int64_t l = *(long*) userdata;
1124
1125         return sd_bus_message_append_basic(reply, 'x', &l);
1126 }
1127
1128 int bus_property_get_ulong(
1129                 sd_bus *bus,
1130                 const char *path,
1131                 const char *interface,
1132                 const char *property,
1133                 sd_bus_message *reply,
1134                 void *userdata,
1135                 sd_bus_error *error) {
1136
1137         uint64_t ul = *(unsigned long*) userdata;
1138
1139         return sd_bus_message_append_basic(reply, 't', &ul);
1140 }
1141 #endif
1142
1143 int bus_log_parse_error(int r) {
1144         log_error("Failed to parse message: %s", strerror(-r));
1145         return r;
1146 }
1147
1148 int bus_log_create_error(int r) {
1149         log_error("Failed to create message: %s", strerror(-r));
1150         return r;
1151 }
1152
1153 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1154         assert(message);
1155         assert(u);
1156
1157         return sd_bus_message_read(
1158                         message,
1159                         "(ssssssouso)",
1160                         &u->id,
1161                         &u->description,
1162                         &u->load_state,
1163                         &u->active_state,
1164                         &u->sub_state,
1165                         &u->following,
1166                         &u->unit_path,
1167                         &u->job_id,
1168                         &u->job_type,
1169                         &u->job_path);
1170 }
1171
1172 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1173         assert(m);
1174
1175         if (r < 0) {
1176                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1177                         sd_bus_reply_method_errno(m, r, error);
1178
1179         } else if (sd_bus_error_is_set(error)) {
1180                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1181                         sd_bus_reply_method_error(m, error);
1182         } else
1183                 return r;
1184
1185         log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1186                   bus_message_type_to_string(m->header->type),
1187                   strna(m->sender),
1188                   strna(m->path),
1189                   strna(m->interface),
1190                   strna(m->member),
1191                   strna(m->root_container.signature),
1192                   bus_error_message(error, r));
1193
1194         return 1;
1195 }