2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "bus-internal.h"
22 #include "bus-match.h"
23 #include "bus-message.h"
27 #include "hexdecoct.h"
28 #include "string-util.h"
33 * A: type=signal,sender=foo,interface=bar
34 * B: type=signal,sender=quux,interface=fips
35 * C: type=signal,sender=quux,interface=waldo
36 * D: type=signal,member=test
41 * results in this tree:
44 * + BUS_MATCH_MESSAGE_TYPE
45 * | ` BUS_MATCH_VALUE: value == signal
46 * | + DBUS_MATCH_SENDER
47 * | | + BUS_MATCH_VALUE: value == foo
48 * | | | ` DBUS_MATCH_INTERFACE
49 * | | | ` BUS_MATCH_VALUE: value == bar
50 * | | | ` BUS_MATCH_LEAF: A
51 * | | ` BUS_MATCH_VALUE: value == quux
52 * | | ` DBUS_MATCH_INTERFACE
53 * | | | BUS_MATCH_VALUE: value == fips
54 * | | | ` BUS_MATCH_LEAF: B
55 * | | ` BUS_MATCH_VALUE: value == waldo
56 * | | ` BUS_MATCH_LEAF: C
57 * | + DBUS_MATCH_MEMBER
58 * | | ` BUS_MATCH_VALUE: value == test
59 * | | ` BUS_MATCH_LEAF: D
60 * | + BUS_MATCH_LEAF: F
61 * | ` BUS_MATCH_LEAF: G
63 * ` BUS_MATCH_VALUE: value == miau
67 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
68 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
71 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
72 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
73 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
74 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
77 static void bus_match_node_free(struct bus_match_node *node) {
81 assert(node->type != BUS_MATCH_ROOT);
82 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
84 if (node->parent->child) {
85 /* We are apparently linked into the parent's child
86 * list. Let's remove us from there. */
88 assert(node->prev->next == node);
89 node->prev->next = node->next;
91 assert(node->parent->child == node);
92 node->parent->child = node->next;
96 node->next->prev = node->prev;
99 if (node->type == BUS_MATCH_VALUE) {
100 /* We might be in the parent's hash table, so clean
103 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
104 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
105 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
106 hashmap_remove(node->parent->compare.children, node->value.str);
108 free(node->value.str);
111 if (BUS_MATCH_IS_COMPARE(node->type)) {
112 assert(hashmap_isempty(node->compare.children));
113 hashmap_free(node->compare.children);
119 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
122 if (node->type == BUS_MATCH_ROOT)
128 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
131 bus_match_node_free(node);
135 static bool value_node_test(
136 struct bus_match_node *node,
137 enum bus_match_node_type parent_type,
139 const char *value_str,
144 assert(node->type == BUS_MATCH_VALUE);
146 /* Tests parameters against this value node, doing prefix
147 * magic and stuff. */
149 switch (parent_type) {
151 case BUS_MATCH_MESSAGE_TYPE:
152 return node->value.u8 == value_u8;
154 case BUS_MATCH_SENDER:
155 if (streq_ptr(node->value.str, value_str))
158 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
161 /* on kdbus we have the well known names list
162 * in the credentials, let's make use of that
163 * for an accurate match */
165 STRV_FOREACH(i, m->creds.well_known_names)
166 if (streq_ptr(node->value.str, *i))
171 /* If we don't have kdbus, we don't know the
172 * well-known names of the senders. In that,
173 * let's just hope that dbus-daemon doesn't
174 * send us stuff we didn't want. */
176 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
182 case BUS_MATCH_DESTINATION:
183 case BUS_MATCH_INTERFACE:
184 case BUS_MATCH_MEMBER:
186 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
189 return streq_ptr(node->value.str, value_str);
193 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
196 STRV_FOREACH(i, value_strv)
197 if (streq_ptr(node->value.str, *i))
203 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
205 return namespace_simple_pattern(node->value.str, value_str);
209 case BUS_MATCH_PATH_NAMESPACE:
210 return path_simple_pattern(node->value.str, value_str);
212 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
214 return path_complex_pattern(node->value.str, value_str);
219 assert_not_reached("Invalid node type");
223 static bool value_node_same(
224 struct bus_match_node *node,
225 enum bus_match_node_type parent_type,
227 const char *value_str) {
229 /* Tests parameters against this value node, not doing prefix
230 * magic and stuff, i.e. this one actually compares the match
234 assert(node->type == BUS_MATCH_VALUE);
236 switch (parent_type) {
238 case BUS_MATCH_MESSAGE_TYPE:
239 return node->value.u8 == value_u8;
241 case BUS_MATCH_SENDER:
242 case BUS_MATCH_DESTINATION:
243 case BUS_MATCH_INTERFACE:
244 case BUS_MATCH_MEMBER:
246 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
247 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
248 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
249 case BUS_MATCH_PATH_NAMESPACE:
250 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
251 return streq(node->value.str, value_str);
254 assert_not_reached("Invalid node type");
260 struct bus_match_node *node,
263 _cleanup_strv_free_ char **test_strv = NULL;
264 const char *test_str = NULL;
273 if (bus && bus->match_callbacks_modified)
276 /* Not these special semantics: when traversing the tree we
277 * usually let bus_match_run() when called for a node
278 * recursively invoke bus_match_run(). There's are two
279 * exceptions here though, which are BUS_NODE_ROOT (which
280 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
281 * are invoked anyway by its parent. */
283 switch (node->type) {
287 /* Run all children. Since we cannot have any siblings
288 * we won't call any. The children of the root node
289 * are compares or leaves, they will automatically
290 * call their siblings. */
291 return bus_match_run(bus, node->child, m);
293 case BUS_MATCH_VALUE:
295 /* Run all children. We don't execute any siblings, we
296 * assume our caller does that. The children of value
297 * nodes are compares or leaves, they will
298 * automatically call their siblings */
301 return bus_match_run(bus, node->child, m);
306 if (node->leaf.callback->last_iteration == bus->iteration_counter)
309 node->leaf.callback->last_iteration = bus->iteration_counter;
312 r = sd_bus_message_rewind(m, true);
316 /* Run the callback. And then invoke siblings. */
317 if (node->leaf.callback->callback) {
318 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
321 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
323 bus->current_slot = sd_bus_slot_ref(slot);
324 bus->current_handler = node->leaf.callback->callback;
325 bus->current_userdata = slot->userdata;
327 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
329 bus->current_userdata = NULL;
330 bus->current_handler = NULL;
331 bus->current_slot = sd_bus_slot_unref(slot);
334 r = bus_maybe_reply_error(m, r, &error_buffer);
338 if (bus && bus->match_callbacks_modified)
342 return bus_match_run(bus, node->next, m);
344 case BUS_MATCH_MESSAGE_TYPE:
345 test_u8 = m->header->type;
348 case BUS_MATCH_SENDER:
349 test_str = m->sender;
350 /* FIXME: resolve test_str from a well-known to a unique name first */
353 case BUS_MATCH_DESTINATION:
354 test_str = m->destination;
357 case BUS_MATCH_INTERFACE:
358 test_str = m->interface;
361 case BUS_MATCH_MEMBER:
362 test_str = m->member;
366 case BUS_MATCH_PATH_NAMESPACE:
370 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
371 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
374 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
375 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
378 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
379 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
382 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
383 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &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);
433 if (bus && bus->match_callbacks_modified)
438 if (bus && bus->match_callbacks_modified)
441 /* And now, let's invoke our siblings */
442 return bus_match_run(bus, node->next, m);
445 static int bus_match_add_compare_value(
446 struct bus_match_node *where,
447 enum bus_match_node_type t,
449 const char *value_str,
450 struct bus_match_node **ret) {
452 struct bus_match_node *c = NULL, *n = NULL;
456 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
457 assert(BUS_MATCH_IS_COMPARE(t));
460 for (c = where->child; c && c->type != t; c = c->next)
464 /* Comparison node already exists? Then let's see if
465 * the value node exists too. */
467 if (t == BUS_MATCH_MESSAGE_TYPE)
468 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
469 else if (BUS_MATCH_CAN_HASH(t))
470 n = hashmap_get(c->compare.children, value_str);
472 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
481 /* Comparison node, doesn't exist yet? Then let's
484 c = new0(struct bus_match_node, 1);
492 c->next = where->child;
497 if (t == BUS_MATCH_MESSAGE_TYPE) {
498 c->compare.children = hashmap_new(NULL);
499 if (!c->compare.children) {
503 } else if (BUS_MATCH_CAN_HASH(t)) {
504 c->compare.children = hashmap_new(&string_hash_ops);
505 if (!c->compare.children) {
512 n = new0(struct bus_match_node, 1);
518 n->type = BUS_MATCH_VALUE;
519 n->value.u8 = value_u8;
521 n->value.str = strdup(value_str);
529 if (c->compare.children) {
531 if (t == BUS_MATCH_MESSAGE_TYPE)
532 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
534 r = hashmap_put(c->compare.children, n->value.str, n);
550 bus_match_node_maybe_free(c);
560 static int bus_match_find_compare_value(
561 struct bus_match_node *where,
562 enum bus_match_node_type t,
564 const char *value_str,
565 struct bus_match_node **ret) {
567 struct bus_match_node *c, *n;
570 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
571 assert(BUS_MATCH_IS_COMPARE(t));
574 for (c = where->child; c && c->type != t; c = c->next)
580 if (t == BUS_MATCH_MESSAGE_TYPE)
581 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
582 else if (BUS_MATCH_CAN_HASH(t))
583 n = hashmap_get(c->compare.children, value_str);
585 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
597 static int bus_match_add_leaf(
598 struct bus_match_node *where,
599 struct match_callback *callback) {
601 struct bus_match_node *n;
604 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
607 n = new0(struct bus_match_node, 1);
611 n->type = BUS_MATCH_LEAF;
613 n->next = where->child;
617 n->leaf.callback = callback;
618 callback->match_node = n;
625 static int bus_match_find_leaf(
626 struct bus_match_node *where,
627 sd_bus_message_handler_t callback,
629 struct bus_match_node **ret) {
631 struct bus_match_node *c;
634 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
637 for (c = where->child; c; c = c->next) {
640 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
642 if (c->type == BUS_MATCH_LEAF &&
643 c->leaf.callback->callback == callback &&
644 s->userdata == userdata) {
653 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
656 if (n == 4 && startswith(k, "type"))
657 return BUS_MATCH_MESSAGE_TYPE;
658 if (n == 6 && startswith(k, "sender"))
659 return BUS_MATCH_SENDER;
660 if (n == 11 && startswith(k, "destination"))
661 return BUS_MATCH_DESTINATION;
662 if (n == 9 && startswith(k, "interface"))
663 return BUS_MATCH_INTERFACE;
664 if (n == 6 && startswith(k, "member"))
665 return BUS_MATCH_MEMBER;
666 if (n == 4 && startswith(k, "path"))
667 return BUS_MATCH_PATH;
668 if (n == 14 && startswith(k, "path_namespace"))
669 return BUS_MATCH_PATH_NAMESPACE;
671 if (n == 4 && startswith(k, "arg")) {
678 return BUS_MATCH_ARG + j;
681 if (n == 5 && startswith(k, "arg")) {
683 enum bus_match_node_type t;
690 t = BUS_MATCH_ARG + a * 10 + b;
691 if (t > BUS_MATCH_ARG_LAST)
697 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
704 return BUS_MATCH_ARG_PATH + j;
707 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
708 enum bus_match_node_type t;
716 t = BUS_MATCH_ARG_PATH + a * 10 + b;
717 if (t > BUS_MATCH_ARG_PATH_LAST)
723 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
730 return BUS_MATCH_ARG_NAMESPACE + j;
733 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
734 enum bus_match_node_type t;
742 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
743 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
749 if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
756 return BUS_MATCH_ARG_HAS + j;
759 if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
760 enum bus_match_node_type t;
768 t = BUS_MATCH_ARG_HAS + a * 10 + b;
769 if (t > BUS_MATCH_ARG_HAS_LAST)
778 static int match_component_compare(const void *a, const void *b) {
779 const struct bus_match_component *x = a, *y = b;
781 if (x->type < y->type)
783 if (x->type > y->type)
789 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
792 for (i = 0; i < n_components; i++)
793 free(components[i].value_str);
800 struct bus_match_component **_components,
801 unsigned *_n_components) {
803 const char *p = match;
804 struct bus_match_component *components = NULL;
805 size_t components_allocated = 0;
806 unsigned n_components = 0, i;
807 _cleanup_free_ char *value = NULL;
812 assert(_n_components);
816 enum bus_match_node_type t;
818 size_t value_allocated = 0;
819 bool escaped = false, quoted;
822 /* Avahi's match rules appear to include whitespace, skip over it */
829 t = bus_match_node_type_from_string(p, eq - p);
833 quoted = eq[1] == '\'';
835 for (q = eq + 1 + quoted;; q++) {
871 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
888 if (t == BUS_MATCH_MESSAGE_TYPE) {
889 r = bus_message_type_from_string(value, &u);
893 value = mfree(value);
897 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
902 components[n_components].type = t;
903 components[n_components].value_str = value;
904 components[n_components].value_u8 = u;
912 if (q[quoted] != ',') {
920 /* Order the whole thing, so that we always generate the same tree */
921 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
923 /* Check for duplicates */
924 for (i = 0; i+1 < n_components; i++)
925 if (components[i].type == components[i+1].type) {
930 *_components = components;
931 *_n_components = n_components;
936 bus_match_parse_free(components, n_components);
940 #if 0 /// UNNEEDED by elogind
941 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
942 _cleanup_fclose_ FILE *f = NULL;
948 if (n_components <= 0)
953 f = open_memstream(&buffer, &size);
957 for (i = 0; i < n_components; i++) {
963 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
967 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
968 fputs(bus_message_type_to_string(components[i].value_u8), f);
970 fputs(components[i].value_str, f);
975 r = fflush_and_check(f);
984 struct bus_match_node *root,
985 struct bus_match_component *components,
986 unsigned n_components,
987 struct match_callback *callback) {
990 struct bus_match_node *n;
997 for (i = 0; i < n_components; i++) {
998 r = bus_match_add_compare_value(
999 n, components[i].type,
1000 components[i].value_u8, components[i].value_str, &n);
1005 return bus_match_add_leaf(n, callback);
1008 int bus_match_remove(
1009 struct bus_match_node *root,
1010 struct match_callback *callback) {
1012 struct bus_match_node *node, *pp;
1017 node = callback->match_node;
1021 assert(node->type == BUS_MATCH_LEAF);
1023 callback->match_node = NULL;
1027 bus_match_node_free(node);
1029 /* Prune the tree above */
1034 if (!bus_match_node_maybe_free(node))
1042 struct bus_match_node *root,
1043 struct bus_match_component *components,
1044 unsigned n_components,
1045 sd_bus_message_handler_t callback,
1047 struct match_callback **ret) {
1049 struct bus_match_node *n, **gc;
1056 gc = newa(struct bus_match_node*, n_components);
1059 for (i = 0; i < n_components; i++) {
1060 r = bus_match_find_compare_value(
1061 n, components[i].type,
1062 components[i].value_u8, components[i].value_str,
1070 r = bus_match_find_leaf(n, callback, userdata, &n);
1074 *ret = n->leaf.callback;
1078 void bus_match_free(struct bus_match_node *node) {
1079 struct bus_match_node *c;
1084 if (BUS_MATCH_CAN_HASH(node->type)) {
1087 HASHMAP_FOREACH(c, node->compare.children, i)
1090 assert(hashmap_isempty(node->compare.children));
1093 while ((c = node->child))
1096 if (node->type != BUS_MATCH_ROOT)
1097 bus_match_node_free(node);
1100 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1103 case BUS_MATCH_ROOT:
1106 case BUS_MATCH_VALUE:
1109 case BUS_MATCH_LEAF:
1112 case BUS_MATCH_MESSAGE_TYPE:
1115 case BUS_MATCH_SENDER:
1118 case BUS_MATCH_DESTINATION:
1119 return "destination";
1121 case BUS_MATCH_INTERFACE:
1124 case BUS_MATCH_MEMBER:
1127 case BUS_MATCH_PATH:
1130 case BUS_MATCH_PATH_NAMESPACE:
1131 return "path_namespace";
1133 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1134 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1137 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1138 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1141 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1142 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1145 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1146 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1154 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1155 struct bus_match_node *c;
1156 _cleanup_free_ char *pfx = NULL;
1162 pfx = strrep(" ", level);
1163 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1165 if (node->type == BUS_MATCH_VALUE) {
1166 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1167 printf(" <%u>\n", node->value.u8);
1169 printf(" <%s>\n", node->value.str);
1170 } else if (node->type == BUS_MATCH_ROOT)
1172 else if (node->type == BUS_MATCH_LEAF)
1173 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1177 if (BUS_MATCH_CAN_HASH(node->type)) {
1180 HASHMAP_FOREACH(c, node->compare.children, i)
1181 bus_match_dump(c, level + 1);
1184 for (c = node->child; c; c = c->next)
1185 bus_match_dump(c, level + 1);
1188 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1189 bool found_driver = false;
1192 if (n_components <= 0)
1193 return BUS_MATCH_GENERIC;
1197 /* Checks whether the specified match can only match the
1198 * pseudo-service for local messages, which we detect by
1199 * sender, interface or path. If a match is not restricted to
1200 * local messages, then we check if it only matches on the
1203 for (i = 0; i < n_components; i++) {
1204 const struct bus_match_component *c = components + i;
1206 if (c->type == BUS_MATCH_SENDER) {
1207 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1208 return BUS_MATCH_LOCAL;
1210 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1211 found_driver = true;
1214 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1215 return BUS_MATCH_LOCAL;
1217 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1218 return BUS_MATCH_LOCAL;
1221 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;