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