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_HAS_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) ||
71 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_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,
141 assert(node->type == BUS_MATCH_VALUE);
143 /* Tests parameters against this value node, doing prefix
144 * magic and stuff. */
146 switch (parent_type) {
148 case BUS_MATCH_MESSAGE_TYPE:
149 return node->value.u8 == value_u8;
151 case BUS_MATCH_SENDER:
152 if (streq_ptr(node->value.str, value_str))
155 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
158 /* on kdbus we have the well known names list
159 * in the credentials, let's make use of that
160 * for an accurate match */
162 STRV_FOREACH(i, m->creds.well_known_names)
163 if (streq_ptr(node->value.str, *i))
168 /* If we don't have kdbus, we don't know the
169 * well-known names of the senders. In that,
170 * let's just hope that dbus-daemon doesn't
171 * send us stuff we didn't want. */
173 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
179 case BUS_MATCH_DESTINATION:
180 case BUS_MATCH_INTERFACE:
181 case BUS_MATCH_MEMBER:
183 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
186 return streq_ptr(node->value.str, value_str);
190 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
193 STRV_FOREACH(i, value_strv)
194 if (streq_ptr(node->value.str, *i))
200 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
202 return namespace_simple_pattern(node->value.str, value_str);
206 case BUS_MATCH_PATH_NAMESPACE:
207 return path_simple_pattern(node->value.str, value_str);
209 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
211 return path_complex_pattern(node->value.str, value_str);
216 assert_not_reached("Invalid node type");
220 static bool value_node_same(
221 struct bus_match_node *node,
222 enum bus_match_node_type parent_type,
224 const char *value_str) {
226 /* Tests parameters against this value node, not doing prefix
227 * magic and stuff, i.e. this one actually compares the match
231 assert(node->type == BUS_MATCH_VALUE);
233 switch (parent_type) {
235 case BUS_MATCH_MESSAGE_TYPE:
236 return node->value.u8 == value_u8;
238 case BUS_MATCH_SENDER:
239 case BUS_MATCH_DESTINATION:
240 case BUS_MATCH_INTERFACE:
241 case BUS_MATCH_MEMBER:
243 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
244 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
245 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
246 case BUS_MATCH_PATH_NAMESPACE:
247 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
248 return streq(node->value.str, value_str);
251 assert_not_reached("Invalid node type");
257 struct bus_match_node *node,
260 _cleanup_strv_free_ char **test_strv = NULL;
261 const char *test_str = NULL;
270 if (bus && bus->match_callbacks_modified)
273 /* Not these special semantics: when traversing the tree we
274 * usually let bus_match_run() when called for a node
275 * recursively invoke bus_match_run(). There's are two
276 * exceptions here though, which are BUS_NODE_ROOT (which
277 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
278 * are invoked anyway by its parent. */
280 switch (node->type) {
284 /* Run all children. Since we cannot have any siblings
285 * we won't call any. The children of the root node
286 * are compares or leaves, they will automatically
287 * call their siblings. */
288 return bus_match_run(bus, node->child, m);
290 case BUS_MATCH_VALUE:
292 /* Run all children. We don't execute any siblings, we
293 * assume our caller does that. The children of value
294 * nodes are compares or leaves, they will
295 * automatically call their siblings */
298 return bus_match_run(bus, node->child, m);
303 if (node->leaf.callback->last_iteration == bus->iteration_counter)
306 node->leaf.callback->last_iteration = bus->iteration_counter;
309 r = sd_bus_message_rewind(m, true);
313 /* Run the callback. And then invoke siblings. */
314 if (node->leaf.callback->callback) {
315 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
318 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
320 bus->current_slot = sd_bus_slot_ref(slot);
321 bus->current_handler = node->leaf.callback->callback;
322 bus->current_userdata = slot->userdata;
324 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
326 bus->current_userdata = NULL;
327 bus->current_handler = NULL;
328 bus->current_slot = sd_bus_slot_unref(slot);
331 r = bus_maybe_reply_error(m, r, &error_buffer);
335 if (bus && bus->match_callbacks_modified)
339 return bus_match_run(bus, node->next, m);
341 case BUS_MATCH_MESSAGE_TYPE:
342 test_u8 = m->header->type;
345 case BUS_MATCH_SENDER:
346 test_str = m->sender;
347 /* FIXME: resolve test_str from a well-known to a unique name first */
350 case BUS_MATCH_DESTINATION:
351 test_str = m->destination;
354 case BUS_MATCH_INTERFACE:
355 test_str = m->interface;
358 case BUS_MATCH_MEMBER:
359 test_str = m->member;
363 case BUS_MATCH_PATH_NAMESPACE:
367 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
368 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
371 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
372 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
375 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
376 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
379 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
380 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
384 assert_not_reached("Unknown match type.");
387 if (BUS_MATCH_CAN_HASH(node->type)) {
388 struct bus_match_node *found;
390 /* Lookup via hash table, nice! So let's jump directly. */
393 found = hashmap_get(node->compare.children, test_str);
394 else if (test_strv) {
397 STRV_FOREACH(i, test_strv) {
398 found = hashmap_get(node->compare.children, *i);
400 r = bus_match_run(bus, found, m);
407 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
408 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
413 r = bus_match_run(bus, found, m);
418 struct bus_match_node *c;
420 /* No hash table, so let's iterate manually... */
422 for (c = node->child; c; c = c->next) {
423 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
426 r = bus_match_run(bus, c, m);
432 if (bus && bus->match_callbacks_modified)
435 /* And now, let's invoke our siblings */
436 return bus_match_run(bus, node->next, m);
439 static int bus_match_add_compare_value(
440 struct bus_match_node *where,
441 enum bus_match_node_type t,
443 const char *value_str,
444 struct bus_match_node **ret) {
446 struct bus_match_node *c = NULL, *n = NULL;
450 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
451 assert(BUS_MATCH_IS_COMPARE(t));
454 for (c = where->child; c && c->type != t; c = c->next)
458 /* Comparison node already exists? Then let's see if
459 * the value node exists too. */
461 if (t == BUS_MATCH_MESSAGE_TYPE)
462 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
463 else if (BUS_MATCH_CAN_HASH(t))
464 n = hashmap_get(c->compare.children, value_str);
466 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
475 /* Comparison node, doesn't exist yet? Then let's
478 c = new0(struct bus_match_node, 1);
486 c->next = where->child;
491 if (t == BUS_MATCH_MESSAGE_TYPE) {
492 c->compare.children = hashmap_new(NULL);
493 if (!c->compare.children) {
497 } else if (BUS_MATCH_CAN_HASH(t)) {
498 c->compare.children = hashmap_new(&string_hash_ops);
499 if (!c->compare.children) {
506 n = new0(struct bus_match_node, 1);
512 n->type = BUS_MATCH_VALUE;
513 n->value.u8 = value_u8;
515 n->value.str = strdup(value_str);
523 if (c->compare.children) {
525 if (t == BUS_MATCH_MESSAGE_TYPE)
526 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
528 r = hashmap_put(c->compare.children, n->value.str, n);
544 bus_match_node_maybe_free(c);
554 static int bus_match_find_compare_value(
555 struct bus_match_node *where,
556 enum bus_match_node_type t,
558 const char *value_str,
559 struct bus_match_node **ret) {
561 struct bus_match_node *c, *n;
564 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
565 assert(BUS_MATCH_IS_COMPARE(t));
568 for (c = where->child; c && c->type != t; c = c->next)
574 if (t == BUS_MATCH_MESSAGE_TYPE)
575 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
576 else if (BUS_MATCH_CAN_HASH(t))
577 n = hashmap_get(c->compare.children, value_str);
579 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
591 static int bus_match_add_leaf(
592 struct bus_match_node *where,
593 struct match_callback *callback) {
595 struct bus_match_node *n;
598 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
601 n = new0(struct bus_match_node, 1);
605 n->type = BUS_MATCH_LEAF;
607 n->next = where->child;
611 n->leaf.callback = callback;
612 callback->match_node = n;
619 static int bus_match_find_leaf(
620 struct bus_match_node *where,
621 sd_bus_message_handler_t callback,
623 struct bus_match_node **ret) {
625 struct bus_match_node *c;
628 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
631 for (c = where->child; c; c = c->next) {
634 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
636 if (c->type == BUS_MATCH_LEAF &&
637 c->leaf.callback->callback == callback &&
638 s->userdata == userdata) {
647 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
650 if (n == 4 && startswith(k, "type"))
651 return BUS_MATCH_MESSAGE_TYPE;
652 if (n == 6 && startswith(k, "sender"))
653 return BUS_MATCH_SENDER;
654 if (n == 11 && startswith(k, "destination"))
655 return BUS_MATCH_DESTINATION;
656 if (n == 9 && startswith(k, "interface"))
657 return BUS_MATCH_INTERFACE;
658 if (n == 6 && startswith(k, "member"))
659 return BUS_MATCH_MEMBER;
660 if (n == 4 && startswith(k, "path"))
661 return BUS_MATCH_PATH;
662 if (n == 14 && startswith(k, "path_namespace"))
663 return BUS_MATCH_PATH_NAMESPACE;
665 if (n == 4 && startswith(k, "arg")) {
672 return BUS_MATCH_ARG + j;
675 if (n == 5 && startswith(k, "arg")) {
677 enum bus_match_node_type t;
684 t = BUS_MATCH_ARG + a * 10 + b;
685 if (t > BUS_MATCH_ARG_LAST)
691 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
698 return BUS_MATCH_ARG_PATH + j;
701 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
702 enum bus_match_node_type t;
710 t = BUS_MATCH_ARG_PATH + a * 10 + b;
711 if (t > BUS_MATCH_ARG_PATH_LAST)
717 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
724 return BUS_MATCH_ARG_NAMESPACE + j;
727 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
728 enum bus_match_node_type t;
736 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
737 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
743 if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
750 return BUS_MATCH_ARG_HAS + j;
753 if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
754 enum bus_match_node_type t;
762 t = BUS_MATCH_ARG_HAS + a * 10 + b;
763 if (t > BUS_MATCH_ARG_HAS_LAST)
772 static int match_component_compare(const void *a, const void *b) {
773 const struct bus_match_component *x = a, *y = b;
775 if (x->type < y->type)
777 if (x->type > y->type)
783 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
786 for (i = 0; i < n_components; i++)
787 free(components[i].value_str);
794 struct bus_match_component **_components,
795 unsigned *_n_components) {
797 const char *p = match;
798 struct bus_match_component *components = NULL;
799 size_t components_allocated = 0;
800 unsigned n_components = 0, i;
801 _cleanup_free_ char *value = NULL;
806 assert(_n_components);
810 enum bus_match_node_type t;
812 size_t value_allocated = 0;
813 bool escaped = false, quoted;
816 /* Avahi's match rules appear to include whitespace, skip over it */
823 t = bus_match_node_type_from_string(p, eq - p);
827 quoted = eq[1] == '\'';
829 for (q = eq + 1 + quoted;; q++) {
865 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
882 if (t == BUS_MATCH_MESSAGE_TYPE) {
883 r = bus_message_type_from_string(value, &u);
887 value = mfree(value);
891 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
896 components[n_components].type = t;
897 components[n_components].value_str = value;
898 components[n_components].value_u8 = u;
906 if (q[quoted] != ',') {
914 /* Order the whole thing, so that we always generate the same tree */
915 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
917 /* Check for duplicates */
918 for (i = 0; i+1 < n_components; i++)
919 if (components[i].type == components[i+1].type) {
924 *_components = components;
925 *_n_components = n_components;
930 bus_match_parse_free(components, n_components);
934 /// UNNEEDED by elogind
936 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
937 _cleanup_fclose_ FILE *f = NULL;
943 if (n_components <= 0)
948 f = open_memstream(&buffer, &size);
952 for (i = 0; i < n_components; i++) {
958 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
962 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
963 fputs(bus_message_type_to_string(components[i].value_u8), f);
965 fputs(components[i].value_str, f);
970 r = fflush_and_check(f);
979 struct bus_match_node *root,
980 struct bus_match_component *components,
981 unsigned n_components,
982 struct match_callback *callback) {
985 struct bus_match_node *n;
992 for (i = 0; i < n_components; i++) {
993 r = bus_match_add_compare_value(
994 n, components[i].type,
995 components[i].value_u8, components[i].value_str, &n);
1000 return bus_match_add_leaf(n, callback);
1003 int bus_match_remove(
1004 struct bus_match_node *root,
1005 struct match_callback *callback) {
1007 struct bus_match_node *node, *pp;
1012 node = callback->match_node;
1016 assert(node->type == BUS_MATCH_LEAF);
1018 callback->match_node = NULL;
1022 bus_match_node_free(node);
1024 /* Prune the tree above */
1029 if (!bus_match_node_maybe_free(node))
1037 struct bus_match_node *root,
1038 struct bus_match_component *components,
1039 unsigned n_components,
1040 sd_bus_message_handler_t callback,
1042 struct match_callback **ret) {
1044 struct bus_match_node *n, **gc;
1051 gc = newa(struct bus_match_node*, n_components);
1054 for (i = 0; i < n_components; i++) {
1055 r = bus_match_find_compare_value(
1056 n, components[i].type,
1057 components[i].value_u8, components[i].value_str,
1065 r = bus_match_find_leaf(n, callback, userdata, &n);
1069 *ret = n->leaf.callback;
1073 void bus_match_free(struct bus_match_node *node) {
1074 struct bus_match_node *c;
1079 if (BUS_MATCH_CAN_HASH(node->type)) {
1082 HASHMAP_FOREACH(c, node->compare.children, i)
1085 assert(hashmap_isempty(node->compare.children));
1088 while ((c = node->child))
1091 if (node->type != BUS_MATCH_ROOT)
1092 bus_match_node_free(node);
1095 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1098 case BUS_MATCH_ROOT:
1101 case BUS_MATCH_VALUE:
1104 case BUS_MATCH_LEAF:
1107 case BUS_MATCH_MESSAGE_TYPE:
1110 case BUS_MATCH_SENDER:
1113 case BUS_MATCH_DESTINATION:
1114 return "destination";
1116 case BUS_MATCH_INTERFACE:
1119 case BUS_MATCH_MEMBER:
1122 case BUS_MATCH_PATH:
1125 case BUS_MATCH_PATH_NAMESPACE:
1126 return "path_namespace";
1128 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1129 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1132 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1133 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1136 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1137 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1140 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1141 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1149 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1150 struct bus_match_node *c;
1151 _cleanup_free_ char *pfx = NULL;
1157 pfx = strrep(" ", level);
1158 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1160 if (node->type == BUS_MATCH_VALUE) {
1161 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1162 printf(" <%u>\n", node->value.u8);
1164 printf(" <%s>\n", node->value.str);
1165 } else if (node->type == BUS_MATCH_ROOT)
1167 else if (node->type == BUS_MATCH_LEAF)
1168 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1172 if (BUS_MATCH_CAN_HASH(node->type)) {
1175 HASHMAP_FOREACH(c, node->compare.children, i)
1176 bus_match_dump(c, level + 1);
1179 for (c = node->child; c; c = c->next)
1180 bus_match_dump(c, level + 1);
1183 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1184 bool found_driver = false;
1187 if (n_components <= 0)
1188 return BUS_MATCH_GENERIC;
1192 /* Checks whether the specified match can only match the
1193 * pseudo-service for local messages, which we detect by
1194 * sender, interface or path. If a match is not restricted to
1195 * local messages, then we check if it only matches on the
1198 for (i = 0; i < n_components; i++) {
1199 const struct bus_match_component *c = components + i;
1201 if (c->type == BUS_MATCH_SENDER) {
1202 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1203 return BUS_MATCH_LOCAL;
1205 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1206 found_driver = true;
1209 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1210 return BUS_MATCH_LOCAL;
1212 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1213 return BUS_MATCH_LOCAL;
1216 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;