1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "bus-internal.h"
23 #include "bus-message.h"
25 #include "string-util.h"
27 #include "bus-match.h"
31 * A: type=signal,sender=foo,interface=bar
32 * B: type=signal,sender=quux,interface=fips
33 * C: type=signal,sender=quux,interface=waldo
34 * D: type=signal,member=test
39 * results in this tree:
42 * + BUS_MATCH_MESSAGE_TYPE
43 * | ` BUS_MATCH_VALUE: value == signal
44 * | + DBUS_MATCH_SENDER
45 * | | + BUS_MATCH_VALUE: value == foo
46 * | | | ` DBUS_MATCH_INTERFACE
47 * | | | ` BUS_MATCH_VALUE: value == bar
48 * | | | ` BUS_MATCH_LEAF: A
49 * | | ` BUS_MATCH_VALUE: value == quux
50 * | | ` DBUS_MATCH_INTERFACE
51 * | | | BUS_MATCH_VALUE: value == fips
52 * | | | ` BUS_MATCH_LEAF: B
53 * | | ` BUS_MATCH_VALUE: value == waldo
54 * | | ` BUS_MATCH_LEAF: C
55 * | + DBUS_MATCH_MEMBER
56 * | | ` BUS_MATCH_VALUE: value == test
57 * | | ` BUS_MATCH_LEAF: D
58 * | + BUS_MATCH_LEAF: F
59 * | ` BUS_MATCH_LEAF: G
61 * ` BUS_MATCH_VALUE: value == miau
65 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
66 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
69 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
70 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
71 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
72 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
75 static void bus_match_node_free(struct bus_match_node
*node
) {
79 assert(node
->type
!= BUS_MATCH_ROOT
);
80 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
82 if (node
->parent
->child
) {
83 /* We are apparently linked into the parent's child
84 * list. Let's remove us from there. */
86 assert(node
->prev
->next
== node
);
87 node
->prev
->next
= node
->next
;
89 assert(node
->parent
->child
== node
);
90 node
->parent
->child
= node
->next
;
94 node
->next
->prev
= node
->prev
;
97 if (node
->type
== BUS_MATCH_VALUE
) {
98 /* We might be in the parent's hash table, so clean
101 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
102 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
103 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
104 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
106 free(node
->value
.str
);
109 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
110 assert(hashmap_isempty(node
->compare
.children
));
111 hashmap_free(node
->compare
.children
);
117 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
120 if (node
->type
== BUS_MATCH_ROOT
)
126 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
129 bus_match_node_free(node
);
133 static bool value_node_test(
134 struct bus_match_node
*node
,
135 enum bus_match_node_type parent_type
,
137 const char *value_str
,
142 assert(node
->type
== BUS_MATCH_VALUE
);
144 /* Tests parameters against this value node, doing prefix
145 * magic and stuff. */
147 switch (parent_type
) {
149 case BUS_MATCH_MESSAGE_TYPE
:
150 return node
->value
.u8
== value_u8
;
152 case BUS_MATCH_SENDER
:
153 if (streq_ptr(node
->value
.str
, value_str
))
156 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
159 /* on kdbus we have the well known names list
160 * in the credentials, let's make use of that
161 * for an accurate match */
163 STRV_FOREACH(i
, m
->creds
.well_known_names
)
164 if (streq_ptr(node
->value
.str
, *i
))
169 /* If we don't have kdbus, we don't know the
170 * well-known names of the senders. In that,
171 * let's just hope that dbus-daemon doesn't
172 * send us stuff we didn't want. */
174 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
180 case BUS_MATCH_DESTINATION
:
181 case BUS_MATCH_INTERFACE
:
182 case BUS_MATCH_MEMBER
:
184 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
187 return streq_ptr(node
->value
.str
, value_str
);
191 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
194 STRV_FOREACH(i
, value_strv
)
195 if (streq_ptr(node
->value
.str
, *i
))
201 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
203 return namespace_simple_pattern(node
->value
.str
, value_str
);
207 case BUS_MATCH_PATH_NAMESPACE
:
208 return path_simple_pattern(node
->value
.str
, value_str
);
210 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
212 return path_complex_pattern(node
->value
.str
, value_str
);
217 assert_not_reached("Invalid node type");
221 static bool value_node_same(
222 struct bus_match_node
*node
,
223 enum bus_match_node_type parent_type
,
225 const char *value_str
) {
227 /* Tests parameters against this value node, not doing prefix
228 * magic and stuff, i.e. this one actually compares the match
232 assert(node
->type
== BUS_MATCH_VALUE
);
234 switch (parent_type
) {
236 case BUS_MATCH_MESSAGE_TYPE
:
237 return node
->value
.u8
== value_u8
;
239 case BUS_MATCH_SENDER
:
240 case BUS_MATCH_DESTINATION
:
241 case BUS_MATCH_INTERFACE
:
242 case BUS_MATCH_MEMBER
:
244 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
245 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
246 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
247 case BUS_MATCH_PATH_NAMESPACE
:
248 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
249 return streq(node
->value
.str
, value_str
);
252 assert_not_reached("Invalid node type");
258 struct bus_match_node
*node
,
261 _cleanup_strv_free_
char **test_strv
= NULL
;
262 const char *test_str
= NULL
;
271 if (bus
&& bus
->match_callbacks_modified
)
274 /* Not these special semantics: when traversing the tree we
275 * usually let bus_match_run() when called for a node
276 * recursively invoke bus_match_run(). There's are two
277 * exceptions here though, which are BUS_NODE_ROOT (which
278 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
279 * are invoked anyway by its parent. */
281 switch (node
->type
) {
285 /* Run all children. Since we cannot have any siblings
286 * we won't call any. The children of the root node
287 * are compares or leaves, they will automatically
288 * call their siblings. */
289 return bus_match_run(bus
, node
->child
, m
);
291 case BUS_MATCH_VALUE
:
293 /* Run all children. We don't execute any siblings, we
294 * assume our caller does that. The children of value
295 * nodes are compares or leaves, they will
296 * automatically call their siblings */
299 return bus_match_run(bus
, node
->child
, m
);
304 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
307 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
310 r
= sd_bus_message_rewind(m
, true);
314 /* Run the callback. And then invoke siblings. */
315 if (node
->leaf
.callback
->callback
) {
316 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
319 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
321 bus
->current_slot
= sd_bus_slot_ref(slot
);
322 bus
->current_handler
= node
->leaf
.callback
->callback
;
323 bus
->current_userdata
= slot
->userdata
;
325 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
327 bus
->current_userdata
= NULL
;
328 bus
->current_handler
= NULL
;
329 bus
->current_slot
= sd_bus_slot_unref(slot
);
332 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
336 if (bus
&& bus
->match_callbacks_modified
)
340 return bus_match_run(bus
, node
->next
, m
);
342 case BUS_MATCH_MESSAGE_TYPE
:
343 test_u8
= m
->header
->type
;
346 case BUS_MATCH_SENDER
:
347 test_str
= m
->sender
;
348 /* FIXME: resolve test_str from a well-known to a unique name first */
351 case BUS_MATCH_DESTINATION
:
352 test_str
= m
->destination
;
355 case BUS_MATCH_INTERFACE
:
356 test_str
= m
->interface
;
359 case BUS_MATCH_MEMBER
:
360 test_str
= m
->member
;
364 case BUS_MATCH_PATH_NAMESPACE
:
368 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
369 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
372 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
373 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
376 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
377 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
380 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
381 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
385 assert_not_reached("Unknown match type.");
388 if (BUS_MATCH_CAN_HASH(node
->type
)) {
389 struct bus_match_node
*found
;
391 /* Lookup via hash table, nice! So let's jump directly. */
394 found
= hashmap_get(node
->compare
.children
, test_str
);
395 else if (test_strv
) {
398 STRV_FOREACH(i
, test_strv
) {
399 found
= hashmap_get(node
->compare
.children
, *i
);
401 r
= bus_match_run(bus
, found
, m
);
408 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
409 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
414 r
= bus_match_run(bus
, found
, m
);
419 struct bus_match_node
*c
;
421 /* No hash table, so let's iterate manually... */
423 for (c
= node
->child
; c
; c
= c
->next
) {
424 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
427 r
= bus_match_run(bus
, c
, m
);
433 if (bus
&& bus
->match_callbacks_modified
)
436 /* And now, let's invoke our siblings */
437 return bus_match_run(bus
, node
->next
, m
);
440 static int bus_match_add_compare_value(
441 struct bus_match_node
*where
,
442 enum bus_match_node_type t
,
444 const char *value_str
,
445 struct bus_match_node
**ret
) {
447 struct bus_match_node
*c
= NULL
, *n
= NULL
;
451 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
452 assert(BUS_MATCH_IS_COMPARE(t
));
455 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
459 /* Comparison node already exists? Then let's see if
460 * the value node exists too. */
462 if (t
== BUS_MATCH_MESSAGE_TYPE
)
463 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
464 else if (BUS_MATCH_CAN_HASH(t
))
465 n
= hashmap_get(c
->compare
.children
, value_str
);
467 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
476 /* Comparison node, doesn't exist yet? Then let's
479 c
= new0(struct bus_match_node
, 1);
487 c
->next
= where
->child
;
492 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
493 c
->compare
.children
= hashmap_new(NULL
);
494 if (!c
->compare
.children
) {
498 } else if (BUS_MATCH_CAN_HASH(t
)) {
499 c
->compare
.children
= hashmap_new(&string_hash_ops
);
500 if (!c
->compare
.children
) {
507 n
= new0(struct bus_match_node
, 1);
513 n
->type
= BUS_MATCH_VALUE
;
514 n
->value
.u8
= value_u8
;
516 n
->value
.str
= strdup(value_str
);
524 if (c
->compare
.children
) {
526 if (t
== BUS_MATCH_MESSAGE_TYPE
)
527 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
529 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
545 bus_match_node_maybe_free(c
);
555 static int bus_match_find_compare_value(
556 struct bus_match_node
*where
,
557 enum bus_match_node_type t
,
559 const char *value_str
,
560 struct bus_match_node
**ret
) {
562 struct bus_match_node
*c
, *n
;
565 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
566 assert(BUS_MATCH_IS_COMPARE(t
));
569 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
575 if (t
== BUS_MATCH_MESSAGE_TYPE
)
576 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
577 else if (BUS_MATCH_CAN_HASH(t
))
578 n
= hashmap_get(c
->compare
.children
, value_str
);
580 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
592 static int bus_match_add_leaf(
593 struct bus_match_node
*where
,
594 struct match_callback
*callback
) {
596 struct bus_match_node
*n
;
599 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
602 n
= new0(struct bus_match_node
, 1);
606 n
->type
= BUS_MATCH_LEAF
;
608 n
->next
= where
->child
;
612 n
->leaf
.callback
= callback
;
613 callback
->match_node
= n
;
620 static int bus_match_find_leaf(
621 struct bus_match_node
*where
,
622 sd_bus_message_handler_t callback
,
624 struct bus_match_node
**ret
) {
626 struct bus_match_node
*c
;
629 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
632 for (c
= where
->child
; c
; c
= c
->next
) {
635 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
637 if (c
->type
== BUS_MATCH_LEAF
&&
638 c
->leaf
.callback
->callback
== callback
&&
639 s
->userdata
== userdata
) {
648 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
651 if (n
== 4 && startswith(k
, "type"))
652 return BUS_MATCH_MESSAGE_TYPE
;
653 if (n
== 6 && startswith(k
, "sender"))
654 return BUS_MATCH_SENDER
;
655 if (n
== 11 && startswith(k
, "destination"))
656 return BUS_MATCH_DESTINATION
;
657 if (n
== 9 && startswith(k
, "interface"))
658 return BUS_MATCH_INTERFACE
;
659 if (n
== 6 && startswith(k
, "member"))
660 return BUS_MATCH_MEMBER
;
661 if (n
== 4 && startswith(k
, "path"))
662 return BUS_MATCH_PATH
;
663 if (n
== 14 && startswith(k
, "path_namespace"))
664 return BUS_MATCH_PATH_NAMESPACE
;
666 if (n
== 4 && startswith(k
, "arg")) {
673 return BUS_MATCH_ARG
+ j
;
676 if (n
== 5 && startswith(k
, "arg")) {
678 enum bus_match_node_type t
;
685 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
686 if (t
> BUS_MATCH_ARG_LAST
)
692 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
699 return BUS_MATCH_ARG_PATH
+ j
;
702 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
703 enum bus_match_node_type t
;
711 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
712 if (t
> BUS_MATCH_ARG_PATH_LAST
)
718 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
725 return BUS_MATCH_ARG_NAMESPACE
+ j
;
728 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
729 enum bus_match_node_type t
;
737 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
738 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
744 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
751 return BUS_MATCH_ARG_HAS
+ j
;
754 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
755 enum bus_match_node_type t
;
763 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
764 if (t
> BUS_MATCH_ARG_HAS_LAST
)
773 static int match_component_compare(const void *a
, const void *b
) {
774 const struct bus_match_component
*x
= a
, *y
= b
;
776 if (x
->type
< y
->type
)
778 if (x
->type
> y
->type
)
784 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
787 for (i
= 0; i
< n_components
; i
++)
788 free(components
[i
].value_str
);
795 struct bus_match_component
**_components
,
796 unsigned *_n_components
) {
798 const char *p
= match
;
799 struct bus_match_component
*components
= NULL
;
800 size_t components_allocated
= 0;
801 unsigned n_components
= 0, i
;
802 _cleanup_free_
char *value
= NULL
;
807 assert(_n_components
);
811 enum bus_match_node_type t
;
813 size_t value_allocated
= 0;
814 bool escaped
= false, quoted
;
817 /* Avahi's match rules appear to include whitespace, skip over it */
824 t
= bus_match_node_type_from_string(p
, eq
- p
);
828 quoted
= eq
[1] == '\'';
830 for (q
= eq
+ 1 + quoted
;; q
++) {
866 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
883 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
884 r
= bus_message_type_from_string(value
, &u
);
888 value
= mfree(value
);
892 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
897 components
[n_components
].type
= t
;
898 components
[n_components
].value_str
= value
;
899 components
[n_components
].value_u8
= u
;
907 if (q
[quoted
] != ',') {
915 /* Order the whole thing, so that we always generate the same tree */
916 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
918 /* Check for duplicates */
919 for (i
= 0; i
+1 < n_components
; i
++)
920 if (components
[i
].type
== components
[i
+1].type
) {
925 *_components
= components
;
926 *_n_components
= n_components
;
931 bus_match_parse_free(components
, n_components
);
935 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
936 _cleanup_fclose_
FILE *f
= NULL
;
942 if (n_components
<= 0)
947 f
= open_memstream(&buffer
, &size
);
951 for (i
= 0; i
< n_components
; i
++) {
957 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
961 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
962 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
964 fputs(components
[i
].value_str
, f
);
969 r
= fflush_and_check(f
);
977 struct bus_match_node
*root
,
978 struct bus_match_component
*components
,
979 unsigned n_components
,
980 struct match_callback
*callback
) {
983 struct bus_match_node
*n
;
990 for (i
= 0; i
< n_components
; i
++) {
991 r
= bus_match_add_compare_value(
992 n
, components
[i
].type
,
993 components
[i
].value_u8
, components
[i
].value_str
, &n
);
998 return bus_match_add_leaf(n
, callback
);
1001 int bus_match_remove(
1002 struct bus_match_node
*root
,
1003 struct match_callback
*callback
) {
1005 struct bus_match_node
*node
, *pp
;
1010 node
= callback
->match_node
;
1014 assert(node
->type
== BUS_MATCH_LEAF
);
1016 callback
->match_node
= NULL
;
1020 bus_match_node_free(node
);
1022 /* Prune the tree above */
1027 if (!bus_match_node_maybe_free(node
))
1035 struct bus_match_node
*root
,
1036 struct bus_match_component
*components
,
1037 unsigned n_components
,
1038 sd_bus_message_handler_t callback
,
1040 struct match_callback
**ret
) {
1042 struct bus_match_node
*n
, **gc
;
1049 gc
= newa(struct bus_match_node
*, n_components
);
1052 for (i
= 0; i
< n_components
; i
++) {
1053 r
= bus_match_find_compare_value(
1054 n
, components
[i
].type
,
1055 components
[i
].value_u8
, components
[i
].value_str
,
1063 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1067 *ret
= n
->leaf
.callback
;
1071 void bus_match_free(struct bus_match_node
*node
) {
1072 struct bus_match_node
*c
;
1077 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1080 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1083 assert(hashmap_isempty(node
->compare
.children
));
1086 while ((c
= node
->child
))
1089 if (node
->type
!= BUS_MATCH_ROOT
)
1090 bus_match_node_free(node
);
1093 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1096 case BUS_MATCH_ROOT
:
1099 case BUS_MATCH_VALUE
:
1102 case BUS_MATCH_LEAF
:
1105 case BUS_MATCH_MESSAGE_TYPE
:
1108 case BUS_MATCH_SENDER
:
1111 case BUS_MATCH_DESTINATION
:
1112 return "destination";
1114 case BUS_MATCH_INTERFACE
:
1117 case BUS_MATCH_MEMBER
:
1120 case BUS_MATCH_PATH
:
1123 case BUS_MATCH_PATH_NAMESPACE
:
1124 return "path_namespace";
1126 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1127 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1130 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1131 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1134 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1135 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1138 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1139 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1147 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1148 struct bus_match_node
*c
;
1149 _cleanup_free_
char *pfx
= NULL
;
1155 pfx
= strrep(" ", level
);
1156 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1158 if (node
->type
== BUS_MATCH_VALUE
) {
1159 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1160 printf(" <%u>\n", node
->value
.u8
);
1162 printf(" <%s>\n", node
->value
.str
);
1163 } else if (node
->type
== BUS_MATCH_ROOT
)
1165 else if (node
->type
== BUS_MATCH_LEAF
)
1166 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1170 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1173 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1174 bus_match_dump(c
, level
+ 1);
1177 for (c
= node
->child
; c
; c
= c
->next
)
1178 bus_match_dump(c
, level
+ 1);
1181 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1182 bool found_driver
= false;
1185 if (n_components
<= 0)
1186 return BUS_MATCH_GENERIC
;
1190 /* Checks whether the specified match can only match the
1191 * pseudo-service for local messages, which we detect by
1192 * sender, interface or path. If a match is not restricted to
1193 * local messages, then we check if it only matches on the
1196 for (i
= 0; i
< n_components
; i
++) {
1197 const struct bus_match_component
*c
= components
+ i
;
1199 if (c
->type
== BUS_MATCH_SENDER
) {
1200 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1201 return BUS_MATCH_LOCAL
;
1203 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1204 found_driver
= true;
1207 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1208 return BUS_MATCH_LOCAL
;
1210 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1211 return BUS_MATCH_LOCAL
;
1214 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;