Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include "alloc-util.h"
4 : : #include "bus-internal.h"
5 : : #include "bus-match.h"
6 : : #include "bus-message.h"
7 : : #include "bus-util.h"
8 : : #include "fd-util.h"
9 : : #include "fileio.h"
10 : : #include "hexdecoct.h"
11 : : #include "sort-util.h"
12 : : #include "string-util.h"
13 : : #include "strv.h"
14 : :
15 : : /* Example:
16 : : *
17 : : * A: type=signal,sender=foo,interface=bar
18 : : * B: type=signal,sender=quux,interface=fips
19 : : * C: type=signal,sender=quux,interface=waldo
20 : : * D: type=signal,member=test
21 : : * E: sender=miau
22 : : * F: type=signal
23 : : * G: type=signal
24 : : *
25 : : * results in this tree:
26 : : *
27 : : * BUS_MATCH_ROOT
28 : : * + BUS_MATCH_MESSAGE_TYPE
29 : : * | ` BUS_MATCH_VALUE: value == signal
30 : : * | + DBUS_MATCH_SENDER
31 : : * | | + BUS_MATCH_VALUE: value == foo
32 : : * | | | ` DBUS_MATCH_INTERFACE
33 : : * | | | ` BUS_MATCH_VALUE: value == bar
34 : : * | | | ` BUS_MATCH_LEAF: A
35 : : * | | ` BUS_MATCH_VALUE: value == quux
36 : : * | | ` DBUS_MATCH_INTERFACE
37 : : * | | | BUS_MATCH_VALUE: value == fips
38 : : * | | | ` BUS_MATCH_LEAF: B
39 : : * | | ` BUS_MATCH_VALUE: value == waldo
40 : : * | | ` BUS_MATCH_LEAF: C
41 : : * | + DBUS_MATCH_MEMBER
42 : : * | | ` BUS_MATCH_VALUE: value == test
43 : : * | | ` BUS_MATCH_LEAF: D
44 : : * | + BUS_MATCH_LEAF: F
45 : : * | ` BUS_MATCH_LEAF: G
46 : : * ` BUS_MATCH_SENDER
47 : : * ` BUS_MATCH_VALUE: value == miau
48 : : * ` BUS_MATCH_LEAF: E
49 : : */
50 : :
51 : 3088 : static bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
52 [ + + + - ]: 3088 : return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
53 : : }
54 : :
55 : 2245 : static bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
56 [ + + + + ]: 2245 : return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
57 [ + + + + : 4534 : (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
+ + ]
58 [ + - ]: 44 : (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
59 : : }
60 : :
61 : 1376 : static void bus_match_node_free(struct bus_match_node *node) {
62 [ - + ]: 1376 : assert(node);
63 [ - + ]: 1376 : assert(node->parent);
64 [ - + ]: 1376 : assert(!node->child);
65 [ - + ]: 1376 : assert(node->type != BUS_MATCH_ROOT);
66 [ - + ]: 1376 : assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
67 : :
68 [ + + ]: 1376 : if (node->parent->child) {
69 : : /* We are apparently linked into the parent's child
70 : : * list. Let's remove us from there. */
71 [ + + ]: 844 : if (node->prev) {
72 [ - + ]: 4 : assert(node->prev->next == node);
73 : 4 : node->prev->next = node->next;
74 : : } else {
75 [ - + ]: 840 : assert(node->parent->child == node);
76 : 840 : node->parent->child = node->next;
77 : : }
78 : :
79 [ + + ]: 844 : if (node->next)
80 : 96 : node->next->prev = node->prev;
81 : : }
82 : :
83 [ + + ]: 1376 : if (node->type == BUS_MATCH_VALUE) {
84 : : /* We might be in the parent's hash table, so clean
85 : : * this up */
86 : :
87 [ + + ]: 608 : if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
88 : 120 : hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
89 [ + + + - ]: 488 : else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
90 : 412 : hashmap_remove(node->parent->compare.children, node->value.str);
91 : :
92 : 608 : free(node->value.str);
93 : : }
94 : :
95 [ + + ]: 1376 : if (BUS_MATCH_IS_COMPARE(node->type)) {
96 [ - + ]: 576 : assert(hashmap_isempty(node->compare.children));
97 : 576 : hashmap_free(node->compare.children);
98 : : }
99 : :
100 : 1376 : free(node);
101 : 1376 : }
102 : :
103 : 1168 : static bool bus_match_node_maybe_free(struct bus_match_node *node) {
104 [ - + ]: 1168 : assert(node);
105 : :
106 [ + + ]: 1168 : if (node->type == BUS_MATCH_ROOT)
107 : 112 : return false;
108 : :
109 [ + + ]: 1056 : if (node->child)
110 : 16 : return false;
111 : :
112 [ + + + + ]: 1040 : if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
113 : 8 : return true;
114 : :
115 : 1032 : bus_match_node_free(node);
116 : 1032 : return true;
117 : : }
118 : :
119 : 59 : static bool value_node_test(
120 : : struct bus_match_node *node,
121 : : enum bus_match_node_type parent_type,
122 : : uint8_t value_u8,
123 : : const char *value_str,
124 : : char **value_strv,
125 : : sd_bus_message *m) {
126 : :
127 [ - + ]: 59 : assert(node);
128 [ - + ]: 59 : assert(node->type == BUS_MATCH_VALUE);
129 : :
130 : : /* Tests parameters against this value node, doing prefix
131 : : * magic and stuff. */
132 : :
133 [ - + - - : 59 : switch (parent_type) {
+ + + - ]
134 : :
135 : 0 : case BUS_MATCH_MESSAGE_TYPE:
136 : 0 : return node->value.u8 == value_u8;
137 : :
138 : 31 : case BUS_MATCH_SENDER:
139 [ + + ]: 31 : if (streq_ptr(node->value.str, value_str))
140 : 12 : return true;
141 : :
142 [ - + ]: 19 : if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
143 : : char **i;
144 : :
145 : : /* on kdbus we have the well known names list
146 : : * in the credentials, let's make use of that
147 : : * for an accurate match */
148 : :
149 [ # # # # ]: 0 : STRV_FOREACH(i, m->creds.well_known_names)
150 [ # # ]: 0 : if (streq_ptr(node->value.str, *i))
151 : 0 : return true;
152 : :
153 : : } else {
154 : :
155 : : /* If we don't have kdbus, we don't know the
156 : : * well-known names of the senders. In that,
157 : : * let's just hope that dbus-daemon doesn't
158 : : * send us stuff we didn't want. */
159 : :
160 [ + - + + : 19 : if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
- + ]
161 : 0 : return true;
162 : : }
163 : :
164 : 19 : return false;
165 : :
166 : 0 : case BUS_MATCH_DESTINATION:
167 : : case BUS_MATCH_INTERFACE:
168 : : case BUS_MATCH_MEMBER:
169 : : case BUS_MATCH_PATH:
170 : : case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
171 : :
172 [ # # ]: 0 : if (value_str)
173 : 0 : return streq_ptr(node->value.str, value_str);
174 : :
175 : 0 : return false;
176 : :
177 : 0 : case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
178 : : char **i;
179 : :
180 [ # # # # ]: 0 : STRV_FOREACH(i, value_strv)
181 [ # # ]: 0 : if (streq_ptr(node->value.str, *i))
182 : 0 : return true;
183 : :
184 : 0 : return false;
185 : : }
186 : :
187 : 8 : case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
188 [ + - ]: 8 : if (value_str)
189 : 8 : return namespace_simple_pattern(node->value.str, value_str);
190 : :
191 : 0 : return false;
192 : :
193 : 16 : case BUS_MATCH_PATH_NAMESPACE:
194 : 16 : return path_simple_pattern(node->value.str, value_str);
195 : :
196 : 4 : case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
197 [ + - ]: 4 : if (value_str)
198 : 4 : return path_complex_pattern(node->value.str, value_str);
199 : :
200 : 0 : return false;
201 : :
202 : 0 : default:
203 : 0 : assert_not_reached("Invalid node type");
204 : : }
205 : : }
206 : :
207 : 20 : static bool value_node_same(
208 : : struct bus_match_node *node,
209 : : enum bus_match_node_type parent_type,
210 : : uint8_t value_u8,
211 : : const char *value_str) {
212 : :
213 : : /* Tests parameters against this value node, not doing prefix
214 : : * magic and stuff, i.e. this one actually compares the match
215 : : * itself. */
216 : :
217 [ - + ]: 20 : assert(node);
218 [ - + ]: 20 : assert(node->type == BUS_MATCH_VALUE);
219 : :
220 [ - + - ]: 20 : switch (parent_type) {
221 : :
222 : 0 : case BUS_MATCH_MESSAGE_TYPE:
223 : 0 : return node->value.u8 == value_u8;
224 : :
225 : 20 : case BUS_MATCH_SENDER:
226 : : case BUS_MATCH_DESTINATION:
227 : : case BUS_MATCH_INTERFACE:
228 : : case BUS_MATCH_MEMBER:
229 : : case BUS_MATCH_PATH:
230 : : case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
231 : : case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
232 : : case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
233 : : case BUS_MATCH_PATH_NAMESPACE:
234 : : case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
235 : 20 : return streq(node->value.str, value_str);
236 : :
237 : 0 : default:
238 : 0 : assert_not_reached("Invalid node type");
239 : : }
240 : : }
241 : :
242 : 1305 : int bus_match_run(
243 : : sd_bus *bus,
244 : : struct bus_match_node *node,
245 : : sd_bus_message *m) {
246 : :
247 : 1305 : _cleanup_strv_free_ char **test_strv = NULL;
248 : 1305 : const char *test_str = NULL;
249 : 1305 : uint8_t test_u8 = 0;
250 : : int r;
251 : :
252 [ - + ]: 1305 : assert(m);
253 : :
254 [ + + ]: 1305 : if (!node)
255 : 446 : return 0;
256 : :
257 [ + + - + ]: 859 : if (bus && bus->match_callbacks_modified)
258 : 0 : return 0;
259 : :
260 : : /* Not these special semantics: when traversing the tree we
261 : : * usually let bus_match_run() when called for a node
262 : : * recursively invoke bus_match_run(). There's are two
263 : : * exceptions here though, which are BUS_NODE_ROOT (which
264 : : * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
265 : : * are invoked anyway by its parent. */
266 : :
267 [ + + + + : 859 : switch (node->type) {
+ - + + +
+ + + +
- ]
268 : :
269 : 259 : case BUS_MATCH_ROOT:
270 : :
271 : : /* Run all children. Since we cannot have any siblings
272 : : * we won't call any. The children of the root node
273 : : * are compares or leaves, they will automatically
274 : : * call their siblings. */
275 : 259 : return bus_match_run(bus, node->child, m);
276 : :
277 : 215 : case BUS_MATCH_VALUE:
278 : :
279 : : /* Run all children. We don't execute any siblings, we
280 : : * assume our caller does that. The children of value
281 : : * nodes are compares or leaves, they will
282 : : * automatically call their siblings */
283 : :
284 [ - + ]: 215 : assert(node->child);
285 : 215 : return bus_match_run(bus, node->child, m);
286 : :
287 : 100 : case BUS_MATCH_LEAF:
288 : :
289 [ + + ]: 100 : if (bus) {
290 : : /* Don't run this match as long as the AddMatch() call is not complete yet.
291 : : *
292 : : * Don't run this match unless the 'after' counter has been reached.
293 : : *
294 : : * Don't run this match more than once per iteration */
295 : :
296 [ + - ]: 20 : if (node->leaf.callback->install_slot ||
297 [ + - ]: 20 : m->read_counter <= node->leaf.callback->after ||
298 [ - + ]: 20 : node->leaf.callback->last_iteration == bus->iteration_counter)
299 : 0 : return bus_match_run(bus, node->next, m);
300 : :
301 : 20 : node->leaf.callback->last_iteration = bus->iteration_counter;
302 : : }
303 : :
304 : 100 : r = sd_bus_message_rewind(m, true);
305 [ - + ]: 100 : if (r < 0)
306 : 0 : return r;
307 : :
308 : : /* Run the callback. And then invoke siblings. */
309 [ + - ]: 100 : if (node->leaf.callback->callback) {
310 [ + + ]: 100 : _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
311 : : sd_bus_slot *slot;
312 : :
313 : 100 : slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
314 [ + + ]: 100 : if (bus) {
315 : 20 : bus->current_slot = sd_bus_slot_ref(slot);
316 : 20 : bus->current_handler = node->leaf.callback->callback;
317 : 20 : bus->current_userdata = slot->userdata;
318 : : }
319 : 100 : r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
320 [ + + ]: 100 : if (bus) {
321 : 20 : bus->current_userdata = NULL;
322 : 20 : bus->current_handler = NULL;
323 : 20 : bus->current_slot = sd_bus_slot_unref(slot);
324 : : }
325 : :
326 : 100 : r = bus_maybe_reply_error(m, r, &error_buffer);
327 [ - + ]: 100 : if (r != 0)
328 : 0 : return r;
329 : :
330 [ + + + + ]: 100 : if (bus && bus->match_callbacks_modified)
331 : 4 : return 0;
332 : : }
333 : :
334 : 96 : return bus_match_run(bus, node->next, m);
335 : :
336 : 79 : case BUS_MATCH_MESSAGE_TYPE:
337 : 79 : test_u8 = m->header->type;
338 : 79 : break;
339 : :
340 : 31 : case BUS_MATCH_SENDER:
341 : 31 : test_str = m->sender;
342 : : /* FIXME: resolve test_str from a well-known to a unique name first */
343 : 31 : break;
344 : :
345 : 0 : case BUS_MATCH_DESTINATION:
346 : 0 : test_str = m->destination;
347 : 0 : break;
348 : :
349 : 55 : case BUS_MATCH_INTERFACE:
350 : 55 : test_str = m->interface;
351 : 55 : break;
352 : :
353 : 44 : case BUS_MATCH_MEMBER:
354 : 44 : test_str = m->member;
355 : 44 : break;
356 : :
357 : 32 : case BUS_MATCH_PATH:
358 : : case BUS_MATCH_PATH_NAMESPACE:
359 : 32 : test_str = m->path;
360 : 32 : break;
361 : :
362 : 24 : case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
363 : 24 : (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
364 : 24 : break;
365 : :
366 : 4 : case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
367 : 4 : (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
368 : 4 : break;
369 : :
370 : 8 : case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
371 : 8 : (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
372 : 8 : break;
373 : :
374 : 8 : case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
375 : 8 : (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
376 : 8 : break;
377 : :
378 : 0 : default:
379 : 0 : assert_not_reached("Unknown match type.");
380 : : }
381 : :
382 [ + + ]: 285 : if (BUS_MATCH_CAN_HASH(node->type)) {
383 : : struct bus_match_node *found;
384 : :
385 : : /* Lookup via hash table, nice! So let's jump directly. */
386 : :
387 [ + + ]: 234 : if (test_str)
388 : 139 : found = hashmap_get(node->compare.children, test_str);
389 [ + + ]: 95 : else if (test_strv) {
390 : : char **i;
391 : :
392 [ + - + + ]: 32 : STRV_FOREACH(i, test_strv) {
393 : 24 : found = hashmap_get(node->compare.children, *i);
394 [ + - ]: 24 : if (found) {
395 : 24 : r = bus_match_run(bus, found, m);
396 [ - + ]: 24 : if (r != 0)
397 : 0 : return r;
398 : : }
399 : : }
400 : :
401 : 8 : found = NULL;
402 [ + + ]: 87 : } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
403 : 79 : found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
404 : : else
405 : 8 : found = NULL;
406 : :
407 [ + + ]: 234 : if (found) {
408 : 159 : r = bus_match_run(bus, found, m);
409 [ - + ]: 159 : if (r != 0)
410 : 0 : return r;
411 : : }
412 : : } else {
413 : : struct bus_match_node *c;
414 : :
415 : : /* No hash table, so let's iterate manually... */
416 : :
417 [ + + ]: 106 : for (c = node->child; c; c = c->next) {
418 [ + + ]: 59 : if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
419 : 27 : continue;
420 : :
421 : 32 : r = bus_match_run(bus, c, m);
422 [ - + ]: 32 : if (r != 0)
423 : 0 : return r;
424 : :
425 [ + + + + ]: 32 : if (bus && bus->match_callbacks_modified)
426 : 4 : return 0;
427 : : }
428 : : }
429 : :
430 [ + + + + ]: 281 : if (bus && bus->match_callbacks_modified)
431 : 20 : return 0;
432 : :
433 : : /* And now, let's invoke our siblings */
434 : 261 : return bus_match_run(bus, node->next, m);
435 : : }
436 : :
437 : 672 : static int bus_match_add_compare_value(
438 : : struct bus_match_node *where,
439 : : enum bus_match_node_type t,
440 : : uint8_t value_u8,
441 : : const char *value_str,
442 : : struct bus_match_node **ret) {
443 : :
444 : 672 : struct bus_match_node *c = NULL, *n = NULL;
445 : : int r;
446 : :
447 [ - + ]: 672 : assert(where);
448 [ + - - + ]: 672 : assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
449 [ - + ]: 672 : assert(BUS_MATCH_IS_COMPARE(t));
450 [ - + ]: 672 : assert(ret);
451 : :
452 [ + + + + ]: 904 : for (c = where->child; c && c->type != t; c = c->next)
453 : : ;
454 : :
455 [ + + ]: 672 : if (c) {
456 : : /* Comparison node already exists? Then let's see if
457 : : * the value node exists too. */
458 : :
459 [ + + ]: 96 : if (t == BUS_MATCH_MESSAGE_TYPE)
460 : 20 : n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
461 [ + + ]: 76 : else if (BUS_MATCH_CAN_HASH(t))
462 : 56 : n = hashmap_get(c->compare.children, value_str);
463 : : else {
464 [ + + + + ]: 24 : for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
465 : : ;
466 : : }
467 : :
468 [ + + ]: 96 : if (n) {
469 : 64 : *ret = n;
470 : 64 : return 0;
471 : : }
472 : : } else {
473 : : /* Comparison node, doesn't exist yet? Then let's
474 : : * create it. */
475 : :
476 : 576 : c = new0(struct bus_match_node, 1);
477 [ - + ]: 576 : if (!c) {
478 : 0 : r = -ENOMEM;
479 : 0 : goto fail;
480 : : }
481 : :
482 : 576 : c->type = t;
483 : 576 : c->parent = where;
484 : 576 : c->next = where->child;
485 [ + + ]: 576 : if (c->next)
486 : 92 : c->next->prev = c;
487 : 576 : where->child = c;
488 : :
489 [ + + ]: 576 : if (t == BUS_MATCH_MESSAGE_TYPE) {
490 : 116 : c->compare.children = hashmap_new(NULL);
491 [ - + ]: 116 : if (!c->compare.children) {
492 : 0 : r = -ENOMEM;
493 : 0 : goto fail;
494 : : }
495 [ + + ]: 460 : } else if (BUS_MATCH_CAN_HASH(t)) {
496 : 388 : c->compare.children = hashmap_new(&string_hash_ops);
497 [ - + ]: 388 : if (!c->compare.children) {
498 : 0 : r = -ENOMEM;
499 : 0 : goto fail;
500 : : }
501 : : }
502 : : }
503 : :
504 : 608 : n = new0(struct bus_match_node, 1);
505 [ - + ]: 608 : if (!n) {
506 : 0 : r = -ENOMEM;
507 : 0 : goto fail;
508 : : }
509 : :
510 : 608 : n->type = BUS_MATCH_VALUE;
511 : 608 : n->value.u8 = value_u8;
512 [ + + ]: 608 : if (value_str) {
513 : 488 : n->value.str = strdup(value_str);
514 [ - + ]: 488 : if (!n->value.str) {
515 : 0 : r = -ENOMEM;
516 : 0 : goto fail;
517 : : }
518 : : }
519 : :
520 : 608 : n->parent = c;
521 [ + + ]: 608 : if (c->compare.children) {
522 : :
523 [ + + ]: 532 : if (t == BUS_MATCH_MESSAGE_TYPE)
524 : 120 : r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
525 : : else
526 : 412 : r = hashmap_put(c->compare.children, n->value.str, n);
527 : :
528 [ - + ]: 532 : if (r < 0)
529 : 0 : goto fail;
530 : : } else {
531 : 76 : n->next = c->child;
532 [ + + ]: 76 : if (n->next)
533 : 4 : n->next->prev = n;
534 : 76 : c->child = n;
535 : : }
536 : :
537 : 608 : *ret = n;
538 : 608 : return 1;
539 : :
540 : 0 : fail:
541 [ # # ]: 0 : if (c)
542 : 0 : bus_match_node_maybe_free(c);
543 : :
544 [ # # ]: 0 : if (n) {
545 : 0 : free(n->value.str);
546 : 0 : free(n);
547 : : }
548 : :
549 : 0 : return r;
550 : : }
551 : :
552 : 192 : static int bus_match_add_leaf(
553 : : struct bus_match_node *where,
554 : : struct match_callback *callback) {
555 : :
556 : : struct bus_match_node *n;
557 : :
558 [ - + ]: 192 : assert(where);
559 [ + - - + ]: 192 : assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
560 [ - + ]: 192 : assert(callback);
561 : :
562 : 192 : n = new0(struct bus_match_node, 1);
563 [ - + ]: 192 : if (!n)
564 : 0 : return -ENOMEM;
565 : :
566 : 192 : n->type = BUS_MATCH_LEAF;
567 : 192 : n->parent = where;
568 : 192 : n->next = where->child;
569 [ + + ]: 192 : if (n->next)
570 : 4 : n->next->prev = n;
571 : :
572 : 192 : n->leaf.callback = callback;
573 : 192 : callback->match_node = n;
574 : :
575 : 192 : where->child = n;
576 : :
577 : 192 : return 1;
578 : : }
579 : :
580 : 1752 : enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
581 [ - + ]: 1752 : assert(k);
582 : :
583 [ + + + + ]: 1752 : if (n == 4 && startswith(k, "type"))
584 : 140 : return BUS_MATCH_MESSAGE_TYPE;
585 [ + + + + ]: 1612 : if (n == 6 && startswith(k, "sender"))
586 : 84 : return BUS_MATCH_SENDER;
587 [ + + + - ]: 1528 : if (n == 11 && startswith(k, "destination"))
588 : 4 : return BUS_MATCH_DESTINATION;
589 [ + + + + ]: 1524 : if (n == 9 && startswith(k, "interface"))
590 : 156 : return BUS_MATCH_INTERFACE;
591 [ + + + - ]: 1368 : if (n == 6 && startswith(k, "member"))
592 : 144 : return BUS_MATCH_MEMBER;
593 [ + + + + ]: 1224 : if (n == 4 && startswith(k, "path"))
594 : 132 : return BUS_MATCH_PATH;
595 [ + + + + ]: 1092 : if (n == 14 && startswith(k, "path_namespace"))
596 : 12 : return BUS_MATCH_PATH_NAMESPACE;
597 : :
598 [ + + + - ]: 1080 : if (n == 4 && startswith(k, "arg")) {
599 : : int j;
600 : :
601 : 76 : j = undecchar(k[3]);
602 [ - + ]: 76 : if (j < 0)
603 : 0 : return -EINVAL;
604 : :
605 : 76 : return BUS_MATCH_ARG + j;
606 : : }
607 : :
608 [ + + + - ]: 1004 : if (n == 5 && startswith(k, "arg")) {
609 : : int a, b;
610 : : enum bus_match_node_type t;
611 : :
612 : 216 : a = undecchar(k[3]);
613 : 216 : b = undecchar(k[4]);
614 [ + - - + ]: 216 : if (a <= 0 || b < 0)
615 : 0 : return -EINVAL;
616 : :
617 : 216 : t = BUS_MATCH_ARG + a * 10 + b;
618 [ - + ]: 216 : if (t > BUS_MATCH_ARG_LAST)
619 : 0 : return -EINVAL;
620 : :
621 : 216 : return t;
622 : : }
623 : :
624 [ + + + - : 788 : if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
+ + ]
625 : : int j;
626 : :
627 : 44 : j = undecchar(k[3]);
628 [ - + ]: 44 : if (j < 0)
629 : 0 : return -EINVAL;
630 : :
631 : 44 : return BUS_MATCH_ARG_PATH + j;
632 : : }
633 : :
634 [ + + + - : 744 : if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
+ - ]
635 : : enum bus_match_node_type t;
636 : : int a, b;
637 : :
638 : 216 : a = undecchar(k[3]);
639 : 216 : b = undecchar(k[4]);
640 [ + - - + ]: 216 : if (a <= 0 || b < 0)
641 : 0 : return -EINVAL;
642 : :
643 : 216 : t = BUS_MATCH_ARG_PATH + a * 10 + b;
644 [ - + ]: 216 : if (t > BUS_MATCH_ARG_PATH_LAST)
645 : 0 : return -EINVAL;
646 : :
647 : 216 : return t;
648 : : }
649 : :
650 [ + + + - : 528 : if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
+ - ]
651 : : int j;
652 : :
653 : 44 : j = undecchar(k[3]);
654 [ - + ]: 44 : if (j < 0)
655 : 0 : return -EINVAL;
656 : :
657 : 44 : return BUS_MATCH_ARG_NAMESPACE + j;
658 : : }
659 : :
660 [ + + + - : 484 : if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
+ - ]
661 : : enum bus_match_node_type t;
662 : : int a, b;
663 : :
664 : 216 : a = undecchar(k[3]);
665 : 216 : b = undecchar(k[4]);
666 [ + - - + ]: 216 : if (a <= 0 || b < 0)
667 : 0 : return -EINVAL;
668 : :
669 : 216 : t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
670 [ - + ]: 216 : if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
671 : 0 : return -EINVAL;
672 : :
673 : 216 : return t;
674 : : }
675 : :
676 [ + + + - : 268 : if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
+ - ]
677 : : int j;
678 : :
679 : 52 : j = undecchar(k[3]);
680 [ - + ]: 52 : if (j < 0)
681 : 0 : return -EINVAL;
682 : :
683 : 52 : return BUS_MATCH_ARG_HAS + j;
684 : : }
685 : :
686 [ + - + - : 216 : if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
+ - ]
687 : : enum bus_match_node_type t;
688 : : int a, b;
689 : :
690 : 216 : a = undecchar(k[3]);
691 : 216 : b = undecchar(k[4]);
692 [ + - - + ]: 216 : if (a <= 0 || b < 0)
693 : 0 : return -EINVAL;
694 : :
695 : 216 : t = BUS_MATCH_ARG_HAS + a * 10 + b;
696 [ - + ]: 216 : if (t > BUS_MATCH_ARG_HAS_LAST)
697 : 0 : return -EINVAL;
698 : :
699 : 216 : return t;
700 : : }
701 : :
702 : 0 : return -EINVAL;
703 : : }
704 : :
705 : 780 : static int match_component_compare(const struct bus_match_component *a, const struct bus_match_component *b) {
706 [ + + ]: 780 : return CMP(a->type, b->type);
707 : : }
708 : :
709 : 216 : void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
710 : : unsigned i;
711 : :
712 [ + + ]: 920 : for (i = 0; i < n_components; i++)
713 : 704 : free(components[i].value_str);
714 : :
715 : 216 : free(components);
716 : 216 : }
717 : :
718 : 216 : int bus_match_parse(
719 : : const char *match,
720 : : struct bus_match_component **_components,
721 : : unsigned *_n_components) {
722 : :
723 : 216 : const char *p = match;
724 : 216 : struct bus_match_component *components = NULL;
725 : 216 : size_t components_allocated = 0;
726 : 216 : unsigned n_components = 0, i;
727 : 216 : _cleanup_free_ char *value = NULL;
728 : : int r;
729 : :
730 [ - + ]: 216 : assert(match);
731 [ - + ]: 216 : assert(_components);
732 [ - + ]: 216 : assert(_n_components);
733 : :
734 [ + + ]: 728 : while (*p != 0) {
735 : : const char *eq, *q;
736 : : enum bus_match_node_type t;
737 : 704 : unsigned j = 0;
738 : 704 : size_t value_allocated = 0;
739 : 704 : bool escaped = false, quoted;
740 : : uint8_t u;
741 : :
742 : : /* Avahi's match rules appear to include whitespace, skip over it */
743 : 704 : p += strspn(p, " ");
744 : :
745 : 704 : eq = strchr(p, '=');
746 [ - + ]: 704 : if (!eq)
747 : 0 : return -EINVAL;
748 : :
749 : 704 : t = bus_match_node_type_from_string(p, eq - p);
750 [ - + ]: 704 : if (t < 0)
751 : 0 : return -EINVAL;
752 : :
753 : 704 : quoted = eq[1] == '\'';
754 : :
755 : 704 : for (q = eq + 1 + quoted;; q++) {
756 : :
757 [ - + ]: 11776 : if (*q == 0) {
758 : :
759 [ # # ]: 0 : if (quoted) {
760 : 0 : r = -EINVAL;
761 : 0 : goto fail;
762 : : } else {
763 [ # # ]: 0 : if (value)
764 : 0 : value[j] = 0;
765 : 0 : break;
766 : : }
767 : : }
768 : :
769 [ + + ]: 11776 : if (!escaped) {
770 [ + + ]: 11768 : if (*q == '\\') {
771 : 8 : escaped = true;
772 : 8 : continue;
773 : : }
774 : :
775 [ + + ]: 11760 : if (quoted) {
776 [ + + ]: 11736 : if (*q == '\'') {
777 [ + - ]: 700 : if (value)
778 : 700 : value[j] = 0;
779 : 700 : break;
780 : : }
781 : : } else {
782 [ + + ]: 24 : if (*q == ',') {
783 [ + - ]: 4 : if (value)
784 : 4 : value[j] = 0;
785 : :
786 : 4 : break;
787 : : }
788 : : }
789 : : }
790 : :
791 [ - + ]: 11064 : if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
792 : 0 : r = -ENOMEM;
793 : 0 : goto fail;
794 : : }
795 : :
796 : 11064 : value[j++] = *q;
797 : 11064 : escaped = false;
798 : : }
799 : :
800 [ - + ]: 704 : if (!value) {
801 : 0 : value = strdup("");
802 [ # # ]: 0 : if (!value) {
803 : 0 : r = -ENOMEM;
804 : 0 : goto fail;
805 : : }
806 : : }
807 : :
808 [ + + ]: 704 : if (t == BUS_MATCH_MESSAGE_TYPE) {
809 : 136 : r = bus_message_type_from_string(value, &u);
810 [ - + ]: 136 : if (r < 0)
811 : 0 : goto fail;
812 : :
813 : 136 : value = mfree(value);
814 : : } else
815 : 568 : u = 0;
816 : :
817 [ - + ]: 704 : if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
818 : 0 : r = -ENOMEM;
819 : 0 : goto fail;
820 : : }
821 : :
822 : 704 : components[n_components].type = t;
823 : 704 : components[n_components].value_str = TAKE_PTR(value);
824 : 704 : components[n_components].value_u8 = u;
825 : 704 : n_components++;
826 : :
827 [ + + ]: 704 : if (q[quoted] == 0)
828 : 192 : break;
829 : :
830 [ - + ]: 512 : if (q[quoted] != ',') {
831 : 0 : r = -EINVAL;
832 : 0 : goto fail;
833 : : }
834 : :
835 : 512 : p = q + 1 + quoted;
836 : : }
837 : :
838 : : /* Order the whole thing, so that we always generate the same tree */
839 : 216 : typesafe_qsort(components, n_components, match_component_compare);
840 : :
841 : : /* Check for duplicates */
842 [ + + ]: 712 : for (i = 0; i+1 < n_components; i++)
843 [ - + ]: 496 : if (components[i].type == components[i+1].type) {
844 : 0 : r = -EINVAL;
845 : 0 : goto fail;
846 : : }
847 : :
848 : 216 : *_components = components;
849 : 216 : *_n_components = n_components;
850 : :
851 : 216 : return 0;
852 : :
853 : 0 : fail:
854 : 0 : bus_match_parse_free(components, n_components);
855 : 0 : return r;
856 : : }
857 : :
858 : 0 : char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
859 : 0 : _cleanup_fclose_ FILE *f = NULL;
860 : 0 : char *buffer = NULL;
861 : 0 : size_t size = 0;
862 : : unsigned i;
863 : : int r;
864 : :
865 [ # # ]: 0 : if (n_components <= 0)
866 : 0 : return strdup("");
867 : :
868 [ # # ]: 0 : assert(components);
869 : :
870 : 0 : f = open_memstream_unlocked(&buffer, &size);
871 [ # # ]: 0 : if (!f)
872 : 0 : return NULL;
873 : :
874 [ # # ]: 0 : for (i = 0; i < n_components; i++) {
875 : : char buf[32];
876 : :
877 [ # # ]: 0 : if (i != 0)
878 : 0 : fputc(',', f);
879 : :
880 : 0 : fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
881 : 0 : fputc('=', f);
882 : 0 : fputc('\'', f);
883 : :
884 [ # # ]: 0 : if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
885 : 0 : fputs(bus_message_type_to_string(components[i].value_u8), f);
886 : : else
887 : 0 : fputs(components[i].value_str, f);
888 : :
889 : 0 : fputc('\'', f);
890 : : }
891 : :
892 : 0 : r = fflush_and_check(f);
893 [ # # ]: 0 : if (r < 0)
894 : 0 : return NULL;
895 : :
896 : 0 : return buffer;
897 : : }
898 : :
899 : 192 : int bus_match_add(
900 : : struct bus_match_node *root,
901 : : struct bus_match_component *components,
902 : : unsigned n_components,
903 : : struct match_callback *callback) {
904 : :
905 : : unsigned i;
906 : : struct bus_match_node *n;
907 : : int r;
908 : :
909 [ - + ]: 192 : assert(root);
910 [ - + ]: 192 : assert(callback);
911 : :
912 : 192 : n = root;
913 [ + + ]: 864 : for (i = 0; i < n_components; i++) {
914 : 1344 : r = bus_match_add_compare_value(
915 : 672 : n, components[i].type,
916 : 672 : components[i].value_u8, components[i].value_str, &n);
917 [ - + ]: 672 : if (r < 0)
918 : 0 : return r;
919 : : }
920 : :
921 : 192 : return bus_match_add_leaf(n, callback);
922 : : }
923 : :
924 : 128 : int bus_match_remove(
925 : : struct bus_match_node *root,
926 : : struct match_callback *callback) {
927 : :
928 : : struct bus_match_node *node, *pp;
929 : :
930 [ - + ]: 128 : assert(root);
931 [ - + ]: 128 : assert(callback);
932 : :
933 : 128 : node = callback->match_node;
934 [ - + ]: 128 : if (!node)
935 : 0 : return 0;
936 : :
937 [ - + ]: 128 : assert(node->type == BUS_MATCH_LEAF);
938 : :
939 : 128 : callback->match_node = NULL;
940 : :
941 : : /* Free the leaf */
942 : 128 : pp = node->parent;
943 : 128 : bus_match_node_free(node);
944 : :
945 : : /* Prune the tree above */
946 [ + - ]: 1168 : while (pp) {
947 : 1168 : node = pp;
948 : 1168 : pp = node->parent;
949 : :
950 [ + + ]: 1168 : if (!bus_match_node_maybe_free(node))
951 : 128 : break;
952 : : }
953 : :
954 : 128 : return 1;
955 : : }
956 : :
957 : 432 : void bus_match_free(struct bus_match_node *node) {
958 : : struct bus_match_node *c;
959 : :
960 [ - + ]: 432 : if (!node)
961 : 0 : return;
962 : :
963 [ + + ]: 432 : if (BUS_MATCH_CAN_HASH(node->type)) {
964 : : Iterator i;
965 : :
966 [ + + ]: 124 : HASHMAP_FOREACH(c, node->compare.children, i)
967 : 72 : bus_match_free(c);
968 : :
969 [ - + ]: 52 : assert(hashmap_isempty(node->compare.children));
970 : : }
971 : :
972 [ + + ]: 576 : while ((c = node->child))
973 : 144 : bus_match_free(c);
974 : :
975 [ + + ]: 432 : if (node->type != BUS_MATCH_ROOT)
976 : 216 : bus_match_node_free(node);
977 : : }
978 : :
979 : 1568 : const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
980 [ + + + + : 1568 : switch (t) {
+ + + + +
+ + + + +
- ]
981 : :
982 : 16 : case BUS_MATCH_ROOT:
983 : 16 : return "root";
984 : :
985 : 204 : case BUS_MATCH_VALUE:
986 : 204 : return "value";
987 : :
988 : 148 : case BUS_MATCH_LEAF:
989 : 148 : return "leaf";
990 : :
991 : 16 : case BUS_MATCH_MESSAGE_TYPE:
992 : 16 : return "type";
993 : :
994 : 12 : case BUS_MATCH_SENDER:
995 : 12 : return "sender";
996 : :
997 : 4 : case BUS_MATCH_DESTINATION:
998 : 4 : return "destination";
999 : :
1000 : 32 : case BUS_MATCH_INTERFACE:
1001 : 32 : return "interface";
1002 : :
1003 : 20 : case BUS_MATCH_MEMBER:
1004 : 20 : return "member";
1005 : :
1006 : 20 : case BUS_MATCH_PATH:
1007 : 20 : return "path";
1008 : :
1009 : 12 : case BUS_MATCH_PATH_NAMESPACE:
1010 : 12 : return "path_namespace";
1011 : :
1012 : 296 : case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1013 : 296 : snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1014 : 296 : return buf;
1015 : :
1016 : 260 : case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1017 : 260 : snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1018 : 260 : return buf;
1019 : :
1020 : 264 : case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1021 : 264 : snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1022 : 264 : return buf;
1023 : :
1024 : 264 : case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1025 : 264 : snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1026 : 264 : return buf;
1027 : :
1028 : 0 : default:
1029 : 0 : return NULL;
1030 : : }
1031 : : }
1032 : :
1033 : 504 : void bus_match_dump(struct bus_match_node *node, unsigned level) {
1034 : : struct bus_match_node *c;
1035 [ + - ]: 504 : _cleanup_free_ char *pfx = NULL;
1036 : : char buf[32];
1037 : :
1038 [ - + ]: 504 : if (!node)
1039 : 0 : return;
1040 : :
1041 : 504 : pfx = strrep(" ", level);
1042 : 504 : printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1043 : :
1044 [ + + ]: 504 : if (node->type == BUS_MATCH_VALUE) {
1045 [ + + ]: 200 : if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1046 : 20 : printf(" <%u>\n", node->value.u8);
1047 : : else
1048 : 180 : printf(" <%s>\n", node->value.str);
1049 [ + + ]: 304 : } else if (node->type == BUS_MATCH_ROOT)
1050 : 12 : puts(" root");
1051 [ + + ]: 292 : else if (node->type == BUS_MATCH_LEAF)
1052 : 144 : printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1053 : : else
1054 : 148 : putchar('\n');
1055 : :
1056 [ + + ]: 504 : if (BUS_MATCH_CAN_HASH(node->type)) {
1057 : : Iterator i;
1058 : :
1059 [ + + ]: 284 : HASHMAP_FOREACH(c, node->compare.children, i)
1060 : 164 : bus_match_dump(c, level + 1);
1061 : : }
1062 : :
1063 [ + + ]: 832 : for (c = node->child; c; c = c->next)
1064 : 328 : bus_match_dump(c, level + 1);
1065 : : }
1066 : :
1067 : 144 : enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1068 : 144 : bool found_driver = false;
1069 : : unsigned i;
1070 : :
1071 [ + + ]: 144 : if (n_components <= 0)
1072 : 4 : return BUS_MATCH_GENERIC;
1073 : :
1074 [ - + ]: 140 : assert(components);
1075 : :
1076 : : /* Checks whether the specified match can only match the
1077 : : * pseudo-service for local messages, which we detect by
1078 : : * sender, interface or path. If a match is not restricted to
1079 : : * local messages, then we check if it only matches on the
1080 : : * driver. */
1081 : :
1082 [ + + ]: 440 : for (i = 0; i < n_components; i++) {
1083 : 364 : const struct bus_match_component *c = components + i;
1084 : :
1085 [ + + ]: 364 : if (c->type == BUS_MATCH_SENDER) {
1086 [ + + ]: 68 : if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1087 : 56 : return BUS_MATCH_LOCAL;
1088 : :
1089 [ + - ]: 12 : if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1090 : 12 : found_driver = true;
1091 : : }
1092 : :
1093 [ + + + + ]: 308 : if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1094 : 4 : return BUS_MATCH_LOCAL;
1095 : :
1096 [ + + + + ]: 304 : if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1097 : 4 : return BUS_MATCH_LOCAL;
1098 : : }
1099 : :
1100 [ + + ]: 76 : return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
1101 : :
1102 : : }
|