chiark / gitweb /
sd-bus: get rid of kdbus flags cruft
[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(object_path_is_valid(path), -EINVAL);
1551         assert_return(callback, -EINVAL);
1552         assert_return(!bus_pid_changed(bus), -ECHILD);
1553
1554         n = bus_node_allocate(bus, path);
1555         if (!n)
1556                 return -ENOMEM;
1557
1558         s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
1559         if (!s) {
1560                 r = -ENOMEM;
1561                 goto fail;
1562         }
1563
1564         s->node_callback.callback = callback;
1565         s->node_callback.is_fallback = fallback;
1566
1567         s->node_callback.node = n;
1568         LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
1569         bus->nodes_modified = true;
1570
1571         if (slot)
1572                 *slot = s;
1573
1574         return 0;
1575
1576 fail:
1577         sd_bus_slot_unref(s);
1578         bus_node_gc(bus, n);
1579
1580         return r;
1581 }
1582
1583 _public_ int sd_bus_add_object(
1584                 sd_bus *bus,
1585                 sd_bus_slot **slot,
1586                 const char *path,
1587                 sd_bus_message_handler_t callback,
1588                 void *userdata) {
1589
1590         return bus_add_object(bus, slot, false, path, callback, userdata);
1591 }
1592
1593 _public_ int sd_bus_add_fallback(
1594                 sd_bus *bus,
1595                 sd_bus_slot **slot,
1596                 const char *prefix,
1597                 sd_bus_message_handler_t callback,
1598                 void *userdata) {
1599
1600         return bus_add_object(bus, slot, true, prefix, callback, userdata);
1601 }
1602
1603 static void vtable_member_hash_func(const void *a, struct siphash *state) {
1604         const struct vtable_member *m = a;
1605
1606         assert(m);
1607
1608         string_hash_func(m->path, state);
1609         string_hash_func(m->interface, state);
1610         string_hash_func(m->member, state);
1611 }
1612
1613 static int vtable_member_compare_func(const void *a, const void *b) {
1614         const struct vtable_member *x = a, *y = b;
1615         int r;
1616
1617         assert(x);
1618         assert(y);
1619
1620         r = strcmp(x->path, y->path);
1621         if (r != 0)
1622                 return r;
1623
1624         r = strcmp(x->interface, y->interface);
1625         if (r != 0)
1626                 return r;
1627
1628         return strcmp(x->member, y->member);
1629 }
1630
1631 static const struct hash_ops vtable_member_hash_ops = {
1632         .hash = vtable_member_hash_func,
1633         .compare = vtable_member_compare_func
1634 };
1635
1636 static int add_object_vtable_internal(
1637                 sd_bus *bus,
1638                 sd_bus_slot **slot,
1639                 const char *path,
1640                 const char *interface,
1641                 const sd_bus_vtable *vtable,
1642                 bool fallback,
1643                 sd_bus_object_find_t find,
1644                 void *userdata) {
1645
1646         sd_bus_slot *s = NULL;
1647         struct node_vtable *i, *existing = NULL;
1648         const sd_bus_vtable *v;
1649         struct node *n;
1650         int r;
1651
1652         assert_return(bus, -EINVAL);
1653         assert_return(object_path_is_valid(path), -EINVAL);
1654         assert_return(interface_name_is_valid(interface), -EINVAL);
1655         assert_return(vtable, -EINVAL);
1656         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1657         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1658         assert_return(!bus_pid_changed(bus), -ECHILD);
1659         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1660                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1661                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1662                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1663
1664         r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops);
1665         if (r < 0)
1666                 return r;
1667
1668         r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops);
1669         if (r < 0)
1670                 return r;
1671
1672         n = bus_node_allocate(bus, path);
1673         if (!n)
1674                 return -ENOMEM;
1675
1676         LIST_FOREACH(vtables, i, n->vtables) {
1677                 if (i->is_fallback != fallback) {
1678                         r = -EPROTOTYPE;
1679                         goto fail;
1680                 }
1681
1682                 if (streq(i->interface, interface)) {
1683
1684                         if (i->vtable == vtable) {
1685                                 r = -EEXIST;
1686                                 goto fail;
1687                         }
1688
1689                         existing = i;
1690                 }
1691         }
1692
1693         s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
1694         if (!s) {
1695                 r = -ENOMEM;
1696                 goto fail;
1697         }
1698
1699         s->node_vtable.is_fallback = fallback;
1700         s->node_vtable.vtable = vtable;
1701         s->node_vtable.find = find;
1702
1703         s->node_vtable.interface = strdup(interface);
1704         if (!s->node_vtable.interface) {
1705                 r = -ENOMEM;
1706                 goto fail;
1707         }
1708
1709         for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1710
1711                 switch (v->type) {
1712
1713                 case _SD_BUS_VTABLE_METHOD: {
1714                         struct vtable_member *m;
1715
1716                         if (!member_name_is_valid(v->x.method.member) ||
1717                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1718                             !signature_is_valid(strempty(v->x.method.result), false) ||
1719                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1720                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1721                                 r = -EINVAL;
1722                                 goto fail;
1723                         }
1724
1725                         m = new0(struct vtable_member, 1);
1726                         if (!m) {
1727                                 r = -ENOMEM;
1728                                 goto fail;
1729                         }
1730
1731                         m->parent = &s->node_vtable;
1732                         m->path = n->path;
1733                         m->interface = s->node_vtable.interface;
1734                         m->member = v->x.method.member;
1735                         m->vtable = v;
1736
1737                         r = hashmap_put(bus->vtable_methods, m, m);
1738                         if (r < 0) {
1739                                 free(m);
1740                                 goto fail;
1741                         }
1742
1743                         break;
1744                 }
1745
1746                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1747
1748                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1749                                 r = -EINVAL;
1750                                 goto fail;
1751                         }
1752
1753                         if (v->flags & SD_BUS_VTABLE_PROPERTY_CONST) {
1754                                 r = -EINVAL;
1755                                 goto fail;
1756                         }
1757
1758                         _fallthrough_;
1759                 case _SD_BUS_VTABLE_PROPERTY: {
1760                         struct vtable_member *m;
1761
1762                         if (!member_name_is_valid(v->x.property.member) ||
1763                             !signature_is_single(v->x.property.signature, false) ||
1764                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1765                             (v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ||
1766                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
1767                             ((v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) && (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)) ||
1768                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1769                                 r = -EINVAL;
1770                                 goto fail;
1771                         }
1772
1773                         m = new0(struct vtable_member, 1);
1774                         if (!m) {
1775                                 r = -ENOMEM;
1776                                 goto fail;
1777                         }
1778
1779                         m->parent = &s->node_vtable;
1780                         m->path = n->path;
1781                         m->interface = s->node_vtable.interface;
1782                         m->member = v->x.property.member;
1783                         m->vtable = v;
1784
1785                         r = hashmap_put(bus->vtable_properties, m, m);
1786                         if (r < 0) {
1787                                 free(m);
1788                                 goto fail;
1789                         }
1790
1791                         break;
1792                 }
1793
1794                 case _SD_BUS_VTABLE_SIGNAL:
1795
1796                         if (!member_name_is_valid(v->x.signal.member) ||
1797                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1798                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1799                                 r = -EINVAL;
1800                                 goto fail;
1801                         }
1802
1803                         break;
1804
1805                 default:
1806                         r = -EINVAL;
1807                         goto fail;
1808                 }
1809         }
1810
1811         s->node_vtable.node = n;
1812         LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
1813         bus->nodes_modified = true;
1814
1815         if (slot)
1816                 *slot = s;
1817
1818         return 0;
1819
1820 fail:
1821         sd_bus_slot_unref(s);
1822         bus_node_gc(bus, n);
1823
1824         return r;
1825 }
1826
1827 _public_ int sd_bus_add_object_vtable(
1828                 sd_bus *bus,
1829                 sd_bus_slot **slot,
1830                 const char *path,
1831                 const char *interface,
1832                 const sd_bus_vtable *vtable,
1833                 void *userdata) {
1834
1835         return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
1836 }
1837
1838 _public_ int sd_bus_add_fallback_vtable(
1839                 sd_bus *bus,
1840                 sd_bus_slot **slot,
1841                 const char *prefix,
1842                 const char *interface,
1843                 const sd_bus_vtable *vtable,
1844                 sd_bus_object_find_t find,
1845                 void *userdata) {
1846
1847         return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
1848 }
1849
1850 _public_ int sd_bus_add_node_enumerator(
1851                 sd_bus *bus,
1852                 sd_bus_slot **slot,
1853                 const char *path,
1854                 sd_bus_node_enumerator_t callback,
1855                 void *userdata) {
1856
1857         sd_bus_slot *s;
1858         struct node *n;
1859         int r;
1860
1861         assert_return(bus, -EINVAL);
1862         assert_return(object_path_is_valid(path), -EINVAL);
1863         assert_return(callback, -EINVAL);
1864         assert_return(!bus_pid_changed(bus), -ECHILD);
1865
1866         n = bus_node_allocate(bus, path);
1867         if (!n)
1868                 return -ENOMEM;
1869
1870         s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
1871         if (!s) {
1872                 r = -ENOMEM;
1873                 goto fail;
1874         }
1875
1876         s->node_enumerator.callback = callback;
1877
1878         s->node_enumerator.node = n;
1879         LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
1880         bus->nodes_modified = true;
1881
1882         if (slot)
1883                 *slot = s;
1884
1885         return 0;
1886
1887 fail:
1888         sd_bus_slot_unref(s);
1889         bus_node_gc(bus, n);
1890
1891         return r;
1892 }
1893
1894 static int emit_properties_changed_on_interface(
1895                 sd_bus *bus,
1896                 const char *prefix,
1897                 const char *path,
1898                 const char *interface,
1899                 bool require_fallback,
1900                 bool *found_interface,
1901                 char **names) {
1902
1903         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1904         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1905         bool has_invalidating = false, has_changing = false;
1906         struct vtable_member key = {};
1907         struct node_vtable *c;
1908         struct node *n;
1909         char **property;
1910         void *u = NULL;
1911         int r;
1912
1913         assert(bus);
1914         assert(prefix);
1915         assert(path);
1916         assert(interface);
1917         assert(found_interface);
1918
1919         n = hashmap_get(bus->nodes, prefix);
1920         if (!n)
1921                 return 0;
1922
1923         r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
1924         if (r < 0)
1925                 return r;
1926
1927         r = sd_bus_message_append(m, "s", interface);
1928         if (r < 0)
1929                 return r;
1930
1931         r = sd_bus_message_open_container(m, 'a', "{sv}");
1932         if (r < 0)
1933                 return r;
1934
1935         key.path = prefix;
1936         key.interface = interface;
1937
1938         LIST_FOREACH(vtables, c, n->vtables) {
1939                 if (require_fallback && !c->is_fallback)
1940                         continue;
1941
1942                 if (!streq(c->interface, interface))
1943                         continue;
1944
1945                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
1946                 if (r < 0)
1947                         return r;
1948                 if (bus->nodes_modified)
1949                         return 0;
1950                 if (r == 0)
1951                         continue;
1952
1953                 *found_interface = true;
1954
1955                 if (names) {
1956                         /* If the caller specified a list of
1957                          * properties we include exactly those in the
1958                          * PropertiesChanged message */
1959
1960                         STRV_FOREACH(property, names) {
1961                                 struct vtable_member *v;
1962
1963                                 assert_return(member_name_is_valid(*property), -EINVAL);
1964
1965                                 key.member = *property;
1966                                 v = hashmap_get(bus->vtable_properties, &key);
1967                                 if (!v)
1968                                         return -ENOENT;
1969
1970                                 /* If there are two vtables for the same
1971                                  * interface, let's handle this property when
1972                                  * we come to that vtable. */
1973                                 if (c != v->parent)
1974                                         continue;
1975
1976                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
1977                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
1978
1979                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
1980
1981                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
1982                                         has_invalidating = true;
1983                                         continue;
1984                                 }
1985
1986                                 has_changing = true;
1987
1988                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
1989                                 if (r < 0)
1990                                         return r;
1991                                 if (bus->nodes_modified)
1992                                         return 0;
1993                         }
1994                 } else {
1995                         const sd_bus_vtable *v;
1996
1997                         /* If the caller specified no properties list
1998                          * we include all properties that are marked
1999                          * as changing in the message. */
2000
2001                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2002                                 if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
2003                                         continue;
2004
2005                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
2006                                         continue;
2007
2008                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2009                                         has_invalidating = true;
2010                                         continue;
2011                                 }
2012
2013                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
2014                                         continue;
2015
2016                                 has_changing = true;
2017
2018                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
2019                                 if (r < 0)
2020                                         return r;
2021                                 if (bus->nodes_modified)
2022                                         return 0;
2023                         }
2024                 }
2025         }
2026
2027         if (!has_invalidating && !has_changing)
2028                 return 0;
2029
2030         r = sd_bus_message_close_container(m);
2031         if (r < 0)
2032                 return r;
2033
2034         r = sd_bus_message_open_container(m, 'a', "s");
2035         if (r < 0)
2036                 return r;
2037
2038         if (has_invalidating) {
2039                 LIST_FOREACH(vtables, c, n->vtables) {
2040                         if (require_fallback && !c->is_fallback)
2041                                 continue;
2042
2043                         if (!streq(c->interface, interface))
2044                                 continue;
2045
2046                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
2047                         if (r < 0)
2048                                 return r;
2049                         if (bus->nodes_modified)
2050                                 return 0;
2051                         if (r == 0)
2052                                 continue;
2053
2054                         if (names) {
2055                                 STRV_FOREACH(property, names) {
2056                                         struct vtable_member *v;
2057
2058                                         key.member = *property;
2059                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
2060                                         assert(c == v->parent);
2061
2062                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2063                                                 continue;
2064
2065                                         r = sd_bus_message_append(m, "s", *property);
2066                                         if (r < 0)
2067                                                 return r;
2068                                 }
2069                         } else {
2070                                 const sd_bus_vtable *v;
2071
2072                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2073                                         if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
2074                                                 continue;
2075
2076                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
2077                                                 continue;
2078
2079                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2080                                                 continue;
2081
2082                                         r = sd_bus_message_append(m, "s", v->x.property.member);
2083                                         if (r < 0)
2084                                                 return r;
2085                                 }
2086                         }
2087                 }
2088         }
2089
2090         r = sd_bus_message_close_container(m);
2091         if (r < 0)
2092                 return r;
2093
2094         r = sd_bus_send(bus, m, NULL);
2095         if (r < 0)
2096                 return r;
2097
2098         return 1;
2099 }
2100
2101 _public_ int sd_bus_emit_properties_changed_strv(
2102                 sd_bus *bus,
2103                 const char *path,
2104                 const char *interface,
2105                 char **names) {
2106
2107         BUS_DONT_DESTROY(bus);
2108         bool found_interface = false;
2109         char *prefix;
2110         int r;
2111
2112         assert_return(bus, -EINVAL);
2113         assert_return(object_path_is_valid(path), -EINVAL);
2114         assert_return(interface_name_is_valid(interface), -EINVAL);
2115         assert_return(!bus_pid_changed(bus), -ECHILD);
2116
2117         if (!BUS_IS_OPEN(bus->state))
2118                 return -ENOTCONN;
2119
2120         /* A non-NULL but empty names list means nothing needs to be
2121            generated. A NULL list OTOH indicates that all properties
2122            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2123            included in the PropertiesChanged message. */
2124         if (names && names[0] == NULL)
2125                 return 0;
2126
2127         do {
2128                 bus->nodes_modified = false;
2129
2130                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
2131                 if (r != 0)
2132                         return r;
2133                 if (bus->nodes_modified)
2134                         continue;
2135
2136                 prefix = alloca(strlen(path) + 1);
2137                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2138                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
2139                         if (r != 0)
2140                                 return r;
2141                         if (bus->nodes_modified)
2142                                 break;
2143                 }
2144
2145         } while (bus->nodes_modified);
2146
2147         return found_interface ? 0 : -ENOENT;
2148 }
2149
2150 _public_ int sd_bus_emit_properties_changed(
2151                 sd_bus *bus,
2152                 const char *path,
2153                 const char *interface,
2154                 const char *name, ...)  {
2155
2156         char **names;
2157
2158         assert_return(bus, -EINVAL);
2159         assert_return(object_path_is_valid(path), -EINVAL);
2160         assert_return(interface_name_is_valid(interface), -EINVAL);
2161         assert_return(!bus_pid_changed(bus), -ECHILD);
2162
2163         if (!BUS_IS_OPEN(bus->state))
2164                 return -ENOTCONN;
2165
2166         if (!name)
2167                 return 0;
2168
2169         names = strv_from_stdarg_alloca(name);
2170
2171         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2172 }
2173
2174 static int object_added_append_all_prefix(
2175                 sd_bus *bus,
2176                 sd_bus_message *m,
2177                 Set *s,
2178                 const char *prefix,
2179                 const char *path,
2180                 bool require_fallback) {
2181
2182         const char *previous_interface = NULL;
2183         struct node_vtable *c;
2184         struct node *n;
2185         int r;
2186
2187         assert(bus);
2188         assert(m);
2189         assert(s);
2190         assert(prefix);
2191         assert(path);
2192
2193         n = hashmap_get(bus->nodes, prefix);
2194         if (!n)
2195                 return 0;
2196
2197         LIST_FOREACH(vtables, c, n->vtables) {
2198                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2199                 void *u = NULL;
2200
2201                 if (require_fallback && !c->is_fallback)
2202                         continue;
2203
2204                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2205                 if (r < 0)
2206                         return r;
2207                 if (bus->nodes_modified)
2208                         return 0;
2209                 if (r == 0)
2210                         continue;
2211
2212                 if (!streq_ptr(c->interface, previous_interface)) {
2213                         /* If a child-node already handled this interface, we
2214                          * skip it on any of its parents. The child vtables
2215                          * always fully override any conflicting vtables of
2216                          * any parent node. */
2217                         if (set_get(s, c->interface))
2218                                 continue;
2219
2220                         r = set_put(s, c->interface);
2221                         if (r < 0)
2222                                 return r;
2223
2224                         if (previous_interface) {
2225                                 r = sd_bus_message_close_container(m);
2226                                 if (r < 0)
2227                                         return r;
2228                                 r = sd_bus_message_close_container(m);
2229                                 if (r < 0)
2230                                         return r;
2231                         }
2232
2233                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2234                         if (r < 0)
2235                                 return r;
2236                         r = sd_bus_message_append(m, "s", c->interface);
2237                         if (r < 0)
2238                                 return r;
2239                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2240                         if (r < 0)
2241                                 return r;
2242
2243                         previous_interface = c->interface;
2244                 }
2245
2246                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2247                 if (r < 0)
2248                         return r;
2249                 if (bus->nodes_modified)
2250                         return 0;
2251         }
2252
2253         if (previous_interface) {
2254                 r = sd_bus_message_close_container(m);
2255                 if (r < 0)
2256                         return r;
2257                 r = sd_bus_message_close_container(m);
2258                 if (r < 0)
2259                         return r;
2260         }
2261
2262         return 0;
2263 }
2264
2265 static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2266         _cleanup_set_free_ Set *s = NULL;
2267         char *prefix;
2268         int r;
2269
2270         assert(bus);
2271         assert(m);
2272         assert(path);
2273
2274         /*
2275          * This appends all interfaces registered on path @path. We first add
2276          * the builtin interfaces, which are always available and handled by
2277          * sd-bus. Then, we add all interfaces registered on the exact node,
2278          * followed by all fallback interfaces registered on any parent prefix.
2279          *
2280          * If an interface is registered multiple times on the same node with
2281          * different vtables, we merge all the properties across all vtables.
2282          * However, if a child node has the same interface registered as one of
2283          * its parent nodes has as fallback, we make the child overwrite the
2284          * parent instead of extending it. Therefore, we keep a "Set" of all
2285          * handled interfaces during parent traversal, so we skip interfaces on
2286          * a parent that were overwritten by a child.
2287          */
2288
2289         s = set_new(&string_hash_ops);
2290         if (!s)
2291                 return -ENOMEM;
2292
2293         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Peer", 0);
2294         if (r < 0)
2295                 return r;
2296         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Introspectable", 0);
2297         if (r < 0)
2298                 return r;
2299         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);
2300         if (r < 0)
2301                 return r;
2302         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
2303         if (r < 0)
2304                 return r;
2305
2306         r = object_added_append_all_prefix(bus, m, s, path, path, false);
2307         if (r < 0)
2308                 return r;
2309         if (bus->nodes_modified)
2310                 return 0;
2311
2312         prefix = alloca(strlen(path) + 1);
2313         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2314                 r = object_added_append_all_prefix(bus, m, s, prefix, path, true);
2315                 if (r < 0)
2316                         return r;
2317                 if (bus->nodes_modified)
2318                         return 0;
2319         }
2320
2321         return 0;
2322 }
2323
2324 _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
2325         BUS_DONT_DESTROY(bus);
2326
2327         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2328         struct node *object_manager;
2329         int r;
2330
2331         /*
2332          * This emits an InterfacesAdded signal on the given path, by iterating
2333          * all registered vtables and fallback vtables on the path. All
2334          * properties are queried and included in the signal.
2335          * This call is equivalent to sd_bus_emit_interfaces_added() with an
2336          * explicit list of registered interfaces. However, unlike
2337          * interfaces_added(), this call can figure out the list of supported
2338          * interfaces itself. Furthermore, it properly adds the builtin
2339          * org.freedesktop.DBus.* interfaces.
2340          */
2341
2342         assert_return(bus, -EINVAL);
2343         assert_return(object_path_is_valid(path), -EINVAL);
2344         assert_return(!bus_pid_changed(bus), -ECHILD);
2345
2346         if (!BUS_IS_OPEN(bus->state))
2347                 return -ENOTCONN;
2348
2349         r = bus_find_parent_object_manager(bus, &object_manager, path);
2350         if (r < 0)
2351                 return r;
2352         if (r == 0)
2353                 return -ESRCH;
2354
2355         do {
2356                 bus->nodes_modified = false;
2357                 m = sd_bus_message_unref(m);
2358
2359                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2360                 if (r < 0)
2361                         return r;
2362
2363                 r = sd_bus_message_append_basic(m, 'o', path);
2364                 if (r < 0)
2365                         return r;
2366
2367                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2368                 if (r < 0)
2369                         return r;
2370
2371                 r = object_added_append_all(bus, m, path);
2372                 if (r < 0)
2373                         return r;
2374
2375                 if (bus->nodes_modified)
2376                         continue;
2377
2378                 r = sd_bus_message_close_container(m);
2379                 if (r < 0)
2380                         return r;
2381
2382         } while (bus->nodes_modified);
2383
2384         return sd_bus_send(bus, m, NULL);
2385 }
2386
2387 static int object_removed_append_all_prefix(
2388                 sd_bus *bus,
2389                 sd_bus_message *m,
2390                 Set *s,
2391                 const char *prefix,
2392                 const char *path,
2393                 bool require_fallback) {
2394
2395         const char *previous_interface = NULL;
2396         struct node_vtable *c;
2397         struct node *n;
2398         int r;
2399
2400         assert(bus);
2401         assert(m);
2402         assert(s);
2403         assert(prefix);
2404         assert(path);
2405
2406         n = hashmap_get(bus->nodes, prefix);
2407         if (!n)
2408                 return 0;
2409
2410         LIST_FOREACH(vtables, c, n->vtables) {
2411                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2412                 void *u = NULL;
2413
2414                 if (require_fallback && !c->is_fallback)
2415                         continue;
2416                 if (streq_ptr(c->interface, previous_interface))
2417                         continue;
2418
2419                 /* If a child-node already handled this interface, we
2420                  * skip it on any of its parents. The child vtables
2421                  * always fully override any conflicting vtables of
2422                  * any parent node. */
2423                 if (set_get(s, c->interface))
2424                         continue;
2425
2426                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2427                 if (r < 0)
2428                         return r;
2429                 if (bus->nodes_modified)
2430                         return 0;
2431                 if (r == 0)
2432                         continue;
2433
2434                 r = set_put(s, c->interface);
2435                 if (r < 0)
2436                         return r;
2437
2438                 r = sd_bus_message_append(m, "s", c->interface);
2439                 if (r < 0)
2440                         return r;
2441
2442                 previous_interface = c->interface;
2443         }
2444
2445         return 0;
2446 }
2447
2448 static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2449         _cleanup_set_free_ Set *s = NULL;
2450         char *prefix;
2451         int r;
2452
2453         assert(bus);
2454         assert(m);
2455         assert(path);
2456
2457         /* see sd_bus_emit_object_added() for details */
2458
2459         s = set_new(&string_hash_ops);
2460         if (!s)
2461                 return -ENOMEM;
2462
2463         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Peer");
2464         if (r < 0)
2465                 return r;
2466         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Introspectable");
2467         if (r < 0)
2468                 return r;
2469         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Properties");
2470         if (r < 0)
2471                 return r;
2472         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
2473         if (r < 0)
2474                 return r;
2475
2476         r = object_removed_append_all_prefix(bus, m, s, path, path, false);
2477         if (r < 0)
2478                 return r;
2479         if (bus->nodes_modified)
2480                 return 0;
2481
2482         prefix = alloca(strlen(path) + 1);
2483         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2484                 r = object_removed_append_all_prefix(bus, m, s, prefix, path, true);
2485                 if (r < 0)
2486                         return r;
2487                 if (bus->nodes_modified)
2488                         return 0;
2489         }
2490
2491         return 0;
2492 }
2493
2494 _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
2495         BUS_DONT_DESTROY(bus);
2496
2497         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2498         struct node *object_manager;
2499         int r;
2500
2501         /*
2502          * This is like sd_bus_emit_object_added(), but emits an
2503          * InterfacesRemoved signal on the given path. This only includes any
2504          * registered interfaces but skips the properties. Note that this will
2505          * call into the find() callbacks of any registered vtable. Therefore,
2506          * you must call this function before destroying/unlinking your object.
2507          * Otherwise, the list of interfaces will be incomplete. However, note
2508          * that this will *NOT* call into any property callback. Therefore, the
2509          * object might be in an "destructed" state, as long as we can find it.
2510          */
2511
2512         assert_return(bus, -EINVAL);
2513         assert_return(object_path_is_valid(path), -EINVAL);
2514         assert_return(!bus_pid_changed(bus), -ECHILD);
2515
2516         if (!BUS_IS_OPEN(bus->state))
2517                 return -ENOTCONN;
2518
2519         r = bus_find_parent_object_manager(bus, &object_manager, path);
2520         if (r < 0)
2521                 return r;
2522         if (r == 0)
2523                 return -ESRCH;
2524
2525         do {
2526                 bus->nodes_modified = false;
2527                 m = sd_bus_message_unref(m);
2528
2529                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2530                 if (r < 0)
2531                         return r;
2532
2533                 r = sd_bus_message_append_basic(m, 'o', path);
2534                 if (r < 0)
2535                         return r;
2536
2537                 r = sd_bus_message_open_container(m, 'a', "s");
2538                 if (r < 0)
2539                         return r;
2540
2541                 r = object_removed_append_all(bus, m, path);
2542                 if (r < 0)
2543                         return r;
2544
2545                 if (bus->nodes_modified)
2546                         continue;
2547
2548                 r = sd_bus_message_close_container(m);
2549                 if (r < 0)
2550                         return r;
2551
2552         } while (bus->nodes_modified);
2553
2554         return sd_bus_send(bus, m, NULL);
2555 }
2556
2557 static int interfaces_added_append_one_prefix(
2558                 sd_bus *bus,
2559                 sd_bus_message *m,
2560                 const char *prefix,
2561                 const char *path,
2562                 const char *interface,
2563                 bool require_fallback) {
2564
2565         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2566         bool found_interface = false;
2567         struct node_vtable *c;
2568         struct node *n;
2569         void *u = NULL;
2570         int r;
2571
2572         assert(bus);
2573         assert(m);
2574         assert(prefix);
2575         assert(path);
2576         assert(interface);
2577
2578         n = hashmap_get(bus->nodes, prefix);
2579         if (!n)
2580                 return 0;
2581
2582         LIST_FOREACH(vtables, c, n->vtables) {
2583                 if (require_fallback && !c->is_fallback)
2584                         continue;
2585
2586                 if (!streq(c->interface, interface))
2587                         continue;
2588
2589                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2590                 if (r < 0)
2591                         return r;
2592                 if (bus->nodes_modified)
2593                         return 0;
2594                 if (r == 0)
2595                         continue;
2596
2597                 if (!found_interface) {
2598                         r = sd_bus_message_append_basic(m, 's', interface);
2599                         if (r < 0)
2600                                 return r;
2601
2602                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2603                         if (r < 0)
2604                                 return r;
2605
2606                         found_interface = true;
2607                 }
2608
2609                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2610                 if (r < 0)
2611                         return r;
2612                 if (bus->nodes_modified)
2613                         return 0;
2614         }
2615
2616         if (found_interface) {
2617                 r = sd_bus_message_close_container(m);
2618                 if (r < 0)
2619                         return r;
2620         }
2621
2622         return found_interface;
2623 }
2624
2625 static int interfaces_added_append_one(
2626                 sd_bus *bus,
2627                 sd_bus_message *m,
2628                 const char *path,
2629                 const char *interface) {
2630
2631         char *prefix;
2632         int r;
2633
2634         assert(bus);
2635         assert(m);
2636         assert(path);
2637         assert(interface);
2638
2639         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2640         if (r != 0)
2641                 return r;
2642         if (bus->nodes_modified)
2643                 return 0;
2644
2645         prefix = alloca(strlen(path) + 1);
2646         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2647                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2648                 if (r != 0)
2649                         return r;
2650                 if (bus->nodes_modified)
2651                         return 0;
2652         }
2653
2654         return -ENOENT;
2655 }
2656
2657 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2658         BUS_DONT_DESTROY(bus);
2659
2660         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2661         struct node *object_manager;
2662         char **i;
2663         int r;
2664
2665         assert_return(bus, -EINVAL);
2666         assert_return(object_path_is_valid(path), -EINVAL);
2667         assert_return(!bus_pid_changed(bus), -ECHILD);
2668
2669         if (!BUS_IS_OPEN(bus->state))
2670                 return -ENOTCONN;
2671
2672         if (strv_isempty(interfaces))
2673                 return 0;
2674
2675         r = bus_find_parent_object_manager(bus, &object_manager, path);
2676         if (r < 0)
2677                 return r;
2678         if (r == 0)
2679                 return -ESRCH;
2680
2681         do {
2682                 bus->nodes_modified = false;
2683                 m = sd_bus_message_unref(m);
2684
2685                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2686                 if (r < 0)
2687                         return r;
2688
2689                 r = sd_bus_message_append_basic(m, 'o', path);
2690                 if (r < 0)
2691                         return r;
2692
2693                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2694                 if (r < 0)
2695                         return r;
2696
2697                 STRV_FOREACH(i, interfaces) {
2698                         assert_return(interface_name_is_valid(*i), -EINVAL);
2699
2700                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2701                         if (r < 0)
2702                                 return r;
2703
2704                         r = interfaces_added_append_one(bus, m, path, *i);
2705                         if (r < 0)
2706                                 return r;
2707
2708                         if (bus->nodes_modified)
2709                                 break;
2710
2711                         r = sd_bus_message_close_container(m);
2712                         if (r < 0)
2713                                 return r;
2714                 }
2715
2716                 if (bus->nodes_modified)
2717                         continue;
2718
2719                 r = sd_bus_message_close_container(m);
2720                 if (r < 0)
2721                         return r;
2722
2723         } while (bus->nodes_modified);
2724
2725         return sd_bus_send(bus, m, NULL);
2726 }
2727
2728 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2729         char **interfaces;
2730
2731         assert_return(bus, -EINVAL);
2732         assert_return(object_path_is_valid(path), -EINVAL);
2733         assert_return(!bus_pid_changed(bus), -ECHILD);
2734
2735         if (!BUS_IS_OPEN(bus->state))
2736                 return -ENOTCONN;
2737
2738         interfaces = strv_from_stdarg_alloca(interface);
2739
2740         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2741 }
2742
2743 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2744         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2745         struct node *object_manager;
2746         int r;
2747
2748         assert_return(bus, -EINVAL);
2749         assert_return(object_path_is_valid(path), -EINVAL);
2750         assert_return(!bus_pid_changed(bus), -ECHILD);
2751
2752         if (!BUS_IS_OPEN(bus->state))
2753                 return -ENOTCONN;
2754
2755         if (strv_isempty(interfaces))
2756                 return 0;
2757
2758         r = bus_find_parent_object_manager(bus, &object_manager, path);
2759         if (r < 0)
2760                 return r;
2761         if (r == 0)
2762                 return -ESRCH;
2763
2764         r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2765         if (r < 0)
2766                 return r;
2767
2768         r = sd_bus_message_append_basic(m, 'o', path);
2769         if (r < 0)
2770                 return r;
2771
2772         r = sd_bus_message_append_strv(m, interfaces);
2773         if (r < 0)
2774                 return r;
2775
2776         return sd_bus_send(bus, m, NULL);
2777 }
2778
2779 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2780         char **interfaces;
2781
2782         assert_return(bus, -EINVAL);
2783         assert_return(object_path_is_valid(path), -EINVAL);
2784         assert_return(!bus_pid_changed(bus), -ECHILD);
2785
2786         if (!BUS_IS_OPEN(bus->state))
2787                 return -ENOTCONN;
2788
2789         interfaces = strv_from_stdarg_alloca(interface);
2790
2791         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2792 }
2793
2794 _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
2795         sd_bus_slot *s;
2796         struct node *n;
2797         int r;
2798
2799         assert_return(bus, -EINVAL);
2800         assert_return(object_path_is_valid(path), -EINVAL);
2801         assert_return(!bus_pid_changed(bus), -ECHILD);
2802
2803         n = bus_node_allocate(bus, path);
2804         if (!n)
2805                 return -ENOMEM;
2806
2807         s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
2808         if (!s) {
2809                 r = -ENOMEM;
2810                 goto fail;
2811         }
2812
2813         s->node_object_manager.node = n;
2814         LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
2815         bus->nodes_modified = true;
2816
2817         if (slot)
2818                 *slot = s;
2819
2820         return 0;
2821
2822 fail:
2823         sd_bus_slot_unref(s);
2824         bus_node_gc(bus, n);
2825
2826         return r;
2827 }