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