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