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