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 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
301 bus->current_slot = sd_bus_slot_unref(slot);
303 r = bus_maybe_reply_error(m, r, &error_buffer);
307 if (bus && bus->match_callbacks_modified)
311 return bus_match_run(bus, node->next, m);
313 case BUS_MATCH_MESSAGE_TYPE:
314 test_u8 = m->header->type;
317 case BUS_MATCH_SENDER:
318 test_str = m->sender;
319 /* FIXME: resolve test_str from a well-known to a unique name first */
322 case BUS_MATCH_DESTINATION:
323 test_str = m->destination;
326 case BUS_MATCH_INTERFACE:
327 test_str = m->interface;
330 case BUS_MATCH_MEMBER:
331 test_str = m->member;
335 case BUS_MATCH_PATH_NAMESPACE:
339 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
340 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
343 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
344 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
347 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
348 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
352 assert_not_reached("Unknown match type.");
355 if (BUS_MATCH_CAN_HASH(node->type)) {
356 struct bus_match_node *found;
358 /* Lookup via hash table, nice! So let's jump directly. */
361 found = hashmap_get(node->compare.children, test_str);
362 else if (node->type == BUS_MATCH_MESSAGE_TYPE)
363 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
368 r = bus_match_run(bus, found, m);
373 struct bus_match_node *c;
375 /* No hash table, so let's iterate manually... */
377 for (c = node->child; c; c = c->next) {
378 if (!value_node_test(c, node->type, test_u8, test_str, m))
381 r = bus_match_run(bus, c, m);
387 if (bus && bus->match_callbacks_modified)
390 /* And now, let's invoke our siblings */
391 return bus_match_run(bus, node->next, m);
394 static int bus_match_add_compare_value(
395 struct bus_match_node *where,
396 enum bus_match_node_type t,
398 const char *value_str,
399 struct bus_match_node **ret) {
401 struct bus_match_node *c = NULL, *n = NULL;
405 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
406 assert(BUS_MATCH_IS_COMPARE(t));
409 for (c = where->child; c && c->type != t; c = c->next)
413 /* Comparison node already exists? Then let's see if
414 * the value node exists too. */
416 if (t == BUS_MATCH_MESSAGE_TYPE)
417 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
418 else if (BUS_MATCH_CAN_HASH(t))
419 n = hashmap_get(c->compare.children, value_str);
421 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
430 /* Comparison node, doesn't exist yet? Then let's
433 c = new0(struct bus_match_node, 1);
441 c->next = where->child;
446 if (t == BUS_MATCH_MESSAGE_TYPE) {
447 c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
448 if (!c->compare.children) {
452 } else if (BUS_MATCH_CAN_HASH(t)) {
453 c->compare.children = hashmap_new(string_hash_func, string_compare_func);
454 if (!c->compare.children) {
461 n = new0(struct bus_match_node, 1);
467 n->type = BUS_MATCH_VALUE;
468 n->value.u8 = value_u8;
470 n->value.str = strdup(value_str);
478 if (c->compare.children) {
480 if (t == BUS_MATCH_MESSAGE_TYPE)
481 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
483 r = hashmap_put(c->compare.children, n->value.str, n);
499 bus_match_node_maybe_free(c);
509 static int bus_match_find_compare_value(
510 struct bus_match_node *where,
511 enum bus_match_node_type t,
513 const char *value_str,
514 struct bus_match_node **ret) {
516 struct bus_match_node *c, *n;
519 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
520 assert(BUS_MATCH_IS_COMPARE(t));
523 for (c = where->child; c && c->type != t; c = c->next)
529 if (t == BUS_MATCH_MESSAGE_TYPE)
530 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
531 else if (BUS_MATCH_CAN_HASH(t))
532 n = hashmap_get(c->compare.children, value_str);
534 for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
546 static int bus_match_add_leaf(
547 struct bus_match_node *where,
548 struct match_callback *callback) {
550 struct bus_match_node *n;
553 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
556 n = new0(struct bus_match_node, 1);
560 n->type = BUS_MATCH_LEAF;
562 n->next = where->child;
566 n->leaf.callback = callback;
567 callback->match_node = n;
574 static int bus_match_find_leaf(
575 struct bus_match_node *where,
576 sd_bus_message_handler_t callback,
578 struct bus_match_node **ret) {
580 struct bus_match_node *c;
583 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
586 for (c = where->child; c; c = c->next) {
589 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
591 if (c->type == BUS_MATCH_LEAF &&
592 c->leaf.callback->callback == callback &&
593 s->userdata == userdata) {
602 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
605 if (n == 4 && startswith(k, "type"))
606 return BUS_MATCH_MESSAGE_TYPE;
607 if (n == 6 && startswith(k, "sender"))
608 return BUS_MATCH_SENDER;
609 if (n == 11 && startswith(k, "destination"))
610 return BUS_MATCH_DESTINATION;
611 if (n == 9 && startswith(k, "interface"))
612 return BUS_MATCH_INTERFACE;
613 if (n == 6 && startswith(k, "member"))
614 return BUS_MATCH_MEMBER;
615 if (n == 4 && startswith(k, "path"))
616 return BUS_MATCH_PATH;
617 if (n == 14 && startswith(k, "path_namespace"))
618 return BUS_MATCH_PATH_NAMESPACE;
620 if (n == 4 && startswith(k, "arg")) {
627 return BUS_MATCH_ARG + j;
630 if (n == 5 && startswith(k, "arg")) {
632 enum bus_match_node_type t;
639 t = BUS_MATCH_ARG + a * 10 + b;
640 if (t > BUS_MATCH_ARG_LAST)
646 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
653 return BUS_MATCH_ARG_PATH + j;
656 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
657 enum bus_match_node_type t;
665 t = BUS_MATCH_ARG_PATH + a * 10 + b;
666 if (t > BUS_MATCH_ARG_PATH_LAST)
672 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
679 return BUS_MATCH_ARG_NAMESPACE + j;
682 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
683 enum bus_match_node_type t;
691 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
692 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
701 static int match_component_compare(const void *a, const void *b) {
702 const struct bus_match_component *x = a, *y = b;
704 if (x->type < y->type)
706 if (x->type > y->type)
712 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
715 for (i = 0; i < n_components; i++)
716 free(components[i].value_str);
723 struct bus_match_component **_components,
724 unsigned *_n_components) {
726 const char *p = match;
727 struct bus_match_component *components = NULL;
728 size_t components_allocated = 0;
729 unsigned n_components = 0, i;
730 _cleanup_free_ char *value = NULL;
735 assert(_n_components);
739 enum bus_match_node_type t;
741 size_t value_allocated = 0;
742 bool escaped = false, quoted;
749 t = bus_match_node_type_from_string(p, eq - p);
753 quoted = eq[1] == '\'';
755 for (q = eq + 1 + quoted;; q++) {
791 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
808 if (t == BUS_MATCH_MESSAGE_TYPE) {
809 r = bus_message_type_from_string(value, &u);
818 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
823 components[n_components].type = t;
824 components[n_components].value_str = value;
825 components[n_components].value_u8 = u;
833 if (q[quoted] != ',') {
841 /* Order the whole thing, so that we always generate the same tree */
842 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
844 /* Check for duplicates */
845 for (i = 0; i+1 < n_components; i++)
846 if (components[i].type == components[i+1].type) {
851 *_components = components;
852 *_n_components = n_components;
857 bus_match_parse_free(components, n_components);
861 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
862 _cleanup_free_ FILE *f = NULL;
867 if (n_components <= 0)
872 f = open_memstream(&buffer, &size);
876 for (i = 0; i < n_components; i++) {
882 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
886 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
887 fputs(bus_message_type_to_string(components[i].value_u8), f);
889 fputs(components[i].value_str, f);
902 struct bus_match_node *root,
903 struct bus_match_component *components,
904 unsigned n_components,
905 struct match_callback *callback) {
908 struct bus_match_node *n;
915 for (i = 0; i < n_components; i++) {
916 r = bus_match_add_compare_value(
917 n, components[i].type,
918 components[i].value_u8, components[i].value_str, &n);
923 return bus_match_add_leaf(n, callback);
926 int bus_match_remove(
927 struct bus_match_node *root,
928 struct match_callback *callback) {
930 struct bus_match_node *node, *pp;
935 node = callback->match_node;
939 assert(node->type == BUS_MATCH_LEAF);
941 callback->match_node = NULL;
945 bus_match_node_free(node);
947 /* Prune the tree above */
952 if (!bus_match_node_maybe_free(node))
960 struct bus_match_node *root,
961 struct bus_match_component *components,
962 unsigned n_components,
963 sd_bus_message_handler_t callback,
965 struct match_callback **ret) {
967 struct bus_match_node *n, **gc;
974 gc = newa(struct bus_match_node*, n_components);
977 for (i = 0; i < n_components; i++) {
978 r = bus_match_find_compare_value(
979 n, components[i].type,
980 components[i].value_u8, components[i].value_str,
988 r = bus_match_find_leaf(n, callback, userdata, &n);
992 *ret = n->leaf.callback;
996 void bus_match_free(struct bus_match_node *node) {
997 struct bus_match_node *c;
1002 if (BUS_MATCH_CAN_HASH(node->type)) {
1005 HASHMAP_FOREACH(c, node->compare.children, i)
1008 assert(hashmap_isempty(node->compare.children));
1011 while ((c = node->child))
1014 if (node->type != BUS_MATCH_ROOT)
1015 bus_match_node_free(node);
1018 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1021 case BUS_MATCH_ROOT:
1024 case BUS_MATCH_VALUE:
1027 case BUS_MATCH_LEAF:
1030 case BUS_MATCH_MESSAGE_TYPE:
1033 case BUS_MATCH_SENDER:
1036 case BUS_MATCH_DESTINATION:
1037 return "destination";
1039 case BUS_MATCH_INTERFACE:
1042 case BUS_MATCH_MEMBER:
1045 case BUS_MATCH_PATH:
1048 case BUS_MATCH_PATH_NAMESPACE:
1049 return "path_namespace";
1051 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1052 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1055 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1056 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1059 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1060 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1068 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1069 struct bus_match_node *c;
1070 _cleanup_free_ char *pfx = NULL;
1076 pfx = strrep(" ", level);
1077 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1079 if (node->type == BUS_MATCH_VALUE) {
1080 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1081 printf(" <%u>\n", node->value.u8);
1083 printf(" <%s>\n", node->value.str);
1084 } else if (node->type == BUS_MATCH_ROOT)
1086 else if (node->type == BUS_MATCH_LEAF)
1087 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1091 if (BUS_MATCH_CAN_HASH(node->type)) {
1094 HASHMAP_FOREACH(c, node->compare.children, i)
1095 bus_match_dump(c, level + 1);
1098 for (c = node->child; c; c = c->next)
1099 bus_match_dump(c, level + 1);