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