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 "alloc-util.h"
22 #include "bus-internal.h"
23 #include "bus-match.h"
24 #include "bus-message.h"
28 #include "hexdecoct.h"
29 #include "string-util.h"
34 * A: type=signal,sender=foo,interface=bar
35 * B: type=signal,sender=quux,interface=fips
36 * C: type=signal,sender=quux,interface=waldo
37 * D: type=signal,member=test
42 * results in this tree:
45 * + BUS_MATCH_MESSAGE_TYPE
46 * | ` BUS_MATCH_VALUE: value == signal
47 * | + DBUS_MATCH_SENDER
48 * | | + BUS_MATCH_VALUE: value == foo
49 * | | | ` DBUS_MATCH_INTERFACE
50 * | | | ` BUS_MATCH_VALUE: value == bar
51 * | | | ` BUS_MATCH_LEAF: A
52 * | | ` BUS_MATCH_VALUE: value == quux
53 * | | ` DBUS_MATCH_INTERFACE
54 * | | | BUS_MATCH_VALUE: value == fips
55 * | | | ` BUS_MATCH_LEAF: B
56 * | | ` BUS_MATCH_VALUE: value == waldo
57 * | | ` BUS_MATCH_LEAF: C
58 * | + DBUS_MATCH_MEMBER
59 * | | ` BUS_MATCH_VALUE: value == test
60 * | | ` BUS_MATCH_LEAF: D
61 * | + BUS_MATCH_LEAF: F
62 * | ` BUS_MATCH_LEAF: G
64 * ` BUS_MATCH_VALUE: value == miau
68 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
69 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
72 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
73 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
74 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
75 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
78 static void bus_match_node_free(struct bus_match_node
*node
) {
82 assert(node
->type
!= BUS_MATCH_ROOT
);
83 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
85 if (node
->parent
->child
) {
86 /* We are apparently linked into the parent's child
87 * list. Let's remove us from there. */
89 assert(node
->prev
->next
== node
);
90 node
->prev
->next
= node
->next
;
92 assert(node
->parent
->child
== node
);
93 node
->parent
->child
= node
->next
;
97 node
->next
->prev
= node
->prev
;
100 if (node
->type
== BUS_MATCH_VALUE
) {
101 /* We might be in the parent's hash table, so clean
104 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
105 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
106 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
107 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
109 free(node
->value
.str
);
112 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
113 assert(hashmap_isempty(node
->compare
.children
));
114 hashmap_free(node
->compare
.children
);
120 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
123 if (node
->type
== BUS_MATCH_ROOT
)
129 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
132 bus_match_node_free(node
);
136 static bool value_node_test(
137 struct bus_match_node
*node
,
138 enum bus_match_node_type parent_type
,
140 const char *value_str
,
145 assert(node
->type
== BUS_MATCH_VALUE
);
147 /* Tests parameters against this value node, doing prefix
148 * magic and stuff. */
150 switch (parent_type
) {
152 case BUS_MATCH_MESSAGE_TYPE
:
153 return node
->value
.u8
== value_u8
;
155 case BUS_MATCH_SENDER
:
156 if (streq_ptr(node
->value
.str
, value_str
))
159 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
162 /* on kdbus we have the well known names list
163 * in the credentials, let's make use of that
164 * for an accurate match */
166 STRV_FOREACH(i
, m
->creds
.well_known_names
)
167 if (streq_ptr(node
->value
.str
, *i
))
172 /* If we don't have kdbus, we don't know the
173 * well-known names of the senders. In that,
174 * let's just hope that dbus-daemon doesn't
175 * send us stuff we didn't want. */
177 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
183 case BUS_MATCH_DESTINATION
:
184 case BUS_MATCH_INTERFACE
:
185 case BUS_MATCH_MEMBER
:
187 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
190 return streq_ptr(node
->value
.str
, value_str
);
194 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
197 STRV_FOREACH(i
, value_strv
)
198 if (streq_ptr(node
->value
.str
, *i
))
204 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
206 return namespace_simple_pattern(node
->value
.str
, value_str
);
210 case BUS_MATCH_PATH_NAMESPACE
:
211 return path_simple_pattern(node
->value
.str
, value_str
);
213 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
215 return path_complex_pattern(node
->value
.str
, value_str
);
220 assert_not_reached("Invalid node type");
224 static bool value_node_same(
225 struct bus_match_node
*node
,
226 enum bus_match_node_type parent_type
,
228 const char *value_str
) {
230 /* Tests parameters against this value node, not doing prefix
231 * magic and stuff, i.e. this one actually compares the match
235 assert(node
->type
== BUS_MATCH_VALUE
);
237 switch (parent_type
) {
239 case BUS_MATCH_MESSAGE_TYPE
:
240 return node
->value
.u8
== value_u8
;
242 case BUS_MATCH_SENDER
:
243 case BUS_MATCH_DESTINATION
:
244 case BUS_MATCH_INTERFACE
:
245 case BUS_MATCH_MEMBER
:
247 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
248 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
249 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
250 case BUS_MATCH_PATH_NAMESPACE
:
251 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
252 return streq(node
->value
.str
, value_str
);
255 assert_not_reached("Invalid node type");
261 struct bus_match_node
*node
,
264 _cleanup_strv_free_
char **test_strv
= NULL
;
265 const char *test_str
= NULL
;
274 if (bus
&& bus
->match_callbacks_modified
)
277 /* Not these special semantics: when traversing the tree we
278 * usually let bus_match_run() when called for a node
279 * recursively invoke bus_match_run(). There's are two
280 * exceptions here though, which are BUS_NODE_ROOT (which
281 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
282 * are invoked anyway by its parent. */
284 switch (node
->type
) {
288 /* Run all children. Since we cannot have any siblings
289 * we won't call any. The children of the root node
290 * are compares or leaves, they will automatically
291 * call their siblings. */
292 return bus_match_run(bus
, node
->child
, m
);
294 case BUS_MATCH_VALUE
:
296 /* Run all children. We don't execute any siblings, we
297 * assume our caller does that. The children of value
298 * nodes are compares or leaves, they will
299 * automatically call their siblings */
302 return bus_match_run(bus
, node
->child
, m
);
307 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
310 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
313 r
= sd_bus_message_rewind(m
, true);
317 /* Run the callback. And then invoke siblings. */
318 if (node
->leaf
.callback
->callback
) {
319 _cleanup_(sd_bus_error_free
) sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
322 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
324 bus
->current_slot
= sd_bus_slot_ref(slot
);
325 bus
->current_handler
= node
->leaf
.callback
->callback
;
326 bus
->current_userdata
= slot
->userdata
;
328 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
330 bus
->current_userdata
= NULL
;
331 bus
->current_handler
= NULL
;
332 bus
->current_slot
= sd_bus_slot_unref(slot
);
335 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
339 if (bus
&& bus
->match_callbacks_modified
)
343 return bus_match_run(bus
, node
->next
, m
);
345 case BUS_MATCH_MESSAGE_TYPE
:
346 test_u8
= m
->header
->type
;
349 case BUS_MATCH_SENDER
:
350 test_str
= m
->sender
;
351 /* FIXME: resolve test_str from a well-known to a unique name first */
354 case BUS_MATCH_DESTINATION
:
355 test_str
= m
->destination
;
358 case BUS_MATCH_INTERFACE
:
359 test_str
= m
->interface
;
362 case BUS_MATCH_MEMBER
:
363 test_str
= m
->member
;
367 case BUS_MATCH_PATH_NAMESPACE
:
371 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
372 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
375 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
376 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
379 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
380 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
383 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
384 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
388 assert_not_reached("Unknown match type.");
391 if (BUS_MATCH_CAN_HASH(node
->type
)) {
392 struct bus_match_node
*found
;
394 /* Lookup via hash table, nice! So let's jump directly. */
397 found
= hashmap_get(node
->compare
.children
, test_str
);
398 else if (test_strv
) {
401 STRV_FOREACH(i
, test_strv
) {
402 found
= hashmap_get(node
->compare
.children
, *i
);
404 r
= bus_match_run(bus
, found
, m
);
411 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
412 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
417 r
= bus_match_run(bus
, found
, m
);
422 struct bus_match_node
*c
;
424 /* No hash table, so let's iterate manually... */
426 for (c
= node
->child
; c
; c
= c
->next
) {
427 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
430 r
= bus_match_run(bus
, c
, m
);
434 if (bus
&& bus
->match_callbacks_modified
)
439 if (bus
&& bus
->match_callbacks_modified
)
442 /* And now, let's invoke our siblings */
443 return bus_match_run(bus
, node
->next
, m
);
446 static int bus_match_add_compare_value(
447 struct bus_match_node
*where
,
448 enum bus_match_node_type t
,
450 const char *value_str
,
451 struct bus_match_node
**ret
) {
453 struct bus_match_node
*c
= NULL
, *n
= NULL
;
457 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
458 assert(BUS_MATCH_IS_COMPARE(t
));
461 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
465 /* Comparison node already exists? Then let's see if
466 * the value node exists too. */
468 if (t
== BUS_MATCH_MESSAGE_TYPE
)
469 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
470 else if (BUS_MATCH_CAN_HASH(t
))
471 n
= hashmap_get(c
->compare
.children
, value_str
);
473 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
482 /* Comparison node, doesn't exist yet? Then let's
485 c
= new0(struct bus_match_node
, 1);
493 c
->next
= where
->child
;
498 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
499 c
->compare
.children
= hashmap_new(NULL
);
500 if (!c
->compare
.children
) {
504 } else if (BUS_MATCH_CAN_HASH(t
)) {
505 c
->compare
.children
= hashmap_new(&string_hash_ops
);
506 if (!c
->compare
.children
) {
513 n
= new0(struct bus_match_node
, 1);
519 n
->type
= BUS_MATCH_VALUE
;
520 n
->value
.u8
= value_u8
;
522 n
->value
.str
= strdup(value_str
);
530 if (c
->compare
.children
) {
532 if (t
== BUS_MATCH_MESSAGE_TYPE
)
533 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
535 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
551 bus_match_node_maybe_free(c
);
561 static int bus_match_find_compare_value(
562 struct bus_match_node
*where
,
563 enum bus_match_node_type t
,
565 const char *value_str
,
566 struct bus_match_node
**ret
) {
568 struct bus_match_node
*c
, *n
;
571 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
572 assert(BUS_MATCH_IS_COMPARE(t
));
575 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
581 if (t
== BUS_MATCH_MESSAGE_TYPE
)
582 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
583 else if (BUS_MATCH_CAN_HASH(t
))
584 n
= hashmap_get(c
->compare
.children
, value_str
);
586 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
598 static int bus_match_add_leaf(
599 struct bus_match_node
*where
,
600 struct match_callback
*callback
) {
602 struct bus_match_node
*n
;
605 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
608 n
= new0(struct bus_match_node
, 1);
612 n
->type
= BUS_MATCH_LEAF
;
614 n
->next
= where
->child
;
618 n
->leaf
.callback
= callback
;
619 callback
->match_node
= n
;
626 static int bus_match_find_leaf(
627 struct bus_match_node
*where
,
628 sd_bus_message_handler_t callback
,
630 struct bus_match_node
**ret
) {
632 struct bus_match_node
*c
;
635 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
638 for (c
= where
->child
; c
; c
= c
->next
) {
641 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
643 if (c
->type
== BUS_MATCH_LEAF
&&
644 c
->leaf
.callback
->callback
== callback
&&
645 s
->userdata
== userdata
) {
654 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
657 if (n
== 4 && startswith(k
, "type"))
658 return BUS_MATCH_MESSAGE_TYPE
;
659 if (n
== 6 && startswith(k
, "sender"))
660 return BUS_MATCH_SENDER
;
661 if (n
== 11 && startswith(k
, "destination"))
662 return BUS_MATCH_DESTINATION
;
663 if (n
== 9 && startswith(k
, "interface"))
664 return BUS_MATCH_INTERFACE
;
665 if (n
== 6 && startswith(k
, "member"))
666 return BUS_MATCH_MEMBER
;
667 if (n
== 4 && startswith(k
, "path"))
668 return BUS_MATCH_PATH
;
669 if (n
== 14 && startswith(k
, "path_namespace"))
670 return BUS_MATCH_PATH_NAMESPACE
;
672 if (n
== 4 && startswith(k
, "arg")) {
679 return BUS_MATCH_ARG
+ j
;
682 if (n
== 5 && startswith(k
, "arg")) {
684 enum bus_match_node_type t
;
691 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
692 if (t
> BUS_MATCH_ARG_LAST
)
698 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
705 return BUS_MATCH_ARG_PATH
+ j
;
708 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
709 enum bus_match_node_type t
;
717 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
718 if (t
> BUS_MATCH_ARG_PATH_LAST
)
724 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
731 return BUS_MATCH_ARG_NAMESPACE
+ j
;
734 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
735 enum bus_match_node_type t
;
743 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
744 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
750 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
757 return BUS_MATCH_ARG_HAS
+ j
;
760 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
761 enum bus_match_node_type t
;
769 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
770 if (t
> BUS_MATCH_ARG_HAS_LAST
)
779 static int match_component_compare(const void *a
, const void *b
) {
780 const struct bus_match_component
*x
= a
, *y
= b
;
782 if (x
->type
< y
->type
)
784 if (x
->type
> y
->type
)
790 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
793 for (i
= 0; i
< n_components
; i
++)
794 free(components
[i
].value_str
);
801 struct bus_match_component
**_components
,
802 unsigned *_n_components
) {
804 const char *p
= match
;
805 struct bus_match_component
*components
= NULL
;
806 size_t components_allocated
= 0;
807 unsigned n_components
= 0, i
;
808 _cleanup_free_
char *value
= NULL
;
813 assert(_n_components
);
817 enum bus_match_node_type t
;
819 size_t value_allocated
= 0;
820 bool escaped
= false, quoted
;
823 /* Avahi's match rules appear to include whitespace, skip over it */
830 t
= bus_match_node_type_from_string(p
, eq
- p
);
834 quoted
= eq
[1] == '\'';
836 for (q
= eq
+ 1 + quoted
;; q
++) {
872 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
889 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
890 r
= bus_message_type_from_string(value
, &u
);
894 value
= mfree(value
);
898 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
903 components
[n_components
].type
= t
;
904 components
[n_components
].value_str
= value
;
905 components
[n_components
].value_u8
= u
;
913 if (q
[quoted
] != ',') {
921 /* Order the whole thing, so that we always generate the same tree */
922 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
924 /* Check for duplicates */
925 for (i
= 0; i
+1 < n_components
; i
++)
926 if (components
[i
].type
== components
[i
+1].type
) {
931 *_components
= components
;
932 *_n_components
= n_components
;
937 bus_match_parse_free(components
, n_components
);
941 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
942 _cleanup_fclose_
FILE *f
= NULL
;
948 if (n_components
<= 0)
953 f
= open_memstream(&buffer
, &size
);
957 for (i
= 0; i
< n_components
; i
++) {
961 fputc_unlocked(',', f
);
963 fputs_unlocked(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
964 fputc_unlocked('=', f
);
965 fputc_unlocked('\'', f
);
967 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
968 fputs_unlocked(bus_message_type_to_string(components
[i
].value_u8
), f
);
970 fputs_unlocked(components
[i
].value_str
, f
);
972 fputc_unlocked('\'', f
);
975 r
= fflush_and_check(f
);
983 struct bus_match_node
*root
,
984 struct bus_match_component
*components
,
985 unsigned n_components
,
986 struct match_callback
*callback
) {
989 struct bus_match_node
*n
;
996 for (i
= 0; i
< n_components
; i
++) {
997 r
= bus_match_add_compare_value(
998 n
, components
[i
].type
,
999 components
[i
].value_u8
, components
[i
].value_str
, &n
);
1004 return bus_match_add_leaf(n
, callback
);
1007 int bus_match_remove(
1008 struct bus_match_node
*root
,
1009 struct match_callback
*callback
) {
1011 struct bus_match_node
*node
, *pp
;
1016 node
= callback
->match_node
;
1020 assert(node
->type
== BUS_MATCH_LEAF
);
1022 callback
->match_node
= NULL
;
1026 bus_match_node_free(node
);
1028 /* Prune the tree above */
1033 if (!bus_match_node_maybe_free(node
))
1041 struct bus_match_node
*root
,
1042 struct bus_match_component
*components
,
1043 unsigned n_components
,
1044 sd_bus_message_handler_t callback
,
1046 struct match_callback
**ret
) {
1048 struct bus_match_node
*n
, **gc
;
1055 gc
= newa(struct bus_match_node
*, n_components
);
1058 for (i
= 0; i
< n_components
; i
++) {
1059 r
= bus_match_find_compare_value(
1060 n
, components
[i
].type
,
1061 components
[i
].value_u8
, components
[i
].value_str
,
1069 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1073 *ret
= n
->leaf
.callback
;
1077 void bus_match_free(struct bus_match_node
*node
) {
1078 struct bus_match_node
*c
;
1083 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1086 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1089 assert(hashmap_isempty(node
->compare
.children
));
1092 while ((c
= node
->child
))
1095 if (node
->type
!= BUS_MATCH_ROOT
)
1096 bus_match_node_free(node
);
1099 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1102 case BUS_MATCH_ROOT
:
1105 case BUS_MATCH_VALUE
:
1108 case BUS_MATCH_LEAF
:
1111 case BUS_MATCH_MESSAGE_TYPE
:
1114 case BUS_MATCH_SENDER
:
1117 case BUS_MATCH_DESTINATION
:
1118 return "destination";
1120 case BUS_MATCH_INTERFACE
:
1123 case BUS_MATCH_MEMBER
:
1126 case BUS_MATCH_PATH
:
1129 case BUS_MATCH_PATH_NAMESPACE
:
1130 return "path_namespace";
1132 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1133 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1136 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1137 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1140 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1141 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1144 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1145 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1153 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1154 struct bus_match_node
*c
;
1155 _cleanup_free_
char *pfx
= NULL
;
1161 pfx
= strrep(" ", level
);
1162 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1164 if (node
->type
== BUS_MATCH_VALUE
) {
1165 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1166 printf(" <%u>\n", node
->value
.u8
);
1168 printf(" <%s>\n", node
->value
.str
);
1169 } else if (node
->type
== BUS_MATCH_ROOT
)
1171 else if (node
->type
== BUS_MATCH_LEAF
)
1172 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1176 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1179 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1180 bus_match_dump(c
, level
+ 1);
1183 for (c
= node
->child
; c
; c
= c
->next
)
1184 bus_match_dump(c
, level
+ 1);
1187 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1188 bool found_driver
= false;
1191 if (n_components
<= 0)
1192 return BUS_MATCH_GENERIC
;
1196 /* Checks whether the specified match can only match the
1197 * pseudo-service for local messages, which we detect by
1198 * sender, interface or path. If a match is not restricted to
1199 * local messages, then we check if it only matches on the
1202 for (i
= 0; i
< n_components
; i
++) {
1203 const struct bus_match_component
*c
= components
+ i
;
1205 if (c
->type
== BUS_MATCH_SENDER
) {
1206 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1207 return BUS_MATCH_LOCAL
;
1209 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1210 found_driver
= true;
1213 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1214 return BUS_MATCH_LOCAL
;
1216 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1217 return BUS_MATCH_LOCAL
;
1220 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;