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