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