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