1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2013 Lennart Poettering
8 #include "alloc-util.h"
9 #include "bus-internal.h"
10 #include "bus-match.h"
11 #include "bus-message.h"
15 #include "hexdecoct.h"
16 #include "string-util.h"
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
29 * results in this tree:
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
51 * ` BUS_MATCH_VALUE: value == miau
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
;
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
);
65 static void bus_match_node_free(struct bus_match_node
*node
) {
69 assert(node
->type
!= BUS_MATCH_ROOT
);
70 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
72 if (node
->parent
->child
) {
73 /* We are apparently linked into the parent's child
74 * list. Let's remove us from there. */
76 assert(node
->prev
->next
== node
);
77 node
->prev
->next
= node
->next
;
79 assert(node
->parent
->child
== node
);
80 node
->parent
->child
= node
->next
;
84 node
->next
->prev
= node
->prev
;
87 if (node
->type
== BUS_MATCH_VALUE
) {
88 /* We might be in the parent's hash table, so clean
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
);
96 free(node
->value
.str
);
99 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
100 assert(hashmap_isempty(node
->compare
.children
));
101 hashmap_free(node
->compare
.children
);
107 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
110 if (node
->type
== BUS_MATCH_ROOT
)
116 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
119 bus_match_node_free(node
);
123 static bool value_node_test(
124 struct bus_match_node
*node
,
125 enum bus_match_node_type parent_type
,
127 const char *value_str
,
132 assert(node
->type
== BUS_MATCH_VALUE
);
134 /* Tests parameters against this value node, doing prefix
135 * magic and stuff. */
137 switch (parent_type
) {
139 case BUS_MATCH_MESSAGE_TYPE
:
140 return node
->value
.u8
== value_u8
;
142 case BUS_MATCH_SENDER
:
143 if (streq_ptr(node
->value
.str
, value_str
))
146 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
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 */
153 STRV_FOREACH(i
, m
->creds
.well_known_names
)
154 if (streq_ptr(node
->value
.str
, *i
))
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. */
164 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
170 case BUS_MATCH_DESTINATION
:
171 case BUS_MATCH_INTERFACE
:
172 case BUS_MATCH_MEMBER
:
174 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
177 return streq_ptr(node
->value
.str
, value_str
);
181 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
184 STRV_FOREACH(i
, value_strv
)
185 if (streq_ptr(node
->value
.str
, *i
))
191 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
193 return namespace_simple_pattern(node
->value
.str
, value_str
);
197 case BUS_MATCH_PATH_NAMESPACE
:
198 return path_simple_pattern(node
->value
.str
, value_str
);
200 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
202 return path_complex_pattern(node
->value
.str
, value_str
);
207 assert_not_reached("Invalid node type");
211 static bool value_node_same(
212 struct bus_match_node
*node
,
213 enum bus_match_node_type parent_type
,
215 const char *value_str
) {
217 /* Tests parameters against this value node, not doing prefix
218 * magic and stuff, i.e. this one actually compares the match
222 assert(node
->type
== BUS_MATCH_VALUE
);
224 switch (parent_type
) {
226 case BUS_MATCH_MESSAGE_TYPE
:
227 return node
->value
.u8
== value_u8
;
229 case BUS_MATCH_SENDER
:
230 case BUS_MATCH_DESTINATION
:
231 case BUS_MATCH_INTERFACE
:
232 case BUS_MATCH_MEMBER
:
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
);
242 assert_not_reached("Invalid node type");
248 struct bus_match_node
*node
,
251 _cleanup_strv_free_
char **test_strv
= NULL
;
252 const char *test_str
= NULL
;
261 if (bus
&& bus
->match_callbacks_modified
)
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. */
271 switch (node
->type
) {
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
);
281 case BUS_MATCH_VALUE
:
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 */
289 return bus_match_run(bus
, node
->child
, m
);
294 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
297 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
300 r
= sd_bus_message_rewind(m
, true);
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
;
309 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
311 bus
->current_slot
= sd_bus_slot_ref(slot
);
312 bus
->current_handler
= node
->leaf
.callback
->callback
;
313 bus
->current_userdata
= slot
->userdata
;
315 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
317 bus
->current_userdata
= NULL
;
318 bus
->current_handler
= NULL
;
319 bus
->current_slot
= sd_bus_slot_unref(slot
);
322 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
326 if (bus
&& bus
->match_callbacks_modified
)
330 return bus_match_run(bus
, node
->next
, m
);
332 case BUS_MATCH_MESSAGE_TYPE
:
333 test_u8
= m
->header
->type
;
336 case BUS_MATCH_SENDER
:
337 test_str
= m
->sender
;
338 /* FIXME: resolve test_str from a well-known to a unique name first */
341 case BUS_MATCH_DESTINATION
:
342 test_str
= m
->destination
;
345 case BUS_MATCH_INTERFACE
:
346 test_str
= m
->interface
;
349 case BUS_MATCH_MEMBER
:
350 test_str
= m
->member
;
354 case BUS_MATCH_PATH_NAMESPACE
:
358 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
359 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
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
);
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
);
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
);
375 assert_not_reached("Unknown match type.");
378 if (BUS_MATCH_CAN_HASH(node
->type
)) {
379 struct bus_match_node
*found
;
381 /* Lookup via hash table, nice! So let's jump directly. */
384 found
= hashmap_get(node
->compare
.children
, test_str
);
385 else if (test_strv
) {
388 STRV_FOREACH(i
, test_strv
) {
389 found
= hashmap_get(node
->compare
.children
, *i
);
391 r
= bus_match_run(bus
, found
, m
);
398 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
399 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
404 r
= bus_match_run(bus
, found
, m
);
409 struct bus_match_node
*c
;
411 /* No hash table, so let's iterate manually... */
413 for (c
= node
->child
; c
; c
= c
->next
) {
414 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
417 r
= bus_match_run(bus
, c
, m
);
421 if (bus
&& bus
->match_callbacks_modified
)
426 if (bus
&& bus
->match_callbacks_modified
)
429 /* And now, let's invoke our siblings */
430 return bus_match_run(bus
, node
->next
, m
);
433 static int bus_match_add_compare_value(
434 struct bus_match_node
*where
,
435 enum bus_match_node_type t
,
437 const char *value_str
,
438 struct bus_match_node
**ret
) {
440 struct bus_match_node
*c
= NULL
, *n
= NULL
;
444 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
445 assert(BUS_MATCH_IS_COMPARE(t
));
448 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
452 /* Comparison node already exists? Then let's see if
453 * the value node exists too. */
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
);
460 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
469 /* Comparison node, doesn't exist yet? Then let's
472 c
= new0(struct bus_match_node
, 1);
480 c
->next
= where
->child
;
485 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
486 c
->compare
.children
= hashmap_new(NULL
);
487 if (!c
->compare
.children
) {
491 } else if (BUS_MATCH_CAN_HASH(t
)) {
492 c
->compare
.children
= hashmap_new(&string_hash_ops
);
493 if (!c
->compare
.children
) {
500 n
= new0(struct bus_match_node
, 1);
506 n
->type
= BUS_MATCH_VALUE
;
507 n
->value
.u8
= value_u8
;
509 n
->value
.str
= strdup(value_str
);
517 if (c
->compare
.children
) {
519 if (t
== BUS_MATCH_MESSAGE_TYPE
)
520 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
522 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
538 bus_match_node_maybe_free(c
);
548 static int bus_match_find_compare_value(
549 struct bus_match_node
*where
,
550 enum bus_match_node_type t
,
552 const char *value_str
,
553 struct bus_match_node
**ret
) {
555 struct bus_match_node
*c
, *n
;
558 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
559 assert(BUS_MATCH_IS_COMPARE(t
));
562 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
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
);
573 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
585 static int bus_match_add_leaf(
586 struct bus_match_node
*where
,
587 struct match_callback
*callback
) {
589 struct bus_match_node
*n
;
592 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
595 n
= new0(struct bus_match_node
, 1);
599 n
->type
= BUS_MATCH_LEAF
;
601 n
->next
= where
->child
;
605 n
->leaf
.callback
= callback
;
606 callback
->match_node
= n
;
613 static int bus_match_find_leaf(
614 struct bus_match_node
*where
,
615 sd_bus_message_handler_t callback
,
617 struct bus_match_node
**ret
) {
619 struct bus_match_node
*c
;
622 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
625 for (c
= where
->child
; c
; c
= c
->next
) {
628 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
630 if (c
->type
== BUS_MATCH_LEAF
&&
631 c
->leaf
.callback
->callback
== callback
&&
632 s
->userdata
== userdata
) {
641 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
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
;
659 if (n
== 4 && startswith(k
, "arg")) {
666 return BUS_MATCH_ARG
+ j
;
669 if (n
== 5 && startswith(k
, "arg")) {
671 enum bus_match_node_type t
;
678 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
679 if (t
> BUS_MATCH_ARG_LAST
)
685 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
692 return BUS_MATCH_ARG_PATH
+ j
;
695 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
696 enum bus_match_node_type t
;
704 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
705 if (t
> BUS_MATCH_ARG_PATH_LAST
)
711 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
718 return BUS_MATCH_ARG_NAMESPACE
+ j
;
721 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
722 enum bus_match_node_type t
;
730 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
731 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
737 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
744 return BUS_MATCH_ARG_HAS
+ j
;
747 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
748 enum bus_match_node_type t
;
756 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
757 if (t
> BUS_MATCH_ARG_HAS_LAST
)
766 static int match_component_compare(const void *a
, const void *b
) {
767 const struct bus_match_component
*x
= a
, *y
= b
;
769 if (x
->type
< y
->type
)
771 if (x
->type
> y
->type
)
777 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
780 for (i
= 0; i
< n_components
; i
++)
781 free(components
[i
].value_str
);
788 struct bus_match_component
**_components
,
789 unsigned *_n_components
) {
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
;
800 assert(_n_components
);
804 enum bus_match_node_type t
;
806 size_t value_allocated
= 0;
807 bool escaped
= false, quoted
;
810 /* Avahi's match rules appear to include whitespace, skip over it */
817 t
= bus_match_node_type_from_string(p
, eq
- p
);
821 quoted
= eq
[1] == '\'';
823 for (q
= eq
+ 1 + quoted
;; q
++) {
859 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
876 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
877 r
= bus_message_type_from_string(value
, &u
);
881 value
= mfree(value
);
885 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
890 components
[n_components
].type
= t
;
891 components
[n_components
].value_str
= TAKE_PTR(value
);
892 components
[n_components
].value_u8
= u
;
898 if (q
[quoted
] != ',') {
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
);
909 /* Check for duplicates */
910 for (i
= 0; i
+1 < n_components
; i
++)
911 if (components
[i
].type
== components
[i
+1].type
) {
916 *_components
= components
;
917 *_n_components
= n_components
;
922 bus_match_parse_free(components
, n_components
);
926 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
927 _cleanup_fclose_
FILE *f
= NULL
;
933 if (n_components
<= 0)
938 f
= open_memstream(&buffer
, &size
);
942 __fsetlocking(f
, FSETLOCKING_BYCALLER
);
944 for (i
= 0; i
< n_components
; i
++) {
950 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
954 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
955 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
957 fputs(components
[i
].value_str
, f
);
962 r
= fflush_and_check(f
);
970 struct bus_match_node
*root
,
971 struct bus_match_component
*components
,
972 unsigned n_components
,
973 struct match_callback
*callback
) {
976 struct bus_match_node
*n
;
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
);
991 return bus_match_add_leaf(n
, callback
);
994 int bus_match_remove(
995 struct bus_match_node
*root
,
996 struct match_callback
*callback
) {
998 struct bus_match_node
*node
, *pp
;
1003 node
= callback
->match_node
;
1007 assert(node
->type
== BUS_MATCH_LEAF
);
1009 callback
->match_node
= NULL
;
1013 bus_match_node_free(node
);
1015 /* Prune the tree above */
1020 if (!bus_match_node_maybe_free(node
))
1028 struct bus_match_node
*root
,
1029 struct bus_match_component
*components
,
1030 unsigned n_components
,
1031 sd_bus_message_handler_t callback
,
1033 struct match_callback
**ret
) {
1035 struct bus_match_node
*n
, **gc
;
1042 gc
= newa(struct bus_match_node
*, n_components
);
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
,
1056 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1060 *ret
= n
->leaf
.callback
;
1064 void bus_match_free(struct bus_match_node
*node
) {
1065 struct bus_match_node
*c
;
1070 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1073 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1076 assert(hashmap_isempty(node
->compare
.children
));
1079 while ((c
= node
->child
))
1082 if (node
->type
!= BUS_MATCH_ROOT
)
1083 bus_match_node_free(node
);
1086 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1089 case BUS_MATCH_ROOT
:
1092 case BUS_MATCH_VALUE
:
1095 case BUS_MATCH_LEAF
:
1098 case BUS_MATCH_MESSAGE_TYPE
:
1101 case BUS_MATCH_SENDER
:
1104 case BUS_MATCH_DESTINATION
:
1105 return "destination";
1107 case BUS_MATCH_INTERFACE
:
1110 case BUS_MATCH_MEMBER
:
1113 case BUS_MATCH_PATH
:
1116 case BUS_MATCH_PATH_NAMESPACE
:
1117 return "path_namespace";
1119 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1120 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1123 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1124 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1127 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1128 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1131 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1132 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1140 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1141 struct bus_match_node
*c
;
1142 _cleanup_free_
char *pfx
= NULL
;
1148 pfx
= strrep(" ", level
);
1149 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1151 if (node
->type
== BUS_MATCH_VALUE
) {
1152 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1153 printf(" <%u>\n", node
->value
.u8
);
1155 printf(" <%s>\n", node
->value
.str
);
1156 } else if (node
->type
== BUS_MATCH_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
);
1163 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1166 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1167 bus_match_dump(c
, level
+ 1);
1170 for (c
= node
->child
; c
; c
= c
->next
)
1171 bus_match_dump(c
, level
+ 1);
1174 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1175 bool found_driver
= false;
1178 if (n_components
<= 0)
1179 return BUS_MATCH_GENERIC
;
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
1189 for (i
= 0; i
< n_components
; i
++) {
1190 const struct bus_match_component
*c
= components
+ i
;
1192 if (c
->type
== BUS_MATCH_SENDER
) {
1193 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1194 return BUS_MATCH_LOCAL
;
1196 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1197 found_driver
= true;
1200 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1201 return BUS_MATCH_LOCAL
;
1203 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1204 return BUS_MATCH_LOCAL
;
1207 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;