]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-match.c
tmpfiles: accurately report creation results
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-match.c
CommitLineData
392d5b37
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include "bus-internal.h"
23#include "bus-message.h"
24#include "bus-match.h"
ebcf1f97
LP
25#include "bus-error.h"
26#include "bus-util.h"
06100c7a 27#include "strv.h"
392d5b37
LP
28
29/* Example:
30 *
31 * A: type=signal,sender=foo,interface=bar
32 * B: type=signal,sender=quux,interface=fips
33 * C: type=signal,sender=quux,interface=waldo
34 * D: type=signal,member=test
35 * E: sender=miau
36 * F: type=signal
37 * G: type=signal
38 *
39 * results in this tree:
40 *
41 * BUS_MATCH_ROOT
42 * + BUS_MATCH_MESSAGE_TYPE
43 * | ` BUS_MATCH_VALUE: value == signal
44 * | + DBUS_MATCH_SENDER
45 * | | + BUS_MATCH_VALUE: value == foo
46 * | | | ` DBUS_MATCH_INTERFACE
47 * | | | ` BUS_MATCH_VALUE: value == bar
48 * | | | ` BUS_MATCH_LEAF: A
49 * | | ` BUS_MATCH_VALUE: value == quux
50 * | | ` DBUS_MATCH_INTERFACE
51 * | | | BUS_MATCH_VALUE: value == fips
52 * | | | ` BUS_MATCH_LEAF: B
53 * | | ` BUS_MATCH_VALUE: value == waldo
54 * | | ` BUS_MATCH_LEAF: C
55 * | + DBUS_MATCH_MEMBER
56 * | | ` BUS_MATCH_VALUE: value == test
57 * | | ` BUS_MATCH_LEAF: D
58 * | + BUS_MATCH_LEAF: F
59 * | ` BUS_MATCH_LEAF: G
60 * ` BUS_MATCH_SENDER
61 * ` BUS_MATCH_VALUE: value == miau
62 * ` BUS_MATCH_LEAF: E
63 */
64
65static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
ae7bed3f 66 return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
392d5b37
LP
67}
68
69static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
70 return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
71 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
72}
73
74static void bus_match_node_free(struct bus_match_node *node) {
75 assert(node);
76 assert(node->parent);
77 assert(!node->child);
78 assert(node->type != BUS_MATCH_ROOT);
79 assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
80
81 if (node->parent->child) {
82 /* We are apparently linked into the parent's child
83 * list. Let's remove us from there. */
84 if (node->prev) {
85 assert(node->prev->next == node);
86 node->prev->next = node->next;
87 } else {
88 assert(node->parent->child == node);
89 node->parent->child = node->next;
90 }
91
92 if (node->next)
93 node->next->prev = node->prev;
94 }
95
96 if (node->type == BUS_MATCH_VALUE) {
97 /* We might be in the parent's hash table, so clean
98 * this up */
99
100 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
101 hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
102 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
103 hashmap_remove(node->parent->compare.children, node->value.str);
104
105 free(node->value.str);
106 }
107
108 if (BUS_MATCH_IS_COMPARE(node->type)) {
109 assert(hashmap_isempty(node->compare.children));
110 hashmap_free(node->compare.children);
111 }
112
113 free(node);
114}
115
116static bool bus_match_node_maybe_free(struct bus_match_node *node) {
117 assert(node);
118
19befb2d
LP
119 if (node->type == BUS_MATCH_ROOT)
120 return false;
121
392d5b37
LP
122 if (node->child)
123 return false;
124
125 if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
126 return true;
127
128 bus_match_node_free(node);
129 return true;
130}
131
132static bool value_node_test(
133 struct bus_match_node *node,
134 enum bus_match_node_type parent_type,
135 uint8_t value_u8,
06100c7a 136 const char *value_str,
198b158f 137 char **value_strv,
06100c7a 138 sd_bus_message *m) {
392d5b37
LP
139
140 assert(node);
141 assert(node->type == BUS_MATCH_VALUE);
142
143 /* Tests parameters against this value node, doing prefix
144 * magic and stuff. */
145
146 switch (parent_type) {
147
148 case BUS_MATCH_MESSAGE_TYPE:
149 return node->value.u8 == value_u8;
150
151 case BUS_MATCH_SENDER:
ae7bed3f
LP
152 if (streq_ptr(node->value.str, value_str))
153 return true;
154
06100c7a
LP
155 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
156 char **i;
ae7bed3f 157
06100c7a
LP
158 /* on kdbus we have the well known names list
159 * in the credentials, let's make use of that
160 * for an accurate match */
161
162 STRV_FOREACH(i, m->creds.well_known_names)
163 if (streq_ptr(node->value.str, *i))
164 return true;
165
166 } else {
167
168 /* If we don't have kdbus, we don't know the
169 * well-known names of the senders. In that,
170 * let's just hope that dbus-daemon doesn't
171 * send us stuff we didn't want. */
172
173 if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
174 return true;
175 }
ae7bed3f
LP
176
177 return false;
178
06100c7a 179 case BUS_MATCH_DESTINATION:
392d5b37
LP
180 case BUS_MATCH_INTERFACE:
181 case BUS_MATCH_MEMBER:
182 case BUS_MATCH_PATH:
198b158f
LP
183 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
184 char **i;
392d5b37 185
198b158f
LP
186 if (value_str)
187 return streq_ptr(node->value.str, value_str);
188
189 STRV_FOREACH(i, value_strv)
190 if (streq_ptr(node->value.str, *i))
191 return true;
192
193 return false;
194 }
195
196 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
197 char **i;
198
199 if (value_str)
200 return namespace_simple_pattern(node->value.str, value_str);
201
202 STRV_FOREACH(i, value_strv)
203 if (namespace_simple_pattern(node->value.str, *i))
204 return true;
205 return false;
206 }
392d5b37
LP
207
208 case BUS_MATCH_PATH_NAMESPACE:
209 return path_simple_pattern(node->value.str, value_str);
210
198b158f
LP
211 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
212 char **i;
213
214 if (value_str)
215 return path_complex_pattern(node->value.str, value_str);
216
217 STRV_FOREACH(i, value_strv)
218 if (path_complex_pattern(node->value.str, *i))
219 return true;
220
221 return false;
222 }
392d5b37
LP
223
224 default:
225 assert_not_reached("Invalid node type");
226 }
227}
228
229static bool value_node_same(
230 struct bus_match_node *node,
231 enum bus_match_node_type parent_type,
232 uint8_t value_u8,
233 const char *value_str) {
234
235 /* Tests parameters against this value node, not doing prefix
236 * magic and stuff, i.e. this one actually compares the match
ad67ef27 237 * itself. */
392d5b37
LP
238
239 assert(node);
240 assert(node->type == BUS_MATCH_VALUE);
241
242 switch (parent_type) {
243
244 case BUS_MATCH_MESSAGE_TYPE:
245 return node->value.u8 == value_u8;
246
247 case BUS_MATCH_SENDER:
248 case BUS_MATCH_DESTINATION:
249 case BUS_MATCH_INTERFACE:
250 case BUS_MATCH_MEMBER:
251 case BUS_MATCH_PATH:
252 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
253 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
254 case BUS_MATCH_PATH_NAMESPACE:
255 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
256 return streq(node->value.str, value_str);
257
258 default:
259 assert_not_reached("Invalid node type");
260 }
261}
262
263int bus_match_run(
264 sd_bus *bus,
265 struct bus_match_node *node,
392d5b37
LP
266 sd_bus_message *m) {
267
198b158f 268 _cleanup_strv_free_ char **test_strv = NULL;
392d5b37
LP
269 const char *test_str = NULL;
270 uint8_t test_u8 = 0;
271 int r;
272
273 assert(m);
274
275 if (!node)
276 return 0;
277
7286037f
LP
278 if (bus && bus->match_callbacks_modified)
279 return 0;
280
392d5b37
LP
281 /* Not these special semantics: when traversing the tree we
282 * usually let bus_match_run() when called for a node
283 * recursively invoke bus_match_run(). There's are two
284 * exceptions here though, which are BUS_NODE_ROOT (which
285 * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
286 * are invoked anyway by its parent. */
287
288 switch (node->type) {
289
290 case BUS_MATCH_ROOT:
291
292 /* Run all children. Since we cannot have any siblings
293 * we won't call any. The children of the root node
294 * are compares or leaves, they will automatically
295 * call their siblings. */
eb01ba5d 296 return bus_match_run(bus, node->child, m);
392d5b37
LP
297
298 case BUS_MATCH_VALUE:
299
300 /* Run all children. We don't execute any siblings, we
301 * assume our caller does that. The children of value
302 * nodes are compares or leaves, they will
303 * automatically call their siblings */
304
305 assert(node->child);
eb01ba5d 306 return bus_match_run(bus, node->child, m);
392d5b37
LP
307
308 case BUS_MATCH_LEAF:
309
7286037f 310 if (bus) {
19befb2d 311 if (node->leaf.callback->last_iteration == bus->iteration_counter)
7286037f
LP
312 return 0;
313
19befb2d 314 node->leaf.callback->last_iteration = bus->iteration_counter;
7286037f
LP
315 }
316
88fe224c
LP
317 r = sd_bus_message_rewind(m, true);
318 if (r < 0)
319 return r;
320
392d5b37 321 /* Run the callback. And then invoke siblings. */
7e28adeb 322 if (node->leaf.callback->callback) {
ebcf1f97 323 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
1b64f838 324 sd_bus_slot *slot;
ebcf1f97 325
19befb2d 326 slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
caa82984 327 if (bus) {
1b64f838 328 bus->current_slot = sd_bus_slot_ref(slot);
caa82984
LP
329 bus->current_handler = node->leaf.callback->callback;
330 bus->current_userdata = slot->userdata;
331 }
19befb2d 332 r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
caa82984
LP
333 if (bus) {
334 bus->current_userdata = NULL;
335 bus->current_handler = NULL;
1b64f838 336 bus->current_slot = sd_bus_slot_unref(slot);
caa82984 337 }
19befb2d 338
ebcf1f97 339 r = bus_maybe_reply_error(m, r, &error_buffer);
c7819669
LP
340 if (r != 0)
341 return r;
bbb6ff02
LP
342
343 if (bus && bus->match_callbacks_modified)
344 return 0;
c7819669 345 }
392d5b37 346
eb01ba5d 347 return bus_match_run(bus, node->next, m);
392d5b37
LP
348
349 case BUS_MATCH_MESSAGE_TYPE:
350 test_u8 = m->header->type;
351 break;
352
353 case BUS_MATCH_SENDER:
354 test_str = m->sender;
355 /* FIXME: resolve test_str from a well-known to a unique name first */
356 break;
357
358 case BUS_MATCH_DESTINATION:
359 test_str = m->destination;
360 break;
361
362 case BUS_MATCH_INTERFACE:
363 test_str = m->interface;
364 break;
365
366 case BUS_MATCH_MEMBER:
367 test_str = m->member;
368 break;
369
370 case BUS_MATCH_PATH:
371 case BUS_MATCH_PATH_NAMESPACE:
372 test_str = m->path;
373 break;
374
375 case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
198b158f 376 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
392d5b37
LP
377 break;
378
379 case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
198b158f 380 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
392d5b37
LP
381 break;
382
383 case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
198b158f 384 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
392d5b37
LP
385 break;
386
387 default:
388 assert_not_reached("Unknown match type.");
389 }
390
391 if (BUS_MATCH_CAN_HASH(node->type)) {
392 struct bus_match_node *found;
393
394 /* Lookup via hash table, nice! So let's jump directly. */
395
396 if (test_str)
397 found = hashmap_get(node->compare.children, test_str);
198b158f
LP
398 else if (test_strv) {
399 char **i;
400
401 STRV_FOREACH(i, test_strv) {
402 found = hashmap_get(node->compare.children, *i);
403 if (found) {
404 r = bus_match_run(bus, found, m);
405 if (r != 0)
406 return r;
407 }
408 }
409
410 found = NULL;
411 } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
392d5b37
LP
412 found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
413 else
414 found = NULL;
415
416 if (found) {
eb01ba5d 417 r = bus_match_run(bus, found, m);
392d5b37
LP
418 if (r != 0)
419 return r;
420 }
421 } else {
422 struct bus_match_node *c;
423
424 /* No hash table, so let's iterate manually... */
425
426 for (c = node->child; c; c = c->next) {
198b158f 427 if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
392d5b37
LP
428 continue;
429
eb01ba5d 430 r = bus_match_run(bus, c, m);
392d5b37
LP
431 if (r != 0)
432 return r;
433 }
434 }
435
7286037f
LP
436 if (bus && bus->match_callbacks_modified)
437 return 0;
438
392d5b37 439 /* And now, let's invoke our siblings */
eb01ba5d 440 return bus_match_run(bus, node->next, m);
392d5b37
LP
441}
442
443static int bus_match_add_compare_value(
444 struct bus_match_node *where,
445 enum bus_match_node_type t,
446 uint8_t value_u8,
447 const char *value_str,
448 struct bus_match_node **ret) {
449
450 struct bus_match_node *c = NULL, *n = NULL;
451 int r;
452
453 assert(where);
454 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
455 assert(BUS_MATCH_IS_COMPARE(t));
456 assert(ret);
457
458 for (c = where->child; c && c->type != t; c = c->next)
459 ;
460
461 if (c) {
462 /* Comparison node already exists? Then let's see if
463 * the value node exists too. */
464
465 if (t == BUS_MATCH_MESSAGE_TYPE)
466 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
467 else if (BUS_MATCH_CAN_HASH(t))
468 n = hashmap_get(c->compare.children, value_str);
469 else {
470 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
471 ;
472 }
473
474 if (n) {
475 *ret = n;
476 return 0;
477 }
478 } else {
479 /* Comparison node, doesn't exist yet? Then let's
480 * create it. */
481
482 c = new0(struct bus_match_node, 1);
483 if (!c) {
484 r = -ENOMEM;
485 goto fail;
486 }
487
488 c->type = t;
489 c->parent = where;
490 c->next = where->child;
491 if (c->next)
492 c->next->prev = c;
493 where->child = c;
494
495 if (t == BUS_MATCH_MESSAGE_TYPE) {
d5099efc 496 c->compare.children = hashmap_new(NULL);
392d5b37
LP
497 if (!c->compare.children) {
498 r = -ENOMEM;
499 goto fail;
500 }
501 } else if (BUS_MATCH_CAN_HASH(t)) {
d5099efc 502 c->compare.children = hashmap_new(&string_hash_ops);
392d5b37
LP
503 if (!c->compare.children) {
504 r = -ENOMEM;
505 goto fail;
506 }
507 }
508 }
509
510 n = new0(struct bus_match_node, 1);
511 if (!n) {
512 r = -ENOMEM;
513 goto fail;
514 }
515
516 n->type = BUS_MATCH_VALUE;
517 n->value.u8 = value_u8;
518 if (value_str) {
519 n->value.str = strdup(value_str);
520 if (!n->value.str) {
521 r = -ENOMEM;
522 goto fail;
523 }
524 }
525
526 n->parent = c;
527 if (c->compare.children) {
528
529 if (t == BUS_MATCH_MESSAGE_TYPE)
530 r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
531 else
532 r = hashmap_put(c->compare.children, n->value.str, n);
533
534 if (r < 0)
535 goto fail;
536 } else {
537 n->next = c->child;
538 if (n->next)
539 n->next->prev = n;
540 c->child = n;
541 }
542
543 *ret = n;
544 return 1;
545
546fail:
547 if (c)
548 bus_match_node_maybe_free(c);
549
550 if (n) {
551 free(n->value.str);
552 free(n);
553 }
554
555 return r;
556}
557
558static int bus_match_find_compare_value(
559 struct bus_match_node *where,
560 enum bus_match_node_type t,
561 uint8_t value_u8,
562 const char *value_str,
563 struct bus_match_node **ret) {
564
565 struct bus_match_node *c, *n;
566
567 assert(where);
568 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
569 assert(BUS_MATCH_IS_COMPARE(t));
570 assert(ret);
571
572 for (c = where->child; c && c->type != t; c = c->next)
573 ;
574
575 if (!c)
576 return 0;
577
578 if (t == BUS_MATCH_MESSAGE_TYPE)
579 n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
580 else if (BUS_MATCH_CAN_HASH(t))
581 n = hashmap_get(c->compare.children, value_str);
582 else {
ef7b6c01 583 for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
392d5b37
LP
584 ;
585 }
586
587 if (n) {
588 *ret = n;
589 return 1;
590 }
591
592 return 0;
593}
594
595static int bus_match_add_leaf(
596 struct bus_match_node *where,
19befb2d 597 struct match_callback *callback) {
392d5b37
LP
598
599 struct bus_match_node *n;
600
601 assert(where);
602 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
19befb2d 603 assert(callback);
392d5b37
LP
604
605 n = new0(struct bus_match_node, 1);
606 if (!n)
607 return -ENOMEM;
608
609 n->type = BUS_MATCH_LEAF;
610 n->parent = where;
611 n->next = where->child;
612 if (n->next)
613 n->next->prev = n;
19befb2d 614
392d5b37 615 n->leaf.callback = callback;
19befb2d 616 callback->match_node = n;
392d5b37
LP
617
618 where->child = n;
619
392d5b37
LP
620 return 1;
621}
622
623static int bus_match_find_leaf(
624 struct bus_match_node *where,
52f3ba91 625 sd_bus_message_handler_t callback,
392d5b37
LP
626 void *userdata,
627 struct bus_match_node **ret) {
628
629 struct bus_match_node *c;
630
631 assert(where);
632 assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
633 assert(ret);
634
635 for (c = where->child; c; c = c->next) {
19befb2d
LP
636 sd_bus_slot *s;
637
638 s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
639
392d5b37 640 if (c->type == BUS_MATCH_LEAF &&
19befb2d
LP
641 c->leaf.callback->callback == callback &&
642 s->userdata == userdata) {
392d5b37
LP
643 *ret = c;
644 return 1;
645 }
646 }
647
648 return 0;
649}
650
651enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
652 assert(k);
653
2a0e0692 654 if (n == 4 && startswith(k, "type"))
392d5b37 655 return BUS_MATCH_MESSAGE_TYPE;
2a0e0692 656 if (n == 6 && startswith(k, "sender"))
392d5b37 657 return BUS_MATCH_SENDER;
2a0e0692 658 if (n == 11 && startswith(k, "destination"))
392d5b37 659 return BUS_MATCH_DESTINATION;
2a0e0692 660 if (n == 9 && startswith(k, "interface"))
392d5b37 661 return BUS_MATCH_INTERFACE;
2a0e0692 662 if (n == 6 && startswith(k, "member"))
392d5b37 663 return BUS_MATCH_MEMBER;
2a0e0692 664 if (n == 4 && startswith(k, "path"))
392d5b37 665 return BUS_MATCH_PATH;
2a0e0692 666 if (n == 14 && startswith(k, "path_namespace"))
392d5b37
LP
667 return BUS_MATCH_PATH_NAMESPACE;
668
2a0e0692 669 if (n == 4 && startswith(k, "arg")) {
392d5b37
LP
670 int j;
671
672 j = undecchar(k[3]);
673 if (j < 0)
674 return -EINVAL;
675
676 return BUS_MATCH_ARG + j;
677 }
678
2a0e0692 679 if (n == 5 && startswith(k, "arg")) {
392d5b37
LP
680 int a, b;
681 enum bus_match_node_type t;
682
683 a = undecchar(k[3]);
684 b = undecchar(k[4]);
685 if (a <= 0 || b < 0)
686 return -EINVAL;
687
688 t = BUS_MATCH_ARG + a * 10 + b;
689 if (t > BUS_MATCH_ARG_LAST)
690 return -EINVAL;
691
692 return t;
693 }
694
2a0e0692 695 if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
392d5b37
LP
696 int j;
697
698 j = undecchar(k[3]);
699 if (j < 0)
700 return -EINVAL;
701
702 return BUS_MATCH_ARG_PATH + j;
703 }
704
2a0e0692 705 if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
392d5b37
LP
706 enum bus_match_node_type t;
707 int a, b;
708
709 a = undecchar(k[3]);
710 b = undecchar(k[4]);
711 if (a <= 0 || b < 0)
712 return -EINVAL;
713
714 t = BUS_MATCH_ARG_PATH + a * 10 + b;
715 if (t > BUS_MATCH_ARG_PATH_LAST)
716 return -EINVAL;
717
718 return t;
719 }
720
2a0e0692 721 if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
392d5b37
LP
722 int j;
723
724 j = undecchar(k[3]);
725 if (j < 0)
726 return -EINVAL;
727
728 return BUS_MATCH_ARG_NAMESPACE + j;
729 }
730
2a0e0692 731 if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
392d5b37
LP
732 enum bus_match_node_type t;
733 int a, b;
734
735 a = undecchar(k[3]);
736 b = undecchar(k[4]);
737 if (a <= 0 || b < 0)
738 return -EINVAL;
739
740 t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
741 if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
742 return -EINVAL;
743
744 return t;
745 }
746
747 return -EINVAL;
748}
749
392d5b37 750static int match_component_compare(const void *a, const void *b) {
c7819669 751 const struct bus_match_component *x = a, *y = b;
392d5b37
LP
752
753 if (x->type < y->type)
754 return -1;
755 if (x->type > y->type)
756 return 1;
757
758 return 0;
759}
760
c7819669 761void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
392d5b37
LP
762 unsigned i;
763
764 for (i = 0; i < n_components; i++)
765 free(components[i].value_str);
766
767 free(components);
768}
769
c7819669 770int bus_match_parse(
392d5b37 771 const char *match,
c7819669 772 struct bus_match_component **_components,
392d5b37
LP
773 unsigned *_n_components) {
774
775 const char *p = match;
c7819669 776 struct bus_match_component *components = NULL;
392d5b37
LP
777 size_t components_allocated = 0;
778 unsigned n_components = 0, i;
779 _cleanup_free_ char *value = NULL;
780 int r;
781
782 assert(match);
783 assert(_components);
784 assert(_n_components);
785
786 while (*p != 0) {
787 const char *eq, *q;
788 enum bus_match_node_type t;
789 unsigned j = 0;
790 size_t value_allocated = 0;
bc6422cb 791 bool escaped = false, quoted;
392d5b37
LP
792 uint8_t u;
793
771b2724
LP
794 /* Avahi's match rules appear to include whitespace, skip over it */
795 p += strspn(p, " ");
796
392d5b37
LP
797 eq = strchr(p, '=');
798 if (!eq)
799 return -EINVAL;
800
392d5b37
LP
801 t = bus_match_node_type_from_string(p, eq - p);
802 if (t < 0)
803 return -EINVAL;
804
bc6422cb
LP
805 quoted = eq[1] == '\'';
806
807 for (q = eq + 1 + quoted;; q++) {
392d5b37
LP
808
809 if (*q == 0) {
bc6422cb
LP
810
811 if (quoted) {
812 r = -EINVAL;
813 goto fail;
814 } else {
815 if (value)
816 value[j] = 0;
817 break;
818 }
392d5b37
LP
819 }
820
821 if (!escaped) {
822 if (*q == '\\') {
823 escaped = true;
824 continue;
825 }
bc6422cb
LP
826
827 if (quoted) {
828 if (*q == '\'') {
829 if (value)
830 value[j] = 0;
831 break;
832 }
833 } else {
834 if (*q == ',') {
835 if (value)
836 value[j] = 0;
837
838 break;
839 }
392d5b37
LP
840 }
841 }
842
2244a6fb 843 if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
392d5b37
LP
844 r = -ENOMEM;
845 goto fail;
846 }
847
848 value[j++] = *q;
849 escaped = false;
850 }
851
2c8d477a
LP
852 if (!value) {
853 value = strdup("");
854 if (!value) {
855 r = -ENOMEM;
856 goto fail;
857 }
858 }
859
392d5b37
LP
860 if (t == BUS_MATCH_MESSAGE_TYPE) {
861 r = bus_message_type_from_string(value, &u);
862 if (r < 0)
863 goto fail;
864
865 free(value);
866 value = NULL;
867 } else
868 u = 0;
869
2244a6fb 870 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
392d5b37
LP
871 r = -ENOMEM;
872 goto fail;
873 }
874
875 components[n_components].type = t;
876 components[n_components].value_str = value;
877 components[n_components].value_u8 = u;
878 n_components++;
879
880 value = NULL;
881
a3e648cc 882 if (q[quoted] == 0)
392d5b37
LP
883 break;
884
bc6422cb 885 if (q[quoted] != ',') {
392d5b37
LP
886 r = -EINVAL;
887 goto fail;
888 }
889
bc6422cb 890 p = q + 1 + quoted;
392d5b37
LP
891 }
892
893 /* Order the whole thing, so that we always generate the same tree */
7ff7394d 894 qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
392d5b37
LP
895
896 /* Check for duplicates */
897 for (i = 0; i+1 < n_components; i++)
898 if (components[i].type == components[i+1].type) {
899 r = -EINVAL;
900 goto fail;
901 }
902
903 *_components = components;
904 *_n_components = n_components;
905
906 return 0;
907
908fail:
c7819669 909 bus_match_parse_free(components, n_components);
392d5b37
LP
910 return r;
911}
912
53461b74
LP
913char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
914 _cleanup_free_ FILE *f = NULL;
915 char *buffer = NULL;
916 size_t size = 0;
917 unsigned i;
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 fflush(f);
947 if (ferror(f))
948 return NULL;
949
950 return buffer;
951}
952
392d5b37
LP
953int bus_match_add(
954 struct bus_match_node *root,
c7819669
LP
955 struct bus_match_component *components,
956 unsigned n_components,
19befb2d 957 struct match_callback *callback) {
392d5b37 958
c7819669 959 unsigned i;
392d5b37
LP
960 struct bus_match_node *n;
961 int r;
962
963 assert(root);
19befb2d 964 assert(callback);
392d5b37
LP
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)
c7819669 972 return r;
392d5b37
LP
973 }
974
19befb2d
LP
975 return bus_match_add_leaf(n, callback);
976}
392d5b37 977
19befb2d
LP
978int bus_match_remove(
979 struct bus_match_node *root,
980 struct match_callback *callback) {
392d5b37 981
19befb2d
LP
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;
392d5b37
LP
1009}
1010
19befb2d 1011int bus_match_find(
392d5b37 1012 struct bus_match_node *root,
c7819669
LP
1013 struct bus_match_component *components,
1014 unsigned n_components,
52f3ba91 1015 sd_bus_message_handler_t callback,
c7819669 1016 void *userdata,
19befb2d 1017 struct match_callback **ret) {
392d5b37 1018
392d5b37 1019 struct bus_match_node *n, **gc;
19befb2d 1020 unsigned i;
392d5b37
LP
1021 int r;
1022
1023 assert(root);
19befb2d 1024 assert(ret);
392d5b37
LP
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)
c7819669 1035 return r;
392d5b37
LP
1036
1037 gc[i] = n;
1038 }
1039
1040 r = bus_match_find_leaf(n, callback, userdata, &n);
1041 if (r <= 0)
c7819669
LP
1042 return r;
1043
19befb2d
LP
1044 *ret = n->leaf.callback;
1045 return 1;
392d5b37
LP
1046}
1047
1048void 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
1070const 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
1120void 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)
19befb2d 1139 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
392d5b37
LP
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}