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