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