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"
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) {
118 if (node->type == BUS_MATCH_ROOT)
124 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
127 bus_match_node_free(node);
131 static bool value_node_test(
132 struct bus_match_node *node,
133 enum bus_match_node_type parent_type,
135 const char *value_str,
140 assert(node->type == BUS_MATCH_VALUE);
142 /* Tests parameters against this value node, doing prefix
143 * magic and stuff. */
145 switch (parent_type) {
147 case BUS_MATCH_MESSAGE_TYPE:
148 return node->value.u8 == value_u8;
150 case BUS_MATCH_SENDER:
151 if (streq_ptr(node->value.str, value_str))
154 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
157 /* on kdbus we have the well known names list
158 * in the credentials, let's make use of that
159 * for an accurate match */
161 STRV_FOREACH(i, m->creds.well_known_names)
162 if (streq_ptr(node->value.str, *i))
167 /* If we don't have kdbus, we don't know the
168 * well-known names of the senders. In that,
169 * let's just hope that dbus-daemon doesn't
170 * send us stuff we didn't want. */
172 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
178 case BUS_MATCH_DESTINATION:
179 case BUS_MATCH_INTERFACE:
180 case BUS_MATCH_MEMBER:
182 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
186 return streq_ptr(node->value.str, value_str);
188 STRV_FOREACH(i, value_strv)
189 if (streq_ptr(node->value.str, *i))
195 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
199 return namespace_simple_pattern(node->value.str, value_str);
201 STRV_FOREACH(i, value_strv)
202 if (namespace_simple_pattern(node->value.str, *i))
207 case BUS_MATCH_PATH_NAMESPACE:
208 return path_simple_pattern(node->value.str, value_str);
210 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
214 return path_complex_pattern(node->value.str, value_str);
216 STRV_FOREACH(i, value_strv)
217 if (path_complex_pattern(node->value.str, *i))
224 assert_not_reached("Invalid node type");
228 static bool value_node_same(
229 struct bus_match_node *node,
230 enum bus_match_node_type parent_type,
232 const char *value_str) {
234 /* Tests parameters against this value node, not doing prefix
235 * magic and stuff, i.e. this one actually compares the match
239 assert(node->type == BUS_MATCH_VALUE);
241 switch (parent_type) {
243 case BUS_MATCH_MESSAGE_TYPE:
244 return node->value.u8 == value_u8;
246 case BUS_MATCH_SENDER:
247 case BUS_MATCH_DESTINATION:
248 case BUS_MATCH_INTERFACE:
249 case BUS_MATCH_MEMBER:
251 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
252 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
253 case BUS_MATCH_PATH_NAMESPACE:
254 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
255 return streq(node->value.str, value_str);
258 assert_not_reached("Invalid node type");
264 struct bus_match_node *node,
267 _cleanup_strv_free_ char **test_strv = NULL;
268 const char *test_str = NULL;
277 if (bus && bus->match_callbacks_modified)
280 /* Not these special semantics: when traversing the tree we
281 * usually let bus_match_run() when called for a node
282 * recursively invoke bus_match_run(). There's are two
283 * exceptions here though, which are BUS_NODE_ROOT (which
284 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
285 * are invoked anyway by its parent. */
287 switch (node->type) {
291 /* Run all children. Since we cannot have any siblings
292 * we won't call any. The children of the root node
293 * are compares or leaves, they will automatically
294 * call their siblings. */
295 return bus_match_run(bus, node->child, m);
297 case BUS_MATCH_VALUE:
299 /* Run all children. We don't execute any siblings, we
300 * assume our caller does that. The children of value
301 * nodes are compares or leaves, they will
302 * automatically call their siblings */
305 return bus_match_run(bus, node->child, m);
310 if (node->leaf.callback->last_iteration == bus->iteration_counter)
313 node->leaf.callback->last_iteration = bus->iteration_counter;
316 r = sd_bus_message_rewind(m, true);
320 /* Run the callback. And then invoke siblings. */
321 if (node->leaf.callback->callback) {
322 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
325 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
327 bus->current_slot = sd_bus_slot_ref(slot);
328 bus->current_handler = node->leaf.callback->callback;
329 bus->current_userdata = slot->userdata;
331 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
333 bus->current_userdata = NULL;
334 bus->current_handler = NULL;
335 bus->current_slot = sd_bus_slot_unref(slot);
338 r = bus_maybe_reply_error(m, r, &error_buffer);
342 if (bus && bus->match_callbacks_modified)
346 return bus_match_run(bus, node->next, m);
348 case BUS_MATCH_MESSAGE_TYPE:
349 test_u8 = m->header->type;
352 case BUS_MATCH_SENDER:
353 test_str = m->sender;
354 /* FIXME: resolve test_str from a well-known to a unique name first */
357 case BUS_MATCH_DESTINATION:
358 test_str = m->destination;
361 case BUS_MATCH_INTERFACE:
362 test_str = m->interface;
365 case BUS_MATCH_MEMBER:
366 test_str = m->member;
370 case BUS_MATCH_PATH_NAMESPACE:
374 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
375 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
378 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
379 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
382 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
383 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
387 assert_not_reached("Unknown match type.");
390 if (BUS_MATCH_CAN_HASH(node->type)) {
391 struct bus_match_node *found;
393 /* Lookup via hash table, nice! So let's jump directly. */
396 found = hashmap_get(node->compare.children, test_str);
397 else if (test_strv) {
400 STRV_FOREACH(i, test_strv) {
401 found = hashmap_get(node->compare.children, *i);
403 r = bus_match_run(bus, found, m);
410 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
411 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
416 r = bus_match_run(bus, found, m);
421 struct bus_match_node *c;
423 /* No hash table, so let's iterate manually... */
425 for (c = node->child; c; c = c->next) {
426 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
429 r = bus_match_run(bus, c, m);
435 if (bus && bus->match_callbacks_modified)
438 /* And now, let's invoke our siblings */
439 return bus_match_run(bus, node->next, m);
442 static int bus_match_add_compare_value(
443 struct bus_match_node *where,
444 enum bus_match_node_type t,
446 const char *value_str,
447 struct bus_match_node **ret) {
449 struct bus_match_node *c = NULL, *n = NULL;
453 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
454 assert(BUS_MATCH_IS_COMPARE(t));
457 for (c = where->child; c && c->type != t; c = c->next)
461 /* Comparison node already exists? Then let's see if
462 * the value node exists too. */
464 if (t == BUS_MATCH_MESSAGE_TYPE)
465 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
466 else if (BUS_MATCH_CAN_HASH(t))
467 n = hashmap_get(c->compare.children, value_str);
469 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
478 /* Comparison node, doesn't exist yet? Then let's
481 c = new0(struct bus_match_node, 1);
489 c->next = where->child;
494 if (t == BUS_MATCH_MESSAGE_TYPE) {
495 c->compare.children = hashmap_new(NULL);
496 if (!c->compare.children) {
500 } else if (BUS_MATCH_CAN_HASH(t)) {
501 c->compare.children = hashmap_new(&string_hash_ops);
502 if (!c->compare.children) {
509 n = new0(struct bus_match_node, 1);
515 n->type = BUS_MATCH_VALUE;
516 n->value.u8 = value_u8;
518 n->value.str = strdup(value_str);
526 if (c->compare.children) {
528 if (t == BUS_MATCH_MESSAGE_TYPE)
529 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
531 r = hashmap_put(c->compare.children, n->value.str, n);
547 bus_match_node_maybe_free(c);
557 static int bus_match_find_compare_value(
558 struct bus_match_node *where,
559 enum bus_match_node_type t,
561 const char *value_str,
562 struct bus_match_node **ret) {
564 struct bus_match_node *c, *n;
567 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
568 assert(BUS_MATCH_IS_COMPARE(t));
571 for (c = where->child; c && c->type != t; c = c->next)
577 if (t == BUS_MATCH_MESSAGE_TYPE)
578 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
579 else if (BUS_MATCH_CAN_HASH(t))
580 n = hashmap_get(c->compare.children, value_str);
582 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
594 static int bus_match_add_leaf(
595 struct bus_match_node *where,
596 struct match_callback *callback) {
598 struct bus_match_node *n;
601 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
604 n = new0(struct bus_match_node, 1);
608 n->type = BUS_MATCH_LEAF;
610 n->next = where->child;
614 n->leaf.callback = callback;
615 callback->match_node = n;
622 static int bus_match_find_leaf(
623 struct bus_match_node *where,
624 sd_bus_message_handler_t callback,
626 struct bus_match_node **ret) {
628 struct bus_match_node *c;
631 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
634 for (c = where->child; c; c = c->next) {
637 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
639 if (c->type == BUS_MATCH_LEAF &&
640 c->leaf.callback->callback == callback &&
641 s->userdata == userdata) {
650 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
653 if (n == 4 && startswith(k, "type"))
654 return BUS_MATCH_MESSAGE_TYPE;
655 if (n == 6 && startswith(k, "sender"))
656 return BUS_MATCH_SENDER;
657 if (n == 11 && startswith(k, "destination"))
658 return BUS_MATCH_DESTINATION;
659 if (n == 9 && startswith(k, "interface"))
660 return BUS_MATCH_INTERFACE;
661 if (n == 6 && startswith(k, "member"))
662 return BUS_MATCH_MEMBER;
663 if (n == 4 && startswith(k, "path"))
664 return BUS_MATCH_PATH;
665 if (n == 14 && startswith(k, "path_namespace"))
666 return BUS_MATCH_PATH_NAMESPACE;
668 if (n == 4 && startswith(k, "arg")) {
675 return BUS_MATCH_ARG + j;
678 if (n == 5 && startswith(k, "arg")) {
680 enum bus_match_node_type t;
687 t = BUS_MATCH_ARG + a * 10 + b;
688 if (t > BUS_MATCH_ARG_LAST)
694 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
701 return BUS_MATCH_ARG_PATH + j;
704 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
705 enum bus_match_node_type t;
713 t = BUS_MATCH_ARG_PATH + a * 10 + b;
714 if (t > BUS_MATCH_ARG_PATH_LAST)
720 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
727 return BUS_MATCH_ARG_NAMESPACE + j;
730 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
731 enum bus_match_node_type t;
739 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
740 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
749 static int match_component_compare(const void *a, const void *b) {
750 const struct bus_match_component *x = a, *y = b;
752 if (x->type < y->type)
754 if (x->type > y->type)
760 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
763 for (i = 0; i < n_components; i++)
764 free(components[i].value_str);
771 struct bus_match_component **_components,
772 unsigned *_n_components) {
774 const char *p = match;
775 struct bus_match_component *components = NULL;
776 size_t components_allocated = 0;
777 unsigned n_components = 0, i;
778 _cleanup_free_ char *value = NULL;
783 assert(_n_components);
787 enum bus_match_node_type t;
789 size_t value_allocated = 0;
790 bool escaped = false, quoted;
793 /* Avahi's match rules appear to include whitespace, skip over it */
800 t = bus_match_node_type_from_string(p, eq - p);
804 quoted = eq[1] == '\'';
806 for (q = eq + 1 + quoted;; q++) {
842 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
859 if (t == BUS_MATCH_MESSAGE_TYPE) {
860 r = bus_message_type_from_string(value, &u);
869 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
874 components[n_components].type = t;
875 components[n_components].value_str = value;
876 components[n_components].value_u8 = u;
884 if (q[quoted] != ',') {
892 /* Order the whole thing, so that we always generate the same tree */
893 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
895 /* Check for duplicates */
896 for (i = 0; i+1 < n_components; i++)
897 if (components[i].type == components[i+1].type) {
902 *_components = components;
903 *_n_components = n_components;
908 bus_match_parse_free(components, n_components);
912 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
913 _cleanup_free_ FILE *f = NULL;
918 if (n_components <= 0)
923 f = open_memstream(&buffer, &size);
927 for (i = 0; i < n_components; i++) {
933 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
937 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
938 fputs(bus_message_type_to_string(components[i].value_u8), f);
940 fputs(components[i].value_str, f);
953 struct bus_match_node *root,
954 struct bus_match_component *components,
955 unsigned n_components,
956 struct match_callback *callback) {
959 struct bus_match_node *n;
966 for (i = 0; i < n_components; i++) {
967 r = bus_match_add_compare_value(
968 n, components[i].type,
969 components[i].value_u8, components[i].value_str, &n);
974 return bus_match_add_leaf(n, callback);
977 int bus_match_remove(
978 struct bus_match_node *root,
979 struct match_callback *callback) {
981 struct bus_match_node *node, *pp;
986 node = callback->match_node;
990 assert(node->type == BUS_MATCH_LEAF);
992 callback->match_node = NULL;
996 bus_match_node_free(node);
998 /* Prune the tree above */
1003 if (!bus_match_node_maybe_free(node))
1011 struct bus_match_node *root,
1012 struct bus_match_component *components,
1013 unsigned n_components,
1014 sd_bus_message_handler_t callback,
1016 struct match_callback **ret) {
1018 struct bus_match_node *n, **gc;
1025 gc = newa(struct bus_match_node*, n_components);
1028 for (i = 0; i < n_components; i++) {
1029 r = bus_match_find_compare_value(
1030 n, components[i].type,
1031 components[i].value_u8, components[i].value_str,
1039 r = bus_match_find_leaf(n, callback, userdata, &n);
1043 *ret = n->leaf.callback;
1047 void bus_match_free(struct bus_match_node *node) {
1048 struct bus_match_node *c;
1053 if (BUS_MATCH_CAN_HASH(node->type)) {
1056 HASHMAP_FOREACH(c, node->compare.children, i)
1059 assert(hashmap_isempty(node->compare.children));
1062 while ((c = node->child))
1065 if (node->type != BUS_MATCH_ROOT)
1066 bus_match_node_free(node);
1069 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1072 case BUS_MATCH_ROOT:
1075 case BUS_MATCH_VALUE:
1078 case BUS_MATCH_LEAF:
1081 case BUS_MATCH_MESSAGE_TYPE:
1084 case BUS_MATCH_SENDER:
1087 case BUS_MATCH_DESTINATION:
1088 return "destination";
1090 case BUS_MATCH_INTERFACE:
1093 case BUS_MATCH_MEMBER:
1096 case BUS_MATCH_PATH:
1099 case BUS_MATCH_PATH_NAMESPACE:
1100 return "path_namespace";
1102 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1103 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1106 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1107 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1110 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1111 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1119 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1120 struct bus_match_node *c;
1121 _cleanup_free_ char *pfx = NULL;
1127 pfx = strrep(" ", level);
1128 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1130 if (node->type == BUS_MATCH_VALUE) {
1131 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1132 printf(" <%u>\n", node->value.u8);
1134 printf(" <%s>\n", node->value.str);
1135 } else if (node->type == BUS_MATCH_ROOT)
1137 else if (node->type == BUS_MATCH_LEAF)
1138 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1142 if (BUS_MATCH_CAN_HASH(node->type)) {
1145 HASHMAP_FOREACH(c, node->compare.children, i)
1146 bus_match_dump(c, level + 1);
1149 for (c = node->child; c; c = c->next)
1150 bus_match_dump(c, level + 1);