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; !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;
755 t = bus_match_node_type_from_string(p, eq - p);
759 quoted = eq[1] == '\'';
761 for (q = eq + 1 + quoted;; q++) {
797 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
814 if (t == BUS_MATCH_MESSAGE_TYPE) {
815 r = bus_message_type_from_string(value, &u);
824 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
829 components[n_components].type = t;
830 components[n_components].value_str = value;
831 components[n_components].value_u8 = u;
839 if (q[quoted] != ',') {
847 /* Order the whole thing, so that we always generate the same tree */
848 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
850 /* Check for duplicates */
851 for (i = 0; i+1 < n_components; i++)
852 if (components[i].type == components[i+1].type) {
857 *_components = components;
858 *_n_components = n_components;
863 bus_match_parse_free(components, n_components);
867 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
868 _cleanup_free_ FILE *f = NULL;
873 if (n_components <= 0)
878 f = open_memstream(&buffer, &size);
882 for (i = 0; i < n_components; i++) {
888 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
892 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
893 fputs(bus_message_type_to_string(components[i].value_u8), f);
895 fputs(components[i].value_str, f);
908 struct bus_match_node *root,
909 struct bus_match_component *components,
910 unsigned n_components,
911 struct match_callback *callback) {
914 struct bus_match_node *n;
921 for (i = 0; i < n_components; i++) {
922 r = bus_match_add_compare_value(
923 n, components[i].type,
924 components[i].value_u8, components[i].value_str, &n);
929 return bus_match_add_leaf(n, callback);
932 int bus_match_remove(
933 struct bus_match_node *root,
934 struct match_callback *callback) {
936 struct bus_match_node *node, *pp;
941 node = callback->match_node;
945 assert(node->type == BUS_MATCH_LEAF);
947 callback->match_node = NULL;
951 bus_match_node_free(node);
953 /* Prune the tree above */
958 if (!bus_match_node_maybe_free(node))
966 struct bus_match_node *root,
967 struct bus_match_component *components,
968 unsigned n_components,
969 sd_bus_message_handler_t callback,
971 struct match_callback **ret) {
973 struct bus_match_node *n, **gc;
980 gc = newa(struct bus_match_node*, n_components);
983 for (i = 0; i < n_components; i++) {
984 r = bus_match_find_compare_value(
985 n, components[i].type,
986 components[i].value_u8, components[i].value_str,
994 r = bus_match_find_leaf(n, callback, userdata, &n);
998 *ret = n->leaf.callback;
1002 void bus_match_free(struct bus_match_node *node) {
1003 struct bus_match_node *c;
1008 if (BUS_MATCH_CAN_HASH(node->type)) {
1011 HASHMAP_FOREACH(c, node->compare.children, i)
1014 assert(hashmap_isempty(node->compare.children));
1017 while ((c = node->child))
1020 if (node->type != BUS_MATCH_ROOT)
1021 bus_match_node_free(node);
1024 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1027 case BUS_MATCH_ROOT:
1030 case BUS_MATCH_VALUE:
1033 case BUS_MATCH_LEAF:
1036 case BUS_MATCH_MESSAGE_TYPE:
1039 case BUS_MATCH_SENDER:
1042 case BUS_MATCH_DESTINATION:
1043 return "destination";
1045 case BUS_MATCH_INTERFACE:
1048 case BUS_MATCH_MEMBER:
1051 case BUS_MATCH_PATH:
1054 case BUS_MATCH_PATH_NAMESPACE:
1055 return "path_namespace";
1057 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1058 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1061 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1062 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1065 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1066 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1074 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1075 struct bus_match_node *c;
1076 _cleanup_free_ char *pfx = NULL;
1082 pfx = strrep(" ", level);
1083 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1085 if (node->type == BUS_MATCH_VALUE) {
1086 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1087 printf(" <%u>\n", node->value.u8);
1089 printf(" <%s>\n", node->value.str);
1090 } else if (node->type == BUS_MATCH_ROOT)
1092 else if (node->type == BUS_MATCH_LEAF)
1093 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1097 if (BUS_MATCH_CAN_HASH(node->type)) {
1100 HASHMAP_FOREACH(c, node->compare.children, i)
1101 bus_match_dump(c, level + 1);
1104 for (c = node->child; c; c = c->next)
1105 bus_match_dump(c, level + 1);