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