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