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