1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <stdio_ext.h>
23 #include "alloc-util.h"
24 #include "bus-internal.h"
25 #include "bus-match.h"
26 #include "bus-message.h"
30 #include "hexdecoct.h"
31 #include "string-util.h"
36 * A: type=signal,sender=foo,interface=bar
37 * B: type=signal,sender=quux,interface=fips
38 * C: type=signal,sender=quux,interface=waldo
39 * D: type=signal,member=test
44 * results in this tree:
47 * + BUS_MATCH_MESSAGE_TYPE
48 * | ` BUS_MATCH_VALUE: value == signal
49 * | + DBUS_MATCH_SENDER
50 * | | + BUS_MATCH_VALUE: value == foo
51 * | | | ` DBUS_MATCH_INTERFACE
52 * | | | ` BUS_MATCH_VALUE: value == bar
53 * | | | ` BUS_MATCH_LEAF: A
54 * | | ` BUS_MATCH_VALUE: value == quux
55 * | | ` DBUS_MATCH_INTERFACE
56 * | | | BUS_MATCH_VALUE: value == fips
57 * | | | ` BUS_MATCH_LEAF: B
58 * | | ` BUS_MATCH_VALUE: value == waldo
59 * | | ` BUS_MATCH_LEAF: C
60 * | + DBUS_MATCH_MEMBER
61 * | | ` BUS_MATCH_VALUE: value == test
62 * | | ` BUS_MATCH_LEAF: D
63 * | + BUS_MATCH_LEAF: F
64 * | ` BUS_MATCH_LEAF: G
66 * ` BUS_MATCH_VALUE: value == miau
70 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
71 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
74 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
75 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
76 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
77 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
80 static void bus_match_node_free(struct bus_match_node
*node
) {
84 assert(node
->type
!= BUS_MATCH_ROOT
);
85 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
87 if (node
->parent
->child
) {
88 /* We are apparently linked into the parent's child
89 * list. Let's remove us from there. */
91 assert(node
->prev
->next
== node
);
92 node
->prev
->next
= node
->next
;
94 assert(node
->parent
->child
== node
);
95 node
->parent
->child
= node
->next
;
99 node
->next
->prev
= node
->prev
;
102 if (node
->type
== BUS_MATCH_VALUE
) {
103 /* We might be in the parent's hash table, so clean
106 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
107 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
108 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
109 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
111 free(node
->value
.str
);
114 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
115 assert(hashmap_isempty(node
->compare
.children
));
116 hashmap_free(node
->compare
.children
);
122 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
125 if (node
->type
== BUS_MATCH_ROOT
)
131 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
134 bus_match_node_free(node
);
138 static bool value_node_test(
139 struct bus_match_node
*node
,
140 enum bus_match_node_type parent_type
,
142 const char *value_str
,
147 assert(node
->type
== BUS_MATCH_VALUE
);
149 /* Tests parameters against this value node, doing prefix
150 * magic and stuff. */
152 switch (parent_type
) {
154 case BUS_MATCH_MESSAGE_TYPE
:
155 return node
->value
.u8
== value_u8
;
157 case BUS_MATCH_SENDER
:
158 if (streq_ptr(node
->value
.str
, value_str
))
161 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
164 /* on kdbus we have the well known names list
165 * in the credentials, let's make use of that
166 * for an accurate match */
168 STRV_FOREACH(i
, m
->creds
.well_known_names
)
169 if (streq_ptr(node
->value
.str
, *i
))
174 /* If we don't have kdbus, we don't know the
175 * well-known names of the senders. In that,
176 * let's just hope that dbus-daemon doesn't
177 * send us stuff we didn't want. */
179 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
185 case BUS_MATCH_DESTINATION
:
186 case BUS_MATCH_INTERFACE
:
187 case BUS_MATCH_MEMBER
:
189 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
192 return streq_ptr(node
->value
.str
, value_str
);
196 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
199 STRV_FOREACH(i
, value_strv
)
200 if (streq_ptr(node
->value
.str
, *i
))
206 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
208 return namespace_simple_pattern(node
->value
.str
, value_str
);
212 case BUS_MATCH_PATH_NAMESPACE
:
213 return path_simple_pattern(node
->value
.str
, value_str
);
215 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
217 return path_complex_pattern(node
->value
.str
, value_str
);
222 assert_not_reached("Invalid node type");
226 static bool value_node_same(
227 struct bus_match_node
*node
,
228 enum bus_match_node_type parent_type
,
230 const char *value_str
) {
232 /* Tests parameters against this value node, not doing prefix
233 * magic and stuff, i.e. this one actually compares the match
237 assert(node
->type
== BUS_MATCH_VALUE
);
239 switch (parent_type
) {
241 case BUS_MATCH_MESSAGE_TYPE
:
242 return node
->value
.u8
== value_u8
;
244 case BUS_MATCH_SENDER
:
245 case BUS_MATCH_DESTINATION
:
246 case BUS_MATCH_INTERFACE
:
247 case BUS_MATCH_MEMBER
:
249 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
250 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
251 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
252 case BUS_MATCH_PATH_NAMESPACE
:
253 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
254 return streq(node
->value
.str
, value_str
);
257 assert_not_reached("Invalid node type");
263 struct bus_match_node
*node
,
266 _cleanup_strv_free_
char **test_strv
= NULL
;
267 const char *test_str
= NULL
;
276 if (bus
&& bus
->match_callbacks_modified
)
279 /* Not these special semantics: when traversing the tree we
280 * usually let bus_match_run() when called for a node
281 * recursively invoke bus_match_run(). There's are two
282 * exceptions here though, which are BUS_NODE_ROOT (which
283 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
284 * are invoked anyway by its parent. */
286 switch (node
->type
) {
290 /* Run all children. Since we cannot have any siblings
291 * we won't call any. The children of the root node
292 * are compares or leaves, they will automatically
293 * call their siblings. */
294 return bus_match_run(bus
, node
->child
, m
);
296 case BUS_MATCH_VALUE
:
298 /* Run all children. We don't execute any siblings, we
299 * assume our caller does that. The children of value
300 * nodes are compares or leaves, they will
301 * automatically call their siblings */
304 return bus_match_run(bus
, node
->child
, m
);
309 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
312 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
315 r
= sd_bus_message_rewind(m
, true);
319 /* Run the callback. And then invoke siblings. */
320 if (node
->leaf
.callback
->callback
) {
321 _cleanup_(sd_bus_error_free
) sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
324 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
326 bus
->current_slot
= sd_bus_slot_ref(slot
);
327 bus
->current_handler
= node
->leaf
.callback
->callback
;
328 bus
->current_userdata
= slot
->userdata
;
330 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
332 bus
->current_userdata
= NULL
;
333 bus
->current_handler
= NULL
;
334 bus
->current_slot
= sd_bus_slot_unref(slot
);
337 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
341 if (bus
&& bus
->match_callbacks_modified
)
345 return bus_match_run(bus
, node
->next
, m
);
347 case BUS_MATCH_MESSAGE_TYPE
:
348 test_u8
= m
->header
->type
;
351 case BUS_MATCH_SENDER
:
352 test_str
= m
->sender
;
353 /* FIXME: resolve test_str from a well-known to a unique name first */
356 case BUS_MATCH_DESTINATION
:
357 test_str
= m
->destination
;
360 case BUS_MATCH_INTERFACE
:
361 test_str
= m
->interface
;
364 case BUS_MATCH_MEMBER
:
365 test_str
= m
->member
;
369 case BUS_MATCH_PATH_NAMESPACE
:
373 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
374 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
377 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
378 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
381 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
382 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
385 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
386 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
390 assert_not_reached("Unknown match type.");
393 if (BUS_MATCH_CAN_HASH(node
->type
)) {
394 struct bus_match_node
*found
;
396 /* Lookup via hash table, nice! So let's jump directly. */
399 found
= hashmap_get(node
->compare
.children
, test_str
);
400 else if (test_strv
) {
403 STRV_FOREACH(i
, test_strv
) {
404 found
= hashmap_get(node
->compare
.children
, *i
);
406 r
= bus_match_run(bus
, found
, m
);
413 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
414 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
419 r
= bus_match_run(bus
, found
, m
);
424 struct bus_match_node
*c
;
426 /* No hash table, so let's iterate manually... */
428 for (c
= node
->child
; c
; c
= c
->next
) {
429 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
432 r
= bus_match_run(bus
, c
, m
);
436 if (bus
&& bus
->match_callbacks_modified
)
441 if (bus
&& bus
->match_callbacks_modified
)
444 /* And now, let's invoke our siblings */
445 return bus_match_run(bus
, node
->next
, m
);
448 static int bus_match_add_compare_value(
449 struct bus_match_node
*where
,
450 enum bus_match_node_type t
,
452 const char *value_str
,
453 struct bus_match_node
**ret
) {
455 struct bus_match_node
*c
= NULL
, *n
= NULL
;
459 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
460 assert(BUS_MATCH_IS_COMPARE(t
));
463 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
467 /* Comparison node already exists? Then let's see if
468 * the value node exists too. */
470 if (t
== BUS_MATCH_MESSAGE_TYPE
)
471 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
472 else if (BUS_MATCH_CAN_HASH(t
))
473 n
= hashmap_get(c
->compare
.children
, value_str
);
475 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
484 /* Comparison node, doesn't exist yet? Then let's
487 c
= new0(struct bus_match_node
, 1);
495 c
->next
= where
->child
;
500 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
501 c
->compare
.children
= hashmap_new(NULL
);
502 if (!c
->compare
.children
) {
506 } else if (BUS_MATCH_CAN_HASH(t
)) {
507 c
->compare
.children
= hashmap_new(&string_hash_ops
);
508 if (!c
->compare
.children
) {
515 n
= new0(struct bus_match_node
, 1);
521 n
->type
= BUS_MATCH_VALUE
;
522 n
->value
.u8
= value_u8
;
524 n
->value
.str
= strdup(value_str
);
532 if (c
->compare
.children
) {
534 if (t
== BUS_MATCH_MESSAGE_TYPE
)
535 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
537 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
553 bus_match_node_maybe_free(c
);
563 static int bus_match_find_compare_value(
564 struct bus_match_node
*where
,
565 enum bus_match_node_type t
,
567 const char *value_str
,
568 struct bus_match_node
**ret
) {
570 struct bus_match_node
*c
, *n
;
573 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
574 assert(BUS_MATCH_IS_COMPARE(t
));
577 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
583 if (t
== BUS_MATCH_MESSAGE_TYPE
)
584 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
585 else if (BUS_MATCH_CAN_HASH(t
))
586 n
= hashmap_get(c
->compare
.children
, value_str
);
588 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
600 static int bus_match_add_leaf(
601 struct bus_match_node
*where
,
602 struct match_callback
*callback
) {
604 struct bus_match_node
*n
;
607 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
610 n
= new0(struct bus_match_node
, 1);
614 n
->type
= BUS_MATCH_LEAF
;
616 n
->next
= where
->child
;
620 n
->leaf
.callback
= callback
;
621 callback
->match_node
= n
;
628 static int bus_match_find_leaf(
629 struct bus_match_node
*where
,
630 sd_bus_message_handler_t callback
,
632 struct bus_match_node
**ret
) {
634 struct bus_match_node
*c
;
637 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
640 for (c
= where
->child
; c
; c
= c
->next
) {
643 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
645 if (c
->type
== BUS_MATCH_LEAF
&&
646 c
->leaf
.callback
->callback
== callback
&&
647 s
->userdata
== userdata
) {
656 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
659 if (n
== 4 && startswith(k
, "type"))
660 return BUS_MATCH_MESSAGE_TYPE
;
661 if (n
== 6 && startswith(k
, "sender"))
662 return BUS_MATCH_SENDER
;
663 if (n
== 11 && startswith(k
, "destination"))
664 return BUS_MATCH_DESTINATION
;
665 if (n
== 9 && startswith(k
, "interface"))
666 return BUS_MATCH_INTERFACE
;
667 if (n
== 6 && startswith(k
, "member"))
668 return BUS_MATCH_MEMBER
;
669 if (n
== 4 && startswith(k
, "path"))
670 return BUS_MATCH_PATH
;
671 if (n
== 14 && startswith(k
, "path_namespace"))
672 return BUS_MATCH_PATH_NAMESPACE
;
674 if (n
== 4 && startswith(k
, "arg")) {
681 return BUS_MATCH_ARG
+ j
;
684 if (n
== 5 && startswith(k
, "arg")) {
686 enum bus_match_node_type t
;
693 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
694 if (t
> BUS_MATCH_ARG_LAST
)
700 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
707 return BUS_MATCH_ARG_PATH
+ j
;
710 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
711 enum bus_match_node_type t
;
719 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
720 if (t
> BUS_MATCH_ARG_PATH_LAST
)
726 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
733 return BUS_MATCH_ARG_NAMESPACE
+ j
;
736 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
737 enum bus_match_node_type t
;
745 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
746 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
752 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
759 return BUS_MATCH_ARG_HAS
+ j
;
762 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
763 enum bus_match_node_type t
;
771 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
772 if (t
> BUS_MATCH_ARG_HAS_LAST
)
781 static int match_component_compare(const void *a
, const void *b
) {
782 const struct bus_match_component
*x
= a
, *y
= b
;
784 if (x
->type
< y
->type
)
786 if (x
->type
> y
->type
)
792 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
795 for (i
= 0; i
< n_components
; i
++)
796 free(components
[i
].value_str
);
803 struct bus_match_component
**_components
,
804 unsigned *_n_components
) {
806 const char *p
= match
;
807 struct bus_match_component
*components
= NULL
;
808 size_t components_allocated
= 0;
809 unsigned n_components
= 0, i
;
810 _cleanup_free_
char *value
= NULL
;
815 assert(_n_components
);
819 enum bus_match_node_type t
;
821 size_t value_allocated
= 0;
822 bool escaped
= false, quoted
;
825 /* Avahi's match rules appear to include whitespace, skip over it */
832 t
= bus_match_node_type_from_string(p
, eq
- p
);
836 quoted
= eq
[1] == '\'';
838 for (q
= eq
+ 1 + quoted
;; q
++) {
874 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
891 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
892 r
= bus_message_type_from_string(value
, &u
);
896 value
= mfree(value
);
900 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
905 components
[n_components
].type
= t
;
906 components
[n_components
].value_str
= value
;
907 components
[n_components
].value_u8
= u
;
915 if (q
[quoted
] != ',') {
923 /* Order the whole thing, so that we always generate the same tree */
924 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
926 /* Check for duplicates */
927 for (i
= 0; i
+1 < n_components
; i
++)
928 if (components
[i
].type
== components
[i
+1].type
) {
933 *_components
= components
;
934 *_n_components
= n_components
;
939 bus_match_parse_free(components
, n_components
);
943 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
944 _cleanup_fclose_
FILE *f
= NULL
;
950 if (n_components
<= 0)
955 f
= open_memstream(&buffer
, &size
);
959 __fsetlocking(f
, FSETLOCKING_BYCALLER
);
961 for (i
= 0; i
< n_components
; i
++) {
967 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
971 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
972 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
974 fputs(components
[i
].value_str
, f
);
979 r
= fflush_and_check(f
);
987 struct bus_match_node
*root
,
988 struct bus_match_component
*components
,
989 unsigned n_components
,
990 struct match_callback
*callback
) {
993 struct bus_match_node
*n
;
1000 for (i
= 0; i
< n_components
; i
++) {
1001 r
= bus_match_add_compare_value(
1002 n
, components
[i
].type
,
1003 components
[i
].value_u8
, components
[i
].value_str
, &n
);
1008 return bus_match_add_leaf(n
, callback
);
1011 int bus_match_remove(
1012 struct bus_match_node
*root
,
1013 struct match_callback
*callback
) {
1015 struct bus_match_node
*node
, *pp
;
1020 node
= callback
->match_node
;
1024 assert(node
->type
== BUS_MATCH_LEAF
);
1026 callback
->match_node
= NULL
;
1030 bus_match_node_free(node
);
1032 /* Prune the tree above */
1037 if (!bus_match_node_maybe_free(node
))
1045 struct bus_match_node
*root
,
1046 struct bus_match_component
*components
,
1047 unsigned n_components
,
1048 sd_bus_message_handler_t callback
,
1050 struct match_callback
**ret
) {
1052 struct bus_match_node
*n
, **gc
;
1059 gc
= newa(struct bus_match_node
*, n_components
);
1062 for (i
= 0; i
< n_components
; i
++) {
1063 r
= bus_match_find_compare_value(
1064 n
, components
[i
].type
,
1065 components
[i
].value_u8
, components
[i
].value_str
,
1073 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1077 *ret
= n
->leaf
.callback
;
1081 void bus_match_free(struct bus_match_node
*node
) {
1082 struct bus_match_node
*c
;
1087 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1090 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1093 assert(hashmap_isempty(node
->compare
.children
));
1096 while ((c
= node
->child
))
1099 if (node
->type
!= BUS_MATCH_ROOT
)
1100 bus_match_node_free(node
);
1103 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1106 case BUS_MATCH_ROOT
:
1109 case BUS_MATCH_VALUE
:
1112 case BUS_MATCH_LEAF
:
1115 case BUS_MATCH_MESSAGE_TYPE
:
1118 case BUS_MATCH_SENDER
:
1121 case BUS_MATCH_DESTINATION
:
1122 return "destination";
1124 case BUS_MATCH_INTERFACE
:
1127 case BUS_MATCH_MEMBER
:
1130 case BUS_MATCH_PATH
:
1133 case BUS_MATCH_PATH_NAMESPACE
:
1134 return "path_namespace";
1136 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1137 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1140 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1141 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1144 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1145 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1148 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1149 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1157 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1158 struct bus_match_node
*c
;
1159 _cleanup_free_
char *pfx
= NULL
;
1165 pfx
= strrep(" ", level
);
1166 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1168 if (node
->type
== BUS_MATCH_VALUE
) {
1169 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1170 printf(" <%u>\n", node
->value
.u8
);
1172 printf(" <%s>\n", node
->value
.str
);
1173 } else if (node
->type
== BUS_MATCH_ROOT
)
1175 else if (node
->type
== BUS_MATCH_LEAF
)
1176 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1180 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1183 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1184 bus_match_dump(c
, level
+ 1);
1187 for (c
= node
->child
; c
; c
= c
->next
)
1188 bus_match_dump(c
, level
+ 1);
1191 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1192 bool found_driver
= false;
1195 if (n_components
<= 0)
1196 return BUS_MATCH_GENERIC
;
1200 /* Checks whether the specified match can only match the
1201 * pseudo-service for local messages, which we detect by
1202 * sender, interface or path. If a match is not restricted to
1203 * local messages, then we check if it only matches on the
1206 for (i
= 0; i
< n_components
; i
++) {
1207 const struct bus_match_component
*c
= components
+ i
;
1209 if (c
->type
== BUS_MATCH_SENDER
) {
1210 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1211 return BUS_MATCH_LOCAL
;
1213 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1214 found_driver
= true;
1217 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1218 return BUS_MATCH_LOCAL
;
1220 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1221 return BUS_MATCH_LOCAL
;
1224 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;