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