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