]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-match.c
sd-bus: make sure we properly handle NULL callback functions
[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 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
300 if (bus)
301 bus->current_slot = sd_bus_slot_unref(slot);
302
303 r = bus_maybe_reply_error(m, r, &error_buffer);
304 if (r != 0)
305 return r;
306
307 if (bus && bus->match_callbacks_modified)
308 return 0;
309 }
310
311 return bus_match_run(bus, node->next, m);
312
313 case BUS_MATCH_MESSAGE_TYPE:
314 test_u8 = m->header->type;
315 break;
316
317 case BUS_MATCH_SENDER:
318 test_str = m->sender;
319 /* FIXME: resolve test_str from a well-known to a unique name first */
320 break;
321
322 case BUS_MATCH_DESTINATION:
323 test_str = m->destination;
324 break;
325
326 case BUS_MATCH_INTERFACE:
327 test_str = m->interface;
328 break;
329
330 case BUS_MATCH_MEMBER:
331 test_str = m->member;
332 break;
333
334 case BUS_MATCH_PATH:
335 case BUS_MATCH_PATH_NAMESPACE:
336 test_str = m->path;
337 break;
338
339 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
340 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
341 break;
342
343 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
344 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
345 break;
346
347 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
348 test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
349 break;
350
351 default:
352 assert_not_reached("Unknown match type.");
353 }
354
355 if (BUS_MATCH_CAN_HASH(node->type)) {
356 struct bus_match_node *found;
357
358 /* Lookup via hash table, nice! So let's jump directly. */
359
360 if (test_str)
361 found = hashmap_get(node->compare.children, test_str);
362 else if (node->type == BUS_MATCH_MESSAGE_TYPE)
363 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
364 else
365 found = NULL;
366
367 if (found) {
368 r = bus_match_run(bus, found, m);
369 if (r != 0)
370 return r;
371 }
372 } else {
373 struct bus_match_node *c;
374
375 /* No hash table, so let's iterate manually... */
376
377 for (c = node->child; c; c = c->next) {
378 if (!value_node_test(c, node->type, test_u8, test_str, m))
379 continue;
380
381 r = bus_match_run(bus, c, m);
382 if (r != 0)
383 return r;
384 }
385 }
386
387 if (bus && bus->match_callbacks_modified)
388 return 0;
389
390 /* And now, let's invoke our siblings */
391 return bus_match_run(bus, node->next, m);
392 }
393
394 static int bus_match_add_compare_value(
395 struct bus_match_node *where,
396 enum bus_match_node_type t,
397 uint8_t value_u8,
398 const char *value_str,
399 struct bus_match_node **ret) {
400
401 struct bus_match_node *c = NULL, *n = NULL;
402 int r;
403
404 assert(where);
405 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
406 assert(BUS_MATCH_IS_COMPARE(t));
407 assert(ret);
408
409 for (c = where->child; c && c->type != t; c = c->next)
410 ;
411
412 if (c) {
413 /* Comparison node already exists? Then let's see if
414 * the value node exists too. */
415
416 if (t == BUS_MATCH_MESSAGE_TYPE)
417 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
418 else if (BUS_MATCH_CAN_HASH(t))
419 n = hashmap_get(c->compare.children, value_str);
420 else {
421 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
422 ;
423 }
424
425 if (n) {
426 *ret = n;
427 return 0;
428 }
429 } else {
430 /* Comparison node, doesn't exist yet? Then let's
431 * create it. */
432
433 c = new0(struct bus_match_node, 1);
434 if (!c) {
435 r = -ENOMEM;
436 goto fail;
437 }
438
439 c->type = t;
440 c->parent = where;
441 c->next = where->child;
442 if (c->next)
443 c->next->prev = c;
444 where->child = c;
445
446 if (t == BUS_MATCH_MESSAGE_TYPE) {
447 c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
448 if (!c->compare.children) {
449 r = -ENOMEM;
450 goto fail;
451 }
452 } else if (BUS_MATCH_CAN_HASH(t)) {
453 c->compare.children = hashmap_new(string_hash_func, string_compare_func);
454 if (!c->compare.children) {
455 r = -ENOMEM;
456 goto fail;
457 }
458 }
459 }
460
461 n = new0(struct bus_match_node, 1);
462 if (!n) {
463 r = -ENOMEM;
464 goto fail;
465 }
466
467 n->type = BUS_MATCH_VALUE;
468 n->value.u8 = value_u8;
469 if (value_str) {
470 n->value.str = strdup(value_str);
471 if (!n->value.str) {
472 r = -ENOMEM;
473 goto fail;
474 }
475 }
476
477 n->parent = c;
478 if (c->compare.children) {
479
480 if (t == BUS_MATCH_MESSAGE_TYPE)
481 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
482 else
483 r = hashmap_put(c->compare.children, n->value.str, n);
484
485 if (r < 0)
486 goto fail;
487 } else {
488 n->next = c->child;
489 if (n->next)
490 n->next->prev = n;
491 c->child = n;
492 }
493
494 *ret = n;
495 return 1;
496
497 fail:
498 if (c)
499 bus_match_node_maybe_free(c);
500
501 if (n) {
502 free(n->value.str);
503 free(n);
504 }
505
506 return r;
507 }
508
509 static int bus_match_find_compare_value(
510 struct bus_match_node *where,
511 enum bus_match_node_type t,
512 uint8_t value_u8,
513 const char *value_str,
514 struct bus_match_node **ret) {
515
516 struct bus_match_node *c, *n;
517
518 assert(where);
519 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
520 assert(BUS_MATCH_IS_COMPARE(t));
521 assert(ret);
522
523 for (c = where->child; c && c->type != t; c = c->next)
524 ;
525
526 if (!c)
527 return 0;
528
529 if (t == BUS_MATCH_MESSAGE_TYPE)
530 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
531 else if (BUS_MATCH_CAN_HASH(t))
532 n = hashmap_get(c->compare.children, value_str);
533 else {
534 for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
535 ;
536 }
537
538 if (n) {
539 *ret = n;
540 return 1;
541 }
542
543 return 0;
544 }
545
546 static int bus_match_add_leaf(
547 struct bus_match_node *where,
548 struct match_callback *callback) {
549
550 struct bus_match_node *n;
551
552 assert(where);
553 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
554 assert(callback);
555
556 n = new0(struct bus_match_node, 1);
557 if (!n)
558 return -ENOMEM;
559
560 n->type = BUS_MATCH_LEAF;
561 n->parent = where;
562 n->next = where->child;
563 if (n->next)
564 n->next->prev = n;
565
566 n->leaf.callback = callback;
567 callback->match_node = n;
568
569 where->child = n;
570
571 return 1;
572 }
573
574 static int bus_match_find_leaf(
575 struct bus_match_node *where,
576 sd_bus_message_handler_t callback,
577 void *userdata,
578 struct bus_match_node **ret) {
579
580 struct bus_match_node *c;
581
582 assert(where);
583 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
584 assert(ret);
585
586 for (c = where->child; c; c = c->next) {
587 sd_bus_slot *s;
588
589 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
590
591 if (c->type == BUS_MATCH_LEAF &&
592 c->leaf.callback->callback == callback &&
593 s->userdata == userdata) {
594 *ret = c;
595 return 1;
596 }
597 }
598
599 return 0;
600 }
601
602 enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
603 assert(k);
604
605 if (n == 4 && startswith(k, "type"))
606 return BUS_MATCH_MESSAGE_TYPE;
607 if (n == 6 && startswith(k, "sender"))
608 return BUS_MATCH_SENDER;
609 if (n == 11 && startswith(k, "destination"))
610 return BUS_MATCH_DESTINATION;
611 if (n == 9 && startswith(k, "interface"))
612 return BUS_MATCH_INTERFACE;
613 if (n == 6 && startswith(k, "member"))
614 return BUS_MATCH_MEMBER;
615 if (n == 4 && startswith(k, "path"))
616 return BUS_MATCH_PATH;
617 if (n == 14 && startswith(k, "path_namespace"))
618 return BUS_MATCH_PATH_NAMESPACE;
619
620 if (n == 4 && startswith(k, "arg")) {
621 int j;
622
623 j = undecchar(k[3]);
624 if (j < 0)
625 return -EINVAL;
626
627 return BUS_MATCH_ARG + j;
628 }
629
630 if (n == 5 && startswith(k, "arg")) {
631 int a, b;
632 enum bus_match_node_type t;
633
634 a = undecchar(k[3]);
635 b = undecchar(k[4]);
636 if (a <= 0 || b < 0)
637 return -EINVAL;
638
639 t = BUS_MATCH_ARG + a * 10 + b;
640 if (t > BUS_MATCH_ARG_LAST)
641 return -EINVAL;
642
643 return t;
644 }
645
646 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
647 int j;
648
649 j = undecchar(k[3]);
650 if (j < 0)
651 return -EINVAL;
652
653 return BUS_MATCH_ARG_PATH + j;
654 }
655
656 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
657 enum bus_match_node_type t;
658 int a, b;
659
660 a = undecchar(k[3]);
661 b = undecchar(k[4]);
662 if (a <= 0 || b < 0)
663 return -EINVAL;
664
665 t = BUS_MATCH_ARG_PATH + a * 10 + b;
666 if (t > BUS_MATCH_ARG_PATH_LAST)
667 return -EINVAL;
668
669 return t;
670 }
671
672 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
673 int j;
674
675 j = undecchar(k[3]);
676 if (j < 0)
677 return -EINVAL;
678
679 return BUS_MATCH_ARG_NAMESPACE + j;
680 }
681
682 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
683 enum bus_match_node_type t;
684 int a, b;
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_NAMESPACE + a * 10 + b;
692 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
693 return -EINVAL;
694
695 return t;
696 }
697
698 return -EINVAL;
699 }
700
701 static int match_component_compare(const void *a, const void *b) {
702 const struct bus_match_component *x = a, *y = b;
703
704 if (x->type < y->type)
705 return -1;
706 if (x->type > y->type)
707 return 1;
708
709 return 0;
710 }
711
712 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
713 unsigned i;
714
715 for (i = 0; i < n_components; i++)
716 free(components[i].value_str);
717
718 free(components);
719 }
720
721 int bus_match_parse(
722 const char *match,
723 struct bus_match_component **_components,
724 unsigned *_n_components) {
725
726 const char *p = match;
727 struct bus_match_component *components = NULL;
728 size_t components_allocated = 0;
729 unsigned n_components = 0, i;
730 _cleanup_free_ char *value = NULL;
731 int r;
732
733 assert(match);
734 assert(_components);
735 assert(_n_components);
736
737 while (*p != 0) {
738 const char *eq, *q;
739 enum bus_match_node_type t;
740 unsigned j = 0;
741 size_t value_allocated = 0;
742 bool escaped = false, quoted;
743 uint8_t u;
744
745 eq = strchr(p, '=');
746 if (!eq)
747 return -EINVAL;
748
749 t = bus_match_node_type_from_string(p, eq - p);
750 if (t < 0)
751 return -EINVAL;
752
753 quoted = eq[1] == '\'';
754
755 for (q = eq + 1 + quoted;; q++) {
756
757 if (*q == 0) {
758
759 if (quoted) {
760 r = -EINVAL;
761 goto fail;
762 } else {
763 if (value)
764 value[j] = 0;
765 break;
766 }
767 }
768
769 if (!escaped) {
770 if (*q == '\\') {
771 escaped = true;
772 continue;
773 }
774
775 if (quoted) {
776 if (*q == '\'') {
777 if (value)
778 value[j] = 0;
779 break;
780 }
781 } else {
782 if (*q == ',') {
783 if (value)
784 value[j] = 0;
785
786 break;
787 }
788 }
789 }
790
791 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
792 r = -ENOMEM;
793 goto fail;
794 }
795
796 value[j++] = *q;
797 escaped = false;
798 }
799
800 if (!value) {
801 value = strdup("");
802 if (!value) {
803 r = -ENOMEM;
804 goto fail;
805 }
806 }
807
808 if (t == BUS_MATCH_MESSAGE_TYPE) {
809 r = bus_message_type_from_string(value, &u);
810 if (r < 0)
811 goto fail;
812
813 free(value);
814 value = NULL;
815 } else
816 u = 0;
817
818 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
819 r = -ENOMEM;
820 goto fail;
821 }
822
823 components[n_components].type = t;
824 components[n_components].value_str = value;
825 components[n_components].value_u8 = u;
826 n_components++;
827
828 value = NULL;
829
830 if (q[quoted] == 0)
831 break;
832
833 if (q[quoted] != ',') {
834 r = -EINVAL;
835 goto fail;
836 }
837
838 p = q + 1 + quoted;
839 }
840
841 /* Order the whole thing, so that we always generate the same tree */
842 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
843
844 /* Check for duplicates */
845 for (i = 0; i+1 < n_components; i++)
846 if (components[i].type == components[i+1].type) {
847 r = -EINVAL;
848 goto fail;
849 }
850
851 *_components = components;
852 *_n_components = n_components;
853
854 return 0;
855
856 fail:
857 bus_match_parse_free(components, n_components);
858 return r;
859 }
860
861 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
862 _cleanup_free_ FILE *f = NULL;
863 char *buffer = NULL;
864 size_t size = 0;
865 unsigned i;
866
867 if (n_components <= 0)
868 return strdup("");
869
870 assert(components);
871
872 f = open_memstream(&buffer, &size);
873 if (!f)
874 return NULL;
875
876 for (i = 0; i < n_components; i++) {
877 char buf[32];
878
879 if (i != 0)
880 fputc(',', f);
881
882 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
883 fputc('=', f);
884 fputc('\'', f);
885
886 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
887 fputs(bus_message_type_to_string(components[i].value_u8), f);
888 else
889 fputs(components[i].value_str, f);
890
891 fputc('\'', f);
892 }
893
894 fflush(f);
895 if (ferror(f))
896 return NULL;
897
898 return buffer;
899 }
900
901 int bus_match_add(
902 struct bus_match_node *root,
903 struct bus_match_component *components,
904 unsigned n_components,
905 struct match_callback *callback) {
906
907 unsigned i;
908 struct bus_match_node *n;
909 int r;
910
911 assert(root);
912 assert(callback);
913
914 n = root;
915 for (i = 0; i < n_components; i++) {
916 r = bus_match_add_compare_value(
917 n, components[i].type,
918 components[i].value_u8, components[i].value_str, &n);
919 if (r < 0)
920 return r;
921 }
922
923 return bus_match_add_leaf(n, callback);
924 }
925
926 int bus_match_remove(
927 struct bus_match_node *root,
928 struct match_callback *callback) {
929
930 struct bus_match_node *node, *pp;
931
932 assert(root);
933 assert(callback);
934
935 node = callback->match_node;
936 if (!node)
937 return 0;
938
939 assert(node->type == BUS_MATCH_LEAF);
940
941 callback->match_node = NULL;
942
943 /* Free the leaf */
944 pp = node->parent;
945 bus_match_node_free(node);
946
947 /* Prune the tree above */
948 while (pp) {
949 node = pp;
950 pp = node->parent;
951
952 if (!bus_match_node_maybe_free(node))
953 break;
954 }
955
956 return 1;
957 }
958
959 int bus_match_find(
960 struct bus_match_node *root,
961 struct bus_match_component *components,
962 unsigned n_components,
963 sd_bus_message_handler_t callback,
964 void *userdata,
965 struct match_callback **ret) {
966
967 struct bus_match_node *n, **gc;
968 unsigned i;
969 int r;
970
971 assert(root);
972 assert(ret);
973
974 gc = newa(struct bus_match_node*, n_components);
975
976 n = root;
977 for (i = 0; i < n_components; i++) {
978 r = bus_match_find_compare_value(
979 n, components[i].type,
980 components[i].value_u8, components[i].value_str,
981 &n);
982 if (r <= 0)
983 return r;
984
985 gc[i] = n;
986 }
987
988 r = bus_match_find_leaf(n, callback, userdata, &n);
989 if (r <= 0)
990 return r;
991
992 *ret = n->leaf.callback;
993 return 1;
994 }
995
996 void bus_match_free(struct bus_match_node *node) {
997 struct bus_match_node *c;
998
999 if (!node)
1000 return;
1001
1002 if (BUS_MATCH_CAN_HASH(node->type)) {
1003 Iterator i;
1004
1005 HASHMAP_FOREACH(c, node->compare.children, i)
1006 bus_match_free(c);
1007
1008 assert(hashmap_isempty(node->compare.children));
1009 }
1010
1011 while ((c = node->child))
1012 bus_match_free(c);
1013
1014 if (node->type != BUS_MATCH_ROOT)
1015 bus_match_node_free(node);
1016 }
1017
1018 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1019 switch (t) {
1020
1021 case BUS_MATCH_ROOT:
1022 return "root";
1023
1024 case BUS_MATCH_VALUE:
1025 return "value";
1026
1027 case BUS_MATCH_LEAF:
1028 return "leaf";
1029
1030 case BUS_MATCH_MESSAGE_TYPE:
1031 return "type";
1032
1033 case BUS_MATCH_SENDER:
1034 return "sender";
1035
1036 case BUS_MATCH_DESTINATION:
1037 return "destination";
1038
1039 case BUS_MATCH_INTERFACE:
1040 return "interface";
1041
1042 case BUS_MATCH_MEMBER:
1043 return "member";
1044
1045 case BUS_MATCH_PATH:
1046 return "path";
1047
1048 case BUS_MATCH_PATH_NAMESPACE:
1049 return "path_namespace";
1050
1051 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1052 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1053 return buf;
1054
1055 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1056 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1057 return buf;
1058
1059 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1060 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1061 return buf;
1062
1063 default:
1064 return NULL;
1065 }
1066 }
1067
1068 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1069 struct bus_match_node *c;
1070 _cleanup_free_ char *pfx = NULL;
1071 char buf[32];
1072
1073 if (!node)
1074 return;
1075
1076 pfx = strrep(" ", level);
1077 printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1078
1079 if (node->type == BUS_MATCH_VALUE) {
1080 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1081 printf(" <%u>\n", node->value.u8);
1082 else
1083 printf(" <%s>\n", node->value.str);
1084 } else if (node->type == BUS_MATCH_ROOT)
1085 puts(" root");
1086 else if (node->type == BUS_MATCH_LEAF)
1087 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1088 else
1089 putchar('\n');
1090
1091 if (BUS_MATCH_CAN_HASH(node->type)) {
1092 Iterator i;
1093
1094 HASHMAP_FOREACH(c, node->compare.children, i)
1095 bus_match_dump(c, level + 1);
1096 }
1097
1098 for (c = node->child; c; c = c->next)
1099 bus_match_dump(c, level + 1);
1100 }