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