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