chiark / gitweb /
bus: make sd_bus_request_name() and sd_bus_release_name() behave more like other...
[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 != SD_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, then let's talk directly to the system
443          * instance, instead of going via the bus */
444
445         r = sd_bus_new(&bus);
446         if (r < 0)
447                 return r;
448
449         r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
450         if (r < 0)
451                 return r;
452
453         r = sd_bus_start(bus);
454         if (r < 0)
455                 return r;
456
457         r = bus_check_peercred(bus);
458         if (r < 0)
459                 return r;
460
461         *_bus = bus;
462         bus = NULL;
463
464         return 0;
465 }
466
467 int bus_open_user_systemd(sd_bus **_bus) {
468         _cleanup_bus_unref_ sd_bus *bus = NULL;
469         _cleanup_free_ char *p = NULL;
470         const char *e;
471         int r;
472
473         /* If we are supposed to talk to the instance, try via
474          * XDG_RUNTIME_DIR first, then fallback to normal bus
475          * access */
476
477         assert(_bus);
478
479         e = secure_getenv("XDG_RUNTIME_DIR");
480         if (!e)
481                 return sd_bus_open_user(_bus);
482
483         if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
484                 return -ENOMEM;
485
486         r = sd_bus_new(&bus);
487         if (r < 0)
488                 return r;
489
490         r = sd_bus_set_address(bus, p);
491         if (r < 0)
492                 return r;
493
494         r = sd_bus_start(bus);
495         if (r < 0)
496                 return r;
497
498         r = bus_check_peercred(bus);
499         if (r < 0)
500                 return r;
501
502         *_bus = bus;
503         bus = NULL;
504
505         return 0;
506 }
507
508 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
509         char type;
510         const char *contents;
511         int r;
512
513         assert(name);
514         assert(property);
515
516         r = sd_bus_message_peek_type(property, &type, &contents);
517         if (r < 0)
518                 return r;
519
520         switch (type) {
521
522         case SD_BUS_TYPE_STRING: {
523                 const char *s;
524
525                 r = sd_bus_message_read_basic(property, type, &s);
526                 if (r < 0)
527                         return r;
528
529                 if (all || !isempty(s))
530                         printf("%s=%s\n", name, s);
531
532                 return 1;
533         }
534
535         case SD_BUS_TYPE_BOOLEAN: {
536                 bool b;
537
538                 r = sd_bus_message_read_basic(property, type, &b);
539                 if (r < 0)
540                         return r;
541
542                 printf("%s=%s\n", name, yes_no(b));
543
544                 return 1;
545         }
546
547         case SD_BUS_TYPE_UINT64: {
548                 uint64_t u;
549
550                 r = sd_bus_message_read_basic(property, type, &u);
551                 if (r < 0)
552                         return r;
553
554                 /* Yes, heuristics! But we can change this check
555                  * should it turn out to not be sufficient */
556
557                 if (endswith(name, "Timestamp")) {
558                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
559
560                         t = format_timestamp(timestamp, sizeof(timestamp), u);
561                         if (t || all)
562                                 printf("%s=%s\n", name, strempty(t));
563
564                 } else if (strstr(name, "USec")) {
565                         char timespan[FORMAT_TIMESPAN_MAX];
566
567                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
568                 } else
569                         printf("%s=%llu\n", name, (unsigned long long) u);
570
571                 return 1;
572         }
573
574         case SD_BUS_TYPE_UINT32: {
575                 uint32_t u;
576
577                 r = sd_bus_message_read_basic(property, type, &u);
578                 if (r < 0)
579                         return r;
580
581                 if (strstr(name, "UMask") || strstr(name, "Mode"))
582                         printf("%s=%04o\n", name, u);
583                 else
584                         printf("%s=%u\n", name, (unsigned) u);
585
586                 return 1;
587         }
588
589         case SD_BUS_TYPE_INT32: {
590                 int32_t i;
591
592                 r = sd_bus_message_read_basic(property, type, &i);
593                 if (r < 0)
594                         return r;
595
596                 printf("%s=%i\n", name, (int) i);
597                 return 1;
598         }
599
600         case SD_BUS_TYPE_DOUBLE: {
601                 double d;
602
603                 r = sd_bus_message_read_basic(property, type, &d);
604                 if (r < 0)
605                         return r;
606
607                 printf("%s=%g\n", name, d);
608                 return 1;
609         }
610
611         case SD_BUS_TYPE_ARRAY:
612                 if (streq(contents, "s")) {
613                         bool first = true;
614                         const char *str;
615
616                         r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
617                         if (r < 0)
618                                 return r;
619
620                         while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
621                                 if (first)
622                                         printf("%s=", name);
623
624                                 printf("%s%s", first ? "" : " ", str);
625
626                                 first = false;
627                         }
628                         if (r < 0)
629                                 return r;
630
631                         if (first && all)
632                                 printf("%s=", name);
633                         if (!first || all)
634                                 puts("");
635
636                         r = sd_bus_message_exit_container(property);
637                         if (r < 0)
638                                 return r;
639
640                         return 1;
641
642                 } else if (streq(contents, "y")) {
643                         const uint8_t *u;
644                         size_t n;
645
646                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
647                         if (r < 0)
648                                 return r;
649
650                         if (all || n > 0) {
651                                 unsigned int i;
652
653                                 printf("%s=", name);
654
655                                 for (i = 0; i < n; i++)
656                                         printf("%02x", u[i]);
657
658                                 puts("");
659                         }
660
661                         return 1;
662
663                 } else if (streq(contents, "u")) {
664                         uint32_t *u;
665                         size_t n;
666
667                         r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
668                         if (r < 0)
669                                 return r;
670
671                         if (all || n > 0) {
672                                 unsigned int i;
673
674                                 printf("%s=", name);
675
676                                 for (i = 0; i < n; i++)
677                                         printf("%08x", u[i]);
678
679                                 puts("");
680                         }
681
682                         return 1;
683                 }
684
685                 break;
686         }
687
688         return 0;
689 }
690
691 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
692         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
693         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
694         int r;
695
696         assert(bus);
697         assert(path);
698
699         r = sd_bus_call_method(bus,
700                         dest,
701                         path,
702                         "org.freedesktop.DBus.Properties",
703                         "GetAll",
704                         &error,
705                         &reply,
706                         "s", "");
707         if (r < 0)
708                 return r;
709
710         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
711         if (r < 0)
712                 return r;
713
714         while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
715                 const char *name;
716                 const char *contents;
717
718                 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
719                 if (r < 0)
720                         return r;
721
722                 if (!filter || strv_find(filter, name)) {
723                         r = sd_bus_message_peek_type(reply, NULL, &contents);
724                         if (r < 0)
725                                 return r;
726
727                         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
728                         if (r < 0)
729                                 return r;
730
731                         r = bus_print_property(name, reply, all);
732                         if (r < 0)
733                                 return r;
734                         if (r == 0) {
735                                 if (all)
736                                         printf("%s=[unprintable]\n", name);
737                                 /* skip what we didn't read */
738                                 r = sd_bus_message_skip(reply, contents);
739                                 if (r < 0)
740                                         return r;
741                         }
742
743                         r = sd_bus_message_exit_container(reply);
744                         if (r < 0)
745                                 return r;
746                 } else {
747                         r = sd_bus_message_skip(reply, "v");
748                         if (r < 0)
749                                 return r;
750                 }
751
752                 r = sd_bus_message_exit_container(reply);
753                 if (r < 0)
754                         return r;
755         }
756         if (r < 0)
757                 return r;
758
759         r = sd_bus_message_exit_container(reply);
760         if (r < 0)
761                 return r;
762
763         return 0;
764 }
765
766 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
767         sd_id128_t *p = userdata;
768         const void *v;
769         size_t n;
770         int r;
771
772         r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
773         if (r < 0)
774                 return r;
775
776         if (n == 0)
777                 *p = SD_ID128_NULL;
778         else if (n == 16)
779                 memcpy((*p).bytes, v, n);
780         else
781                 return -EINVAL;
782
783         return 0;
784 }
785
786 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
787         char type;
788         int r;
789
790         r = sd_bus_message_peek_type(m, &type, NULL);
791         if (r < 0)
792                 return r;
793
794         switch (type) {
795         case SD_BUS_TYPE_STRING: {
796                 const char *s;
797                 char *str;
798                 char **p = userdata;
799
800                 r = sd_bus_message_read_basic(m, type, &s);
801                 if (r < 0)
802                         break;
803
804                 if (isempty(s))
805                         break;
806
807                 str = strdup(s);
808                 if (!str) {
809                         r = -ENOMEM;
810                         break;
811                 }
812                 free(*p);
813                 *p = str;
814
815                 break;
816         }
817
818         case SD_BUS_TYPE_ARRAY: {
819                _cleanup_strv_free_ char **l = NULL;
820                char ***p = userdata;
821
822                 r = bus_message_read_strv_extend(m, &l);
823                 if (r < 0)
824                         break;
825
826                 strv_free(*p);
827                 *p = l;
828                 l = NULL;
829
830                 break;
831         }
832
833         case SD_BUS_TYPE_BOOLEAN: {
834                 unsigned b;
835                 bool *p = userdata;
836
837                 r = sd_bus_message_read_basic(m, type, &b);
838                 if (r < 0)
839                         break;
840
841                 *p = b;
842
843                 break;
844         }
845
846         case SD_BUS_TYPE_UINT32: {
847                 uint64_t u;
848                 uint32_t *p = userdata;
849
850                 r = sd_bus_message_read_basic(m, type, &u);
851                 if (r < 0)
852                         break;
853
854                 *p = u;
855
856                 break;
857         }
858
859         case SD_BUS_TYPE_UINT64: {
860                 uint64_t t;
861                 uint64_t *p = userdata;
862
863                 r = sd_bus_message_read_basic(m, type, &t);
864                 if (r < 0)
865                         break;
866
867                 *p = t;
868
869                 break;
870         }
871
872         default:
873                 break;
874         }
875
876         return r;
877 }
878
879 int bus_map_all_properties(sd_bus *bus,
880                            const char *destination,
881                            const char *path,
882                            const struct bus_properties_map *map,
883                            void *userdata) {
884         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
885         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
886         int r;
887
888         assert(bus);
889         assert(destination);
890         assert(path);
891         assert(map);
892
893         r = sd_bus_call_method( bus,
894                         destination,
895                         path,
896                         "org.freedesktop.DBus.Properties",
897                         "GetAll",
898                         &error,
899                         &m,
900                         "s", "");
901         if (r < 0)
902                 return r;
903
904         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
905         if (r < 0)
906                 return r;
907
908         while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
909                 const struct bus_properties_map *prop;
910                 const char *member;
911                 const char *contents;
912                 void *v;
913                 unsigned i;
914
915                 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
916                 if (r < 0)
917                         return r;
918
919                 for (i = 0, prop = NULL; map[i].member; i++)
920                         if (streq(map[i].member, member)) {
921                                 prop = &map[i];
922                                 break;
923                         }
924
925                 if (prop) {
926                         r = sd_bus_message_peek_type(m, NULL, &contents);
927                         if (r < 0)
928                                 return r;
929
930                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
931                         if (r < 0)
932                                 return r;
933
934                         v = (uint8_t *)userdata + prop->offset;
935                         if (map[i].set)
936                                 r = prop->set(bus, member, m, &error, v);
937                         else
938                                 r = map_basic(bus, member, m, &error, v);
939
940                         r = sd_bus_message_exit_container(m);
941                         if (r < 0)
942                                 return r;
943                 } else {
944                         r = sd_bus_message_skip(m, "v");
945                         if (r < 0)
946                                 return r;
947                 }
948
949                 r = sd_bus_message_exit_container(m);
950                 if (r < 0)
951                         return r;
952         }
953
954         return r;
955 }
956
957 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
958         int r;
959
960         assert(transport >= 0);
961         assert(transport < _BUS_TRANSPORT_MAX);
962         assert(bus);
963
964         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
965         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
966
967         switch (transport) {
968
969         case BUS_TRANSPORT_LOCAL:
970                 if (user)
971                         r = sd_bus_default_user(bus);
972                 else
973                         r = sd_bus_default_system(bus);
974
975                 break;
976
977         case BUS_TRANSPORT_REMOTE:
978                 r = sd_bus_open_system_remote(host, bus);
979                 break;
980
981         case BUS_TRANSPORT_CONTAINER:
982                 r = sd_bus_open_system_container(host, bus);
983                 break;
984
985         default:
986                 assert_not_reached("Hmm, unknown transport type.");
987         }
988
989         return r;
990 }
991
992 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
993         int r;
994
995         assert(transport >= 0);
996         assert(transport < _BUS_TRANSPORT_MAX);
997         assert(bus);
998
999         assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1000         assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1001
1002         switch (transport) {
1003
1004         case BUS_TRANSPORT_LOCAL:
1005                 if (user)
1006                         r = bus_open_user_systemd(bus);
1007                 else
1008                         r = bus_open_system_systemd(bus);
1009
1010                 break;
1011
1012         case BUS_TRANSPORT_REMOTE:
1013                 r = sd_bus_open_system_remote(host, bus);
1014                 break;
1015
1016         case BUS_TRANSPORT_CONTAINER:
1017                 r = sd_bus_open_system_container(host, bus);
1018                 break;
1019
1020         default:
1021                 assert_not_reached("Hmm, unknown transport type.");
1022         }
1023
1024         return r;
1025 }
1026
1027 int bus_property_get_tristate(
1028                 sd_bus *bus,
1029                 const char *path,
1030                 const char *interface,
1031                 const char *property,
1032                 sd_bus_message *reply,
1033                 void *userdata,
1034                 sd_bus_error *error) {
1035
1036         int *tristate = userdata;
1037
1038         return sd_bus_message_append(reply, "b", *tristate > 0);
1039 }
1040
1041 int bus_property_get_bool(
1042                 sd_bus *bus,
1043                 const char *path,
1044                 const char *interface,
1045                 const char *property,
1046                 sd_bus_message *reply,
1047                 void *userdata,
1048                 sd_bus_error *error) {
1049
1050         int b = *(bool*) userdata;
1051
1052         return sd_bus_message_append_basic(reply, 'b', &b);
1053 }
1054
1055 #if __SIZEOF_SIZE_T__ != 8
1056 int bus_property_get_size(
1057                 sd_bus *bus,
1058                 const char *path,
1059                 const char *interface,
1060                 const char *property,
1061                 sd_bus_message *reply,
1062                 void *userdata,
1063                 sd_bus_error *error) {
1064
1065         uint64_t sz = *(size_t*) userdata;
1066
1067         return sd_bus_message_append_basic(reply, 't', &sz);
1068 }
1069 #endif
1070
1071 #if __SIZEOF_LONG__ != 8
1072 int bus_property_get_long(
1073                 sd_bus *bus,
1074                 const char *path,
1075                 const char *interface,
1076                 const char *property,
1077                 sd_bus_message *reply,
1078                 void *userdata,
1079                 sd_bus_error *error) {
1080
1081         int64_t l = *(long*) userdata;
1082
1083         return sd_bus_message_append_basic(reply, 'x', &l);
1084 }
1085
1086 int bus_property_get_ulong(
1087                 sd_bus *bus,
1088                 const char *path,
1089                 const char *interface,
1090                 const char *property,
1091                 sd_bus_message *reply,
1092                 void *userdata,
1093                 sd_bus_error *error) {
1094
1095         uint64_t ul = *(unsigned long*) userdata;
1096
1097         return sd_bus_message_append_basic(reply, 't', &ul);
1098 }
1099 #endif
1100
1101 int bus_log_parse_error(int r) {
1102         log_error("Failed to parse message: %s", strerror(-r));
1103         return r;
1104 }
1105
1106 int bus_log_create_error(int r) {
1107         log_error("Failed to create message: %s", strerror(-r));
1108         return r;
1109 }
1110
1111 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1112         assert(message);
1113         assert(u);
1114
1115         return sd_bus_message_read(
1116                         message,
1117                         "(ssssssouso)",
1118                         &u->id,
1119                         &u->description,
1120                         &u->load_state,
1121                         &u->active_state,
1122                         &u->sub_state,
1123                         &u->following,
1124                         &u->unit_path,
1125                         &u->job_id,
1126                         &u->job_type,
1127                         &u->job_path);
1128 }
1129
1130 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1131         assert(m);
1132
1133         if (r < 0) {
1134                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1135                         sd_bus_reply_method_errno(m, r, error);
1136
1137         } else if (sd_bus_error_is_set(error)) {
1138                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1139                         sd_bus_reply_method_error(m, error);
1140         } else
1141                 return r;
1142
1143         log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1144                   bus_message_type_to_string(m->header->type),
1145                   strna(m->sender),
1146                   strna(m->path),
1147                   strna(m->interface),
1148                   strna(m->member),
1149                   strna(m->root_container.signature),
1150                   bus_error_message(error, r));
1151
1152         return 1;
1153 }