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