1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "bus-internal.h"
6 #include "bus-message.h"
10 #include "sort-util.h"
11 #include "string-util.h"
16 * A: type=signal,sender=foo,interface=bar
17 * B: type=signal,sender=quux,interface=fips
18 * C: type=signal,sender=quux,interface=waldo
19 * D: type=signal,member=test
24 * results in this tree:
27 * + BUS_MATCH_MESSAGE_TYPE
28 * | ` BUS_MATCH_VALUE: value == signal
29 * | + DBUS_MATCH_SENDER
30 * | | + BUS_MATCH_VALUE: value == foo
31 * | | | ` DBUS_MATCH_INTERFACE
32 * | | | ` BUS_MATCH_VALUE: value == bar
33 * | | | ` BUS_MATCH_LEAF: A
34 * | | ` BUS_MATCH_VALUE: value == quux
35 * | | ` DBUS_MATCH_INTERFACE
36 * | | | BUS_MATCH_VALUE: value == fips
37 * | | | ` BUS_MATCH_LEAF: B
38 * | | ` BUS_MATCH_VALUE: value == waldo
39 * | | ` BUS_MATCH_LEAF: C
40 * | + DBUS_MATCH_MEMBER
41 * | | ` BUS_MATCH_VALUE: value == test
42 * | | ` BUS_MATCH_LEAF: D
43 * | + BUS_MATCH_LEAF: F
44 * | ` BUS_MATCH_LEAF: G
46 * ` BUS_MATCH_VALUE: value == miau
50 static bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
51 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_HAS_LAST
;
54 static bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
55 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
56 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_LAST
) ||
57 (t
>= BUS_MATCH_ARG_HAS
&& t
<= BUS_MATCH_ARG_HAS_LAST
);
60 static void bus_match_node_free(struct bus_match_node
*node
) {
64 assert(node
->type
!= BUS_MATCH_ROOT
);
65 assert(node
->type
< _BUS_MATCH_NODE_TYPE_MAX
);
67 if (node
->parent
->child
) {
68 /* We are apparently linked into the parent's child
69 * list. Let's remove us from there. */
71 assert(node
->prev
->next
== node
);
72 node
->prev
->next
= node
->next
;
74 assert(node
->parent
->child
== node
);
75 node
->parent
->child
= node
->next
;
79 node
->next
->prev
= node
->prev
;
82 if (node
->type
== BUS_MATCH_VALUE
) {
83 /* We might be in the parent's hash table, so clean
86 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
87 hashmap_remove(node
->parent
->compare
.children
, UINT_TO_PTR(node
->value
.u8
));
88 else if (BUS_MATCH_CAN_HASH(node
->parent
->type
) && node
->value
.str
)
89 hashmap_remove(node
->parent
->compare
.children
, node
->value
.str
);
91 free(node
->value
.str
);
94 if (BUS_MATCH_IS_COMPARE(node
->type
)) {
95 assert(hashmap_isempty(node
->compare
.children
));
96 hashmap_free(node
->compare
.children
);
102 static bool bus_match_node_maybe_free(struct bus_match_node
*node
) {
105 if (node
->type
== BUS_MATCH_ROOT
)
111 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
114 bus_match_node_free(node
);
118 static bool value_node_test(
119 struct bus_match_node
*node
,
120 enum bus_match_node_type parent_type
,
122 const char *value_str
,
127 assert(node
->type
== BUS_MATCH_VALUE
);
129 /* Tests parameters against this value node, doing prefix
130 * magic and stuff. */
132 switch (parent_type
) {
134 case BUS_MATCH_MESSAGE_TYPE
:
135 return node
->value
.u8
== value_u8
;
137 case BUS_MATCH_SENDER
:
138 if (streq_ptr(node
->value
.str
, value_str
))
141 if (m
->creds
.mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
142 /* on kdbus we have the well known names list
143 * in the credentials, let's make use of that
144 * for an accurate match */
146 STRV_FOREACH(i
, m
->creds
.well_known_names
)
147 if (streq_ptr(node
->value
.str
, *i
))
152 /* If we don't have kdbus, we don't know the
153 * well-known names of the senders. In that,
154 * let's just hope that dbus-daemon doesn't
155 * send us stuff we didn't want. */
157 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
163 case BUS_MATCH_DESTINATION
:
164 case BUS_MATCH_INTERFACE
:
165 case BUS_MATCH_MEMBER
:
167 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
170 return streq_ptr(node
->value
.str
, value_str
);
174 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
: {
175 STRV_FOREACH(i
, value_strv
)
176 if (streq_ptr(node
->value
.str
, *i
))
182 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
184 return namespace_simple_pattern(node
->value
.str
, value_str
);
188 case BUS_MATCH_PATH_NAMESPACE
:
189 return path_simple_pattern(node
->value
.str
, value_str
);
191 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
193 return path_complex_pattern(node
->value
.str
, value_str
);
198 assert_not_reached();
202 static bool value_node_same(
203 struct bus_match_node
*node
,
204 enum bus_match_node_type parent_type
,
206 const char *value_str
) {
208 /* Tests parameters against this value node, not doing prefix
209 * magic and stuff, i.e. this one actually compares the match
213 assert(node
->type
== BUS_MATCH_VALUE
);
215 switch (parent_type
) {
217 case BUS_MATCH_MESSAGE_TYPE
:
218 return node
->value
.u8
== value_u8
;
220 case BUS_MATCH_SENDER
:
221 case BUS_MATCH_DESTINATION
:
222 case BUS_MATCH_INTERFACE
:
223 case BUS_MATCH_MEMBER
:
225 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
226 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
227 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
228 case BUS_MATCH_PATH_NAMESPACE
:
229 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
230 return streq(node
->value
.str
, value_str
);
233 assert_not_reached();
239 struct bus_match_node
*node
,
242 _cleanup_strv_free_
char **test_strv
= NULL
;
243 const char *test_str
= NULL
;
252 if (bus
&& bus
->match_callbacks_modified
)
255 /* Not these special semantics: when traversing the tree we
256 * usually let bus_match_run() when called for a node
257 * recursively invoke bus_match_run(). There's are two
258 * exceptions here though, which are BUS_NODE_ROOT (which
259 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
260 * are invoked anyway by its parent. */
262 switch (node
->type
) {
266 /* Run all children. Since we cannot have any siblings
267 * we won't call any. The children of the root node
268 * are compares or leaves, they will automatically
269 * call their siblings. */
270 return bus_match_run(bus
, node
->child
, m
);
272 case BUS_MATCH_VALUE
:
274 /* Run all children. We don't execute any siblings, we
275 * assume our caller does that. The children of value
276 * nodes are compares or leaves, they will
277 * automatically call their siblings */
280 return bus_match_run(bus
, node
->child
, m
);
285 /* Don't run this match as long as the AddMatch() call is not complete yet.
287 * Don't run this match unless the 'after' counter has been reached.
289 * Don't run this match more than once per iteration */
291 if (node
->leaf
.callback
->install_slot
||
292 m
->read_counter
<= node
->leaf
.callback
->after
||
293 node
->leaf
.callback
->last_iteration
== bus
->iteration_counter
)
294 return bus_match_run(bus
, node
->next
, m
);
296 node
->leaf
.callback
->last_iteration
= bus
->iteration_counter
;
299 r
= sd_bus_message_rewind(m
, true);
303 /* Run the callback. And then invoke siblings. */
304 if (node
->leaf
.callback
->callback
) {
305 _cleanup_(sd_bus_error_free
) sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
308 slot
= container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
);
310 bus
->current_slot
= sd_bus_slot_ref(slot
);
311 bus
->current_handler
= node
->leaf
.callback
->callback
;
312 bus
->current_userdata
= slot
->userdata
;
314 r
= node
->leaf
.callback
->callback(m
, slot
->userdata
, &error_buffer
);
316 bus
->current_userdata
= NULL
;
317 bus
->current_handler
= NULL
;
318 bus
->current_slot
= sd_bus_slot_unref(slot
);
321 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
325 if (bus
&& bus
->match_callbacks_modified
)
329 return bus_match_run(bus
, node
->next
, m
);
331 case BUS_MATCH_MESSAGE_TYPE
:
332 test_u8
= m
->header
->type
;
335 case BUS_MATCH_SENDER
:
336 test_str
= m
->sender
;
337 /* FIXME: resolve test_str from a well-known to a unique name first */
340 case BUS_MATCH_DESTINATION
:
341 test_str
= m
->destination
;
344 case BUS_MATCH_INTERFACE
:
345 test_str
= m
->interface
;
348 case BUS_MATCH_MEMBER
:
349 test_str
= m
->member
;
353 case BUS_MATCH_PATH_NAMESPACE
:
357 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
358 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
, &test_str
);
361 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
362 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
, &test_str
);
365 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
366 (void) bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
, &test_str
);
369 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
370 (void) bus_message_get_arg_strv(m
, node
->type
- BUS_MATCH_ARG_HAS
, &test_strv
);
374 assert_not_reached();
377 if (BUS_MATCH_CAN_HASH(node
->type
)) {
378 struct bus_match_node
*found
;
380 /* Lookup via hash table, nice! So let's jump directly. */
383 found
= hashmap_get(node
->compare
.children
, test_str
);
384 else if (test_strv
) {
385 STRV_FOREACH(i
, test_strv
) {
386 found
= hashmap_get(node
->compare
.children
, *i
);
388 r
= bus_match_run(bus
, found
, m
);
395 } else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
396 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
401 r
= bus_match_run(bus
, found
, m
);
406 /* No hash table, so let's iterate manually... */
407 for (struct bus_match_node
*c
= node
->child
; c
; c
= c
->next
) {
408 if (!value_node_test(c
, node
->type
, test_u8
, test_str
, test_strv
, m
))
411 r
= bus_match_run(bus
, c
, m
);
415 if (bus
&& bus
->match_callbacks_modified
)
419 if (bus
&& bus
->match_callbacks_modified
)
422 /* And now, let's invoke our siblings */
423 return bus_match_run(bus
, node
->next
, m
);
426 static int bus_match_add_compare_value(
427 struct bus_match_node
*where
,
428 enum bus_match_node_type t
,
430 const char *value_str
,
431 struct bus_match_node
**ret
) {
433 struct bus_match_node
*c
, *n
= NULL
;
437 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
438 assert(BUS_MATCH_IS_COMPARE(t
));
441 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
445 /* Comparison node already exists? Then let's see if the value node exists too. */
447 if (t
== BUS_MATCH_MESSAGE_TYPE
)
448 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
449 else if (BUS_MATCH_CAN_HASH(t
))
450 n
= hashmap_get(c
->compare
.children
, value_str
);
452 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
460 /* Comparison node, doesn't exist yet? Then let's create it. */
462 c
= new0(struct bus_match_node
, 1);
470 c
->next
= where
->child
;
475 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
476 c
->compare
.children
= hashmap_new(NULL
);
477 if (!c
->compare
.children
) {
481 } else if (BUS_MATCH_CAN_HASH(t
)) {
482 c
->compare
.children
= hashmap_new(&string_hash_ops
);
483 if (!c
->compare
.children
) {
490 n
= new0(struct bus_match_node
, 1);
496 n
->type
= BUS_MATCH_VALUE
;
497 n
->value
.u8
= value_u8
;
499 n
->value
.str
= strdup(value_str
);
507 if (c
->compare
.children
) {
509 if (t
== BUS_MATCH_MESSAGE_TYPE
)
510 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
512 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
528 bus_match_node_maybe_free(c
);
538 static int bus_match_add_leaf(
539 struct bus_match_node
*where
,
540 struct match_callback
*callback
) {
542 struct bus_match_node
*n
;
545 assert(IN_SET(where
->type
, BUS_MATCH_ROOT
, BUS_MATCH_VALUE
));
548 n
= new0(struct bus_match_node
, 1);
552 n
->type
= BUS_MATCH_LEAF
;
554 n
->next
= where
->child
;
558 n
->leaf
.callback
= callback
;
559 callback
->match_node
= n
;
566 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
569 if (n
== 4 && startswith(k
, "type"))
570 return BUS_MATCH_MESSAGE_TYPE
;
571 if (n
== 6 && startswith(k
, "sender"))
572 return BUS_MATCH_SENDER
;
573 if (n
== 11 && startswith(k
, "destination"))
574 return BUS_MATCH_DESTINATION
;
575 if (n
== 9 && startswith(k
, "interface"))
576 return BUS_MATCH_INTERFACE
;
577 if (n
== 6 && startswith(k
, "member"))
578 return BUS_MATCH_MEMBER
;
579 if (n
== 4 && startswith(k
, "path"))
580 return BUS_MATCH_PATH
;
581 if (n
== 14 && startswith(k
, "path_namespace"))
582 return BUS_MATCH_PATH_NAMESPACE
;
584 if (n
== 4 && startswith(k
, "arg")) {
591 return BUS_MATCH_ARG
+ j
;
594 if (n
== 5 && startswith(k
, "arg")) {
596 enum bus_match_node_type t
;
603 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
604 if (t
> BUS_MATCH_ARG_LAST
)
610 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
617 return BUS_MATCH_ARG_PATH
+ j
;
620 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
621 enum bus_match_node_type t
;
629 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
630 if (t
> BUS_MATCH_ARG_PATH_LAST
)
636 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
643 return BUS_MATCH_ARG_NAMESPACE
+ j
;
646 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
647 enum bus_match_node_type t
;
655 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
656 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
662 if (n
== 7 && startswith(k
, "arg") && startswith(k
+ 4, "has")) {
669 return BUS_MATCH_ARG_HAS
+ j
;
672 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 5, "has")) {
673 enum bus_match_node_type t
;
681 t
= BUS_MATCH_ARG_HAS
+ a
* 10 + b
;
682 if (t
> BUS_MATCH_ARG_HAS_LAST
)
691 static int match_component_compare(const struct bus_match_component
*a
, const struct bus_match_component
*b
) {
692 return CMP(a
->type
, b
->type
);
695 void bus_match_parse_free(struct bus_match_component
*components
, size_t n_components
) {
696 for (size_t i
= 0; i
< n_components
; i
++)
697 free(components
[i
].value_str
);
704 struct bus_match_component
**ret_components
,
705 size_t *ret_n_components
) {
707 struct bus_match_component
*components
= NULL
;
708 size_t n_components
= 0;
712 assert(ret_components
);
713 assert(ret_n_components
);
715 CLEANUP_ARRAY(components
, n_components
, bus_match_parse_free
);
717 while (*match
!= '\0') {
719 enum bus_match_node_type t
;
721 _cleanup_free_
char *value
= NULL
;
722 bool escaped
= false, quoted
;
725 /* Avahi's match rules appear to include whitespace, skip over it */
726 match
+= strspn(match
, " ");
728 eq
= strchr(match
, '=');
732 t
= bus_match_node_type_from_string(match
, eq
- match
);
736 quoted
= eq
[1] == '\'';
738 for (q
= eq
+ 1 + quoted
;; q
++) {
771 if (!GREEDY_REALLOC(value
, j
+ 2))
784 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
785 r
= bus_message_type_from_string(value
, &u
);
789 value
= mfree(value
);
793 if (!GREEDY_REALLOC(components
, n_components
+ 1))
796 components
[n_components
++] = (struct bus_match_component
) {
798 .value_str
= TAKE_PTR(value
),
805 if (q
[quoted
] != ',')
808 match
= q
+ 1 + quoted
;
811 /* Order the whole thing, so that we always generate the same tree */
812 typesafe_qsort(components
, n_components
, match_component_compare
);
814 /* Check for duplicates */
815 for (size_t i
= 0; i
+1 < n_components
; i
++)
816 if (components
[i
].type
== components
[i
+1].type
)
819 *ret_components
= TAKE_PTR(components
);
820 *ret_n_components
= n_components
;
825 char *bus_match_to_string(struct bus_match_component
*components
, size_t n_components
) {
826 _cleanup_free_
char *buffer
= NULL
;
830 if (n_components
<= 0)
835 FILE *f
= open_memstream_unlocked(&buffer
, &size
);
839 for (size_t i
= 0; i
< n_components
; i
++) {
845 fputs(bus_match_node_type_to_string(components
[i
].type
, buf
, sizeof(buf
)), f
);
849 if (components
[i
].type
== BUS_MATCH_MESSAGE_TYPE
)
850 fputs(bus_message_type_to_string(components
[i
].value_u8
), f
);
852 fputs(components
[i
].value_str
, f
);
857 r
= fflush_and_check(f
);
861 return TAKE_PTR(buffer
);
865 struct bus_match_node
*root
,
866 struct bus_match_component
*components
,
868 struct match_callback
*callback
) {
875 for (size_t i
= 0; i
< n_components
; i
++) {
876 r
= bus_match_add_compare_value(root
,
878 components
[i
].value_u8
,
879 components
[i
].value_str
,
885 return bus_match_add_leaf(root
, callback
);
888 int bus_match_remove(
889 struct bus_match_node
*root
,
890 struct match_callback
*callback
) {
892 struct bus_match_node
*node
, *pp
;
897 node
= callback
->match_node
;
901 assert(node
->type
== BUS_MATCH_LEAF
);
903 callback
->match_node
= NULL
;
907 bus_match_node_free(node
);
909 /* Prune the tree above */
914 if (!bus_match_node_maybe_free(node
))
921 void bus_match_free(struct bus_match_node
*node
) {
922 struct bus_match_node
*c
;
927 if (BUS_MATCH_CAN_HASH(node
->type
)) {
929 HASHMAP_FOREACH(c
, node
->compare
.children
)
932 assert(hashmap_isempty(node
->compare
.children
));
935 while ((c
= node
->child
))
938 if (node
->type
!= BUS_MATCH_ROOT
)
939 bus_match_node_free(node
);
942 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
948 case BUS_MATCH_VALUE
:
954 case BUS_MATCH_MESSAGE_TYPE
:
957 case BUS_MATCH_SENDER
:
960 case BUS_MATCH_DESTINATION
:
961 return "destination";
963 case BUS_MATCH_INTERFACE
:
966 case BUS_MATCH_MEMBER
:
972 case BUS_MATCH_PATH_NAMESPACE
:
973 return "path_namespace";
975 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
976 return snprintf_ok(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
978 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
979 return snprintf_ok(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
981 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
982 return snprintf_ok(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
984 case BUS_MATCH_ARG_HAS
... BUS_MATCH_ARG_HAS_LAST
:
985 return snprintf_ok(buf
, l
, "arg%ihas", t
- BUS_MATCH_ARG_HAS
);
992 void bus_match_dump(FILE *out
, struct bus_match_node
*node
, unsigned level
) {
998 fprintf(out
, "%*s[%s]", 2 * (int) level
, "", bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
1000 if (node
->type
== BUS_MATCH_VALUE
) {
1001 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
1002 fprintf(out
, " <%u>\n", node
->value
.u8
);
1004 fprintf(out
, " <%s>\n", node
->value
.str
);
1005 } else if (node
->type
== BUS_MATCH_ROOT
)
1006 fputs(" root\n", out
);
1007 else if (node
->type
== BUS_MATCH_LEAF
)
1008 fprintf(out
, " %p/%p\n", node
->leaf
.callback
->callback
,
1009 container_of(node
->leaf
.callback
, sd_bus_slot
, match_callback
)->userdata
);
1013 if (BUS_MATCH_CAN_HASH(node
->type
)) {
1014 struct bus_match_node
*c
;
1015 HASHMAP_FOREACH(c
, node
->compare
.children
)
1016 bus_match_dump(out
, c
, level
+ 1);
1019 for (struct bus_match_node
*c
= node
->child
; c
; c
= c
->next
)
1020 bus_match_dump(out
, c
, level
+ 1);
1023 enum bus_match_scope
bus_match_get_scope(const struct bus_match_component
*components
, size_t n_components
) {
1024 bool found_driver
= false;
1026 if (n_components
<= 0)
1027 return BUS_MATCH_GENERIC
;
1031 /* Checks whether the specified match can only match the
1032 * pseudo-service for local messages, which we detect by
1033 * sender, interface or path. If a match is not restricted to
1034 * local messages, then we check if it only matches on the
1037 for (size_t i
= 0; i
< n_components
; i
++) {
1038 const struct bus_match_component
*c
= components
+ i
;
1040 if (c
->type
== BUS_MATCH_SENDER
) {
1041 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1042 return BUS_MATCH_LOCAL
;
1044 if (streq_ptr(c
->value_str
, "org.freedesktop.DBus"))
1045 found_driver
= true;
1048 if (c
->type
== BUS_MATCH_INTERFACE
&& streq_ptr(c
->value_str
, "org.freedesktop.DBus.Local"))
1049 return BUS_MATCH_LOCAL
;
1051 if (c
->type
== BUS_MATCH_PATH
&& streq_ptr(c
->value_str
, "/org/freedesktop/DBus/Local"))
1052 return BUS_MATCH_LOCAL
;
1055 return found_driver
? BUS_MATCH_DRIVER
: BUS_MATCH_GENERIC
;