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);
298 return bus_match_run(bus, node->next, m);
300 case BUS_MATCH_MESSAGE_TYPE:
301 test_u8 = m->header->type;
304 case BUS_MATCH_SENDER:
305 test_str = m->sender;
306 /* FIXME: resolve test_str from a well-known to a unique name first */
309 case BUS_MATCH_DESTINATION:
310 test_str = m->destination;
313 case BUS_MATCH_INTERFACE:
314 test_str = m->interface;
317 case BUS_MATCH_MEMBER:
318 test_str = m->member;
322 case BUS_MATCH_PATH_NAMESPACE:
326 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
327 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
330 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
331 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
334 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
335 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
339 assert_not_reached("Unknown match type.");
342 if (BUS_MATCH_CAN_HASH(node->type)) {
343 struct bus_match_node *found;
345 /* Lookup via hash table, nice! So let's jump directly. */
348 found = hashmap_get(node->compare.children, test_str);
349 else if (node->type == BUS_MATCH_MESSAGE_TYPE)
350 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
355 r = bus_match_run(bus, found, m);
360 struct bus_match_node *c;
362 /* No hash table, so let's iterate manually... */
364 for (c = node->child; c; c = c->next) {
365 if (!value_node_test(c, node->type, test_u8, test_str, m))
368 r = bus_match_run(bus, c, m);
374 if (bus && bus->match_callbacks_modified)
377 /* And now, let's invoke our siblings */
378 return bus_match_run(bus, node->next, m);
381 static int bus_match_add_compare_value(
382 struct bus_match_node *where,
383 enum bus_match_node_type t,
385 const char *value_str,
386 struct bus_match_node **ret) {
388 struct bus_match_node *c = NULL, *n = NULL;
392 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
393 assert(BUS_MATCH_IS_COMPARE(t));
396 for (c = where->child; c && c->type != t; c = c->next)
400 /* Comparison node already exists? Then let's see if
401 * the value node exists too. */
403 if (t == BUS_MATCH_MESSAGE_TYPE)
404 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
405 else if (BUS_MATCH_CAN_HASH(t))
406 n = hashmap_get(c->compare.children, value_str);
408 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
417 /* Comparison node, doesn't exist yet? Then let's
420 c = new0(struct bus_match_node, 1);
428 c->next = where->child;
433 if (t == BUS_MATCH_MESSAGE_TYPE) {
434 c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
435 if (!c->compare.children) {
439 } else if (BUS_MATCH_CAN_HASH(t)) {
440 c->compare.children = hashmap_new(string_hash_func, string_compare_func);
441 if (!c->compare.children) {
448 n = new0(struct bus_match_node, 1);
454 n->type = BUS_MATCH_VALUE;
455 n->value.u8 = value_u8;
457 n->value.str = strdup(value_str);
465 if (c->compare.children) {
467 if (t == BUS_MATCH_MESSAGE_TYPE)
468 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
470 r = hashmap_put(c->compare.children, n->value.str, n);
486 bus_match_node_maybe_free(c);
496 static int bus_match_find_compare_value(
497 struct bus_match_node *where,
498 enum bus_match_node_type t,
500 const char *value_str,
501 struct bus_match_node **ret) {
503 struct bus_match_node *c, *n;
506 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
507 assert(BUS_MATCH_IS_COMPARE(t));
510 for (c = where->child; c && c->type != t; c = c->next)
516 if (t == BUS_MATCH_MESSAGE_TYPE)
517 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
518 else if (BUS_MATCH_CAN_HASH(t))
519 n = hashmap_get(c->compare.children, value_str);
521 for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
533 static int bus_match_add_leaf(
534 struct bus_match_node *where,
535 sd_bus_message_handler_t callback,
538 struct bus_match_node **ret) {
540 struct bus_match_node *n;
543 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
546 n = new0(struct bus_match_node, 1);
550 n->type = BUS_MATCH_LEAF;
552 n->next = where->child;
555 n->leaf.callback = callback;
556 n->leaf.userdata = userdata;
557 n->leaf.cookie = cookie;
565 static int bus_match_find_leaf(
566 struct bus_match_node *where,
567 sd_bus_message_handler_t callback,
569 struct bus_match_node **ret) {
571 struct bus_match_node *c;
574 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
577 for (c = where->child; c; c = c->next) {
578 if (c->type == BUS_MATCH_LEAF &&
579 c->leaf.callback == callback &&
580 c->leaf.userdata == userdata) {
589 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
592 if (n == 4 && startswith(k, "type"))
593 return BUS_MATCH_MESSAGE_TYPE;
594 if (n == 6 && startswith(k, "sender"))
595 return BUS_MATCH_SENDER;
596 if (n == 11 && startswith(k, "destination"))
597 return BUS_MATCH_DESTINATION;
598 if (n == 9 && startswith(k, "interface"))
599 return BUS_MATCH_INTERFACE;
600 if (n == 6 && startswith(k, "member"))
601 return BUS_MATCH_MEMBER;
602 if (n == 4 && startswith(k, "path"))
603 return BUS_MATCH_PATH;
604 if (n == 14 && startswith(k, "path_namespace"))
605 return BUS_MATCH_PATH_NAMESPACE;
607 if (n == 4 && startswith(k, "arg")) {
614 return BUS_MATCH_ARG + j;
617 if (n == 5 && startswith(k, "arg")) {
619 enum bus_match_node_type t;
626 t = BUS_MATCH_ARG + a * 10 + b;
627 if (t > BUS_MATCH_ARG_LAST)
633 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
640 return BUS_MATCH_ARG_PATH + j;
643 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
644 enum bus_match_node_type t;
652 t = BUS_MATCH_ARG_PATH + a * 10 + b;
653 if (t > BUS_MATCH_ARG_PATH_LAST)
659 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
666 return BUS_MATCH_ARG_NAMESPACE + j;
669 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
670 enum bus_match_node_type t;
678 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
679 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
688 static int match_component_compare(const void *a, const void *b) {
689 const struct bus_match_component *x = a, *y = b;
691 if (x->type < y->type)
693 if (x->type > y->type)
699 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
702 for (i = 0; i < n_components; i++)
703 free(components[i].value_str);
710 struct bus_match_component **_components,
711 unsigned *_n_components) {
713 const char *p = match;
714 struct bus_match_component *components = NULL;
715 size_t components_allocated = 0;
716 unsigned n_components = 0, i;
717 _cleanup_free_ char *value = NULL;
722 assert(_n_components);
726 enum bus_match_node_type t;
728 size_t value_allocated = 0;
729 bool escaped = false;
739 t = bus_match_node_type_from_string(p, eq - p);
743 for (q = eq + 2;; q++) {
762 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
779 if (t == BUS_MATCH_MESSAGE_TYPE) {
780 r = bus_message_type_from_string(value, &u);
789 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
794 components[n_components].type = t;
795 components[n_components].value_str = value;
796 components[n_components].value_u8 = u;
812 /* Order the whole thing, so that we always generate the same tree */
813 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
815 /* Check for duplicates */
816 for (i = 0; i+1 < n_components; i++)
817 if (components[i].type == components[i+1].type) {
822 *_components = components;
823 *_n_components = n_components;
828 bus_match_parse_free(components, n_components);
832 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
833 _cleanup_free_ FILE *f = NULL;
838 if (n_components <= 0)
843 f = open_memstream(&buffer, &size);
847 for (i = 0; i < n_components; i++) {
853 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
857 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
858 fputs(bus_message_type_to_string(components[i].value_u8), f);
860 fputs(components[i].value_str, f);
873 struct bus_match_node *root,
874 struct bus_match_component *components,
875 unsigned n_components,
876 sd_bus_message_handler_t callback,
879 struct bus_match_node **ret) {
882 struct bus_match_node *n;
888 for (i = 0; i < n_components; i++) {
889 r = bus_match_add_compare_value(
890 n, components[i].type,
891 components[i].value_u8, components[i].value_str, &n);
896 r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
906 int bus_match_remove(
907 struct bus_match_node *root,
908 struct bus_match_component *components,
909 unsigned n_components,
910 sd_bus_message_handler_t callback,
915 struct bus_match_node *n, **gc;
920 gc = newa(struct bus_match_node*, n_components);
923 for (i = 0; i < n_components; i++) {
924 r = bus_match_find_compare_value(
925 n, components[i].type,
926 components[i].value_u8, components[i].value_str,
934 r = bus_match_find_leaf(n, callback, userdata, &n);
939 *cookie = n->leaf.cookie;
942 bus_match_node_free(n);
944 /* Prune the tree above */
945 for (i = n_components; i > 0; i --) {
946 struct bus_match_node *p = gc[i-1]->parent;
948 if (!bus_match_node_maybe_free(gc[i-1]))
951 if (!bus_match_node_maybe_free(p))
958 void bus_match_free(struct bus_match_node *node) {
959 struct bus_match_node *c;
964 if (BUS_MATCH_CAN_HASH(node->type)) {
967 HASHMAP_FOREACH(c, node->compare.children, i)
970 assert(hashmap_isempty(node->compare.children));
973 while ((c = node->child))
976 if (node->type != BUS_MATCH_ROOT)
977 bus_match_node_free(node);
980 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
986 case BUS_MATCH_VALUE:
992 case BUS_MATCH_MESSAGE_TYPE:
995 case BUS_MATCH_SENDER:
998 case BUS_MATCH_DESTINATION:
999 return "destination";
1001 case BUS_MATCH_INTERFACE:
1004 case BUS_MATCH_MEMBER:
1007 case BUS_MATCH_PATH:
1010 case BUS_MATCH_PATH_NAMESPACE:
1011 return "path_namespace";
1013 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1014 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1017 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1018 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1021 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1022 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1030 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1031 struct bus_match_node *c;
1032 _cleanup_free_ char *pfx = NULL;
1038 pfx = strrep(" ", level);
1039 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1041 if (node->type == BUS_MATCH_VALUE) {
1042 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1043 printf(" <%u>\n", node->value.u8);
1045 printf(" <%s>\n", node->value.str);
1046 } else if (node->type == BUS_MATCH_ROOT)
1048 else if (node->type == BUS_MATCH_LEAF)
1049 printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
1053 if (BUS_MATCH_CAN_HASH(node->type)) {
1056 HASHMAP_FOREACH(c, node->compare.children, i)
1057 bus_match_dump(c, level + 1);
1060 for (c = node->child; c; c = c->next)
1061 bus_match_dump(c, level + 1);