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