]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-util.c
tree-wide: use set_ensure_put()
[thirdparty/systemd.git] / src / shared / bus-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <inttypes.h>
6 #include <stdlib.h>
7 #include <sys/ioctl.h>
8 #include <sys/resource.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11
12 #include "sd-bus.h"
13 #include "sd-daemon.h"
14 #include "sd-event.h"
15 #include "sd-id128.h"
16
17 #include "alloc-util.h"
18 #include "bus-internal.h"
19 #include "bus-introspect.h"
20 #include "bus-label.h"
21 #include "bus-message.h"
22 #include "bus-util.h"
23 #include "cap-list.h"
24 #include "cgroup-util.h"
25 #include "escape.h"
26 #include "mountpoint-util.h"
27 #include "nsflags.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "rlimit-util.h"
31 #include "socket-util.h"
32 #include "stdio-util.h"
33 #include "strv.h"
34 #include "user-util.h"
35
36 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
37 sd_event *e = userdata;
38
39 assert(m);
40 assert(e);
41
42 sd_bus_close(sd_bus_message_get_bus(m));
43 sd_event_exit(e, 0);
44
45 return 1;
46 }
47
48 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
49 const char *match;
50 const char *unique;
51 int r;
52
53 assert(e);
54 assert(bus);
55 assert(name);
56
57 /* We unregister the name here and then wait for the
58 * NameOwnerChanged signal for this event to arrive before we
59 * quit. We do this in order to make sure that any queued
60 * requests are still processed before we really exit. */
61
62 r = sd_bus_get_unique_name(bus, &unique);
63 if (r < 0)
64 return r;
65
66 match = strjoina(
67 "sender='org.freedesktop.DBus',"
68 "type='signal',"
69 "interface='org.freedesktop.DBus',"
70 "member='NameOwnerChanged',"
71 "path='/org/freedesktop/DBus',"
72 "arg0='", name, "',",
73 "arg1='", unique, "',",
74 "arg2=''");
75
76 r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
77 if (r < 0)
78 return r;
79
80 r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
81 if (r < 0)
82 return r;
83
84 return 0;
85 }
86
87 int bus_event_loop_with_idle(
88 sd_event *e,
89 sd_bus *bus,
90 const char *name,
91 usec_t timeout,
92 check_idle_t check_idle,
93 void *userdata) {
94 bool exiting = false;
95 int r, code;
96
97 assert(e);
98 assert(bus);
99 assert(name);
100
101 for (;;) {
102 bool idle;
103
104 r = sd_event_get_state(e);
105 if (r < 0)
106 return r;
107 if (r == SD_EVENT_FINISHED)
108 break;
109
110 if (check_idle)
111 idle = check_idle(userdata);
112 else
113 idle = true;
114
115 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
116 if (r < 0)
117 return r;
118
119 if (r == 0 && !exiting && idle) {
120 /* Inform the service manager that we are going down, so that it will queue all
121 * further start requests, instead of assuming we are already running. */
122 sd_notify(false, "STOPPING=1");
123
124 r = bus_async_unregister_and_exit(e, bus, name);
125 if (r < 0)
126 return r;
127
128 exiting = true;
129 continue;
130 }
131 }
132
133 r = sd_event_get_exit_code(e, &code);
134 if (r < 0)
135 return r;
136
137 return code;
138 }
139
140 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
141 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
142 int r, has_owner = 0;
143
144 assert(c);
145 assert(name);
146
147 r = sd_bus_call_method(c,
148 "org.freedesktop.DBus",
149 "/org/freedesktop/dbus",
150 "org.freedesktop.DBus",
151 "NameHasOwner",
152 error,
153 &rep,
154 "s",
155 name);
156 if (r < 0)
157 return r;
158
159 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
160 if (r < 0)
161 return sd_bus_error_set_errno(error, r);
162
163 return has_owner;
164 }
165
166 int bus_check_peercred(sd_bus *c) {
167 struct ucred ucred;
168 int fd, r;
169
170 assert(c);
171
172 fd = sd_bus_get_fd(c);
173 if (fd < 0)
174 return fd;
175
176 r = getpeercred(fd, &ucred);
177 if (r < 0)
178 return r;
179
180 if (ucred.uid != 0 && ucred.uid != geteuid())
181 return -EPERM;
182
183 return 1;
184 }
185
186 int bus_connect_system_systemd(sd_bus **_bus) {
187 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
188 int r;
189
190 assert(_bus);
191
192 if (geteuid() != 0)
193 return sd_bus_default_system(_bus);
194
195 /* If we are root then let's talk directly to the system
196 * instance, instead of going via the bus */
197
198 r = sd_bus_new(&bus);
199 if (r < 0)
200 return r;
201
202 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
203 if (r < 0)
204 return r;
205
206 r = sd_bus_start(bus);
207 if (r < 0)
208 return sd_bus_default_system(_bus);
209
210 r = bus_check_peercred(bus);
211 if (r < 0)
212 return r;
213
214 *_bus = TAKE_PTR(bus);
215
216 return 0;
217 }
218
219 int bus_connect_user_systemd(sd_bus **_bus) {
220 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
221 _cleanup_free_ char *ee = NULL;
222 const char *e;
223 int r;
224
225 assert(_bus);
226
227 e = secure_getenv("XDG_RUNTIME_DIR");
228 if (!e)
229 return sd_bus_default_user(_bus);
230
231 ee = bus_address_escape(e);
232 if (!ee)
233 return -ENOMEM;
234
235 r = sd_bus_new(&bus);
236 if (r < 0)
237 return r;
238
239 bus->address = strjoin("unix:path=", ee, "/systemd/private");
240 if (!bus->address)
241 return -ENOMEM;
242
243 r = sd_bus_start(bus);
244 if (r < 0)
245 return sd_bus_default_user(_bus);
246
247 r = bus_check_peercred(bus);
248 if (r < 0)
249 return r;
250
251 *_bus = TAKE_PTR(bus);
252
253 return 0;
254 }
255
256 int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *value) {
257 assert(name);
258
259 if (expected_value && !streq_ptr(expected_value, value))
260 return 0;
261
262 if (only_value)
263 puts(value);
264 else
265 printf("%s=%s\n", name, value);
266
267 return 0;
268 }
269
270 int bus_print_property_valuef(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) {
271 va_list ap;
272 int r;
273
274 assert(name);
275 assert(fmt);
276
277 if (expected_value) {
278 _cleanup_free_ char *s = NULL;
279
280 va_start(ap, fmt);
281 r = vasprintf(&s, fmt, ap);
282 va_end(ap);
283 if (r < 0)
284 return -ENOMEM;
285
286 if (streq_ptr(expected_value, s)) {
287 if (only_value)
288 puts(s);
289 else
290 printf("%s=%s\n", name, s);
291 }
292
293 return 0;
294 }
295
296 if (!only_value)
297 printf("%s=", name);
298 va_start(ap, fmt);
299 vprintf(fmt, ap);
300 va_end(ap);
301 puts("");
302
303 return 0;
304 }
305
306 static int bus_print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
307 char type;
308 const char *contents;
309 int r;
310
311 assert(name);
312 assert(m);
313
314 r = sd_bus_message_peek_type(m, &type, &contents);
315 if (r < 0)
316 return r;
317
318 switch (type) {
319
320 case SD_BUS_TYPE_STRING: {
321 const char *s;
322
323 r = sd_bus_message_read_basic(m, type, &s);
324 if (r < 0)
325 return r;
326
327 if (all || !isempty(s)) {
328 bool good;
329
330 /* This property has a single value, so we need to take
331 * care not to print a new line, everything else is OK. */
332 good = !strchr(s, '\n');
333 bus_print_property_value(name, expected_value, value, good ? s : "[unprintable]");
334 }
335
336 return 1;
337 }
338
339 case SD_BUS_TYPE_BOOLEAN: {
340 int b;
341
342 r = sd_bus_message_read_basic(m, type, &b);
343 if (r < 0)
344 return r;
345
346 if (expected_value && parse_boolean(expected_value) != b)
347 return 1;
348
349 bus_print_property_value(name, NULL, value, yes_no(b));
350 return 1;
351 }
352
353 case SD_BUS_TYPE_UINT64: {
354 uint64_t u;
355
356 r = sd_bus_message_read_basic(m, type, &u);
357 if (r < 0)
358 return r;
359
360 /* Yes, heuristics! But we can change this check
361 * should it turn out to not be sufficient */
362
363 if (endswith(name, "Timestamp") ||
364 STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec")) {
365 char timestamp[FORMAT_TIMESTAMP_MAX];
366 const char *t;
367
368 t = format_timestamp(timestamp, sizeof(timestamp), u);
369 if (t || all)
370 bus_print_property_value(name, expected_value, value, strempty(t));
371
372 } else if (strstr(name, "USec")) {
373 char timespan[FORMAT_TIMESPAN_MAX];
374
375 (void) format_timespan(timespan, sizeof(timespan), u, 0);
376 bus_print_property_value(name, expected_value, value, timespan);
377
378 } else if (streq(name, "CoredumpFilter")) {
379 char buf[STRLEN("0xFFFFFFFF")];
380
381 xsprintf(buf, "0x%"PRIx64, u);
382 bus_print_property_value(name, expected_value, value, buf);
383
384 } else if (streq(name, "RestrictNamespaces")) {
385 _cleanup_free_ char *s = NULL;
386 const char *result;
387
388 if ((u & NAMESPACE_FLAGS_ALL) == 0)
389 result = "yes";
390 else if (FLAGS_SET(u, NAMESPACE_FLAGS_ALL))
391 result = "no";
392 else {
393 r = namespace_flags_to_string(u, &s);
394 if (r < 0)
395 return r;
396
397 result = strempty(s);
398 }
399
400 bus_print_property_value(name, expected_value, value, result);
401
402 } else if (streq(name, "MountFlags")) {
403 const char *result;
404
405 result = mount_propagation_flags_to_string(u);
406 if (!result)
407 return -EINVAL;
408
409 bus_print_property_value(name, expected_value, value, result);
410
411 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
412 _cleanup_free_ char *s = NULL;
413
414 r = capability_set_to_string_alloc(u, &s);
415 if (r < 0)
416 return r;
417
418 bus_print_property_value(name, expected_value, value, s);
419
420 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
421 (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
422 (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
423 (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
424 (endswith(name, "NSec") && u == (uint64_t) -1))
425
426 bus_print_property_value(name, expected_value, value, "[not set]");
427
428 else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
429 (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
430 (startswith(name, "Limit") && u == (uint64_t) -1) ||
431 (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
432
433 bus_print_property_value(name, expected_value, value, "infinity");
434 else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == (uint64_t) -1)
435 bus_print_property_value(name, expected_value, value, "[no data]");
436 else
437 bus_print_property_valuef(name, expected_value, value, "%"PRIu64, u);
438
439 return 1;
440 }
441
442 case SD_BUS_TYPE_INT64: {
443 int64_t i;
444
445 r = sd_bus_message_read_basic(m, type, &i);
446 if (r < 0)
447 return r;
448
449 bus_print_property_valuef(name, expected_value, value, "%"PRIi64, i);
450 return 1;
451 }
452
453 case SD_BUS_TYPE_UINT32: {
454 uint32_t u;
455
456 r = sd_bus_message_read_basic(m, type, &u);
457 if (r < 0)
458 return r;
459
460 if (strstr(name, "UMask") || strstr(name, "Mode"))
461 bus_print_property_valuef(name, expected_value, value, "%04o", u);
462
463 else if (streq(name, "UID")) {
464 if (u == UID_INVALID)
465 bus_print_property_value(name, expected_value, value, "[not set]");
466 else
467 bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
468 } else if (streq(name, "GID")) {
469 if (u == GID_INVALID)
470 bus_print_property_value(name, expected_value, value, "[not set]");
471 else
472 bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
473 } else
474 bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
475
476 return 1;
477 }
478
479 case SD_BUS_TYPE_INT32: {
480 int32_t i;
481
482 r = sd_bus_message_read_basic(m, type, &i);
483 if (r < 0)
484 return r;
485
486 bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
487 return 1;
488 }
489
490 case SD_BUS_TYPE_DOUBLE: {
491 double d;
492
493 r = sd_bus_message_read_basic(m, type, &d);
494 if (r < 0)
495 return r;
496
497 bus_print_property_valuef(name, expected_value, value, "%g", d);
498 return 1;
499 }
500
501 case SD_BUS_TYPE_ARRAY:
502 if (streq(contents, "s")) {
503 bool first = true;
504 const char *str;
505
506 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents);
507 if (r < 0)
508 return r;
509
510 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
511 _cleanup_free_ char *e = NULL;
512
513 e = shell_maybe_quote(str, ESCAPE_BACKSLASH_ONELINE);
514 if (!e)
515 return -ENOMEM;
516
517 if (first) {
518 if (!value)
519 printf("%s=", name);
520 first = false;
521 } else
522 fputs(" ", stdout);
523
524 fputs(e, stdout);
525 }
526 if (r < 0)
527 return r;
528
529 if (first && all && !value)
530 printf("%s=", name);
531 if (!first || all)
532 puts("");
533
534 r = sd_bus_message_exit_container(m);
535 if (r < 0)
536 return r;
537
538 return 1;
539
540 } else if (streq(contents, "y")) {
541 const uint8_t *u;
542 size_t n;
543
544 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
545 if (r < 0)
546 return r;
547
548 if (all || n > 0) {
549 unsigned i;
550
551 if (!value)
552 printf("%s=", name);
553
554 for (i = 0; i < n; i++)
555 printf("%02x", u[i]);
556
557 puts("");
558 }
559
560 return 1;
561
562 } else if (streq(contents, "u")) {
563 uint32_t *u;
564 size_t n;
565
566 r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
567 if (r < 0)
568 return r;
569
570 if (all || n > 0) {
571 unsigned i;
572
573 if (!value)
574 printf("%s=", name);
575
576 for (i = 0; i < n; i++)
577 printf("%08x", u[i]);
578
579 puts("");
580 }
581
582 return 1;
583 }
584
585 break;
586 }
587
588 return 0;
589 }
590
591 int bus_message_print_all_properties(
592 sd_bus_message *m,
593 bus_message_print_t func,
594 char **filter,
595 bool value,
596 bool all,
597 Set **found_properties) {
598
599 int r;
600
601 assert(m);
602
603 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
604 if (r < 0)
605 return r;
606
607 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
608 _cleanup_free_ char *name_with_equal = NULL;
609 const char *name, *contents, *expected_value = NULL;
610
611 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
612 if (r < 0)
613 return r;
614
615 if (found_properties) {
616 r = set_ensure_put(found_properties, &string_hash_ops, name);
617 if (r < 0 && r != -EEXIST)
618 return log_oom();
619 }
620
621 name_with_equal = strjoin(name, "=");
622 if (!name_with_equal)
623 return log_oom();
624
625 if (!filter || strv_find(filter, name) ||
626 (expected_value = strv_find_startswith(filter, name_with_equal))) {
627 r = sd_bus_message_peek_type(m, NULL, &contents);
628 if (r < 0)
629 return r;
630
631 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
632 if (r < 0)
633 return r;
634
635 if (func)
636 r = func(name, expected_value, m, value, all);
637 if (!func || r == 0)
638 r = bus_print_property(name, expected_value, m, value, all);
639 if (r < 0)
640 return r;
641 if (r == 0) {
642 if (all && !expected_value)
643 printf("%s=[unprintable]\n", name);
644 /* skip what we didn't read */
645 r = sd_bus_message_skip(m, contents);
646 if (r < 0)
647 return r;
648 }
649
650 r = sd_bus_message_exit_container(m);
651 if (r < 0)
652 return r;
653 } else {
654 r = sd_bus_message_skip(m, "v");
655 if (r < 0)
656 return r;
657 }
658
659 r = sd_bus_message_exit_container(m);
660 if (r < 0)
661 return r;
662 }
663 if (r < 0)
664 return r;
665
666 r = sd_bus_message_exit_container(m);
667 if (r < 0)
668 return r;
669
670 return 0;
671 }
672
673 int bus_print_all_properties(
674 sd_bus *bus,
675 const char *dest,
676 const char *path,
677 bus_message_print_t func,
678 char **filter,
679 bool value,
680 bool all,
681 Set **found_properties) {
682
683 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
684 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
685 int r;
686
687 assert(bus);
688 assert(path);
689
690 r = sd_bus_call_method(bus,
691 dest,
692 path,
693 "org.freedesktop.DBus.Properties",
694 "GetAll",
695 &error,
696 &reply,
697 "s", "");
698 if (r < 0)
699 return r;
700
701 return bus_message_print_all_properties(reply, func, filter, value, all, found_properties);
702 }
703
704 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
705 sd_id128_t *p = userdata;
706 const void *v;
707 size_t n;
708 int r;
709
710 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
711 if (r < 0)
712 return r;
713
714 if (n == 0)
715 *p = SD_ID128_NULL;
716 else if (n == 16)
717 memcpy((*p).bytes, v, n);
718 else
719 return -EINVAL;
720
721 return 0;
722 }
723
724 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
725 char type;
726 int r;
727
728 r = sd_bus_message_peek_type(m, &type, NULL);
729 if (r < 0)
730 return r;
731
732 switch (type) {
733
734 case SD_BUS_TYPE_STRING:
735 case SD_BUS_TYPE_OBJECT_PATH: {
736 const char **p = userdata;
737 const char *s;
738
739 r = sd_bus_message_read_basic(m, type, &s);
740 if (r < 0)
741 return r;
742
743 if (isempty(s))
744 s = NULL;
745
746 if (flags & BUS_MAP_STRDUP)
747 return free_and_strdup((char **) userdata, s);
748
749 *p = s;
750 return 0;
751 }
752
753 case SD_BUS_TYPE_ARRAY: {
754 _cleanup_strv_free_ char **l = NULL;
755 char ***p = userdata;
756
757 r = bus_message_read_strv_extend(m, &l);
758 if (r < 0)
759 return r;
760
761 return strv_extend_strv(p, l, false);
762 }
763
764 case SD_BUS_TYPE_BOOLEAN: {
765 int b;
766
767 r = sd_bus_message_read_basic(m, type, &b);
768 if (r < 0)
769 return r;
770
771 if (flags & BUS_MAP_BOOLEAN_AS_BOOL)
772 *(bool*) userdata = b;
773 else
774 *(int*) userdata = b;
775
776 return 0;
777 }
778
779 case SD_BUS_TYPE_INT32:
780 case SD_BUS_TYPE_UINT32: {
781 uint32_t u, *p = userdata;
782
783 r = sd_bus_message_read_basic(m, type, &u);
784 if (r < 0)
785 return r;
786
787 *p = u;
788 return 0;
789 }
790
791 case SD_BUS_TYPE_INT64:
792 case SD_BUS_TYPE_UINT64: {
793 uint64_t t, *p = userdata;
794
795 r = sd_bus_message_read_basic(m, type, &t);
796 if (r < 0)
797 return r;
798
799 *p = t;
800 return 0;
801 }
802
803 case SD_BUS_TYPE_DOUBLE: {
804 double d, *p = userdata;
805
806 r = sd_bus_message_read_basic(m, type, &d);
807 if (r < 0)
808 return r;
809
810 *p = d;
811 return 0;
812 }}
813
814 return -EOPNOTSUPP;
815 }
816
817 int bus_message_map_all_properties(
818 sd_bus_message *m,
819 const struct bus_properties_map *map,
820 unsigned flags,
821 sd_bus_error *error,
822 void *userdata) {
823
824 int r;
825
826 assert(m);
827 assert(map);
828
829 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
830 if (r < 0)
831 return r;
832
833 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
834 const struct bus_properties_map *prop;
835 const char *member;
836 const char *contents;
837 void *v;
838 unsigned i;
839
840 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
841 if (r < 0)
842 return r;
843
844 for (i = 0, prop = NULL; map[i].member; i++)
845 if (streq(map[i].member, member)) {
846 prop = &map[i];
847 break;
848 }
849
850 if (prop) {
851 r = sd_bus_message_peek_type(m, NULL, &contents);
852 if (r < 0)
853 return r;
854
855 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
856 if (r < 0)
857 return r;
858
859 v = (uint8_t *)userdata + prop->offset;
860 if (map[i].set)
861 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
862 else
863 r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v);
864 if (r < 0)
865 return r;
866
867 r = sd_bus_message_exit_container(m);
868 if (r < 0)
869 return r;
870 } else {
871 r = sd_bus_message_skip(m, "v");
872 if (r < 0)
873 return r;
874 }
875
876 r = sd_bus_message_exit_container(m);
877 if (r < 0)
878 return r;
879 }
880 if (r < 0)
881 return r;
882
883 return sd_bus_message_exit_container(m);
884 }
885
886 int bus_map_all_properties(
887 sd_bus *bus,
888 const char *destination,
889 const char *path,
890 const struct bus_properties_map *map,
891 unsigned flags,
892 sd_bus_error *error,
893 sd_bus_message **reply,
894 void *userdata) {
895
896 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
897 int r;
898
899 assert(bus);
900 assert(destination);
901 assert(path);
902 assert(map);
903 assert(reply || (flags & BUS_MAP_STRDUP));
904
905 r = sd_bus_call_method(
906 bus,
907 destination,
908 path,
909 "org.freedesktop.DBus.Properties",
910 "GetAll",
911 error,
912 &m,
913 "s", "");
914 if (r < 0)
915 return r;
916
917 r = bus_message_map_all_properties(m, map, flags, error, userdata);
918 if (r < 0)
919 return r;
920
921 if (reply)
922 *reply = sd_bus_message_ref(m);
923
924 return r;
925 }
926
927 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
928 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
929 int r;
930
931 assert(transport >= 0);
932 assert(transport < _BUS_TRANSPORT_MAX);
933 assert(ret);
934
935 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
936 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
937
938 switch (transport) {
939
940 case BUS_TRANSPORT_LOCAL:
941 if (user)
942 r = sd_bus_default_user(&bus);
943 else {
944 if (sd_booted() <= 0) {
945 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
946 log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
947
948 return -EHOSTDOWN;
949 }
950 r = sd_bus_default_system(&bus);
951 }
952 break;
953
954 case BUS_TRANSPORT_REMOTE:
955 r = sd_bus_open_system_remote(&bus, host);
956 break;
957
958 case BUS_TRANSPORT_MACHINE:
959 r = sd_bus_open_system_machine(&bus, host);
960 break;
961
962 default:
963 assert_not_reached("Hmm, unknown transport type.");
964 }
965 if (r < 0)
966 return r;
967
968 r = sd_bus_set_exit_on_disconnect(bus, true);
969 if (r < 0)
970 return r;
971
972 *ret = TAKE_PTR(bus);
973
974 return 0;
975 }
976
977 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
978 int r;
979
980 assert(transport >= 0);
981 assert(transport < _BUS_TRANSPORT_MAX);
982 assert(bus);
983
984 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
985 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
986
987 switch (transport) {
988
989 case BUS_TRANSPORT_LOCAL:
990 if (user)
991 r = bus_connect_user_systemd(bus);
992 else {
993 if (sd_booted() <= 0)
994 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
995 return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
996 "System has not been booted with systemd as init system (PID 1). Can't operate.");
997 r = bus_connect_system_systemd(bus);
998 }
999 break;
1000
1001 case BUS_TRANSPORT_REMOTE:
1002 r = sd_bus_open_system_remote(bus, host);
1003 break;
1004
1005 case BUS_TRANSPORT_MACHINE:
1006 r = sd_bus_open_system_machine(bus, host);
1007 break;
1008
1009 default:
1010 assert_not_reached("Hmm, unknown transport type.");
1011 }
1012
1013 return r;
1014 }
1015
1016 int bus_property_get_bool(
1017 sd_bus *bus,
1018 const char *path,
1019 const char *interface,
1020 const char *property,
1021 sd_bus_message *reply,
1022 void *userdata,
1023 sd_bus_error *error) {
1024
1025 int b = *(bool*) userdata;
1026
1027 return sd_bus_message_append_basic(reply, 'b', &b);
1028 }
1029
1030 int bus_property_set_bool(
1031 sd_bus *bus,
1032 const char *path,
1033 const char *interface,
1034 const char *property,
1035 sd_bus_message *value,
1036 void *userdata,
1037 sd_bus_error *error) {
1038
1039 int b, r;
1040
1041 r = sd_bus_message_read(value, "b", &b);
1042 if (r < 0)
1043 return r;
1044
1045 *(bool*) userdata = b;
1046 return 0;
1047 }
1048
1049 int bus_property_get_id128(
1050 sd_bus *bus,
1051 const char *path,
1052 const char *interface,
1053 const char *property,
1054 sd_bus_message *reply,
1055 void *userdata,
1056 sd_bus_error *error) {
1057
1058 sd_id128_t *id = userdata;
1059
1060 if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1061 return sd_bus_message_append(reply, "ay", 0);
1062 else
1063 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1064 }
1065
1066 #if __SIZEOF_SIZE_T__ != 8
1067 int bus_property_get_size(
1068 sd_bus *bus,
1069 const char *path,
1070 const char *interface,
1071 const char *property,
1072 sd_bus_message *reply,
1073 void *userdata,
1074 sd_bus_error *error) {
1075
1076 uint64_t sz = *(size_t*) userdata;
1077
1078 return sd_bus_message_append_basic(reply, 't', &sz);
1079 }
1080 #endif
1081
1082 #if __SIZEOF_LONG__ != 8
1083 int bus_property_get_long(
1084 sd_bus *bus,
1085 const char *path,
1086 const char *interface,
1087 const char *property,
1088 sd_bus_message *reply,
1089 void *userdata,
1090 sd_bus_error *error) {
1091
1092 int64_t l = *(long*) userdata;
1093
1094 return sd_bus_message_append_basic(reply, 'x', &l);
1095 }
1096
1097 int bus_property_get_ulong(
1098 sd_bus *bus,
1099 const char *path,
1100 const char *interface,
1101 const char *property,
1102 sd_bus_message *reply,
1103 void *userdata,
1104 sd_bus_error *error) {
1105
1106 uint64_t ul = *(unsigned long*) userdata;
1107
1108 return sd_bus_message_append_basic(reply, 't', &ul);
1109 }
1110 #endif
1111
1112 /**
1113 * bus_path_encode_unique() - encode unique object path
1114 * @b: bus connection or NULL
1115 * @prefix: object path prefix
1116 * @sender_id: unique-name of client, or NULL
1117 * @external_id: external ID to be chosen by client, or NULL
1118 * @ret_path: storage for encoded object path pointer
1119 *
1120 * Whenever we provide a bus API that allows clients to create and manage
1121 * server-side objects, we need to provide a unique name for these objects. If
1122 * we let the server choose the name, we suffer from a race condition: If a
1123 * client creates an object asynchronously, it cannot destroy that object until
1124 * it received the method reply. It cannot know the name of the new object,
1125 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1126 *
1127 * Therefore, many APIs allow the client to choose the unique name for newly
1128 * created objects. There're two problems to solve, though:
1129 * 1) Object names are usually defined via dbus object paths, which are
1130 * usually globally namespaced. Therefore, multiple clients must be able
1131 * to choose unique object names without interference.
1132 * 2) If multiple libraries share the same bus connection, they must be
1133 * able to choose unique object names without interference.
1134 * The first problem is solved easily by prefixing a name with the
1135 * unique-bus-name of a connection. The server side must enforce this and
1136 * reject any other name. The second problem is solved by providing unique
1137 * suffixes from within sd-bus.
1138 *
1139 * This helper allows clients to create unique object-paths. It uses the
1140 * template '/prefix/sender_id/external_id' and returns the new path in
1141 * @ret_path (must be freed by the caller).
1142 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1143 * NULL, this function allocates a unique suffix via @b (by requesting a new
1144 * cookie). If both @sender_id and @external_id are given, @b can be passed as
1145 * NULL.
1146 *
1147 * Returns: 0 on success, negative error code on failure.
1148 */
1149 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1150 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1151 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1152 int r;
1153
1154 assert_return(b || (sender_id && external_id), -EINVAL);
1155 assert_return(sd_bus_object_path_is_valid(prefix), -EINVAL);
1156 assert_return(ret_path, -EINVAL);
1157
1158 if (!sender_id) {
1159 r = sd_bus_get_unique_name(b, &sender_id);
1160 if (r < 0)
1161 return r;
1162 }
1163
1164 if (!external_id) {
1165 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1166 external_id = external_buf;
1167 }
1168
1169 sender_label = bus_label_escape(sender_id);
1170 if (!sender_label)
1171 return -ENOMEM;
1172
1173 external_label = bus_label_escape(external_id);
1174 if (!external_label)
1175 return -ENOMEM;
1176
1177 p = path_join(prefix, sender_label, external_label);
1178 if (!p)
1179 return -ENOMEM;
1180
1181 *ret_path = p;
1182 return 0;
1183 }
1184
1185 /**
1186 * bus_path_decode_unique() - decode unique object path
1187 * @path: object path to decode
1188 * @prefix: object path prefix
1189 * @ret_sender: output parameter for sender-id label
1190 * @ret_external: output parameter for external-id label
1191 *
1192 * This does the reverse of bus_path_encode_unique() (see its description for
1193 * details). Both trailing labels, sender-id and external-id, are unescaped and
1194 * returned in the given output parameters (the caller must free them).
1195 *
1196 * Note that this function returns 0 if the path does not match the template
1197 * (see bus_path_encode_unique()), 1 if it matched.
1198 *
1199 * Returns: Negative error code on failure, 0 if the given object path does not
1200 * match the template (return parameters are set to NULL), 1 if it was
1201 * parsed successfully (return parameters contain allocated labels).
1202 */
1203 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1204 const char *p, *q;
1205 char *sender, *external;
1206
1207 assert(sd_bus_object_path_is_valid(path));
1208 assert(sd_bus_object_path_is_valid(prefix));
1209 assert(ret_sender);
1210 assert(ret_external);
1211
1212 p = object_path_startswith(path, prefix);
1213 if (!p) {
1214 *ret_sender = NULL;
1215 *ret_external = NULL;
1216 return 0;
1217 }
1218
1219 q = strchr(p, '/');
1220 if (!q) {
1221 *ret_sender = NULL;
1222 *ret_external = NULL;
1223 return 0;
1224 }
1225
1226 sender = bus_label_unescape_n(p, q - p);
1227 external = bus_label_unescape(q + 1);
1228 if (!sender || !external) {
1229 free(sender);
1230 free(external);
1231 return -ENOMEM;
1232 }
1233
1234 *ret_sender = sender;
1235 *ret_external = external;
1236 return 1;
1237 }
1238
1239 int bus_property_get_rlimit(
1240 sd_bus *bus,
1241 const char *path,
1242 const char *interface,
1243 const char *property,
1244 sd_bus_message *reply,
1245 void *userdata,
1246 sd_bus_error *error) {
1247
1248 const char *is_soft;
1249 struct rlimit *rl;
1250 uint64_t u;
1251 rlim_t x;
1252
1253 assert(bus);
1254 assert(reply);
1255 assert(userdata);
1256
1257 is_soft = endswith(property, "Soft");
1258
1259 rl = *(struct rlimit**) userdata;
1260 if (rl)
1261 x = is_soft ? rl->rlim_cur : rl->rlim_max;
1262 else {
1263 struct rlimit buf = {};
1264 const char *s, *p;
1265 int z;
1266
1267 /* Chop off "Soft" suffix */
1268 s = is_soft ? strndupa(property, is_soft - property) : property;
1269
1270 /* Skip over any prefix, such as "Default" */
1271 assert_se(p = strstr(s, "Limit"));
1272
1273 z = rlimit_from_string(p + 5);
1274 assert(z >= 0);
1275
1276 (void) getrlimit(z, &buf);
1277 x = is_soft ? buf.rlim_cur : buf.rlim_max;
1278 }
1279
1280 /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
1281 * archs */
1282 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1283
1284 return sd_bus_message_append(reply, "t", u);
1285 }
1286
1287 int bus_track_add_name_many(sd_bus_track *t, char **l) {
1288 int r = 0;
1289 char **i;
1290
1291 assert(t);
1292
1293 /* Continues adding after failure, and returns the first failure. */
1294
1295 STRV_FOREACH(i, l) {
1296 int k;
1297
1298 k = sd_bus_track_add_name(t, *i);
1299 if (k < 0 && r >= 0)
1300 r = k;
1301 }
1302
1303 return r;
1304 }
1305
1306 int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
1307 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1308 const char *e;
1309 int r;
1310
1311 assert(ret);
1312
1313 /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
1314 * turned on. */
1315
1316 r = sd_bus_new(&bus);
1317 if (r < 0)
1318 return r;
1319
1320 if (description) {
1321 r = sd_bus_set_description(bus, description);
1322 if (r < 0)
1323 return r;
1324 }
1325
1326 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1327 if (!e)
1328 e = DEFAULT_SYSTEM_BUS_ADDRESS;
1329
1330 r = sd_bus_set_address(bus, e);
1331 if (r < 0)
1332 return r;
1333
1334 r = sd_bus_set_bus_client(bus, true);
1335 if (r < 0)
1336 return r;
1337
1338 r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1339 if (r < 0)
1340 return r;
1341
1342 r = sd_bus_set_watch_bind(bus, true);
1343 if (r < 0)
1344 return r;
1345
1346 r = sd_bus_set_connected_signal(bus, true);
1347 if (r < 0)
1348 return r;
1349
1350 r = sd_bus_start(bus);
1351 if (r < 0)
1352 return r;
1353
1354 *ret = TAKE_PTR(bus);
1355
1356 return 0;
1357 }
1358
1359 int bus_reply_pair_array(sd_bus_message *m, char **l) {
1360 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1361 char **k, **v;
1362 int r;
1363
1364 assert(m);
1365
1366 /* Reply to the specified message with a message containing a dictionary put together from the
1367 * specified strv */
1368
1369 r = sd_bus_message_new_method_return(m, &reply);
1370 if (r < 0)
1371 return r;
1372
1373 r = sd_bus_message_open_container(reply, 'a', "{ss}");
1374 if (r < 0)
1375 return r;
1376
1377 STRV_FOREACH_PAIR(k, v, l) {
1378 r = sd_bus_message_append(reply, "{ss}", *k, *v);
1379 if (r < 0)
1380 return r;
1381 }
1382
1383 r = sd_bus_message_close_container(reply);
1384 if (r < 0)
1385 return r;
1386
1387 return sd_bus_send(NULL, reply, NULL);
1388 }
1389
1390 static void bus_message_unref_wrapper(void *m) {
1391 sd_bus_message_unref(m);
1392 }
1393
1394 const struct hash_ops bus_message_hash_ops = {
1395 .hash = trivial_hash_func,
1396 .compare = trivial_compare_func,
1397 .free_value = bus_message_unref_wrapper,
1398 };
1399
1400 /* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface
1401 * strings encapsulated within a single struct.
1402 */
1403 int bus_call_method_async(
1404 sd_bus *bus,
1405 sd_bus_slot **slot,
1406 const BusLocator *locator,
1407 const char *member,
1408 sd_bus_message_handler_t callback,
1409 void *userdata,
1410 const char *types, ...) {
1411
1412 va_list ap;
1413 int r;
1414
1415 assert(locator);
1416
1417 va_start(ap, types);
1418 r = sd_bus_call_method_asyncv(bus, slot, locator->destination, locator->path, locator->interface, member, callback, userdata, types, ap);
1419 va_end(ap);
1420
1421 return r;
1422 }
1423
1424 int bus_call_method(
1425 sd_bus *bus,
1426 const BusLocator *locator,
1427 const char *member,
1428 sd_bus_error *error,
1429 sd_bus_message **reply,
1430 const char *types, ...) {
1431
1432 va_list ap;
1433 int r;
1434
1435 assert(locator);
1436
1437 va_start(ap, types);
1438 r = sd_bus_call_methodv(bus, locator->destination, locator->path, locator->interface, member, error, reply, types, ap);
1439 va_end(ap);
1440
1441 return r;
1442 }
1443
1444 int bus_get_property(
1445 sd_bus *bus,
1446 const BusLocator *locator,
1447 const char *member,
1448 sd_bus_error *error,
1449 sd_bus_message **reply,
1450 const char *type) {
1451
1452 assert(locator);
1453
1454 return sd_bus_get_property(bus, locator->destination, locator->path, locator->interface, member, error, reply, type);
1455 }
1456
1457 int bus_get_property_trivial(
1458 sd_bus *bus,
1459 const BusLocator *locator,
1460 const char *member,
1461 sd_bus_error *error,
1462 char type, void *ptr) {
1463
1464 assert(locator);
1465
1466 return sd_bus_get_property_trivial(bus, locator->destination, locator->path, locator->interface, member, error, type, ptr);
1467 }
1468
1469 int bus_get_property_string(
1470 sd_bus *bus,
1471 const BusLocator *locator,
1472 const char *member,
1473 sd_bus_error *error,
1474 char **ret) {
1475
1476 assert(locator);
1477
1478 return sd_bus_get_property_string(bus, locator->destination, locator->path, locator->interface, member, error, ret);
1479 }
1480
1481 int bus_get_property_strv(
1482 sd_bus *bus,
1483 const BusLocator *locator,
1484 const char *member,
1485 sd_bus_error *error,
1486 char ***ret) {
1487
1488 assert(locator);
1489
1490 return sd_bus_get_property_strv(bus, locator->destination, locator->path, locator->interface, member, error, ret);
1491 }
1492
1493 int bus_set_property(
1494 sd_bus *bus,
1495 const BusLocator *locator,
1496 const char *member,
1497 sd_bus_error *error,
1498 const char *type, ...) {
1499
1500 va_list ap;
1501 int r;
1502
1503 assert(locator);
1504
1505 va_start(ap, type);
1506 r = sd_bus_set_propertyv(bus, locator->destination, locator->path, locator->interface, member, error, type, ap);
1507 va_end(ap);
1508
1509 return r;
1510 }
1511
1512 int bus_match_signal(
1513 sd_bus *bus,
1514 sd_bus_slot **ret,
1515 const BusLocator *locator,
1516 const char *member,
1517 sd_bus_message_handler_t callback,
1518 void *userdata) {
1519
1520 assert(locator);
1521
1522 return sd_bus_match_signal(bus, ret, locator->destination, locator->path, locator->interface, member, callback, userdata);
1523 }
1524
1525 int bus_match_signal_async(
1526 sd_bus *bus,
1527 sd_bus_slot **ret,
1528 const BusLocator *locator,
1529 const char *member,
1530 sd_bus_message_handler_t callback,
1531 sd_bus_message_handler_t install_callback,
1532 void *userdata) {
1533
1534 assert(locator);
1535
1536 return sd_bus_match_signal_async(bus, ret, locator->destination, locator->path, locator->interface, member, callback, install_callback, userdata);
1537 }
1538
1539 int bus_message_new_method_call(
1540 sd_bus *bus,
1541 sd_bus_message **m,
1542 const BusLocator *locator,
1543 const char *member) {
1544
1545 assert(locator);
1546
1547 return sd_bus_message_new_method_call(bus, m, locator->destination, locator->path, locator->interface, member);
1548 }
1549
1550 int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata) {
1551 int r;
1552
1553 log_debug("Registering bus object implementation for path=%s iface=%s", impl->path, impl->interface);
1554
1555 for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
1556 r = sd_bus_add_object_vtable(bus, NULL,
1557 impl->path,
1558 impl->interface,
1559 *p,
1560 userdata);
1561 if (r < 0)
1562 return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
1563 impl->path,
1564 impl->interface);
1565 }
1566
1567 for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
1568 r = sd_bus_add_fallback_vtable(bus, NULL,
1569 impl->path,
1570 impl->interface,
1571 p->vtable,
1572 p->object_find,
1573 userdata);
1574 if (r < 0)
1575 return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
1576 impl->path,
1577 impl->interface);
1578 }
1579
1580 if (impl->node_enumerator) {
1581 r = sd_bus_add_node_enumerator(bus, NULL,
1582 impl->path,
1583 impl->node_enumerator,
1584 userdata);
1585 if (r < 0)
1586 return log_error_errno(r, "Failed to add node enumerator for %s: %m",
1587 impl->path);
1588 }
1589
1590 if (impl->manager) {
1591 r = sd_bus_add_object_manager(bus, NULL, impl->path);
1592 if (r < 0)
1593 return log_error_errno(r, "Failed to add object manager for %s: %m", impl->path);
1594 }
1595
1596 for (size_t i = 0; impl->children && impl->children[i]; i++) {
1597 r = bus_add_implementation(bus, impl->children[i], userdata);
1598 if (r < 0)
1599 return r;
1600 }
1601
1602 return 0;
1603 }
1604
1605 static const BusObjectImplementation* find_implementation(
1606 const char *pattern,
1607 const BusObjectImplementation* const* bus_objects) {
1608
1609 for (size_t i = 0; bus_objects && bus_objects[i]; i++) {
1610 const BusObjectImplementation *impl = bus_objects[i];
1611
1612 if (STR_IN_SET(pattern, impl->path, impl->interface))
1613 return impl;
1614
1615 impl = find_implementation(pattern, impl->children);
1616 if (impl)
1617 return impl;
1618 }
1619
1620 return NULL;
1621 }
1622
1623 static int bus_introspect_implementation(
1624 struct introspect *intro,
1625 const BusObjectImplementation *impl) {
1626 int r;
1627
1628 for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
1629 r = introspect_write_interface(intro, impl->interface, *p);
1630 if (r < 0)
1631 return log_error_errno(r, "Failed to write introspection data: %m");
1632 }
1633
1634 for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
1635 r = introspect_write_interface(intro, impl->interface, p->vtable);
1636 if (r < 0)
1637 return log_error_errno(r, "Failed to write introspection data: %m");
1638 }
1639
1640 return 0;
1641 }
1642
1643 static void list_paths(
1644 FILE *out,
1645 const BusObjectImplementation* const* bus_objects) {
1646
1647 for (size_t i = 0; bus_objects[i]; i++) {
1648 fprintf(out, "%s\t%s\n", bus_objects[i]->path, bus_objects[i]->interface);
1649 if (bus_objects[i]->children)
1650 list_paths(out, bus_objects[i]->children);
1651 }
1652 }
1653
1654 int bus_introspect_implementations(
1655 FILE *out,
1656 const char *pattern,
1657 const BusObjectImplementation* const* bus_objects) {
1658
1659 const BusObjectImplementation *impl, *main_impl = NULL;
1660 _cleanup_free_ char *s = NULL;
1661 int r;
1662
1663 if (streq(pattern, "list")) {
1664 list_paths(out, bus_objects);
1665 return 0;
1666 }
1667
1668 struct introspect intro = {};
1669 bool is_interface = sd_bus_interface_name_is_valid(pattern);
1670
1671 impl = find_implementation(pattern, bus_objects);
1672 if (!impl)
1673 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
1674 "%s %s not found",
1675 is_interface ? "Interface" : "Object path",
1676 pattern);
1677
1678 /* We use trusted=false here to get all the @org.freedesktop.systemd1.Privileged annotations. */
1679 r = introspect_begin(&intro, false);
1680 if (r < 0)
1681 return log_error_errno(r, "Failed to write introspection data: %m");
1682
1683 r = introspect_write_default_interfaces(&intro, impl->manager);
1684 if (r < 0)
1685 return log_error_errno(r, "Failed to write introspection data: %m");
1686
1687 /* Check if there is a non-fallback path that applies to the given interface, also
1688 * print it. This is useful in the case of units: o.fd.systemd1.Service is declared
1689 * as a fallback vtable for o/fd/systemd1/unit, and we also want to print
1690 * o.fd.systemd1.Unit, which is the non-fallback implementation. */
1691 if (impl->fallback_vtables && is_interface)
1692 main_impl = find_implementation(impl->path, bus_objects);
1693
1694 if (main_impl)
1695 bus_introspect_implementation(&intro, main_impl);
1696
1697 if (impl != main_impl)
1698 bus_introspect_implementation(&intro, impl);
1699
1700 _cleanup_set_free_ Set *nodes = NULL;
1701
1702 for (size_t i = 0; impl->children && impl->children[i]; i++) {
1703 r = set_put_strdup(&nodes, impl->children[i]->path);
1704 if (r < 0)
1705 return log_oom();
1706 }
1707
1708 r = introspect_write_child_nodes(&intro, nodes, impl->path);
1709 if (r < 0)
1710 return r;
1711
1712 r = introspect_finish(&intro, &s);
1713 if (r < 0)
1714 return log_error_errno(r, "Failed to write introspection data: %m");
1715
1716 fputs(s, out);
1717 return 0;
1718 }