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,
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:
183 return streq_ptr(node->value.str, value_str);
185 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
186 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:
192 return path_complex_pattern(node->value.str, value_str);
195 assert_not_reached("Invalid node type");
199 static bool value_node_same(
200 struct bus_match_node *node,
201 enum bus_match_node_type parent_type,
203 const char *value_str) {
205 /* Tests parameters against this value node, not doing prefix
206 * magic and stuff, i.e. this one actually compares the match
210 assert(node->type == BUS_MATCH_VALUE);
212 switch (parent_type) {
214 case BUS_MATCH_MESSAGE_TYPE:
215 return node->value.u8 == value_u8;
217 case BUS_MATCH_SENDER:
218 case BUS_MATCH_DESTINATION:
219 case BUS_MATCH_INTERFACE:
220 case BUS_MATCH_MEMBER:
222 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
223 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
224 case BUS_MATCH_PATH_NAMESPACE:
225 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
226 return streq(node->value.str, value_str);
229 assert_not_reached("Invalid node type");
235 struct bus_match_node *node,
239 const char *test_str = NULL;
248 if (bus && bus->match_callbacks_modified)
251 /* Not these special semantics: when traversing the tree we
252 * usually let bus_match_run() when called for a node
253 * recursively invoke bus_match_run(). There's are two
254 * exceptions here though, which are BUS_NODE_ROOT (which
255 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
256 * are invoked anyway by its parent. */
258 switch (node->type) {
262 /* Run all children. Since we cannot have any siblings
263 * we won't call any. The children of the root node
264 * are compares or leaves, they will automatically
265 * call their siblings. */
266 return bus_match_run(bus, node->child, m);
268 case BUS_MATCH_VALUE:
270 /* Run all children. We don't execute any siblings, we
271 * assume our caller does that. The children of value
272 * nodes are compares or leaves, they will
273 * automatically call their siblings */
276 return bus_match_run(bus, node->child, m);
281 if (node->leaf.callback->last_iteration == bus->iteration_counter)
284 node->leaf.callback->last_iteration = bus->iteration_counter;
287 r = sd_bus_message_rewind(m, true);
291 /* Run the callback. And then invoke siblings. */
292 if (node->leaf.callback->callback) {
293 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
296 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
298 bus->current_slot = sd_bus_slot_ref(slot);
299 bus->current_handler = node->leaf.callback->callback;
300 bus->current_userdata = slot->userdata;
302 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
304 bus->current_userdata = NULL;
305 bus->current_handler = NULL;
306 bus->current_slot = sd_bus_slot_unref(slot);
309 r = bus_maybe_reply_error(m, r, &error_buffer);
313 if (bus && bus->match_callbacks_modified)
317 return bus_match_run(bus, node->next, m);
319 case BUS_MATCH_MESSAGE_TYPE:
320 test_u8 = m->header->type;
323 case BUS_MATCH_SENDER:
324 test_str = m->sender;
325 /* FIXME: resolve test_str from a well-known to a unique name first */
328 case BUS_MATCH_DESTINATION:
329 test_str = m->destination;
332 case BUS_MATCH_INTERFACE:
333 test_str = m->interface;
336 case BUS_MATCH_MEMBER:
337 test_str = m->member;
341 case BUS_MATCH_PATH_NAMESPACE:
345 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
346 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
349 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
350 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
353 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
354 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
358 assert_not_reached("Unknown match type.");
361 if (BUS_MATCH_CAN_HASH(node->type)) {
362 struct bus_match_node *found;
364 /* Lookup via hash table, nice! So let's jump directly. */
367 found = hashmap_get(node->compare.children, test_str);
368 else if (node->type == BUS_MATCH_MESSAGE_TYPE)
369 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
374 r = bus_match_run(bus, found, m);
379 struct bus_match_node *c;
381 /* No hash table, so let's iterate manually... */
383 for (c = node->child; c; c = c->next) {
384 if (!value_node_test(c, node->type, test_u8, test_str, m))
387 r = bus_match_run(bus, c, m);
393 if (bus && bus->match_callbacks_modified)
396 /* And now, let's invoke our siblings */
397 return bus_match_run(bus, node->next, m);
400 static int bus_match_add_compare_value(
401 struct bus_match_node *where,
402 enum bus_match_node_type t,
404 const char *value_str,
405 struct bus_match_node **ret) {
407 struct bus_match_node *c = NULL, *n = NULL;
411 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
412 assert(BUS_MATCH_IS_COMPARE(t));
415 for (c = where->child; c && c->type != t; c = c->next)
419 /* Comparison node already exists? Then let's see if
420 * the value node exists too. */
422 if (t == BUS_MATCH_MESSAGE_TYPE)
423 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
424 else if (BUS_MATCH_CAN_HASH(t))
425 n = hashmap_get(c->compare.children, value_str);
427 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
436 /* Comparison node, doesn't exist yet? Then let's
439 c = new0(struct bus_match_node, 1);
447 c->next = where->child;
452 if (t == BUS_MATCH_MESSAGE_TYPE) {
453 c->compare.children = hashmap_new(NULL);
454 if (!c->compare.children) {
458 } else if (BUS_MATCH_CAN_HASH(t)) {
459 c->compare.children = hashmap_new(&string_hash_ops);
460 if (!c->compare.children) {
467 n = new0(struct bus_match_node, 1);
473 n->type = BUS_MATCH_VALUE;
474 n->value.u8 = value_u8;
476 n->value.str = strdup(value_str);
484 if (c->compare.children) {
486 if (t == BUS_MATCH_MESSAGE_TYPE)
487 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
489 r = hashmap_put(c->compare.children, n->value.str, n);
505 bus_match_node_maybe_free(c);
515 static int bus_match_find_compare_value(
516 struct bus_match_node *where,
517 enum bus_match_node_type t,
519 const char *value_str,
520 struct bus_match_node **ret) {
522 struct bus_match_node *c, *n;
525 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
526 assert(BUS_MATCH_IS_COMPARE(t));
529 for (c = where->child; c && c->type != t; c = c->next)
535 if (t == BUS_MATCH_MESSAGE_TYPE)
536 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
537 else if (BUS_MATCH_CAN_HASH(t))
538 n = hashmap_get(c->compare.children, value_str);
540 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
552 static int bus_match_add_leaf(
553 struct bus_match_node *where,
554 struct match_callback *callback) {
556 struct bus_match_node *n;
559 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
562 n = new0(struct bus_match_node, 1);
566 n->type = BUS_MATCH_LEAF;
568 n->next = where->child;
572 n->leaf.callback = callback;
573 callback->match_node = n;
580 static int bus_match_find_leaf(
581 struct bus_match_node *where,
582 sd_bus_message_handler_t callback,
584 struct bus_match_node **ret) {
586 struct bus_match_node *c;
589 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
592 for (c = where->child; c; c = c->next) {
595 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
597 if (c->type == BUS_MATCH_LEAF &&
598 c->leaf.callback->callback == callback &&
599 s->userdata == userdata) {
608 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
611 if (n == 4 && startswith(k, "type"))
612 return BUS_MATCH_MESSAGE_TYPE;
613 if (n == 6 && startswith(k, "sender"))
614 return BUS_MATCH_SENDER;
615 if (n == 11 && startswith(k, "destination"))
616 return BUS_MATCH_DESTINATION;
617 if (n == 9 && startswith(k, "interface"))
618 return BUS_MATCH_INTERFACE;
619 if (n == 6 && startswith(k, "member"))
620 return BUS_MATCH_MEMBER;
621 if (n == 4 && startswith(k, "path"))
622 return BUS_MATCH_PATH;
623 if (n == 14 && startswith(k, "path_namespace"))
624 return BUS_MATCH_PATH_NAMESPACE;
626 if (n == 4 && startswith(k, "arg")) {
633 return BUS_MATCH_ARG + j;
636 if (n == 5 && startswith(k, "arg")) {
638 enum bus_match_node_type t;
645 t = BUS_MATCH_ARG + a * 10 + b;
646 if (t > BUS_MATCH_ARG_LAST)
652 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
659 return BUS_MATCH_ARG_PATH + j;
662 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
663 enum bus_match_node_type t;
671 t = BUS_MATCH_ARG_PATH + a * 10 + b;
672 if (t > BUS_MATCH_ARG_PATH_LAST)
678 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
685 return BUS_MATCH_ARG_NAMESPACE + j;
688 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
689 enum bus_match_node_type t;
697 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
698 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
707 static int match_component_compare(const void *a, const void *b) {
708 const struct bus_match_component *x = a, *y = b;
710 if (x->type < y->type)
712 if (x->type > y->type)
718 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
721 for (i = 0; i < n_components; i++)
722 free(components[i].value_str);
729 struct bus_match_component **_components,
730 unsigned *_n_components) {
732 const char *p = match;
733 struct bus_match_component *components = NULL;
734 size_t components_allocated = 0;
735 unsigned n_components = 0, i;
736 _cleanup_free_ char *value = NULL;
741 assert(_n_components);
745 enum bus_match_node_type t;
747 size_t value_allocated = 0;
748 bool escaped = false, quoted;
751 /* Avahi's match rules appear to include whitespace, skip over it */
758 t = bus_match_node_type_from_string(p, eq - p);
762 quoted = eq[1] == '\'';
764 for (q = eq + 1 + quoted;; q++) {
800 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
817 if (t == BUS_MATCH_MESSAGE_TYPE) {
818 r = bus_message_type_from_string(value, &u);
827 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
832 components[n_components].type = t;
833 components[n_components].value_str = value;
834 components[n_components].value_u8 = u;
842 if (q[quoted] != ',') {
850 /* Order the whole thing, so that we always generate the same tree */
851 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
853 /* Check for duplicates */
854 for (i = 0; i+1 < n_components; i++)
855 if (components[i].type == components[i+1].type) {
860 *_components = components;
861 *_n_components = n_components;
866 bus_match_parse_free(components, n_components);
870 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
871 _cleanup_free_ FILE *f = NULL;
876 if (n_components <= 0)
881 f = open_memstream(&buffer, &size);
885 for (i = 0; i < n_components; i++) {
891 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
895 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
896 fputs(bus_message_type_to_string(components[i].value_u8), f);
898 fputs(components[i].value_str, f);
911 struct bus_match_node *root,
912 struct bus_match_component *components,
913 unsigned n_components,
914 struct match_callback *callback) {
917 struct bus_match_node *n;
924 for (i = 0; i < n_components; i++) {
925 r = bus_match_add_compare_value(
926 n, components[i].type,
927 components[i].value_u8, components[i].value_str, &n);
932 return bus_match_add_leaf(n, callback);
935 int bus_match_remove(
936 struct bus_match_node *root,
937 struct match_callback *callback) {
939 struct bus_match_node *node, *pp;
944 node = callback->match_node;
948 assert(node->type == BUS_MATCH_LEAF);
950 callback->match_node = NULL;
954 bus_match_node_free(node);
956 /* Prune the tree above */
961 if (!bus_match_node_maybe_free(node))
969 struct bus_match_node *root,
970 struct bus_match_component *components,
971 unsigned n_components,
972 sd_bus_message_handler_t callback,
974 struct match_callback **ret) {
976 struct bus_match_node *n, **gc;
983 gc = newa(struct bus_match_node*, n_components);
986 for (i = 0; i < n_components; i++) {
987 r = bus_match_find_compare_value(
988 n, components[i].type,
989 components[i].value_u8, components[i].value_str,
997 r = bus_match_find_leaf(n, callback, userdata, &n);
1001 *ret = n->leaf.callback;
1005 void bus_match_free(struct bus_match_node *node) {
1006 struct bus_match_node *c;
1011 if (BUS_MATCH_CAN_HASH(node->type)) {
1014 HASHMAP_FOREACH(c, node->compare.children, i)
1017 assert(hashmap_isempty(node->compare.children));
1020 while ((c = node->child))
1023 if (node->type != BUS_MATCH_ROOT)
1024 bus_match_node_free(node);
1027 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1030 case BUS_MATCH_ROOT:
1033 case BUS_MATCH_VALUE:
1036 case BUS_MATCH_LEAF:
1039 case BUS_MATCH_MESSAGE_TYPE:
1042 case BUS_MATCH_SENDER:
1045 case BUS_MATCH_DESTINATION:
1046 return "destination";
1048 case BUS_MATCH_INTERFACE:
1051 case BUS_MATCH_MEMBER:
1054 case BUS_MATCH_PATH:
1057 case BUS_MATCH_PATH_NAMESPACE:
1058 return "path_namespace";
1060 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1061 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1064 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1065 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1068 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1069 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1077 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1078 struct bus_match_node *c;
1079 _cleanup_free_ char *pfx = NULL;
1085 pfx = strrep(" ", level);
1086 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1088 if (node->type == BUS_MATCH_VALUE) {
1089 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1090 printf(" <%u>\n", node->value.u8);
1092 printf(" <%s>\n", node->value.str);
1093 } else if (node->type == BUS_MATCH_ROOT)
1095 else if (node->type == BUS_MATCH_LEAF)
1096 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1100 if (BUS_MATCH_CAN_HASH(node->type)) {
1103 HASHMAP_FOREACH(c, node->compare.children, i)
1104 bus_match_dump(c, level + 1);
1107 for (c = node->child; c; c = c->next)
1108 bus_match_dump(c, level + 1);