2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "bus-internal.h"
22 #include "bus-match.h"
23 #include "bus-message.h"
27 #include "hexdecoct.h"
28 #include "string-util.h"
33 * A: type=signal,sender=foo,interface=bar
34 * B: type=signal,sender=quux,interface=fips
35 * C: type=signal,sender=quux,interface=waldo
36 * D: type=signal,member=test
41 * results in this tree:
44 * + BUS_MATCH_MESSAGE_TYPE
45 * | ` BUS_MATCH_VALUE: value == signal
46 * | + DBUS_MATCH_SENDER
47 * | | + BUS_MATCH_VALUE: value == foo
48 * | | | ` DBUS_MATCH_INTERFACE
49 * | | | ` BUS_MATCH_VALUE: value == bar
50 * | | | ` BUS_MATCH_LEAF: A
51 * | | ` BUS_MATCH_VALUE: value == quux
52 * | | ` DBUS_MATCH_INTERFACE
53 * | | | BUS_MATCH_VALUE: value == fips
54 * | | | ` BUS_MATCH_LEAF: B
55 * | | ` BUS_MATCH_VALUE: value == waldo
56 * | | ` BUS_MATCH_LEAF: C
57 * | + DBUS_MATCH_MEMBER
58 * | | ` BUS_MATCH_VALUE: value == test
59 * | | ` BUS_MATCH_LEAF: D
60 * | + BUS_MATCH_LEAF: F
61 * | ` BUS_MATCH_LEAF: G
63 * ` BUS_MATCH_VALUE: value == miau
67 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
68 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
71 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
72 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
73 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
74 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
77 static void bus_match_node_free(struct bus_match_node
*node
) {
81 assert(node
->type
!= BUS_MATCH_ROOT
);
82 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
84 if (node
->parent
->child
) {
85 /* We are apparently linked into the parent's child
86 * list. Let's remove us from there. */
88 assert(node
->prev
->next
== node
);
89 node
->prev
->next
= node
->next
;
91 assert(node
->parent
->child
== node
);
92 node
->parent
->child
= node
->next
;
96 node
->next
->prev
= node
->prev
;
99 if (node
->type
== BUS_MATCH_VALUE
) {
100 /* We might be in the parent's hash table, so clean
103 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
104 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
105 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
106 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
108 free(node
->value
.str
);
111 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
112 assert(hashmap_isempty(node
->compare
.children
));
113 hashmap_free(node
->compare
.children
);
119 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
122 if (node
->type
== BUS_MATCH_ROOT
)
128 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
131 bus_match_node_free(node
);
135 static bool value_node_test(
136 struct bus_match_node
*node
,
137 enum bus_match_node_type parent_type
,
139 const char *value_str
,
144 assert(node
->type
== BUS_MATCH_VALUE
);
146 /* Tests parameters against this value node, doing prefix
147 * magic and stuff. */
149 switch (parent_type
) {
151 case BUS_MATCH_MESSAGE_TYPE
:
152 return node
->value
.u8
== value_u8
;
154 case BUS_MATCH_SENDER
:
155 if (streq_ptr(node
->value
.str
, value_str
))
158 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
161 /* on kdbus we have the well known names list
162 * in the credentials, let's make use of that
163 * for an accurate match */
165 STRV_FOREACH(i
, m
->creds
.well_known_names
)
166 if (streq_ptr(node
->value
.str
, *i
))
171 /* If we don't have kdbus, we don't know the
172 * well-known names of the senders. In that,
173 * let's just hope that dbus-daemon doesn't
174 * send us stuff we didn't want. */
176 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
182 case BUS_MATCH_DESTINATION
:
183 case BUS_MATCH_INTERFACE
:
184 case BUS_MATCH_MEMBER
:
186 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
189 return streq_ptr(node
->value
.str
, value_str
);
193 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
196 STRV_FOREACH(i
, value_strv
)
197 if (streq_ptr(node
->value
.str
, *i
))
203 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
205 return namespace_simple_pattern(node
->value
.str
, value_str
);
209 case BUS_MATCH_PATH_NAMESPACE
:
210 return path_simple_pattern(node
->value
.str
, value_str
);
212 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
214 return path_complex_pattern(node
->value
.str
, value_str
);
219 assert_not_reached("Invalid node type");
223 static bool value_node_same(
224 struct bus_match_node
*node
,
225 enum bus_match_node_type parent_type
,
227 const char *value_str
) {
229 /* Tests parameters against this value node, not doing prefix
230 * magic and stuff, i.e. this one actually compares the match
234 assert(node
->type
== BUS_MATCH_VALUE
);
236 switch (parent_type
) {
238 case BUS_MATCH_MESSAGE_TYPE
:
239 return node
->value
.u8
== value_u8
;
241 case BUS_MATCH_SENDER
:
242 case BUS_MATCH_DESTINATION
:
243 case BUS_MATCH_INTERFACE
:
244 case BUS_MATCH_MEMBER
:
246 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
247 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
248 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
249 case BUS_MATCH_PATH_NAMESPACE
:
250 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
251 return streq(node
->value
.str
, value_str
);
254 assert_not_reached("Invalid node type");
260 struct bus_match_node
*node
,
263 _cleanup_strv_free_
char **test_strv
= NULL
;
264 const char *test_str
= NULL
;
273 if (bus
&& bus
->match_callbacks_modified
)
276 /* Not these special semantics: when traversing the tree we
277 * usually let bus_match_run() when called for a node
278 * recursively invoke bus_match_run(). There's are two
279 * exceptions here though, which are BUS_NODE_ROOT (which
280 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
281 * are invoked anyway by its parent. */
283 switch (node
->type
) {
287 /* Run all children. Since we cannot have any siblings
288 * we won't call any. The children of the root node
289 * are compares or leaves, they will automatically
290 * call their siblings. */
291 return bus_match_run(bus
, node
->child
, m
);
293 case BUS_MATCH_VALUE
:
295 /* Run all children. We don't execute any siblings, we
296 * assume our caller does that. The children of value
297 * nodes are compares or leaves, they will
298 * automatically call their siblings */
301 return bus_match_run(bus
, node
->child
, m
);
306 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
309 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
312 r
= sd_bus_message_rewind(m
, true);
316 /* Run the callback. And then invoke siblings. */
317 if (node
->leaf
.callback
->callback
) {
318 _cleanup_(sd_bus_error_free
) sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
321 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
323 bus
->current_slot
= sd_bus_slot_ref(slot
);
324 bus
->current_handler
= node
->leaf
.callback
->callback
;
325 bus
->current_userdata
= slot
->userdata
;
327 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
329 bus
->current_userdata
= NULL
;
330 bus
->current_handler
= NULL
;
331 bus
->current_slot
= sd_bus_slot_unref(slot
);
334 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
338 if (bus
&& bus
->match_callbacks_modified
)
342 return bus_match_run(bus
, node
->next
, m
);
344 case BUS_MATCH_MESSAGE_TYPE
:
345 test_u8
= m
->header
->type
;
348 case BUS_MATCH_SENDER
:
349 test_str
= m
->sender
;
350 /* FIXME: resolve test_str from a well-known to a unique name first */
353 case BUS_MATCH_DESTINATION
:
354 test_str
= m
->destination
;
357 case BUS_MATCH_INTERFACE
:
358 test_str
= m
->interface
;
361 case BUS_MATCH_MEMBER
:
362 test_str
= m
->member
;
366 case BUS_MATCH_PATH_NAMESPACE
:
370 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
371 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
374 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
375 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
378 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
379 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
382 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
383 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
387 assert_not_reached("Unknown match type.");
390 if (BUS_MATCH_CAN_HASH(node
->type
)) {
391 struct bus_match_node
*found
;
393 /* Lookup via hash table, nice! So let's jump directly. */
396 found
= hashmap_get(node
->compare
.children
, test_str
);
397 else if (test_strv
) {
400 STRV_FOREACH(i
, test_strv
) {
401 found
= hashmap_get(node
->compare
.children
, *i
);
403 r
= bus_match_run(bus
, found
, m
);
410 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
411 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
416 r
= bus_match_run(bus
, found
, m
);
421 struct bus_match_node
*c
;
423 /* No hash table, so let's iterate manually... */
425 for (c
= node
->child
; c
; c
= c
->next
) {
426 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
429 r
= bus_match_run(bus
, c
, m
);
433 if (bus
&& bus
->match_callbacks_modified
)
438 if (bus
&& bus
->match_callbacks_modified
)
441 /* And now, let's invoke our siblings */
442 return bus_match_run(bus
, node
->next
, m
);
445 static int bus_match_add_compare_value(
446 struct bus_match_node
*where
,
447 enum bus_match_node_type t
,
449 const char *value_str
,
450 struct bus_match_node
**ret
) {
452 struct bus_match_node
*c
= NULL
, *n
= NULL
;
456 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
457 assert(BUS_MATCH_IS_COMPARE(t
));
460 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
464 /* Comparison node already exists? Then let's see if
465 * the value node exists too. */
467 if (t
== BUS_MATCH_MESSAGE_TYPE
)
468 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
469 else if (BUS_MATCH_CAN_HASH(t
))
470 n
= hashmap_get(c
->compare
.children
, value_str
);
472 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
481 /* Comparison node, doesn't exist yet? Then let's
484 c
= new0(struct bus_match_node
, 1);
492 c
->next
= where
->child
;
497 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
498 c
->compare
.children
= hashmap_new(NULL
);
499 if (!c
->compare
.children
) {
503 } else if (BUS_MATCH_CAN_HASH(t
)) {
504 c
->compare
.children
= hashmap_new(&string_hash_ops
);
505 if (!c
->compare
.children
) {
512 n
= new0(struct bus_match_node
, 1);
518 n
->type
= BUS_MATCH_VALUE
;
519 n
->value
.u8
= value_u8
;
521 n
->value
.str
= strdup(value_str
);
529 if (c
->compare
.children
) {
531 if (t
== BUS_MATCH_MESSAGE_TYPE
)
532 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
534 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
550 bus_match_node_maybe_free(c
);
560 static int bus_match_find_compare_value(
561 struct bus_match_node
*where
,
562 enum bus_match_node_type t
,
564 const char *value_str
,
565 struct bus_match_node
**ret
) {
567 struct bus_match_node
*c
, *n
;
570 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
571 assert(BUS_MATCH_IS_COMPARE(t
));
574 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
580 if (t
== BUS_MATCH_MESSAGE_TYPE
)
581 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
582 else if (BUS_MATCH_CAN_HASH(t
))
583 n
= hashmap_get(c
->compare
.children
, value_str
);
585 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
597 static int bus_match_add_leaf(
598 struct bus_match_node
*where
,
599 struct match_callback
*callback
) {
601 struct bus_match_node
*n
;
604 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
607 n
= new0(struct bus_match_node
, 1);
611 n
->type
= BUS_MATCH_LEAF
;
613 n
->next
= where
->child
;
617 n
->leaf
.callback
= callback
;
618 callback
->match_node
= n
;
625 static int bus_match_find_leaf(
626 struct bus_match_node
*where
,
627 sd_bus_message_handler_t callback
,
629 struct bus_match_node
**ret
) {
631 struct bus_match_node
*c
;
634 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
637 for (c
= where
->child
; c
; c
= c
->next
) {
640 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
642 if (c
->type
== BUS_MATCH_LEAF
&&
643 c
->leaf
.callback
->callback
== callback
&&
644 s
->userdata
== userdata
) {
653 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
656 if (n
== 4 && startswith(k
, "type"))
657 return BUS_MATCH_MESSAGE_TYPE
;
658 if (n
== 6 && startswith(k
, "sender"))
659 return BUS_MATCH_SENDER
;
660 if (n
== 11 && startswith(k
, "destination"))
661 return BUS_MATCH_DESTINATION
;
662 if (n
== 9 && startswith(k
, "interface"))
663 return BUS_MATCH_INTERFACE
;
664 if (n
== 6 && startswith(k
, "member"))
665 return BUS_MATCH_MEMBER
;
666 if (n
== 4 && startswith(k
, "path"))
667 return BUS_MATCH_PATH
;
668 if (n
== 14 && startswith(k
, "path_namespace"))
669 return BUS_MATCH_PATH_NAMESPACE
;
671 if (n
== 4 && startswith(k
, "arg")) {
678 return BUS_MATCH_ARG
+ j
;
681 if (n
== 5 && startswith(k
, "arg")) {
683 enum bus_match_node_type t
;
690 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
691 if (t
> BUS_MATCH_ARG_LAST
)
697 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
704 return BUS_MATCH_ARG_PATH
+ j
;
707 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
708 enum bus_match_node_type t
;
716 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
717 if (t
> BUS_MATCH_ARG_PATH_LAST
)
723 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
730 return BUS_MATCH_ARG_NAMESPACE
+ j
;
733 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
734 enum bus_match_node_type t
;
742 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
743 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
749 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
756 return BUS_MATCH_ARG_HAS
+ j
;
759 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
760 enum bus_match_node_type t
;
768 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
769 if (t
> BUS_MATCH_ARG_HAS_LAST
)
778 static int match_component_compare(const void *a
, const void *b
) {
779 const struct bus_match_component
*x
= a
, *y
= b
;
781 if (x
->type
< y
->type
)
783 if (x
->type
> y
->type
)
789 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
792 for (i
= 0; i
< n_components
; i
++)
793 free(components
[i
].value_str
);
800 struct bus_match_component
**_components
,
801 unsigned *_n_components
) {
803 const char *p
= match
;
804 struct bus_match_component
*components
= NULL
;
805 size_t components_allocated
= 0;
806 unsigned n_components
= 0, i
;
807 _cleanup_free_
char *value
= NULL
;
812 assert(_n_components
);
816 enum bus_match_node_type t
;
818 size_t value_allocated
= 0;
819 bool escaped
= false, quoted
;
822 /* Avahi's match rules appear to include whitespace, skip over it */
829 t
= bus_match_node_type_from_string(p
, eq
- p
);
833 quoted
= eq
[1] == '\'';
835 for (q
= eq
+ 1 + quoted
;; q
++) {
871 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
888 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
889 r
= bus_message_type_from_string(value
, &u
);
893 value
= mfree(value
);
897 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
902 components
[n_components
].type
= t
;
903 components
[n_components
].value_str
= value
;
904 components
[n_components
].value_u8
= u
;
912 if (q
[quoted
] != ',') {
920 /* Order the whole thing, so that we always generate the same tree */
921 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
923 /* Check for duplicates */
924 for (i
= 0; i
+1 < n_components
; i
++)
925 if (components
[i
].type
== components
[i
+1].type
) {
930 *_components
= components
;
931 *_n_components
= n_components
;
936 bus_match_parse_free(components
, n_components
);
940 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
941 _cleanup_fclose_
FILE *f
= NULL
;
947 if (n_components
<= 0)
952 f
= open_memstream(&buffer
, &size
);
956 for (i
= 0; i
< n_components
; i
++) {
960 fputc_unlocked(',', f
);
962 fputs_unlocked(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
963 fputc_unlocked('=', f
);
964 fputc_unlocked('\'', f
);
966 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
967 fputs_unlocked(bus_message_type_to_string(components
[i
].value_u8
), f
);
969 fputs_unlocked(components
[i
].value_str
, f
);
971 fputc_unlocked('\'', f
);
974 r
= fflush_and_check(f
);
982 struct bus_match_node
*root
,
983 struct bus_match_component
*components
,
984 unsigned n_components
,
985 struct match_callback
*callback
) {
988 struct bus_match_node
*n
;
995 for (i
= 0; i
< n_components
; i
++) {
996 r
= bus_match_add_compare_value(
997 n
, components
[i
].type
,
998 components
[i
].value_u8
, components
[i
].value_str
, &n
);
1003 return bus_match_add_leaf(n
, callback
);
1006 int bus_match_remove(
1007 struct bus_match_node
*root
,
1008 struct match_callback
*callback
) {
1010 struct bus_match_node
*node
, *pp
;
1015 node
= callback
->match_node
;
1019 assert(node
->type
== BUS_MATCH_LEAF
);
1021 callback
->match_node
= NULL
;
1025 bus_match_node_free(node
);
1027 /* Prune the tree above */
1032 if (!bus_match_node_maybe_free(node
))
1040 struct bus_match_node
*root
,
1041 struct bus_match_component
*components
,
1042 unsigned n_components
,
1043 sd_bus_message_handler_t callback
,
1045 struct match_callback
**ret
) {
1047 struct bus_match_node
*n
, **gc
;
1054 gc
= newa(struct bus_match_node
*, n_components
);
1057 for (i
= 0; i
< n_components
; i
++) {
1058 r
= bus_match_find_compare_value(
1059 n
, components
[i
].type
,
1060 components
[i
].value_u8
, components
[i
].value_str
,
1068 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1072 *ret
= n
->leaf
.callback
;
1076 void bus_match_free(struct bus_match_node
*node
) {
1077 struct bus_match_node
*c
;
1082 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1085 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1088 assert(hashmap_isempty(node
->compare
.children
));
1091 while ((c
= node
->child
))
1094 if (node
->type
!= BUS_MATCH_ROOT
)
1095 bus_match_node_free(node
);
1098 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1101 case BUS_MATCH_ROOT
:
1104 case BUS_MATCH_VALUE
:
1107 case BUS_MATCH_LEAF
:
1110 case BUS_MATCH_MESSAGE_TYPE
:
1113 case BUS_MATCH_SENDER
:
1116 case BUS_MATCH_DESTINATION
:
1117 return "destination";
1119 case BUS_MATCH_INTERFACE
:
1122 case BUS_MATCH_MEMBER
:
1125 case BUS_MATCH_PATH
:
1128 case BUS_MATCH_PATH_NAMESPACE
:
1129 return "path_namespace";
1131 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1132 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1135 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1136 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1139 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1140 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1143 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1144 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1152 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1153 struct bus_match_node
*c
;
1154 _cleanup_free_
char *pfx
= NULL
;
1160 pfx
= strrep(" ", level
);
1161 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1163 if (node
->type
== BUS_MATCH_VALUE
) {
1164 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1165 printf(" <%u>\n", node
->value
.u8
);
1167 printf(" <%s>\n", node
->value
.str
);
1168 } else if (node
->type
== BUS_MATCH_ROOT
)
1170 else if (node
->type
== BUS_MATCH_LEAF
)
1171 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1175 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1178 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1179 bus_match_dump(c
, level
+ 1);
1182 for (c
= node
->child
; c
; c
= c
->next
)
1183 bus_match_dump(c
, level
+ 1);
1186 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1187 bool found_driver
= false;
1190 if (n_components
<= 0)
1191 return BUS_MATCH_GENERIC
;
1195 /* Checks whether the specified match can only match the
1196 * pseudo-service for local messages, which we detect by
1197 * sender, interface or path. If a match is not restricted to
1198 * local messages, then we check if it only matches on the
1201 for (i
= 0; i
< n_components
; i
++) {
1202 const struct bus_match_component
*c
= components
+ i
;
1204 if (c
->type
== BUS_MATCH_SENDER
) {
1205 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1206 return BUS_MATCH_LOCAL
;
1208 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1209 found_driver
= true;
1212 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1213 return BUS_MATCH_LOCAL
;
1215 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1216 return BUS_MATCH_LOCAL
;
1219 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;