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