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) {
122 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
125 bus_match_node_free(node);
129 static bool value_node_test(
130 struct bus_match_node *node,
131 enum bus_match_node_type parent_type,
133 const char *value_str,
137 assert(node->type == BUS_MATCH_VALUE);
139 /* Tests parameters against this value node, doing prefix
140 * magic and stuff. */
142 switch (parent_type) {
144 case BUS_MATCH_MESSAGE_TYPE:
145 return node->value.u8 == value_u8;
147 case BUS_MATCH_SENDER:
148 if (streq_ptr(node->value.str, value_str))
151 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
154 /* on kdbus we have the well known names list
155 * in the credentials, let's make use of that
156 * for an accurate match */
158 STRV_FOREACH(i, m->creds.well_known_names)
159 if (streq_ptr(node->value.str, *i))
164 /* If we don't have kdbus, we don't know the
165 * well-known names of the senders. In that,
166 * let's just hope that dbus-daemon doesn't
167 * send us stuff we didn't want. */
169 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
175 case BUS_MATCH_DESTINATION:
176 case BUS_MATCH_INTERFACE:
177 case BUS_MATCH_MEMBER:
179 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
180 return streq_ptr(node->value.str, value_str);
182 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
183 return namespace_simple_pattern(node->value.str, value_str);
185 case BUS_MATCH_PATH_NAMESPACE:
186 return path_simple_pattern(node->value.str, value_str);
188 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
189 return path_complex_pattern(node->value.str, value_str);
192 assert_not_reached("Invalid node type");
196 static bool value_node_same(
197 struct bus_match_node *node,
198 enum bus_match_node_type parent_type,
200 const char *value_str) {
202 /* Tests parameters against this value node, not doing prefix
203 * magic and stuff, i.e. this one actually compares the match
207 assert(node->type == BUS_MATCH_VALUE);
209 switch (parent_type) {
211 case BUS_MATCH_MESSAGE_TYPE:
212 return node->value.u8 == value_u8;
214 case BUS_MATCH_SENDER:
215 case BUS_MATCH_DESTINATION:
216 case BUS_MATCH_INTERFACE:
217 case BUS_MATCH_MEMBER:
219 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
220 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
221 case BUS_MATCH_PATH_NAMESPACE:
222 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
223 return streq(node->value.str, value_str);
226 assert_not_reached("Invalid node type");
232 struct bus_match_node *node,
236 const char *test_str = NULL;
245 if (bus && bus->match_callbacks_modified)
248 /* Not these special semantics: when traversing the tree we
249 * usually let bus_match_run() when called for a node
250 * recursively invoke bus_match_run(). There's are two
251 * exceptions here though, which are BUS_NODE_ROOT (which
252 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
253 * are invoked anyway by its parent. */
255 switch (node->type) {
259 /* Run all children. Since we cannot have any siblings
260 * we won't call any. The children of the root node
261 * are compares or leaves, they will automatically
262 * call their siblings. */
263 return bus_match_run(bus, node->child, m);
265 case BUS_MATCH_VALUE:
267 /* Run all children. We don't execute any siblings, we
268 * assume our caller does that. The children of value
269 * nodes are compares or leaves, they will
270 * automatically call their siblings */
273 return bus_match_run(bus, node->child, m);
278 if (node->leaf.last_iteration == bus->iteration_counter)
281 node->leaf.last_iteration = bus->iteration_counter;
284 r = sd_bus_message_rewind(m, true);
288 /* Run the callback. And then invoke siblings. */
289 if (node->leaf.callback) {
290 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
292 r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
293 r = bus_maybe_reply_error(m, r, &error_buffer);
297 if (bus && bus->match_callbacks_modified)
301 return bus_match_run(bus, node->next, m);
303 case BUS_MATCH_MESSAGE_TYPE:
304 test_u8 = m->header->type;
307 case BUS_MATCH_SENDER:
308 test_str = m->sender;
309 /* FIXME: resolve test_str from a well-known to a unique name first */
312 case BUS_MATCH_DESTINATION:
313 test_str = m->destination;
316 case BUS_MATCH_INTERFACE:
317 test_str = m->interface;
320 case BUS_MATCH_MEMBER:
321 test_str = m->member;
325 case BUS_MATCH_PATH_NAMESPACE:
329 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
330 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
333 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
334 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
337 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
338 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
342 assert_not_reached("Unknown match type.");
345 if (BUS_MATCH_CAN_HASH(node->type)) {
346 struct bus_match_node *found;
348 /* Lookup via hash table, nice! So let's jump directly. */
351 found = hashmap_get(node->compare.children, test_str);
352 else if (node->type == BUS_MATCH_MESSAGE_TYPE)
353 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
358 r = bus_match_run(bus, found, m);
363 struct bus_match_node *c;
365 /* No hash table, so let's iterate manually... */
367 for (c = node->child; c; c = c->next) {
368 if (!value_node_test(c, node->type, test_u8, test_str, m))
371 r = bus_match_run(bus, c, m);
377 if (bus && bus->match_callbacks_modified)
380 /* And now, let's invoke our siblings */
381 return bus_match_run(bus, node->next, m);
384 static int bus_match_add_compare_value(
385 struct bus_match_node *where,
386 enum bus_match_node_type t,
388 const char *value_str,
389 struct bus_match_node **ret) {
391 struct bus_match_node *c = NULL, *n = NULL;
395 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
396 assert(BUS_MATCH_IS_COMPARE(t));
399 for (c = where->child; c && c->type != t; c = c->next)
403 /* Comparison node already exists? Then let's see if
404 * the value node exists too. */
406 if (t == BUS_MATCH_MESSAGE_TYPE)
407 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
408 else if (BUS_MATCH_CAN_HASH(t))
409 n = hashmap_get(c->compare.children, value_str);
411 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
420 /* Comparison node, doesn't exist yet? Then let's
423 c = new0(struct bus_match_node, 1);
431 c->next = where->child;
436 if (t == BUS_MATCH_MESSAGE_TYPE) {
437 c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
438 if (!c->compare.children) {
442 } else if (BUS_MATCH_CAN_HASH(t)) {
443 c->compare.children = hashmap_new(string_hash_func, string_compare_func);
444 if (!c->compare.children) {
451 n = new0(struct bus_match_node, 1);
457 n->type = BUS_MATCH_VALUE;
458 n->value.u8 = value_u8;
460 n->value.str = strdup(value_str);
468 if (c->compare.children) {
470 if (t == BUS_MATCH_MESSAGE_TYPE)
471 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
473 r = hashmap_put(c->compare.children, n->value.str, n);
489 bus_match_node_maybe_free(c);
499 static int bus_match_find_compare_value(
500 struct bus_match_node *where,
501 enum bus_match_node_type t,
503 const char *value_str,
504 struct bus_match_node **ret) {
506 struct bus_match_node *c, *n;
509 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
510 assert(BUS_MATCH_IS_COMPARE(t));
513 for (c = where->child; c && c->type != t; c = c->next)
519 if (t == BUS_MATCH_MESSAGE_TYPE)
520 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
521 else if (BUS_MATCH_CAN_HASH(t))
522 n = hashmap_get(c->compare.children, value_str);
524 for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
536 static int bus_match_add_leaf(
537 struct bus_match_node *where,
538 sd_bus_message_handler_t callback,
541 struct bus_match_node **ret) {
543 struct bus_match_node *n;
546 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
549 n = new0(struct bus_match_node, 1);
553 n->type = BUS_MATCH_LEAF;
555 n->next = where->child;
558 n->leaf.callback = callback;
559 n->leaf.userdata = userdata;
560 n->leaf.cookie = cookie;
568 static int bus_match_find_leaf(
569 struct bus_match_node *where,
570 sd_bus_message_handler_t callback,
572 struct bus_match_node **ret) {
574 struct bus_match_node *c;
577 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
580 for (c = where->child; c; c = c->next) {
581 if (c->type == BUS_MATCH_LEAF &&
582 c->leaf.callback == callback &&
583 c->leaf.userdata == userdata) {
592 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
595 if (n == 4 && startswith(k, "type"))
596 return BUS_MATCH_MESSAGE_TYPE;
597 if (n == 6 && startswith(k, "sender"))
598 return BUS_MATCH_SENDER;
599 if (n == 11 && startswith(k, "destination"))
600 return BUS_MATCH_DESTINATION;
601 if (n == 9 && startswith(k, "interface"))
602 return BUS_MATCH_INTERFACE;
603 if (n == 6 && startswith(k, "member"))
604 return BUS_MATCH_MEMBER;
605 if (n == 4 && startswith(k, "path"))
606 return BUS_MATCH_PATH;
607 if (n == 14 && startswith(k, "path_namespace"))
608 return BUS_MATCH_PATH_NAMESPACE;
610 if (n == 4 && startswith(k, "arg")) {
617 return BUS_MATCH_ARG + j;
620 if (n == 5 && startswith(k, "arg")) {
622 enum bus_match_node_type t;
629 t = BUS_MATCH_ARG + a * 10 + b;
630 if (t > BUS_MATCH_ARG_LAST)
636 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
643 return BUS_MATCH_ARG_PATH + j;
646 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
647 enum bus_match_node_type t;
655 t = BUS_MATCH_ARG_PATH + a * 10 + b;
656 if (t > BUS_MATCH_ARG_PATH_LAST)
662 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
669 return BUS_MATCH_ARG_NAMESPACE + j;
672 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
673 enum bus_match_node_type t;
681 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
682 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
691 static int match_component_compare(const void *a, const void *b) {
692 const struct bus_match_component *x = a, *y = b;
694 if (x->type < y->type)
696 if (x->type > y->type)
702 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
705 for (i = 0; i < n_components; i++)
706 free(components[i].value_str);
713 struct bus_match_component **_components,
714 unsigned *_n_components) {
716 const char *p = match;
717 struct bus_match_component *components = NULL;
718 size_t components_allocated = 0;
719 unsigned n_components = 0, i;
720 _cleanup_free_ char *value = NULL;
725 assert(_n_components);
729 enum bus_match_node_type t;
731 size_t value_allocated = 0;
732 bool escaped = false, quoted;
739 t = bus_match_node_type_from_string(p, eq - p);
743 quoted = eq[1] == '\'';
745 for (q = eq + 1 + quoted;; q++) {
781 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
798 if (t == BUS_MATCH_MESSAGE_TYPE) {
799 r = bus_message_type_from_string(value, &u);
808 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
813 components[n_components].type = t;
814 components[n_components].value_str = value;
815 components[n_components].value_u8 = u;
823 if (q[quoted] != ',') {
831 /* Order the whole thing, so that we always generate the same tree */
832 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
834 /* Check for duplicates */
835 for (i = 0; i+1 < n_components; i++)
836 if (components[i].type == components[i+1].type) {
841 *_components = components;
842 *_n_components = n_components;
847 bus_match_parse_free(components, n_components);
851 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
852 _cleanup_free_ FILE *f = NULL;
857 if (n_components <= 0)
862 f = open_memstream(&buffer, &size);
866 for (i = 0; i < n_components; i++) {
872 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
876 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
877 fputs(bus_message_type_to_string(components[i].value_u8), f);
879 fputs(components[i].value_str, f);
892 struct bus_match_node *root,
893 struct bus_match_component *components,
894 unsigned n_components,
895 sd_bus_message_handler_t callback,
898 struct bus_match_node **ret) {
901 struct bus_match_node *n;
907 for (i = 0; i < n_components; i++) {
908 r = bus_match_add_compare_value(
909 n, components[i].type,
910 components[i].value_u8, components[i].value_str, &n);
915 r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
925 int bus_match_remove(
926 struct bus_match_node *root,
927 struct bus_match_component *components,
928 unsigned n_components,
929 sd_bus_message_handler_t callback,
934 struct bus_match_node *n, **gc;
939 gc = newa(struct bus_match_node*, n_components);
942 for (i = 0; i < n_components; i++) {
943 r = bus_match_find_compare_value(
944 n, components[i].type,
945 components[i].value_u8, components[i].value_str,
953 r = bus_match_find_leaf(n, callback, userdata, &n);
958 *cookie = n->leaf.cookie;
961 bus_match_node_free(n);
963 /* Prune the tree above */
964 for (i = n_components; i > 0; i --) {
965 struct bus_match_node *p = gc[i-1]->parent;
967 if (!bus_match_node_maybe_free(gc[i-1]))
970 if (!bus_match_node_maybe_free(p))
977 void bus_match_free(struct bus_match_node *node) {
978 struct bus_match_node *c;
983 if (BUS_MATCH_CAN_HASH(node->type)) {
986 HASHMAP_FOREACH(c, node->compare.children, i)
989 assert(hashmap_isempty(node->compare.children));
992 while ((c = node->child))
995 if (node->type != BUS_MATCH_ROOT)
996 bus_match_node_free(node);
999 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1002 case BUS_MATCH_ROOT:
1005 case BUS_MATCH_VALUE:
1008 case BUS_MATCH_LEAF:
1011 case BUS_MATCH_MESSAGE_TYPE:
1014 case BUS_MATCH_SENDER:
1017 case BUS_MATCH_DESTINATION:
1018 return "destination";
1020 case BUS_MATCH_INTERFACE:
1023 case BUS_MATCH_MEMBER:
1026 case BUS_MATCH_PATH:
1029 case BUS_MATCH_PATH_NAMESPACE:
1030 return "path_namespace";
1032 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1033 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1036 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1037 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1040 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1041 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1049 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1050 struct bus_match_node *c;
1051 _cleanup_free_ char *pfx = NULL;
1057 pfx = strrep(" ", level);
1058 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1060 if (node->type == BUS_MATCH_VALUE) {
1061 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1062 printf(" <%u>\n", node->value.u8);
1064 printf(" <%s>\n", node->value.str);
1065 } else if (node->type == BUS_MATCH_ROOT)
1067 else if (node->type == BUS_MATCH_LEAF)
1068 printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
1072 if (BUS_MATCH_CAN_HASH(node->type)) {
1075 HASHMAP_FOREACH(c, node->compare.children, i)
1076 bus_match_dump(c, level + 1);
1079 for (c = node->child; c; c = c->next)
1080 bus_match_dump(c, level + 1);