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 "alloc-util.h"
23 #include "bus-internal.h"
24 #include "bus-match.h"
25 #include "bus-message.h"
29 #include "hexdecoct.h"
30 #include "string-util.h"
35 * A: type=signal,sender=foo,interface=bar
36 * B: type=signal,sender=quux,interface=fips
37 * C: type=signal,sender=quux,interface=waldo
38 * D: type=signal,member=test
43 * results in this tree:
46 * + BUS_MATCH_MESSAGE_TYPE
47 * | ` BUS_MATCH_VALUE: value == signal
48 * | + DBUS_MATCH_SENDER
49 * | | + BUS_MATCH_VALUE: value == foo
50 * | | | ` DBUS_MATCH_INTERFACE
51 * | | | ` BUS_MATCH_VALUE: value == bar
52 * | | | ` BUS_MATCH_LEAF: A
53 * | | ` BUS_MATCH_VALUE: value == quux
54 * | | ` DBUS_MATCH_INTERFACE
55 * | | | BUS_MATCH_VALUE: value == fips
56 * | | | ` BUS_MATCH_LEAF: B
57 * | | ` BUS_MATCH_VALUE: value == waldo
58 * | | ` BUS_MATCH_LEAF: C
59 * | + DBUS_MATCH_MEMBER
60 * | | ` BUS_MATCH_VALUE: value == test
61 * | | ` BUS_MATCH_LEAF: D
62 * | + BUS_MATCH_LEAF: F
63 * | ` BUS_MATCH_LEAF: G
65 * ` BUS_MATCH_VALUE: value == miau
69 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
70 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
73 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
74 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
75 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
76 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
79 static void bus_match_node_free(struct bus_match_node *node) {
83 assert(node->type != BUS_MATCH_ROOT);
84 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
86 if (node->parent->child) {
87 /* We are apparently linked into the parent's child
88 * list. Let's remove us from there. */
90 assert(node->prev->next == node);
91 node->prev->next = node->next;
93 assert(node->parent->child == node);
94 node->parent->child = node->next;
98 node->next->prev = node->prev;
101 if (node->type == BUS_MATCH_VALUE) {
102 /* We might be in the parent's hash table, so clean
105 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
106 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
107 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
108 hashmap_remove(node->parent->compare.children, node->value.str);
110 free(node->value.str);
113 if (BUS_MATCH_IS_COMPARE(node->type)) {
114 assert(hashmap_isempty(node->compare.children));
115 hashmap_free(node->compare.children);
121 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
124 if (node->type == BUS_MATCH_ROOT)
130 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
133 bus_match_node_free(node);
137 static bool value_node_test(
138 struct bus_match_node *node,
139 enum bus_match_node_type parent_type,
141 const char *value_str,
146 assert(node->type == BUS_MATCH_VALUE);
148 /* Tests parameters against this value node, doing prefix
149 * magic and stuff. */
151 switch (parent_type) {
153 case BUS_MATCH_MESSAGE_TYPE:
154 return node->value.u8 == value_u8;
156 case BUS_MATCH_SENDER:
157 if (streq_ptr(node->value.str, value_str))
160 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
163 /* on kdbus we have the well known names list
164 * in the credentials, let's make use of that
165 * for an accurate match */
167 STRV_FOREACH(i, m->creds.well_known_names)
168 if (streq_ptr(node->value.str, *i))
173 /* If we don't have kdbus, we don't know the
174 * well-known names of the senders. In that,
175 * let's just hope that dbus-daemon doesn't
176 * send us stuff we didn't want. */
178 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
184 case BUS_MATCH_DESTINATION:
185 case BUS_MATCH_INTERFACE:
186 case BUS_MATCH_MEMBER:
188 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
191 return streq_ptr(node->value.str, value_str);
195 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
198 STRV_FOREACH(i, value_strv)
199 if (streq_ptr(node->value.str, *i))
205 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
207 return namespace_simple_pattern(node->value.str, value_str);
211 case BUS_MATCH_PATH_NAMESPACE:
212 return path_simple_pattern(node->value.str, value_str);
214 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
216 return path_complex_pattern(node->value.str, value_str);
221 assert_not_reached("Invalid node type");
225 static bool value_node_same(
226 struct bus_match_node *node,
227 enum bus_match_node_type parent_type,
229 const char *value_str) {
231 /* Tests parameters against this value node, not doing prefix
232 * magic and stuff, i.e. this one actually compares the match
236 assert(node->type == BUS_MATCH_VALUE);
238 switch (parent_type) {
240 case BUS_MATCH_MESSAGE_TYPE:
241 return node->value.u8 == value_u8;
243 case BUS_MATCH_SENDER:
244 case BUS_MATCH_DESTINATION:
245 case BUS_MATCH_INTERFACE:
246 case BUS_MATCH_MEMBER:
248 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
249 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
250 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
251 case BUS_MATCH_PATH_NAMESPACE:
252 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
253 return streq(node->value.str, value_str);
256 assert_not_reached("Invalid node type");
262 struct bus_match_node *node,
265 _cleanup_strv_free_ char **test_strv = NULL;
266 const char *test_str = NULL;
275 if (bus && bus->match_callbacks_modified)
278 /* Not these special semantics: when traversing the tree we
279 * usually let bus_match_run() when called for a node
280 * recursively invoke bus_match_run(). There's are two
281 * exceptions here though, which are BUS_NODE_ROOT (which
282 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
283 * are invoked anyway by its parent. */
285 switch (node->type) {
289 /* Run all children. Since we cannot have any siblings
290 * we won't call any. The children of the root node
291 * are compares or leaves, they will automatically
292 * call their siblings. */
293 return bus_match_run(bus, node->child, m);
295 case BUS_MATCH_VALUE:
297 /* Run all children. We don't execute any siblings, we
298 * assume our caller does that. The children of value
299 * nodes are compares or leaves, they will
300 * automatically call their siblings */
303 return bus_match_run(bus, node->child, m);
308 if (node->leaf.callback->last_iteration == bus->iteration_counter)
311 node->leaf.callback->last_iteration = bus->iteration_counter;
314 r = sd_bus_message_rewind(m, true);
318 /* Run the callback. And then invoke siblings. */
319 if (node->leaf.callback->callback) {
320 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
323 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
325 bus->current_slot = sd_bus_slot_ref(slot);
326 bus->current_handler = node->leaf.callback->callback;
327 bus->current_userdata = slot->userdata;
329 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
331 bus->current_userdata = NULL;
332 bus->current_handler = NULL;
333 bus->current_slot = sd_bus_slot_unref(slot);
336 r = bus_maybe_reply_error(m, r, &error_buffer);
340 if (bus && bus->match_callbacks_modified)
344 return bus_match_run(bus, node->next, m);
346 case BUS_MATCH_MESSAGE_TYPE:
347 test_u8 = m->header->type;
350 case BUS_MATCH_SENDER:
351 test_str = m->sender;
352 /* FIXME: resolve test_str from a well-known to a unique name first */
355 case BUS_MATCH_DESTINATION:
356 test_str = m->destination;
359 case BUS_MATCH_INTERFACE:
360 test_str = m->interface;
363 case BUS_MATCH_MEMBER:
364 test_str = m->member;
368 case BUS_MATCH_PATH_NAMESPACE:
372 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
373 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
376 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
377 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
380 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
381 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
384 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
385 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
389 assert_not_reached("Unknown match type.");
392 if (BUS_MATCH_CAN_HASH(node->type)) {
393 struct bus_match_node *found;
395 /* Lookup via hash table, nice! So let's jump directly. */
398 found = hashmap_get(node->compare.children, test_str);
399 else if (test_strv) {
402 STRV_FOREACH(i, test_strv) {
403 found = hashmap_get(node->compare.children, *i);
405 r = bus_match_run(bus, found, m);
412 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
413 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
418 r = bus_match_run(bus, found, m);
423 struct bus_match_node *c;
425 /* No hash table, so let's iterate manually... */
427 for (c = node->child; c; c = c->next) {
428 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
431 r = bus_match_run(bus, c, m);
437 if (bus && bus->match_callbacks_modified)
440 /* And now, let's invoke our siblings */
441 return bus_match_run(bus, node->next, m);
444 static int bus_match_add_compare_value(
445 struct bus_match_node *where,
446 enum bus_match_node_type t,
448 const char *value_str,
449 struct bus_match_node **ret) {
451 struct bus_match_node *c = NULL, *n = NULL;
455 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
456 assert(BUS_MATCH_IS_COMPARE(t));
459 for (c = where->child; c && c->type != t; c = c->next)
463 /* Comparison node already exists? Then let's see if
464 * the value node exists too. */
466 if (t == BUS_MATCH_MESSAGE_TYPE)
467 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
468 else if (BUS_MATCH_CAN_HASH(t))
469 n = hashmap_get(c->compare.children, value_str);
471 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
480 /* Comparison node, doesn't exist yet? Then let's
483 c = new0(struct bus_match_node, 1);
491 c->next = where->child;
496 if (t == BUS_MATCH_MESSAGE_TYPE) {
497 c->compare.children = hashmap_new(NULL);
498 if (!c->compare.children) {
502 } else if (BUS_MATCH_CAN_HASH(t)) {
503 c->compare.children = hashmap_new(&string_hash_ops);
504 if (!c->compare.children) {
511 n = new0(struct bus_match_node, 1);
517 n->type = BUS_MATCH_VALUE;
518 n->value.u8 = value_u8;
520 n->value.str = strdup(value_str);
528 if (c->compare.children) {
530 if (t == BUS_MATCH_MESSAGE_TYPE)
531 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
533 r = hashmap_put(c->compare.children, n->value.str, n);
549 bus_match_node_maybe_free(c);
559 static int bus_match_find_compare_value(
560 struct bus_match_node *where,
561 enum bus_match_node_type t,
563 const char *value_str,
564 struct bus_match_node **ret) {
566 struct bus_match_node *c, *n;
569 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
570 assert(BUS_MATCH_IS_COMPARE(t));
573 for (c = where->child; c && c->type != t; c = c->next)
579 if (t == BUS_MATCH_MESSAGE_TYPE)
580 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
581 else if (BUS_MATCH_CAN_HASH(t))
582 n = hashmap_get(c->compare.children, value_str);
584 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
596 static int bus_match_add_leaf(
597 struct bus_match_node *where,
598 struct match_callback *callback) {
600 struct bus_match_node *n;
603 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
606 n = new0(struct bus_match_node, 1);
610 n->type = BUS_MATCH_LEAF;
612 n->next = where->child;
616 n->leaf.callback = callback;
617 callback->match_node = n;
624 static int bus_match_find_leaf(
625 struct bus_match_node *where,
626 sd_bus_message_handler_t callback,
628 struct bus_match_node **ret) {
630 struct bus_match_node *c;
633 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
636 for (c = where->child; c; c = c->next) {
639 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
641 if (c->type == BUS_MATCH_LEAF &&
642 c->leaf.callback->callback == callback &&
643 s->userdata == userdata) {
652 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
655 if (n == 4 && startswith(k, "type"))
656 return BUS_MATCH_MESSAGE_TYPE;
657 if (n == 6 && startswith(k, "sender"))
658 return BUS_MATCH_SENDER;
659 if (n == 11 && startswith(k, "destination"))
660 return BUS_MATCH_DESTINATION;
661 if (n == 9 && startswith(k, "interface"))
662 return BUS_MATCH_INTERFACE;
663 if (n == 6 && startswith(k, "member"))
664 return BUS_MATCH_MEMBER;
665 if (n == 4 && startswith(k, "path"))
666 return BUS_MATCH_PATH;
667 if (n == 14 && startswith(k, "path_namespace"))
668 return BUS_MATCH_PATH_NAMESPACE;
670 if (n == 4 && startswith(k, "arg")) {
677 return BUS_MATCH_ARG + j;
680 if (n == 5 && startswith(k, "arg")) {
682 enum bus_match_node_type t;
689 t = BUS_MATCH_ARG + a * 10 + b;
690 if (t > BUS_MATCH_ARG_LAST)
696 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
703 return BUS_MATCH_ARG_PATH + j;
706 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
707 enum bus_match_node_type t;
715 t = BUS_MATCH_ARG_PATH + a * 10 + b;
716 if (t > BUS_MATCH_ARG_PATH_LAST)
722 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
729 return BUS_MATCH_ARG_NAMESPACE + j;
732 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
733 enum bus_match_node_type t;
741 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
742 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
748 if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
755 return BUS_MATCH_ARG_HAS + j;
758 if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
759 enum bus_match_node_type t;
767 t = BUS_MATCH_ARG_HAS + a * 10 + b;
768 if (t > BUS_MATCH_ARG_HAS_LAST)
777 static int match_component_compare(const void *a, const void *b) {
778 const struct bus_match_component *x = a, *y = b;
780 if (x->type < y->type)
782 if (x->type > y->type)
788 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
791 for (i = 0; i < n_components; i++)
792 free(components[i].value_str);
799 struct bus_match_component **_components,
800 unsigned *_n_components) {
802 const char *p = match;
803 struct bus_match_component *components = NULL;
804 size_t components_allocated = 0;
805 unsigned n_components = 0, i;
806 _cleanup_free_ char *value = NULL;
811 assert(_n_components);
815 enum bus_match_node_type t;
817 size_t value_allocated = 0;
818 bool escaped = false, quoted;
821 /* Avahi's match rules appear to include whitespace, skip over it */
828 t = bus_match_node_type_from_string(p, eq - p);
832 quoted = eq[1] == '\'';
834 for (q = eq + 1 + quoted;; q++) {
870 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
887 if (t == BUS_MATCH_MESSAGE_TYPE) {
888 r = bus_message_type_from_string(value, &u);
892 value = mfree(value);
896 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
901 components[n_components].type = t;
902 components[n_components].value_str = value;
903 components[n_components].value_u8 = u;
911 if (q[quoted] != ',') {
919 /* Order the whole thing, so that we always generate the same tree */
920 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
922 /* Check for duplicates */
923 for (i = 0; i+1 < n_components; i++)
924 if (components[i].type == components[i+1].type) {
929 *_components = components;
930 *_n_components = n_components;
935 bus_match_parse_free(components, n_components);
939 #if 0 /// UNNEEDED by elogind
940 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
941 _cleanup_fclose_ FILE *f = NULL;
947 if (n_components <= 0)
952 f = open_memstream(&buffer, &size);
956 for (i = 0; i < n_components; i++) {
962 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
966 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
967 fputs(bus_message_type_to_string(components[i].value_u8), f);
969 fputs(components[i].value_str, f);
974 r = fflush_and_check(f);
983 struct bus_match_node *root,
984 struct bus_match_component *components,
985 unsigned n_components,
986 struct match_callback *callback) {
989 struct bus_match_node *n;
996 for (i = 0; i < n_components; i++) {
997 r = bus_match_add_compare_value(
998 n, components[i].type,
999 components[i].value_u8, components[i].value_str, &n);
1004 return bus_match_add_leaf(n, callback);
1007 int bus_match_remove(
1008 struct bus_match_node *root,
1009 struct match_callback *callback) {
1011 struct bus_match_node *node, *pp;
1016 node = callback->match_node;
1020 assert(node->type == BUS_MATCH_LEAF);
1022 callback->match_node = NULL;
1026 bus_match_node_free(node);
1028 /* Prune the tree above */
1033 if (!bus_match_node_maybe_free(node))
1041 struct bus_match_node *root,
1042 struct bus_match_component *components,
1043 unsigned n_components,
1044 sd_bus_message_handler_t callback,
1046 struct match_callback **ret) {
1048 struct bus_match_node *n, **gc;
1055 gc = newa(struct bus_match_node*, n_components);
1058 for (i = 0; i < n_components; i++) {
1059 r = bus_match_find_compare_value(
1060 n, components[i].type,
1061 components[i].value_u8, components[i].value_str,
1069 r = bus_match_find_leaf(n, callback, userdata, &n);
1073 *ret = n->leaf.callback;
1077 void bus_match_free(struct bus_match_node *node) {
1078 struct bus_match_node *c;
1083 if (BUS_MATCH_CAN_HASH(node->type)) {
1086 HASHMAP_FOREACH(c, node->compare.children, i)
1089 assert(hashmap_isempty(node->compare.children));
1092 while ((c = node->child))
1095 if (node->type != BUS_MATCH_ROOT)
1096 bus_match_node_free(node);
1099 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1102 case BUS_MATCH_ROOT:
1105 case BUS_MATCH_VALUE:
1108 case BUS_MATCH_LEAF:
1111 case BUS_MATCH_MESSAGE_TYPE:
1114 case BUS_MATCH_SENDER:
1117 case BUS_MATCH_DESTINATION:
1118 return "destination";
1120 case BUS_MATCH_INTERFACE:
1123 case BUS_MATCH_MEMBER:
1126 case BUS_MATCH_PATH:
1129 case BUS_MATCH_PATH_NAMESPACE:
1130 return "path_namespace";
1132 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1133 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1136 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1137 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1140 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1141 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1144 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1145 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1153 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1154 struct bus_match_node *c;
1155 _cleanup_free_ char *pfx = NULL;
1161 pfx = strrep(" ", level);
1162 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1164 if (node->type == BUS_MATCH_VALUE) {
1165 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1166 printf(" <%u>\n", node->value.u8);
1168 printf(" <%s>\n", node->value.str);
1169 } else if (node->type == BUS_MATCH_ROOT)
1171 else if (node->type == BUS_MATCH_LEAF)
1172 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1176 if (BUS_MATCH_CAN_HASH(node->type)) {
1179 HASHMAP_FOREACH(c, node->compare.children, i)
1180 bus_match_dump(c, level + 1);
1183 for (c = node->child; c; c = c->next)
1184 bus_match_dump(c, level + 1);
1187 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1188 bool found_driver = false;
1191 if (n_components <= 0)
1192 return BUS_MATCH_GENERIC;
1196 /* Checks whether the specified match can only match the
1197 * pseudo-service for local messages, which we detect by
1198 * sender, interface or path. If a match is not restricted to
1199 * local messages, then we check if it only matches on the
1202 for (i = 0; i < n_components; i++) {
1203 const struct bus_match_component *c = components + i;
1205 if (c->type == BUS_MATCH_SENDER) {
1206 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1207 return BUS_MATCH_LOCAL;
1209 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1210 found_driver = true;
1213 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1214 return BUS_MATCH_LOCAL;
1216 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1217 return BUS_MATCH_LOCAL;
1220 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;