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