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"
24 #include "bus-match.h"
29 * A: type=signal,sender=foo,interface=bar
30 * B: type=signal,sender=quux,interface=fips
31 * C: type=signal,sender=quux,interface=waldo
32 * D: type=signal,member=test
37 * results in this tree:
40 * + BUS_MATCH_MESSAGE_TYPE
41 * | ` BUS_MATCH_VALUE: value == signal
42 * | + DBUS_MATCH_SENDER
43 * | | + BUS_MATCH_VALUE: value == foo
44 * | | | ` DBUS_MATCH_INTERFACE
45 * | | | ` BUS_MATCH_VALUE: value == bar
46 * | | | ` BUS_MATCH_LEAF: A
47 * | | ` BUS_MATCH_VALUE: value == quux
48 * | | ` DBUS_MATCH_INTERFACE
49 * | | | BUS_MATCH_VALUE: value == fips
50 * | | | ` BUS_MATCH_LEAF: B
51 * | | ` BUS_MATCH_VALUE: value == waldo
52 * | | ` BUS_MATCH_LEAF: C
53 * | + DBUS_MATCH_MEMBER
54 * | | ` BUS_MATCH_VALUE: value == test
55 * | | ` BUS_MATCH_LEAF: D
56 * | + BUS_MATCH_LEAF: F
57 * | ` BUS_MATCH_LEAF: G
59 * ` BUS_MATCH_VALUE: value == miau
63 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
64 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
67 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
68 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
69 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
70 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
73 static void bus_match_node_free(struct bus_match_node
*node
) {
77 assert(node
->type
!= BUS_MATCH_ROOT
);
78 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
80 if (node
->parent
->child
) {
81 /* We are apparently linked into the parent's child
82 * list. Let's remove us from there. */
84 assert(node
->prev
->next
== node
);
85 node
->prev
->next
= node
->next
;
87 assert(node
->parent
->child
== node
);
88 node
->parent
->child
= node
->next
;
92 node
->next
->prev
= node
->prev
;
95 if (node
->type
== BUS_MATCH_VALUE
) {
96 /* We might be in the parent's hash table, so clean
99 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
100 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
101 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
102 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
104 free(node
->value
.str
);
107 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
108 assert(hashmap_isempty(node
->compare
.children
));
109 hashmap_free(node
->compare
.children
);
115 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
118 if (node
->type
== BUS_MATCH_ROOT
)
124 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
127 bus_match_node_free(node
);
131 static bool value_node_test(
132 struct bus_match_node
*node
,
133 enum bus_match_node_type parent_type
,
135 const char *value_str
,
140 assert(node
->type
== BUS_MATCH_VALUE
);
142 /* Tests parameters against this value node, doing prefix
143 * magic and stuff. */
145 switch (parent_type
) {
147 case BUS_MATCH_MESSAGE_TYPE
:
148 return node
->value
.u8
== value_u8
;
150 case BUS_MATCH_SENDER
:
151 if (streq_ptr(node
->value
.str
, value_str
))
154 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
157 /* on kdbus we have the well known names list
158 * in the credentials, let's make use of that
159 * for an accurate match */
161 STRV_FOREACH(i
, m
->creds
.well_known_names
)
162 if (streq_ptr(node
->value
.str
, *i
))
167 /* If we don't have kdbus, we don't know the
168 * well-known names of the senders. In that,
169 * let's just hope that dbus-daemon doesn't
170 * send us stuff we didn't want. */
172 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
178 case BUS_MATCH_DESTINATION
:
179 case BUS_MATCH_INTERFACE
:
180 case BUS_MATCH_MEMBER
:
182 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
185 return streq_ptr(node
->value
.str
, value_str
);
189 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
192 STRV_FOREACH(i
, value_strv
)
193 if (streq_ptr(node
->value
.str
, *i
))
199 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
201 return namespace_simple_pattern(node
->value
.str
, value_str
);
205 case BUS_MATCH_PATH_NAMESPACE
:
206 return path_simple_pattern(node
->value
.str
, value_str
);
208 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
210 return path_complex_pattern(node
->value
.str
, value_str
);
215 assert_not_reached("Invalid node type");
219 static bool value_node_same(
220 struct bus_match_node
*node
,
221 enum bus_match_node_type parent_type
,
223 const char *value_str
) {
225 /* Tests parameters against this value node, not doing prefix
226 * magic and stuff, i.e. this one actually compares the match
230 assert(node
->type
== BUS_MATCH_VALUE
);
232 switch (parent_type
) {
234 case BUS_MATCH_MESSAGE_TYPE
:
235 return node
->value
.u8
== value_u8
;
237 case BUS_MATCH_SENDER
:
238 case BUS_MATCH_DESTINATION
:
239 case BUS_MATCH_INTERFACE
:
240 case BUS_MATCH_MEMBER
:
242 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
243 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
244 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
245 case BUS_MATCH_PATH_NAMESPACE
:
246 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
247 return streq(node
->value
.str
, value_str
);
250 assert_not_reached("Invalid node type");
256 struct bus_match_node
*node
,
259 _cleanup_strv_free_
char **test_strv
= NULL
;
260 const char *test_str
= NULL
;
269 if (bus
&& bus
->match_callbacks_modified
)
272 /* Not these special semantics: when traversing the tree we
273 * usually let bus_match_run() when called for a node
274 * recursively invoke bus_match_run(). There's are two
275 * exceptions here though, which are BUS_NODE_ROOT (which
276 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
277 * are invoked anyway by its parent. */
279 switch (node
->type
) {
283 /* Run all children. Since we cannot have any siblings
284 * we won't call any. The children of the root node
285 * are compares or leaves, they will automatically
286 * call their siblings. */
287 return bus_match_run(bus
, node
->child
, m
);
289 case BUS_MATCH_VALUE
:
291 /* Run all children. We don't execute any siblings, we
292 * assume our caller does that. The children of value
293 * nodes are compares or leaves, they will
294 * automatically call their siblings */
297 return bus_match_run(bus
, node
->child
, m
);
302 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
305 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
308 r
= sd_bus_message_rewind(m
, true);
312 /* Run the callback. And then invoke siblings. */
313 if (node
->leaf
.callback
->callback
) {
314 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
317 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
319 bus
->current_slot
= sd_bus_slot_ref(slot
);
320 bus
->current_handler
= node
->leaf
.callback
->callback
;
321 bus
->current_userdata
= slot
->userdata
;
323 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
325 bus
->current_userdata
= NULL
;
326 bus
->current_handler
= NULL
;
327 bus
->current_slot
= sd_bus_slot_unref(slot
);
330 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
334 if (bus
&& bus
->match_callbacks_modified
)
338 return bus_match_run(bus
, node
->next
, m
);
340 case BUS_MATCH_MESSAGE_TYPE
:
341 test_u8
= m
->header
->type
;
344 case BUS_MATCH_SENDER
:
345 test_str
= m
->sender
;
346 /* FIXME: resolve test_str from a well-known to a unique name first */
349 case BUS_MATCH_DESTINATION
:
350 test_str
= m
->destination
;
353 case BUS_MATCH_INTERFACE
:
354 test_str
= m
->interface
;
357 case BUS_MATCH_MEMBER
:
358 test_str
= m
->member
;
362 case BUS_MATCH_PATH_NAMESPACE
:
366 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
367 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
370 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
371 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
374 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
375 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
378 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
379 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
383 assert_not_reached("Unknown match type.");
386 if (BUS_MATCH_CAN_HASH(node
->type
)) {
387 struct bus_match_node
*found
;
389 /* Lookup via hash table, nice! So let's jump directly. */
392 found
= hashmap_get(node
->compare
.children
, test_str
);
393 else if (test_strv
) {
396 STRV_FOREACH(i
, test_strv
) {
397 found
= hashmap_get(node
->compare
.children
, *i
);
399 r
= bus_match_run(bus
, found
, m
);
406 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
407 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
412 r
= bus_match_run(bus
, found
, m
);
417 struct bus_match_node
*c
;
419 /* No hash table, so let's iterate manually... */
421 for (c
= node
->child
; c
; c
= c
->next
) {
422 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
425 r
= bus_match_run(bus
, c
, m
);
431 if (bus
&& bus
->match_callbacks_modified
)
434 /* And now, let's invoke our siblings */
435 return bus_match_run(bus
, node
->next
, m
);
438 static int bus_match_add_compare_value(
439 struct bus_match_node
*where
,
440 enum bus_match_node_type t
,
442 const char *value_str
,
443 struct bus_match_node
**ret
) {
445 struct bus_match_node
*c
= NULL
, *n
= NULL
;
449 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
450 assert(BUS_MATCH_IS_COMPARE(t
));
453 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
457 /* Comparison node already exists? Then let's see if
458 * the value node exists too. */
460 if (t
== BUS_MATCH_MESSAGE_TYPE
)
461 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
462 else if (BUS_MATCH_CAN_HASH(t
))
463 n
= hashmap_get(c
->compare
.children
, value_str
);
465 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
474 /* Comparison node, doesn't exist yet? Then let's
477 c
= new0(struct bus_match_node
, 1);
485 c
->next
= where
->child
;
490 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
491 c
->compare
.children
= hashmap_new(NULL
);
492 if (!c
->compare
.children
) {
496 } else if (BUS_MATCH_CAN_HASH(t
)) {
497 c
->compare
.children
= hashmap_new(&string_hash_ops
);
498 if (!c
->compare
.children
) {
505 n
= new0(struct bus_match_node
, 1);
511 n
->type
= BUS_MATCH_VALUE
;
512 n
->value
.u8
= value_u8
;
514 n
->value
.str
= strdup(value_str
);
522 if (c
->compare
.children
) {
524 if (t
== BUS_MATCH_MESSAGE_TYPE
)
525 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
527 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
543 bus_match_node_maybe_free(c
);
553 static int bus_match_find_compare_value(
554 struct bus_match_node
*where
,
555 enum bus_match_node_type t
,
557 const char *value_str
,
558 struct bus_match_node
**ret
) {
560 struct bus_match_node
*c
, *n
;
563 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
564 assert(BUS_MATCH_IS_COMPARE(t
));
567 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
573 if (t
== BUS_MATCH_MESSAGE_TYPE
)
574 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
575 else if (BUS_MATCH_CAN_HASH(t
))
576 n
= hashmap_get(c
->compare
.children
, value_str
);
578 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
590 static int bus_match_add_leaf(
591 struct bus_match_node
*where
,
592 struct match_callback
*callback
) {
594 struct bus_match_node
*n
;
597 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
600 n
= new0(struct bus_match_node
, 1);
604 n
->type
= BUS_MATCH_LEAF
;
606 n
->next
= where
->child
;
610 n
->leaf
.callback
= callback
;
611 callback
->match_node
= n
;
618 static int bus_match_find_leaf(
619 struct bus_match_node
*where
,
620 sd_bus_message_handler_t callback
,
622 struct bus_match_node
**ret
) {
624 struct bus_match_node
*c
;
627 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
630 for (c
= where
->child
; c
; c
= c
->next
) {
633 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
635 if (c
->type
== BUS_MATCH_LEAF
&&
636 c
->leaf
.callback
->callback
== callback
&&
637 s
->userdata
== userdata
) {
646 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
649 if (n
== 4 && startswith(k
, "type"))
650 return BUS_MATCH_MESSAGE_TYPE
;
651 if (n
== 6 && startswith(k
, "sender"))
652 return BUS_MATCH_SENDER
;
653 if (n
== 11 && startswith(k
, "destination"))
654 return BUS_MATCH_DESTINATION
;
655 if (n
== 9 && startswith(k
, "interface"))
656 return BUS_MATCH_INTERFACE
;
657 if (n
== 6 && startswith(k
, "member"))
658 return BUS_MATCH_MEMBER
;
659 if (n
== 4 && startswith(k
, "path"))
660 return BUS_MATCH_PATH
;
661 if (n
== 14 && startswith(k
, "path_namespace"))
662 return BUS_MATCH_PATH_NAMESPACE
;
664 if (n
== 4 && startswith(k
, "arg")) {
671 return BUS_MATCH_ARG
+ j
;
674 if (n
== 5 && startswith(k
, "arg")) {
676 enum bus_match_node_type t
;
683 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
684 if (t
> BUS_MATCH_ARG_LAST
)
690 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
697 return BUS_MATCH_ARG_PATH
+ j
;
700 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
701 enum bus_match_node_type t
;
709 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
710 if (t
> BUS_MATCH_ARG_PATH_LAST
)
716 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
723 return BUS_MATCH_ARG_NAMESPACE
+ j
;
726 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
727 enum bus_match_node_type t
;
735 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
736 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
742 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
749 return BUS_MATCH_ARG_HAS
+ j
;
752 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
753 enum bus_match_node_type t
;
761 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
762 if (t
> BUS_MATCH_ARG_HAS_LAST
)
771 static int match_component_compare(const void *a
, const void *b
) {
772 const struct bus_match_component
*x
= a
, *y
= b
;
774 if (x
->type
< y
->type
)
776 if (x
->type
> y
->type
)
782 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
785 for (i
= 0; i
< n_components
; i
++)
786 free(components
[i
].value_str
);
793 struct bus_match_component
**_components
,
794 unsigned *_n_components
) {
796 const char *p
= match
;
797 struct bus_match_component
*components
= NULL
;
798 size_t components_allocated
= 0;
799 unsigned n_components
= 0, i
;
800 _cleanup_free_
char *value
= NULL
;
805 assert(_n_components
);
809 enum bus_match_node_type t
;
811 size_t value_allocated
= 0;
812 bool escaped
= false, quoted
;
815 /* Avahi's match rules appear to include whitespace, skip over it */
822 t
= bus_match_node_type_from_string(p
, eq
- p
);
826 quoted
= eq
[1] == '\'';
828 for (q
= eq
+ 1 + quoted
;; q
++) {
864 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
881 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
882 r
= bus_message_type_from_string(value
, &u
);
886 value
= mfree(value
);
890 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
895 components
[n_components
].type
= t
;
896 components
[n_components
].value_str
= value
;
897 components
[n_components
].value_u8
= u
;
905 if (q
[quoted
] != ',') {
913 /* Order the whole thing, so that we always generate the same tree */
914 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
916 /* Check for duplicates */
917 for (i
= 0; i
+1 < n_components
; i
++)
918 if (components
[i
].type
== components
[i
+1].type
) {
923 *_components
= components
;
924 *_n_components
= n_components
;
929 bus_match_parse_free(components
, n_components
);
933 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
934 _cleanup_free_
FILE *f
= NULL
;
940 if (n_components
<= 0)
945 f
= open_memstream(&buffer
, &size
);
949 for (i
= 0; i
< n_components
; i
++) {
955 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
959 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
960 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
962 fputs(components
[i
].value_str
, f
);
967 r
= fflush_and_check(f
);
975 struct bus_match_node
*root
,
976 struct bus_match_component
*components
,
977 unsigned n_components
,
978 struct match_callback
*callback
) {
981 struct bus_match_node
*n
;
988 for (i
= 0; i
< n_components
; i
++) {
989 r
= bus_match_add_compare_value(
990 n
, components
[i
].type
,
991 components
[i
].value_u8
, components
[i
].value_str
, &n
);
996 return bus_match_add_leaf(n
, callback
);
999 int bus_match_remove(
1000 struct bus_match_node
*root
,
1001 struct match_callback
*callback
) {
1003 struct bus_match_node
*node
, *pp
;
1008 node
= callback
->match_node
;
1012 assert(node
->type
== BUS_MATCH_LEAF
);
1014 callback
->match_node
= NULL
;
1018 bus_match_node_free(node
);
1020 /* Prune the tree above */
1025 if (!bus_match_node_maybe_free(node
))
1033 struct bus_match_node
*root
,
1034 struct bus_match_component
*components
,
1035 unsigned n_components
,
1036 sd_bus_message_handler_t callback
,
1038 struct match_callback
**ret
) {
1040 struct bus_match_node
*n
, **gc
;
1047 gc
= newa(struct bus_match_node
*, n_components
);
1050 for (i
= 0; i
< n_components
; i
++) {
1051 r
= bus_match_find_compare_value(
1052 n
, components
[i
].type
,
1053 components
[i
].value_u8
, components
[i
].value_str
,
1061 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1065 *ret
= n
->leaf
.callback
;
1069 void bus_match_free(struct bus_match_node
*node
) {
1070 struct bus_match_node
*c
;
1075 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1078 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1081 assert(hashmap_isempty(node
->compare
.children
));
1084 while ((c
= node
->child
))
1087 if (node
->type
!= BUS_MATCH_ROOT
)
1088 bus_match_node_free(node
);
1091 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1094 case BUS_MATCH_ROOT
:
1097 case BUS_MATCH_VALUE
:
1100 case BUS_MATCH_LEAF
:
1103 case BUS_MATCH_MESSAGE_TYPE
:
1106 case BUS_MATCH_SENDER
:
1109 case BUS_MATCH_DESTINATION
:
1110 return "destination";
1112 case BUS_MATCH_INTERFACE
:
1115 case BUS_MATCH_MEMBER
:
1118 case BUS_MATCH_PATH
:
1121 case BUS_MATCH_PATH_NAMESPACE
:
1122 return "path_namespace";
1124 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1125 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1128 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1129 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1132 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1133 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1136 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1137 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1145 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1146 struct bus_match_node
*c
;
1147 _cleanup_free_
char *pfx
= NULL
;
1153 pfx
= strrep(" ", level
);
1154 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1156 if (node
->type
== BUS_MATCH_VALUE
) {
1157 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1158 printf(" <%u>\n", node
->value
.u8
);
1160 printf(" <%s>\n", node
->value
.str
);
1161 } else if (node
->type
== BUS_MATCH_ROOT
)
1163 else if (node
->type
== BUS_MATCH_LEAF
)
1164 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1168 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1171 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1172 bus_match_dump(c
, level
+ 1);
1175 for (c
= node
->child
; c
; c
= c
->next
)
1176 bus_match_dump(c
, level
+ 1);
1179 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1180 bool found_driver
= false;
1183 if (n_components
<= 0)
1184 return BUS_MATCH_GENERIC
;
1188 /* Checks whether the specified match can only match the
1189 * pseudo-service for local messages, which we detect by
1190 * sender, interface or path. If a match is not restricted to
1191 * local messages, then we check if it only matches on the
1194 for (i
= 0; i
< n_components
; i
++) {
1195 const struct bus_match_component
*c
= components
+ i
;
1197 if (c
->type
== BUS_MATCH_SENDER
) {
1198 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1199 return BUS_MATCH_LOCAL
;
1201 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1202 found_driver
= true;
1205 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1206 return BUS_MATCH_LOCAL
;
1208 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1209 return BUS_MATCH_LOCAL
;
1212 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;