/src/systemd/src/libsystemd/sd-bus/bus-slot.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | |
3 | | #include "sd-bus.h" |
4 | | |
5 | | #include "alloc-util.h" |
6 | | #include "bus-control.h" |
7 | | #include "bus-objects.h" |
8 | | #include "bus-slot.h" |
9 | | #include "string-util.h" |
10 | | |
11 | | sd_bus_slot *bus_slot_allocate( |
12 | | sd_bus *bus, |
13 | | bool floating, |
14 | | BusSlotType type, |
15 | | size_t extra, |
16 | 527 | void *userdata) { |
17 | | |
18 | 527 | sd_bus_slot *slot; |
19 | | |
20 | 527 | assert(bus); |
21 | | |
22 | 527 | slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra); |
23 | 527 | if (!slot) |
24 | 0 | return NULL; |
25 | | |
26 | 527 | slot->n_ref = 1; |
27 | 527 | slot->type = type; |
28 | 527 | slot->bus = bus; |
29 | 527 | slot->floating = floating; |
30 | 527 | slot->userdata = userdata; |
31 | | |
32 | 527 | if (!floating) |
33 | 0 | sd_bus_ref(bus); |
34 | | |
35 | 527 | LIST_PREPEND(slots, bus->slots, slot); |
36 | | |
37 | 527 | return slot; |
38 | 527 | } |
39 | | |
40 | 1.05k | void bus_slot_disconnect(sd_bus_slot *slot, bool unref) { |
41 | 1.05k | sd_bus *bus; |
42 | | |
43 | 1.05k | assert(slot); |
44 | | |
45 | 1.05k | if (!slot->bus) |
46 | 527 | return; |
47 | | |
48 | 527 | switch (slot->type) { |
49 | | |
50 | 527 | case BUS_REPLY_CALLBACK: |
51 | | |
52 | 527 | if (slot->reply_callback.cookie != 0) |
53 | 527 | ordered_hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie); |
54 | | |
55 | 527 | if (slot->reply_callback.timeout_usec != 0) |
56 | 527 | prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx); |
57 | | |
58 | 527 | break; |
59 | | |
60 | 0 | case BUS_FILTER_CALLBACK: |
61 | 0 | slot->bus->filter_callbacks_modified = true; |
62 | 0 | LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback); |
63 | 0 | break; |
64 | | |
65 | 0 | case BUS_MATCH_CALLBACK: |
66 | |
|
67 | 0 | if (slot->match_added) |
68 | 0 | (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string); |
69 | |
|
70 | 0 | if (slot->match_callback.install_slot) { |
71 | 0 | bus_slot_disconnect(slot->match_callback.install_slot, true); |
72 | 0 | slot->match_callback.install_slot = sd_bus_slot_unref(slot->match_callback.install_slot); |
73 | 0 | } |
74 | |
|
75 | 0 | slot->bus->match_callbacks_modified = true; |
76 | 0 | bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback); |
77 | |
|
78 | 0 | slot->match_callback.match_string = mfree(slot->match_callback.match_string); |
79 | |
|
80 | 0 | break; |
81 | | |
82 | 0 | case BUS_NODE_CALLBACK: |
83 | |
|
84 | 0 | if (slot->node_callback.node) { |
85 | 0 | LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback); |
86 | 0 | slot->bus->nodes_modified = true; |
87 | |
|
88 | 0 | bus_node_gc(slot->bus, slot->node_callback.node); |
89 | 0 | } |
90 | |
|
91 | 0 | break; |
92 | | |
93 | 0 | case BUS_NODE_ENUMERATOR: |
94 | |
|
95 | 0 | if (slot->node_enumerator.node) { |
96 | 0 | LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator); |
97 | 0 | slot->bus->nodes_modified = true; |
98 | |
|
99 | 0 | bus_node_gc(slot->bus, slot->node_enumerator.node); |
100 | 0 | } |
101 | |
|
102 | 0 | break; |
103 | | |
104 | 0 | case BUS_NODE_OBJECT_MANAGER: |
105 | |
|
106 | 0 | if (slot->node_object_manager.node) { |
107 | 0 | LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager); |
108 | 0 | slot->bus->nodes_modified = true; |
109 | |
|
110 | 0 | bus_node_gc(slot->bus, slot->node_object_manager.node); |
111 | 0 | } |
112 | |
|
113 | 0 | break; |
114 | | |
115 | 0 | case BUS_NODE_VTABLE: |
116 | |
|
117 | 0 | if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) { |
118 | 0 | const sd_bus_vtable *v; |
119 | |
|
120 | 0 | for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(slot->node_vtable.vtable, v)) { |
121 | 0 | struct vtable_member *x = NULL; |
122 | |
|
123 | 0 | switch (v->type) { |
124 | | |
125 | 0 | case _SD_BUS_VTABLE_METHOD: { |
126 | 0 | struct vtable_member key; |
127 | |
|
128 | 0 | key.path = slot->node_vtable.node->path; |
129 | 0 | key.interface = slot->node_vtable.interface; |
130 | 0 | key.member = v->x.method.member; |
131 | |
|
132 | 0 | x = hashmap_remove(slot->bus->vtable_methods, &key); |
133 | 0 | break; |
134 | 0 | } |
135 | | |
136 | 0 | case _SD_BUS_VTABLE_PROPERTY: |
137 | 0 | case _SD_BUS_VTABLE_WRITABLE_PROPERTY: { |
138 | 0 | struct vtable_member key; |
139 | |
|
140 | 0 | key.path = slot->node_vtable.node->path; |
141 | 0 | key.interface = slot->node_vtable.interface; |
142 | 0 | key.member = v->x.method.member; |
143 | |
|
144 | 0 | x = hashmap_remove(slot->bus->vtable_properties, &key); |
145 | 0 | break; |
146 | 0 | }} |
147 | | |
148 | 0 | free(x); |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | 0 | slot->node_vtable.interface = mfree(slot->node_vtable.interface); |
153 | |
|
154 | 0 | if (slot->node_vtable.node) { |
155 | 0 | LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable); |
156 | 0 | slot->bus->nodes_modified = true; |
157 | |
|
158 | 0 | bus_node_gc(slot->bus, slot->node_vtable.node); |
159 | 0 | } |
160 | |
|
161 | 0 | break; |
162 | | |
163 | 0 | default: |
164 | 0 | assert_not_reached(); |
165 | 527 | } |
166 | | |
167 | 527 | bus = slot->bus; |
168 | | |
169 | 527 | slot->type = _BUS_SLOT_INVALID; |
170 | 527 | slot->bus = NULL; |
171 | 527 | LIST_REMOVE(slots, bus->slots, slot); |
172 | | |
173 | 527 | if (!slot->floating) |
174 | 0 | sd_bus_unref(bus); |
175 | 527 | else if (unref) |
176 | 527 | sd_bus_slot_unref(slot); |
177 | 527 | } |
178 | | |
179 | 527 | static sd_bus_slot* bus_slot_free(sd_bus_slot *slot) { |
180 | 527 | assert(slot); |
181 | | |
182 | 527 | bus_slot_disconnect(slot, false); |
183 | | |
184 | 527 | if (slot->destroy_callback) |
185 | 0 | slot->destroy_callback(slot->userdata); |
186 | | |
187 | 527 | free(slot->description); |
188 | 527 | return mfree(slot); |
189 | 527 | } |
190 | | |
191 | | DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_slot, sd_bus_slot, bus_slot_free); |
192 | | |
193 | 0 | _public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) { |
194 | 0 | assert_return(slot, NULL); |
195 | | |
196 | 0 | return slot->bus; |
197 | 0 | } |
198 | | |
199 | 0 | _public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) { |
200 | 0 | assert_return(slot, NULL); |
201 | | |
202 | 0 | return slot->userdata; |
203 | 0 | } |
204 | | |
205 | 0 | _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) { |
206 | 0 | void *ret; |
207 | |
|
208 | 0 | assert_return(slot, NULL); |
209 | | |
210 | 0 | ret = slot->userdata; |
211 | 0 | slot->userdata = userdata; |
212 | |
|
213 | 0 | return ret; |
214 | 0 | } |
215 | | |
216 | 0 | _public_ int sd_bus_slot_set_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t callback) { |
217 | 0 | assert_return(slot, -EINVAL); |
218 | | |
219 | 0 | slot->destroy_callback = callback; |
220 | 0 | return 0; |
221 | 0 | } |
222 | | |
223 | 0 | _public_ int sd_bus_slot_get_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t *callback) { |
224 | 0 | assert_return(slot, -EINVAL); |
225 | | |
226 | 0 | if (callback) |
227 | 0 | *callback = slot->destroy_callback; |
228 | |
|
229 | 0 | return !!slot->destroy_callback; |
230 | 0 | } |
231 | | |
232 | 0 | _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) { |
233 | 0 | assert_return(slot, NULL); |
234 | 0 | assert_return(slot->type >= 0, NULL); |
235 | | |
236 | 0 | if (slot->bus->current_slot != slot) |
237 | 0 | return NULL; |
238 | | |
239 | 0 | return slot->bus->current_message; |
240 | 0 | } |
241 | | |
242 | 0 | _public_ sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *slot) { |
243 | 0 | assert_return(slot, NULL); |
244 | 0 | assert_return(slot->type >= 0, NULL); |
245 | | |
246 | 0 | if (slot->bus->current_slot != slot) |
247 | 0 | return NULL; |
248 | | |
249 | 0 | return slot->bus->current_handler; |
250 | 0 | } |
251 | | |
252 | 0 | _public_ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot) { |
253 | 0 | assert_return(slot, NULL); |
254 | 0 | assert_return(slot->type >= 0, NULL); |
255 | | |
256 | 0 | if (slot->bus->current_slot != slot) |
257 | 0 | return NULL; |
258 | | |
259 | 0 | return slot->bus->current_userdata; |
260 | 0 | } |
261 | | |
262 | 0 | _public_ int sd_bus_slot_get_floating(sd_bus_slot *slot) { |
263 | 0 | assert_return(slot, -EINVAL); |
264 | | |
265 | 0 | return slot->floating; |
266 | 0 | } |
267 | | |
268 | 0 | _public_ int sd_bus_slot_set_floating(sd_bus_slot *slot, int b) { |
269 | 0 | assert_return(slot, -EINVAL); |
270 | | |
271 | 0 | if (slot->floating == !!b) |
272 | 0 | return 0; |
273 | | |
274 | 0 | if (!slot->bus) /* already disconnected slots can't be reconnected */ |
275 | 0 | return -ESTALE; |
276 | | |
277 | 0 | slot->floating = b; |
278 | | |
279 | | /* When a slot is "floating" then the bus references the slot. Otherwise the slot references the bus. Hence, |
280 | | * when we move from one to the other, let's increase one reference and decrease the other. */ |
281 | |
|
282 | 0 | if (b) { |
283 | 0 | sd_bus_slot_ref(slot); |
284 | 0 | sd_bus_unref(slot->bus); |
285 | 0 | } else { |
286 | 0 | sd_bus_ref(slot->bus); |
287 | 0 | sd_bus_slot_unref(slot); |
288 | 0 | } |
289 | |
|
290 | 0 | return 1; |
291 | 0 | } |
292 | | |
293 | 0 | _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description) { |
294 | 0 | assert_return(slot, -EINVAL); |
295 | | |
296 | 0 | return free_and_strdup(&slot->description, description); |
297 | 0 | } |
298 | | |
299 | 0 | _public_ int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description) { |
300 | 0 | assert_return(slot, -EINVAL); |
301 | 0 | assert_return(description, -EINVAL); |
302 | | |
303 | 0 | if (slot->description) |
304 | 0 | *description = slot->description; |
305 | 0 | else if (slot->type == BUS_MATCH_CALLBACK) |
306 | 0 | *description = slot->match_callback.match_string; |
307 | 0 | else |
308 | 0 | return -ENXIO; |
309 | | |
310 | 0 | return 0; |
311 | 0 | } |