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