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