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"
25 #include "bus-error.h"
30 * A: type=signal,sender=foo,interface=bar
31 * B: type=signal,sender=quux,interface=fips
32 * C: type=signal,sender=quux,interface=waldo
33 * D: type=signal,member=test
38 * results in this tree:
41 * + BUS_MATCH_MESSAGE_TYPE
42 * | ` BUS_MATCH_VALUE: value == signal
43 * | + DBUS_MATCH_SENDER
44 * | | + BUS_MATCH_VALUE: value == foo
45 * | | | ` DBUS_MATCH_INTERFACE
46 * | | | ` BUS_MATCH_VALUE: value == bar
47 * | | | ` BUS_MATCH_LEAF: A
48 * | | ` BUS_MATCH_VALUE: value == quux
49 * | | ` DBUS_MATCH_INTERFACE
50 * | | | BUS_MATCH_VALUE: value == fips
51 * | | | ` BUS_MATCH_LEAF: B
52 * | | ` BUS_MATCH_VALUE: value == waldo
53 * | | ` BUS_MATCH_LEAF: C
54 * | + DBUS_MATCH_MEMBER
55 * | | ` BUS_MATCH_VALUE: value == test
56 * | | ` BUS_MATCH_LEAF: D
57 * | + BUS_MATCH_LEAF: F
58 * | ` BUS_MATCH_LEAF: G
60 * ` BUS_MATCH_VALUE: value == miau
64 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t
) {
65 return t
>= BUS_MATCH_SENDER
&& t
<= BUS_MATCH_ARG_NAMESPACE_LAST
;
68 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t
) {
69 return (t
>= BUS_MATCH_MESSAGE_TYPE
&& t
<= BUS_MATCH_PATH
) ||
70 (t
>= BUS_MATCH_ARG
&& t
<= BUS_MATCH_ARG_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
) {
121 if (BUS_MATCH_IS_COMPARE(node
->type
) && !hashmap_isempty(node
->compare
.children
))
124 bus_match_node_free(node
);
128 static bool value_node_test(
129 struct bus_match_node
*node
,
130 enum bus_match_node_type parent_type
,
132 const char *value_str
) {
135 assert(node
->type
== BUS_MATCH_VALUE
);
137 /* Tests parameters against this value node, doing prefix
138 * magic and stuff. */
140 switch (parent_type
) {
142 case BUS_MATCH_MESSAGE_TYPE
:
143 return node
->value
.u8
== value_u8
;
145 case BUS_MATCH_SENDER
:
146 case BUS_MATCH_DESTINATION
:
147 if (streq_ptr(node
->value
.str
, value_str
))
150 /* FIXME: So here's an ugliness: if the match is for a
151 * well-known name then we cannot actually check this
152 * correctly here. This doesn't matter much for dbus1
153 * where no false positives exist, hence we just
154 * ignore this case here. For kdbus the messages
155 * should contain all well-known names of the sender,
156 * hence we can fix things there correctly. */
158 if (node
->value
.str
[0] != ':' && value_str
&& value_str
[0] == ':')
163 case BUS_MATCH_INTERFACE
:
164 case BUS_MATCH_MEMBER
:
166 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
167 return streq_ptr(node
->value
.str
, value_str
);
169 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
170 return namespace_simple_pattern(node
->value
.str
, value_str
);
172 case BUS_MATCH_PATH_NAMESPACE
:
173 return path_simple_pattern(node
->value
.str
, value_str
);
175 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
176 return path_complex_pattern(node
->value
.str
, value_str
);
179 assert_not_reached("Invalid node type");
183 static bool value_node_same(
184 struct bus_match_node
*node
,
185 enum bus_match_node_type parent_type
,
187 const char *value_str
) {
189 /* Tests parameters against this value node, not doing prefix
190 * magic and stuff, i.e. this one actually compares the match
194 assert(node
->type
== BUS_MATCH_VALUE
);
196 switch (parent_type
) {
198 case BUS_MATCH_MESSAGE_TYPE
:
199 return node
->value
.u8
== value_u8
;
201 case BUS_MATCH_SENDER
:
202 case BUS_MATCH_DESTINATION
:
203 case BUS_MATCH_INTERFACE
:
204 case BUS_MATCH_MEMBER
:
206 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
207 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
208 case BUS_MATCH_PATH_NAMESPACE
:
209 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
210 return streq(node
->value
.str
, value_str
);
213 assert_not_reached("Invalid node type");
219 struct bus_match_node
*node
,
223 const char *test_str
= NULL
;
232 if (bus
&& bus
->match_callbacks_modified
)
235 /* Not these special semantics: when traversing the tree we
236 * usually let bus_match_run() when called for a node
237 * recursively invoke bus_match_run(). There's are two
238 * exceptions here though, which are BUS_NODE_ROOT (which
239 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
240 * are invoked anyway by its parent. */
242 switch (node
->type
) {
246 /* Run all children. Since we cannot have any siblings
247 * we won't call any. The children of the root node
248 * are compares or leaves, they will automatically
249 * call their siblings. */
250 return bus_match_run(bus
, node
->child
, m
);
252 case BUS_MATCH_VALUE
:
254 /* Run all children. We don't execute any siblings, we
255 * assume our caller does that. The children of value
256 * nodes are compares or leaves, they will
257 * automatically call their siblings */
260 return bus_match_run(bus
, node
->child
, m
);
265 if (node
->leaf
.last_iteration
== bus
->iteration_counter
)
268 node
->leaf
.last_iteration
= bus
->iteration_counter
;
271 r
= sd_bus_message_rewind(m
, true);
275 /* Run the callback. And then invoke siblings. */
276 if (node
->leaf
.callback
) {
277 _cleanup_bus_error_free_ sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
279 r
= node
->leaf
.callback(bus
, m
, node
->leaf
.userdata
, &error_buffer
);
280 r
= bus_maybe_reply_error(m
, r
, &error_buffer
);
285 return bus_match_run(bus
, node
->next
, m
);
287 case BUS_MATCH_MESSAGE_TYPE
:
288 test_u8
= m
->header
->type
;
291 case BUS_MATCH_SENDER
:
292 test_str
= m
->sender
;
293 /* FIXME: resolve test_str from a well-known to a unique name first */
296 case BUS_MATCH_DESTINATION
:
297 test_str
= m
->destination
;
300 case BUS_MATCH_INTERFACE
:
301 test_str
= m
->interface
;
304 case BUS_MATCH_MEMBER
:
305 test_str
= m
->member
;
309 case BUS_MATCH_PATH_NAMESPACE
:
313 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
314 test_str
= bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG
);
317 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
318 test_str
= bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_PATH
);
321 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
322 test_str
= bus_message_get_arg(m
, node
->type
- BUS_MATCH_ARG_NAMESPACE
);
326 assert_not_reached("Unknown match type.");
329 if (BUS_MATCH_CAN_HASH(node
->type
)) {
330 struct bus_match_node
*found
;
332 /* Lookup via hash table, nice! So let's jump directly. */
335 found
= hashmap_get(node
->compare
.children
, test_str
);
336 else if (node
->type
== BUS_MATCH_MESSAGE_TYPE
)
337 found
= hashmap_get(node
->compare
.children
, UINT_TO_PTR(test_u8
));
342 r
= bus_match_run(bus
, found
, m
);
347 struct bus_match_node
*c
;
349 /* No hash table, so let's iterate manually... */
351 for (c
= node
->child
; c
; c
= c
->next
) {
352 if (!value_node_test(c
, node
->type
, test_u8
, test_str
))
355 r
= bus_match_run(bus
, c
, m
);
361 if (bus
&& bus
->match_callbacks_modified
)
364 /* And now, let's invoke our siblings */
365 return bus_match_run(bus
, node
->next
, m
);
368 static int bus_match_add_compare_value(
369 struct bus_match_node
*where
,
370 enum bus_match_node_type t
,
372 const char *value_str
,
373 struct bus_match_node
**ret
) {
375 struct bus_match_node
*c
= NULL
, *n
= NULL
;
379 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
380 assert(BUS_MATCH_IS_COMPARE(t
));
383 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
387 /* Comparison node already exists? Then let's see if
388 * the value node exists too. */
390 if (t
== BUS_MATCH_MESSAGE_TYPE
)
391 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
392 else if (BUS_MATCH_CAN_HASH(t
))
393 n
= hashmap_get(c
->compare
.children
, value_str
);
395 for (n
= c
->child
; n
&& !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
404 /* Comparison node, doesn't exist yet? Then let's
407 c
= new0(struct bus_match_node
, 1);
415 c
->next
= where
->child
;
420 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
421 c
->compare
.children
= hashmap_new(trivial_hash_func
, trivial_compare_func
);
422 if (!c
->compare
.children
) {
426 } else if (BUS_MATCH_CAN_HASH(t
)) {
427 c
->compare
.children
= hashmap_new(string_hash_func
, string_compare_func
);
428 if (!c
->compare
.children
) {
435 n
= new0(struct bus_match_node
, 1);
441 n
->type
= BUS_MATCH_VALUE
;
442 n
->value
.u8
= value_u8
;
444 n
->value
.str
= strdup(value_str
);
452 if (c
->compare
.children
) {
454 if (t
== BUS_MATCH_MESSAGE_TYPE
)
455 r
= hashmap_put(c
->compare
.children
, UINT_TO_PTR(value_u8
), n
);
457 r
= hashmap_put(c
->compare
.children
, n
->value
.str
, n
);
473 bus_match_node_maybe_free(c
);
483 static int bus_match_find_compare_value(
484 struct bus_match_node
*where
,
485 enum bus_match_node_type t
,
487 const char *value_str
,
488 struct bus_match_node
**ret
) {
490 struct bus_match_node
*c
, *n
;
493 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
494 assert(BUS_MATCH_IS_COMPARE(t
));
497 for (c
= where
->child
; c
&& c
->type
!= t
; c
= c
->next
)
503 if (t
== BUS_MATCH_MESSAGE_TYPE
)
504 n
= hashmap_get(c
->compare
.children
, UINT_TO_PTR(value_u8
));
505 else if (BUS_MATCH_CAN_HASH(t
))
506 n
= hashmap_get(c
->compare
.children
, value_str
);
508 for (n
= c
->child
; !value_node_same(n
, t
, value_u8
, value_str
); n
= n
->next
)
520 static int bus_match_add_leaf(
521 struct bus_match_node
*where
,
522 sd_bus_message_handler_t callback
,
525 struct bus_match_node
**ret
) {
527 struct bus_match_node
*n
;
530 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
533 n
= new0(struct bus_match_node
, 1);
537 n
->type
= BUS_MATCH_LEAF
;
539 n
->next
= where
->child
;
542 n
->leaf
.callback
= callback
;
543 n
->leaf
.userdata
= userdata
;
544 n
->leaf
.cookie
= cookie
;
552 static int bus_match_find_leaf(
553 struct bus_match_node
*where
,
554 sd_bus_message_handler_t callback
,
556 struct bus_match_node
**ret
) {
558 struct bus_match_node
*c
;
561 assert(where
->type
== BUS_MATCH_ROOT
|| where
->type
== BUS_MATCH_VALUE
);
564 for (c
= where
->child
; c
; c
= c
->next
) {
565 if (c
->type
== BUS_MATCH_LEAF
&&
566 c
->leaf
.callback
== callback
&&
567 c
->leaf
.userdata
== userdata
) {
576 enum bus_match_node_type
bus_match_node_type_from_string(const char *k
, size_t n
) {
579 if (n
== 4 && startswith(k
, "type"))
580 return BUS_MATCH_MESSAGE_TYPE
;
581 if (n
== 6 && startswith(k
, "sender"))
582 return BUS_MATCH_SENDER
;
583 if (n
== 11 && startswith(k
, "destination"))
584 return BUS_MATCH_DESTINATION
;
585 if (n
== 9 && startswith(k
, "interface"))
586 return BUS_MATCH_INTERFACE
;
587 if (n
== 6 && startswith(k
, "member"))
588 return BUS_MATCH_MEMBER
;
589 if (n
== 4 && startswith(k
, "path"))
590 return BUS_MATCH_PATH
;
591 if (n
== 14 && startswith(k
, "path_namespace"))
592 return BUS_MATCH_PATH_NAMESPACE
;
594 if (n
== 4 && startswith(k
, "arg")) {
601 return BUS_MATCH_ARG
+ j
;
604 if (n
== 5 && startswith(k
, "arg")) {
606 enum bus_match_node_type t
;
613 t
= BUS_MATCH_ARG
+ a
* 10 + b
;
614 if (t
> BUS_MATCH_ARG_LAST
)
620 if (n
== 8 && startswith(k
, "arg") && startswith(k
+ 4, "path")) {
627 return BUS_MATCH_ARG_PATH
+ j
;
630 if (n
== 9 && startswith(k
, "arg") && startswith(k
+ 5, "path")) {
631 enum bus_match_node_type t
;
639 t
= BUS_MATCH_ARG_PATH
+ a
* 10 + b
;
640 if (t
> BUS_MATCH_ARG_PATH_LAST
)
646 if (n
== 13 && startswith(k
, "arg") && startswith(k
+ 4, "namespace")) {
653 return BUS_MATCH_ARG_NAMESPACE
+ j
;
656 if (n
== 14 && startswith(k
, "arg") && startswith(k
+ 5, "namespace")) {
657 enum bus_match_node_type t
;
665 t
= BUS_MATCH_ARG_NAMESPACE
+ a
* 10 + b
;
666 if (t
> BUS_MATCH_ARG_NAMESPACE_LAST
)
675 static int match_component_compare(const void *a
, const void *b
) {
676 const struct bus_match_component
*x
= a
, *y
= b
;
678 if (x
->type
< y
->type
)
680 if (x
->type
> y
->type
)
686 void bus_match_parse_free(struct bus_match_component
*components
, unsigned n_components
) {
689 for (i
= 0; i
< n_components
; i
++)
690 free(components
[i
].value_str
);
697 struct bus_match_component
**_components
,
698 unsigned *_n_components
) {
700 const char *p
= match
;
701 struct bus_match_component
*components
= NULL
;
702 size_t components_allocated
= 0;
703 unsigned n_components
= 0, i
;
704 _cleanup_free_
char *value
= NULL
;
709 assert(_n_components
);
713 enum bus_match_node_type t
;
715 size_t value_allocated
= 0;
716 bool escaped
= false;
726 t
= bus_match_node_type_from_string(p
, eq
- p
);
730 for (q
= eq
+ 2;; q
++) {
749 if (!GREEDY_REALLOC(value
, value_allocated
, j
+ 2)) {
758 if (t
== BUS_MATCH_MESSAGE_TYPE
) {
759 r
= bus_message_type_from_string(value
, &u
);
768 if (!GREEDY_REALLOC(components
, components_allocated
, n_components
+ 1)) {
773 components
[n_components
].type
= t
;
774 components
[n_components
].value_str
= value
;
775 components
[n_components
].value_u8
= u
;
791 /* Order the whole thing, so that we always generate the same tree */
792 qsort_safe(components
, n_components
, sizeof(struct bus_match_component
), match_component_compare
);
794 /* Check for duplicates */
795 for (i
= 0; i
+1 < n_components
; i
++)
796 if (components
[i
].type
== components
[i
+1].type
) {
801 *_components
= components
;
802 *_n_components
= n_components
;
807 bus_match_parse_free(components
, n_components
);
812 struct bus_match_node
*root
,
813 struct bus_match_component
*components
,
814 unsigned n_components
,
815 sd_bus_message_handler_t callback
,
818 struct bus_match_node
**ret
) {
821 struct bus_match_node
*n
;
827 for (i
= 0; i
< n_components
; i
++) {
828 r
= bus_match_add_compare_value(
829 n
, components
[i
].type
,
830 components
[i
].value_u8
, components
[i
].value_str
, &n
);
835 r
= bus_match_add_leaf(n
, callback
, userdata
, cookie
, &n
);
845 int bus_match_remove(
846 struct bus_match_node
*root
,
847 struct bus_match_component
*components
,
848 unsigned n_components
,
849 sd_bus_message_handler_t callback
,
854 struct bus_match_node
*n
, **gc
;
859 gc
= newa(struct bus_match_node
*, n_components
);
862 for (i
= 0; i
< n_components
; i
++) {
863 r
= bus_match_find_compare_value(
864 n
, components
[i
].type
,
865 components
[i
].value_u8
, components
[i
].value_str
,
873 r
= bus_match_find_leaf(n
, callback
, userdata
, &n
);
878 *cookie
= n
->leaf
.cookie
;
881 bus_match_node_free(n
);
883 /* Prune the tree above */
884 for (i
= n_components
; i
> 0; i
--) {
885 struct bus_match_node
*p
= gc
[i
-1]->parent
;
887 if (!bus_match_node_maybe_free(gc
[i
-1]))
890 if (!bus_match_node_maybe_free(p
))
897 void bus_match_free(struct bus_match_node
*node
) {
898 struct bus_match_node
*c
;
903 if (BUS_MATCH_CAN_HASH(node
->type
)) {
906 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
909 assert(hashmap_isempty(node
->compare
.children
));
912 while ((c
= node
->child
))
915 if (node
->type
!= BUS_MATCH_ROOT
)
916 bus_match_node_free(node
);
919 const char* bus_match_node_type_to_string(enum bus_match_node_type t
, char buf
[], size_t l
) {
925 case BUS_MATCH_VALUE
:
931 case BUS_MATCH_MESSAGE_TYPE
:
934 case BUS_MATCH_SENDER
:
937 case BUS_MATCH_DESTINATION
:
938 return "destination";
940 case BUS_MATCH_INTERFACE
:
943 case BUS_MATCH_MEMBER
:
949 case BUS_MATCH_PATH_NAMESPACE
:
950 return "path_namespace";
952 case BUS_MATCH_ARG
... BUS_MATCH_ARG_LAST
:
953 snprintf(buf
, l
, "arg%i", t
- BUS_MATCH_ARG
);
956 case BUS_MATCH_ARG_PATH
... BUS_MATCH_ARG_PATH_LAST
:
957 snprintf(buf
, l
, "arg%ipath", t
- BUS_MATCH_ARG_PATH
);
960 case BUS_MATCH_ARG_NAMESPACE
... BUS_MATCH_ARG_NAMESPACE_LAST
:
961 snprintf(buf
, l
, "arg%inamespace", t
- BUS_MATCH_ARG_NAMESPACE
);
969 void bus_match_dump(struct bus_match_node
*node
, unsigned level
) {
970 struct bus_match_node
*c
;
971 _cleanup_free_
char *pfx
= NULL
;
977 pfx
= strrep(" ", level
);
978 printf("%s[%s]", strempty(pfx
), bus_match_node_type_to_string(node
->type
, buf
, sizeof(buf
)));
980 if (node
->type
== BUS_MATCH_VALUE
) {
981 if (node
->parent
->type
== BUS_MATCH_MESSAGE_TYPE
)
982 printf(" <%u>\n", node
->value
.u8
);
984 printf(" <%s>\n", node
->value
.str
);
985 } else if (node
->type
== BUS_MATCH_ROOT
)
987 else if (node
->type
== BUS_MATCH_LEAF
)
988 printf(" %p/%p\n", node
->leaf
.callback
, node
->leaf
.userdata
);
992 if (BUS_MATCH_CAN_HASH(node
->type
)) {
995 HASHMAP_FOREACH(c
, node
->compare
.children
, i
)
996 bus_match_dump(c
, level
+ 1);
999 for (c
= node
->child
; c
; c
= c
->next
)
1000 bus_match_dump(c
, level
+ 1);