]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-util.c
treewide: no need to negate errno for log_*_errno()
[thirdparty/systemd.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, c;
216 const char *sender;
217
218 sender = sd_bus_message_get_sender(call);
219 if (!sender)
220 return -EBADMSG;
221
222 c = sd_bus_message_get_allow_interactive_authorization(call);
223 if (c < 0)
224 return c;
225 if (c > 0)
226 interactive = true;
227
228 r = sd_bus_call_method(
229 call->bus,
230 "org.freedesktop.PolicyKit1",
231 "/org/freedesktop/PolicyKit1/Authority",
232 "org.freedesktop.PolicyKit1.Authority",
233 "CheckAuthorization",
234 e,
235 &reply,
236 "(sa{sv})sa{ss}us",
237 "system-bus-name", 1, "name", "s", sender,
238 action,
239 0,
240 !!interactive,
241 "");
242
243 if (r < 0) {
244 /* Treat no PK available as access denied */
245 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
246 sd_bus_error_free(e);
247 return -EACCES;
248 }
249
250 return r;
251 }
252
253 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
254 if (r < 0)
255 return r;
256
257 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
258 if (r < 0)
259 return r;
260
261 if (authorized)
262 return 1;
263
264 if (_challenge) {
265 *_challenge = challenge;
266 return 0;
267 }
268 }
269 #endif
270
271 return -EACCES;
272 }
273
274 #ifdef ENABLE_POLKIT
275
276 typedef struct AsyncPolkitQuery {
277 sd_bus_message *request, *reply;
278 sd_bus_message_handler_t callback;
279 void *userdata;
280 sd_bus_slot *slot;
281 Hashmap *registry;
282 } AsyncPolkitQuery;
283
284 static void async_polkit_query_free(AsyncPolkitQuery *q) {
285
286 if (!q)
287 return;
288
289 sd_bus_slot_unref(q->slot);
290
291 if (q->registry && q->request)
292 hashmap_remove(q->registry, q->request);
293
294 sd_bus_message_unref(q->request);
295 sd_bus_message_unref(q->reply);
296
297 free(q);
298 }
299
300 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
301 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
302 AsyncPolkitQuery *q = userdata;
303 int r;
304
305 assert(bus);
306 assert(reply);
307 assert(q);
308
309 q->slot = sd_bus_slot_unref(q->slot);
310 q->reply = sd_bus_message_ref(reply);
311
312 r = sd_bus_message_rewind(q->request, true);
313 if (r < 0) {
314 r = sd_bus_reply_method_errno(q->request, r, NULL);
315 goto finish;
316 }
317
318 r = q->callback(bus, q->request, q->userdata, &error_buffer);
319 r = bus_maybe_reply_error(q->request, r, &error_buffer);
320
321 finish:
322 async_polkit_query_free(q);
323
324 return r;
325 }
326
327 #endif
328
329 int bus_verify_polkit_async(
330 sd_bus_message *call,
331 int capability,
332 const char *action,
333 bool interactive,
334 Hashmap **registry,
335 sd_bus_error *error) {
336
337 #ifdef ENABLE_POLKIT
338 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
339 AsyncPolkitQuery *q;
340 const char *sender;
341 sd_bus_message_handler_t callback;
342 void *userdata;
343 int c;
344 #endif
345 int r;
346
347 assert(call);
348 assert(action);
349 assert(registry);
350
351 #ifdef ENABLE_POLKIT
352 q = hashmap_get(*registry, call);
353 if (q) {
354 int authorized, challenge;
355
356 /* This is the second invocation of this function, and
357 * there's already a response from polkit, let's
358 * process it */
359 assert(q->reply);
360
361 if (sd_bus_message_is_method_error(q->reply, NULL)) {
362 const sd_bus_error *e;
363
364 /* Copy error from polkit reply */
365 e = sd_bus_message_get_error(q->reply);
366 sd_bus_error_copy(error, e);
367
368 /* Treat no PK available as access denied */
369 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
370 return -EACCES;
371
372 return -sd_bus_error_get_errno(e);
373 }
374
375 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
376 if (r >= 0)
377 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
378
379 if (r < 0)
380 return r;
381
382 if (authorized)
383 return 1;
384
385 if (challenge)
386 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
387
388 return -EACCES;
389 }
390 #endif
391
392 r = sd_bus_query_sender_privilege(call, capability);
393 if (r < 0)
394 return r;
395 else if (r > 0)
396 return 1;
397
398 #ifdef ENABLE_POLKIT
399 if (sd_bus_get_current_message(call->bus) != call)
400 return -EINVAL;
401
402 callback = sd_bus_get_current_handler(call->bus);
403 if (!callback)
404 return -EINVAL;
405
406 userdata = sd_bus_get_current_userdata(call->bus);
407
408 sender = sd_bus_message_get_sender(call);
409 if (!sender)
410 return -EBADMSG;
411
412 c = sd_bus_message_get_allow_interactive_authorization(call);
413 if (c < 0)
414 return c;
415 if (c > 0)
416 interactive = true;
417
418 r = hashmap_ensure_allocated(registry, NULL);
419 if (r < 0)
420 return r;
421
422 r = sd_bus_message_new_method_call(
423 call->bus,
424 &pk,
425 "org.freedesktop.PolicyKit1",
426 "/org/freedesktop/PolicyKit1/Authority",
427 "org.freedesktop.PolicyKit1.Authority",
428 "CheckAuthorization");
429 if (r < 0)
430 return r;
431
432 r = sd_bus_message_append(
433 pk,
434 "(sa{sv})sa{ss}us",
435 "system-bus-name", 1, "name", "s", sender,
436 action,
437 0,
438 !!interactive,
439 NULL);
440 if (r < 0)
441 return r;
442
443 q = new0(AsyncPolkitQuery, 1);
444 if (!q)
445 return -ENOMEM;
446
447 q->request = sd_bus_message_ref(call);
448 q->callback = callback;
449 q->userdata = userdata;
450
451 r = hashmap_put(*registry, call, q);
452 if (r < 0) {
453 async_polkit_query_free(q);
454 return r;
455 }
456
457 q->registry = *registry;
458
459 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
460 if (r < 0) {
461 async_polkit_query_free(q);
462 return r;
463 }
464
465 return 0;
466 #endif
467
468 return -EACCES;
469 }
470
471 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
472 #ifdef ENABLE_POLKIT
473 AsyncPolkitQuery *q;
474
475 while ((q = hashmap_steal_first(registry)))
476 async_polkit_query_free(q);
477
478 hashmap_free(registry);
479 #endif
480 }
481
482 int bus_check_peercred(sd_bus *c) {
483 struct ucred ucred;
484 socklen_t l;
485 int fd;
486
487 assert(c);
488
489 fd = sd_bus_get_fd(c);
490 if (fd < 0)
491 return fd;
492
493 l = sizeof(struct ucred);
494 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
495 return -errno;
496
497 if (l != sizeof(struct ucred))
498 return -E2BIG;
499
500 if (ucred.uid != 0 && ucred.uid != geteuid())
501 return -EPERM;
502
503 return 1;
504 }
505
506 int bus_open_system_systemd(sd_bus **_bus) {
507 _cleanup_bus_unref_ sd_bus *bus = NULL;
508 int r;
509
510 assert(_bus);
511
512 if (geteuid() != 0)
513 return sd_bus_open_system(_bus);
514
515 /* If we are root and kdbus is not available, then let's talk
516 * directly to the system instance, instead of going via the
517 * bus */
518
519 #ifdef ENABLE_KDBUS
520 r = sd_bus_new(&bus);
521 if (r < 0)
522 return r;
523
524 r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH);
525 if (r < 0)
526 return r;
527
528 bus->bus_client = true;
529
530 r = sd_bus_start(bus);
531 if (r >= 0) {
532 *_bus = bus;
533 bus = NULL;
534 return 0;
535 }
536
537 bus = sd_bus_unref(bus);
538 #endif
539
540 r = sd_bus_new(&bus);
541 if (r < 0)
542 return r;
543
544 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
545 if (r < 0)
546 return r;
547
548 r = sd_bus_start(bus);
549 if (r < 0)
550 return sd_bus_open_system(_bus);
551
552 r = bus_check_peercred(bus);
553 if (r < 0)
554 return r;
555
556 *_bus = bus;
557 bus = NULL;
558
559 return 0;
560 }
561
562 int bus_open_user_systemd(sd_bus **_bus) {
563 _cleanup_bus_unref_ sd_bus *bus = NULL;
564 _cleanup_free_ char *ee = NULL;
565 const char *e;
566 int r;
567
568 /* Try via kdbus first, and then directly */
569
570 assert(_bus);
571
572 #ifdef ENABLE_KDBUS
573 r = sd_bus_new(&bus);
574 if (r < 0)
575 return r;
576
577 if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, getuid()) < 0)
578 return -ENOMEM;
579
580 bus->bus_client = true;
581
582 r = sd_bus_start(bus);
583 if (r >= 0) {
584 *_bus = bus;
585 bus = NULL;
586 return 0;
587 }
588
589 bus = sd_bus_unref(bus);
590 #endif
591
592 e = secure_getenv("XDG_RUNTIME_DIR");
593 if (!e)
594 return sd_bus_open_user(_bus);
595
596 ee = bus_address_escape(e);
597 if (!ee)
598 return -ENOMEM;
599
600 r = sd_bus_new(&bus);
601 if (r < 0)
602 return r;
603
604 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
605 if (!bus->address)
606 return -ENOMEM;
607
608 r = sd_bus_start(bus);
609 if (r < 0)
610 return sd_bus_open_user(_bus);
611
612 r = bus_check_peercred(bus);
613 if (r < 0)
614 return r;
615
616 *_bus = bus;
617 bus = NULL;
618
619 return 0;
620 }
621
622 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
623 char type;
624 const char *contents;
625 int r;
626
627 assert(name);
628 assert(property);
629
630 r = sd_bus_message_peek_type(property, &type, &contents);
631 if (r < 0)
632 return r;
633
634 switch (type) {
635
636 case SD_BUS_TYPE_STRING: {
637 const char *s;
638
639 r = sd_bus_message_read_basic(property, type, &s);
640 if (r < 0)
641 return r;
642
643 if (all || !isempty(s)) {
644 _cleanup_free_ char *escaped = NULL;
645
646 escaped = xescape(s, "\n");
647 if (!escaped)
648 return -ENOMEM;
649
650 printf("%s=%s\n", name, escaped);
651 }
652
653 return 1;
654 }
655
656 case SD_BUS_TYPE_BOOLEAN: {
657 int b;
658
659 r = sd_bus_message_read_basic(property, type, &b);
660 if (r < 0)
661 return r;
662
663 printf("%s=%s\n", name, yes_no(b));
664
665 return 1;
666 }
667
668 case SD_BUS_TYPE_UINT64: {
669 uint64_t u;
670
671 r = sd_bus_message_read_basic(property, type, &u);
672 if (r < 0)
673 return r;
674
675 /* Yes, heuristics! But we can change this check
676 * should it turn out to not be sufficient */
677
678 if (endswith(name, "Timestamp")) {
679 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
680
681 t = format_timestamp(timestamp, sizeof(timestamp), u);
682 if (t || all)
683 printf("%s=%s\n", name, strempty(t));
684
685 } else if (strstr(name, "USec")) {
686 char timespan[FORMAT_TIMESPAN_MAX];
687
688 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
689 } else
690 printf("%s=%llu\n", name, (unsigned long long) u);
691
692 return 1;
693 }
694
695 case SD_BUS_TYPE_UINT32: {
696 uint32_t u;
697
698 r = sd_bus_message_read_basic(property, type, &u);
699 if (r < 0)
700 return r;
701
702 if (strstr(name, "UMask") || strstr(name, "Mode"))
703 printf("%s=%04o\n", name, u);
704 else
705 printf("%s=%u\n", name, (unsigned) u);
706
707 return 1;
708 }
709
710 case SD_BUS_TYPE_INT32: {
711 int32_t i;
712
713 r = sd_bus_message_read_basic(property, type, &i);
714 if (r < 0)
715 return r;
716
717 printf("%s=%i\n", name, (int) i);
718 return 1;
719 }
720
721 case SD_BUS_TYPE_DOUBLE: {
722 double d;
723
724 r = sd_bus_message_read_basic(property, type, &d);
725 if (r < 0)
726 return r;
727
728 printf("%s=%g\n", name, d);
729 return 1;
730 }
731
732 case SD_BUS_TYPE_ARRAY:
733 if (streq(contents, "s")) {
734 bool first = true;
735 const char *str;
736
737 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
738 if (r < 0)
739 return r;
740
741 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
742 _cleanup_free_ char *escaped = NULL;
743
744 if (first)
745 printf("%s=", name);
746
747 escaped = xescape(str, "\n ");
748 if (!escaped)
749 return -ENOMEM;
750
751 printf("%s%s", first ? "" : " ", escaped);
752
753 first = false;
754 }
755 if (r < 0)
756 return r;
757
758 if (first && all)
759 printf("%s=", name);
760 if (!first || all)
761 puts("");
762
763 r = sd_bus_message_exit_container(property);
764 if (r < 0)
765 return r;
766
767 return 1;
768
769 } else if (streq(contents, "y")) {
770 const uint8_t *u;
771 size_t n;
772
773 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
774 if (r < 0)
775 return r;
776
777 if (all || n > 0) {
778 unsigned int i;
779
780 printf("%s=", name);
781
782 for (i = 0; i < n; i++)
783 printf("%02x", u[i]);
784
785 puts("");
786 }
787
788 return 1;
789
790 } else if (streq(contents, "u")) {
791 uint32_t *u;
792 size_t n;
793
794 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
795 if (r < 0)
796 return r;
797
798 if (all || n > 0) {
799 unsigned int i;
800
801 printf("%s=", name);
802
803 for (i = 0; i < n; i++)
804 printf("%08x", u[i]);
805
806 puts("");
807 }
808
809 return 1;
810 }
811
812 break;
813 }
814
815 return 0;
816 }
817
818 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
819 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
820 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
821 int r;
822
823 assert(bus);
824 assert(path);
825
826 r = sd_bus_call_method(bus,
827 dest,
828 path,
829 "org.freedesktop.DBus.Properties",
830 "GetAll",
831 &error,
832 &reply,
833 "s", "");
834 if (r < 0)
835 return r;
836
837 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
838 if (r < 0)
839 return r;
840
841 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
842 const char *name;
843 const char *contents;
844
845 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
846 if (r < 0)
847 return r;
848
849 if (!filter || strv_find(filter, name)) {
850 r = sd_bus_message_peek_type(reply, NULL, &contents);
851 if (r < 0)
852 return r;
853
854 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
855 if (r < 0)
856 return r;
857
858 r = bus_print_property(name, reply, all);
859 if (r < 0)
860 return r;
861 if (r == 0) {
862 if (all)
863 printf("%s=[unprintable]\n", name);
864 /* skip what we didn't read */
865 r = sd_bus_message_skip(reply, contents);
866 if (r < 0)
867 return r;
868 }
869
870 r = sd_bus_message_exit_container(reply);
871 if (r < 0)
872 return r;
873 } else {
874 r = sd_bus_message_skip(reply, "v");
875 if (r < 0)
876 return r;
877 }
878
879 r = sd_bus_message_exit_container(reply);
880 if (r < 0)
881 return r;
882 }
883 if (r < 0)
884 return r;
885
886 r = sd_bus_message_exit_container(reply);
887 if (r < 0)
888 return r;
889
890 return 0;
891 }
892
893 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
894 sd_id128_t *p = userdata;
895 const void *v;
896 size_t n;
897 int r;
898
899 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
900 if (r < 0)
901 return r;
902
903 if (n == 0)
904 *p = SD_ID128_NULL;
905 else if (n == 16)
906 memcpy((*p).bytes, v, n);
907 else
908 return -EINVAL;
909
910 return 0;
911 }
912
913 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
914 char type;
915 int r;
916
917 r = sd_bus_message_peek_type(m, &type, NULL);
918 if (r < 0)
919 return r;
920
921 switch (type) {
922 case SD_BUS_TYPE_STRING: {
923 const char *s;
924 char *str;
925 char **p = userdata;
926
927 r = sd_bus_message_read_basic(m, type, &s);
928 if (r < 0)
929 break;
930
931 if (isempty(s))
932 break;
933
934 str = strdup(s);
935 if (!str) {
936 r = -ENOMEM;
937 break;
938 }
939 free(*p);
940 *p = str;
941
942 break;
943 }
944
945 case SD_BUS_TYPE_ARRAY: {
946 _cleanup_strv_free_ char **l = NULL;
947 char ***p = userdata;
948
949 r = bus_message_read_strv_extend(m, &l);
950 if (r < 0)
951 break;
952
953 strv_free(*p);
954 *p = l;
955 l = NULL;
956
957 break;
958 }
959
960 case SD_BUS_TYPE_BOOLEAN: {
961 unsigned b;
962 bool *p = userdata;
963
964 r = sd_bus_message_read_basic(m, type, &b);
965 if (r < 0)
966 break;
967
968 *p = b;
969
970 break;
971 }
972
973 case SD_BUS_TYPE_UINT32: {
974 uint64_t u;
975 uint32_t *p = userdata;
976
977 r = sd_bus_message_read_basic(m, type, &u);
978 if (r < 0)
979 break;
980
981 *p = u;
982
983 break;
984 }
985
986 case SD_BUS_TYPE_UINT64: {
987 uint64_t t;
988 uint64_t *p = userdata;
989
990 r = sd_bus_message_read_basic(m, type, &t);
991 if (r < 0)
992 break;
993
994 *p = t;
995
996 break;
997 }
998
999 default:
1000 break;
1001 }
1002
1003 return r;
1004 }
1005
1006 int bus_message_map_all_properties(sd_bus *bus,
1007 sd_bus_message *m,
1008 const struct bus_properties_map *map,
1009 void *userdata) {
1010 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1011 int r;
1012
1013 assert(bus);
1014 assert(m);
1015 assert(map);
1016
1017 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1018 if (r < 0)
1019 return r;
1020
1021 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1022 const struct bus_properties_map *prop;
1023 const char *member;
1024 const char *contents;
1025 void *v;
1026 unsigned i;
1027
1028 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1029 if (r < 0)
1030 return r;
1031
1032 for (i = 0, prop = NULL; map[i].member; i++)
1033 if (streq(map[i].member, member)) {
1034 prop = &map[i];
1035 break;
1036 }
1037
1038 if (prop) {
1039 r = sd_bus_message_peek_type(m, NULL, &contents);
1040 if (r < 0)
1041 return r;
1042
1043 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1044 if (r < 0)
1045 return r;
1046
1047 v = (uint8_t *)userdata + prop->offset;
1048 if (map[i].set)
1049 r = prop->set(bus, member, m, &error, v);
1050 else
1051 r = map_basic(bus, member, m, &error, v);
1052 if (r < 0)
1053 return r;
1054
1055 r = sd_bus_message_exit_container(m);
1056 if (r < 0)
1057 return r;
1058 } else {
1059 r = sd_bus_message_skip(m, "v");
1060 if (r < 0)
1061 return r;
1062 }
1063
1064 r = sd_bus_message_exit_container(m);
1065 if (r < 0)
1066 return r;
1067 }
1068
1069 return sd_bus_message_exit_container(m);
1070 }
1071
1072 int bus_message_map_properties_changed(sd_bus *bus,
1073 sd_bus_message *m,
1074 const struct bus_properties_map *map,
1075 void *userdata) {
1076 const char *member;
1077 int r, invalidated, i;
1078
1079 assert(bus);
1080 assert(m);
1081 assert(map);
1082
1083 r = bus_message_map_all_properties(bus, m, map, userdata);
1084 if (r < 0)
1085 return r;
1086
1087 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1088 if (r < 0)
1089 return r;
1090
1091 invalidated = 0;
1092 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1093 for (i = 0; map[i].member; i++)
1094 if (streq(map[i].member, member)) {
1095 ++invalidated;
1096 break;
1097 }
1098
1099 r = sd_bus_message_exit_container(m);
1100 if (r < 0)
1101 return r;
1102
1103 return invalidated;
1104 }
1105
1106 int bus_map_all_properties(sd_bus *bus,
1107 const char *destination,
1108 const char *path,
1109 const struct bus_properties_map *map,
1110 void *userdata) {
1111 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1112 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1113 int r;
1114
1115 assert(bus);
1116 assert(destination);
1117 assert(path);
1118 assert(map);
1119
1120 r = sd_bus_call_method(
1121 bus,
1122 destination,
1123 path,
1124 "org.freedesktop.DBus.Properties",
1125 "GetAll",
1126 &error,
1127 &m,
1128 "s", "");
1129 if (r < 0)
1130 return r;
1131
1132 return bus_message_map_all_properties(bus, m, map, userdata);
1133 }
1134
1135 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1136 int r;
1137
1138 assert(transport >= 0);
1139 assert(transport < _BUS_TRANSPORT_MAX);
1140 assert(bus);
1141
1142 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1143 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1144
1145 switch (transport) {
1146
1147 case BUS_TRANSPORT_LOCAL:
1148 if (user)
1149 r = sd_bus_default_user(bus);
1150 else
1151 r = sd_bus_default_system(bus);
1152
1153 break;
1154
1155 case BUS_TRANSPORT_REMOTE:
1156 r = sd_bus_open_system_remote(bus, host);
1157 break;
1158
1159 case BUS_TRANSPORT_CONTAINER:
1160 r = sd_bus_open_system_container(bus, host);
1161 break;
1162
1163 default:
1164 assert_not_reached("Hmm, unknown transport type.");
1165 }
1166
1167 return r;
1168 }
1169
1170 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1171 int r;
1172
1173 assert(transport >= 0);
1174 assert(transport < _BUS_TRANSPORT_MAX);
1175 assert(bus);
1176
1177 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1178 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1179
1180 switch (transport) {
1181
1182 case BUS_TRANSPORT_LOCAL:
1183 if (user)
1184 r = bus_open_user_systemd(bus);
1185 else
1186 r = bus_open_system_systemd(bus);
1187
1188 break;
1189
1190 case BUS_TRANSPORT_REMOTE:
1191 r = sd_bus_open_system_remote(bus, host);
1192 break;
1193
1194 case BUS_TRANSPORT_CONTAINER:
1195 r = sd_bus_open_system_container(bus, host);
1196 break;
1197
1198 default:
1199 assert_not_reached("Hmm, unknown transport type.");
1200 }
1201
1202 return r;
1203 }
1204
1205 int bus_property_get_bool(
1206 sd_bus *bus,
1207 const char *path,
1208 const char *interface,
1209 const char *property,
1210 sd_bus_message *reply,
1211 void *userdata,
1212 sd_bus_error *error) {
1213
1214 int b = *(bool*) userdata;
1215
1216 return sd_bus_message_append_basic(reply, 'b', &b);
1217 }
1218
1219 #if __SIZEOF_SIZE_T__ != 8
1220 int bus_property_get_size(
1221 sd_bus *bus,
1222 const char *path,
1223 const char *interface,
1224 const char *property,
1225 sd_bus_message *reply,
1226 void *userdata,
1227 sd_bus_error *error) {
1228
1229 uint64_t sz = *(size_t*) userdata;
1230
1231 return sd_bus_message_append_basic(reply, 't', &sz);
1232 }
1233 #endif
1234
1235 #if __SIZEOF_LONG__ != 8
1236 int bus_property_get_long(
1237 sd_bus *bus,
1238 const char *path,
1239 const char *interface,
1240 const char *property,
1241 sd_bus_message *reply,
1242 void *userdata,
1243 sd_bus_error *error) {
1244
1245 int64_t l = *(long*) userdata;
1246
1247 return sd_bus_message_append_basic(reply, 'x', &l);
1248 }
1249
1250 int bus_property_get_ulong(
1251 sd_bus *bus,
1252 const char *path,
1253 const char *interface,
1254 const char *property,
1255 sd_bus_message *reply,
1256 void *userdata,
1257 sd_bus_error *error) {
1258
1259 uint64_t ul = *(unsigned long*) userdata;
1260
1261 return sd_bus_message_append_basic(reply, 't', &ul);
1262 }
1263 #endif
1264
1265 int bus_log_parse_error(int r) {
1266 log_error_errno(r, "Failed to parse bus message: %m");
1267 return r;
1268 }
1269
1270 int bus_log_create_error(int r) {
1271 log_error_errno(r, "Failed to create bus message: %m");
1272 return r;
1273 }
1274
1275 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1276 assert(message);
1277 assert(u);
1278
1279 u->machine = NULL;
1280
1281 return sd_bus_message_read(
1282 message,
1283 "(ssssssouso)",
1284 &u->id,
1285 &u->description,
1286 &u->load_state,
1287 &u->active_state,
1288 &u->sub_state,
1289 &u->following,
1290 &u->unit_path,
1291 &u->job_id,
1292 &u->job_type,
1293 &u->job_path);
1294 }
1295
1296 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1297 assert(m);
1298
1299 if (r < 0) {
1300 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1301 sd_bus_reply_method_errno(m, r, error);
1302
1303 } else if (sd_bus_error_is_set(error)) {
1304 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1305 sd_bus_reply_method_error(m, error);
1306 } else
1307 return r;
1308
1309 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1310 bus_message_type_to_string(m->header->type),
1311 strna(m->sender),
1312 strna(m->path),
1313 strna(m->interface),
1314 strna(m->member),
1315 strna(m->root_container.signature),
1316 bus_error_message(error, r));
1317
1318 return 1;
1319 }
1320
1321 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1322 const char *eq, *field;
1323 int r;
1324
1325 assert(m);
1326 assert(assignment);
1327
1328 eq = strchr(assignment, '=');
1329 if (!eq) {
1330 log_error("Not an assignment: %s", assignment);
1331 return -EINVAL;
1332 }
1333
1334 field = strndupa(assignment, eq - assignment);
1335 eq ++;
1336
1337 if (streq(field, "CPUQuota")) {
1338
1339 if (isempty(eq)) {
1340
1341 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1342 if (r < 0)
1343 return bus_log_create_error(r);
1344
1345 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1346
1347 } else if (endswith(eq, "%")) {
1348 double percent;
1349
1350 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1351 log_error("CPU quota '%s' invalid.", eq);
1352 return -EINVAL;
1353 }
1354
1355 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1356 if (r < 0)
1357 return bus_log_create_error(r);
1358
1359 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1360 } else {
1361 log_error("CPU quota needs to be in percent.");
1362 return -EINVAL;
1363 }
1364
1365 if (r < 0)
1366 return bus_log_create_error(r);
1367
1368 return 0;
1369 }
1370
1371 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1372 if (r < 0)
1373 return bus_log_create_error(r);
1374
1375 if (STR_IN_SET(field,
1376 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1377 "SendSIGHUP", "SendSIGKILL")) {
1378
1379 r = parse_boolean(eq);
1380 if (r < 0) {
1381 log_error("Failed to parse boolean assignment %s.", assignment);
1382 return -EINVAL;
1383 }
1384
1385 r = sd_bus_message_append(m, "v", "b", r);
1386
1387 } else if (streq(field, "MemoryLimit")) {
1388 off_t bytes;
1389
1390 r = parse_size(eq, 1024, &bytes);
1391 if (r < 0) {
1392 log_error("Failed to parse bytes specification %s", assignment);
1393 return -EINVAL;
1394 }
1395
1396 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1397
1398 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1399 uint64_t u;
1400
1401 r = safe_atou64(eq, &u);
1402 if (r < 0) {
1403 log_error("Failed to parse %s value %s.", field, eq);
1404 return -EINVAL;
1405 }
1406
1407 r = sd_bus_message_append(m, "v", "t", u);
1408
1409 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1410 r = sd_bus_message_append(m, "v", "s", eq);
1411
1412 else if (streq(field, "DeviceAllow")) {
1413
1414 if (isempty(eq))
1415 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1416 else {
1417 const char *path, *rwm, *e;
1418
1419 e = strchr(eq, ' ');
1420 if (e) {
1421 path = strndupa(eq, e - eq);
1422 rwm = e+1;
1423 } else {
1424 path = eq;
1425 rwm = "";
1426 }
1427
1428 if (!path_startswith(path, "/dev")) {
1429 log_error("%s is not a device file in /dev.", path);
1430 return -EINVAL;
1431 }
1432
1433 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1434 }
1435
1436 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1437
1438 if (isempty(eq))
1439 r = sd_bus_message_append(m, "v", "a(st)", 0);
1440 else {
1441 const char *path, *bandwidth, *e;
1442 off_t bytes;
1443
1444 e = strchr(eq, ' ');
1445 if (e) {
1446 path = strndupa(eq, e - eq);
1447 bandwidth = e+1;
1448 } else {
1449 log_error("Failed to parse %s value %s.", field, eq);
1450 return -EINVAL;
1451 }
1452
1453 if (!path_startswith(path, "/dev")) {
1454 log_error("%s is not a device file in /dev.", path);
1455 return -EINVAL;
1456 }
1457
1458 r = parse_size(bandwidth, 1000, &bytes);
1459 if (r < 0) {
1460 log_error("Failed to parse byte value %s.", bandwidth);
1461 return -EINVAL;
1462 }
1463
1464 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1465 }
1466
1467 } else if (streq(field, "BlockIODeviceWeight")) {
1468
1469 if (isempty(eq))
1470 r = sd_bus_message_append(m, "v", "a(st)", 0);
1471 else {
1472 const char *path, *weight, *e;
1473 uint64_t u;
1474
1475 e = strchr(eq, ' ');
1476 if (e) {
1477 path = strndupa(eq, e - eq);
1478 weight = e+1;
1479 } else {
1480 log_error("Failed to parse %s value %s.", field, eq);
1481 return -EINVAL;
1482 }
1483
1484 if (!path_startswith(path, "/dev")) {
1485 log_error("%s is not a device file in /dev.", path);
1486 return -EINVAL;
1487 }
1488
1489 r = safe_atou64(weight, &u);
1490 if (r < 0) {
1491 log_error("Failed to parse %s value %s.", field, weight);
1492 return -EINVAL;
1493 }
1494 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1495 }
1496
1497 } else if (rlimit_from_string(field) >= 0) {
1498 uint64_t rl;
1499
1500 if (streq(eq, "infinity"))
1501 rl = (uint64_t) -1;
1502 else {
1503 r = safe_atou64(eq, &rl);
1504 if (r < 0) {
1505 log_error("Invalid resource limit: %s", eq);
1506 return -EINVAL;
1507 }
1508 }
1509
1510 r = sd_bus_message_append(m, "v", "t", rl);
1511
1512 } else if (streq(field, "Nice")) {
1513 int32_t i;
1514
1515 r = safe_atoi32(eq, &i);
1516 if (r < 0) {
1517 log_error("Failed to parse %s value %s.", field, eq);
1518 return -EINVAL;
1519 }
1520
1521 r = sd_bus_message_append(m, "v", "i", i);
1522
1523 } else if (streq(field, "Environment")) {
1524
1525 r = sd_bus_message_append(m, "v", "as", 1, eq);
1526
1527 } else if (streq(field, "KillSignal")) {
1528 int sig;
1529
1530 sig = signal_from_string_try_harder(eq);
1531 if (sig < 0) {
1532 log_error("Failed to parse %s value %s.", field, eq);
1533 return -EINVAL;
1534 }
1535
1536 r = sd_bus_message_append(m, "v", "i", sig);
1537
1538 } else {
1539 log_error("Unknown assignment %s.", assignment);
1540 return -EINVAL;
1541 }
1542
1543 if (r < 0)
1544 return bus_log_create_error(r);
1545
1546 return 0;
1547 }