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