]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-util.c
hashmap: introduce hash_ops to make struct Hashmap smaller
[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;
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, NULL);
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_message_map_all_properties(sd_bus *bus,
978 sd_bus_message *m,
979 const struct bus_properties_map *map,
980 void *userdata) {
981 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
982 int r;
983
984 assert(bus);
985 assert(m);
986 assert(map);
987
988 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
989 if (r < 0)
990 return r;
991
992 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
993 const struct bus_properties_map *prop;
994 const char *member;
995 const char *contents;
996 void *v;
997 unsigned i;
998
999 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1000 if (r < 0)
1001 return r;
1002
1003 for (i = 0, prop = NULL; map[i].member; i++)
1004 if (streq(map[i].member, member)) {
1005 prop = &map[i];
1006 break;
1007 }
1008
1009 if (prop) {
1010 r = sd_bus_message_peek_type(m, NULL, &contents);
1011 if (r < 0)
1012 return r;
1013
1014 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1015 if (r < 0)
1016 return r;
1017
1018 v = (uint8_t *)userdata + prop->offset;
1019 if (map[i].set)
1020 r = prop->set(bus, member, m, &error, v);
1021 else
1022 r = map_basic(bus, member, m, &error, v);
1023 if (r < 0)
1024 return r;
1025
1026 r = sd_bus_message_exit_container(m);
1027 if (r < 0)
1028 return r;
1029 } else {
1030 r = sd_bus_message_skip(m, "v");
1031 if (r < 0)
1032 return r;
1033 }
1034
1035 r = sd_bus_message_exit_container(m);
1036 if (r < 0)
1037 return r;
1038 }
1039
1040 return sd_bus_message_exit_container(m);
1041 }
1042
1043 int bus_message_map_properties_changed(sd_bus *bus,
1044 sd_bus_message *m,
1045 const struct bus_properties_map *map,
1046 void *userdata) {
1047 const char *member;
1048 int r, invalidated, i;
1049
1050 assert(bus);
1051 assert(m);
1052 assert(map);
1053
1054 r = bus_message_map_all_properties(bus, m, map, userdata);
1055 if (r < 0)
1056 return r;
1057
1058 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1059 if (r < 0)
1060 return r;
1061
1062 invalidated = 0;
1063 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1064 for (i = 0; map[i].member; i++)
1065 if (streq(map[i].member, member)) {
1066 ++invalidated;
1067 break;
1068 }
1069
1070 r = sd_bus_message_exit_container(m);
1071 if (r < 0)
1072 return r;
1073
1074 return invalidated;
1075 }
1076
1077 int bus_map_all_properties(sd_bus *bus,
1078 const char *destination,
1079 const char *path,
1080 const struct bus_properties_map *map,
1081 void *userdata) {
1082 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1083 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1084 int r;
1085
1086 assert(bus);
1087 assert(destination);
1088 assert(path);
1089 assert(map);
1090
1091 r = sd_bus_call_method(
1092 bus,
1093 destination,
1094 path,
1095 "org.freedesktop.DBus.Properties",
1096 "GetAll",
1097 &error,
1098 &m,
1099 "s", "");
1100 if (r < 0)
1101 return r;
1102
1103 return bus_message_map_all_properties(bus, m, map, userdata);
1104 }
1105
1106 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1107 int r;
1108
1109 assert(transport >= 0);
1110 assert(transport < _BUS_TRANSPORT_MAX);
1111 assert(bus);
1112
1113 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1114 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1115
1116 switch (transport) {
1117
1118 case BUS_TRANSPORT_LOCAL:
1119 if (user)
1120 r = sd_bus_default_user(bus);
1121 else
1122 r = sd_bus_default_system(bus);
1123
1124 break;
1125
1126 case BUS_TRANSPORT_REMOTE:
1127 r = sd_bus_open_system_remote(bus, host);
1128 break;
1129
1130 case BUS_TRANSPORT_CONTAINER:
1131 r = sd_bus_open_system_container(bus, host);
1132 break;
1133
1134 default:
1135 assert_not_reached("Hmm, unknown transport type.");
1136 }
1137
1138 return r;
1139 }
1140
1141 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1142 int r;
1143
1144 assert(transport >= 0);
1145 assert(transport < _BUS_TRANSPORT_MAX);
1146 assert(bus);
1147
1148 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1149 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1150
1151 switch (transport) {
1152
1153 case BUS_TRANSPORT_LOCAL:
1154 if (user)
1155 r = bus_open_user_systemd(bus);
1156 else
1157 r = bus_open_system_systemd(bus);
1158
1159 break;
1160
1161 case BUS_TRANSPORT_REMOTE:
1162 r = sd_bus_open_system_remote(bus, host);
1163 break;
1164
1165 case BUS_TRANSPORT_CONTAINER:
1166 r = sd_bus_open_system_container(bus, host);
1167 break;
1168
1169 default:
1170 assert_not_reached("Hmm, unknown transport type.");
1171 }
1172
1173 return r;
1174 }
1175
1176 int bus_property_get_bool(
1177 sd_bus *bus,
1178 const char *path,
1179 const char *interface,
1180 const char *property,
1181 sd_bus_message *reply,
1182 void *userdata,
1183 sd_bus_error *error) {
1184
1185 int b = *(bool*) userdata;
1186
1187 return sd_bus_message_append_basic(reply, 'b', &b);
1188 }
1189
1190 #if __SIZEOF_SIZE_T__ != 8
1191 int bus_property_get_size(
1192 sd_bus *bus,
1193 const char *path,
1194 const char *interface,
1195 const char *property,
1196 sd_bus_message *reply,
1197 void *userdata,
1198 sd_bus_error *error) {
1199
1200 uint64_t sz = *(size_t*) userdata;
1201
1202 return sd_bus_message_append_basic(reply, 't', &sz);
1203 }
1204 #endif
1205
1206 #if __SIZEOF_LONG__ != 8
1207 int bus_property_get_long(
1208 sd_bus *bus,
1209 const char *path,
1210 const char *interface,
1211 const char *property,
1212 sd_bus_message *reply,
1213 void *userdata,
1214 sd_bus_error *error) {
1215
1216 int64_t l = *(long*) userdata;
1217
1218 return sd_bus_message_append_basic(reply, 'x', &l);
1219 }
1220
1221 int bus_property_get_ulong(
1222 sd_bus *bus,
1223 const char *path,
1224 const char *interface,
1225 const char *property,
1226 sd_bus_message *reply,
1227 void *userdata,
1228 sd_bus_error *error) {
1229
1230 uint64_t ul = *(unsigned long*) userdata;
1231
1232 return sd_bus_message_append_basic(reply, 't', &ul);
1233 }
1234 #endif
1235
1236 int bus_log_parse_error(int r) {
1237 log_error("Failed to parse bus message: %s", strerror(-r));
1238 return r;
1239 }
1240
1241 int bus_log_create_error(int r) {
1242 log_error("Failed to create bus message: %s", strerror(-r));
1243 return r;
1244 }
1245
1246 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1247 assert(message);
1248 assert(u);
1249
1250 u->machine = NULL;
1251
1252 return sd_bus_message_read(
1253 message,
1254 "(ssssssouso)",
1255 &u->id,
1256 &u->description,
1257 &u->load_state,
1258 &u->active_state,
1259 &u->sub_state,
1260 &u->following,
1261 &u->unit_path,
1262 &u->job_id,
1263 &u->job_type,
1264 &u->job_path);
1265 }
1266
1267 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1268 assert(m);
1269
1270 if (r < 0) {
1271 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1272 sd_bus_reply_method_errno(m, r, error);
1273
1274 } else if (sd_bus_error_is_set(error)) {
1275 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1276 sd_bus_reply_method_error(m, error);
1277 } else
1278 return r;
1279
1280 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1281 bus_message_type_to_string(m->header->type),
1282 strna(m->sender),
1283 strna(m->path),
1284 strna(m->interface),
1285 strna(m->member),
1286 strna(m->root_container.signature),
1287 bus_error_message(error, r));
1288
1289 return 1;
1290 }
1291
1292 int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
1293 const char *eq, *field;
1294 int r;
1295
1296 assert(m);
1297 assert(assignment);
1298
1299 eq = strchr(assignment, '=');
1300 if (!eq) {
1301 log_error("Not an assignment: %s", assignment);
1302 return -EINVAL;
1303 }
1304
1305 field = strndupa(assignment, eq - assignment);
1306 eq ++;
1307
1308 if (streq(field, "CPUQuota")) {
1309
1310 if (isempty(eq)) {
1311
1312 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1313 if (r < 0)
1314 return bus_log_create_error(r);
1315
1316 r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
1317
1318 } else if (endswith(eq, "%")) {
1319 double percent;
1320
1321 if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
1322 log_error("CPU quota '%s' invalid.", eq);
1323 return -EINVAL;
1324 }
1325
1326 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
1327 if (r < 0)
1328 return bus_log_create_error(r);
1329
1330 r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
1331 } else {
1332 log_error("CPU quota needs to be in percent.");
1333 return -EINVAL;
1334 }
1335
1336 if (r < 0)
1337 return bus_log_create_error(r);
1338
1339 return 0;
1340 }
1341
1342 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1343 if (r < 0)
1344 return bus_log_create_error(r);
1345
1346 if (STR_IN_SET(field,
1347 "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
1348 "SendSIGHUP", "SendSIGKILL")) {
1349
1350 r = parse_boolean(eq);
1351 if (r < 0) {
1352 log_error("Failed to parse boolean assignment %s.", assignment);
1353 return -EINVAL;
1354 }
1355
1356 r = sd_bus_message_append(m, "v", "b", r);
1357
1358 } else if (streq(field, "MemoryLimit")) {
1359 off_t bytes;
1360
1361 r = parse_size(eq, 1024, &bytes);
1362 if (r < 0) {
1363 log_error("Failed to parse bytes specification %s", assignment);
1364 return -EINVAL;
1365 }
1366
1367 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
1368
1369 } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
1370 uint64_t u;
1371
1372 r = safe_atou64(eq, &u);
1373 if (r < 0) {
1374 log_error("Failed to parse %s value %s.", field, eq);
1375 return -EINVAL;
1376 }
1377
1378 r = sd_bus_message_append(m, "v", "t", u);
1379
1380 } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
1381 r = sd_bus_message_append(m, "v", "s", eq);
1382
1383 else if (streq(field, "DeviceAllow")) {
1384
1385 if (isempty(eq))
1386 r = sd_bus_message_append(m, "v", "a(ss)", 0);
1387 else {
1388 const char *path, *rwm, *e;
1389
1390 e = strchr(eq, ' ');
1391 if (e) {
1392 path = strndupa(eq, e - eq);
1393 rwm = e+1;
1394 } else {
1395 path = eq;
1396 rwm = "";
1397 }
1398
1399 if (!path_startswith(path, "/dev")) {
1400 log_error("%s is not a device file in /dev.", path);
1401 return -EINVAL;
1402 }
1403
1404 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
1405 }
1406
1407 } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
1408
1409 if (isempty(eq))
1410 r = sd_bus_message_append(m, "v", "a(st)", 0);
1411 else {
1412 const char *path, *bandwidth, *e;
1413 off_t bytes;
1414
1415 e = strchr(eq, ' ');
1416 if (e) {
1417 path = strndupa(eq, e - eq);
1418 bandwidth = e+1;
1419 } else {
1420 log_error("Failed to parse %s value %s.", field, eq);
1421 return -EINVAL;
1422 }
1423
1424 if (!path_startswith(path, "/dev")) {
1425 log_error("%s is not a device file in /dev.", path);
1426 return -EINVAL;
1427 }
1428
1429 r = parse_size(bandwidth, 1000, &bytes);
1430 if (r < 0) {
1431 log_error("Failed to parse byte value %s.", bandwidth);
1432 return -EINVAL;
1433 }
1434
1435 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
1436 }
1437
1438 } else if (streq(field, "BlockIODeviceWeight")) {
1439
1440 if (isempty(eq))
1441 r = sd_bus_message_append(m, "v", "a(st)", 0);
1442 else {
1443 const char *path, *weight, *e;
1444 uint64_t u;
1445
1446 e = strchr(eq, ' ');
1447 if (e) {
1448 path = strndupa(eq, e - eq);
1449 weight = e+1;
1450 } else {
1451 log_error("Failed to parse %s value %s.", field, eq);
1452 return -EINVAL;
1453 }
1454
1455 if (!path_startswith(path, "/dev")) {
1456 log_error("%s is not a device file in /dev.", path);
1457 return -EINVAL;
1458 }
1459
1460 r = safe_atou64(weight, &u);
1461 if (r < 0) {
1462 log_error("Failed to parse %s value %s.", field, weight);
1463 return -EINVAL;
1464 }
1465 r = sd_bus_message_append(m, "v", "a(st)", path, u);
1466 }
1467
1468 } else if (rlimit_from_string(field) >= 0) {
1469 uint64_t rl;
1470
1471 if (streq(eq, "infinity"))
1472 rl = (uint64_t) -1;
1473 else {
1474 r = safe_atou64(eq, &rl);
1475 if (r < 0) {
1476 log_error("Invalid resource limit: %s", eq);
1477 return -EINVAL;
1478 }
1479 }
1480
1481 r = sd_bus_message_append(m, "v", "t", rl);
1482
1483 } else if (streq(field, "Nice")) {
1484 int32_t i;
1485
1486 r = safe_atoi32(eq, &i);
1487 if (r < 0) {
1488 log_error("Failed to parse %s value %s.", field, eq);
1489 return -EINVAL;
1490 }
1491
1492 r = sd_bus_message_append(m, "v", "i", i);
1493
1494 } else if (streq(field, "Environment")) {
1495
1496 r = sd_bus_message_append(m, "v", "as", 1, eq);
1497
1498 } else if (streq(field, "KillSignal")) {
1499 int sig;
1500
1501 sig = signal_from_string_try_harder(eq);
1502 if (sig < 0) {
1503 log_error("Failed to parse %s value %s.", field, eq);
1504 return -EINVAL;
1505 }
1506
1507 r = sd_bus_message_append(m, "v", "i", sig);
1508
1509 } else {
1510 log_error("Unknown assignment %s.", assignment);
1511 return -EINVAL;
1512 }
1513
1514 if (r < 0)
1515 return bus_log_create_error(r);
1516
1517 return 0;
1518 }