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 "alloc-util.h"
23 #include "bus-internal.h"
24 #include "bus-match.h"
25 #include "bus-message.h"
29 #include "hexdecoct.h"
30 #include "string-util.h"
35 * A: type=signal,sender=foo,interface=bar
36 * B: type=signal,sender=quux,interface=fips
37 * C: type=signal,sender=quux,interface=waldo
38 * D: type=signal,member=test
43 * results in this tree:
46 * + BUS_MATCH_MESSAGE_TYPE
47 * | ` BUS_MATCH_VALUE: value == signal
48 * | + DBUS_MATCH_SENDER
49 * | | + BUS_MATCH_VALUE: value == foo
50 * | | | ` DBUS_MATCH_INTERFACE
51 * | | | ` BUS_MATCH_VALUE: value == bar
52 * | | | ` BUS_MATCH_LEAF: A
53 * | | ` BUS_MATCH_VALUE: value == quux
54 * | | ` DBUS_MATCH_INTERFACE
55 * | | | BUS_MATCH_VALUE: value == fips
56 * | | | ` BUS_MATCH_LEAF: B
57 * | | ` BUS_MATCH_VALUE: value == waldo
58 * | | ` BUS_MATCH_LEAF: C
59 * | + DBUS_MATCH_MEMBER
60 * | | ` BUS_MATCH_VALUE: value == test
61 * | | ` BUS_MATCH_LEAF: D
62 * | + BUS_MATCH_LEAF: F
63 * | ` BUS_MATCH_LEAF: G
65 * ` BUS_MATCH_VALUE: value == miau
69 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
70 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
73 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
74 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
75 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
76 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
79 static void bus_match_node_free(struct bus_match_node
*node
) {
83 assert(node
->type
!= BUS_MATCH_ROOT
);
84 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
86 if (node
->parent
->child
) {
87 /* We are apparently linked into the parent's child
88 * list. Let's remove us from there. */
90 assert(node
->prev
->next
== node
);
91 node
->prev
->next
= node
->next
;
93 assert(node
->parent
->child
== node
);
94 node
->parent
->child
= node
->next
;
98 node
->next
->prev
= node
->prev
;
101 if (node
->type
== BUS_MATCH_VALUE
) {
102 /* We might be in the parent's hash table, so clean
105 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
106 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
107 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
108 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
110 free(node
->value
.str
);
113 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
114 assert(hashmap_isempty(node
->compare
.children
));
115 hashmap_free(node
->compare
.children
);
121 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
124 if (node
->type
== BUS_MATCH_ROOT
)
130 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
133 bus_match_node_free(node
);
137 static bool value_node_test(
138 struct bus_match_node
*node
,
139 enum bus_match_node_type parent_type
,
141 const char *value_str
,
146 assert(node
->type
== BUS_MATCH_VALUE
);
148 /* Tests parameters against this value node, doing prefix
149 * magic and stuff. */
151 switch (parent_type
) {
153 case BUS_MATCH_MESSAGE_TYPE
:
154 return node
->value
.u8
== value_u8
;
156 case BUS_MATCH_SENDER
:
157 if (streq_ptr(node
->value
.str
, value_str
))
160 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
163 /* on kdbus we have the well known names list
164 * in the credentials, let's make use of that
165 * for an accurate match */
167 STRV_FOREACH(i
, m
->creds
.well_known_names
)
168 if (streq_ptr(node
->value
.str
, *i
))
173 /* If we don't have kdbus, we don't know the
174 * well-known names of the senders. In that,
175 * let's just hope that dbus-daemon doesn't
176 * send us stuff we didn't want. */
178 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
184 case BUS_MATCH_DESTINATION
:
185 case BUS_MATCH_INTERFACE
:
186 case BUS_MATCH_MEMBER
:
188 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
191 return streq_ptr(node
->value
.str
, value_str
);
195 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
198 STRV_FOREACH(i
, value_strv
)
199 if (streq_ptr(node
->value
.str
, *i
))
205 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
207 return namespace_simple_pattern(node
->value
.str
, value_str
);
211 case BUS_MATCH_PATH_NAMESPACE
:
212 return path_simple_pattern(node
->value
.str
, value_str
);
214 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
216 return path_complex_pattern(node
->value
.str
, value_str
);
221 assert_not_reached("Invalid node type");
225 static bool value_node_same(
226 struct bus_match_node
*node
,
227 enum bus_match_node_type parent_type
,
229 const char *value_str
) {
231 /* Tests parameters against this value node, not doing prefix
232 * magic and stuff, i.e. this one actually compares the match
236 assert(node
->type
== BUS_MATCH_VALUE
);
238 switch (parent_type
) {
240 case BUS_MATCH_MESSAGE_TYPE
:
241 return node
->value
.u8
== value_u8
;
243 case BUS_MATCH_SENDER
:
244 case BUS_MATCH_DESTINATION
:
245 case BUS_MATCH_INTERFACE
:
246 case BUS_MATCH_MEMBER
:
248 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
249 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
250 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
251 case BUS_MATCH_PATH_NAMESPACE
:
252 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
253 return streq(node
->value
.str
, value_str
);
256 assert_not_reached("Invalid node type");
262 struct bus_match_node
*node
,
265 _cleanup_strv_free_
char **test_strv
= NULL
;
266 const char *test_str
= NULL
;
275 if (bus
&& bus
->match_callbacks_modified
)
278 /* Not these special semantics: when traversing the tree we
279 * usually let bus_match_run() when called for a node
280 * recursively invoke bus_match_run(). There's are two
281 * exceptions here though, which are BUS_NODE_ROOT (which
282 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
283 * are invoked anyway by its parent. */
285 switch (node
->type
) {
289 /* Run all children. Since we cannot have any siblings
290 * we won't call any. The children of the root node
291 * are compares or leaves, they will automatically
292 * call their siblings. */
293 return bus_match_run(bus
, node
->child
, m
);
295 case BUS_MATCH_VALUE
:
297 /* Run all children. We don't execute any siblings, we
298 * assume our caller does that. The children of value
299 * nodes are compares or leaves, they will
300 * automatically call their siblings */
303 return bus_match_run(bus
, node
->child
, m
);
308 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
311 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
314 r
= sd_bus_message_rewind(m
, true);
318 /* Run the callback. And then invoke siblings. */
319 if (node
->leaf
.callback
->callback
) {
320 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
323 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
325 bus
->current_slot
= sd_bus_slot_ref(slot
);
326 bus
->current_handler
= node
->leaf
.callback
->callback
;
327 bus
->current_userdata
= slot
->userdata
;
329 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
331 bus
->current_userdata
= NULL
;
332 bus
->current_handler
= NULL
;
333 bus
->current_slot
= sd_bus_slot_unref(slot
);
336 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
340 if (bus
&& bus
->match_callbacks_modified
)
344 return bus_match_run(bus
, node
->next
, m
);
346 case BUS_MATCH_MESSAGE_TYPE
:
347 test_u8
= m
->header
->type
;
350 case BUS_MATCH_SENDER
:
351 test_str
= m
->sender
;
352 /* FIXME: resolve test_str from a well-known to a unique name first */
355 case BUS_MATCH_DESTINATION
:
356 test_str
= m
->destination
;
359 case BUS_MATCH_INTERFACE
:
360 test_str
= m
->interface
;
363 case BUS_MATCH_MEMBER
:
364 test_str
= m
->member
;
368 case BUS_MATCH_PATH_NAMESPACE
:
372 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
373 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
376 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
377 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
380 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
381 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
384 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
385 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
389 assert_not_reached("Unknown match type.");
392 if (BUS_MATCH_CAN_HASH(node
->type
)) {
393 struct bus_match_node
*found
;
395 /* Lookup via hash table, nice! So let's jump directly. */
398 found
= hashmap_get(node
->compare
.children
, test_str
);
399 else if (test_strv
) {
402 STRV_FOREACH(i
, test_strv
) {
403 found
= hashmap_get(node
->compare
.children
, *i
);
405 r
= bus_match_run(bus
, found
, m
);
412 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
413 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
418 r
= bus_match_run(bus
, found
, m
);
423 struct bus_match_node
*c
;
425 /* No hash table, so let's iterate manually... */
427 for (c
= node
->child
; c
; c
= c
->next
) {
428 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
431 r
= bus_match_run(bus
, c
, m
);
437 if (bus
&& bus
->match_callbacks_modified
)
440 /* And now, let's invoke our siblings */
441 return bus_match_run(bus
, node
->next
, m
);
444 static int bus_match_add_compare_value(
445 struct bus_match_node
*where
,
446 enum bus_match_node_type t
,
448 const char *value_str
,
449 struct bus_match_node
**ret
) {
451 struct bus_match_node
*c
= NULL
, *n
= NULL
;
455 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
456 assert(BUS_MATCH_IS_COMPARE(t
));
459 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
463 /* Comparison node already exists? Then let's see if
464 * the value node exists too. */
466 if (t
== BUS_MATCH_MESSAGE_TYPE
)
467 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
468 else if (BUS_MATCH_CAN_HASH(t
))
469 n
= hashmap_get(c
->compare
.children
, value_str
);
471 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
480 /* Comparison node, doesn't exist yet? Then let's
483 c
= new0(struct bus_match_node
, 1);
491 c
->next
= where
->child
;
496 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
497 c
->compare
.children
= hashmap_new(NULL
);
498 if (!c
->compare
.children
) {
502 } else if (BUS_MATCH_CAN_HASH(t
)) {
503 c
->compare
.children
= hashmap_new(&string_hash_ops
);
504 if (!c
->compare
.children
) {
511 n
= new0(struct bus_match_node
, 1);
517 n
->type
= BUS_MATCH_VALUE
;
518 n
->value
.u8
= value_u8
;
520 n
->value
.str
= strdup(value_str
);
528 if (c
->compare
.children
) {
530 if (t
== BUS_MATCH_MESSAGE_TYPE
)
531 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
533 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
549 bus_match_node_maybe_free(c
);
559 static int bus_match_find_compare_value(
560 struct bus_match_node
*where
,
561 enum bus_match_node_type t
,
563 const char *value_str
,
564 struct bus_match_node
**ret
) {
566 struct bus_match_node
*c
, *n
;
569 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
570 assert(BUS_MATCH_IS_COMPARE(t
));
573 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
579 if (t
== BUS_MATCH_MESSAGE_TYPE
)
580 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
581 else if (BUS_MATCH_CAN_HASH(t
))
582 n
= hashmap_get(c
->compare
.children
, value_str
);
584 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
596 static int bus_match_add_leaf(
597 struct bus_match_node
*where
,
598 struct match_callback
*callback
) {
600 struct bus_match_node
*n
;
603 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
606 n
= new0(struct bus_match_node
, 1);
610 n
->type
= BUS_MATCH_LEAF
;
612 n
->next
= where
->child
;
616 n
->leaf
.callback
= callback
;
617 callback
->match_node
= n
;
624 static int bus_match_find_leaf(
625 struct bus_match_node
*where
,
626 sd_bus_message_handler_t callback
,
628 struct bus_match_node
**ret
) {
630 struct bus_match_node
*c
;
633 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
636 for (c
= where
->child
; c
; c
= c
->next
) {
639 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
641 if (c
->type
== BUS_MATCH_LEAF
&&
642 c
->leaf
.callback
->callback
== callback
&&
643 s
->userdata
== userdata
) {
652 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
655 if (n
== 4 && startswith(k
, "type"))
656 return BUS_MATCH_MESSAGE_TYPE
;
657 if (n
== 6 && startswith(k
, "sender"))
658 return BUS_MATCH_SENDER
;
659 if (n
== 11 && startswith(k
, "destination"))
660 return BUS_MATCH_DESTINATION
;
661 if (n
== 9 && startswith(k
, "interface"))
662 return BUS_MATCH_INTERFACE
;
663 if (n
== 6 && startswith(k
, "member"))
664 return BUS_MATCH_MEMBER
;
665 if (n
== 4 && startswith(k
, "path"))
666 return BUS_MATCH_PATH
;
667 if (n
== 14 && startswith(k
, "path_namespace"))
668 return BUS_MATCH_PATH_NAMESPACE
;
670 if (n
== 4 && startswith(k
, "arg")) {
677 return BUS_MATCH_ARG
+ j
;
680 if (n
== 5 && startswith(k
, "arg")) {
682 enum bus_match_node_type t
;
689 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
690 if (t
> BUS_MATCH_ARG_LAST
)
696 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
703 return BUS_MATCH_ARG_PATH
+ j
;
706 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
707 enum bus_match_node_type t
;
715 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
716 if (t
> BUS_MATCH_ARG_PATH_LAST
)
722 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
729 return BUS_MATCH_ARG_NAMESPACE
+ j
;
732 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
733 enum bus_match_node_type t
;
741 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
742 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
748 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
755 return BUS_MATCH_ARG_HAS
+ j
;
758 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
759 enum bus_match_node_type t
;
767 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
768 if (t
> BUS_MATCH_ARG_HAS_LAST
)
777 static int match_component_compare(const void *a
, const void *b
) {
778 const struct bus_match_component
*x
= a
, *y
= b
;
780 if (x
->type
< y
->type
)
782 if (x
->type
> y
->type
)
788 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
791 for (i
= 0; i
< n_components
; i
++)
792 free(components
[i
].value_str
);
799 struct bus_match_component
**_components
,
800 unsigned *_n_components
) {
802 const char *p
= match
;
803 struct bus_match_component
*components
= NULL
;
804 size_t components_allocated
= 0;
805 unsigned n_components
= 0, i
;
806 _cleanup_free_
char *value
= NULL
;
811 assert(_n_components
);
815 enum bus_match_node_type t
;
817 size_t value_allocated
= 0;
818 bool escaped
= false, quoted
;
821 /* Avahi's match rules appear to include whitespace, skip over it */
828 t
= bus_match_node_type_from_string(p
, eq
- p
);
832 quoted
= eq
[1] == '\'';
834 for (q
= eq
+ 1 + quoted
;; q
++) {
870 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
887 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
888 r
= bus_message_type_from_string(value
, &u
);
892 value
= mfree(value
);
896 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
901 components
[n_components
].type
= t
;
902 components
[n_components
].value_str
= value
;
903 components
[n_components
].value_u8
= u
;
911 if (q
[quoted
] != ',') {
919 /* Order the whole thing, so that we always generate the same tree */
920 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
922 /* Check for duplicates */
923 for (i
= 0; i
+1 < n_components
; i
++)
924 if (components
[i
].type
== components
[i
+1].type
) {
929 *_components
= components
;
930 *_n_components
= n_components
;
935 bus_match_parse_free(components
, n_components
);
939 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
940 _cleanup_fclose_
FILE *f
= NULL
;
946 if (n_components
<= 0)
951 f
= open_memstream(&buffer
, &size
);
955 for (i
= 0; i
< n_components
; i
++) {
961 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
965 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
966 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
968 fputs(components
[i
].value_str
, f
);
973 r
= fflush_and_check(f
);
981 struct bus_match_node
*root
,
982 struct bus_match_component
*components
,
983 unsigned n_components
,
984 struct match_callback
*callback
) {
987 struct bus_match_node
*n
;
994 for (i
= 0; i
< n_components
; i
++) {
995 r
= bus_match_add_compare_value(
996 n
, components
[i
].type
,
997 components
[i
].value_u8
, components
[i
].value_str
, &n
);
1002 return bus_match_add_leaf(n
, callback
);
1005 int bus_match_remove(
1006 struct bus_match_node
*root
,
1007 struct match_callback
*callback
) {
1009 struct bus_match_node
*node
, *pp
;
1014 node
= callback
->match_node
;
1018 assert(node
->type
== BUS_MATCH_LEAF
);
1020 callback
->match_node
= NULL
;
1024 bus_match_node_free(node
);
1026 /* Prune the tree above */
1031 if (!bus_match_node_maybe_free(node
))
1039 struct bus_match_node
*root
,
1040 struct bus_match_component
*components
,
1041 unsigned n_components
,
1042 sd_bus_message_handler_t callback
,
1044 struct match_callback
**ret
) {
1046 struct bus_match_node
*n
, **gc
;
1053 gc
= newa(struct bus_match_node
*, n_components
);
1056 for (i
= 0; i
< n_components
; i
++) {
1057 r
= bus_match_find_compare_value(
1058 n
, components
[i
].type
,
1059 components
[i
].value_u8
, components
[i
].value_str
,
1067 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1071 *ret
= n
->leaf
.callback
;
1075 void bus_match_free(struct bus_match_node
*node
) {
1076 struct bus_match_node
*c
;
1081 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1084 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1087 assert(hashmap_isempty(node
->compare
.children
));
1090 while ((c
= node
->child
))
1093 if (node
->type
!= BUS_MATCH_ROOT
)
1094 bus_match_node_free(node
);
1097 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1100 case BUS_MATCH_ROOT
:
1103 case BUS_MATCH_VALUE
:
1106 case BUS_MATCH_LEAF
:
1109 case BUS_MATCH_MESSAGE_TYPE
:
1112 case BUS_MATCH_SENDER
:
1115 case BUS_MATCH_DESTINATION
:
1116 return "destination";
1118 case BUS_MATCH_INTERFACE
:
1121 case BUS_MATCH_MEMBER
:
1124 case BUS_MATCH_PATH
:
1127 case BUS_MATCH_PATH_NAMESPACE
:
1128 return "path_namespace";
1130 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1131 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1134 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1135 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1138 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1139 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1142 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
1143 snprintf(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
1151 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1152 struct bus_match_node
*c
;
1153 _cleanup_free_
char *pfx
= NULL
;
1159 pfx
= strrep(" ", level
);
1160 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1162 if (node
->type
== BUS_MATCH_VALUE
) {
1163 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1164 printf(" <%u>\n", node
->value
.u8
);
1166 printf(" <%s>\n", node
->value
.str
);
1167 } else if (node
->type
== BUS_MATCH_ROOT
)
1169 else if (node
->type
== BUS_MATCH_LEAF
)
1170 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1174 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1177 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1178 bus_match_dump(c
, level
+ 1);
1181 for (c
= node
->child
; c
; c
= c
->next
)
1182 bus_match_dump(c
, level
+ 1);
1185 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1186 bool found_driver
= false;
1189 if (n_components
<= 0)
1190 return BUS_MATCH_GENERIC
;
1194 /* Checks whether the specified match can only match the
1195 * pseudo-service for local messages, which we detect by
1196 * sender, interface or path. If a match is not restricted to
1197 * local messages, then we check if it only matches on the
1200 for (i
= 0; i
< n_components
; i
++) {
1201 const struct bus_match_component
*c
= components
+ i
;
1203 if (c
->type
== BUS_MATCH_SENDER
) {
1204 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1205 return BUS_MATCH_LOCAL
;
1207 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1208 found_driver
= true;
1211 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1212 return BUS_MATCH_LOCAL
;
1214 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1215 return BUS_MATCH_LOCAL
;
1218 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;