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