chiark / gitweb /
Add support for SD_BUS_DEFAULT*
[elogind.git] / src / libelogind / sd-bus / bus-objects.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2013 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "bus-internal.h"
23 #include "bus-introspect.h"
24 #include "bus-message.h"
25 #include "bus-objects.h"
26 #include "bus-signature.h"
27 #include "bus-slot.h"
28 #include "bus-type.h"
29 #include "bus-util.h"
30 #include "set.h"
31 #include "string-util.h"
32 #include "strv.h"
33
34 static int node_vtable_get_userdata(
35                 sd_bus *bus,
36                 const char *path,
37                 struct node_vtable *c,
38                 void **userdata,
39                 sd_bus_error *error) {
40
41         sd_bus_slot *s;
42         void *u, *found_u;
43         int r;
44
45         assert(bus);
46         assert(path);
47         assert(c);
48
49         s = container_of(c, sd_bus_slot, node_vtable);
50         u = s->userdata;
51         if (c->find) {
52                 bus->current_slot = sd_bus_slot_ref(s);
53                 bus->current_userdata = u;
54                 r = c->find(bus, path, c->interface, u, &found_u, error);
55                 bus->current_userdata = NULL;
56                 bus->current_slot = sd_bus_slot_unref(s);
57
58                 if (r < 0)
59                         return r;
60                 if (sd_bus_error_is_set(error))
61                         return -sd_bus_error_get_errno(error);
62                 if (r == 0)
63                         return r;
64         } else
65                 found_u = u;
66
67         if (userdata)
68                 *userdata = found_u;
69
70         return 1;
71 }
72
73 static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
74         assert(p);
75
76         return (uint8_t*) u + p->x.method.offset;
77 }
78
79 static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
80         assert(p);
81
82         return (uint8_t*) u + p->x.property.offset;
83 }
84
85 static int vtable_property_get_userdata(
86                 sd_bus *bus,
87                 const char *path,
88                 struct vtable_member *p,
89                 void **userdata,
90                 sd_bus_error *error) {
91
92         void *u;
93         int r;
94
95         assert(bus);
96         assert(path);
97         assert(p);
98         assert(userdata);
99
100         r = node_vtable_get_userdata(bus, path, p->parent, &u, error);
101         if (r <= 0)
102                 return r;
103         if (bus->nodes_modified)
104                 return 0;
105
106         *userdata = vtable_property_convert_userdata(p->vtable, u);
107         return 1;
108 }
109
110 static int add_enumerated_to_set(
111                 sd_bus *bus,
112                 const char *prefix,
113                 struct node_enumerator *first,
114                 Set *s,
115                 sd_bus_error *error) {
116
117         struct node_enumerator *c;
118         int r;
119
120         assert(bus);
121         assert(prefix);
122         assert(s);
123
124         LIST_FOREACH(enumerators, c, first) {
125                 char **children = NULL, **k;
126                 sd_bus_slot *slot;
127
128                 if (bus->nodes_modified)
129                         return 0;
130
131                 slot = container_of(c, sd_bus_slot, node_enumerator);
132
133                 bus->current_slot = sd_bus_slot_ref(slot);
134                 bus->current_userdata = slot->userdata;
135                 r = c->callback(bus, prefix, slot->userdata, &children, error);
136                 bus->current_userdata = NULL;
137                 bus->current_slot = sd_bus_slot_unref(slot);
138
139                 if (r < 0)
140                         return r;
141                 if (sd_bus_error_is_set(error))
142                         return -sd_bus_error_get_errno(error);
143
144                 STRV_FOREACH(k, children) {
145                         if (r < 0) {
146                                 free(*k);
147                                 continue;
148                         }
149
150                         if (!object_path_is_valid(*k)) {
151                                 free(*k);
152                                 r = -EINVAL;
153                                 continue;
154                         }
155
156                         if (!object_path_startswith(*k, prefix)) {
157                                 free(*k);
158                                 continue;
159                         }
160
161                         r = set_consume(s, *k);
162                         if (r == -EEXIST)
163                                 r = 0;
164                 }
165
166                 free(children);
167                 if (r < 0)
168                         return r;
169         }
170
171         return 0;
172 }
173
174 enum {
175         /* if set, add_subtree() works recursively */
176         CHILDREN_RECURSIVE              = (1U << 1),
177         /* if set, add_subtree() scans object-manager hierarchies recursively */
178         CHILDREN_SUBHIERARCHIES         = (1U << 0),
179 };
180
181 static int add_subtree_to_set(
182                 sd_bus *bus,
183                 const char *prefix,
184                 struct node *n,
185                 unsigned int flags,
186                 Set *s,
187                 sd_bus_error *error) {
188
189         struct node *i;
190         int r;
191
192         assert(bus);
193         assert(prefix);
194         assert(n);
195         assert(s);
196
197         r = add_enumerated_to_set(bus, prefix, n->enumerators, s, error);
198         if (r < 0)
199                 return r;
200         if (bus->nodes_modified)
201                 return 0;
202
203         LIST_FOREACH(siblings, i, n->child) {
204                 char *t;
205
206                 if (!object_path_startswith(i->path, prefix))
207                         continue;
208
209                 t = strdup(i->path);
210                 if (!t)
211                         return -ENOMEM;
212
213                 r = set_consume(s, t);
214                 if (r < 0 && r != -EEXIST)
215                         return r;
216
217                 if ((flags & CHILDREN_RECURSIVE) &&
218                     ((flags & CHILDREN_SUBHIERARCHIES) || !i->object_managers)) {
219                         r = add_subtree_to_set(bus, prefix, i, flags, s, error);
220                         if (r < 0)
221                                 return r;
222                         if (bus->nodes_modified)
223                                 return 0;
224                 }
225         }
226
227         return 0;
228 }
229
230 static int get_child_nodes(
231                 sd_bus *bus,
232                 const char *prefix,
233                 struct node *n,
234                 unsigned int flags,
235                 Set **_s,
236                 sd_bus_error *error) {
237
238         Set *s = NULL;
239         int r;
240
241         assert(bus);
242         assert(prefix);
243         assert(n);
244         assert(_s);
245
246         s = set_new(&string_hash_ops);
247         if (!s)
248                 return -ENOMEM;
249
250         r = add_subtree_to_set(bus, prefix, n, flags, s, error);
251         if (r < 0) {
252                 set_free_free(s);
253                 return r;
254         }
255
256         *_s = s;
257         return 0;
258 }
259
260 static int node_callbacks_run(
261                 sd_bus *bus,
262                 sd_bus_message *m,
263                 struct node_callback *first,
264                 bool require_fallback,
265                 bool *found_object) {
266
267         struct node_callback *c;
268         int r;
269
270         assert(bus);
271         assert(m);
272         assert(found_object);
273
274         LIST_FOREACH(callbacks, c, first) {
275                 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
276                 sd_bus_slot *slot;
277
278                 if (bus->nodes_modified)
279                         return 0;
280
281                 if (require_fallback && !c->is_fallback)
282                         continue;
283
284                 *found_object = true;
285
286                 if (c->last_iteration == bus->iteration_counter)
287                         continue;
288
289                 c->last_iteration = bus->iteration_counter;
290
291                 r = sd_bus_message_rewind(m, true);
292                 if (r < 0)
293                         return r;
294
295                 slot = container_of(c, sd_bus_slot, node_callback);
296
297                 bus->current_slot = sd_bus_slot_ref(slot);
298                 bus->current_handler = c->callback;
299                 bus->current_userdata = slot->userdata;
300                 r = c->callback(m, slot->userdata, &error_buffer);
301                 bus->current_userdata = NULL;
302                 bus->current_handler = NULL;
303                 bus->current_slot = sd_bus_slot_unref(slot);
304
305                 r = bus_maybe_reply_error(m, r, &error_buffer);
306                 if (r != 0)
307                         return r;
308         }
309
310         return 0;
311 }
312
313 #define CAPABILITY_SHIFT(x) (((x) >> __builtin_ctzll(_SD_BUS_VTABLE_CAPABILITY_MASK)) & 0xFFFF)
314
315 static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) {
316         uint64_t cap;
317         int r;
318
319         assert(bus);
320         assert(m);
321         assert(c);
322
323         /* If the entire bus is trusted let's grant access */
324         if (bus->trusted)
325                 return 0;
326
327         /* If the member is marked UNPRIVILEGED let's grant access */
328         if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED)
329                 return 0;
330
331         /* Check have the caller has the requested capability
332          * set. Note that the flags value contains the capability
333          * number plus one, which we need to subtract here. We do this
334          * so that we have 0 as special value for "default
335          * capability". */
336         cap = CAPABILITY_SHIFT(c->vtable->flags);
337         if (cap == 0)
338                 cap = CAPABILITY_SHIFT(c->parent->vtable[0].flags);
339         if (cap == 0)
340                 cap = CAP_SYS_ADMIN;
341         else
342                 cap--;
343
344         r = sd_bus_query_sender_privilege(m, cap);
345         if (r < 0)
346                 return r;
347         if (r > 0)
348                 return 0;
349
350         return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member);
351 }
352
353 static int method_callbacks_run(
354                 sd_bus *bus,
355                 sd_bus_message *m,
356                 struct vtable_member *c,
357                 bool require_fallback,
358                 bool *found_object) {
359
360         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
361         const char *signature;
362         void *u;
363         int r;
364
365         assert(bus);
366         assert(m);
367         assert(c);
368         assert(found_object);
369
370         if (require_fallback && !c->parent->is_fallback)
371                 return 0;
372
373         r = check_access(bus, m, c, &error);
374         if (r < 0)
375                 return bus_maybe_reply_error(m, r, &error);
376
377         r = node_vtable_get_userdata(bus, m->path, c->parent, &u, &error);
378         if (r <= 0)
379                 return bus_maybe_reply_error(m, r, &error);
380         if (bus->nodes_modified)
381                 return 0;
382
383         u = vtable_method_convert_userdata(c->vtable, u);
384
385         *found_object = true;
386
387         if (c->last_iteration == bus->iteration_counter)
388                 return 0;
389
390         c->last_iteration = bus->iteration_counter;
391
392         r = sd_bus_message_rewind(m, true);
393         if (r < 0)
394                 return r;
395
396         signature = sd_bus_message_get_signature(m, true);
397         if (!signature)
398                 return -EINVAL;
399
400         if (!streq(strempty(c->vtable->x.method.signature), signature))
401                 return sd_bus_reply_method_errorf(
402                                 m,
403                                 SD_BUS_ERROR_INVALID_ARGS,
404                                 "Invalid arguments '%s' to call %s.%s(), expecting '%s'.",
405                                 signature, c->interface, c->member, strempty(c->vtable->x.method.signature));
406
407         /* Keep track what the signature of the reply to this message
408          * should be, so that this can be enforced when sealing the
409          * reply. */
410         m->enforced_reply_signature = strempty(c->vtable->x.method.result);
411
412         if (c->vtable->x.method.handler) {
413                 sd_bus_slot *slot;
414
415                 slot = container_of(c->parent, sd_bus_slot, node_vtable);
416
417                 bus->current_slot = sd_bus_slot_ref(slot);
418                 bus->current_handler = c->vtable->x.method.handler;
419                 bus->current_userdata = u;
420                 r = c->vtable->x.method.handler(m, u, &error);
421                 bus->current_userdata = NULL;
422                 bus->current_handler = NULL;
423                 bus->current_slot = sd_bus_slot_unref(slot);
424
425                 return bus_maybe_reply_error(m, r, &error);
426         }
427
428         /* If the method callback is NULL, make this a successful NOP */
429         r = sd_bus_reply_method_return(m, NULL);
430         if (r < 0)
431                 return r;
432
433         return 1;
434 }
435
436 static int invoke_property_get(
437                 sd_bus *bus,
438                 sd_bus_slot *slot,
439                 const sd_bus_vtable *v,
440                 const char *path,
441                 const char *interface,
442                 const char *property,
443                 sd_bus_message *reply,
444                 void *userdata,
445                 sd_bus_error *error) {
446
447         const void *p;
448         int r;
449
450         assert(bus);
451         assert(slot);
452         assert(v);
453         assert(path);
454         assert(interface);
455         assert(property);
456         assert(reply);
457
458         if (v->x.property.get) {
459
460                 bus->current_slot = sd_bus_slot_ref(slot);
461                 bus->current_userdata = userdata;
462                 r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
463                 bus->current_userdata = NULL;
464                 bus->current_slot = sd_bus_slot_unref(slot);
465
466                 if (r < 0)
467                         return r;
468                 if (sd_bus_error_is_set(error))
469                         return -sd_bus_error_get_errno(error);
470                 return r;
471         }
472
473         /* Automatic handling if no callback is defined. */
474
475         if (streq(v->x.property.signature, "as"))
476                 return sd_bus_message_append_strv(reply, *(char***) userdata);
477
478         assert(signature_is_single(v->x.property.signature, false));
479         assert(bus_type_is_basic(v->x.property.signature[0]));
480
481         switch (v->x.property.signature[0]) {
482
483         case SD_BUS_TYPE_STRING:
484         case SD_BUS_TYPE_SIGNATURE:
485                 p = strempty(*(char**) userdata);
486                 break;
487
488         case SD_BUS_TYPE_OBJECT_PATH:
489                 p = *(char**) userdata;
490                 assert(p);
491                 break;
492
493         default:
494                 p = userdata;
495                 break;
496         }
497
498         return sd_bus_message_append_basic(reply, v->x.property.signature[0], p);
499 }
500
501 static int invoke_property_set(
502                 sd_bus *bus,
503                 sd_bus_slot *slot,
504                 const sd_bus_vtable *v,
505                 const char *path,
506                 const char *interface,
507                 const char *property,
508                 sd_bus_message *value,
509                 void *userdata,
510                 sd_bus_error *error) {
511
512         int r;
513
514         assert(bus);
515         assert(slot);
516         assert(v);
517         assert(path);
518         assert(interface);
519         assert(property);
520         assert(value);
521
522         if (v->x.property.set) {
523
524                 bus->current_slot = sd_bus_slot_ref(slot);
525                 bus->current_userdata = userdata;
526                 r = v->x.property.set(bus, path, interface, property, value, userdata, error);
527                 bus->current_userdata = NULL;
528                 bus->current_slot = sd_bus_slot_unref(slot);
529
530                 if (r < 0)
531                         return r;
532                 if (sd_bus_error_is_set(error))
533                         return -sd_bus_error_get_errno(error);
534                 return r;
535         }
536
537         /*  Automatic handling if no callback is defined. */
538
539         assert(signature_is_single(v->x.property.signature, false));
540         assert(bus_type_is_basic(v->x.property.signature[0]));
541
542         switch (v->x.property.signature[0]) {
543
544         case SD_BUS_TYPE_STRING:
545         case SD_BUS_TYPE_OBJECT_PATH:
546         case SD_BUS_TYPE_SIGNATURE: {
547                 const char *p;
548                 char *n;
549
550                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p);
551                 if (r < 0)
552                         return r;
553
554                 n = strdup(p);
555                 if (!n)
556                         return -ENOMEM;
557
558                 free(*(char**) userdata);
559                 *(char**) userdata = n;
560
561                 break;
562         }
563
564         default:
565                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata);
566                 if (r < 0)
567                         return r;
568
569                 break;
570         }
571
572         return 1;
573 }
574
575 static int property_get_set_callbacks_run(
576                 sd_bus *bus,
577                 sd_bus_message *m,
578                 struct vtable_member *c,
579                 bool require_fallback,
580                 bool is_get,
581                 bool *found_object) {
582
583         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
584         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
585         sd_bus_slot *slot;
586         void *u = NULL;
587         int r;
588
589         assert(bus);
590         assert(m);
591         assert(c);
592         assert(found_object);
593
594         if (require_fallback && !c->parent->is_fallback)
595                 return 0;
596
597         r = vtable_property_get_userdata(bus, m->path, c, &u, &error);
598         if (r <= 0)
599                 return bus_maybe_reply_error(m, r, &error);
600         if (bus->nodes_modified)
601                 return 0;
602
603         slot = container_of(c->parent, sd_bus_slot, node_vtable);
604
605         *found_object = true;
606
607         r = sd_bus_message_new_method_return(m, &reply);
608         if (r < 0)
609                 return r;
610
611         if (is_get) {
612                 /* Note that we do not protect against reexecution
613                  * here (using the last_iteration check, see below),
614                  * should the node tree have changed and we got called
615                  * again. We assume that property Get() calls are
616                  * ultimately without side-effects or if they aren't
617                  * then at least idempotent. */
618
619                 r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature);
620                 if (r < 0)
621                         return r;
622
623                 /* Note that we do not do an access check here. Read
624                  * access to properties is always unrestricted, since
625                  * PropertiesChanged signals broadcast contents
626                  * anyway. */
627
628                 r = invoke_property_get(bus, slot, c->vtable, m->path, c->interface, c->member, reply, u, &error);
629                 if (r < 0)
630                         return bus_maybe_reply_error(m, r, &error);
631
632                 if (bus->nodes_modified)
633                         return 0;
634
635                 r = sd_bus_message_close_container(reply);
636                 if (r < 0)
637                         return r;
638
639         } else {
640                 const char *signature = NULL;
641                 char type = 0;
642
643                 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
644                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
645
646                 /* Avoid that we call the set routine more than once
647                  * if the processing of this message got restarted
648                  * because the node tree changed. */
649                 if (c->last_iteration == bus->iteration_counter)
650                         return 0;
651
652                 c->last_iteration = bus->iteration_counter;
653
654                 r = sd_bus_message_peek_type(m, &type, &signature);
655                 if (r < 0)
656                         return r;
657
658                 if (type != 'v' || !streq(strempty(signature), strempty(c->vtable->x.property.signature)))
659                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Incorrect parameters for property '%s', expected '%s', got '%s'.", c->member, strempty(c->vtable->x.property.signature), strempty(signature));
660
661                 r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
662                 if (r < 0)
663                         return r;
664
665                 r = check_access(bus, m, c, &error);
666                 if (r < 0)
667                         return bus_maybe_reply_error(m, r, &error);
668
669                 r = invoke_property_set(bus, slot, c->vtable, m->path, c->interface, c->member, m, u, &error);
670                 if (r < 0)
671                         return bus_maybe_reply_error(m, r, &error);
672
673                 if (bus->nodes_modified)
674                         return 0;
675
676                 r = sd_bus_message_exit_container(m);
677                 if (r < 0)
678                         return r;
679         }
680
681         r = sd_bus_send(bus, reply, NULL);
682         if (r < 0)
683                 return r;
684
685         return 1;
686 }
687
688 static int vtable_append_one_property(
689                 sd_bus *bus,
690                 sd_bus_message *reply,
691                 const char *path,
692                 struct node_vtable *c,
693                 const sd_bus_vtable *v,
694                 void *userdata,
695                 sd_bus_error *error) {
696
697         sd_bus_slot *slot;
698         int r;
699
700         assert(bus);
701         assert(reply);
702         assert(path);
703         assert(c);
704         assert(v);
705
706         r = sd_bus_message_open_container(reply, 'e', "sv");
707         if (r < 0)
708                 return r;
709
710         r = sd_bus_message_append(reply, "s", v->x.property.member);
711         if (r < 0)
712                 return r;
713
714         r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
715         if (r < 0)
716                 return r;
717
718         slot = container_of(c, sd_bus_slot, node_vtable);
719
720         r = invoke_property_get(bus, slot, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
721         if (r < 0)
722                 return r;
723         if (bus->nodes_modified)
724                 return 0;
725
726         r = sd_bus_message_close_container(reply);
727         if (r < 0)
728                 return r;
729
730         r = sd_bus_message_close_container(reply);
731         if (r < 0)
732                 return r;
733
734         return 0;
735 }
736
737 static int vtable_append_all_properties(
738                 sd_bus *bus,
739                 sd_bus_message *reply,
740                 const char *path,
741                 struct node_vtable *c,
742                 void *userdata,
743                 sd_bus_error *error) {
744
745         const sd_bus_vtable *v;
746         int r;
747
748         assert(bus);
749         assert(reply);
750         assert(path);
751         assert(c);
752
753         if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
754                 return 1;
755
756         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
757                 if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
758                         continue;
759
760                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
761                         continue;
762
763                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
764                         continue;
765
766                 r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
767                 if (r < 0)
768                         return r;
769                 if (bus->nodes_modified)
770                         return 0;
771         }
772
773         return 1;
774 }
775
776 static int property_get_all_callbacks_run(
777                 sd_bus *bus,
778                 sd_bus_message *m,
779                 struct node_vtable *first,
780                 bool require_fallback,
781                 const char *iface,
782                 bool *found_object) {
783
784         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
785         struct node_vtable *c;
786         bool found_interface;
787         int r;
788
789         assert(bus);
790         assert(m);
791         assert(found_object);
792
793         r = sd_bus_message_new_method_return(m, &reply);
794         if (r < 0)
795                 return r;
796
797         r = sd_bus_message_open_container(reply, 'a', "{sv}");
798         if (r < 0)
799                 return r;
800
801         found_interface = !iface ||
802                 streq(iface, "org.freedesktop.DBus.Properties") ||
803                 streq(iface, "org.freedesktop.DBus.Peer") ||
804                 streq(iface, "org.freedesktop.DBus.Introspectable");
805
806         LIST_FOREACH(vtables, c, first) {
807                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
808                 void *u;
809
810                 if (require_fallback && !c->is_fallback)
811                         continue;
812
813                 r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
814                 if (r < 0)
815                         return bus_maybe_reply_error(m, r, &error);
816                 if (bus->nodes_modified)
817                         return 0;
818                 if (r == 0)
819                         continue;
820
821                 *found_object = true;
822
823                 if (iface && !streq(c->interface, iface))
824                         continue;
825                 found_interface = true;
826
827                 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
828                 if (r < 0)
829                         return bus_maybe_reply_error(m, r, &error);
830                 if (bus->nodes_modified)
831                         return 0;
832         }
833
834         if (!*found_object)
835                 return 0;
836
837         if (!found_interface) {
838                 r = sd_bus_reply_method_errorf(
839                                 m,
840                                 SD_BUS_ERROR_UNKNOWN_INTERFACE,
841                                 "Unknown interface '%s'.", iface);
842                 if (r < 0)
843                         return r;
844
845                 return 1;
846         }
847
848         r = sd_bus_message_close_container(reply);
849         if (r < 0)
850                 return r;
851
852         r = sd_bus_send(bus, reply, NULL);
853         if (r < 0)
854                 return r;
855
856         return 1;
857 }
858
859 static int bus_node_exists(
860                 sd_bus *bus,
861                 struct node *n,
862                 const char *path,
863                 bool require_fallback) {
864
865         struct node_vtable *c;
866         struct node_callback *k;
867         int r;
868
869         assert(bus);
870         assert(n);
871         assert(path);
872
873         /* Tests if there's anything attached directly to this node
874          * for the specified path */
875
876         if (!require_fallback && (n->enumerators || n->object_managers))
877                 return true;
878
879         LIST_FOREACH(callbacks, k, n->callbacks) {
880                 if (require_fallback && !k->is_fallback)
881                         continue;
882
883                 return 1;
884         }
885
886         LIST_FOREACH(vtables, c, n->vtables) {
887                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
888
889                 if (require_fallback && !c->is_fallback)
890                         continue;
891
892                 r = node_vtable_get_userdata(bus, path, c, NULL, &error);
893                 if (r != 0)
894                         return r;
895                 if (bus->nodes_modified)
896                         return 0;
897         }
898
899         return 0;
900 }
901
902 static int process_introspect(
903                 sd_bus *bus,
904                 sd_bus_message *m,
905                 struct node *n,
906                 bool require_fallback,
907                 bool *found_object) {
908
909         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
910         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
911         _cleanup_set_free_free_ Set *s = NULL;
912         const char *previous_interface = NULL;
913         struct introspect intro;
914         struct node_vtable *c;
915         bool empty;
916         int r;
917
918         assert(bus);
919         assert(m);
920         assert(n);
921         assert(found_object);
922
923         r = get_child_nodes(bus, m->path, n, 0, &s, &error);
924         if (r < 0)
925                 return bus_maybe_reply_error(m, r, &error);
926         if (bus->nodes_modified)
927                 return 0;
928
929         r = introspect_begin(&intro, bus->trusted);
930         if (r < 0)
931                 return r;
932
933         r = introspect_write_default_interfaces(&intro, !require_fallback && n->object_managers);
934         if (r < 0)
935                 return r;
936
937         empty = set_isempty(s);
938
939         LIST_FOREACH(vtables, c, n->vtables) {
940                 if (require_fallback && !c->is_fallback)
941                         continue;
942
943                 r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
944                 if (r < 0) {
945                         r = bus_maybe_reply_error(m, r, &error);
946                         goto finish;
947                 }
948                 if (bus->nodes_modified) {
949                         r = 0;
950                         goto finish;
951                 }
952                 if (r == 0)
953                         continue;
954
955                 empty = false;
956
957                 if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
958                         continue;
959
960                 if (!streq_ptr(previous_interface, c->interface)) {
961
962                         if (previous_interface)
963                                 fputs(" </interface>\n", intro.f);
964
965                         fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
966                 }
967
968                 r = introspect_write_interface(&intro, c->vtable);
969                 if (r < 0)
970                         goto finish;
971
972                 previous_interface = c->interface;
973         }
974
975         if (previous_interface)
976                 fputs(" </interface>\n", intro.f);
977
978         if (empty) {
979                 /* Nothing?, let's see if we exist at all, and if not
980                  * refuse to do anything */
981                 r = bus_node_exists(bus, n, m->path, require_fallback);
982                 if (r <= 0) {
983                         r = bus_maybe_reply_error(m, r, &error);
984                         goto finish;
985                 }
986                 if (bus->nodes_modified) {
987                         r = 0;
988                         goto finish;
989                 }
990         }
991
992         *found_object = true;
993
994         r = introspect_write_child_nodes(&intro, s, m->path);
995         if (r < 0)
996                 goto finish;
997
998         r = introspect_finish(&intro, bus, m, &reply);
999         if (r < 0)
1000                 goto finish;
1001
1002         r = sd_bus_send(bus, reply, NULL);
1003         if (r < 0)
1004                 goto finish;
1005
1006         r = 1;
1007
1008 finish:
1009         introspect_free(&intro);
1010         return r;
1011 }
1012
1013 static int object_manager_serialize_path(
1014                 sd_bus *bus,
1015                 sd_bus_message *reply,
1016                 const char *prefix,
1017                 const char *path,
1018                 bool require_fallback,
1019                 sd_bus_error *error) {
1020
1021         const char *previous_interface = NULL;
1022         bool found_something = false;
1023         struct node_vtable *i;
1024         struct node *n;
1025         int r;
1026
1027         assert(bus);
1028         assert(reply);
1029         assert(prefix);
1030         assert(path);
1031         assert(error);
1032
1033         n = hashmap_get(bus->nodes, prefix);
1034         if (!n)
1035                 return 0;
1036
1037         LIST_FOREACH(vtables, i, n->vtables) {
1038                 void *u;
1039
1040                 if (require_fallback && !i->is_fallback)
1041                         continue;
1042
1043                 r = node_vtable_get_userdata(bus, path, i, &u, error);
1044                 if (r < 0)
1045                         return r;
1046                 if (bus->nodes_modified)
1047                         return 0;
1048                 if (r == 0)
1049                         continue;
1050
1051                 if (!found_something) {
1052
1053                         /* Open the object part */
1054
1055                         r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
1056                         if (r < 0)
1057                                 return r;
1058
1059                         r = sd_bus_message_append(reply, "o", path);
1060                         if (r < 0)
1061                                 return r;
1062
1063                         r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
1064                         if (r < 0)
1065                                 return r;
1066
1067                         r = sd_bus_message_append(reply, "{sa{sv}}", "org.freedesktop.DBus.Peer", 0);
1068                         if (r < 0)
1069                                 return r;
1070
1071                         r = sd_bus_message_append(reply, "{sa{sv}}", "org.freedesktop.DBus.Introspectable", 0);
1072                         if (r < 0)
1073                                 return r;
1074
1075                         r = sd_bus_message_append(reply, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);
1076                         if (r < 0)
1077                                 return r;
1078
1079                         r = sd_bus_message_append(reply, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
1080                         if (r < 0)
1081                                 return r;
1082
1083                         found_something = true;
1084                 }
1085
1086                 if (!streq_ptr(previous_interface, i->interface)) {
1087
1088                         /* Maybe close the previous interface part */
1089
1090                         if (previous_interface) {
1091                                 r = sd_bus_message_close_container(reply);
1092                                 if (r < 0)
1093                                         return r;
1094
1095                                 r = sd_bus_message_close_container(reply);
1096                                 if (r < 0)
1097                                         return r;
1098                         }
1099
1100                         /* Open the new interface part */
1101
1102                         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
1103                         if (r < 0)
1104                                 return r;
1105
1106                         r = sd_bus_message_append(reply, "s", i->interface);
1107                         if (r < 0)
1108                                 return r;
1109
1110                         r = sd_bus_message_open_container(reply, 'a', "{sv}");
1111                         if (r < 0)
1112                                 return r;
1113                 }
1114
1115                 r = vtable_append_all_properties(bus, reply, path, i, u, error);
1116                 if (r < 0)
1117                         return r;
1118                 if (bus->nodes_modified)
1119                         return 0;
1120
1121                 previous_interface = i->interface;
1122         }
1123
1124         if (previous_interface) {
1125                 r = sd_bus_message_close_container(reply);
1126                 if (r < 0)
1127                         return r;
1128
1129                 r = sd_bus_message_close_container(reply);
1130                 if (r < 0)
1131                         return r;
1132         }
1133
1134         if (found_something) {
1135                 r = sd_bus_message_close_container(reply);
1136                 if (r < 0)
1137                         return r;
1138
1139                 r = sd_bus_message_close_container(reply);
1140                 if (r < 0)
1141                         return r;
1142         }
1143
1144         return 1;
1145 }
1146
1147 static int object_manager_serialize_path_and_fallbacks(
1148                 sd_bus *bus,
1149                 sd_bus_message *reply,
1150                 const char *path,
1151                 sd_bus_error *error) {
1152
1153         char *prefix;
1154         int r;
1155
1156         assert(bus);
1157         assert(reply);
1158         assert(path);
1159         assert(error);
1160
1161         /* First, add all vtables registered for this path */
1162         r = object_manager_serialize_path(bus, reply, path, path, false, error);
1163         if (r < 0)
1164                 return r;
1165         if (bus->nodes_modified)
1166                 return 0;
1167
1168         /* Second, add fallback vtables registered for any of the prefixes */
1169         prefix = alloca(strlen(path) + 1);
1170         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1171                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
1172                 if (r < 0)
1173                         return r;
1174                 if (bus->nodes_modified)
1175                         return 0;
1176         }
1177
1178         return 0;
1179 }
1180
1181 static int process_get_managed_objects(
1182                 sd_bus *bus,
1183                 sd_bus_message *m,
1184                 struct node *n,
1185                 bool require_fallback,
1186                 bool *found_object) {
1187
1188         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1189         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1190         _cleanup_set_free_free_ Set *s = NULL;
1191         Iterator i;
1192         char *path;
1193         int r;
1194
1195         assert(bus);
1196         assert(m);
1197         assert(n);
1198         assert(found_object);
1199
1200         /* Spec says, GetManagedObjects() is only implemented on the root of a
1201          * sub-tree. Therefore, we require a registered object-manager on
1202          * exactly the queried path, otherwise, we refuse to respond. */
1203
1204         if (require_fallback || !n->object_managers)
1205                 return 0;
1206
1207         r = get_child_nodes(bus, m->path, n, CHILDREN_RECURSIVE, &s, &error);
1208         if (r < 0)
1209                 return bus_maybe_reply_error(m, r, &error);
1210         if (bus->nodes_modified)
1211                 return 0;
1212
1213         r = sd_bus_message_new_method_return(m, &reply);
1214         if (r < 0)
1215                 return r;
1216
1217         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
1218         if (r < 0)
1219                 return r;
1220
1221         SET_FOREACH(path, s, i) {
1222                 r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
1223                 if (r < 0)
1224                         return bus_maybe_reply_error(m, r, &error);
1225
1226                 if (bus->nodes_modified)
1227                         return 0;
1228         }
1229
1230         r = sd_bus_message_close_container(reply);
1231         if (r < 0)
1232                 return r;
1233
1234         r = sd_bus_send(bus, reply, NULL);
1235         if (r < 0)
1236                 return r;
1237
1238         return 1;
1239 }
1240
1241 static int object_find_and_run(
1242                 sd_bus *bus,
1243                 sd_bus_message *m,
1244                 const char *p,
1245                 bool require_fallback,
1246                 bool *found_object) {
1247
1248         struct node *n;
1249         struct vtable_member vtable_key, *v;
1250         int r;
1251
1252         assert(bus);
1253         assert(m);
1254         assert(p);
1255         assert(found_object);
1256
1257         n = hashmap_get(bus->nodes, p);
1258         if (!n)
1259                 return 0;
1260
1261         /* First, try object callbacks */
1262         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
1263         if (r != 0)
1264                 return r;
1265         if (bus->nodes_modified)
1266                 return 0;
1267
1268         if (!m->interface || !m->member)
1269                 return 0;
1270
1271         /* Then, look for a known method */
1272         vtable_key.path = (char*) p;
1273         vtable_key.interface = m->interface;
1274         vtable_key.member = m->member;
1275
1276         v = hashmap_get(bus->vtable_methods, &vtable_key);
1277         if (v) {
1278                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1279                 if (r != 0)
1280                         return r;
1281                 if (bus->nodes_modified)
1282                         return 0;
1283         }
1284
1285         /* Then, look for a known property */
1286         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1287                 bool get = false;
1288
1289                 get = streq(m->member, "Get");
1290
1291                 if (get || streq(m->member, "Set")) {
1292
1293                         r = sd_bus_message_rewind(m, true);
1294                         if (r < 0)
1295                                 return r;
1296
1297                         vtable_key.path = (char*) p;
1298
1299                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1300                         if (r < 0)
1301                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
1302
1303                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1304                         if (v) {
1305                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1306                                 if (r != 0)
1307                                         return r;
1308                         }
1309
1310                 } else if (streq(m->member, "GetAll")) {
1311                         const char *iface;
1312
1313                         r = sd_bus_message_rewind(m, true);
1314                         if (r < 0)
1315                                 return r;
1316
1317                         r = sd_bus_message_read(m, "s", &iface);
1318                         if (r < 0)
1319                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
1320
1321                         if (iface[0] == 0)
1322                                 iface = NULL;
1323
1324                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1325                         if (r != 0)
1326                                 return r;
1327                 }
1328
1329         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1330
1331                 if (!isempty(sd_bus_message_get_signature(m, true)))
1332                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1333
1334                 r = process_introspect(bus, m, n, require_fallback, found_object);
1335                 if (r != 0)
1336                         return r;
1337
1338         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
1339
1340                 if (!isempty(sd_bus_message_get_signature(m, true)))
1341                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1342
1343                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
1344                 if (r != 0)
1345                         return r;
1346         }
1347
1348         if (bus->nodes_modified)
1349                 return 0;
1350
1351         if (!*found_object) {
1352                 r = bus_node_exists(bus, n, m->path, require_fallback);
1353                 if (r < 0)
1354                         return bus_maybe_reply_error(m, r, NULL);
1355                 if (bus->nodes_modified)
1356                         return 0;
1357                 if (r > 0)
1358                         *found_object = true;
1359         }
1360
1361         return 0;
1362 }
1363
1364 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1365         int r;
1366         size_t pl;
1367         bool found_object = false;
1368
1369         assert(bus);
1370         assert(m);
1371
1372         if (bus->is_monitor)
1373                 return 0;
1374
1375         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1376                 return 0;
1377
1378         if (hashmap_isempty(bus->nodes))
1379                 return 0;
1380
1381         /* Never respond to broadcast messages */
1382         if (bus->bus_client && !m->destination)
1383                 return 0;
1384
1385         assert(m->path);
1386         assert(m->member);
1387
1388         pl = strlen(m->path);
1389         do {
1390                 char prefix[pl+1];
1391
1392                 bus->nodes_modified = false;
1393
1394                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1395                 if (r != 0)
1396                         return r;
1397
1398                 /* Look for fallback prefixes */
1399                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1400
1401                         if (bus->nodes_modified)
1402                                 break;
1403
1404                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1405                         if (r != 0)
1406                                 return r;
1407                 }
1408
1409         } while (bus->nodes_modified);
1410
1411         if (!found_object)
1412                 return 0;
1413
1414         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1415             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1416                 r = sd_bus_reply_method_errorf(
1417                                 m,
1418                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
1419                                 "Unknown property or interface.");
1420         else
1421                 r = sd_bus_reply_method_errorf(
1422                                 m,
1423                                 SD_BUS_ERROR_UNKNOWN_METHOD,
1424                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1425
1426         if (r < 0)
1427                 return r;
1428
1429         return 1;
1430 }
1431
1432 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1433         struct node *n, *parent;
1434         const char *e;
1435         _cleanup_free_ char *s = NULL;
1436         char *p;
1437         int r;
1438
1439         assert(bus);
1440         assert(path);
1441         assert(path[0] == '/');
1442
1443         n = hashmap_get(bus->nodes, path);
1444         if (n)
1445                 return n;
1446
1447         r = hashmap_ensure_allocated(&bus->nodes, &string_hash_ops);
1448         if (r < 0)
1449                 return NULL;
1450
1451         s = strdup(path);
1452         if (!s)
1453                 return NULL;
1454
1455         if (streq(path, "/"))
1456                 parent = NULL;
1457         else {
1458                 e = strrchr(path, '/');
1459                 assert(e);
1460
1461                 p = strndupa(path, MAX(1, e - path));
1462
1463                 parent = bus_node_allocate(bus, p);
1464                 if (!parent)
1465                         return NULL;
1466         }
1467
1468         n = new0(struct node, 1);
1469         if (!n)
1470                 return NULL;
1471
1472         n->parent = parent;
1473         n->path = s;
1474         s = NULL; /* do not free */
1475
1476         r = hashmap_put(bus->nodes, n->path, n);
1477         if (r < 0) {
1478                 free(n->path);
1479                 return mfree(n);
1480         }
1481
1482         if (parent)
1483                 LIST_PREPEND(siblings, parent->child, n);
1484
1485         return n;
1486 }
1487
1488 void bus_node_gc(sd_bus *b, struct node *n) {
1489         assert(b);
1490
1491         if (!n)
1492                 return;
1493
1494         if (n->child ||
1495             n->callbacks ||
1496             n->vtables ||
1497             n->enumerators ||
1498             n->object_managers)
1499                 return;
1500
1501         assert_se(hashmap_remove(b->nodes, n->path) == n);
1502
1503         if (n->parent)
1504                 LIST_REMOVE(siblings, n->parent->child, n);
1505
1506         free(n->path);
1507         bus_node_gc(b, n->parent);
1508         free(n);
1509 }
1510
1511 static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) {
1512         struct node *n;
1513
1514         assert(bus);
1515         assert(path);
1516
1517         n = hashmap_get(bus->nodes, path);
1518         if (!n) {
1519                 char *prefix;
1520
1521                 prefix = alloca(strlen(path) + 1);
1522                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1523                         n = hashmap_get(bus->nodes, prefix);
1524                         if (n)
1525                                 break;
1526                 }
1527         }
1528
1529         while (n && !n->object_managers)
1530                 n = n->parent;
1531
1532         if (out)
1533                 *out = n;
1534         return !!n;
1535 }
1536
1537 static int bus_add_object(
1538                 sd_bus *bus,
1539                 sd_bus_slot **slot,
1540                 bool fallback,
1541                 const char *path,
1542                 sd_bus_message_handler_t callback,
1543                 void *userdata) {
1544
1545         sd_bus_slot *s;
1546         struct node *n;
1547         int r;
1548
1549         assert_return(bus, -EINVAL);
1550         assert_return(bus = bus_resolve(bus), -ENOPKG);
1551         assert_return(object_path_is_valid(path), -EINVAL);
1552         assert_return(callback, -EINVAL);
1553         assert_return(!bus_pid_changed(bus), -ECHILD);
1554
1555         n = bus_node_allocate(bus, path);
1556         if (!n)
1557                 return -ENOMEM;
1558
1559         s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
1560         if (!s) {
1561                 r = -ENOMEM;
1562                 goto fail;
1563         }
1564
1565         s->node_callback.callback = callback;
1566         s->node_callback.is_fallback = fallback;
1567
1568         s->node_callback.node = n;
1569         LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
1570         bus->nodes_modified = true;
1571
1572         if (slot)
1573                 *slot = s;
1574
1575         return 0;
1576
1577 fail:
1578         sd_bus_slot_unref(s);
1579         bus_node_gc(bus, n);
1580
1581         return r;
1582 }
1583
1584 _public_ int sd_bus_add_object(
1585                 sd_bus *bus,
1586                 sd_bus_slot **slot,
1587                 const char *path,
1588                 sd_bus_message_handler_t callback,
1589                 void *userdata) {
1590
1591         return bus_add_object(bus, slot, false, path, callback, userdata);
1592 }
1593
1594 _public_ int sd_bus_add_fallback(
1595                 sd_bus *bus,
1596                 sd_bus_slot **slot,
1597                 const char *prefix,
1598                 sd_bus_message_handler_t callback,
1599                 void *userdata) {
1600
1601         return bus_add_object(bus, slot, true, prefix, callback, userdata);
1602 }
1603
1604 static void vtable_member_hash_func(const void *a, struct siphash *state) {
1605         const struct vtable_member *m = a;
1606
1607         assert(m);
1608
1609         string_hash_func(m->path, state);
1610         string_hash_func(m->interface, state);
1611         string_hash_func(m->member, state);
1612 }
1613
1614 static int vtable_member_compare_func(const void *a, const void *b) {
1615         const struct vtable_member *x = a, *y = b;
1616         int r;
1617
1618         assert(x);
1619         assert(y);
1620
1621         r = strcmp(x->path, y->path);
1622         if (r != 0)
1623                 return r;
1624
1625         r = strcmp(x->interface, y->interface);
1626         if (r != 0)
1627                 return r;
1628
1629         return strcmp(x->member, y->member);
1630 }
1631
1632 static const struct hash_ops vtable_member_hash_ops = {
1633         .hash = vtable_member_hash_func,
1634         .compare = vtable_member_compare_func
1635 };
1636
1637 static int add_object_vtable_internal(
1638                 sd_bus *bus,
1639                 sd_bus_slot **slot,
1640                 const char *path,
1641                 const char *interface,
1642                 const sd_bus_vtable *vtable,
1643                 bool fallback,
1644                 sd_bus_object_find_t find,
1645                 void *userdata) {
1646
1647         sd_bus_slot *s = NULL;
1648         struct node_vtable *i, *existing = NULL;
1649         const sd_bus_vtable *v;
1650         struct node *n;
1651         int r;
1652
1653         assert_return(bus, -EINVAL);
1654         assert_return(bus = bus_resolve(bus), -ENOPKG);
1655         assert_return(object_path_is_valid(path), -EINVAL);
1656         assert_return(interface_name_is_valid(interface), -EINVAL);
1657         assert_return(vtable, -EINVAL);
1658         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1659         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1660         assert_return(!bus_pid_changed(bus), -ECHILD);
1661         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1662                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1663                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1664                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1665
1666         r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops);
1667         if (r < 0)
1668                 return r;
1669
1670         r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops);
1671         if (r < 0)
1672                 return r;
1673
1674         n = bus_node_allocate(bus, path);
1675         if (!n)
1676                 return -ENOMEM;
1677
1678         LIST_FOREACH(vtables, i, n->vtables) {
1679                 if (i->is_fallback != fallback) {
1680                         r = -EPROTOTYPE;
1681                         goto fail;
1682                 }
1683
1684                 if (streq(i->interface, interface)) {
1685
1686                         if (i->vtable == vtable) {
1687                                 r = -EEXIST;
1688                                 goto fail;
1689                         }
1690
1691                         existing = i;
1692                 }
1693         }
1694
1695         s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
1696         if (!s) {
1697                 r = -ENOMEM;
1698                 goto fail;
1699         }
1700
1701         s->node_vtable.is_fallback = fallback;
1702         s->node_vtable.vtable = vtable;
1703         s->node_vtable.find = find;
1704
1705         s->node_vtable.interface = strdup(interface);
1706         if (!s->node_vtable.interface) {
1707                 r = -ENOMEM;
1708                 goto fail;
1709         }
1710
1711         for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1712
1713                 switch (v->type) {
1714
1715                 case _SD_BUS_VTABLE_METHOD: {
1716                         struct vtable_member *m;
1717
1718                         if (!member_name_is_valid(v->x.method.member) ||
1719                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1720                             !signature_is_valid(strempty(v->x.method.result), false) ||
1721                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1722                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1723                                 r = -EINVAL;
1724                                 goto fail;
1725                         }
1726
1727                         m = new0(struct vtable_member, 1);
1728                         if (!m) {
1729                                 r = -ENOMEM;
1730                                 goto fail;
1731                         }
1732
1733                         m->parent = &s->node_vtable;
1734                         m->path = n->path;
1735                         m->interface = s->node_vtable.interface;
1736                         m->member = v->x.method.member;
1737                         m->vtable = v;
1738
1739                         r = hashmap_put(bus->vtable_methods, m, m);
1740                         if (r < 0) {
1741                                 free(m);
1742                                 goto fail;
1743                         }
1744
1745                         break;
1746                 }
1747
1748                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1749
1750                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1751                                 r = -EINVAL;
1752                                 goto fail;
1753                         }
1754
1755                         if (v->flags & SD_BUS_VTABLE_PROPERTY_CONST) {
1756                                 r = -EINVAL;
1757                                 goto fail;
1758                         }
1759
1760                         _fallthrough_;
1761                 case _SD_BUS_VTABLE_PROPERTY: {
1762                         struct vtable_member *m;
1763
1764                         if (!member_name_is_valid(v->x.property.member) ||
1765                             !signature_is_single(v->x.property.signature, false) ||
1766                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1767                             (v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ||
1768                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
1769                             ((v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) && (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)) ||
1770                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1771                                 r = -EINVAL;
1772                                 goto fail;
1773                         }
1774
1775                         m = new0(struct vtable_member, 1);
1776                         if (!m) {
1777                                 r = -ENOMEM;
1778                                 goto fail;
1779                         }
1780
1781                         m->parent = &s->node_vtable;
1782                         m->path = n->path;
1783                         m->interface = s->node_vtable.interface;
1784                         m->member = v->x.property.member;
1785                         m->vtable = v;
1786
1787                         r = hashmap_put(bus->vtable_properties, m, m);
1788                         if (r < 0) {
1789                                 free(m);
1790                                 goto fail;
1791                         }
1792
1793                         break;
1794                 }
1795
1796                 case _SD_BUS_VTABLE_SIGNAL:
1797
1798                         if (!member_name_is_valid(v->x.signal.member) ||
1799                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1800                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1801                                 r = -EINVAL;
1802                                 goto fail;
1803                         }
1804
1805                         break;
1806
1807                 default:
1808                         r = -EINVAL;
1809                         goto fail;
1810                 }
1811         }
1812
1813         s->node_vtable.node = n;
1814         LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
1815         bus->nodes_modified = true;
1816
1817         if (slot)
1818                 *slot = s;
1819
1820         return 0;
1821
1822 fail:
1823         sd_bus_slot_unref(s);
1824         bus_node_gc(bus, n);
1825
1826         return r;
1827 }
1828
1829 _public_ int sd_bus_add_object_vtable(
1830                 sd_bus *bus,
1831                 sd_bus_slot **slot,
1832                 const char *path,
1833                 const char *interface,
1834                 const sd_bus_vtable *vtable,
1835                 void *userdata) {
1836
1837         return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
1838 }
1839
1840 _public_ int sd_bus_add_fallback_vtable(
1841                 sd_bus *bus,
1842                 sd_bus_slot **slot,
1843                 const char *prefix,
1844                 const char *interface,
1845                 const sd_bus_vtable *vtable,
1846                 sd_bus_object_find_t find,
1847                 void *userdata) {
1848
1849         return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
1850 }
1851
1852 _public_ int sd_bus_add_node_enumerator(
1853                 sd_bus *bus,
1854                 sd_bus_slot **slot,
1855                 const char *path,
1856                 sd_bus_node_enumerator_t callback,
1857                 void *userdata) {
1858
1859         sd_bus_slot *s;
1860         struct node *n;
1861         int r;
1862
1863         assert_return(bus, -EINVAL);
1864         assert_return(bus = bus_resolve(bus), -ENOPKG);
1865         assert_return(object_path_is_valid(path), -EINVAL);
1866         assert_return(callback, -EINVAL);
1867         assert_return(!bus_pid_changed(bus), -ECHILD);
1868
1869         n = bus_node_allocate(bus, path);
1870         if (!n)
1871                 return -ENOMEM;
1872
1873         s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
1874         if (!s) {
1875                 r = -ENOMEM;
1876                 goto fail;
1877         }
1878
1879         s->node_enumerator.callback = callback;
1880
1881         s->node_enumerator.node = n;
1882         LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
1883         bus->nodes_modified = true;
1884
1885         if (slot)
1886                 *slot = s;
1887
1888         return 0;
1889
1890 fail:
1891         sd_bus_slot_unref(s);
1892         bus_node_gc(bus, n);
1893
1894         return r;
1895 }
1896
1897 static int emit_properties_changed_on_interface(
1898                 sd_bus *bus,
1899                 const char *prefix,
1900                 const char *path,
1901                 const char *interface,
1902                 bool require_fallback,
1903                 bool *found_interface,
1904                 char **names) {
1905
1906         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1907         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1908         bool has_invalidating = false, has_changing = false;
1909         struct vtable_member key = {};
1910         struct node_vtable *c;
1911         struct node *n;
1912         char **property;
1913         void *u = NULL;
1914         int r;
1915
1916         assert(bus);
1917         assert(prefix);
1918         assert(path);
1919         assert(interface);
1920         assert(found_interface);
1921
1922         n = hashmap_get(bus->nodes, prefix);
1923         if (!n)
1924                 return 0;
1925
1926         r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
1927         if (r < 0)
1928                 return r;
1929
1930         r = sd_bus_message_append(m, "s", interface);
1931         if (r < 0)
1932                 return r;
1933
1934         r = sd_bus_message_open_container(m, 'a', "{sv}");
1935         if (r < 0)
1936                 return r;
1937
1938         key.path = prefix;
1939         key.interface = interface;
1940
1941         LIST_FOREACH(vtables, c, n->vtables) {
1942                 if (require_fallback && !c->is_fallback)
1943                         continue;
1944
1945                 if (!streq(c->interface, interface))
1946                         continue;
1947
1948                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
1949                 if (r < 0)
1950                         return r;
1951                 if (bus->nodes_modified)
1952                         return 0;
1953                 if (r == 0)
1954                         continue;
1955
1956                 *found_interface = true;
1957
1958                 if (names) {
1959                         /* If the caller specified a list of
1960                          * properties we include exactly those in the
1961                          * PropertiesChanged message */
1962
1963                         STRV_FOREACH(property, names) {
1964                                 struct vtable_member *v;
1965
1966                                 assert_return(member_name_is_valid(*property), -EINVAL);
1967
1968                                 key.member = *property;
1969                                 v = hashmap_get(bus->vtable_properties, &key);
1970                                 if (!v)
1971                                         return -ENOENT;
1972
1973                                 /* If there are two vtables for the same
1974                                  * interface, let's handle this property when
1975                                  * we come to that vtable. */
1976                                 if (c != v->parent)
1977                                         continue;
1978
1979                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
1980                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
1981
1982                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
1983
1984                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
1985                                         has_invalidating = true;
1986                                         continue;
1987                                 }
1988
1989                                 has_changing = true;
1990
1991                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
1992                                 if (r < 0)
1993                                         return r;
1994                                 if (bus->nodes_modified)
1995                                         return 0;
1996                         }
1997                 } else {
1998                         const sd_bus_vtable *v;
1999
2000                         /* If the caller specified no properties list
2001                          * we include all properties that are marked
2002                          * as changing in the message. */
2003
2004                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2005                                 if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
2006                                         continue;
2007
2008                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
2009                                         continue;
2010
2011                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2012                                         has_invalidating = true;
2013                                         continue;
2014                                 }
2015
2016                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
2017                                         continue;
2018
2019                                 has_changing = true;
2020
2021                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
2022                                 if (r < 0)
2023                                         return r;
2024                                 if (bus->nodes_modified)
2025                                         return 0;
2026                         }
2027                 }
2028         }
2029
2030         if (!has_invalidating && !has_changing)
2031                 return 0;
2032
2033         r = sd_bus_message_close_container(m);
2034         if (r < 0)
2035                 return r;
2036
2037         r = sd_bus_message_open_container(m, 'a', "s");
2038         if (r < 0)
2039                 return r;
2040
2041         if (has_invalidating) {
2042                 LIST_FOREACH(vtables, c, n->vtables) {
2043                         if (require_fallback && !c->is_fallback)
2044                                 continue;
2045
2046                         if (!streq(c->interface, interface))
2047                                 continue;
2048
2049                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
2050                         if (r < 0)
2051                                 return r;
2052                         if (bus->nodes_modified)
2053                                 return 0;
2054                         if (r == 0)
2055                                 continue;
2056
2057                         if (names) {
2058                                 STRV_FOREACH(property, names) {
2059                                         struct vtable_member *v;
2060
2061                                         key.member = *property;
2062                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
2063                                         assert(c == v->parent);
2064
2065                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2066                                                 continue;
2067
2068                                         r = sd_bus_message_append(m, "s", *property);
2069                                         if (r < 0)
2070                                                 return r;
2071                                 }
2072                         } else {
2073                                 const sd_bus_vtable *v;
2074
2075                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2076                                         if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
2077                                                 continue;
2078
2079                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
2080                                                 continue;
2081
2082                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2083                                                 continue;
2084
2085                                         r = sd_bus_message_append(m, "s", v->x.property.member);
2086                                         if (r < 0)
2087                                                 return r;
2088                                 }
2089                         }
2090                 }
2091         }
2092
2093         r = sd_bus_message_close_container(m);
2094         if (r < 0)
2095                 return r;
2096
2097         r = sd_bus_send(bus, m, NULL);
2098         if (r < 0)
2099                 return r;
2100
2101         return 1;
2102 }
2103
2104 _public_ int sd_bus_emit_properties_changed_strv(
2105                 sd_bus *bus,
2106                 const char *path,
2107                 const char *interface,
2108                 char **names) {
2109
2110         BUS_DONT_DESTROY(bus);
2111         bool found_interface = false;
2112         char *prefix;
2113         int r;
2114
2115         assert_return(bus, -EINVAL);
2116         assert_return(bus = bus_resolve(bus), -ENOPKG);
2117         assert_return(object_path_is_valid(path), -EINVAL);
2118         assert_return(interface_name_is_valid(interface), -EINVAL);
2119         assert_return(!bus_pid_changed(bus), -ECHILD);
2120
2121         if (!BUS_IS_OPEN(bus->state))
2122                 return -ENOTCONN;
2123
2124         /* A non-NULL but empty names list means nothing needs to be
2125            generated. A NULL list OTOH indicates that all properties
2126            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2127            included in the PropertiesChanged message. */
2128         if (names && names[0] == NULL)
2129                 return 0;
2130
2131         do {
2132                 bus->nodes_modified = false;
2133
2134                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
2135                 if (r != 0)
2136                         return r;
2137                 if (bus->nodes_modified)
2138                         continue;
2139
2140                 prefix = alloca(strlen(path) + 1);
2141                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2142                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
2143                         if (r != 0)
2144                                 return r;
2145                         if (bus->nodes_modified)
2146                                 break;
2147                 }
2148
2149         } while (bus->nodes_modified);
2150
2151         return found_interface ? 0 : -ENOENT;
2152 }
2153
2154 _public_ int sd_bus_emit_properties_changed(
2155                 sd_bus *bus,
2156                 const char *path,
2157                 const char *interface,
2158                 const char *name, ...)  {
2159
2160         char **names;
2161
2162         assert_return(bus, -EINVAL);
2163         assert_return(bus = bus_resolve(bus), -ENOPKG);
2164         assert_return(object_path_is_valid(path), -EINVAL);
2165         assert_return(interface_name_is_valid(interface), -EINVAL);
2166         assert_return(!bus_pid_changed(bus), -ECHILD);
2167
2168         if (!BUS_IS_OPEN(bus->state))
2169                 return -ENOTCONN;
2170
2171         if (!name)
2172                 return 0;
2173
2174         names = strv_from_stdarg_alloca(name);
2175
2176         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2177 }
2178
2179 static int object_added_append_all_prefix(
2180                 sd_bus *bus,
2181                 sd_bus_message *m,
2182                 Set *s,
2183                 const char *prefix,
2184                 const char *path,
2185                 bool require_fallback) {
2186
2187         const char *previous_interface = NULL;
2188         struct node_vtable *c;
2189         struct node *n;
2190         int r;
2191
2192         assert(bus);
2193         assert(m);
2194         assert(s);
2195         assert(prefix);
2196         assert(path);
2197
2198         n = hashmap_get(bus->nodes, prefix);
2199         if (!n)
2200                 return 0;
2201
2202         LIST_FOREACH(vtables, c, n->vtables) {
2203                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2204                 void *u = NULL;
2205
2206                 if (require_fallback && !c->is_fallback)
2207                         continue;
2208
2209                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2210                 if (r < 0)
2211                         return r;
2212                 if (bus->nodes_modified)
2213                         return 0;
2214                 if (r == 0)
2215                         continue;
2216
2217                 if (!streq_ptr(c->interface, previous_interface)) {
2218                         /* If a child-node already handled this interface, we
2219                          * skip it on any of its parents. The child vtables
2220                          * always fully override any conflicting vtables of
2221                          * any parent node. */
2222                         if (set_get(s, c->interface))
2223                                 continue;
2224
2225                         r = set_put(s, c->interface);
2226                         if (r < 0)
2227                                 return r;
2228
2229                         if (previous_interface) {
2230                                 r = sd_bus_message_close_container(m);
2231                                 if (r < 0)
2232                                         return r;
2233                                 r = sd_bus_message_close_container(m);
2234                                 if (r < 0)
2235                                         return r;
2236                         }
2237
2238                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2239                         if (r < 0)
2240                                 return r;
2241                         r = sd_bus_message_append(m, "s", c->interface);
2242                         if (r < 0)
2243                                 return r;
2244                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2245                         if (r < 0)
2246                                 return r;
2247
2248                         previous_interface = c->interface;
2249                 }
2250
2251                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2252                 if (r < 0)
2253                         return r;
2254                 if (bus->nodes_modified)
2255                         return 0;
2256         }
2257
2258         if (previous_interface) {
2259                 r = sd_bus_message_close_container(m);
2260                 if (r < 0)
2261                         return r;
2262                 r = sd_bus_message_close_container(m);
2263                 if (r < 0)
2264                         return r;
2265         }
2266
2267         return 0;
2268 }
2269
2270 static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2271         _cleanup_set_free_ Set *s = NULL;
2272         char *prefix;
2273         int r;
2274
2275         assert(bus);
2276         assert(m);
2277         assert(path);
2278
2279         /*
2280          * This appends all interfaces registered on path @path. We first add
2281          * the builtin interfaces, which are always available and handled by
2282          * sd-bus. Then, we add all interfaces registered on the exact node,
2283          * followed by all fallback interfaces registered on any parent prefix.
2284          *
2285          * If an interface is registered multiple times on the same node with
2286          * different vtables, we merge all the properties across all vtables.
2287          * However, if a child node has the same interface registered as one of
2288          * its parent nodes has as fallback, we make the child overwrite the
2289          * parent instead of extending it. Therefore, we keep a "Set" of all
2290          * handled interfaces during parent traversal, so we skip interfaces on
2291          * a parent that were overwritten by a child.
2292          */
2293
2294         s = set_new(&string_hash_ops);
2295         if (!s)
2296                 return -ENOMEM;
2297
2298         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Peer", 0);
2299         if (r < 0)
2300                 return r;
2301         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Introspectable", 0);
2302         if (r < 0)
2303                 return r;
2304         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);
2305         if (r < 0)
2306                 return r;
2307         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
2308         if (r < 0)
2309                 return r;
2310
2311         r = object_added_append_all_prefix(bus, m, s, path, path, false);
2312         if (r < 0)
2313                 return r;
2314         if (bus->nodes_modified)
2315                 return 0;
2316
2317         prefix = alloca(strlen(path) + 1);
2318         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2319                 r = object_added_append_all_prefix(bus, m, s, prefix, path, true);
2320                 if (r < 0)
2321                         return r;
2322                 if (bus->nodes_modified)
2323                         return 0;
2324         }
2325
2326         return 0;
2327 }
2328
2329 _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
2330         BUS_DONT_DESTROY(bus);
2331
2332         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2333         struct node *object_manager;
2334         int r;
2335
2336         /*
2337          * This emits an InterfacesAdded signal on the given path, by iterating
2338          * all registered vtables and fallback vtables on the path. All
2339          * properties are queried and included in the signal.
2340          * This call is equivalent to sd_bus_emit_interfaces_added() with an
2341          * explicit list of registered interfaces. However, unlike
2342          * interfaces_added(), this call can figure out the list of supported
2343          * interfaces itself. Furthermore, it properly adds the builtin
2344          * org.freedesktop.DBus.* interfaces.
2345          */
2346
2347         assert_return(bus, -EINVAL);
2348         assert_return(bus = bus_resolve(bus), -ENOPKG);
2349         assert_return(object_path_is_valid(path), -EINVAL);
2350         assert_return(!bus_pid_changed(bus), -ECHILD);
2351
2352         if (!BUS_IS_OPEN(bus->state))
2353                 return -ENOTCONN;
2354
2355         r = bus_find_parent_object_manager(bus, &object_manager, path);
2356         if (r < 0)
2357                 return r;
2358         if (r == 0)
2359                 return -ESRCH;
2360
2361         do {
2362                 bus->nodes_modified = false;
2363                 m = sd_bus_message_unref(m);
2364
2365                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2366                 if (r < 0)
2367                         return r;
2368
2369                 r = sd_bus_message_append_basic(m, 'o', path);
2370                 if (r < 0)
2371                         return r;
2372
2373                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2374                 if (r < 0)
2375                         return r;
2376
2377                 r = object_added_append_all(bus, m, path);
2378                 if (r < 0)
2379                         return r;
2380
2381                 if (bus->nodes_modified)
2382                         continue;
2383
2384                 r = sd_bus_message_close_container(m);
2385                 if (r < 0)
2386                         return r;
2387
2388         } while (bus->nodes_modified);
2389
2390         return sd_bus_send(bus, m, NULL);
2391 }
2392
2393 static int object_removed_append_all_prefix(
2394                 sd_bus *bus,
2395                 sd_bus_message *m,
2396                 Set *s,
2397                 const char *prefix,
2398                 const char *path,
2399                 bool require_fallback) {
2400
2401         const char *previous_interface = NULL;
2402         struct node_vtable *c;
2403         struct node *n;
2404         int r;
2405
2406         assert(bus);
2407         assert(m);
2408         assert(s);
2409         assert(prefix);
2410         assert(path);
2411
2412         n = hashmap_get(bus->nodes, prefix);
2413         if (!n)
2414                 return 0;
2415
2416         LIST_FOREACH(vtables, c, n->vtables) {
2417                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2418                 void *u = NULL;
2419
2420                 if (require_fallback && !c->is_fallback)
2421                         continue;
2422                 if (streq_ptr(c->interface, previous_interface))
2423                         continue;
2424
2425                 /* If a child-node already handled this interface, we
2426                  * skip it on any of its parents. The child vtables
2427                  * always fully override any conflicting vtables of
2428                  * any parent node. */
2429                 if (set_get(s, c->interface))
2430                         continue;
2431
2432                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2433                 if (r < 0)
2434                         return r;
2435                 if (bus->nodes_modified)
2436                         return 0;
2437                 if (r == 0)
2438                         continue;
2439
2440                 r = set_put(s, c->interface);
2441                 if (r < 0)
2442                         return r;
2443
2444                 r = sd_bus_message_append(m, "s", c->interface);
2445                 if (r < 0)
2446                         return r;
2447
2448                 previous_interface = c->interface;
2449         }
2450
2451         return 0;
2452 }
2453
2454 static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2455         _cleanup_set_free_ Set *s = NULL;
2456         char *prefix;
2457         int r;
2458
2459         assert(bus);
2460         assert(m);
2461         assert(path);
2462
2463         /* see sd_bus_emit_object_added() for details */
2464
2465         s = set_new(&string_hash_ops);
2466         if (!s)
2467                 return -ENOMEM;
2468
2469         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Peer");
2470         if (r < 0)
2471                 return r;
2472         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Introspectable");
2473         if (r < 0)
2474                 return r;
2475         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Properties");
2476         if (r < 0)
2477                 return r;
2478         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
2479         if (r < 0)
2480                 return r;
2481
2482         r = object_removed_append_all_prefix(bus, m, s, path, path, false);
2483         if (r < 0)
2484                 return r;
2485         if (bus->nodes_modified)
2486                 return 0;
2487
2488         prefix = alloca(strlen(path) + 1);
2489         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2490                 r = object_removed_append_all_prefix(bus, m, s, prefix, path, true);
2491                 if (r < 0)
2492                         return r;
2493                 if (bus->nodes_modified)
2494                         return 0;
2495         }
2496
2497         return 0;
2498 }
2499
2500 _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
2501         BUS_DONT_DESTROY(bus);
2502
2503         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2504         struct node *object_manager;
2505         int r;
2506
2507         /*
2508          * This is like sd_bus_emit_object_added(), but emits an
2509          * InterfacesRemoved signal on the given path. This only includes any
2510          * registered interfaces but skips the properties. Note that this will
2511          * call into the find() callbacks of any registered vtable. Therefore,
2512          * you must call this function before destroying/unlinking your object.
2513          * Otherwise, the list of interfaces will be incomplete. However, note
2514          * that this will *NOT* call into any property callback. Therefore, the
2515          * object might be in an "destructed" state, as long as we can find it.
2516          */
2517
2518         assert_return(bus, -EINVAL);
2519         assert_return(bus = bus_resolve(bus), -ENOPKG);
2520         assert_return(object_path_is_valid(path), -EINVAL);
2521         assert_return(!bus_pid_changed(bus), -ECHILD);
2522
2523         if (!BUS_IS_OPEN(bus->state))
2524                 return -ENOTCONN;
2525
2526         r = bus_find_parent_object_manager(bus, &object_manager, path);
2527         if (r < 0)
2528                 return r;
2529         if (r == 0)
2530                 return -ESRCH;
2531
2532         do {
2533                 bus->nodes_modified = false;
2534                 m = sd_bus_message_unref(m);
2535
2536                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2537                 if (r < 0)
2538                         return r;
2539
2540                 r = sd_bus_message_append_basic(m, 'o', path);
2541                 if (r < 0)
2542                         return r;
2543
2544                 r = sd_bus_message_open_container(m, 'a', "s");
2545                 if (r < 0)
2546                         return r;
2547
2548                 r = object_removed_append_all(bus, m, path);
2549                 if (r < 0)
2550                         return r;
2551
2552                 if (bus->nodes_modified)
2553                         continue;
2554
2555                 r = sd_bus_message_close_container(m);
2556                 if (r < 0)
2557                         return r;
2558
2559         } while (bus->nodes_modified);
2560
2561         return sd_bus_send(bus, m, NULL);
2562 }
2563
2564 static int interfaces_added_append_one_prefix(
2565                 sd_bus *bus,
2566                 sd_bus_message *m,
2567                 const char *prefix,
2568                 const char *path,
2569                 const char *interface,
2570                 bool require_fallback) {
2571
2572         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2573         bool found_interface = false;
2574         struct node_vtable *c;
2575         struct node *n;
2576         void *u = NULL;
2577         int r;
2578
2579         assert(bus);
2580         assert(m);
2581         assert(prefix);
2582         assert(path);
2583         assert(interface);
2584
2585         n = hashmap_get(bus->nodes, prefix);
2586         if (!n)
2587                 return 0;
2588
2589         LIST_FOREACH(vtables, c, n->vtables) {
2590                 if (require_fallback && !c->is_fallback)
2591                         continue;
2592
2593                 if (!streq(c->interface, interface))
2594                         continue;
2595
2596                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2597                 if (r < 0)
2598                         return r;
2599                 if (bus->nodes_modified)
2600                         return 0;
2601                 if (r == 0)
2602                         continue;
2603
2604                 if (!found_interface) {
2605                         r = sd_bus_message_append_basic(m, 's', interface);
2606                         if (r < 0)
2607                                 return r;
2608
2609                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2610                         if (r < 0)
2611                                 return r;
2612
2613                         found_interface = true;
2614                 }
2615
2616                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2617                 if (r < 0)
2618                         return r;
2619                 if (bus->nodes_modified)
2620                         return 0;
2621         }
2622
2623         if (found_interface) {
2624                 r = sd_bus_message_close_container(m);
2625                 if (r < 0)
2626                         return r;
2627         }
2628
2629         return found_interface;
2630 }
2631
2632 static int interfaces_added_append_one(
2633                 sd_bus *bus,
2634                 sd_bus_message *m,
2635                 const char *path,
2636                 const char *interface) {
2637
2638         char *prefix;
2639         int r;
2640
2641         assert(bus);
2642         assert(m);
2643         assert(path);
2644         assert(interface);
2645
2646         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2647         if (r != 0)
2648                 return r;
2649         if (bus->nodes_modified)
2650                 return 0;
2651
2652         prefix = alloca(strlen(path) + 1);
2653         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2654                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2655                 if (r != 0)
2656                         return r;
2657                 if (bus->nodes_modified)
2658                         return 0;
2659         }
2660
2661         return -ENOENT;
2662 }
2663
2664 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2665         BUS_DONT_DESTROY(bus);
2666
2667         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2668         struct node *object_manager;
2669         char **i;
2670         int r;
2671
2672         assert_return(bus, -EINVAL);
2673         assert_return(bus = bus_resolve(bus), -ENOPKG);
2674         assert_return(object_path_is_valid(path), -EINVAL);
2675         assert_return(!bus_pid_changed(bus), -ECHILD);
2676
2677         if (!BUS_IS_OPEN(bus->state))
2678                 return -ENOTCONN;
2679
2680         if (strv_isempty(interfaces))
2681                 return 0;
2682
2683         r = bus_find_parent_object_manager(bus, &object_manager, path);
2684         if (r < 0)
2685                 return r;
2686         if (r == 0)
2687                 return -ESRCH;
2688
2689         do {
2690                 bus->nodes_modified = false;
2691                 m = sd_bus_message_unref(m);
2692
2693                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2694                 if (r < 0)
2695                         return r;
2696
2697                 r = sd_bus_message_append_basic(m, 'o', path);
2698                 if (r < 0)
2699                         return r;
2700
2701                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2702                 if (r < 0)
2703                         return r;
2704
2705                 STRV_FOREACH(i, interfaces) {
2706                         assert_return(interface_name_is_valid(*i), -EINVAL);
2707
2708                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2709                         if (r < 0)
2710                                 return r;
2711
2712                         r = interfaces_added_append_one(bus, m, path, *i);
2713                         if (r < 0)
2714                                 return r;
2715
2716                         if (bus->nodes_modified)
2717                                 break;
2718
2719                         r = sd_bus_message_close_container(m);
2720                         if (r < 0)
2721                                 return r;
2722                 }
2723
2724                 if (bus->nodes_modified)
2725                         continue;
2726
2727                 r = sd_bus_message_close_container(m);
2728                 if (r < 0)
2729                         return r;
2730
2731         } while (bus->nodes_modified);
2732
2733         return sd_bus_send(bus, m, NULL);
2734 }
2735
2736 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2737         char **interfaces;
2738
2739         assert_return(bus, -EINVAL);
2740         assert_return(bus = bus_resolve(bus), -ENOPKG);
2741         assert_return(object_path_is_valid(path), -EINVAL);
2742         assert_return(!bus_pid_changed(bus), -ECHILD);
2743
2744         if (!BUS_IS_OPEN(bus->state))
2745                 return -ENOTCONN;
2746
2747         interfaces = strv_from_stdarg_alloca(interface);
2748
2749         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2750 }
2751
2752 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2753         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2754         struct node *object_manager;
2755         int r;
2756
2757         assert_return(bus, -EINVAL);
2758         assert_return(bus = bus_resolve(bus), -ENOPKG);
2759         assert_return(object_path_is_valid(path), -EINVAL);
2760         assert_return(!bus_pid_changed(bus), -ECHILD);
2761
2762         if (!BUS_IS_OPEN(bus->state))
2763                 return -ENOTCONN;
2764
2765         if (strv_isempty(interfaces))
2766                 return 0;
2767
2768         r = bus_find_parent_object_manager(bus, &object_manager, path);
2769         if (r < 0)
2770                 return r;
2771         if (r == 0)
2772                 return -ESRCH;
2773
2774         r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2775         if (r < 0)
2776                 return r;
2777
2778         r = sd_bus_message_append_basic(m, 'o', path);
2779         if (r < 0)
2780                 return r;
2781
2782         r = sd_bus_message_append_strv(m, interfaces);
2783         if (r < 0)
2784                 return r;
2785
2786         return sd_bus_send(bus, m, NULL);
2787 }
2788
2789 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2790         char **interfaces;
2791
2792         assert_return(bus, -EINVAL);
2793         assert_return(bus = bus_resolve(bus), -ENOPKG);
2794         assert_return(object_path_is_valid(path), -EINVAL);
2795         assert_return(!bus_pid_changed(bus), -ECHILD);
2796
2797         if (!BUS_IS_OPEN(bus->state))
2798                 return -ENOTCONN;
2799
2800         interfaces = strv_from_stdarg_alloca(interface);
2801
2802         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2803 }
2804
2805 _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
2806         sd_bus_slot *s;
2807         struct node *n;
2808         int r;
2809
2810         assert_return(bus, -EINVAL);
2811         assert_return(bus = bus_resolve(bus), -ENOPKG);
2812         assert_return(object_path_is_valid(path), -EINVAL);
2813         assert_return(!bus_pid_changed(bus), -ECHILD);
2814
2815         n = bus_node_allocate(bus, path);
2816         if (!n)
2817                 return -ENOMEM;
2818
2819         s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
2820         if (!s) {
2821                 r = -ENOMEM;
2822                 goto fail;
2823         }
2824
2825         s->node_object_manager.node = n;
2826         LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
2827         bus->nodes_modified = true;
2828
2829         if (slot)
2830                 *slot = s;
2831
2832         return 0;
2833
2834 fail:
2835         sd_bus_slot_unref(s);
2836         bus_node_gc(bus, n);
2837
2838         return r;
2839 }