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)) {
766 if (t == BUS_MATCH_MESSAGE_TYPE) {
767 r = bus_message_type_from_string(value, &u);
776 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
781 components[n_components].type = t;
782 components[n_components].value_str = value;
783 components[n_components].value_u8 = u;
799 /* Order the whole thing, so that we always generate the same tree */
800 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
802 /* Check for duplicates */
803 for (i = 0; i+1 < n_components; i++)
804 if (components[i].type == components[i+1].type) {
809 *_components = components;
810 *_n_components = n_components;
815 bus_match_parse_free(components, n_components);
820 struct bus_match_node *root,
821 struct bus_match_component *components,
822 unsigned n_components,
823 sd_bus_message_handler_t callback,
826 struct bus_match_node **ret) {
829 struct bus_match_node *n;
835 for (i = 0; i < n_components; i++) {
836 r = bus_match_add_compare_value(
837 n, components[i].type,
838 components[i].value_u8, components[i].value_str, &n);
843 r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
853 int bus_match_remove(
854 struct bus_match_node *root,
855 struct bus_match_component *components,
856 unsigned n_components,
857 sd_bus_message_handler_t callback,
862 struct bus_match_node *n, **gc;
867 gc = newa(struct bus_match_node*, n_components);
870 for (i = 0; i < n_components; i++) {
871 r = bus_match_find_compare_value(
872 n, components[i].type,
873 components[i].value_u8, components[i].value_str,
881 r = bus_match_find_leaf(n, callback, userdata, &n);
886 *cookie = n->leaf.cookie;
889 bus_match_node_free(n);
891 /* Prune the tree above */
892 for (i = n_components; i > 0; i --) {
893 struct bus_match_node *p = gc[i-1]->parent;
895 if (!bus_match_node_maybe_free(gc[i-1]))
898 if (!bus_match_node_maybe_free(p))
905 void bus_match_free(struct bus_match_node *node) {
906 struct bus_match_node *c;
911 if (BUS_MATCH_CAN_HASH(node->type)) {
914 HASHMAP_FOREACH(c, node->compare.children, i)
917 assert(hashmap_isempty(node->compare.children));
920 while ((c = node->child))
923 if (node->type != BUS_MATCH_ROOT)
924 bus_match_node_free(node);
927 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
933 case BUS_MATCH_VALUE:
939 case BUS_MATCH_MESSAGE_TYPE:
942 case BUS_MATCH_SENDER:
945 case BUS_MATCH_DESTINATION:
946 return "destination";
948 case BUS_MATCH_INTERFACE:
951 case BUS_MATCH_MEMBER:
957 case BUS_MATCH_PATH_NAMESPACE:
958 return "path_namespace";
960 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
961 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
964 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
965 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
968 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
969 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
977 void bus_match_dump(struct bus_match_node *node, unsigned level) {
978 struct bus_match_node *c;
979 _cleanup_free_ char *pfx = NULL;
985 pfx = strrep(" ", level);
986 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
988 if (node->type == BUS_MATCH_VALUE) {
989 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
990 printf(" <%u>\n", node->value.u8);
992 printf(" <%s>\n", node->value.str);
993 } else if (node->type == BUS_MATCH_ROOT)
995 else if (node->type == BUS_MATCH_LEAF)
996 printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
1000 if (BUS_MATCH_CAN_HASH(node->type)) {
1003 HASHMAP_FOREACH(c, node->compare.children, i)
1004 bus_match_dump(c, level + 1);
1007 for (c = node->child; c; c = c->next)
1008 bus_match_dump(c, level + 1);