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