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