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