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) {
295 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
297 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
299 bus->current_slot = slot;
300 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
302 bus->current_slot = NULL;
304 r = bus_maybe_reply_error(m, r, &error_buffer);
308 if (bus && bus->match_callbacks_modified)
312 return bus_match_run(bus, node->next, m);
314 case BUS_MATCH_MESSAGE_TYPE:
315 test_u8 = m->header->type;
318 case BUS_MATCH_SENDER:
319 test_str = m->sender;
320 /* FIXME: resolve test_str from a well-known to a unique name first */
323 case BUS_MATCH_DESTINATION:
324 test_str = m->destination;
327 case BUS_MATCH_INTERFACE:
328 test_str = m->interface;
331 case BUS_MATCH_MEMBER:
332 test_str = m->member;
336 case BUS_MATCH_PATH_NAMESPACE:
340 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
341 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
344 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
345 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
348 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
349 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
353 assert_not_reached("Unknown match type.");
356 if (BUS_MATCH_CAN_HASH(node->type)) {
357 struct bus_match_node *found;
359 /* Lookup via hash table, nice! So let's jump directly. */
362 found = hashmap_get(node->compare.children, test_str);
363 else if (node->type == BUS_MATCH_MESSAGE_TYPE)
364 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
369 r = bus_match_run(bus, found, m);
374 struct bus_match_node *c;
376 /* No hash table, so let's iterate manually... */
378 for (c = node->child; c; c = c->next) {
379 if (!value_node_test(c, node->type, test_u8, test_str, m))
382 r = bus_match_run(bus, c, m);
388 if (bus && bus->match_callbacks_modified)
391 /* And now, let's invoke our siblings */
392 return bus_match_run(bus, node->next, m);
395 static int bus_match_add_compare_value(
396 struct bus_match_node *where,
397 enum bus_match_node_type t,
399 const char *value_str,
400 struct bus_match_node **ret) {
402 struct bus_match_node *c = NULL, *n = NULL;
406 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
407 assert(BUS_MATCH_IS_COMPARE(t));
410 for (c = where->child; c && c->type != t; c = c->next)
414 /* Comparison node already exists? Then let's see if
415 * the value node exists too. */
417 if (t == BUS_MATCH_MESSAGE_TYPE)
418 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
419 else if (BUS_MATCH_CAN_HASH(t))
420 n = hashmap_get(c->compare.children, value_str);
422 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
431 /* Comparison node, doesn't exist yet? Then let's
434 c = new0(struct bus_match_node, 1);
442 c->next = where->child;
447 if (t == BUS_MATCH_MESSAGE_TYPE) {
448 c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
449 if (!c->compare.children) {
453 } else if (BUS_MATCH_CAN_HASH(t)) {
454 c->compare.children = hashmap_new(string_hash_func, string_compare_func);
455 if (!c->compare.children) {
462 n = new0(struct bus_match_node, 1);
468 n->type = BUS_MATCH_VALUE;
469 n->value.u8 = value_u8;
471 n->value.str = strdup(value_str);
479 if (c->compare.children) {
481 if (t == BUS_MATCH_MESSAGE_TYPE)
482 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
484 r = hashmap_put(c->compare.children, n->value.str, n);
500 bus_match_node_maybe_free(c);
510 static int bus_match_find_compare_value(
511 struct bus_match_node *where,
512 enum bus_match_node_type t,
514 const char *value_str,
515 struct bus_match_node **ret) {
517 struct bus_match_node *c, *n;
520 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
521 assert(BUS_MATCH_IS_COMPARE(t));
524 for (c = where->child; c && c->type != t; c = c->next)
530 if (t == BUS_MATCH_MESSAGE_TYPE)
531 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
532 else if (BUS_MATCH_CAN_HASH(t))
533 n = hashmap_get(c->compare.children, value_str);
535 for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
547 static int bus_match_add_leaf(
548 struct bus_match_node *where,
549 struct match_callback *callback) {
551 struct bus_match_node *n;
554 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
557 n = new0(struct bus_match_node, 1);
561 n->type = BUS_MATCH_LEAF;
563 n->next = where->child;
567 n->leaf.callback = callback;
568 callback->match_node = n;
575 static int bus_match_find_leaf(
576 struct bus_match_node *where,
577 sd_bus_message_handler_t callback,
579 struct bus_match_node **ret) {
581 struct bus_match_node *c;
584 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
587 for (c = where->child; c; c = c->next) {
590 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
592 if (c->type == BUS_MATCH_LEAF &&
593 c->leaf.callback->callback == callback &&
594 s->userdata == userdata) {
603 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
606 if (n == 4 && startswith(k, "type"))
607 return BUS_MATCH_MESSAGE_TYPE;
608 if (n == 6 && startswith(k, "sender"))
609 return BUS_MATCH_SENDER;
610 if (n == 11 && startswith(k, "destination"))
611 return BUS_MATCH_DESTINATION;
612 if (n == 9 && startswith(k, "interface"))
613 return BUS_MATCH_INTERFACE;
614 if (n == 6 && startswith(k, "member"))
615 return BUS_MATCH_MEMBER;
616 if (n == 4 && startswith(k, "path"))
617 return BUS_MATCH_PATH;
618 if (n == 14 && startswith(k, "path_namespace"))
619 return BUS_MATCH_PATH_NAMESPACE;
621 if (n == 4 && startswith(k, "arg")) {
628 return BUS_MATCH_ARG + j;
631 if (n == 5 && startswith(k, "arg")) {
633 enum bus_match_node_type t;
640 t = BUS_MATCH_ARG + a * 10 + b;
641 if (t > BUS_MATCH_ARG_LAST)
647 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
654 return BUS_MATCH_ARG_PATH + j;
657 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
658 enum bus_match_node_type t;
666 t = BUS_MATCH_ARG_PATH + a * 10 + b;
667 if (t > BUS_MATCH_ARG_PATH_LAST)
673 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
680 return BUS_MATCH_ARG_NAMESPACE + j;
683 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
684 enum bus_match_node_type t;
692 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
693 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
702 static int match_component_compare(const void *a, const void *b) {
703 const struct bus_match_component *x = a, *y = b;
705 if (x->type < y->type)
707 if (x->type > y->type)
713 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
716 for (i = 0; i < n_components; i++)
717 free(components[i].value_str);
724 struct bus_match_component **_components,
725 unsigned *_n_components) {
727 const char *p = match;
728 struct bus_match_component *components = NULL;
729 size_t components_allocated = 0;
730 unsigned n_components = 0, i;
731 _cleanup_free_ char *value = NULL;
736 assert(_n_components);
740 enum bus_match_node_type t;
742 size_t value_allocated = 0;
743 bool escaped = false, quoted;
750 t = bus_match_node_type_from_string(p, eq - p);
754 quoted = eq[1] == '\'';
756 for (q = eq + 1 + quoted;; q++) {
792 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
809 if (t == BUS_MATCH_MESSAGE_TYPE) {
810 r = bus_message_type_from_string(value, &u);
819 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
824 components[n_components].type = t;
825 components[n_components].value_str = value;
826 components[n_components].value_u8 = u;
834 if (q[quoted] != ',') {
842 /* Order the whole thing, so that we always generate the same tree */
843 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
845 /* Check for duplicates */
846 for (i = 0; i+1 < n_components; i++)
847 if (components[i].type == components[i+1].type) {
852 *_components = components;
853 *_n_components = n_components;
858 bus_match_parse_free(components, n_components);
862 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
863 _cleanup_free_ FILE *f = NULL;
868 if (n_components <= 0)
873 f = open_memstream(&buffer, &size);
877 for (i = 0; i < n_components; i++) {
883 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
887 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
888 fputs(bus_message_type_to_string(components[i].value_u8), f);
890 fputs(components[i].value_str, f);
903 struct bus_match_node *root,
904 struct bus_match_component *components,
905 unsigned n_components,
906 struct match_callback *callback) {
909 struct bus_match_node *n;
916 for (i = 0; i < n_components; i++) {
917 r = bus_match_add_compare_value(
918 n, components[i].type,
919 components[i].value_u8, components[i].value_str, &n);
924 return bus_match_add_leaf(n, callback);
927 int bus_match_remove(
928 struct bus_match_node *root,
929 struct match_callback *callback) {
931 struct bus_match_node *node, *pp;
936 node = callback->match_node;
940 assert(node->type == BUS_MATCH_LEAF);
942 callback->match_node = NULL;
946 bus_match_node_free(node);
948 /* Prune the tree above */
953 if (!bus_match_node_maybe_free(node))
961 struct bus_match_node *root,
962 struct bus_match_component *components,
963 unsigned n_components,
964 sd_bus_message_handler_t callback,
966 struct match_callback **ret) {
968 struct bus_match_node *n, **gc;
975 gc = newa(struct bus_match_node*, n_components);
978 for (i = 0; i < n_components; i++) {
979 r = bus_match_find_compare_value(
980 n, components[i].type,
981 components[i].value_u8, components[i].value_str,
989 r = bus_match_find_leaf(n, callback, userdata, &n);
993 *ret = n->leaf.callback;
997 void bus_match_free(struct bus_match_node *node) {
998 struct bus_match_node *c;
1003 if (BUS_MATCH_CAN_HASH(node->type)) {
1006 HASHMAP_FOREACH(c, node->compare.children, i)
1009 assert(hashmap_isempty(node->compare.children));
1012 while ((c = node->child))
1015 if (node->type != BUS_MATCH_ROOT)
1016 bus_match_node_free(node);
1019 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1022 case BUS_MATCH_ROOT:
1025 case BUS_MATCH_VALUE:
1028 case BUS_MATCH_LEAF:
1031 case BUS_MATCH_MESSAGE_TYPE:
1034 case BUS_MATCH_SENDER:
1037 case BUS_MATCH_DESTINATION:
1038 return "destination";
1040 case BUS_MATCH_INTERFACE:
1043 case BUS_MATCH_MEMBER:
1046 case BUS_MATCH_PATH:
1049 case BUS_MATCH_PATH_NAMESPACE:
1050 return "path_namespace";
1052 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1053 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1056 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1057 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1060 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1061 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1069 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1070 struct bus_match_node *c;
1071 _cleanup_free_ char *pfx = NULL;
1077 pfx = strrep(" ", level);
1078 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1080 if (node->type == BUS_MATCH_VALUE) {
1081 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1082 printf(" <%u>\n", node->value.u8);
1084 printf(" <%s>\n", node->value.str);
1085 } else if (node->type == BUS_MATCH_ROOT)
1087 else if (node->type == BUS_MATCH_LEAF)
1088 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1092 if (BUS_MATCH_CAN_HASH(node->type)) {
1095 HASHMAP_FOREACH(c, node->compare.children, i)
1096 bus_match_dump(c, level + 1);
1099 for (c = node->child; c; c = c->next)
1100 bus_match_dump(c, level + 1);