]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
c664cf56 LP |
2 | |
3 | #include "bus-introspect.h" | |
4 | #include "bus-object.h" | |
5 | #include "macro.h" | |
6 | #include "string-util.h" | |
7 | #include "strv.h" | |
8 | ||
9 | int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata) { | |
10 | int r; | |
11 | ||
12 | log_debug("Registering bus object implementation for path=%s iface=%s", impl->path, impl->interface); | |
13 | ||
14 | for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) { | |
15 | r = sd_bus_add_object_vtable(bus, NULL, | |
16 | impl->path, | |
17 | impl->interface, | |
18 | *p, | |
19 | userdata); | |
20 | if (r < 0) | |
21 | return log_error_errno(r, "Failed to register bus path %s with interface %s: %m", | |
22 | impl->path, | |
23 | impl->interface); | |
24 | } | |
25 | ||
26 | for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) { | |
27 | r = sd_bus_add_fallback_vtable(bus, NULL, | |
28 | impl->path, | |
29 | impl->interface, | |
30 | p->vtable, | |
31 | p->object_find, | |
32 | userdata); | |
33 | if (r < 0) | |
34 | return log_error_errno(r, "Failed to register bus path %s with interface %s: %m", | |
35 | impl->path, | |
36 | impl->interface); | |
37 | } | |
38 | ||
39 | if (impl->node_enumerator) { | |
40 | r = sd_bus_add_node_enumerator(bus, NULL, | |
41 | impl->path, | |
42 | impl->node_enumerator, | |
43 | userdata); | |
44 | if (r < 0) | |
45 | return log_error_errno(r, "Failed to add node enumerator for %s: %m", | |
46 | impl->path); | |
47 | } | |
48 | ||
49 | if (impl->manager) { | |
50 | r = sd_bus_add_object_manager(bus, NULL, impl->path); | |
51 | if (r < 0) | |
52 | return log_error_errno(r, "Failed to add object manager for %s: %m", impl->path); | |
53 | } | |
54 | ||
55 | for (size_t i = 0; impl->children && impl->children[i]; i++) { | |
56 | r = bus_add_implementation(bus, impl->children[i], userdata); | |
57 | if (r < 0) | |
58 | return r; | |
59 | } | |
60 | ||
61 | return 0; | |
62 | } | |
63 | ||
64 | static const BusObjectImplementation* find_implementation( | |
65 | const char *pattern, | |
66 | const BusObjectImplementation* const* bus_objects) { | |
67 | ||
68 | for (size_t i = 0; bus_objects && bus_objects[i]; i++) { | |
69 | const BusObjectImplementation *impl = bus_objects[i]; | |
70 | ||
71 | if (STR_IN_SET(pattern, impl->path, impl->interface)) | |
72 | return impl; | |
73 | ||
74 | impl = find_implementation(pattern, impl->children); | |
75 | if (impl) | |
76 | return impl; | |
77 | } | |
78 | ||
79 | return NULL; | |
80 | } | |
81 | ||
82 | static int bus_introspect_implementation( | |
83 | struct introspect *intro, | |
84 | const BusObjectImplementation *impl) { | |
85 | int r; | |
86 | ||
87 | for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) { | |
88 | r = introspect_write_interface(intro, impl->interface, *p); | |
89 | if (r < 0) | |
90 | return log_error_errno(r, "Failed to write introspection data: %m"); | |
91 | } | |
92 | ||
93 | for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) { | |
94 | r = introspect_write_interface(intro, impl->interface, p->vtable); | |
95 | if (r < 0) | |
96 | return log_error_errno(r, "Failed to write introspection data: %m"); | |
97 | } | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
102 | static void list_paths( | |
103 | FILE *out, | |
104 | const BusObjectImplementation* const* bus_objects) { | |
105 | ||
106 | for (size_t i = 0; bus_objects[i]; i++) { | |
107 | fprintf(out, "%s\t%s\n", bus_objects[i]->path, bus_objects[i]->interface); | |
108 | if (bus_objects[i]->children) | |
109 | list_paths(out, bus_objects[i]->children); | |
110 | } | |
111 | } | |
112 | ||
113 | int bus_introspect_implementations( | |
114 | FILE *out, | |
115 | const char *pattern, | |
116 | const BusObjectImplementation* const* bus_objects) { | |
117 | ||
118 | const BusObjectImplementation *impl, *main_impl = NULL; | |
119 | _cleanup_free_ char *s = NULL; | |
120 | int r; | |
121 | ||
122 | if (streq(pattern, "list")) { | |
123 | list_paths(out, bus_objects); | |
124 | return 0; | |
125 | } | |
126 | ||
127 | struct introspect intro = {}; | |
128 | bool is_interface = sd_bus_interface_name_is_valid(pattern); | |
129 | ||
130 | impl = find_implementation(pattern, bus_objects); | |
131 | if (!impl) | |
132 | return log_error_errno(SYNTHETIC_ERRNO(ENOENT), | |
133 | "%s %s not found", | |
134 | is_interface ? "Interface" : "Object path", | |
135 | pattern); | |
136 | ||
137 | /* We use trusted=false here to get all the @org.freedesktop.systemd1.Privileged annotations. */ | |
138 | r = introspect_begin(&intro, false); | |
139 | if (r < 0) | |
140 | return log_error_errno(r, "Failed to write introspection data: %m"); | |
141 | ||
142 | r = introspect_write_default_interfaces(&intro, impl->manager); | |
143 | if (r < 0) | |
144 | return log_error_errno(r, "Failed to write introspection data: %m"); | |
145 | ||
146 | /* Check if there is a non-fallback path that applies to the given interface, also | |
147 | * print it. This is useful in the case of units: o.fd.systemd1.Service is declared | |
148 | * as a fallback vtable for o/fd/systemd1/unit, and we also want to print | |
149 | * o.fd.systemd1.Unit, which is the non-fallback implementation. */ | |
150 | if (impl->fallback_vtables && is_interface) | |
151 | main_impl = find_implementation(impl->path, bus_objects); | |
152 | ||
153 | if (main_impl) | |
154 | bus_introspect_implementation(&intro, main_impl); | |
155 | ||
156 | if (impl != main_impl) | |
157 | bus_introspect_implementation(&intro, impl); | |
158 | ||
acac8834 | 159 | _cleanup_ordered_set_free_ OrderedSet *nodes = NULL; |
c664cf56 LP |
160 | |
161 | for (size_t i = 0; impl->children && impl->children[i]; i++) { | |
acac8834 | 162 | r = ordered_set_put_strdup(&nodes, impl->children[i]->path); |
c664cf56 LP |
163 | if (r < 0) |
164 | return log_oom(); | |
165 | } | |
166 | ||
167 | r = introspect_write_child_nodes(&intro, nodes, impl->path); | |
168 | if (r < 0) | |
169 | return r; | |
170 | ||
171 | r = introspect_finish(&intro, &s); | |
172 | if (r < 0) | |
173 | return log_error_errno(r, "Failed to write introspection data: %m"); | |
174 | ||
175 | fputs(s, out); | |
176 | return 0; | |
177 | } |