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