chiark / gitweb /
Prep v230: Apply missing upstream fixes and updates (5/8) src/libelogind.
[elogind.git] / src / libelogind / sd-bus / bus-match.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include "alloc-util.h"
21 #include "bus-internal.h"
22 #include "bus-match.h"
23 #include "bus-message.h"
24 #include "bus-util.h"
25 #include "fd-util.h"
26 #include "fileio.h"
27 #include "hexdecoct.h"
28 #include "string-util.h"
29 #include "strv.h"
30
31 /* Example:
32  *
33  *  A: type=signal,sender=foo,interface=bar
34  *  B: type=signal,sender=quux,interface=fips
35  *  C: type=signal,sender=quux,interface=waldo
36  *  D: type=signal,member=test
37  *  E: sender=miau
38  *  F: type=signal
39  *  G: type=signal
40  *
41  *  results in this tree:
42  *
43  *  BUS_MATCH_ROOT
44  *  + BUS_MATCH_MESSAGE_TYPE
45  *  | ` BUS_MATCH_VALUE: value == signal
46  *  |   + DBUS_MATCH_SENDER
47  *  |   | + BUS_MATCH_VALUE: value == foo
48  *  |   | | ` DBUS_MATCH_INTERFACE
49  *  |   | |   ` BUS_MATCH_VALUE: value == bar
50  *  |   | |     ` BUS_MATCH_LEAF: A
51  *  |   | ` BUS_MATCH_VALUE: value == quux
52  *  |   |   ` DBUS_MATCH_INTERFACE
53  *  |   |     | BUS_MATCH_VALUE: value == fips
54  *  |   |     | ` BUS_MATCH_LEAF: B
55  *  |   |     ` BUS_MATCH_VALUE: value == waldo
56  *  |   |       ` BUS_MATCH_LEAF: C
57  *  |   + DBUS_MATCH_MEMBER
58  *  |   | ` BUS_MATCH_VALUE: value == test
59  *  |   |   ` BUS_MATCH_LEAF: D
60  *  |   + BUS_MATCH_LEAF: F
61  *  |   ` BUS_MATCH_LEAF: G
62  *  ` BUS_MATCH_SENDER
63  *    ` BUS_MATCH_VALUE: value == miau
64  *      ` BUS_MATCH_LEAF: E
65  */
66
67 static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
68         return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST;
69 }
70
71 static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
72         return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
73                 (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) ||
74                 (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST);
75 }
76
77 static void bus_match_node_free(struct bus_match_node *node) {
78         assert(node);
79         assert(node->parent);
80         assert(!node->child);
81         assert(node->type != BUS_MATCH_ROOT);
82         assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
83
84         if (node->parent->child) {
85                 /* We are apparently linked into the parent's child
86                  * list. Let's remove us from there. */
87                 if (node->prev) {
88                         assert(node->prev->next == node);
89                         node->prev->next = node->next;
90                 } else {
91                         assert(node->parent->child == node);
92                         node->parent->child = node->next;
93                 }
94
95                 if (node->next)
96                         node->next->prev = node->prev;
97         }
98
99         if (node->type == BUS_MATCH_VALUE) {
100                 /* We might be in the parent's hash table, so clean
101                  * this up */
102
103                 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
104                         hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
105                 else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
106                         hashmap_remove(node->parent->compare.children, node->value.str);
107
108                 free(node->value.str);
109         }
110
111         if (BUS_MATCH_IS_COMPARE(node->type)) {
112                 assert(hashmap_isempty(node->compare.children));
113                 hashmap_free(node->compare.children);
114         }
115
116         free(node);
117 }
118
119 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
120         assert(node);
121
122         if (node->type == BUS_MATCH_ROOT)
123                 return false;
124
125         if (node->child)
126                 return false;
127
128         if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
129                 return true;
130
131         bus_match_node_free(node);
132         return true;
133 }
134
135 static bool value_node_test(
136                 struct bus_match_node *node,
137                 enum bus_match_node_type parent_type,
138                 uint8_t value_u8,
139                 const char *value_str,
140                 char **value_strv,
141                 sd_bus_message *m) {
142
143         assert(node);
144         assert(node->type == BUS_MATCH_VALUE);
145
146         /* Tests parameters against this value node, doing prefix
147          * magic and stuff. */
148
149         switch (parent_type) {
150
151         case BUS_MATCH_MESSAGE_TYPE:
152                 return node->value.u8 == value_u8;
153
154         case BUS_MATCH_SENDER:
155                 if (streq_ptr(node->value.str, value_str))
156                         return true;
157
158                 if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
159                         char **i;
160
161                         /* on kdbus we have the well known names list
162                          * in the credentials, let's make use of that
163                          * for an accurate match */
164
165                         STRV_FOREACH(i, m->creds.well_known_names)
166                                 if (streq_ptr(node->value.str, *i))
167                                         return true;
168
169                 } else {
170
171                         /* If we don't have kdbus, we don't know the
172                          * well-known names of the senders. In that,
173                          * let's just hope that dbus-daemon doesn't
174                          * send us stuff we didn't want. */
175
176                         if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
177                                 return true;
178                 }
179
180                 return false;
181
182         case BUS_MATCH_DESTINATION:
183         case BUS_MATCH_INTERFACE:
184         case BUS_MATCH_MEMBER:
185         case BUS_MATCH_PATH:
186         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
187
188                 if (value_str)
189                         return streq_ptr(node->value.str, value_str);
190
191                 return false;
192
193         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: {
194                 char **i;
195
196                 STRV_FOREACH(i, value_strv)
197                         if (streq_ptr(node->value.str, *i))
198                                 return true;
199
200                 return false;
201         }
202
203         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
204                 if (value_str)
205                         return namespace_simple_pattern(node->value.str, value_str);
206
207                 return false;
208
209         case BUS_MATCH_PATH_NAMESPACE:
210                 return path_simple_pattern(node->value.str, value_str);
211
212         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
213                 if (value_str)
214                         return path_complex_pattern(node->value.str, value_str);
215
216                 return false;
217
218         default:
219                 assert_not_reached("Invalid node type");
220         }
221 }
222
223 static bool value_node_same(
224                 struct bus_match_node *node,
225                 enum bus_match_node_type parent_type,
226                 uint8_t value_u8,
227                 const char *value_str) {
228
229         /* Tests parameters against this value node, not doing prefix
230          * magic and stuff, i.e. this one actually compares the match
231          * itself. */
232
233         assert(node);
234         assert(node->type == BUS_MATCH_VALUE);
235
236         switch (parent_type) {
237
238         case BUS_MATCH_MESSAGE_TYPE:
239                 return node->value.u8 == value_u8;
240
241         case BUS_MATCH_SENDER:
242         case BUS_MATCH_DESTINATION:
243         case BUS_MATCH_INTERFACE:
244         case BUS_MATCH_MEMBER:
245         case BUS_MATCH_PATH:
246         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
247         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
248         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
249         case BUS_MATCH_PATH_NAMESPACE:
250         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
251                 return streq(node->value.str, value_str);
252
253         default:
254                 assert_not_reached("Invalid node type");
255         }
256 }
257
258 int bus_match_run(
259                 sd_bus *bus,
260                 struct bus_match_node *node,
261                 sd_bus_message *m) {
262
263         _cleanup_strv_free_ char **test_strv = NULL;
264         const char *test_str = NULL;
265         uint8_t test_u8 = 0;
266         int r;
267
268         assert(m);
269
270         if (!node)
271                 return 0;
272
273         if (bus && bus->match_callbacks_modified)
274                 return 0;
275
276         /* Not these special semantics: when traversing the tree we
277          * usually let bus_match_run() when called for a node
278          * recursively invoke bus_match_run(). There's are two
279          * exceptions here though, which are BUS_NODE_ROOT (which
280          * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
281          * are invoked anyway by its parent. */
282
283         switch (node->type) {
284
285         case BUS_MATCH_ROOT:
286
287                 /* Run all children. Since we cannot have any siblings
288                  * we won't call any. The children of the root node
289                  * are compares or leaves, they will automatically
290                  * call their siblings. */
291                 return bus_match_run(bus, node->child, m);
292
293         case BUS_MATCH_VALUE:
294
295                 /* Run all children. We don't execute any siblings, we
296                  * assume our caller does that. The children of value
297                  * nodes are compares or leaves, they will
298                  * automatically call their siblings */
299
300                 assert(node->child);
301                 return bus_match_run(bus, node->child, m);
302
303         case BUS_MATCH_LEAF:
304
305                 if (bus) {
306                         if (node->leaf.callback->last_iteration == bus->iteration_counter)
307                                 return 0;
308
309                         node->leaf.callback->last_iteration = bus->iteration_counter;
310                 }
311
312                 r = sd_bus_message_rewind(m, true);
313                 if (r < 0)
314                         return r;
315
316                 /* Run the callback. And then invoke siblings. */
317                 if (node->leaf.callback->callback) {
318                         _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
319                         sd_bus_slot *slot;
320
321                         slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
322                         if (bus) {
323                                 bus->current_slot = sd_bus_slot_ref(slot);
324                                 bus->current_handler = node->leaf.callback->callback;
325                                 bus->current_userdata = slot->userdata;
326                         }
327                         r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
328                         if (bus) {
329                                 bus->current_userdata = NULL;
330                                 bus->current_handler = NULL;
331                                 bus->current_slot = sd_bus_slot_unref(slot);
332                         }
333
334                         r = bus_maybe_reply_error(m, r, &error_buffer);
335                         if (r != 0)
336                                 return r;
337
338                         if (bus && bus->match_callbacks_modified)
339                                 return 0;
340                 }
341
342                 return bus_match_run(bus, node->next, m);
343
344         case BUS_MATCH_MESSAGE_TYPE:
345                 test_u8 = m->header->type;
346                 break;
347
348         case BUS_MATCH_SENDER:
349                 test_str = m->sender;
350                 /* FIXME: resolve test_str from a well-known to a unique name first */
351                 break;
352
353         case BUS_MATCH_DESTINATION:
354                 test_str = m->destination;
355                 break;
356
357         case BUS_MATCH_INTERFACE:
358                 test_str = m->interface;
359                 break;
360
361         case BUS_MATCH_MEMBER:
362                 test_str = m->member;
363                 break;
364
365         case BUS_MATCH_PATH:
366         case BUS_MATCH_PATH_NAMESPACE:
367                 test_str = m->path;
368                 break;
369
370         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
371                 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str);
372                 break;
373
374         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
375                 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str);
376                 break;
377
378         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
379                 (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str);
380                 break;
381
382         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
383                 (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &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         if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) {
747                 int j;
748
749                 j = undecchar(k[3]);
750                 if (j < 0)
751                         return -EINVAL;
752
753                 return BUS_MATCH_ARG_HAS + j;
754         }
755
756         if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) {
757                 enum bus_match_node_type t;
758                 int a, b;
759
760                 a = undecchar(k[3]);
761                 b = undecchar(k[4]);
762                 if (a <= 0 || b < 0)
763                         return -EINVAL;
764
765                 t = BUS_MATCH_ARG_HAS + a * 10 + b;
766                 if (t > BUS_MATCH_ARG_HAS_LAST)
767                         return -EINVAL;
768
769                 return t;
770         }
771
772         return -EINVAL;
773 }
774
775 static int match_component_compare(const void *a, const void *b) {
776         const struct bus_match_component *x = a, *y = b;
777
778         if (x->type < y->type)
779                 return -1;
780         if (x->type > y->type)
781                 return 1;
782
783         return 0;
784 }
785
786 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
787         unsigned i;
788
789         for (i = 0; i < n_components; i++)
790                 free(components[i].value_str);
791
792         free(components);
793 }
794
795 int bus_match_parse(
796                 const char *match,
797                 struct bus_match_component **_components,
798                 unsigned *_n_components) {
799
800         const char *p = match;
801         struct bus_match_component *components = NULL;
802         size_t components_allocated = 0;
803         unsigned n_components = 0, i;
804         _cleanup_free_ char *value = NULL;
805         int r;
806
807         assert(match);
808         assert(_components);
809         assert(_n_components);
810
811         while (*p != 0) {
812                 const char *eq, *q;
813                 enum bus_match_node_type t;
814                 unsigned j = 0;
815                 size_t value_allocated = 0;
816                 bool escaped = false, quoted;
817                 uint8_t u;
818
819                 /* Avahi's match rules appear to include whitespace, skip over it */
820                 p += strspn(p, " ");
821
822                 eq = strchr(p, '=');
823                 if (!eq)
824                         return -EINVAL;
825
826                 t = bus_match_node_type_from_string(p, eq - p);
827                 if (t < 0)
828                         return -EINVAL;
829
830                 quoted = eq[1] == '\'';
831
832                 for (q = eq + 1 + quoted;; q++) {
833
834                         if (*q == 0) {
835
836                                 if (quoted) {
837                                         r = -EINVAL;
838                                         goto fail;
839                                 } else {
840                                         if (value)
841                                                 value[j] = 0;
842                                         break;
843                                 }
844                         }
845
846                         if (!escaped) {
847                                 if (*q == '\\') {
848                                         escaped = true;
849                                         continue;
850                                 }
851
852                                 if (quoted) {
853                                         if (*q == '\'') {
854                                                 if (value)
855                                                         value[j] = 0;
856                                                 break;
857                                         }
858                                 } else {
859                                         if (*q == ',') {
860                                                 if (value)
861                                                         value[j] = 0;
862
863                                                 break;
864                                         }
865                                 }
866                         }
867
868                         if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
869                                 r = -ENOMEM;
870                                 goto fail;
871                         }
872
873                         value[j++] = *q;
874                         escaped = false;
875                 }
876
877                 if (!value) {
878                         value = strdup("");
879                         if (!value) {
880                                 r = -ENOMEM;
881                                 goto fail;
882                         }
883                 }
884
885                 if (t == BUS_MATCH_MESSAGE_TYPE) {
886                         r = bus_message_type_from_string(value, &u);
887                         if (r < 0)
888                                 goto fail;
889
890                         value = mfree(value);
891                 } else
892                         u = 0;
893
894                 if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
895                         r = -ENOMEM;
896                         goto fail;
897                 }
898
899                 components[n_components].type = t;
900                 components[n_components].value_str = value;
901                 components[n_components].value_u8 = u;
902                 n_components++;
903
904                 value = NULL;
905
906                 if (q[quoted] == 0)
907                         break;
908
909                 if (q[quoted] != ',') {
910                         r = -EINVAL;
911                         goto fail;
912                 }
913
914                 p = q + 1 + quoted;
915         }
916
917         /* Order the whole thing, so that we always generate the same tree */
918         qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
919
920         /* Check for duplicates */
921         for (i = 0; i+1 < n_components; i++)
922                 if (components[i].type == components[i+1].type) {
923                         r = -EINVAL;
924                         goto fail;
925                 }
926
927         *_components = components;
928         *_n_components = n_components;
929
930         return 0;
931
932 fail:
933         bus_match_parse_free(components, n_components);
934         return r;
935 }
936
937 #if 0 /// UNNEEDED by elogind
938 char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
939         _cleanup_fclose_ FILE *f = NULL;
940         char *buffer = NULL;
941         size_t size = 0;
942         unsigned i;
943         int r;
944
945         if (n_components <= 0)
946                 return strdup("");
947
948         assert(components);
949
950         f = open_memstream(&buffer, &size);
951         if (!f)
952                 return NULL;
953
954         for (i = 0; i < n_components; i++) {
955                 char buf[32];
956
957                 if (i != 0)
958                         fputc(',', f);
959
960                 fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
961                 fputc('=', f);
962                 fputc('\'', f);
963
964                 if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
965                         fputs(bus_message_type_to_string(components[i].value_u8), f);
966                 else
967                         fputs(components[i].value_str, f);
968
969                 fputc('\'', f);
970         }
971
972         r = fflush_and_check(f);
973         if (r < 0)
974                 return NULL;
975
976         return buffer;
977 }
978 #endif // 0
979
980 int bus_match_add(
981                 struct bus_match_node *root,
982                 struct bus_match_component *components,
983                 unsigned n_components,
984                 struct match_callback *callback) {
985
986         unsigned i;
987         struct bus_match_node *n;
988         int r;
989
990         assert(root);
991         assert(callback);
992
993         n = root;
994         for (i = 0; i < n_components; i++) {
995                 r = bus_match_add_compare_value(
996                                 n, components[i].type,
997                                 components[i].value_u8, components[i].value_str, &n);
998                 if (r < 0)
999                         return r;
1000         }
1001
1002         return bus_match_add_leaf(n, callback);
1003 }
1004
1005 int bus_match_remove(
1006                 struct bus_match_node *root,
1007                 struct match_callback *callback) {
1008
1009         struct bus_match_node *node, *pp;
1010
1011         assert(root);
1012         assert(callback);
1013
1014         node = callback->match_node;
1015         if (!node)
1016                 return 0;
1017
1018         assert(node->type == BUS_MATCH_LEAF);
1019
1020         callback->match_node = NULL;
1021
1022         /* Free the leaf */
1023         pp = node->parent;
1024         bus_match_node_free(node);
1025
1026         /* Prune the tree above */
1027         while (pp) {
1028                 node = pp;
1029                 pp = node->parent;
1030
1031                 if (!bus_match_node_maybe_free(node))
1032                         break;
1033         }
1034
1035         return 1;
1036 }
1037
1038 int bus_match_find(
1039                 struct bus_match_node *root,
1040                 struct bus_match_component *components,
1041                 unsigned n_components,
1042                 sd_bus_message_handler_t callback,
1043                 void *userdata,
1044                 struct match_callback **ret) {
1045
1046         struct bus_match_node *n, **gc;
1047         unsigned i;
1048         int r;
1049
1050         assert(root);
1051         assert(ret);
1052
1053         gc = newa(struct bus_match_node*, n_components);
1054
1055         n = root;
1056         for (i = 0; i < n_components; i++) {
1057                 r = bus_match_find_compare_value(
1058                                 n, components[i].type,
1059                                 components[i].value_u8, components[i].value_str,
1060                                 &n);
1061                 if (r <= 0)
1062                         return r;
1063
1064                 gc[i] = n;
1065         }
1066
1067         r = bus_match_find_leaf(n, callback, userdata, &n);
1068         if (r <= 0)
1069                 return r;
1070
1071         *ret = n->leaf.callback;
1072         return 1;
1073 }
1074
1075 void bus_match_free(struct bus_match_node *node) {
1076         struct bus_match_node *c;
1077
1078         if (!node)
1079                 return;
1080
1081         if (BUS_MATCH_CAN_HASH(node->type)) {
1082                 Iterator i;
1083
1084                 HASHMAP_FOREACH(c, node->compare.children, i)
1085                         bus_match_free(c);
1086
1087                 assert(hashmap_isempty(node->compare.children));
1088         }
1089
1090         while ((c = node->child))
1091                 bus_match_free(c);
1092
1093         if (node->type != BUS_MATCH_ROOT)
1094                 bus_match_node_free(node);
1095 }
1096
1097 const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
1098         switch (t) {
1099
1100         case BUS_MATCH_ROOT:
1101                 return "root";
1102
1103         case BUS_MATCH_VALUE:
1104                 return "value";
1105
1106         case BUS_MATCH_LEAF:
1107                 return "leaf";
1108
1109         case BUS_MATCH_MESSAGE_TYPE:
1110                 return "type";
1111
1112         case BUS_MATCH_SENDER:
1113                 return "sender";
1114
1115         case BUS_MATCH_DESTINATION:
1116                 return "destination";
1117
1118         case BUS_MATCH_INTERFACE:
1119                 return "interface";
1120
1121         case BUS_MATCH_MEMBER:
1122                 return "member";
1123
1124         case BUS_MATCH_PATH:
1125                 return "path";
1126
1127         case BUS_MATCH_PATH_NAMESPACE:
1128                 return "path_namespace";
1129
1130         case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
1131                 snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
1132                 return buf;
1133
1134         case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
1135                 snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
1136                 return buf;
1137
1138         case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
1139                 snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
1140                 return buf;
1141
1142         case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST:
1143                 snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS);
1144                 return buf;
1145
1146         default:
1147                 return NULL;
1148         }
1149 }
1150
1151 void bus_match_dump(struct bus_match_node *node, unsigned level) {
1152         struct bus_match_node *c;
1153         _cleanup_free_ char *pfx = NULL;
1154         char buf[32];
1155
1156         if (!node)
1157                 return;
1158
1159         pfx = strrep("  ", level);
1160         printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
1161
1162         if (node->type == BUS_MATCH_VALUE) {
1163                 if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
1164                         printf(" <%u>\n", node->value.u8);
1165                 else
1166                         printf(" <%s>\n", node->value.str);
1167         } else if (node->type == BUS_MATCH_ROOT)
1168                 puts(" root");
1169         else if (node->type == BUS_MATCH_LEAF)
1170                 printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
1171         else
1172                 putchar('\n');
1173
1174         if (BUS_MATCH_CAN_HASH(node->type)) {
1175                 Iterator i;
1176
1177                 HASHMAP_FOREACH(c, node->compare.children, i)
1178                         bus_match_dump(c, level + 1);
1179         }
1180
1181         for (c = node->child; c; c = c->next)
1182                 bus_match_dump(c, level + 1);
1183 }
1184
1185 enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
1186         bool found_driver = false;
1187         unsigned i;
1188
1189         if (n_components <= 0)
1190                 return BUS_MATCH_GENERIC;
1191
1192         assert(components);
1193
1194         /* Checks whether the specified match can only match the
1195          * pseudo-service for local messages, which we detect by
1196          * sender, interface or path. If a match is not restricted to
1197          * local messages, then we check if it only matches on the
1198          * driver. */
1199
1200         for (i = 0; i < n_components; i++) {
1201                 const struct bus_match_component *c = components + i;
1202
1203                 if (c->type == BUS_MATCH_SENDER) {
1204                         if (streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1205                                 return BUS_MATCH_LOCAL;
1206
1207                         if (streq_ptr(c->value_str, "org.freedesktop.DBus"))
1208                                 found_driver = true;
1209                 }
1210
1211                 if (c->type == BUS_MATCH_INTERFACE && streq_ptr(c->value_str, "org.freedesktop.DBus.Local"))
1212                         return BUS_MATCH_LOCAL;
1213
1214                 if (c->type == BUS_MATCH_PATH && streq_ptr(c->value_str, "/org/freedesktop/DBus/Local"))
1215                         return BUS_MATCH_LOCAL;
1216         }
1217
1218         return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC;
1219
1220 }