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