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