chiark / gitweb /
sd-bus: add 'offset' member for vtable methods
[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                 r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
754                 if (r < 0)
755                         return r;
756                 if (bus->nodes_modified)
757                         return 0;
758         }
759
760         return 1;
761 }
762
763 static int property_get_all_callbacks_run(
764                 sd_bus *bus,
765                 sd_bus_message *m,
766                 struct node_vtable *first,
767                 bool require_fallback,
768                 const char *iface,
769                 bool *found_object) {
770
771         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
772         struct node_vtable *c;
773         bool found_interface;
774         int r;
775
776         assert(bus);
777         assert(m);
778         assert(found_object);
779
780         r = sd_bus_message_new_method_return(m, &reply);
781         if (r < 0)
782                 return r;
783
784         r = sd_bus_message_open_container(reply, 'a', "{sv}");
785         if (r < 0)
786                 return r;
787
788         found_interface = !iface ||
789                 streq(iface, "org.freedesktop.DBus.Properties") ||
790                 streq(iface, "org.freedesktop.DBus.Peer") ||
791                 streq(iface, "org.freedesktop.DBus.Introspectable");
792
793         LIST_FOREACH(vtables, c, first) {
794                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
795                 void *u;
796
797                 if (require_fallback && !c->is_fallback)
798                         continue;
799
800                 r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
801                 if (r < 0)
802                         return bus_maybe_reply_error(m, r, &error);
803                 if (bus->nodes_modified)
804                         return 0;
805                 if (r == 0)
806                         continue;
807
808                 *found_object = true;
809
810                 if (iface && !streq(c->interface, iface))
811                         continue;
812                 found_interface = true;
813
814                 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
815                 if (r < 0)
816                         return bus_maybe_reply_error(m, r, &error);
817                 if (bus->nodes_modified)
818                         return 0;
819         }
820
821         if (!found_interface) {
822                 r = sd_bus_reply_method_errorf(
823                                 m,
824                                 SD_BUS_ERROR_UNKNOWN_INTERFACE,
825                                 "Unknown interface '%s'.", iface);
826                 if (r < 0)
827                         return r;
828
829                 return 1;
830         }
831
832         r = sd_bus_message_close_container(reply);
833         if (r < 0)
834                 return r;
835
836         r = sd_bus_send(bus, reply, NULL);
837         if (r < 0)
838                 return r;
839
840         return 1;
841 }
842
843 static int bus_node_exists(
844                 sd_bus *bus,
845                 struct node *n,
846                 const char *path,
847                 bool require_fallback) {
848
849         struct node_vtable *c;
850         struct node_callback *k;
851         int r;
852
853         assert(bus);
854         assert(n);
855         assert(path);
856
857         /* Tests if there's anything attached directly to this node
858          * for the specified path */
859
860         if (!require_fallback && (n->enumerators || n->object_managers))
861                 return true;
862
863         LIST_FOREACH(callbacks, k, n->callbacks) {
864                 if (require_fallback && !k->is_fallback)
865                         continue;
866
867                 return 1;
868         }
869
870         LIST_FOREACH(vtables, c, n->vtables) {
871                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
872
873                 if (require_fallback && !c->is_fallback)
874                         continue;
875
876                 r = node_vtable_get_userdata(bus, path, c, NULL, &error);
877                 if (r != 0)
878                         return r;
879                 if (bus->nodes_modified)
880                         return 0;
881         }
882
883         return 0;
884 }
885
886 static int process_introspect(
887                 sd_bus *bus,
888                 sd_bus_message *m,
889                 struct node *n,
890                 bool require_fallback,
891                 bool *found_object) {
892
893         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
894         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
895         _cleanup_set_free_free_ Set *s = NULL;
896         const char *previous_interface = NULL;
897         struct introspect intro;
898         struct node_vtable *c;
899         bool empty;
900         int r;
901
902         assert(bus);
903         assert(m);
904         assert(n);
905         assert(found_object);
906
907         r = get_child_nodes(bus, m->path, n, false, &s, &error);
908         if (r < 0)
909                 return bus_maybe_reply_error(m, r, &error);
910         if (bus->nodes_modified)
911                 return 0;
912
913         r = introspect_begin(&intro, bus->trusted);
914         if (r < 0)
915                 return r;
916
917         r = introspect_write_default_interfaces(&intro, !require_fallback && n->object_managers);
918         if (r < 0)
919                 return r;
920
921         empty = set_isempty(s);
922
923         LIST_FOREACH(vtables, c, n->vtables) {
924                 if (require_fallback && !c->is_fallback)
925                         continue;
926
927                 r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
928                 if (r < 0) {
929                         r = bus_maybe_reply_error(m, r, &error);
930                         goto finish;
931                 }
932                 if (bus->nodes_modified) {
933                         r = 0;
934                         goto finish;
935                 }
936                 if (r == 0)
937                         continue;
938
939                 empty = false;
940
941                 if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
942                         continue;
943
944                 if (!streq_ptr(previous_interface, c->interface)) {
945
946                         if (previous_interface)
947                                 fputs(" </interface>\n", intro.f);
948
949                         fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
950                 }
951
952                 r = introspect_write_interface(&intro, c->vtable);
953                 if (r < 0)
954                         goto finish;
955
956                 previous_interface = c->interface;
957         }
958
959         if (previous_interface)
960                 fputs(" </interface>\n", intro.f);
961
962         if (empty) {
963                 /* Nothing?, let's see if we exist at all, and if not
964                  * refuse to do anything */
965                 r = bus_node_exists(bus, n, m->path, require_fallback);
966                 if (r <= 0)
967                         goto finish;
968                 if (bus->nodes_modified) {
969                         r = 0;
970                         goto finish;
971                 }
972         }
973
974         *found_object = true;
975
976         r = introspect_write_child_nodes(&intro, s, m->path);
977         if (r < 0)
978                 goto finish;
979
980         r = introspect_finish(&intro, bus, m, &reply);
981         if (r < 0)
982                 goto finish;
983
984         r = sd_bus_send(bus, reply, NULL);
985         if (r < 0)
986                 goto finish;
987
988         r = 1;
989
990 finish:
991         introspect_free(&intro);
992         return r;
993 }
994
995 static int object_manager_serialize_path(
996                 sd_bus *bus,
997                 sd_bus_message *reply,
998                 const char *prefix,
999                 const char *path,
1000                 bool require_fallback,
1001                 sd_bus_error *error) {
1002
1003         const char *previous_interface = NULL;
1004         bool found_something = false;
1005         struct node_vtable *i;
1006         struct node *n;
1007         int r;
1008
1009         assert(bus);
1010         assert(reply);
1011         assert(prefix);
1012         assert(path);
1013         assert(error);
1014
1015         n = hashmap_get(bus->nodes, prefix);
1016         if (!n)
1017                 return 0;
1018
1019         LIST_FOREACH(vtables, i, n->vtables) {
1020                 void *u;
1021
1022                 if (require_fallback && !i->is_fallback)
1023                         continue;
1024
1025                 r = node_vtable_get_userdata(bus, path, i, &u, error);
1026                 if (r < 0)
1027                         return r;
1028                 if (bus->nodes_modified)
1029                         return 0;
1030                 if (r == 0)
1031                         continue;
1032
1033                 if (!found_something) {
1034
1035                         /* Open the object part */
1036
1037                         r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
1038                         if (r < 0)
1039                                 return r;
1040
1041                         r = sd_bus_message_append(reply, "o", path);
1042                         if (r < 0)
1043                                 return r;
1044
1045                         r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
1046                         if (r < 0)
1047                                 return r;
1048
1049                         found_something = true;
1050                 }
1051
1052                 if (!streq_ptr(previous_interface, i->interface)) {
1053
1054                         /* Maybe close the previous interface part */
1055
1056                         if (previous_interface) {
1057                                 r = sd_bus_message_close_container(reply);
1058                                 if (r < 0)
1059                                         return r;
1060
1061                                 r = sd_bus_message_close_container(reply);
1062                                 if (r < 0)
1063                                         return r;
1064                         }
1065
1066                         /* Open the new interface part */
1067
1068                         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
1069                         if (r < 0)
1070                                 return r;
1071
1072                         r = sd_bus_message_append(reply, "s", i->interface);
1073                         if (r < 0)
1074                                 return r;
1075
1076                         r = sd_bus_message_open_container(reply, 'a', "{sv}");
1077                         if (r < 0)
1078                                 return r;
1079                 }
1080
1081                 r = vtable_append_all_properties(bus, reply, path, i, u, error);
1082                 if (r < 0)
1083                         return r;
1084                 if (bus->nodes_modified)
1085                         return 0;
1086
1087                 previous_interface = i->interface;
1088         }
1089
1090         if (previous_interface) {
1091                 r = sd_bus_message_close_container(reply);
1092                 if (r < 0)
1093                         return r;
1094
1095                 r = sd_bus_message_close_container(reply);
1096                 if (r < 0)
1097                         return r;
1098         }
1099
1100         if (found_something) {
1101                 r = sd_bus_message_close_container(reply);
1102                 if (r < 0)
1103                         return r;
1104
1105                 r = sd_bus_message_close_container(reply);
1106                 if (r < 0)
1107                         return r;
1108         }
1109
1110         return 1;
1111 }
1112
1113 static int object_manager_serialize_path_and_fallbacks(
1114                 sd_bus *bus,
1115                 sd_bus_message *reply,
1116                 const char *path,
1117                 sd_bus_error *error) {
1118
1119         char *prefix;
1120         int r;
1121
1122         assert(bus);
1123         assert(reply);
1124         assert(path);
1125         assert(error);
1126
1127         /* First, add all vtables registered for this path */
1128         r = object_manager_serialize_path(bus, reply, path, path, false, error);
1129         if (r < 0)
1130                 return r;
1131         if (bus->nodes_modified)
1132                 return 0;
1133
1134         /* Second, add fallback vtables registered for any of the prefixes */
1135         prefix = alloca(strlen(path) + 1);
1136         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1137                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
1138                 if (r < 0)
1139                         return r;
1140                 if (bus->nodes_modified)
1141                         return 0;
1142         }
1143
1144         return 0;
1145 }
1146
1147 static int process_get_managed_objects(
1148                 sd_bus *bus,
1149                 sd_bus_message *m,
1150                 struct node *n,
1151                 bool require_fallback,
1152                 bool *found_object) {
1153
1154         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1155         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1156         _cleanup_set_free_free_ Set *s = NULL;
1157         Iterator i;
1158         char *path;
1159         int r;
1160
1161         assert(bus);
1162         assert(m);
1163         assert(n);
1164         assert(found_object);
1165
1166         /* Spec says, GetManagedObjects() is only implemented on the root of a
1167          * sub-tree. Therefore, we require a registered object-manager on
1168          * exactly the queried path, otherwise, we refuse to respond. */
1169
1170         if (require_fallback || !n->object_managers)
1171                 return 0;
1172
1173         r = get_child_nodes(bus, m->path, n, true, &s, &error);
1174         if (r < 0)
1175                 return r;
1176         if (bus->nodes_modified)
1177                 return 0;
1178
1179         r = set_put_strdup(s, m->path);
1180         if (r < 0)
1181                 return r;
1182
1183         r = sd_bus_message_new_method_return(m, &reply);
1184         if (r < 0)
1185                 return r;
1186
1187         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
1188         if (r < 0)
1189                 return r;
1190
1191         SET_FOREACH(path, s, i) {
1192                 r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
1193                 if (r < 0)
1194                         return r;
1195
1196                 if (bus->nodes_modified)
1197                         return 0;
1198         }
1199
1200         r = sd_bus_message_close_container(reply);
1201         if (r < 0)
1202                 return r;
1203
1204         r = sd_bus_send(bus, reply, NULL);
1205         if (r < 0)
1206                 return r;
1207
1208         return 1;
1209 }
1210
1211 static int object_find_and_run(
1212                 sd_bus *bus,
1213                 sd_bus_message *m,
1214                 const char *p,
1215                 bool require_fallback,
1216                 bool *found_object) {
1217
1218         struct node *n;
1219         struct vtable_member vtable_key, *v;
1220         int r;
1221
1222         assert(bus);
1223         assert(m);
1224         assert(p);
1225         assert(found_object);
1226
1227         n = hashmap_get(bus->nodes, p);
1228         if (!n)
1229                 return 0;
1230
1231         /* First, try object callbacks */
1232         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
1233         if (r != 0)
1234                 return r;
1235         if (bus->nodes_modified)
1236                 return 0;
1237
1238         if (!m->interface || !m->member)
1239                 return 0;
1240
1241         /* Then, look for a known method */
1242         vtable_key.path = (char*) p;
1243         vtable_key.interface = m->interface;
1244         vtable_key.member = m->member;
1245
1246         v = hashmap_get(bus->vtable_methods, &vtable_key);
1247         if (v) {
1248                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1249                 if (r != 0)
1250                         return r;
1251                 if (bus->nodes_modified)
1252                         return 0;
1253         }
1254
1255         /* Then, look for a known property */
1256         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1257                 bool get = false;
1258
1259                 get = streq(m->member, "Get");
1260
1261                 if (get || streq(m->member, "Set")) {
1262
1263                         r = sd_bus_message_rewind(m, true);
1264                         if (r < 0)
1265                                 return r;
1266
1267                         vtable_key.path = (char*) p;
1268
1269                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1270                         if (r < 0)
1271                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
1272
1273                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1274                         if (v) {
1275                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1276                                 if (r != 0)
1277                                         return r;
1278                         }
1279
1280                 } else if (streq(m->member, "GetAll")) {
1281                         const char *iface;
1282
1283                         r = sd_bus_message_rewind(m, true);
1284                         if (r < 0)
1285                                 return r;
1286
1287                         r = sd_bus_message_read(m, "s", &iface);
1288                         if (r < 0)
1289                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
1290
1291                         if (iface[0] == 0)
1292                                 iface = NULL;
1293
1294                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1295                         if (r != 0)
1296                                 return r;
1297                 }
1298
1299         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1300
1301                 if (!isempty(sd_bus_message_get_signature(m, true)))
1302                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1303
1304                 r = process_introspect(bus, m, n, require_fallback, found_object);
1305                 if (r != 0)
1306                         return r;
1307
1308         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
1309
1310                 if (!isempty(sd_bus_message_get_signature(m, true)))
1311                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1312
1313                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
1314                 if (r != 0)
1315                         return r;
1316         }
1317
1318         if (bus->nodes_modified)
1319                 return 0;
1320
1321         if (!*found_object) {
1322                 r = bus_node_exists(bus, n, m->path, require_fallback);
1323                 if (r < 0)
1324                         return r;
1325                 if (bus->nodes_modified)
1326                         return 0;
1327                 if (r > 0)
1328                         *found_object = true;
1329         }
1330
1331         return 0;
1332 }
1333
1334 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1335         int r;
1336         size_t pl;
1337         bool found_object = false;
1338
1339         assert(bus);
1340         assert(m);
1341
1342         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1343                 return 0;
1344
1345         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1346                 return 0;
1347
1348         if (hashmap_isempty(bus->nodes))
1349                 return 0;
1350
1351         /* Never respond to broadcast messages */
1352         if (bus->bus_client && !m->destination)
1353                 return 0;
1354
1355         assert(m->path);
1356         assert(m->member);
1357
1358         pl = strlen(m->path);
1359         do {
1360                 char prefix[pl+1];
1361
1362                 bus->nodes_modified = false;
1363
1364                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1365                 if (r != 0)
1366                         return r;
1367
1368                 /* Look for fallback prefixes */
1369                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1370
1371                         if (bus->nodes_modified)
1372                                 break;
1373
1374                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1375                         if (r != 0)
1376                                 return r;
1377                 }
1378
1379         } while (bus->nodes_modified);
1380
1381         if (!found_object)
1382                 return 0;
1383
1384         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1385             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1386                 r = sd_bus_reply_method_errorf(
1387                                 m,
1388                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
1389                                 "Unknown property or interface.");
1390         else
1391                 r = sd_bus_reply_method_errorf(
1392                                 m,
1393                                 SD_BUS_ERROR_UNKNOWN_METHOD,
1394                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1395
1396         if (r < 0)
1397                 return r;
1398
1399         return 1;
1400 }
1401
1402 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1403         struct node *n, *parent;
1404         const char *e;
1405         _cleanup_free_ char *s = NULL;
1406         char *p;
1407         int r;
1408
1409         assert(bus);
1410         assert(path);
1411         assert(path[0] == '/');
1412
1413         n = hashmap_get(bus->nodes, path);
1414         if (n)
1415                 return n;
1416
1417         r = hashmap_ensure_allocated(&bus->nodes, &string_hash_ops);
1418         if (r < 0)
1419                 return NULL;
1420
1421         s = strdup(path);
1422         if (!s)
1423                 return NULL;
1424
1425         if (streq(path, "/"))
1426                 parent = NULL;
1427         else {
1428                 e = strrchr(path, '/');
1429                 assert(e);
1430
1431                 p = strndupa(path, MAX(1, e - path));
1432
1433                 parent = bus_node_allocate(bus, p);
1434                 if (!parent)
1435                         return NULL;
1436         }
1437
1438         n = new0(struct node, 1);
1439         if (!n)
1440                 return NULL;
1441
1442         n->parent = parent;
1443         n->path = s;
1444         s = NULL; /* do not free */
1445
1446         r = hashmap_put(bus->nodes, n->path, n);
1447         if (r < 0) {
1448                 free(n->path);
1449                 free(n);
1450                 return NULL;
1451         }
1452
1453         if (parent)
1454                 LIST_PREPEND(siblings, parent->child, n);
1455
1456         return n;
1457 }
1458
1459 void bus_node_gc(sd_bus *b, struct node *n) {
1460         assert(b);
1461
1462         if (!n)
1463                 return;
1464
1465         if (n->child ||
1466             n->callbacks ||
1467             n->vtables ||
1468             n->enumerators ||
1469             n->object_managers)
1470                 return;
1471
1472         assert(hashmap_remove(b->nodes, n->path) == n);
1473
1474         if (n->parent)
1475                 LIST_REMOVE(siblings, n->parent->child, n);
1476
1477         free(n->path);
1478         bus_node_gc(b, n->parent);
1479         free(n);
1480 }
1481
1482 static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) {
1483         struct node *n;
1484
1485         assert(bus);
1486         assert(path);
1487
1488         n = hashmap_get(bus->nodes, path);
1489         if (!n) {
1490                 char *prefix;
1491
1492                 prefix = alloca(strlen(path) + 1);
1493                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1494                         n = hashmap_get(bus->nodes, prefix);
1495                         if (n)
1496                                 break;
1497                 }
1498         }
1499
1500         while (n && !n->object_managers)
1501                 n = n->parent;
1502
1503         if (out)
1504                 *out = n;
1505         return !!n;
1506 }
1507
1508 static int bus_add_object(
1509                 sd_bus *bus,
1510                 sd_bus_slot **slot,
1511                 bool fallback,
1512                 const char *path,
1513                 sd_bus_message_handler_t callback,
1514                 void *userdata) {
1515
1516         sd_bus_slot *s;
1517         struct node *n;
1518         int r;
1519
1520         assert_return(bus, -EINVAL);
1521         assert_return(object_path_is_valid(path), -EINVAL);
1522         assert_return(callback, -EINVAL);
1523         assert_return(!bus_pid_changed(bus), -ECHILD);
1524
1525         n = bus_node_allocate(bus, path);
1526         if (!n)
1527                 return -ENOMEM;
1528
1529         s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
1530         if (!s) {
1531                 r = -ENOMEM;
1532                 goto fail;
1533         }
1534
1535         s->node_callback.callback = callback;
1536         s->node_callback.is_fallback = fallback;
1537
1538         s->node_callback.node = n;
1539         LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
1540         bus->nodes_modified = true;
1541
1542         if (slot)
1543                 *slot = s;
1544
1545         return 0;
1546
1547 fail:
1548         sd_bus_slot_unref(s);
1549         bus_node_gc(bus, n);
1550
1551         return r;
1552 }
1553
1554 _public_ int sd_bus_add_object(
1555                 sd_bus *bus,
1556                 sd_bus_slot **slot,
1557                 const char *path,
1558                 sd_bus_message_handler_t callback,
1559                 void *userdata) {
1560
1561         return bus_add_object(bus, slot, false, path, callback, userdata);
1562 }
1563
1564 _public_ int sd_bus_add_fallback(
1565                 sd_bus *bus,
1566                 sd_bus_slot **slot,
1567                 const char *prefix,
1568                 sd_bus_message_handler_t callback,
1569                 void *userdata) {
1570
1571         return bus_add_object(bus, slot, true, prefix, callback, userdata);
1572 }
1573
1574 static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
1575         const struct vtable_member *m = a;
1576         uint8_t hash_key2[HASH_KEY_SIZE];
1577         unsigned long ret;
1578
1579         assert(m);
1580
1581         ret = string_hash_func(m->path, hash_key);
1582
1583         /* Use a slightly different hash key for the interface */
1584         memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
1585         hash_key2[0]++;
1586         ret ^= string_hash_func(m->interface, hash_key2);
1587
1588         /* And an even different one for the  member */
1589         hash_key2[0]++;
1590         ret ^= string_hash_func(m->member, hash_key2);
1591
1592         return ret;
1593 }
1594
1595 static int vtable_member_compare_func(const void *a, const void *b) {
1596         const struct vtable_member *x = a, *y = b;
1597         int r;
1598
1599         assert(x);
1600         assert(y);
1601
1602         r = strcmp(x->path, y->path);
1603         if (r != 0)
1604                 return r;
1605
1606         r = strcmp(x->interface, y->interface);
1607         if (r != 0)
1608                 return r;
1609
1610         return strcmp(x->member, y->member);
1611 }
1612
1613 static const struct hash_ops vtable_member_hash_ops = {
1614         .hash = vtable_member_hash_func,
1615         .compare = vtable_member_compare_func
1616 };
1617
1618 static int add_object_vtable_internal(
1619                 sd_bus *bus,
1620                 sd_bus_slot **slot,
1621                 const char *path,
1622                 const char *interface,
1623                 const sd_bus_vtable *vtable,
1624                 bool fallback,
1625                 sd_bus_object_find_t find,
1626                 void *userdata) {
1627
1628         sd_bus_slot *s = NULL;
1629         struct node_vtable *i, *existing = NULL;
1630         const sd_bus_vtable *v;
1631         struct node *n;
1632         int r;
1633
1634         assert_return(bus, -EINVAL);
1635         assert_return(object_path_is_valid(path), -EINVAL);
1636         assert_return(interface_name_is_valid(interface), -EINVAL);
1637         assert_return(vtable, -EINVAL);
1638         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1639         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1640         assert_return(!bus_pid_changed(bus), -ECHILD);
1641         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1642                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1643                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1644                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1645
1646         r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops);
1647         if (r < 0)
1648                 return r;
1649
1650         r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops);
1651         if (r < 0)
1652                 return r;
1653
1654         n = bus_node_allocate(bus, path);
1655         if (!n)
1656                 return -ENOMEM;
1657
1658         LIST_FOREACH(vtables, i, n->vtables) {
1659                 if (i->is_fallback != fallback) {
1660                         r = -EPROTOTYPE;
1661                         goto fail;
1662                 }
1663
1664                 if (streq(i->interface, interface)) {
1665
1666                         if (i->vtable == vtable) {
1667                                 r = -EEXIST;
1668                                 goto fail;
1669                         }
1670
1671                         existing = i;
1672                 }
1673         }
1674
1675         s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
1676         if (!s) {
1677                 r = -ENOMEM;
1678                 goto fail;
1679         }
1680
1681         s->node_vtable.is_fallback = fallback;
1682         s->node_vtable.vtable = vtable;
1683         s->node_vtable.find = find;
1684
1685         s->node_vtable.interface = strdup(interface);
1686         if (!s->node_vtable.interface) {
1687                 r = -ENOMEM;
1688                 goto fail;
1689         }
1690
1691         for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1692
1693                 switch (v->type) {
1694
1695                 case _SD_BUS_VTABLE_METHOD: {
1696                         struct vtable_member *m;
1697
1698                         if (!member_name_is_valid(v->x.method.member) ||
1699                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1700                             !signature_is_valid(strempty(v->x.method.result), false) ||
1701                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1702                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1703                                 r = -EINVAL;
1704                                 goto fail;
1705                         }
1706
1707                         m = new0(struct vtable_member, 1);
1708                         if (!m) {
1709                                 r = -ENOMEM;
1710                                 goto fail;
1711                         }
1712
1713                         m->parent = &s->node_vtable;
1714                         m->path = n->path;
1715                         m->interface = s->node_vtable.interface;
1716                         m->member = v->x.method.member;
1717                         m->vtable = v;
1718
1719                         r = hashmap_put(bus->vtable_methods, m, m);
1720                         if (r < 0) {
1721                                 free(m);
1722                                 goto fail;
1723                         }
1724
1725                         break;
1726                 }
1727
1728                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1729
1730                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1731                                 r = -EINVAL;
1732                                 goto fail;
1733                         }
1734
1735                         if (v->flags & SD_BUS_VTABLE_PROPERTY_CONST) {
1736                                 r = -EINVAL;
1737                                 goto fail;
1738                         }
1739
1740                         /* Fall through */
1741
1742                 case _SD_BUS_VTABLE_PROPERTY: {
1743                         struct vtable_member *m;
1744
1745                         if (!member_name_is_valid(v->x.property.member) ||
1746                             !signature_is_single(v->x.property.signature, false) ||
1747                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1748                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1749                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
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 static int object_removed_append_all_prefix(
2370                 sd_bus *bus,
2371                 sd_bus_message *m,
2372                 Set *s,
2373                 const char *prefix,
2374                 const char *path,
2375                 bool require_fallback) {
2376
2377         const char *previous_interface = NULL;
2378         struct node_vtable *c;
2379         struct node *n;
2380         int r;
2381
2382         assert(bus);
2383         assert(m);
2384         assert(s);
2385         assert(prefix);
2386         assert(path);
2387
2388         n = hashmap_get(bus->nodes, prefix);
2389         if (!n)
2390                 return 0;
2391
2392         LIST_FOREACH(vtables, c, n->vtables) {
2393                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2394                 void *u = NULL;
2395
2396                 if (require_fallback && !c->is_fallback)
2397                         continue;
2398                 if (streq_ptr(c->interface, previous_interface))
2399                         continue;
2400
2401                 /* If a child-node already handled this interface, we
2402                  * skip it on any of its parents. The child vtables
2403                  * always fully override any conflicting vtables of
2404                  * any parent node. */
2405                 if (set_get(s, c->interface))
2406                         continue;
2407
2408                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2409                 if (r < 0)
2410                         return r;
2411                 if (bus->nodes_modified)
2412                         return 0;
2413                 if (r == 0)
2414                         continue;
2415
2416                 r = set_put(s, c->interface);
2417                 if (r < 0)
2418                         return r;
2419
2420                 r = sd_bus_message_append(m, "s", c->interface);
2421                 if (r < 0)
2422                         return r;
2423
2424                 previous_interface = c->interface;
2425         }
2426
2427         return 0;
2428 }
2429
2430 static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2431         _cleanup_set_free_ Set *s = NULL;
2432         char *prefix;
2433         int r;
2434
2435         assert(bus);
2436         assert(m);
2437         assert(path);
2438
2439         /* see sd_bus_emit_object_added() for details */
2440
2441         s = set_new(&string_hash_ops);
2442         if (!s)
2443                 return -ENOMEM;
2444
2445         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Peer");
2446         if (r < 0)
2447                 return r;
2448         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Introspectable");
2449         if (r < 0)
2450                 return r;
2451         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Properties");
2452         if (r < 0)
2453                 return r;
2454         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
2455         if (r < 0)
2456                 return r;
2457
2458         r = object_removed_append_all_prefix(bus, m, s, path, path, false);
2459         if (r < 0)
2460                 return r;
2461         if (bus->nodes_modified)
2462                 return 0;
2463
2464         prefix = alloca(strlen(path) + 1);
2465         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2466                 r = object_removed_append_all_prefix(bus, m, s, prefix, path, true);
2467                 if (r < 0)
2468                         return r;
2469                 if (bus->nodes_modified)
2470                         return 0;
2471         }
2472
2473         return 0;
2474 }
2475
2476 _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
2477         BUS_DONT_DESTROY(bus);
2478
2479         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2480         struct node *object_manager;
2481         int r;
2482
2483         /*
2484          * This is like sd_bus_emit_object_added(), but emits an
2485          * InterfacesRemoved signal on the given path. This only includes any
2486          * registered interfaces but skips the properties. Note that this will
2487          * call into the find() callbacks of any registered vtable. Therefore,
2488          * you must call this function before destroying/unlinking your object.
2489          * Otherwise, the list of interfaces will be incomplete. However, note
2490          * that this will *NOT* call into any property callback. Therefore, the
2491          * object might be in an "destructed" state, as long as we can find it.
2492          */
2493
2494         assert_return(bus, -EINVAL);
2495         assert_return(object_path_is_valid(path), -EINVAL);
2496         assert_return(!bus_pid_changed(bus), -ECHILD);
2497
2498         if (!BUS_IS_OPEN(bus->state))
2499                 return -ENOTCONN;
2500
2501         r = bus_find_parent_object_manager(bus, &object_manager, path);
2502         if (r < 0)
2503                 return r;
2504         if (r == 0)
2505                 return -ESRCH;
2506
2507         do {
2508                 bus->nodes_modified = false;
2509                 m = sd_bus_message_unref(m);
2510
2511                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2512                 if (r < 0)
2513                         return r;
2514
2515                 r = sd_bus_message_append_basic(m, 'o', path);
2516                 if (r < 0)
2517                         return r;
2518
2519                 r = sd_bus_message_open_container(m, 'a', "s");
2520                 if (r < 0)
2521                         return r;
2522
2523                 r = object_removed_append_all(bus, m, path);
2524                 if (r < 0)
2525                         return r;
2526
2527                 if (bus->nodes_modified)
2528                         continue;
2529
2530                 r = sd_bus_message_close_container(m);
2531                 if (r < 0)
2532                         return r;
2533
2534         } while (bus->nodes_modified);
2535
2536         return sd_bus_send(bus, m, NULL);
2537 }
2538
2539 static int interfaces_added_append_one_prefix(
2540                 sd_bus *bus,
2541                 sd_bus_message *m,
2542                 const char *prefix,
2543                 const char *path,
2544                 const char *interface,
2545                 bool require_fallback) {
2546
2547         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2548         bool found_interface = false;
2549         struct node_vtable *c;
2550         struct node *n;
2551         void *u = NULL;
2552         int r;
2553
2554         assert(bus);
2555         assert(m);
2556         assert(prefix);
2557         assert(path);
2558         assert(interface);
2559
2560         n = hashmap_get(bus->nodes, prefix);
2561         if (!n)
2562                 return 0;
2563
2564         LIST_FOREACH(vtables, c, n->vtables) {
2565                 if (require_fallback && !c->is_fallback)
2566                         continue;
2567
2568                 if (!streq(c->interface, interface))
2569                         continue;
2570
2571                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2572                 if (r < 0)
2573                         return r;
2574                 if (bus->nodes_modified)
2575                         return 0;
2576                 if (r == 0)
2577                         continue;
2578
2579                 if (!found_interface) {
2580                         r = sd_bus_message_append_basic(m, 's', interface);
2581                         if (r < 0)
2582                                 return r;
2583
2584                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2585                         if (r < 0)
2586                                 return r;
2587
2588                         found_interface = true;
2589                 }
2590
2591                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2592                 if (r < 0)
2593                         return r;
2594                 if (bus->nodes_modified)
2595                         return 0;
2596         }
2597
2598         if (found_interface) {
2599                 r = sd_bus_message_close_container(m);
2600                 if (r < 0)
2601                         return r;
2602         }
2603
2604         return found_interface;
2605 }
2606
2607 static int interfaces_added_append_one(
2608                 sd_bus *bus,
2609                 sd_bus_message *m,
2610                 const char *path,
2611                 const char *interface) {
2612
2613         char *prefix;
2614         int r;
2615
2616         assert(bus);
2617         assert(m);
2618         assert(path);
2619         assert(interface);
2620
2621         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2622         if (r != 0)
2623                 return r;
2624         if (bus->nodes_modified)
2625                 return 0;
2626
2627         prefix = alloca(strlen(path) + 1);
2628         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2629                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2630                 if (r != 0)
2631                         return r;
2632                 if (bus->nodes_modified)
2633                         return 0;
2634         }
2635
2636         return -ENOENT;
2637 }
2638
2639 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2640         BUS_DONT_DESTROY(bus);
2641
2642         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2643         struct node *object_manager;
2644         char **i;
2645         int r;
2646
2647         assert_return(bus, -EINVAL);
2648         assert_return(object_path_is_valid(path), -EINVAL);
2649         assert_return(!bus_pid_changed(bus), -ECHILD);
2650
2651         if (!BUS_IS_OPEN(bus->state))
2652                 return -ENOTCONN;
2653
2654         if (strv_isempty(interfaces))
2655                 return 0;
2656
2657         r = bus_find_parent_object_manager(bus, &object_manager, path);
2658         if (r < 0)
2659                 return r;
2660         if (r == 0)
2661                 return -ESRCH;
2662
2663         do {
2664                 bus->nodes_modified = false;
2665                 m = sd_bus_message_unref(m);
2666
2667                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2668                 if (r < 0)
2669                         return r;
2670
2671                 r = sd_bus_message_append_basic(m, 'o', path);
2672                 if (r < 0)
2673                         return r;
2674
2675                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2676                 if (r < 0)
2677                         return r;
2678
2679                 STRV_FOREACH(i, interfaces) {
2680                         assert_return(interface_name_is_valid(*i), -EINVAL);
2681
2682                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2683                         if (r < 0)
2684                                 return r;
2685
2686                         r = interfaces_added_append_one(bus, m, path, *i);
2687                         if (r < 0)
2688                                 return r;
2689
2690                         if (bus->nodes_modified)
2691                                 break;
2692
2693                         r = sd_bus_message_close_container(m);
2694                         if (r < 0)
2695                                 return r;
2696                 }
2697
2698                 if (bus->nodes_modified)
2699                         continue;
2700
2701                 r = sd_bus_message_close_container(m);
2702                 if (r < 0)
2703                         return r;
2704
2705         } while (bus->nodes_modified);
2706
2707         return sd_bus_send(bus, m, NULL);
2708 }
2709
2710 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2711         char **interfaces;
2712
2713         assert_return(bus, -EINVAL);
2714         assert_return(object_path_is_valid(path), -EINVAL);
2715         assert_return(!bus_pid_changed(bus), -ECHILD);
2716
2717         if (!BUS_IS_OPEN(bus->state))
2718                 return -ENOTCONN;
2719
2720         interfaces = strv_from_stdarg_alloca(interface);
2721
2722         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2723 }
2724
2725 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2726         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2727         struct node *object_manager;
2728         int r;
2729
2730         assert_return(bus, -EINVAL);
2731         assert_return(object_path_is_valid(path), -EINVAL);
2732         assert_return(!bus_pid_changed(bus), -ECHILD);
2733
2734         if (!BUS_IS_OPEN(bus->state))
2735                 return -ENOTCONN;
2736
2737         if (strv_isempty(interfaces))
2738                 return 0;
2739
2740         r = bus_find_parent_object_manager(bus, &object_manager, path);
2741         if (r < 0)
2742                 return r;
2743         if (r == 0)
2744                 return -ESRCH;
2745
2746         r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2747         if (r < 0)
2748                 return r;
2749
2750         r = sd_bus_message_append_basic(m, 'o', path);
2751         if (r < 0)
2752                 return r;
2753
2754         r = sd_bus_message_append_strv(m, interfaces);
2755         if (r < 0)
2756                 return r;
2757
2758         return sd_bus_send(bus, m, NULL);
2759 }
2760
2761 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2762         char **interfaces;
2763
2764         assert_return(bus, -EINVAL);
2765         assert_return(object_path_is_valid(path), -EINVAL);
2766         assert_return(!bus_pid_changed(bus), -ECHILD);
2767
2768         if (!BUS_IS_OPEN(bus->state))
2769                 return -ENOTCONN;
2770
2771         interfaces = strv_from_stdarg_alloca(interface);
2772
2773         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2774 }
2775
2776 _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
2777         sd_bus_slot *s;
2778         struct node *n;
2779         int r;
2780
2781         assert_return(bus, -EINVAL);
2782         assert_return(object_path_is_valid(path), -EINVAL);
2783         assert_return(!bus_pid_changed(bus), -ECHILD);
2784
2785         n = bus_node_allocate(bus, path);
2786         if (!n)
2787                 return -ENOMEM;
2788
2789         s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
2790         if (!s) {
2791                 r = -ENOMEM;
2792                 goto fail;
2793         }
2794
2795         s->node_object_manager.node = n;
2796         LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
2797         bus->nodes_modified = true;
2798
2799         if (slot)
2800                 *slot = s;
2801
2802         return 0;
2803
2804 fail:
2805         sd_bus_slot_unref(s);
2806         bus_node_gc(bus, n);
2807
2808         return r;
2809 }