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"
31 * A: type=signal,sender=foo,interface=bar
32 * B: type=signal,sender=quux,interface=fips
33 * C: type=signal,sender=quux,interface=waldo
34 * D: type=signal,member=test
39 * results in this tree:
42 * + BUS_MATCH_MESSAGE_TYPE
43 * | ` BUS_MATCH_VALUE: value == signal
44 * | + DBUS_MATCH_SENDER
45 * | | + BUS_MATCH_VALUE: value == foo
46 * | | | ` DBUS_MATCH_INTERFACE
47 * | | | ` BUS_MATCH_VALUE: value == bar
48 * | | | ` BUS_MATCH_LEAF: A
49 * | | ` BUS_MATCH_VALUE: value == quux
50 * | | ` DBUS_MATCH_INTERFACE
51 * | | | BUS_MATCH_VALUE: value == fips
52 * | | | ` BUS_MATCH_LEAF: B
53 * | | ` BUS_MATCH_VALUE: value == waldo
54 * | | ` BUS_MATCH_LEAF: C
55 * | + DBUS_MATCH_MEMBER
56 * | | ` BUS_MATCH_VALUE: value == test
57 * | | ` BUS_MATCH_LEAF: D
58 * | + BUS_MATCH_LEAF: F
59 * | ` BUS_MATCH_LEAF: G
61 * ` BUS_MATCH_VALUE: value == miau
65 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
66 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
69 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
70 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
71 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
74 static void bus_match_node_free(struct bus_match_node *node) {
78 assert(node->type != BUS_MATCH_ROOT);
79 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
81 if (node->parent->child) {
82 /* We are apparently linked into the parent's child
83 * list. Let's remove us from there. */
85 assert(node->prev->next == node);
86 node->prev->next = node->next;
88 assert(node->parent->child == node);
89 node->parent->child = node->next;
93 node->next->prev = node->prev;
96 if (node->type == BUS_MATCH_VALUE) {
97 /* We might be in the parent's hash table, so clean
100 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
101 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
102 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
103 hashmap_remove(node->parent->compare.children, node->value.str);
105 free(node->value.str);
108 if (BUS_MATCH_IS_COMPARE(node->type)) {
109 assert(hashmap_isempty(node->compare.children));
110 hashmap_free(node->compare.children);
116 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
119 if (node->type == BUS_MATCH_ROOT)
125 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
128 bus_match_node_free(node);
132 static bool value_node_test(
133 struct bus_match_node *node,
134 enum bus_match_node_type parent_type,
136 const char *value_str,
141 assert(node->type == BUS_MATCH_VALUE);
143 /* Tests parameters against this value node, doing prefix
144 * magic and stuff. */
146 switch (parent_type) {
148 case BUS_MATCH_MESSAGE_TYPE:
149 return node->value.u8 == value_u8;
151 case BUS_MATCH_SENDER:
152 if (streq_ptr(node->value.str, value_str))
155 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
158 /* on kdbus we have the well known names list
159 * in the credentials, let's make use of that
160 * for an accurate match */
162 STRV_FOREACH(i, m->creds.well_known_names)
163 if (streq_ptr(node->value.str, *i))
168 /* If we don't have kdbus, we don't know the
169 * well-known names of the senders. In that,
170 * let's just hope that dbus-daemon doesn't
171 * send us stuff we didn't want. */
173 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
179 case BUS_MATCH_DESTINATION:
180 case BUS_MATCH_INTERFACE:
181 case BUS_MATCH_MEMBER:
183 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
187 return streq_ptr(node->value.str, value_str);
189 STRV_FOREACH(i, value_strv)
190 if (streq_ptr(node->value.str, *i))
196 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
200 return namespace_simple_pattern(node->value.str, value_str);
202 STRV_FOREACH(i, value_strv)
203 if (namespace_simple_pattern(node->value.str, *i))
208 case BUS_MATCH_PATH_NAMESPACE:
209 return path_simple_pattern(node->value.str, value_str);
211 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
215 return path_complex_pattern(node->value.str, value_str);
217 STRV_FOREACH(i, value_strv)
218 if (path_complex_pattern(node->value.str, *i))
225 assert_not_reached("Invalid node type");
229 static bool value_node_same(
230 struct bus_match_node *node,
231 enum bus_match_node_type parent_type,
233 const char *value_str) {
235 /* Tests parameters against this value node, not doing prefix
236 * magic and stuff, i.e. this one actually compares the match
240 assert(node->type == BUS_MATCH_VALUE);
242 switch (parent_type) {
244 case BUS_MATCH_MESSAGE_TYPE:
245 return node->value.u8 == value_u8;
247 case BUS_MATCH_SENDER:
248 case BUS_MATCH_DESTINATION:
249 case BUS_MATCH_INTERFACE:
250 case BUS_MATCH_MEMBER:
252 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
253 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
254 case BUS_MATCH_PATH_NAMESPACE:
255 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
256 return streq(node->value.str, value_str);
259 assert_not_reached("Invalid node type");
265 struct bus_match_node *node,
268 _cleanup_strv_free_ char **test_strv = NULL;
269 const char *test_str = NULL;
278 if (bus && bus->match_callbacks_modified)
281 /* Not these special semantics: when traversing the tree we
282 * usually let bus_match_run() when called for a node
283 * recursively invoke bus_match_run(). There's are two
284 * exceptions here though, which are BUS_NODE_ROOT (which
285 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
286 * are invoked anyway by its parent. */
288 switch (node->type) {
292 /* Run all children. Since we cannot have any siblings
293 * we won't call any. The children of the root node
294 * are compares or leaves, they will automatically
295 * call their siblings. */
296 return bus_match_run(bus, node->child, m);
298 case BUS_MATCH_VALUE:
300 /* Run all children. We don't execute any siblings, we
301 * assume our caller does that. The children of value
302 * nodes are compares or leaves, they will
303 * automatically call their siblings */
306 return bus_match_run(bus, node->child, m);
311 if (node->leaf.callback->last_iteration == bus->iteration_counter)
314 node->leaf.callback->last_iteration = bus->iteration_counter;
317 r = sd_bus_message_rewind(m, true);
321 /* Run the callback. And then invoke siblings. */
322 if (node->leaf.callback->callback) {
323 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
326 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
328 bus->current_slot = sd_bus_slot_ref(slot);
329 bus->current_handler = node->leaf.callback->callback;
330 bus->current_userdata = slot->userdata;
332 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
334 bus->current_userdata = NULL;
335 bus->current_handler = NULL;
336 bus->current_slot = sd_bus_slot_unref(slot);
339 r = bus_maybe_reply_error(m, r, &error_buffer);
343 if (bus && bus->match_callbacks_modified)
347 return bus_match_run(bus, node->next, m);
349 case BUS_MATCH_MESSAGE_TYPE:
350 test_u8 = m->header->type;
353 case BUS_MATCH_SENDER:
354 test_str = m->sender;
355 /* FIXME: resolve test_str from a well-known to a unique name first */
358 case BUS_MATCH_DESTINATION:
359 test_str = m->destination;
362 case BUS_MATCH_INTERFACE:
363 test_str = m->interface;
366 case BUS_MATCH_MEMBER:
367 test_str = m->member;
371 case BUS_MATCH_PATH_NAMESPACE:
375 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
376 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
379 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
380 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
383 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
384 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
388 assert_not_reached("Unknown match type.");
391 if (BUS_MATCH_CAN_HASH(node->type)) {
392 struct bus_match_node *found;
394 /* Lookup via hash table, nice! So let's jump directly. */
397 found = hashmap_get(node->compare.children, test_str);
398 else if (test_strv) {
401 STRV_FOREACH(i, test_strv) {
402 found = hashmap_get(node->compare.children, *i);
404 r = bus_match_run(bus, found, m);
411 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
412 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
417 r = bus_match_run(bus, found, m);
422 struct bus_match_node *c;
424 /* No hash table, so let's iterate manually... */
426 for (c = node->child; c; c = c->next) {
427 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
430 r = bus_match_run(bus, c, m);
436 if (bus && bus->match_callbacks_modified)
439 /* And now, let's invoke our siblings */
440 return bus_match_run(bus, node->next, m);
443 static int bus_match_add_compare_value(
444 struct bus_match_node *where,
445 enum bus_match_node_type t,
447 const char *value_str,
448 struct bus_match_node **ret) {
450 struct bus_match_node *c = NULL, *n = NULL;
454 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
455 assert(BUS_MATCH_IS_COMPARE(t));
458 for (c = where->child; c && c->type != t; c = c->next)
462 /* Comparison node already exists? Then let's see if
463 * the value node exists too. */
465 if (t == BUS_MATCH_MESSAGE_TYPE)
466 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
467 else if (BUS_MATCH_CAN_HASH(t))
468 n = hashmap_get(c->compare.children, value_str);
470 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
479 /* Comparison node, doesn't exist yet? Then let's
482 c = new0(struct bus_match_node, 1);
490 c->next = where->child;
495 if (t == BUS_MATCH_MESSAGE_TYPE) {
496 c->compare.children = hashmap_new(NULL);
497 if (!c->compare.children) {
501 } else if (BUS_MATCH_CAN_HASH(t)) {
502 c->compare.children = hashmap_new(&string_hash_ops);
503 if (!c->compare.children) {
510 n = new0(struct bus_match_node, 1);
516 n->type = BUS_MATCH_VALUE;
517 n->value.u8 = value_u8;
519 n->value.str = strdup(value_str);
527 if (c->compare.children) {
529 if (t == BUS_MATCH_MESSAGE_TYPE)
530 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
532 r = hashmap_put(c->compare.children, n->value.str, n);
548 bus_match_node_maybe_free(c);
558 static int bus_match_find_compare_value(
559 struct bus_match_node *where,
560 enum bus_match_node_type t,
562 const char *value_str,
563 struct bus_match_node **ret) {
565 struct bus_match_node *c, *n;
568 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
569 assert(BUS_MATCH_IS_COMPARE(t));
572 for (c = where->child; c && c->type != t; c = c->next)
578 if (t == BUS_MATCH_MESSAGE_TYPE)
579 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
580 else if (BUS_MATCH_CAN_HASH(t))
581 n = hashmap_get(c->compare.children, value_str);
583 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
595 static int bus_match_add_leaf(
596 struct bus_match_node *where,
597 struct match_callback *callback) {
599 struct bus_match_node *n;
602 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
605 n = new0(struct bus_match_node, 1);
609 n->type = BUS_MATCH_LEAF;
611 n->next = where->child;
615 n->leaf.callback = callback;
616 callback->match_node = n;
623 static int bus_match_find_leaf(
624 struct bus_match_node *where,
625 sd_bus_message_handler_t callback,
627 struct bus_match_node **ret) {
629 struct bus_match_node *c;
632 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
635 for (c = where->child; c; c = c->next) {
638 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
640 if (c->type == BUS_MATCH_LEAF &&
641 c->leaf.callback->callback == callback &&
642 s->userdata == userdata) {
651 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
654 if (n == 4 && startswith(k, "type"))
655 return BUS_MATCH_MESSAGE_TYPE;
656 if (n == 6 && startswith(k, "sender"))
657 return BUS_MATCH_SENDER;
658 if (n == 11 && startswith(k, "destination"))
659 return BUS_MATCH_DESTINATION;
660 if (n == 9 && startswith(k, "interface"))
661 return BUS_MATCH_INTERFACE;
662 if (n == 6 && startswith(k, "member"))
663 return BUS_MATCH_MEMBER;
664 if (n == 4 && startswith(k, "path"))
665 return BUS_MATCH_PATH;
666 if (n == 14 && startswith(k, "path_namespace"))
667 return BUS_MATCH_PATH_NAMESPACE;
669 if (n == 4 && startswith(k, "arg")) {
676 return BUS_MATCH_ARG + j;
679 if (n == 5 && startswith(k, "arg")) {
681 enum bus_match_node_type t;
688 t = BUS_MATCH_ARG + a * 10 + b;
689 if (t > BUS_MATCH_ARG_LAST)
695 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
702 return BUS_MATCH_ARG_PATH + j;
705 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
706 enum bus_match_node_type t;
714 t = BUS_MATCH_ARG_PATH + a * 10 + b;
715 if (t > BUS_MATCH_ARG_PATH_LAST)
721 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
728 return BUS_MATCH_ARG_NAMESPACE + j;
731 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
732 enum bus_match_node_type t;
740 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
741 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
750 static int match_component_compare(const void *a, const void *b) {
751 const struct bus_match_component *x = a, *y = b;
753 if (x->type < y->type)
755 if (x->type > y->type)
761 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
764 for (i = 0; i < n_components; i++)
765 free(components[i].value_str);
772 struct bus_match_component **_components,
773 unsigned *_n_components) {
775 const char *p = match;
776 struct bus_match_component *components = NULL;
777 size_t components_allocated = 0;
778 unsigned n_components = 0, i;
779 _cleanup_free_ char *value = NULL;
784 assert(_n_components);
788 enum bus_match_node_type t;
790 size_t value_allocated = 0;
791 bool escaped = false, quoted;
794 /* Avahi's match rules appear to include whitespace, skip over it */
801 t = bus_match_node_type_from_string(p, eq - p);
805 quoted = eq[1] == '\'';
807 for (q = eq + 1 + quoted;; q++) {
843 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
860 if (t == BUS_MATCH_MESSAGE_TYPE) {
861 r = bus_message_type_from_string(value, &u);
870 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
875 components[n_components].type = t;
876 components[n_components].value_str = value;
877 components[n_components].value_u8 = u;
885 if (q[quoted] != ',') {
893 /* Order the whole thing, so that we always generate the same tree */
894 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
896 /* Check for duplicates */
897 for (i = 0; i+1 < n_components; i++)
898 if (components[i].type == components[i+1].type) {
903 *_components = components;
904 *_n_components = n_components;
909 bus_match_parse_free(components, n_components);
913 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
914 _cleanup_free_ FILE *f = NULL;
919 if (n_components <= 0)
924 f = open_memstream(&buffer, &size);
928 for (i = 0; i < n_components; i++) {
934 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
938 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
939 fputs(bus_message_type_to_string(components[i].value_u8), f);
941 fputs(components[i].value_str, f);
954 struct bus_match_node *root,
955 struct bus_match_component *components,
956 unsigned n_components,
957 struct match_callback *callback) {
960 struct bus_match_node *n;
967 for (i = 0; i < n_components; i++) {
968 r = bus_match_add_compare_value(
969 n, components[i].type,
970 components[i].value_u8, components[i].value_str, &n);
975 return bus_match_add_leaf(n, callback);
978 int bus_match_remove(
979 struct bus_match_node *root,
980 struct match_callback *callback) {
982 struct bus_match_node *node, *pp;
987 node = callback->match_node;
991 assert(node->type == BUS_MATCH_LEAF);
993 callback->match_node = NULL;
997 bus_match_node_free(node);
999 /* Prune the tree above */
1004 if (!bus_match_node_maybe_free(node))
1012 struct bus_match_node *root,
1013 struct bus_match_component *components,
1014 unsigned n_components,
1015 sd_bus_message_handler_t callback,
1017 struct match_callback **ret) {
1019 struct bus_match_node *n, **gc;
1026 gc = newa(struct bus_match_node*, n_components);
1029 for (i = 0; i < n_components; i++) {
1030 r = bus_match_find_compare_value(
1031 n, components[i].type,
1032 components[i].value_u8, components[i].value_str,
1040 r = bus_match_find_leaf(n, callback, userdata, &n);
1044 *ret = n->leaf.callback;
1048 void bus_match_free(struct bus_match_node *node) {
1049 struct bus_match_node *c;
1054 if (BUS_MATCH_CAN_HASH(node->type)) {
1057 HASHMAP_FOREACH(c, node->compare.children, i)
1060 assert(hashmap_isempty(node->compare.children));
1063 while ((c = node->child))
1066 if (node->type != BUS_MATCH_ROOT)
1067 bus_match_node_free(node);
1070 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1073 case BUS_MATCH_ROOT:
1076 case BUS_MATCH_VALUE:
1079 case BUS_MATCH_LEAF:
1082 case BUS_MATCH_MESSAGE_TYPE:
1085 case BUS_MATCH_SENDER:
1088 case BUS_MATCH_DESTINATION:
1089 return "destination";
1091 case BUS_MATCH_INTERFACE:
1094 case BUS_MATCH_MEMBER:
1097 case BUS_MATCH_PATH:
1100 case BUS_MATCH_PATH_NAMESPACE:
1101 return "path_namespace";
1103 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1104 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1107 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1108 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1111 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1112 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1120 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1121 struct bus_match_node *c;
1122 _cleanup_free_ char *pfx = NULL;
1128 pfx = strrep(" ", level);
1129 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1131 if (node->type == BUS_MATCH_VALUE) {
1132 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1133 printf(" <%u>\n", node->value.u8);
1135 printf(" <%s>\n", node->value.str);
1136 } else if (node->type == BUS_MATCH_ROOT)
1138 else if (node->type == BUS_MATCH_LEAF)
1139 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1143 if (BUS_MATCH_CAN_HASH(node->type)) {
1146 HASHMAP_FOREACH(c, node->compare.children, i)
1147 bus_match_dump(c, level + 1);
1150 for (c = node->child; c; c = c->next)
1151 bus_match_dump(c, level + 1);