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