]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-match.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-match.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "bus-internal.h"
23 #include "bus-match.h"
24 #include "bus-message.h"
25 #include "bus-util.h"
26 #include "fd-util.h"
27 #include "fileio.h"
28 #include "hexdecoct.h"
29 #include "string-util.h"
30 #include "strv.h"
31
32 /* Example:
33 *
34 * A: type=signal,sender=foo,interface=bar
35 * B: type=signal,sender=quux,interface=fips
36 * C: type=signal,sender=quux,interface=waldo
37 * D: type=signal,member=test
38 * E: sender=miau
39 * F: type=signal
40 * G: type=signal
41 *
42 * results in this tree:
43 *
44 * BUS_MATCH_ROOT
45 * + BUS_MATCH_MESSAGE_TYPE
46 * | ` BUS_MATCH_VALUE: value == signal
47 * | + DBUS_MATCH_SENDER
48 * | | + BUS_MATCH_VALUE: value == foo
49 * | | | ` DBUS_MATCH_INTERFACE
50 * | | | ` BUS_MATCH_VALUE: value == bar
51 * | | | ` BUS_MATCH_LEAF: A
52 * | | ` BUS_MATCH_VALUE: value == quux
53 * | | ` DBUS_MATCH_INTERFACE
54 * | | | BUS_MATCH_VALUE: value == fips
55 * | | | ` BUS_MATCH_LEAF: B
56 * | | ` BUS_MATCH_VALUE: value == waldo
57 * | | ` BUS_MATCH_LEAF: C
58 * | + DBUS_MATCH_MEMBER
59 * | | ` BUS_MATCH_VALUE: value == test
60 * | | ` BUS_MATCH_LEAF: D
61 * | + BUS_MATCH_LEAF: F
62 * | ` BUS_MATCH_LEAF: G
63 * ` BUS_MATCH_SENDER
64 * ` BUS_MATCH_VALUE: value == miau
65 * ` BUS_MATCH_LEAF: E
66 */
67
68 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
69 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
70 }
71
72 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
73 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
74 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
75 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
76 }
77
78 static void bus_match_node_free(struct bus_match_node *node) {
79 assert(node);
80 assert(node->parent);
81 assert(!node->child);
82 assert(node->type != BUS_MATCH_ROOT);
83 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
84
85 if (node->parent->child) {
86 /* We are apparently linked into the parent's child
87 * list. Let's remove us from there. */
88 if (node->prev) {
89 assert(node->prev->next == node);
90 node->prev->next = node->next;
91 } else {
92 assert(node->parent->child == node);
93 node->parent->child = node->next;
94 }
95
96 if (node->next)
97 node->next->prev = node->prev;
98 }
99
100 if (node->type == BUS_MATCH_VALUE) {
101 /* We might be in the parent's hash table, so clean
102 * this up */
103
104 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
105 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
106 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
107 hashmap_remove(node->parent->compare.children, node->value.str);
108
109 free(node->value.str);
110 }
111
112 if (BUS_MATCH_IS_COMPARE(node->type)) {
113 assert(hashmap_isempty(node->compare.children));
114 hashmap_free(node->compare.children);
115 }
116
117 free(node);
118 }
119
120 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
121 assert(node);
122
123 if (node->type == BUS_MATCH_ROOT)
124 return false;
125
126 if (node->child)
127 return false;
128
129 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
130 return true;
131
132 bus_match_node_free(node);
133 return true;
134 }
135
136 static bool value_node_test(
137 struct bus_match_node *node,
138 enum bus_match_node_type parent_type,
139 uint8_t value_u8,
140 const char *value_str,
141 char **value_strv,
142 sd_bus_message *m) {
143
144 assert(node);
145 assert(node->type == BUS_MATCH_VALUE);
146
147 /* Tests parameters against this value node, doing prefix
148 * magic and stuff. */
149
150 switch (parent_type) {
151
152 case BUS_MATCH_MESSAGE_TYPE:
153 return node->value.u8 == value_u8;
154
155 case BUS_MATCH_SENDER:
156 if (streq_ptr(node->value.str, value_str))
157 return true;
158
159 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
160 char **i;
161
162 /* on kdbus we have the well known names list
163 * in the credentials, let's make use of that
164 * for an accurate match */
165
166 STRV_FOREACH(i, m->creds.well_known_names)
167 if (streq_ptr(node->value.str, *i))
168 return true;
169
170 } else {
171
172 /* If we don't have kdbus, we don't know the
173 * well-known names of the senders. In that,
174 * let's just hope that dbus-daemon doesn't
175 * send us stuff we didn't want. */
176
177 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
178 return true;
179 }
180
181 return false;
182
183 case BUS_MATCH_DESTINATION:
184 case BUS_MATCH_INTERFACE:
185 case BUS_MATCH_MEMBER:
186 case BUS_MATCH_PATH:
187 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
188
189 if (value_str)
190 return streq_ptr(node->value.str, value_str);
191
192 return false;
193
194 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
195 char **i;
196
197 STRV_FOREACH(i, value_strv)
198 if (streq_ptr(node->value.str, *i))
199 return true;
200
201 return false;
202 }
203
204 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
205 if (value_str)
206 return namespace_simple_pattern(node->value.str, value_str);
207
208 return false;
209
210 case BUS_MATCH_PATH_NAMESPACE:
211 return path_simple_pattern(node->value.str, value_str);
212
213 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
214 if (value_str)
215 return path_complex_pattern(node->value.str, value_str);
216
217 return false;
218
219 default:
220 assert_not_reached("Invalid node type");
221 }
222 }
223
224 static bool value_node_same(
225 struct bus_match_node *node,
226 enum bus_match_node_type parent_type,
227 uint8_t value_u8,
228 const char *value_str) {
229
230 /* Tests parameters against this value node, not doing prefix
231 * magic and stuff, i.e. this one actually compares the match
232 * itself. */
233
234 assert(node);
235 assert(node->type == BUS_MATCH_VALUE);
236
237 switch (parent_type) {
238
239 case BUS_MATCH_MESSAGE_TYPE:
240 return node->value.u8 == value_u8;
241
242 case BUS_MATCH_SENDER:
243 case BUS_MATCH_DESTINATION:
244 case BUS_MATCH_INTERFACE:
245 case BUS_MATCH_MEMBER:
246 case BUS_MATCH_PATH:
247 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
248 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
249 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
250 case BUS_MATCH_PATH_NAMESPACE:
251 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
252 return streq(node->value.str, value_str);
253
254 default:
255 assert_not_reached("Invalid node type");
256 }
257 }
258
259 int bus_match_run(
260 sd_bus *bus,
261 struct bus_match_node *node,
262 sd_bus_message *m) {
263
264 _cleanup_strv_free_ char **test_strv = NULL;
265 const char *test_str = NULL;
266 uint8_t test_u8 = 0;
267 int r;
268
269 assert(m);
270
271 if (!node)
272 return 0;
273
274 if (bus && bus->match_callbacks_modified)
275 return 0;
276
277 /* Not these special semantics: when traversing the tree we
278 * usually let bus_match_run() when called for a node
279 * recursively invoke bus_match_run(). There's are two
280 * exceptions here though, which are BUS_NODE_ROOT (which
281 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
282 * are invoked anyway by its parent. */
283
284 switch (node->type) {
285
286 case BUS_MATCH_ROOT:
287
288 /* Run all children. Since we cannot have any siblings
289 * we won't call any. The children of the root node
290 * are compares or leaves, they will automatically
291 * call their siblings. */
292 return bus_match_run(bus, node->child, m);
293
294 case BUS_MATCH_VALUE:
295
296 /* Run all children. We don't execute any siblings, we
297 * assume our caller does that. The children of value
298 * nodes are compares or leaves, they will
299 * automatically call their siblings */
300
301 assert(node->child);
302 return bus_match_run(bus, node->child, m);
303
304 case BUS_MATCH_LEAF:
305
306 if (bus) {
307 if (node->leaf.callback->last_iteration == bus->iteration_counter)
308 return 0;
309
310 node->leaf.callback->last_iteration = bus->iteration_counter;
311 }
312
313 r = sd_bus_message_rewind(m, true);
314 if (r < 0)
315 return r;
316
317 /* Run the callback. And then invoke siblings. */
318 if (node->leaf.callback->callback) {
319 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
320 sd_bus_slot *slot;
321
322 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
323 if (bus) {
324 bus->current_slot = sd_bus_slot_ref(slot);
325 bus->current_handler = node->leaf.callback->callback;
326 bus->current_userdata = slot->userdata;
327 }
328 r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
329 if (bus) {
330 bus->current_userdata = NULL;
331 bus->current_handler = NULL;
332 bus->current_slot = sd_bus_slot_unref(slot);
333 }
334
335 r = bus_maybe_reply_error(m, r, &error_buffer);
336 if (r != 0)
337 return r;
338
339 if (bus && bus->match_callbacks_modified)
340 return 0;
341 }
342
343 return bus_match_run(bus, node->next, m);
344
345 case BUS_MATCH_MESSAGE_TYPE:
346 test_u8 = m->header->type;
347 break;
348
349 case BUS_MATCH_SENDER:
350 test_str = m->sender;
351 /* FIXME: resolve test_str from a well-known to a unique name first */
352 break;
353
354 case BUS_MATCH_DESTINATION:
355 test_str = m->destination;
356 break;
357
358 case BUS_MATCH_INTERFACE:
359 test_str = m->interface;
360 break;
361
362 case BUS_MATCH_MEMBER:
363 test_str = m->member;
364 break;
365
366 case BUS_MATCH_PATH:
367 case BUS_MATCH_PATH_NAMESPACE:
368 test_str = m->path;
369 break;
370
371 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
372 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
373 break;
374
375 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
376 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
377 break;
378
379 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
380 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
381 break;
382
383 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
384 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv);
385 break;
386
387 default:
388 assert_not_reached("Unknown match type.");
389 }
390
391 if (BUS_MATCH_CAN_HASH(node->type)) {
392 struct bus_match_node *found;
393
394 /* Lookup via hash table, nice! So let's jump directly. */
395
396 if (test_str)
397 found = hashmap_get(node->compare.children, test_str);
398 else if (test_strv) {
399 char **i;
400
401 STRV_FOREACH(i, test_strv) {
402 found = hashmap_get(node->compare.children, *i);
403 if (found) {
404 r = bus_match_run(bus, found, m);
405 if (r != 0)
406 return r;
407 }
408 }
409
410 found = NULL;
411 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
412 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
413 else
414 found = NULL;
415
416 if (found) {
417 r = bus_match_run(bus, found, m);
418 if (r != 0)
419 return r;
420 }
421 } else {
422 struct bus_match_node *c;
423
424 /* No hash table, so let's iterate manually... */
425
426 for (c = node->child; c; c = c->next) {
427 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
428 continue;
429
430 r = bus_match_run(bus, c, m);
431 if (r != 0)
432 return r;
433
434 if (bus && bus->match_callbacks_modified)
435 return 0;
436 }
437 }
438
439 if (bus && bus->match_callbacks_modified)
440 return 0;
441
442 /* And now, let's invoke our siblings */
443 return bus_match_run(bus, node->next, m);
444 }
445
446 static int bus_match_add_compare_value(
447 struct bus_match_node *where,
448 enum bus_match_node_type t,
449 uint8_t value_u8,
450 const char *value_str,
451 struct bus_match_node **ret) {
452
453 struct bus_match_node *c = NULL, *n = NULL;
454 int r;
455
456 assert(where);
457 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
458 assert(BUS_MATCH_IS_COMPARE(t));
459 assert(ret);
460
461 for (c = where->child; c && c->type != t; c = c->next)
462 ;
463
464 if (c) {
465 /* Comparison node already exists? Then let's see if
466 * the value node exists too. */
467
468 if (t == BUS_MATCH_MESSAGE_TYPE)
469 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
470 else if (BUS_MATCH_CAN_HASH(t))
471 n = hashmap_get(c->compare.children, value_str);
472 else {
473 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
474 ;
475 }
476
477 if (n) {
478 *ret = n;
479 return 0;
480 }
481 } else {
482 /* Comparison node, doesn't exist yet? Then let's
483 * create it. */
484
485 c = new0(struct bus_match_node, 1);
486 if (!c) {
487 r = -ENOMEM;
488 goto fail;
489 }
490
491 c->type = t;
492 c->parent = where;
493 c->next = where->child;
494 if (c->next)
495 c->next->prev = c;
496 where->child = c;
497
498 if (t == BUS_MATCH_MESSAGE_TYPE) {
499 c->compare.children = hashmap_new(NULL);
500 if (!c->compare.children) {
501 r = -ENOMEM;
502 goto fail;
503 }
504 } else if (BUS_MATCH_CAN_HASH(t)) {
505 c->compare.children = hashmap_new(&string_hash_ops);
506 if (!c->compare.children) {
507 r = -ENOMEM;
508 goto fail;
509 }
510 }
511 }
512
513 n = new0(struct bus_match_node, 1);
514 if (!n) {
515 r = -ENOMEM;
516 goto fail;
517 }
518
519 n->type = BUS_MATCH_VALUE;
520 n->value.u8 = value_u8;
521 if (value_str) {
522 n->value.str = strdup(value_str);
523 if (!n->value.str) {
524 r = -ENOMEM;
525 goto fail;
526 }
527 }
528
529 n->parent = c;
530 if (c->compare.children) {
531
532 if (t == BUS_MATCH_MESSAGE_TYPE)
533 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
534 else
535 r = hashmap_put(c->compare.children, n->value.str, n);
536
537 if (r < 0)
538 goto fail;
539 } else {
540 n->next = c->child;
541 if (n->next)
542 n->next->prev = n;
543 c->child = n;
544 }
545
546 *ret = n;
547 return 1;
548
549 fail:
550 if (c)
551 bus_match_node_maybe_free(c);
552
553 if (n) {
554 free(n->value.str);
555 free(n);
556 }
557
558 return r;
559 }
560
561 static int bus_match_find_compare_value(
562 struct bus_match_node *where,
563 enum bus_match_node_type t,
564 uint8_t value_u8,
565 const char *value_str,
566 struct bus_match_node **ret) {
567
568 struct bus_match_node *c, *n;
569
570 assert(where);
571 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
572 assert(BUS_MATCH_IS_COMPARE(t));
573 assert(ret);
574
575 for (c = where->child; c && c->type != t; c = c->next)
576 ;
577
578 if (!c)
579 return 0;
580
581 if (t == BUS_MATCH_MESSAGE_TYPE)
582 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
583 else if (BUS_MATCH_CAN_HASH(t))
584 n = hashmap_get(c->compare.children, value_str);
585 else {
586 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
587 ;
588 }
589
590 if (n) {
591 *ret = n;
592 return 1;
593 }
594
595 return 0;
596 }
597
598 static int bus_match_add_leaf(
599 struct bus_match_node *where,
600 struct match_callback *callback) {
601
602 struct bus_match_node *n;
603
604 assert(where);
605 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
606 assert(callback);
607
608 n = new0(struct bus_match_node, 1);
609 if (!n)
610 return -ENOMEM;
611
612 n->type = BUS_MATCH_LEAF;
613 n->parent = where;
614 n->next = where->child;
615 if (n->next)
616 n->next->prev = n;
617
618 n->leaf.callback = callback;
619 callback->match_node = n;
620
621 where->child = n;
622
623 return 1;
624 }
625
626 static int bus_match_find_leaf(
627 struct bus_match_node *where,
628 sd_bus_message_handler_t callback,
629 void *userdata,
630 struct bus_match_node **ret) {
631
632 struct bus_match_node *c;
633
634 assert(where);
635 assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
636 assert(ret);
637
638 for (c = where->child; c; c = c->next) {
639 sd_bus_slot *s;
640
641 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
642
643 if (c->type == BUS_MATCH_LEAF &&
644 c->leaf.callback->callback == callback &&
645 s->userdata == userdata) {
646 *ret = c;
647 return 1;
648 }
649 }
650
651 return 0;
652 }
653
654 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
655 assert(k);
656
657 if (n == 4 && startswith(k, "type"))
658 return BUS_MATCH_MESSAGE_TYPE;
659 if (n == 6 && startswith(k, "sender"))
660 return BUS_MATCH_SENDER;
661 if (n == 11 && startswith(k, "destination"))
662 return BUS_MATCH_DESTINATION;
663 if (n == 9 && startswith(k, "interface"))
664 return BUS_MATCH_INTERFACE;
665 if (n == 6 && startswith(k, "member"))
666 return BUS_MATCH_MEMBER;
667 if (n == 4 && startswith(k, "path"))
668 return BUS_MATCH_PATH;
669 if (n == 14 && startswith(k, "path_namespace"))
670 return BUS_MATCH_PATH_NAMESPACE;
671
672 if (n == 4 && startswith(k, "arg")) {
673 int j;
674
675 j = undecchar(k[3]);
676 if (j < 0)
677 return -EINVAL;
678
679 return BUS_MATCH_ARG + j;
680 }
681
682 if (n == 5 && startswith(k, "arg")) {
683 int a, b;
684 enum bus_match_node_type t;
685
686 a = undecchar(k[3]);
687 b = undecchar(k[4]);
688 if (a <= 0 || b < 0)
689 return -EINVAL;
690
691 t = BUS_MATCH_ARG + a * 10 + b;
692 if (t > BUS_MATCH_ARG_LAST)
693 return -EINVAL;
694
695 return t;
696 }
697
698 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
699 int j;
700
701 j = undecchar(k[3]);
702 if (j < 0)
703 return -EINVAL;
704
705 return BUS_MATCH_ARG_PATH + j;
706 }
707
708 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
709 enum bus_match_node_type t;
710 int a, b;
711
712 a = undecchar(k[3]);
713 b = undecchar(k[4]);
714 if (a <= 0 || b < 0)
715 return -EINVAL;
716
717 t = BUS_MATCH_ARG_PATH + a * 10 + b;
718 if (t > BUS_MATCH_ARG_PATH_LAST)
719 return -EINVAL;
720
721 return t;
722 }
723
724 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
725 int j;
726
727 j = undecchar(k[3]);
728 if (j < 0)
729 return -EINVAL;
730
731 return BUS_MATCH_ARG_NAMESPACE + j;
732 }
733
734 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
735 enum bus_match_node_type t;
736 int a, b;
737
738 a = undecchar(k[3]);
739 b = undecchar(k[4]);
740 if (a <= 0 || b < 0)
741 return -EINVAL;
742
743 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
744 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
745 return -EINVAL;
746
747 return t;
748 }
749
750 if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
751 int j;
752
753 j = undecchar(k[3]);
754 if (j < 0)
755 return -EINVAL;
756
757 return BUS_MATCH_ARG_HAS + j;
758 }
759
760 if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
761 enum bus_match_node_type t;
762 int a, b;
763
764 a = undecchar(k[3]);
765 b = undecchar(k[4]);
766 if (a <= 0 || b < 0)
767 return -EINVAL;
768
769 t = BUS_MATCH_ARG_HAS + a * 10 + b;
770 if (t > BUS_MATCH_ARG_HAS_LAST)
771 return -EINVAL;
772
773 return t;
774 }
775
776 return -EINVAL;
777 }
778
779 static int match_component_compare(const void *a, const void *b) {
780 const struct bus_match_component *x = a, *y = b;
781
782 if (x->type < y->type)
783 return -1;
784 if (x->type > y->type)
785 return 1;
786
787 return 0;
788 }
789
790 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
791 unsigned i;
792
793 for (i = 0; i < n_components; i++)
794 free(components[i].value_str);
795
796 free(components);
797 }
798
799 int bus_match_parse(
800 const char *match,
801 struct bus_match_component **_components,
802 unsigned *_n_components) {
803
804 const char *p = match;
805 struct bus_match_component *components = NULL;
806 size_t components_allocated = 0;
807 unsigned n_components = 0, i;
808 _cleanup_free_ char *value = NULL;
809 int r;
810
811 assert(match);
812 assert(_components);
813 assert(_n_components);
814
815 while (*p != 0) {
816 const char *eq, *q;
817 enum bus_match_node_type t;
818 unsigned j = 0;
819 size_t value_allocated = 0;
820 bool escaped = false, quoted;
821 uint8_t u;
822
823 /* Avahi's match rules appear to include whitespace, skip over it */
824 p += strspn(p, " ");
825
826 eq = strchr(p, '=');
827 if (!eq)
828 return -EINVAL;
829
830 t = bus_match_node_type_from_string(p, eq - p);
831 if (t < 0)
832 return -EINVAL;
833
834 quoted = eq[1] == '\'';
835
836 for (q = eq + 1 + quoted;; q++) {
837
838 if (*q == 0) {
839
840 if (quoted) {
841 r = -EINVAL;
842 goto fail;
843 } else {
844 if (value)
845 value[j] = 0;
846 break;
847 }
848 }
849
850 if (!escaped) {
851 if (*q == '\\') {
852 escaped = true;
853 continue;
854 }
855
856 if (quoted) {
857 if (*q == '\'') {
858 if (value)
859 value[j] = 0;
860 break;
861 }
862 } else {
863 if (*q == ',') {
864 if (value)
865 value[j] = 0;
866
867 break;
868 }
869 }
870 }
871
872 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
873 r = -ENOMEM;
874 goto fail;
875 }
876
877 value[j++] = *q;
878 escaped = false;
879 }
880
881 if (!value) {
882 value = strdup("");
883 if (!value) {
884 r = -ENOMEM;
885 goto fail;
886 }
887 }
888
889 if (t == BUS_MATCH_MESSAGE_TYPE) {
890 r = bus_message_type_from_string(value, &u);
891 if (r < 0)
892 goto fail;
893
894 value = mfree(value);
895 } else
896 u = 0;
897
898 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
899 r = -ENOMEM;
900 goto fail;
901 }
902
903 components[n_components].type = t;
904 components[n_components].value_str = value;
905 components[n_components].value_u8 = u;
906 n_components++;
907
908 value = NULL;
909
910 if (q[quoted] == 0)
911 break;
912
913 if (q[quoted] != ',') {
914 r = -EINVAL;
915 goto fail;
916 }
917
918 p = q + 1 + quoted;
919 }
920
921 /* Order the whole thing, so that we always generate the same tree */
922 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
923
924 /* Check for duplicates */
925 for (i = 0; i+1 < n_components; i++)
926 if (components[i].type == components[i+1].type) {
927 r = -EINVAL;
928 goto fail;
929 }
930
931 *_components = components;
932 *_n_components = n_components;
933
934 return 0;
935
936 fail:
937 bus_match_parse_free(components, n_components);
938 return r;
939 }
940
941 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
942 _cleanup_fclose_ FILE *f = NULL;
943 char *buffer = NULL;
944 size_t size = 0;
945 unsigned i;
946 int r;
947
948 if (n_components <= 0)
949 return strdup("");
950
951 assert(components);
952
953 f = open_memstream(&buffer, &size);
954 if (!f)
955 return NULL;
956
957 for (i = 0; i < n_components; i++) {
958 char buf[32];
959
960 if (i != 0)
961 fputc_unlocked(',', f);
962
963 fputs_unlocked(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
964 fputc_unlocked('=', f);
965 fputc_unlocked('\'', f);
966
967 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
968 fputs_unlocked(bus_message_type_to_string(components[i].value_u8), f);
969 else
970 fputs_unlocked(components[i].value_str, f);
971
972 fputc_unlocked('\'', f);
973 }
974
975 r = fflush_and_check(f);
976 if (r < 0)
977 return NULL;
978
979 return buffer;
980 }
981
982 int bus_match_add(
983 struct bus_match_node *root,
984 struct bus_match_component *components,
985 unsigned n_components,
986 struct match_callback *callback) {
987
988 unsigned i;
989 struct bus_match_node *n;
990 int r;
991
992 assert(root);
993 assert(callback);
994
995 n = root;
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);
1000 if (r < 0)
1001 return r;
1002 }
1003
1004 return bus_match_add_leaf(n, callback);
1005 }
1006
1007 int bus_match_remove(
1008 struct bus_match_node *root,
1009 struct match_callback *callback) {
1010
1011 struct bus_match_node *node, *pp;
1012
1013 assert(root);
1014 assert(callback);
1015
1016 node = callback->match_node;
1017 if (!node)
1018 return 0;
1019
1020 assert(node->type == BUS_MATCH_LEAF);
1021
1022 callback->match_node = NULL;
1023
1024 /* Free the leaf */
1025 pp = node->parent;
1026 bus_match_node_free(node);
1027
1028 /* Prune the tree above */
1029 while (pp) {
1030 node = pp;
1031 pp = node->parent;
1032
1033 if (!bus_match_node_maybe_free(node))
1034 break;
1035 }
1036
1037 return 1;
1038 }
1039
1040 int bus_match_find(
1041 struct bus_match_node *root,
1042 struct bus_match_component *components,
1043 unsigned n_components,
1044 sd_bus_message_handler_t callback,
1045 void *userdata,
1046 struct match_callback **ret) {
1047
1048 struct bus_match_node *n, **gc;
1049 unsigned i;
1050 int r;
1051
1052 assert(root);
1053 assert(ret);
1054
1055 gc = newa(struct bus_match_node*, n_components);
1056
1057 n = root;
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,
1062 &n);
1063 if (r <= 0)
1064 return r;
1065
1066 gc[i] = n;
1067 }
1068
1069 r = bus_match_find_leaf(n, callback, userdata, &n);
1070 if (r <= 0)
1071 return r;
1072
1073 *ret = n->leaf.callback;
1074 return 1;
1075 }
1076
1077 void bus_match_free(struct bus_match_node *node) {
1078 struct bus_match_node *c;
1079
1080 if (!node)
1081 return;
1082
1083 if (BUS_MATCH_CAN_HASH(node->type)) {
1084 Iterator i;
1085
1086 HASHMAP_FOREACH(c, node->compare.children, i)
1087 bus_match_free(c);
1088
1089 assert(hashmap_isempty(node->compare.children));
1090 }
1091
1092 while ((c = node->child))
1093 bus_match_free(c);
1094
1095 if (node->type != BUS_MATCH_ROOT)
1096 bus_match_node_free(node);
1097 }
1098
1099 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1100 switch (t) {
1101
1102 case BUS_MATCH_ROOT:
1103 return "root";
1104
1105 case BUS_MATCH_VALUE:
1106 return "value";
1107
1108 case BUS_MATCH_LEAF:
1109 return "leaf";
1110
1111 case BUS_MATCH_MESSAGE_TYPE:
1112 return "type";
1113
1114 case BUS_MATCH_SENDER:
1115 return "sender";
1116
1117 case BUS_MATCH_DESTINATION:
1118 return "destination";
1119
1120 case BUS_MATCH_INTERFACE:
1121 return "interface";
1122
1123 case BUS_MATCH_MEMBER:
1124 return "member";
1125
1126 case BUS_MATCH_PATH:
1127 return "path";
1128
1129 case BUS_MATCH_PATH_NAMESPACE:
1130 return "path_namespace";
1131
1132 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1133 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1134 return buf;
1135
1136 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1137 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1138 return buf;
1139
1140 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1141 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1142 return buf;
1143
1144 case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1145 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1146 return buf;
1147
1148 default:
1149 return NULL;
1150 }
1151 }
1152
1153 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1154 struct bus_match_node *c;
1155 _cleanup_free_ char *pfx = NULL;
1156 char buf[32];
1157
1158 if (!node)
1159 return;
1160
1161 pfx = strrep(" ", level);
1162 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1163
1164 if (node->type == BUS_MATCH_VALUE) {
1165 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1166 printf(" <%u>\n", node->value.u8);
1167 else
1168 printf(" <%s>\n", node->value.str);
1169 } else if (node->type == BUS_MATCH_ROOT)
1170 puts(" 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);
1173 else
1174 putchar('\n');
1175
1176 if (BUS_MATCH_CAN_HASH(node->type)) {
1177 Iterator i;
1178
1179 HASHMAP_FOREACH(c, node->compare.children, i)
1180 bus_match_dump(c, level + 1);
1181 }
1182
1183 for (c = node->child; c; c = c->next)
1184 bus_match_dump(c, level + 1);
1185 }
1186
1187 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1188 bool found_driver = false;
1189 unsigned i;
1190
1191 if (n_components <= 0)
1192 return BUS_MATCH_GENERIC;
1193
1194 assert(components);
1195
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
1200 * driver. */
1201
1202 for (i = 0; i < n_components; i++) {
1203 const struct bus_match_component *c = components + i;
1204
1205 if (c->type == BUS_MATCH_SENDER) {
1206 if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1207 return BUS_MATCH_LOCAL;
1208
1209 if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1210 found_driver = true;
1211 }
1212
1213 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1214 return BUS_MATCH_LOCAL;
1215
1216 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1217 return BUS_MATCH_LOCAL;
1218 }
1219
1220 return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
1221
1222 }