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