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