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