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"
30 * A: type=signal,sender=foo,interface=bar
31 * B: type=signal,sender=quux,interface=fips
32 * C: type=signal,sender=quux,interface=waldo
33 * D: type=signal,member=test
38 * results in this tree:
41 * + BUS_MATCH_MESSAGE_TYPE
42 * | ` BUS_MATCH_VALUE: value == signal
43 * | + DBUS_MATCH_SENDER
44 * | | + BUS_MATCH_VALUE: value == foo
45 * | | | ` DBUS_MATCH_INTERFACE
46 * | | | ` BUS_MATCH_VALUE: value == bar
47 * | | | ` BUS_MATCH_LEAF: A
48 * | | ` BUS_MATCH_VALUE: value == quux
49 * | | ` DBUS_MATCH_INTERFACE
50 * | | | BUS_MATCH_VALUE: value == fips
51 * | | | ` BUS_MATCH_LEAF: B
52 * | | ` BUS_MATCH_VALUE: value == waldo
53 * | | ` BUS_MATCH_LEAF: C
54 * | + DBUS_MATCH_MEMBER
55 * | | ` BUS_MATCH_VALUE: value == test
56 * | | ` BUS_MATCH_LEAF: D
57 * | + BUS_MATCH_LEAF: F
58 * | ` BUS_MATCH_LEAF: G
60 * ` BUS_MATCH_VALUE: value == miau
64 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
65 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
68 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
69 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
70 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
73 static void bus_match_node_free(struct bus_match_node *node) {
77 assert(node->type != BUS_MATCH_ROOT);
78 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
80 if (node->parent->child) {
81 /* We are apparently linked into the parent's child
82 * list. Let's remove us from there. */
84 assert(node->prev->next == node);
85 node->prev->next = node->next;
87 assert(node->parent->child == node);
88 node->parent->child = node->next;
92 node->next->prev = node->prev;
95 if (node->type == BUS_MATCH_VALUE) {
96 /* We might be in the parent's hash table, so clean
99 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
100 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
101 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
102 hashmap_remove(node->parent->compare.children, node->value.str);
104 free(node->value.str);
107 if (BUS_MATCH_IS_COMPARE(node->type)) {
108 assert(hashmap_isempty(node->compare.children));
109 hashmap_free(node->compare.children);
115 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
118 if (node->type == BUS_MATCH_ROOT)
124 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
127 bus_match_node_free(node);
131 static bool value_node_test(
132 struct bus_match_node *node,
133 enum bus_match_node_type parent_type,
135 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: {
186 return streq_ptr(node->value.str, value_str);
188 STRV_FOREACH(i, value_strv)
189 if (streq_ptr(node->value.str, *i))
195 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
199 return namespace_simple_pattern(node->value.str, value_str);
201 STRV_FOREACH(i, value_strv)
202 if (namespace_simple_pattern(node->value.str, *i))
207 case BUS_MATCH_PATH_NAMESPACE:
208 return path_simple_pattern(node->value.str, value_str);
210 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
214 return path_complex_pattern(node->value.str, value_str);
216 STRV_FOREACH(i, value_strv)
217 if (path_complex_pattern(node->value.str, *i))
224 assert_not_reached("Invalid node type");
228 static bool value_node_same(
229 struct bus_match_node *node,
230 enum bus_match_node_type parent_type,
232 const char *value_str) {
234 /* Tests parameters against this value node, not doing prefix
235 * magic and stuff, i.e. this one actually compares the match
239 assert(node->type == BUS_MATCH_VALUE);
241 switch (parent_type) {
243 case BUS_MATCH_MESSAGE_TYPE:
244 return node->value.u8 == value_u8;
246 case BUS_MATCH_SENDER:
247 case BUS_MATCH_DESTINATION:
248 case BUS_MATCH_INTERFACE:
249 case BUS_MATCH_MEMBER:
251 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
252 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
253 case BUS_MATCH_PATH_NAMESPACE:
254 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
255 return streq(node->value.str, value_str);
258 assert_not_reached("Invalid node type");
264 struct bus_match_node *node,
267 _cleanup_strv_free_ char **test_strv = NULL;
268 const char *test_str = NULL;
277 if (bus && bus->match_callbacks_modified)
280 /* Not these special semantics: when traversing the tree we
281 * usually let bus_match_run() when called for a node
282 * recursively invoke bus_match_run(). There's are two
283 * exceptions here though, which are BUS_NODE_ROOT (which
284 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
285 * are invoked anyway by its parent. */
287 switch (node->type) {
291 /* Run all children. Since we cannot have any siblings
292 * we won't call any. The children of the root node
293 * are compares or leaves, they will automatically
294 * call their siblings. */
295 return bus_match_run(bus, node->child, m);
297 case BUS_MATCH_VALUE:
299 /* Run all children. We don't execute any siblings, we
300 * assume our caller does that. The children of value
301 * nodes are compares or leaves, they will
302 * automatically call their siblings */
305 return bus_match_run(bus, node->child, m);
310 if (node->leaf.callback->last_iteration == bus->iteration_counter)
313 node->leaf.callback->last_iteration = bus->iteration_counter;
316 r = sd_bus_message_rewind(m, true);
320 /* Run the callback. And then invoke siblings. */
321 if (node->leaf.callback->callback) {
322 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
325 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
327 bus->current_slot = sd_bus_slot_ref(slot);
328 bus->current_handler = node->leaf.callback->callback;
329 bus->current_userdata = slot->userdata;
331 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
333 bus->current_userdata = NULL;
334 bus->current_handler = NULL;
335 bus->current_slot = sd_bus_slot_unref(slot);
338 r = bus_maybe_reply_error(m, r, &error_buffer);
342 if (bus && bus->match_callbacks_modified)
346 return bus_match_run(bus, node->next, m);
348 case BUS_MATCH_MESSAGE_TYPE:
349 test_u8 = m->header->type;
352 case BUS_MATCH_SENDER:
353 test_str = m->sender;
354 /* FIXME: resolve test_str from a well-known to a unique name first */
357 case BUS_MATCH_DESTINATION:
358 test_str = m->destination;
361 case BUS_MATCH_INTERFACE:
362 test_str = m->interface;
365 case BUS_MATCH_MEMBER:
366 test_str = m->member;
370 case BUS_MATCH_PATH_NAMESPACE:
374 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
375 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
378 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
379 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
382 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
383 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
387 assert_not_reached("Unknown match type.");
390 if (BUS_MATCH_CAN_HASH(node->type)) {
391 struct bus_match_node *found;
393 /* Lookup via hash table, nice! So let's jump directly. */
396 found = hashmap_get(node->compare.children, test_str);
397 else if (test_strv) {
400 STRV_FOREACH(i, test_strv) {
401 found = hashmap_get(node->compare.children, *i);
403 r = bus_match_run(bus, found, m);
410 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
411 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
416 r = bus_match_run(bus, found, m);
421 struct bus_match_node *c;
423 /* No hash table, so let's iterate manually... */
425 for (c = node->child; c; c = c->next) {
426 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
429 r = bus_match_run(bus, c, m);
435 if (bus && bus->match_callbacks_modified)
438 /* And now, let's invoke our siblings */
439 return bus_match_run(bus, node->next, m);
442 static int bus_match_add_compare_value(
443 struct bus_match_node *where,
444 enum bus_match_node_type t,
446 const char *value_str,
447 struct bus_match_node **ret) {
449 struct bus_match_node *c = NULL, *n = NULL;
453 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
454 assert(BUS_MATCH_IS_COMPARE(t));
457 for (c = where->child; c && c->type != t; c = c->next)
461 /* Comparison node already exists? Then let's see if
462 * the value node exists too. */
464 if (t == BUS_MATCH_MESSAGE_TYPE)
465 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
466 else if (BUS_MATCH_CAN_HASH(t))
467 n = hashmap_get(c->compare.children, value_str);
469 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
478 /* Comparison node, doesn't exist yet? Then let's
481 c = new0(struct bus_match_node, 1);
489 c->next = where->child;
494 if (t == BUS_MATCH_MESSAGE_TYPE) {
495 c->compare.children = hashmap_new(NULL);
496 if (!c->compare.children) {
500 } else if (BUS_MATCH_CAN_HASH(t)) {
501 c->compare.children = hashmap_new(&string_hash_ops);
502 if (!c->compare.children) {
509 n = new0(struct bus_match_node, 1);
515 n->type = BUS_MATCH_VALUE;
516 n->value.u8 = value_u8;
518 n->value.str = strdup(value_str);
526 if (c->compare.children) {
528 if (t == BUS_MATCH_MESSAGE_TYPE)
529 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
531 r = hashmap_put(c->compare.children, n->value.str, n);
547 bus_match_node_maybe_free(c);
557 static int bus_match_find_compare_value(
558 struct bus_match_node *where,
559 enum bus_match_node_type t,
561 const char *value_str,
562 struct bus_match_node **ret) {
564 struct bus_match_node *c, *n;
567 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
568 assert(BUS_MATCH_IS_COMPARE(t));
571 for (c = where->child; c && c->type != t; c = c->next)
577 if (t == BUS_MATCH_MESSAGE_TYPE)
578 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
579 else if (BUS_MATCH_CAN_HASH(t))
580 n = hashmap_get(c->compare.children, value_str);
582 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
594 static int bus_match_add_leaf(
595 struct bus_match_node *where,
596 struct match_callback *callback) {
598 struct bus_match_node *n;
601 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
604 n = new0(struct bus_match_node, 1);
608 n->type = BUS_MATCH_LEAF;
610 n->next = where->child;
614 n->leaf.callback = callback;
615 callback->match_node = n;
622 static int bus_match_find_leaf(
623 struct bus_match_node *where,
624 sd_bus_message_handler_t callback,
626 struct bus_match_node **ret) {
628 struct bus_match_node *c;
631 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
634 for (c = where->child; c; c = c->next) {
637 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
639 if (c->type == BUS_MATCH_LEAF &&
640 c->leaf.callback->callback == callback &&
641 s->userdata == userdata) {
650 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
653 if (n == 4 && startswith(k, "type"))
654 return BUS_MATCH_MESSAGE_TYPE;
655 if (n == 6 && startswith(k, "sender"))
656 return BUS_MATCH_SENDER;
657 if (n == 11 && startswith(k, "destination"))
658 return BUS_MATCH_DESTINATION;
659 if (n == 9 && startswith(k, "interface"))
660 return BUS_MATCH_INTERFACE;
661 if (n == 6 && startswith(k, "member"))
662 return BUS_MATCH_MEMBER;
663 if (n == 4 && startswith(k, "path"))
664 return BUS_MATCH_PATH;
665 if (n == 14 && startswith(k, "path_namespace"))
666 return BUS_MATCH_PATH_NAMESPACE;
668 if (n == 4 && startswith(k, "arg")) {
675 return BUS_MATCH_ARG + j;
678 if (n == 5 && startswith(k, "arg")) {
680 enum bus_match_node_type t;
687 t = BUS_MATCH_ARG + a * 10 + b;
688 if (t > BUS_MATCH_ARG_LAST)
694 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
701 return BUS_MATCH_ARG_PATH + j;
704 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
705 enum bus_match_node_type t;
713 t = BUS_MATCH_ARG_PATH + a * 10 + b;
714 if (t > BUS_MATCH_ARG_PATH_LAST)
720 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
727 return BUS_MATCH_ARG_NAMESPACE + j;
730 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
731 enum bus_match_node_type t;
739 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
740 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
749 static int match_component_compare(const void *a, const void *b) {
750 const struct bus_match_component *x = a, *y = b;
752 if (x->type < y->type)
754 if (x->type > y->type)
760 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
763 for (i = 0; i < n_components; i++)
764 free(components[i].value_str);
771 struct bus_match_component **_components,
772 unsigned *_n_components) {
774 const char *p = match;
775 struct bus_match_component *components = NULL;
776 size_t components_allocated = 0;
777 unsigned n_components = 0, i;
778 _cleanup_free_ char *value = NULL;
783 assert(_n_components);
787 enum bus_match_node_type t;
789 size_t value_allocated = 0;
790 bool escaped = false, quoted;
793 /* Avahi's match rules appear to include whitespace, skip over it */
800 t = bus_match_node_type_from_string(p, eq - p);
804 quoted = eq[1] == '\'';
806 for (q = eq + 1 + quoted;; q++) {
842 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
859 if (t == BUS_MATCH_MESSAGE_TYPE) {
860 r = bus_message_type_from_string(value, &u);
869 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
874 components[n_components].type = t;
875 components[n_components].value_str = value;
876 components[n_components].value_u8 = u;
884 if (q[quoted] != ',') {
892 /* Order the whole thing, so that we always generate the same tree */
893 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
895 /* Check for duplicates */
896 for (i = 0; i+1 < n_components; i++)
897 if (components[i].type == components[i+1].type) {
902 *_components = components;
903 *_n_components = n_components;
908 bus_match_parse_free(components, n_components);
912 /// UNNEEDED by elogind
914 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
915 _cleanup_free_ FILE *f = NULL;
920 if (n_components <= 0)
925 f = open_memstream(&buffer, &size);
929 for (i = 0; i < n_components; i++) {
935 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
939 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
940 fputs(bus_message_type_to_string(components[i].value_u8), f);
942 fputs(components[i].value_str, f);
956 struct bus_match_node *root,
957 struct bus_match_component *components,
958 unsigned n_components,
959 struct match_callback *callback) {
962 struct bus_match_node *n;
969 for (i = 0; i < n_components; i++) {
970 r = bus_match_add_compare_value(
971 n, components[i].type,
972 components[i].value_u8, components[i].value_str, &n);
977 return bus_match_add_leaf(n, callback);
980 int bus_match_remove(
981 struct bus_match_node *root,
982 struct match_callback *callback) {
984 struct bus_match_node *node, *pp;
989 node = callback->match_node;
993 assert(node->type == BUS_MATCH_LEAF);
995 callback->match_node = NULL;
999 bus_match_node_free(node);
1001 /* Prune the tree above */
1006 if (!bus_match_node_maybe_free(node))
1014 struct bus_match_node *root,
1015 struct bus_match_component *components,
1016 unsigned n_components,
1017 sd_bus_message_handler_t callback,
1019 struct match_callback **ret) {
1021 struct bus_match_node *n, **gc;
1028 gc = newa(struct bus_match_node*, n_components);
1031 for (i = 0; i < n_components; i++) {
1032 r = bus_match_find_compare_value(
1033 n, components[i].type,
1034 components[i].value_u8, components[i].value_str,
1042 r = bus_match_find_leaf(n, callback, userdata, &n);
1046 *ret = n->leaf.callback;
1050 void bus_match_free(struct bus_match_node *node) {
1051 struct bus_match_node *c;
1056 if (BUS_MATCH_CAN_HASH(node->type)) {
1059 HASHMAP_FOREACH(c, node->compare.children, i)
1062 assert(hashmap_isempty(node->compare.children));
1065 while ((c = node->child))
1068 if (node->type != BUS_MATCH_ROOT)
1069 bus_match_node_free(node);
1072 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1075 case BUS_MATCH_ROOT:
1078 case BUS_MATCH_VALUE:
1081 case BUS_MATCH_LEAF:
1084 case BUS_MATCH_MESSAGE_TYPE:
1087 case BUS_MATCH_SENDER:
1090 case BUS_MATCH_DESTINATION:
1091 return "destination";
1093 case BUS_MATCH_INTERFACE:
1096 case BUS_MATCH_MEMBER:
1099 case BUS_MATCH_PATH:
1102 case BUS_MATCH_PATH_NAMESPACE:
1103 return "path_namespace";
1105 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1106 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1109 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1110 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1113 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1114 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1122 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1123 struct bus_match_node *c;
1124 _cleanup_free_ char *pfx = NULL;
1130 pfx = strrep(" ", level);
1131 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1133 if (node->type == BUS_MATCH_VALUE) {
1134 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1135 printf(" <%u>\n", node->value.u8);
1137 printf(" <%s>\n", node->value.str);
1138 } else if (node->type == BUS_MATCH_ROOT)
1140 else if (node->type == BUS_MATCH_LEAF)
1141 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1145 if (BUS_MATCH_CAN_HASH(node->type)) {
1148 HASHMAP_FOREACH(c, node->compare.children, i)
1149 bus_match_dump(c, level + 1);
1152 for (c = node->child; c; c = c->next)
1153 bus_match_dump(c, level + 1);
1156 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1157 bool found_driver = false;
1160 if (n_components <= 0)
1161 return BUS_MATCH_GENERIC;
1165 /* Checks whether the specified match can only match the
1166 * pseudo-service for local messages, which we detect by
1167 * sender, interface or path. If a match is not restricted to
1168 * local messages, then we check if it only matches on the
1171 for (i = 0; i < n_components; i++) {
1172 const struct bus_match_component *c = components + i;
1174 if (c->type == BUS_MATCH_SENDER) {
1175 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1176 return BUS_MATCH_LOCAL;
1178 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1179 found_driver = true;
1182 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1183 return BUS_MATCH_LOCAL;
1185 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1186 return BUS_MATCH_LOCAL;
1189 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;