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