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