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_NAMESPACE_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
);
72 static void bus_match_node_free(struct bus_match_node
*node
) {
76 assert(node
->type
!= BUS_MATCH_ROOT
);
77 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
79 if (node
->parent
->child
) {
80 /* We are apparently linked into the parent's child
81 * list. Let's remove us from there. */
83 assert(node
->prev
->next
== node
);
84 node
->prev
->next
= node
->next
;
86 assert(node
->parent
->child
== node
);
87 node
->parent
->child
= node
->next
;
91 node
->next
->prev
= node
->prev
;
94 if (node
->type
== BUS_MATCH_VALUE
) {
95 /* We might be in the parent's hash table, so clean
98 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
99 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
100 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
101 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
103 free(node
->value
.str
);
106 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
107 assert(hashmap_isempty(node
->compare
.children
));
108 hashmap_free(node
->compare
.children
);
114 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
117 if (node
->type
== BUS_MATCH_ROOT
)
123 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
126 bus_match_node_free(node
);
130 static bool value_node_test(
131 struct bus_match_node
*node
,
132 enum bus_match_node_type parent_type
,
134 const char *value_str
,
139 assert(node
->type
== BUS_MATCH_VALUE
);
141 /* Tests parameters against this value node, doing prefix
142 * magic and stuff. */
144 switch (parent_type
) {
146 case BUS_MATCH_MESSAGE_TYPE
:
147 return node
->value
.u8
== value_u8
;
149 case BUS_MATCH_SENDER
:
150 if (streq_ptr(node
->value
.str
, value_str
))
153 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
156 /* on kdbus we have the well known names list
157 * in the credentials, let's make use of that
158 * for an accurate match */
160 STRV_FOREACH(i
, m
->creds
.well_known_names
)
161 if (streq_ptr(node
->value
.str
, *i
))
166 /* If we don't have kdbus, we don't know the
167 * well-known names of the senders. In that,
168 * let's just hope that dbus-daemon doesn't
169 * send us stuff we didn't want. */
171 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
177 case BUS_MATCH_DESTINATION
:
178 case BUS_MATCH_INTERFACE
:
179 case BUS_MATCH_MEMBER
:
181 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
: {
185 return streq_ptr(node
->value
.str
, value_str
);
187 STRV_FOREACH(i
, value_strv
)
188 if (streq_ptr(node
->value
.str
, *i
))
194 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
: {
198 return namespace_simple_pattern(node
->value
.str
, value_str
);
200 STRV_FOREACH(i
, value_strv
)
201 if (namespace_simple_pattern(node
->value
.str
, *i
))
206 case BUS_MATCH_PATH_NAMESPACE
:
207 return path_simple_pattern(node
->value
.str
, value_str
);
209 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
: {
213 return path_complex_pattern(node
->value
.str
, value_str
);
215 STRV_FOREACH(i
, value_strv
)
216 if (path_complex_pattern(node
->value
.str
, *i
))
223 assert_not_reached("Invalid node type");
227 static bool value_node_same(
228 struct bus_match_node
*node
,
229 enum bus_match_node_type parent_type
,
231 const char *value_str
) {
233 /* Tests parameters against this value node, not doing prefix
234 * magic and stuff, i.e. this one actually compares the match
238 assert(node
->type
== BUS_MATCH_VALUE
);
240 switch (parent_type
) {
242 case BUS_MATCH_MESSAGE_TYPE
:
243 return node
->value
.u8
== value_u8
;
245 case BUS_MATCH_SENDER
:
246 case BUS_MATCH_DESTINATION
:
247 case BUS_MATCH_INTERFACE
:
248 case BUS_MATCH_MEMBER
:
250 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
251 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
252 case BUS_MATCH_PATH_NAMESPACE
:
253 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
254 return streq(node
->value
.str
, value_str
);
257 assert_not_reached("Invalid node type");
263 struct bus_match_node
*node
,
266 _cleanup_strv_free_
char **test_strv
= NULL
;
267 const char *test_str
= NULL
;
276 if (bus
&& bus
->match_callbacks_modified
)
279 /* Not these special semantics: when traversing the tree we
280 * usually let bus_match_run() when called for a node
281 * recursively invoke bus_match_run(). There's are two
282 * exceptions here though, which are BUS_NODE_ROOT (which
283 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
284 * are invoked anyway by its parent. */
286 switch (node
->type
) {
290 /* Run all children. Since we cannot have any siblings
291 * we won't call any. The children of the root node
292 * are compares or leaves, they will automatically
293 * call their siblings. */
294 return bus_match_run(bus
, node
->child
, m
);
296 case BUS_MATCH_VALUE
:
298 /* Run all children. We don't execute any siblings, we
299 * assume our caller does that. The children of value
300 * nodes are compares or leaves, they will
301 * automatically call their siblings */
304 return bus_match_run(bus
, node
->child
, m
);
309 if (node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
312 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
315 r
= sd_bus_message_rewind(m
, true);
319 /* Run the callback. And then invoke siblings. */
320 if (node
->leaf
.callback
->callback
) {
321 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
324 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
326 bus
->current_slot
= sd_bus_slot_ref(slot
);
327 bus
->current_handler
= node
->leaf
.callback
->callback
;
328 bus
->current_userdata
= slot
->userdata
;
330 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
332 bus
->current_userdata
= NULL
;
333 bus
->current_handler
= NULL
;
334 bus
->current_slot
= sd_bus_slot_unref(slot
);
337 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
341 if (bus
&& bus
->match_callbacks_modified
)
345 return bus_match_run(bus
, node
->next
, m
);
347 case BUS_MATCH_MESSAGE_TYPE
:
348 test_u8
= m
->header
->type
;
351 case BUS_MATCH_SENDER
:
352 test_str
= m
->sender
;
353 /* FIXME: resolve test_str from a well-known to a unique name first */
356 case BUS_MATCH_DESTINATION
:
357 test_str
= m
->destination
;
360 case BUS_MATCH_INTERFACE
:
361 test_str
= m
->interface
;
364 case BUS_MATCH_MEMBER
:
365 test_str
= m
->member
;
369 case BUS_MATCH_PATH_NAMESPACE
:
373 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
374 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
, &test_strv
);
377 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
378 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
, &test_strv
);
381 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
382 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
, &test_strv
);
386 assert_not_reached("Unknown match type.");
389 if (BUS_MATCH_CAN_HASH(node
->type
)) {
390 struct bus_match_node
*found
;
392 /* Lookup via hash table, nice! So let's jump directly. */
395 found
= hashmap_get(node
->compare
.children
, test_str
);
396 else if (test_strv
) {
399 STRV_FOREACH(i
, test_strv
) {
400 found
= hashmap_get(node
->compare
.children
, *i
);
402 r
= bus_match_run(bus
, found
, m
);
409 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
410 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
415 r
= bus_match_run(bus
, found
, m
);
420 struct bus_match_node
*c
;
422 /* No hash table, so let's iterate manually... */
424 for (c
= node
->child
; c
; c
= c
->next
) {
425 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
428 r
= bus_match_run(bus
, c
, m
);
434 if (bus
&& bus
->match_callbacks_modified
)
437 /* And now, let's invoke our siblings */
438 return bus_match_run(bus
, node
->next
, m
);
441 static int bus_match_add_compare_value(
442 struct bus_match_node
*where
,
443 enum bus_match_node_type t
,
445 const char *value_str
,
446 struct bus_match_node
**ret
) {
448 struct bus_match_node
*c
= NULL
, *n
= NULL
;
452 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
453 assert(BUS_MATCH_IS_COMPARE(t
));
456 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
460 /* Comparison node already exists? Then let's see if
461 * the value node exists too. */
463 if (t
== BUS_MATCH_MESSAGE_TYPE
)
464 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
465 else if (BUS_MATCH_CAN_HASH(t
))
466 n
= hashmap_get(c
->compare
.children
, value_str
);
468 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
477 /* Comparison node, doesn't exist yet? Then let's
480 c
= new0(struct bus_match_node
, 1);
488 c
->next
= where
->child
;
493 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
494 c
->compare
.children
= hashmap_new(NULL
);
495 if (!c
->compare
.children
) {
499 } else if (BUS_MATCH_CAN_HASH(t
)) {
500 c
->compare
.children
= hashmap_new(&string_hash_ops
);
501 if (!c
->compare
.children
) {
508 n
= new0(struct bus_match_node
, 1);
514 n
->type
= BUS_MATCH_VALUE
;
515 n
->value
.u8
= value_u8
;
517 n
->value
.str
= strdup(value_str
);
525 if (c
->compare
.children
) {
527 if (t
== BUS_MATCH_MESSAGE_TYPE
)
528 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
530 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
546 bus_match_node_maybe_free(c
);
556 static int bus_match_find_compare_value(
557 struct bus_match_node
*where
,
558 enum bus_match_node_type t
,
560 const char *value_str
,
561 struct bus_match_node
**ret
) {
563 struct bus_match_node
*c
, *n
;
566 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
567 assert(BUS_MATCH_IS_COMPARE(t
));
570 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
576 if (t
== BUS_MATCH_MESSAGE_TYPE
)
577 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
578 else if (BUS_MATCH_CAN_HASH(t
))
579 n
= hashmap_get(c
->compare
.children
, value_str
);
581 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
593 static int bus_match_add_leaf(
594 struct bus_match_node
*where
,
595 struct match_callback
*callback
) {
597 struct bus_match_node
*n
;
600 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
603 n
= new0(struct bus_match_node
, 1);
607 n
->type
= BUS_MATCH_LEAF
;
609 n
->next
= where
->child
;
613 n
->leaf
.callback
= callback
;
614 callback
->match_node
= n
;
621 static int bus_match_find_leaf(
622 struct bus_match_node
*where
,
623 sd_bus_message_handler_t callback
,
625 struct bus_match_node
**ret
) {
627 struct bus_match_node
*c
;
630 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
633 for (c
= where
->child
; c
; c
= c
->next
) {
636 s
= container_of(c
->leaf
.callback
, sd_bus_slot
, match_callback
);
638 if (c
->type
== BUS_MATCH_LEAF
&&
639 c
->leaf
.callback
->callback
== callback
&&
640 s
->userdata
== userdata
) {
649 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
652 if (n
== 4 && startswith(k
, "type"))
653 return BUS_MATCH_MESSAGE_TYPE
;
654 if (n
== 6 && startswith(k
, "sender"))
655 return BUS_MATCH_SENDER
;
656 if (n
== 11 && startswith(k
, "destination"))
657 return BUS_MATCH_DESTINATION
;
658 if (n
== 9 && startswith(k
, "interface"))
659 return BUS_MATCH_INTERFACE
;
660 if (n
== 6 && startswith(k
, "member"))
661 return BUS_MATCH_MEMBER
;
662 if (n
== 4 && startswith(k
, "path"))
663 return BUS_MATCH_PATH
;
664 if (n
== 14 && startswith(k
, "path_namespace"))
665 return BUS_MATCH_PATH_NAMESPACE
;
667 if (n
== 4 && startswith(k
, "arg")) {
674 return BUS_MATCH_ARG
+ j
;
677 if (n
== 5 && startswith(k
, "arg")) {
679 enum bus_match_node_type t
;
686 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
687 if (t
> BUS_MATCH_ARG_LAST
)
693 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
700 return BUS_MATCH_ARG_PATH
+ j
;
703 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
704 enum bus_match_node_type t
;
712 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
713 if (t
> BUS_MATCH_ARG_PATH_LAST
)
719 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
726 return BUS_MATCH_ARG_NAMESPACE
+ j
;
729 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
730 enum bus_match_node_type t
;
738 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
739 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
748 static int match_component_compare(const void *a
, const void *b
) {
749 const struct bus_match_component
*x
= a
, *y
= b
;
751 if (x
->type
< y
->type
)
753 if (x
->type
> y
->type
)
759 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
762 for (i
= 0; i
< n_components
; i
++)
763 free(components
[i
].value_str
);
770 struct bus_match_component
**_components
,
771 unsigned *_n_components
) {
773 const char *p
= match
;
774 struct bus_match_component
*components
= NULL
;
775 size_t components_allocated
= 0;
776 unsigned n_components
= 0, i
;
777 _cleanup_free_
char *value
= NULL
;
782 assert(_n_components
);
786 enum bus_match_node_type t
;
788 size_t value_allocated
= 0;
789 bool escaped
= false, quoted
;
792 /* Avahi's match rules appear to include whitespace, skip over it */
799 t
= bus_match_node_type_from_string(p
, eq
- p
);
803 quoted
= eq
[1] == '\'';
805 for (q
= eq
+ 1 + quoted
;; q
++) {
841 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
858 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
859 r
= bus_message_type_from_string(value
, &u
);
863 value
= mfree(value
);
867 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
872 components
[n_components
].type
= t
;
873 components
[n_components
].value_str
= value
;
874 components
[n_components
].value_u8
= u
;
882 if (q
[quoted
] != ',') {
890 /* Order the whole thing, so that we always generate the same tree */
891 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
893 /* Check for duplicates */
894 for (i
= 0; i
+1 < n_components
; i
++)
895 if (components
[i
].type
== components
[i
+1].type
) {
900 *_components
= components
;
901 *_n_components
= n_components
;
906 bus_match_parse_free(components
, n_components
);
910 char *bus_match_to_string(struct bus_match_component
*components
, unsigned n_components
) {
911 _cleanup_free_
FILE *f
= NULL
;
917 if (n_components
<= 0)
922 f
= open_memstream(&buffer
, &size
);
926 for (i
= 0; i
< n_components
; i
++) {
932 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
936 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
937 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
939 fputs(components
[i
].value_str
, f
);
944 r
= fflush_and_check(f
);
952 struct bus_match_node
*root
,
953 struct bus_match_component
*components
,
954 unsigned n_components
,
955 struct match_callback
*callback
) {
958 struct bus_match_node
*n
;
965 for (i
= 0; i
< n_components
; i
++) {
966 r
= bus_match_add_compare_value(
967 n
, components
[i
].type
,
968 components
[i
].value_u8
, components
[i
].value_str
, &n
);
973 return bus_match_add_leaf(n
, callback
);
976 int bus_match_remove(
977 struct bus_match_node
*root
,
978 struct match_callback
*callback
) {
980 struct bus_match_node
*node
, *pp
;
985 node
= callback
->match_node
;
989 assert(node
->type
== BUS_MATCH_LEAF
);
991 callback
->match_node
= NULL
;
995 bus_match_node_free(node
);
997 /* Prune the tree above */
1002 if (!bus_match_node_maybe_free(node
))
1010 struct bus_match_node
*root
,
1011 struct bus_match_component
*components
,
1012 unsigned n_components
,
1013 sd_bus_message_handler_t callback
,
1015 struct match_callback
**ret
) {
1017 struct bus_match_node
*n
, **gc
;
1024 gc
= newa(struct bus_match_node
*, n_components
);
1027 for (i
= 0; i
< n_components
; i
++) {
1028 r
= bus_match_find_compare_value(
1029 n
, components
[i
].type
,
1030 components
[i
].value_u8
, components
[i
].value_str
,
1038 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
1042 *ret
= n
->leaf
.callback
;
1046 void bus_match_free(struct bus_match_node
*node
) {
1047 struct bus_match_node
*c
;
1052 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1055 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1058 assert(hashmap_isempty(node
->compare
.children
));
1061 while ((c
= node
->child
))
1064 if (node
->type
!= BUS_MATCH_ROOT
)
1065 bus_match_node_free(node
);
1068 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
1071 case BUS_MATCH_ROOT
:
1074 case BUS_MATCH_VALUE
:
1077 case BUS_MATCH_LEAF
:
1080 case BUS_MATCH_MESSAGE_TYPE
:
1083 case BUS_MATCH_SENDER
:
1086 case BUS_MATCH_DESTINATION
:
1087 return "destination";
1089 case BUS_MATCH_INTERFACE
:
1092 case BUS_MATCH_MEMBER
:
1095 case BUS_MATCH_PATH
:
1098 case BUS_MATCH_PATH_NAMESPACE
:
1099 return "path_namespace";
1101 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
1102 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
1105 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
1106 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
1109 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
1110 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
1118 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
1119 struct bus_match_node
*c
;
1120 _cleanup_free_
char *pfx
= NULL
;
1126 pfx
= strrep(" ", level
);
1127 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1129 if (node
->type
== BUS_MATCH_VALUE
) {
1130 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1131 printf(" <%u>\n", node
->value
.u8
);
1133 printf(" <%s>\n", node
->value
.str
);
1134 } else if (node
->type
== BUS_MATCH_ROOT
)
1136 else if (node
->type
== BUS_MATCH_LEAF
)
1137 printf(" %p/%p\n", node
->leaf
.callback
->callback
, container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1141 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1144 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
1145 bus_match_dump(c
, level
+ 1);
1148 for (c
= node
->child
; c
; c
= c
->next
)
1149 bus_match_dump(c
, level
+ 1);
1152 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, unsigned n_components
) {
1153 bool found_driver
= false;
1156 if (n_components
<= 0)
1157 return BUS_MATCH_GENERIC
;
1161 /* Checks whether the specified match can only match the
1162 * pseudo-service for local messages, which we detect by
1163 * sender, interface or path. If a match is not restricted to
1164 * local messages, then we check if it only matches on the
1167 for (i
= 0; i
< n_components
; i
++) {
1168 const struct bus_match_component
*c
= components
+ i
;
1170 if (c
->type
== BUS_MATCH_SENDER
) {
1171 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1172 return BUS_MATCH_LOCAL
;
1174 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1175 found_driver
= true;
1178 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1179 return BUS_MATCH_LOCAL
;
1181 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1182 return BUS_MATCH_LOCAL
;
1185 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;