chiark / gitweb /
05a00f2178f63c530f1bb0b5388ab3c9d0941b8d
[elogind.git] / src / libelogind / sd-bus / bus-objects.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "strv.h"
23 #include "set.h"
24 #include "bus-internal.h"
25 #include "bus-message.h"
26 #include "bus-type.h"
27 #include "bus-signature.h"
28 #include "bus-introspect.h"
29 #include "bus-util.h"
30 #include "bus-slot.h"
31 #include "bus-objects.h"
32
33 static int node_vtable_get_userdata(
34                 sd_bus *bus,
35                 const char *path,
36                 struct node_vtable *c,
37                 void **userdata,
38                 sd_bus_error *error) {
39
40         sd_bus_slot *s;
41         void *u;
42         int r;
43
44         assert(bus);
45         assert(path);
46         assert(c);
47
48         s = container_of(c, sd_bus_slot, node_vtable);
49         u = s->userdata;
50         if (c->find) {
51                 bus->current_slot = sd_bus_slot_ref(s);
52                 bus->current_userdata = u;
53                 r = c->find(bus, path, c->interface, u, &u, error);
54                 bus->current_userdata = NULL;
55                 bus->current_slot = sd_bus_slot_unref(s);
56
57                 if (r < 0)
58                         return r;
59                 if (sd_bus_error_is_set(error))
60                         return -sd_bus_error_get_errno(error);
61                 if (r == 0)
62                         return r;
63         }
64
65         if (userdata)
66                 *userdata = u;
67
68         return 1;
69 }
70
71 static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
72         assert(p);
73
74         return (uint8_t*) u + p->x.method.offset;
75 }
76
77 static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
78         assert(p);
79
80         return (uint8_t*) u + p->x.property.offset;
81 }
82
83 static int vtable_property_get_userdata(
84                 sd_bus *bus,
85                 const char *path,
86                 struct vtable_member *p,
87                 void **userdata,
88                 sd_bus_error *error) {
89
90         void *u;
91         int r;
92
93         assert(bus);
94         assert(path);
95         assert(p);
96         assert(userdata);
97
98         r = node_vtable_get_userdata(bus, path, p->parent, &u, error);
99         if (r <= 0)
100                 return r;
101         if (bus->nodes_modified)
102                 return 0;
103
104         *userdata = vtable_property_convert_userdata(p->vtable, u);
105         return 1;
106 }
107
108 static int add_enumerated_to_set(
109                 sd_bus *bus,
110                 const char *prefix,
111                 struct node_enumerator *first,
112                 Set *s,
113                 sd_bus_error *error) {
114
115         struct node_enumerator *c;
116         int r;
117
118         assert(bus);
119         assert(prefix);
120         assert(s);
121
122         LIST_FOREACH(enumerators, c, first) {
123                 char **children = NULL, **k;
124                 sd_bus_slot *slot;
125
126                 if (bus->nodes_modified)
127                         return 0;
128
129                 slot = container_of(c, sd_bus_slot, node_enumerator);
130
131                 bus->current_slot = sd_bus_slot_ref(slot);
132                 bus->current_userdata = slot->userdata;
133                 r = c->callback(bus, prefix, slot->userdata, &children, error);
134                 bus->current_userdata = NULL;
135                 bus->current_slot = sd_bus_slot_unref(slot);
136
137                 if (r < 0)
138                         return r;
139                 if (sd_bus_error_is_set(error))
140                         return -sd_bus_error_get_errno(error);
141
142                 STRV_FOREACH(k, children) {
143                         if (r < 0) {
144                                 free(*k);
145                                 continue;
146                         }
147
148                         if (!object_path_is_valid(*k)){
149                                 free(*k);
150                                 r = -EINVAL;
151                                 continue;
152                         }
153
154                         if (!object_path_startswith(*k, prefix)) {
155                                 free(*k);
156                                 continue;
157                         }
158
159                         r = set_consume(s, *k);
160                         if (r == -EEXIST)
161                                 r = 0;
162                 }
163
164                 free(children);
165                 if (r < 0)
166                         return r;
167         }
168
169         return 0;
170 }
171
172 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_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_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_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
582         _cleanup_bus_message_unref_ 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_bus_message_unref_ 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_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_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_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
905         _cleanup_bus_message_unref_ 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                         found_something = true;
1061                 }
1062
1063                 if (!streq_ptr(previous_interface, i->interface)) {
1064
1065                         /* Maybe close the previous interface part */
1066
1067                         if (previous_interface) {
1068                                 r = sd_bus_message_close_container(reply);
1069                                 if (r < 0)
1070                                         return r;
1071
1072                                 r = sd_bus_message_close_container(reply);
1073                                 if (r < 0)
1074                                         return r;
1075                         }
1076
1077                         /* Open the new interface part */
1078
1079                         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
1080                         if (r < 0)
1081                                 return r;
1082
1083                         r = sd_bus_message_append(reply, "s", i->interface);
1084                         if (r < 0)
1085                                 return r;
1086
1087                         r = sd_bus_message_open_container(reply, 'a', "{sv}");
1088                         if (r < 0)
1089                                 return r;
1090                 }
1091
1092                 r = vtable_append_all_properties(bus, reply, path, i, u, error);
1093                 if (r < 0)
1094                         return r;
1095                 if (bus->nodes_modified)
1096                         return 0;
1097
1098                 previous_interface = i->interface;
1099         }
1100
1101         if (previous_interface) {
1102                 r = sd_bus_message_close_container(reply);
1103                 if (r < 0)
1104                         return r;
1105
1106                 r = sd_bus_message_close_container(reply);
1107                 if (r < 0)
1108                         return r;
1109         }
1110
1111         if (found_something) {
1112                 r = sd_bus_message_close_container(reply);
1113                 if (r < 0)
1114                         return r;
1115
1116                 r = sd_bus_message_close_container(reply);
1117                 if (r < 0)
1118                         return r;
1119         }
1120
1121         return 1;
1122 }
1123
1124 static int object_manager_serialize_path_and_fallbacks(
1125                 sd_bus *bus,
1126                 sd_bus_message *reply,
1127                 const char *path,
1128                 sd_bus_error *error) {
1129
1130         char *prefix;
1131         int r;
1132
1133         assert(bus);
1134         assert(reply);
1135         assert(path);
1136         assert(error);
1137
1138         /* First, add all vtables registered for this path */
1139         r = object_manager_serialize_path(bus, reply, path, path, false, error);
1140         if (r < 0)
1141                 return r;
1142         if (bus->nodes_modified)
1143                 return 0;
1144
1145         /* Second, add fallback vtables registered for any of the prefixes */
1146         prefix = alloca(strlen(path) + 1);
1147         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1148                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
1149                 if (r < 0)
1150                         return r;
1151                 if (bus->nodes_modified)
1152                         return 0;
1153         }
1154
1155         return 0;
1156 }
1157
1158 static int process_get_managed_objects(
1159                 sd_bus *bus,
1160                 sd_bus_message *m,
1161                 struct node *n,
1162                 bool require_fallback,
1163                 bool *found_object) {
1164
1165         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1166         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1167         _cleanup_set_free_free_ Set *s = NULL;
1168         Iterator i;
1169         char *path;
1170         int r;
1171
1172         assert(bus);
1173         assert(m);
1174         assert(n);
1175         assert(found_object);
1176
1177         /* Spec says, GetManagedObjects() is only implemented on the root of a
1178          * sub-tree. Therefore, we require a registered object-manager on
1179          * exactly the queried path, otherwise, we refuse to respond. */
1180
1181         if (require_fallback || !n->object_managers)
1182                 return 0;
1183
1184         r = get_child_nodes(bus, m->path, n, CHILDREN_RECURSIVE, &s, &error);
1185         if (r < 0)
1186                 return r;
1187         if (bus->nodes_modified)
1188                 return 0;
1189
1190         r = sd_bus_message_new_method_return(m, &reply);
1191         if (r < 0)
1192                 return r;
1193
1194         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
1195         if (r < 0)
1196                 return r;
1197
1198         SET_FOREACH(path, s, i) {
1199                 r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
1200                 if (r < 0)
1201                         return r;
1202
1203                 if (bus->nodes_modified)
1204                         return 0;
1205         }
1206
1207         r = sd_bus_message_close_container(reply);
1208         if (r < 0)
1209                 return r;
1210
1211         r = sd_bus_send(bus, reply, NULL);
1212         if (r < 0)
1213                 return r;
1214
1215         return 1;
1216 }
1217
1218 static int object_find_and_run(
1219                 sd_bus *bus,
1220                 sd_bus_message *m,
1221                 const char *p,
1222                 bool require_fallback,
1223                 bool *found_object) {
1224
1225         struct node *n;
1226         struct vtable_member vtable_key, *v;
1227         int r;
1228
1229         assert(bus);
1230         assert(m);
1231         assert(p);
1232         assert(found_object);
1233
1234         n = hashmap_get(bus->nodes, p);
1235         if (!n)
1236                 return 0;
1237
1238         /* First, try object callbacks */
1239         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
1240         if (r != 0)
1241                 return r;
1242         if (bus->nodes_modified)
1243                 return 0;
1244
1245         if (!m->interface || !m->member)
1246                 return 0;
1247
1248         /* Then, look for a known method */
1249         vtable_key.path = (char*) p;
1250         vtable_key.interface = m->interface;
1251         vtable_key.member = m->member;
1252
1253         v = hashmap_get(bus->vtable_methods, &vtable_key);
1254         if (v) {
1255                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1256                 if (r != 0)
1257                         return r;
1258                 if (bus->nodes_modified)
1259                         return 0;
1260         }
1261
1262         /* Then, look for a known property */
1263         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1264                 bool get = false;
1265
1266                 get = streq(m->member, "Get");
1267
1268                 if (get || streq(m->member, "Set")) {
1269
1270                         r = sd_bus_message_rewind(m, true);
1271                         if (r < 0)
1272                                 return r;
1273
1274                         vtable_key.path = (char*) p;
1275
1276                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1277                         if (r < 0)
1278                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
1279
1280                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1281                         if (v) {
1282                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1283                                 if (r != 0)
1284                                         return r;
1285                         }
1286
1287                 } else if (streq(m->member, "GetAll")) {
1288                         const char *iface;
1289
1290                         r = sd_bus_message_rewind(m, true);
1291                         if (r < 0)
1292                                 return r;
1293
1294                         r = sd_bus_message_read(m, "s", &iface);
1295                         if (r < 0)
1296                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
1297
1298                         if (iface[0] == 0)
1299                                 iface = NULL;
1300
1301                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1302                         if (r != 0)
1303                                 return r;
1304                 }
1305
1306         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1307
1308                 if (!isempty(sd_bus_message_get_signature(m, true)))
1309                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1310
1311                 r = process_introspect(bus, m, n, require_fallback, found_object);
1312                 if (r != 0)
1313                         return r;
1314
1315         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
1316
1317                 if (!isempty(sd_bus_message_get_signature(m, true)))
1318                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
1319
1320                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
1321                 if (r != 0)
1322                         return r;
1323         }
1324
1325         if (bus->nodes_modified)
1326                 return 0;
1327
1328         if (!*found_object) {
1329                 r = bus_node_exists(bus, n, m->path, require_fallback);
1330                 if (r < 0)
1331                         return r;
1332                 if (bus->nodes_modified)
1333                         return 0;
1334                 if (r > 0)
1335                         *found_object = true;
1336         }
1337
1338         return 0;
1339 }
1340
1341 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1342         int r;
1343         size_t pl;
1344         bool found_object = false;
1345
1346         assert(bus);
1347         assert(m);
1348
1349         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1350                 return 0;
1351
1352         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1353                 return 0;
1354
1355         if (hashmap_isempty(bus->nodes))
1356                 return 0;
1357
1358         /* Never respond to broadcast messages */
1359         if (bus->bus_client && !m->destination)
1360                 return 0;
1361
1362         assert(m->path);
1363         assert(m->member);
1364
1365         pl = strlen(m->path);
1366         do {
1367                 char prefix[pl+1];
1368
1369                 bus->nodes_modified = false;
1370
1371                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1372                 if (r != 0)
1373                         return r;
1374
1375                 /* Look for fallback prefixes */
1376                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1377
1378                         if (bus->nodes_modified)
1379                                 break;
1380
1381                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1382                         if (r != 0)
1383                                 return r;
1384                 }
1385
1386         } while (bus->nodes_modified);
1387
1388         if (!found_object)
1389                 return 0;
1390
1391         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1392             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1393                 r = sd_bus_reply_method_errorf(
1394                                 m,
1395                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
1396                                 "Unknown property or interface.");
1397         else
1398                 r = sd_bus_reply_method_errorf(
1399                                 m,
1400                                 SD_BUS_ERROR_UNKNOWN_METHOD,
1401                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1402
1403         if (r < 0)
1404                 return r;
1405
1406         return 1;
1407 }
1408
1409 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1410         struct node *n, *parent;
1411         const char *e;
1412         _cleanup_free_ char *s = NULL;
1413         char *p;
1414         int r;
1415
1416         assert(bus);
1417         assert(path);
1418         assert(path[0] == '/');
1419
1420         n = hashmap_get(bus->nodes, path);
1421         if (n)
1422                 return n;
1423
1424         r = hashmap_ensure_allocated(&bus->nodes, &string_hash_ops);
1425         if (r < 0)
1426                 return NULL;
1427
1428         s = strdup(path);
1429         if (!s)
1430                 return NULL;
1431
1432         if (streq(path, "/"))
1433                 parent = NULL;
1434         else {
1435                 e = strrchr(path, '/');
1436                 assert(e);
1437
1438                 p = strndupa(path, MAX(1, e - path));
1439
1440                 parent = bus_node_allocate(bus, p);
1441                 if (!parent)
1442                         return NULL;
1443         }
1444
1445         n = new0(struct node, 1);
1446         if (!n)
1447                 return NULL;
1448
1449         n->parent = parent;
1450         n->path = s;
1451         s = NULL; /* do not free */
1452
1453         r = hashmap_put(bus->nodes, n->path, n);
1454         if (r < 0) {
1455                 free(n->path);
1456                 free(n);
1457                 return NULL;
1458         }
1459
1460         if (parent)
1461                 LIST_PREPEND(siblings, parent->child, n);
1462
1463         return n;
1464 }
1465
1466 void bus_node_gc(sd_bus *b, struct node *n) {
1467         assert(b);
1468
1469         if (!n)
1470                 return;
1471
1472         if (n->child ||
1473             n->callbacks ||
1474             n->vtables ||
1475             n->enumerators ||
1476             n->object_managers)
1477                 return;
1478
1479         assert(hashmap_remove(b->nodes, n->path) == n);
1480
1481         if (n->parent)
1482                 LIST_REMOVE(siblings, n->parent->child, n);
1483
1484         free(n->path);
1485         bus_node_gc(b, n->parent);
1486         free(n);
1487 }
1488
1489 static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) {
1490         struct node *n;
1491
1492         assert(bus);
1493         assert(path);
1494
1495         n = hashmap_get(bus->nodes, path);
1496         if (!n) {
1497                 char *prefix;
1498
1499                 prefix = alloca(strlen(path) + 1);
1500                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1501                         n = hashmap_get(bus->nodes, prefix);
1502                         if (n)
1503                                 break;
1504                 }
1505         }
1506
1507         while (n && !n->object_managers)
1508                 n = n->parent;
1509
1510         if (out)
1511                 *out = n;
1512         return !!n;
1513 }
1514
1515 static int bus_add_object(
1516                 sd_bus *bus,
1517                 sd_bus_slot **slot,
1518                 bool fallback,
1519                 const char *path,
1520                 sd_bus_message_handler_t callback,
1521                 void *userdata) {
1522
1523         sd_bus_slot *s;
1524         struct node *n;
1525         int r;
1526
1527         assert_return(bus, -EINVAL);
1528         assert_return(object_path_is_valid(path), -EINVAL);
1529         assert_return(callback, -EINVAL);
1530         assert_return(!bus_pid_changed(bus), -ECHILD);
1531
1532         n = bus_node_allocate(bus, path);
1533         if (!n)
1534                 return -ENOMEM;
1535
1536         s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
1537         if (!s) {
1538                 r = -ENOMEM;
1539                 goto fail;
1540         }
1541
1542         s->node_callback.callback = callback;
1543         s->node_callback.is_fallback = fallback;
1544
1545         s->node_callback.node = n;
1546         LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
1547         bus->nodes_modified = true;
1548
1549         if (slot)
1550                 *slot = s;
1551
1552         return 0;
1553
1554 fail:
1555         sd_bus_slot_unref(s);
1556         bus_node_gc(bus, n);
1557
1558         return r;
1559 }
1560
1561 _public_ int sd_bus_add_object(
1562                 sd_bus *bus,
1563                 sd_bus_slot **slot,
1564                 const char *path,
1565                 sd_bus_message_handler_t callback,
1566                 void *userdata) {
1567
1568         return bus_add_object(bus, slot, false, path, callback, userdata);
1569 }
1570
1571 _public_ int sd_bus_add_fallback(
1572                 sd_bus *bus,
1573                 sd_bus_slot **slot,
1574                 const char *prefix,
1575                 sd_bus_message_handler_t callback,
1576                 void *userdata) {
1577
1578         return bus_add_object(bus, slot, true, prefix, callback, userdata);
1579 }
1580
1581 static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
1582         const struct vtable_member *m = a;
1583         uint8_t hash_key2[HASH_KEY_SIZE];
1584         unsigned long ret;
1585
1586         assert(m);
1587
1588         ret = string_hash_func(m->path, hash_key);
1589
1590         /* Use a slightly different hash key for the interface */
1591         memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
1592         hash_key2[0]++;
1593         ret ^= string_hash_func(m->interface, hash_key2);
1594
1595         /* And an even different one for the  member */
1596         hash_key2[0]++;
1597         ret ^= string_hash_func(m->member, hash_key2);
1598
1599         return ret;
1600 }
1601
1602 static int vtable_member_compare_func(const void *a, const void *b) {
1603         const struct vtable_member *x = a, *y = b;
1604         int r;
1605
1606         assert(x);
1607         assert(y);
1608
1609         r = strcmp(x->path, y->path);
1610         if (r != 0)
1611                 return r;
1612
1613         r = strcmp(x->interface, y->interface);
1614         if (r != 0)
1615                 return r;
1616
1617         return strcmp(x->member, y->member);
1618 }
1619
1620 static const struct hash_ops vtable_member_hash_ops = {
1621         .hash = vtable_member_hash_func,
1622         .compare = vtable_member_compare_func
1623 };
1624
1625 static int add_object_vtable_internal(
1626                 sd_bus *bus,
1627                 sd_bus_slot **slot,
1628                 const char *path,
1629                 const char *interface,
1630                 const sd_bus_vtable *vtable,
1631                 bool fallback,
1632                 sd_bus_object_find_t find,
1633                 void *userdata) {
1634
1635         sd_bus_slot *s = NULL;
1636         struct node_vtable *i, *existing = NULL;
1637         const sd_bus_vtable *v;
1638         struct node *n;
1639         int r;
1640
1641         assert_return(bus, -EINVAL);
1642         assert_return(object_path_is_valid(path), -EINVAL);
1643         assert_return(interface_name_is_valid(interface), -EINVAL);
1644         assert_return(vtable, -EINVAL);
1645         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1646         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1647         assert_return(!bus_pid_changed(bus), -ECHILD);
1648         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1649                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1650                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1651                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1652
1653         r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops);
1654         if (r < 0)
1655                 return r;
1656
1657         r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops);
1658         if (r < 0)
1659                 return r;
1660
1661         n = bus_node_allocate(bus, path);
1662         if (!n)
1663                 return -ENOMEM;
1664
1665         LIST_FOREACH(vtables, i, n->vtables) {
1666                 if (i->is_fallback != fallback) {
1667                         r = -EPROTOTYPE;
1668                         goto fail;
1669                 }
1670
1671                 if (streq(i->interface, interface)) {
1672
1673                         if (i->vtable == vtable) {
1674                                 r = -EEXIST;
1675                                 goto fail;
1676                         }
1677
1678                         existing = i;
1679                 }
1680         }
1681
1682         s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
1683         if (!s) {
1684                 r = -ENOMEM;
1685                 goto fail;
1686         }
1687
1688         s->node_vtable.is_fallback = fallback;
1689         s->node_vtable.vtable = vtable;
1690         s->node_vtable.find = find;
1691
1692         s->node_vtable.interface = strdup(interface);
1693         if (!s->node_vtable.interface) {
1694                 r = -ENOMEM;
1695                 goto fail;
1696         }
1697
1698         for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1699
1700                 switch (v->type) {
1701
1702                 case _SD_BUS_VTABLE_METHOD: {
1703                         struct vtable_member *m;
1704
1705                         if (!member_name_is_valid(v->x.method.member) ||
1706                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1707                             !signature_is_valid(strempty(v->x.method.result), false) ||
1708                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1709                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1710                                 r = -EINVAL;
1711                                 goto fail;
1712                         }
1713
1714                         m = new0(struct vtable_member, 1);
1715                         if (!m) {
1716                                 r = -ENOMEM;
1717                                 goto fail;
1718                         }
1719
1720                         m->parent = &s->node_vtable;
1721                         m->path = n->path;
1722                         m->interface = s->node_vtable.interface;
1723                         m->member = v->x.method.member;
1724                         m->vtable = v;
1725
1726                         r = hashmap_put(bus->vtable_methods, m, m);
1727                         if (r < 0) {
1728                                 free(m);
1729                                 goto fail;
1730                         }
1731
1732                         break;
1733                 }
1734
1735                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1736
1737                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1738                                 r = -EINVAL;
1739                                 goto fail;
1740                         }
1741
1742                         if (v->flags & SD_BUS_VTABLE_PROPERTY_CONST) {
1743                                 r = -EINVAL;
1744                                 goto fail;
1745                         }
1746
1747                         /* Fall through */
1748
1749                 case _SD_BUS_VTABLE_PROPERTY: {
1750                         struct vtable_member *m;
1751
1752                         if (!member_name_is_valid(v->x.property.member) ||
1753                             !signature_is_single(v->x.property.signature, false) ||
1754                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1755                             (v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ||
1756                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
1757                             ((v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) && (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)) ||
1758                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1759                                 r = -EINVAL;
1760                                 goto fail;
1761                         }
1762
1763                         m = new0(struct vtable_member, 1);
1764                         if (!m) {
1765                                 r = -ENOMEM;
1766                                 goto fail;
1767                         }
1768
1769                         m->parent = &s->node_vtable;
1770                         m->path = n->path;
1771                         m->interface = s->node_vtable.interface;
1772                         m->member = v->x.property.member;
1773                         m->vtable = v;
1774
1775                         r = hashmap_put(bus->vtable_properties, m, m);
1776                         if (r < 0) {
1777                                 free(m);
1778                                 goto fail;
1779                         }
1780
1781                         break;
1782                 }
1783
1784                 case _SD_BUS_VTABLE_SIGNAL:
1785
1786                         if (!member_name_is_valid(v->x.signal.member) ||
1787                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1788                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1789                                 r = -EINVAL;
1790                                 goto fail;
1791                         }
1792
1793                         break;
1794
1795                 default:
1796                         r = -EINVAL;
1797                         goto fail;
1798                 }
1799         }
1800
1801         s->node_vtable.node = n;
1802         LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
1803         bus->nodes_modified = true;
1804
1805         if (slot)
1806                 *slot = s;
1807
1808         return 0;
1809
1810 fail:
1811         sd_bus_slot_unref(s);
1812         bus_node_gc(bus, n);
1813
1814         return r;
1815 }
1816
1817 _public_ int sd_bus_add_object_vtable(
1818                 sd_bus *bus,
1819                 sd_bus_slot **slot,
1820                 const char *path,
1821                 const char *interface,
1822                 const sd_bus_vtable *vtable,
1823                 void *userdata) {
1824
1825         return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
1826 }
1827
1828 _public_ int sd_bus_add_fallback_vtable(
1829                 sd_bus *bus,
1830                 sd_bus_slot **slot,
1831                 const char *prefix,
1832                 const char *interface,
1833                 const sd_bus_vtable *vtable,
1834                 sd_bus_object_find_t find,
1835                 void *userdata) {
1836
1837         return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
1838 }
1839
1840 _public_ int sd_bus_add_node_enumerator(
1841                 sd_bus *bus,
1842                 sd_bus_slot **slot,
1843                 const char *path,
1844                 sd_bus_node_enumerator_t callback,
1845                 void *userdata) {
1846
1847         sd_bus_slot *s;
1848         struct node *n;
1849         int r;
1850
1851         assert_return(bus, -EINVAL);
1852         assert_return(object_path_is_valid(path), -EINVAL);
1853         assert_return(callback, -EINVAL);
1854         assert_return(!bus_pid_changed(bus), -ECHILD);
1855
1856         n = bus_node_allocate(bus, path);
1857         if (!n)
1858                 return -ENOMEM;
1859
1860         s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
1861         if (!s) {
1862                 r = -ENOMEM;
1863                 goto fail;
1864         }
1865
1866         s->node_enumerator.callback = callback;
1867
1868         s->node_enumerator.node = n;
1869         LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
1870         bus->nodes_modified = true;
1871
1872         if (slot)
1873                 *slot = s;
1874
1875         return 0;
1876
1877 fail:
1878         sd_bus_slot_unref(s);
1879         bus_node_gc(bus, n);
1880
1881         return r;
1882 }
1883
1884 static int emit_properties_changed_on_interface(
1885                 sd_bus *bus,
1886                 const char *prefix,
1887                 const char *path,
1888                 const char *interface,
1889                 bool require_fallback,
1890                 bool *found_interface,
1891                 char **names) {
1892
1893         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1894         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1895         bool has_invalidating = false, has_changing = false;
1896         struct vtable_member key = {};
1897         struct node_vtable *c;
1898         struct node *n;
1899         char **property;
1900         void *u = NULL;
1901         int r;
1902
1903         assert(bus);
1904         assert(prefix);
1905         assert(path);
1906         assert(interface);
1907         assert(found_interface);
1908
1909         n = hashmap_get(bus->nodes, prefix);
1910         if (!n)
1911                 return 0;
1912
1913         r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
1914         if (r < 0)
1915                 return r;
1916
1917         r = sd_bus_message_append(m, "s", interface);
1918         if (r < 0)
1919                 return r;
1920
1921         r = sd_bus_message_open_container(m, 'a', "{sv}");
1922         if (r < 0)
1923                 return r;
1924
1925         key.path = prefix;
1926         key.interface = interface;
1927
1928         LIST_FOREACH(vtables, c, n->vtables) {
1929                 if (require_fallback && !c->is_fallback)
1930                         continue;
1931
1932                 if (!streq(c->interface, interface))
1933                         continue;
1934
1935                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
1936                 if (r < 0)
1937                         return r;
1938                 if (bus->nodes_modified)
1939                         return 0;
1940                 if (r == 0)
1941                         continue;
1942
1943                 *found_interface = true;
1944
1945                 if (names) {
1946                         /* If the caller specified a list of
1947                          * properties we include exactly those in the
1948                          * PropertiesChanged message */
1949
1950                         STRV_FOREACH(property, names) {
1951                                 struct vtable_member *v;
1952
1953                                 assert_return(member_name_is_valid(*property), -EINVAL);
1954
1955                                 key.member = *property;
1956                                 v = hashmap_get(bus->vtable_properties, &key);
1957                                 if (!v)
1958                                         return -ENOENT;
1959
1960                                 /* If there are two vtables for the same
1961                                  * interface, let's handle this property when
1962                                  * we come to that vtable. */
1963                                 if (c != v->parent)
1964                                         continue;
1965
1966                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
1967                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
1968
1969                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
1970
1971                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
1972                                         has_invalidating = true;
1973                                         continue;
1974                                 }
1975
1976                                 has_changing = true;
1977
1978                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
1979                                 if (r < 0)
1980                                         return r;
1981                                 if (bus->nodes_modified)
1982                                         return 0;
1983                         }
1984                 } else {
1985                         const sd_bus_vtable *v;
1986
1987                         /* If the caller specified no properties list
1988                          * we include all properties that are marked
1989                          * as changing in the message. */
1990
1991                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1992                                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
1993                                         continue;
1994
1995                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
1996                                         continue;
1997
1998                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
1999                                         has_invalidating = true;
2000                                         continue;
2001                                 }
2002
2003                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
2004                                         continue;
2005
2006                                 has_changing = true;
2007
2008                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
2009                                 if (r < 0)
2010                                         return r;
2011                                 if (bus->nodes_modified)
2012                                         return 0;
2013                         }
2014                 }
2015         }
2016
2017         if (!has_invalidating && !has_changing)
2018                 return 0;
2019
2020         r = sd_bus_message_close_container(m);
2021         if (r < 0)
2022                 return r;
2023
2024         r = sd_bus_message_open_container(m, 'a', "s");
2025         if (r < 0)
2026                 return r;
2027
2028         if (has_invalidating) {
2029                 LIST_FOREACH(vtables, c, n->vtables) {
2030                         if (require_fallback && !c->is_fallback)
2031                                 continue;
2032
2033                         if (!streq(c->interface, interface))
2034                                 continue;
2035
2036                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
2037                         if (r < 0)
2038                                 return r;
2039                         if (bus->nodes_modified)
2040                                 return 0;
2041                         if (r == 0)
2042                                 continue;
2043
2044                         if (names) {
2045                                 STRV_FOREACH(property, names) {
2046                                         struct vtable_member *v;
2047
2048                                         key.member = *property;
2049                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
2050                                         assert(c == v->parent);
2051
2052                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2053                                                 continue;
2054
2055                                         r = sd_bus_message_append(m, "s", *property);
2056                                         if (r < 0)
2057                                                 return r;
2058                                 }
2059                         } else {
2060                                 const sd_bus_vtable *v;
2061
2062                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2063                                         if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2064                                                 continue;
2065
2066                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
2067                                                 continue;
2068
2069                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2070                                                 continue;
2071
2072                                         r = sd_bus_message_append(m, "s", v->x.property.member);
2073                                         if (r < 0)
2074                                                 return r;
2075                                 }
2076                         }
2077                 }
2078         }
2079
2080         r = sd_bus_message_close_container(m);
2081         if (r < 0)
2082                 return r;
2083
2084         r = sd_bus_send(bus, m, NULL);
2085         if (r < 0)
2086                 return r;
2087
2088         return 1;
2089 }
2090
2091 _public_ int sd_bus_emit_properties_changed_strv(
2092                 sd_bus *bus,
2093                 const char *path,
2094                 const char *interface,
2095                 char **names) {
2096
2097         BUS_DONT_DESTROY(bus);
2098         bool found_interface = false;
2099         char *prefix;
2100         int r;
2101
2102         assert_return(bus, -EINVAL);
2103         assert_return(object_path_is_valid(path), -EINVAL);
2104         assert_return(interface_name_is_valid(interface), -EINVAL);
2105         assert_return(!bus_pid_changed(bus), -ECHILD);
2106
2107         if (!BUS_IS_OPEN(bus->state))
2108                 return -ENOTCONN;
2109
2110         /* A non-NULL but empty names list means nothing needs to be
2111            generated. A NULL list OTOH indicates that all properties
2112            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2113            included in the PropertiesChanged message. */
2114         if (names && names[0] == NULL)
2115                 return 0;
2116
2117         do {
2118                 bus->nodes_modified = false;
2119
2120                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
2121                 if (r != 0)
2122                         return r;
2123                 if (bus->nodes_modified)
2124                         continue;
2125
2126                 prefix = alloca(strlen(path) + 1);
2127                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2128                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
2129                         if (r != 0)
2130                                 return r;
2131                         if (bus->nodes_modified)
2132                                 break;
2133                 }
2134
2135         } while (bus->nodes_modified);
2136
2137         return found_interface ? 0 : -ENOENT;
2138 }
2139
2140 _public_ int sd_bus_emit_properties_changed(
2141                 sd_bus *bus,
2142                 const char *path,
2143                 const char *interface,
2144                 const char *name, ...)  {
2145
2146         char **names;
2147
2148         assert_return(bus, -EINVAL);
2149         assert_return(object_path_is_valid(path), -EINVAL);
2150         assert_return(interface_name_is_valid(interface), -EINVAL);
2151         assert_return(!bus_pid_changed(bus), -ECHILD);
2152
2153         if (!BUS_IS_OPEN(bus->state))
2154                 return -ENOTCONN;
2155
2156         if (!name)
2157                 return 0;
2158
2159         names = strv_from_stdarg_alloca(name);
2160
2161         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2162 }
2163
2164 static int object_added_append_all_prefix(
2165                 sd_bus *bus,
2166                 sd_bus_message *m,
2167                 Set *s,
2168                 const char *prefix,
2169                 const char *path,
2170                 bool require_fallback) {
2171
2172         const char *previous_interface = NULL;
2173         struct node_vtable *c;
2174         struct node *n;
2175         int r;
2176
2177         assert(bus);
2178         assert(m);
2179         assert(s);
2180         assert(prefix);
2181         assert(path);
2182
2183         n = hashmap_get(bus->nodes, prefix);
2184         if (!n)
2185                 return 0;
2186
2187         LIST_FOREACH(vtables, c, n->vtables) {
2188                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2189                 void *u = NULL;
2190
2191                 if (require_fallback && !c->is_fallback)
2192                         continue;
2193
2194                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2195                 if (r < 0)
2196                         return r;
2197                 if (bus->nodes_modified)
2198                         return 0;
2199                 if (r == 0)
2200                         continue;
2201
2202                 if (!streq_ptr(c->interface, previous_interface)) {
2203                         /* If a child-node already handled this interface, we
2204                          * skip it on any of its parents. The child vtables
2205                          * always fully override any conflicting vtables of
2206                          * any parent node. */
2207                         if (set_get(s, c->interface))
2208                                 continue;
2209
2210                         r = set_put(s, c->interface);
2211                         if (r < 0)
2212                                 return r;
2213
2214                         if (previous_interface) {
2215                                 r = sd_bus_message_close_container(m);
2216                                 if (r < 0)
2217                                         return r;
2218                                 r = sd_bus_message_close_container(m);
2219                                 if (r < 0)
2220                                         return r;
2221                         }
2222
2223                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2224                         if (r < 0)
2225                                 return r;
2226                         r = sd_bus_message_append(m, "s", c->interface);
2227                         if (r < 0)
2228                                 return r;
2229                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2230                         if (r < 0)
2231                                 return r;
2232
2233                         previous_interface = c->interface;
2234                 }
2235
2236                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2237                 if (r < 0)
2238                         return r;
2239                 if (bus->nodes_modified)
2240                         return 0;
2241         }
2242
2243         if (previous_interface) {
2244                 r = sd_bus_message_close_container(m);
2245                 if (r < 0)
2246                         return r;
2247                 r = sd_bus_message_close_container(m);
2248                 if (r < 0)
2249                         return r;
2250         }
2251
2252         return 0;
2253 }
2254
2255 static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2256         _cleanup_set_free_ Set *s = NULL;
2257         char *prefix;
2258         int r;
2259
2260         assert(bus);
2261         assert(m);
2262         assert(path);
2263
2264         /*
2265          * This appends all interfaces registered on path @path. We first add
2266          * the builtin interfaces, which are always available and handled by
2267          * sd-bus. Then, we add all interfaces registered on the exact node,
2268          * followed by all fallback interfaces registered on any parent prefix.
2269          *
2270          * If an interface is registered multiple times on the same node with
2271          * different vtables, we merge all the properties across all vtables.
2272          * However, if a child node has the same interface registered as one of
2273          * its parent nodes has as fallback, we make the child overwrite the
2274          * parent instead of extending it. Therefore, we keep a "Set" of all
2275          * handled interfaces during parent traversal, so we skip interfaces on
2276          * a parent that were overwritten by a child.
2277          */
2278
2279         s = set_new(&string_hash_ops);
2280         if (!s)
2281                 return -ENOMEM;
2282
2283         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Peer", 0);
2284         if (r < 0)
2285                 return r;
2286         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Introspectable", 0);
2287         if (r < 0)
2288                 return r;
2289         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);
2290         if (r < 0)
2291                 return r;
2292         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
2293         if (r < 0)
2294                 return r;
2295
2296         r = object_added_append_all_prefix(bus, m, s, path, path, false);
2297         if (r < 0)
2298                 return r;
2299         if (bus->nodes_modified)
2300                 return 0;
2301
2302         prefix = alloca(strlen(path) + 1);
2303         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2304                 r = object_added_append_all_prefix(bus, m, s, prefix, path, true);
2305                 if (r < 0)
2306                         return r;
2307                 if (bus->nodes_modified)
2308                         return 0;
2309         }
2310
2311         return 0;
2312 }
2313
2314 _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
2315         BUS_DONT_DESTROY(bus);
2316
2317         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2318         struct node *object_manager;
2319         int r;
2320
2321         /*
2322          * This emits an InterfacesAdded signal on the given path, by iterating
2323          * all registered vtables and fallback vtables on the path. All
2324          * properties are queried and included in the signal.
2325          * This call is equivalent to sd_bus_emit_interfaces_added() with an
2326          * explicit list of registered interfaces. However, unlike
2327          * interfaces_added(), this call can figure out the list of supported
2328          * interfaces itself. Furthermore, it properly adds the builtin
2329          * org.freedesktop.DBus.* interfaces.
2330          */
2331
2332         assert_return(bus, -EINVAL);
2333         assert_return(object_path_is_valid(path), -EINVAL);
2334         assert_return(!bus_pid_changed(bus), -ECHILD);
2335
2336         if (!BUS_IS_OPEN(bus->state))
2337                 return -ENOTCONN;
2338
2339         r = bus_find_parent_object_manager(bus, &object_manager, path);
2340         if (r < 0)
2341                 return r;
2342         if (r == 0)
2343                 return -ESRCH;
2344
2345         do {
2346                 bus->nodes_modified = false;
2347                 m = sd_bus_message_unref(m);
2348
2349                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2350                 if (r < 0)
2351                         return r;
2352
2353                 r = sd_bus_message_append_basic(m, 'o', path);
2354                 if (r < 0)
2355                         return r;
2356
2357                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2358                 if (r < 0)
2359                         return r;
2360
2361                 r = object_added_append_all(bus, m, path);
2362                 if (r < 0)
2363                         return r;
2364
2365                 if (bus->nodes_modified)
2366                         continue;
2367
2368                 r = sd_bus_message_close_container(m);
2369                 if (r < 0)
2370                         return r;
2371
2372         } while (bus->nodes_modified);
2373
2374         return sd_bus_send(bus, m, NULL);
2375 }
2376
2377 /// UNNEEDED by elogind
2378 #if 0
2379 static int object_removed_append_all_prefix(
2380                 sd_bus *bus,
2381                 sd_bus_message *m,
2382                 Set *s,
2383                 const char *prefix,
2384                 const char *path,
2385                 bool require_fallback) {
2386
2387         const char *previous_interface = NULL;
2388         struct node_vtable *c;
2389         struct node *n;
2390         int r;
2391
2392         assert(bus);
2393         assert(m);
2394         assert(s);
2395         assert(prefix);
2396         assert(path);
2397
2398         n = hashmap_get(bus->nodes, prefix);
2399         if (!n)
2400                 return 0;
2401
2402         LIST_FOREACH(vtables, c, n->vtables) {
2403                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2404                 void *u = NULL;
2405
2406                 if (require_fallback && !c->is_fallback)
2407                         continue;
2408                 if (streq_ptr(c->interface, previous_interface))
2409                         continue;
2410
2411                 /* If a child-node already handled this interface, we
2412                  * skip it on any of its parents. The child vtables
2413                  * always fully override any conflicting vtables of
2414                  * any parent node. */
2415                 if (set_get(s, c->interface))
2416                         continue;
2417
2418                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2419                 if (r < 0)
2420                         return r;
2421                 if (bus->nodes_modified)
2422                         return 0;
2423                 if (r == 0)
2424                         continue;
2425
2426                 r = set_put(s, c->interface);
2427                 if (r < 0)
2428                         return r;
2429
2430                 r = sd_bus_message_append(m, "s", c->interface);
2431                 if (r < 0)
2432                         return r;
2433
2434                 previous_interface = c->interface;
2435         }
2436
2437         return 0;
2438 }
2439
2440 static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
2441         _cleanup_set_free_ Set *s = NULL;
2442         char *prefix;
2443         int r;
2444
2445         assert(bus);
2446         assert(m);
2447         assert(path);
2448
2449         /* see sd_bus_emit_object_added() for details */
2450
2451         s = set_new(&string_hash_ops);
2452         if (!s)
2453                 return -ENOMEM;
2454
2455         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Peer");
2456         if (r < 0)
2457                 return r;
2458         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Introspectable");
2459         if (r < 0)
2460                 return r;
2461         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Properties");
2462         if (r < 0)
2463                 return r;
2464         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
2465         if (r < 0)
2466                 return r;
2467
2468         r = object_removed_append_all_prefix(bus, m, s, path, path, false);
2469         if (r < 0)
2470                 return r;
2471         if (bus->nodes_modified)
2472                 return 0;
2473
2474         prefix = alloca(strlen(path) + 1);
2475         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2476                 r = object_removed_append_all_prefix(bus, m, s, prefix, path, true);
2477                 if (r < 0)
2478                         return r;
2479                 if (bus->nodes_modified)
2480                         return 0;
2481         }
2482
2483         return 0;
2484 }
2485
2486 _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
2487         BUS_DONT_DESTROY(bus);
2488
2489         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2490         struct node *object_manager;
2491         int r;
2492
2493         /*
2494          * This is like sd_bus_emit_object_added(), but emits an
2495          * InterfacesRemoved signal on the given path. This only includes any
2496          * registered interfaces but skips the properties. Note that this will
2497          * call into the find() callbacks of any registered vtable. Therefore,
2498          * you must call this function before destroying/unlinking your object.
2499          * Otherwise, the list of interfaces will be incomplete. However, note
2500          * that this will *NOT* call into any property callback. Therefore, the
2501          * object might be in an "destructed" state, as long as we can find it.
2502          */
2503
2504         assert_return(bus, -EINVAL);
2505         assert_return(object_path_is_valid(path), -EINVAL);
2506         assert_return(!bus_pid_changed(bus), -ECHILD);
2507
2508         if (!BUS_IS_OPEN(bus->state))
2509                 return -ENOTCONN;
2510
2511         r = bus_find_parent_object_manager(bus, &object_manager, path);
2512         if (r < 0)
2513                 return r;
2514         if (r == 0)
2515                 return -ESRCH;
2516
2517         do {
2518                 bus->nodes_modified = false;
2519                 m = sd_bus_message_unref(m);
2520
2521                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2522                 if (r < 0)
2523                         return r;
2524
2525                 r = sd_bus_message_append_basic(m, 'o', path);
2526                 if (r < 0)
2527                         return r;
2528
2529                 r = sd_bus_message_open_container(m, 'a', "s");
2530                 if (r < 0)
2531                         return r;
2532
2533                 r = object_removed_append_all(bus, m, path);
2534                 if (r < 0)
2535                         return r;
2536
2537                 if (bus->nodes_modified)
2538                         continue;
2539
2540                 r = sd_bus_message_close_container(m);
2541                 if (r < 0)
2542                         return r;
2543
2544         } while (bus->nodes_modified);
2545
2546         return sd_bus_send(bus, m, NULL);
2547 }
2548 #endif // 0
2549
2550 static int interfaces_added_append_one_prefix(
2551                 sd_bus *bus,
2552                 sd_bus_message *m,
2553                 const char *prefix,
2554                 const char *path,
2555                 const char *interface,
2556                 bool require_fallback) {
2557
2558         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2559         bool found_interface = false;
2560         struct node_vtable *c;
2561         struct node *n;
2562         void *u = NULL;
2563         int r;
2564
2565         assert(bus);
2566         assert(m);
2567         assert(prefix);
2568         assert(path);
2569         assert(interface);
2570
2571         n = hashmap_get(bus->nodes, prefix);
2572         if (!n)
2573                 return 0;
2574
2575         LIST_FOREACH(vtables, c, n->vtables) {
2576                 if (require_fallback && !c->is_fallback)
2577                         continue;
2578
2579                 if (!streq(c->interface, interface))
2580                         continue;
2581
2582                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2583                 if (r < 0)
2584                         return r;
2585                 if (bus->nodes_modified)
2586                         return 0;
2587                 if (r == 0)
2588                         continue;
2589
2590                 if (!found_interface) {
2591                         r = sd_bus_message_append_basic(m, 's', interface);
2592                         if (r < 0)
2593                                 return r;
2594
2595                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2596                         if (r < 0)
2597                                 return r;
2598
2599                         found_interface = true;
2600                 }
2601
2602                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2603                 if (r < 0)
2604                         return r;
2605                 if (bus->nodes_modified)
2606                         return 0;
2607         }
2608
2609         if (found_interface) {
2610                 r = sd_bus_message_close_container(m);
2611                 if (r < 0)
2612                         return r;
2613         }
2614
2615         return found_interface;
2616 }
2617
2618 static int interfaces_added_append_one(
2619                 sd_bus *bus,
2620                 sd_bus_message *m,
2621                 const char *path,
2622                 const char *interface) {
2623
2624         char *prefix;
2625         int r;
2626
2627         assert(bus);
2628         assert(m);
2629         assert(path);
2630         assert(interface);
2631
2632         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2633         if (r != 0)
2634                 return r;
2635         if (bus->nodes_modified)
2636                 return 0;
2637
2638         prefix = alloca(strlen(path) + 1);
2639         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2640                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2641                 if (r != 0)
2642                         return r;
2643                 if (bus->nodes_modified)
2644                         return 0;
2645         }
2646
2647         return -ENOENT;
2648 }
2649
2650 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2651         BUS_DONT_DESTROY(bus);
2652
2653         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2654         struct node *object_manager;
2655         char **i;
2656         int r;
2657
2658         assert_return(bus, -EINVAL);
2659         assert_return(object_path_is_valid(path), -EINVAL);
2660         assert_return(!bus_pid_changed(bus), -ECHILD);
2661
2662         if (!BUS_IS_OPEN(bus->state))
2663                 return -ENOTCONN;
2664
2665         if (strv_isempty(interfaces))
2666                 return 0;
2667
2668         r = bus_find_parent_object_manager(bus, &object_manager, path);
2669         if (r < 0)
2670                 return r;
2671         if (r == 0)
2672                 return -ESRCH;
2673
2674         do {
2675                 bus->nodes_modified = false;
2676                 m = sd_bus_message_unref(m);
2677
2678                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
2679                 if (r < 0)
2680                         return r;
2681
2682                 r = sd_bus_message_append_basic(m, 'o', path);
2683                 if (r < 0)
2684                         return r;
2685
2686                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2687                 if (r < 0)
2688                         return r;
2689
2690                 STRV_FOREACH(i, interfaces) {
2691                         assert_return(interface_name_is_valid(*i), -EINVAL);
2692
2693                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2694                         if (r < 0)
2695                                 return r;
2696
2697                         r = interfaces_added_append_one(bus, m, path, *i);
2698                         if (r < 0)
2699                                 return r;
2700
2701                         if (bus->nodes_modified)
2702                                 break;
2703
2704                         r = sd_bus_message_close_container(m);
2705                         if (r < 0)
2706                                 return r;
2707                 }
2708
2709                 if (bus->nodes_modified)
2710                         continue;
2711
2712                 r = sd_bus_message_close_container(m);
2713                 if (r < 0)
2714                         return r;
2715
2716         } while (bus->nodes_modified);
2717
2718         return sd_bus_send(bus, m, NULL);
2719 }
2720
2721 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2722         char **interfaces;
2723
2724         assert_return(bus, -EINVAL);
2725         assert_return(object_path_is_valid(path), -EINVAL);
2726         assert_return(!bus_pid_changed(bus), -ECHILD);
2727
2728         if (!BUS_IS_OPEN(bus->state))
2729                 return -ENOTCONN;
2730
2731         interfaces = strv_from_stdarg_alloca(interface);
2732
2733         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2734 }
2735
2736 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2737         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2738         struct node *object_manager;
2739         int r;
2740
2741         assert_return(bus, -EINVAL);
2742         assert_return(object_path_is_valid(path), -EINVAL);
2743         assert_return(!bus_pid_changed(bus), -ECHILD);
2744
2745         if (!BUS_IS_OPEN(bus->state))
2746                 return -ENOTCONN;
2747
2748         if (strv_isempty(interfaces))
2749                 return 0;
2750
2751         r = bus_find_parent_object_manager(bus, &object_manager, path);
2752         if (r < 0)
2753                 return r;
2754         if (r == 0)
2755                 return -ESRCH;
2756
2757         r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
2758         if (r < 0)
2759                 return r;
2760
2761         r = sd_bus_message_append_basic(m, 'o', path);
2762         if (r < 0)
2763                 return r;
2764
2765         r = sd_bus_message_append_strv(m, interfaces);
2766         if (r < 0)
2767                 return r;
2768
2769         return sd_bus_send(bus, m, NULL);
2770 }
2771
2772 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2773         char **interfaces;
2774
2775         assert_return(bus, -EINVAL);
2776         assert_return(object_path_is_valid(path), -EINVAL);
2777         assert_return(!bus_pid_changed(bus), -ECHILD);
2778
2779         if (!BUS_IS_OPEN(bus->state))
2780                 return -ENOTCONN;
2781
2782         interfaces = strv_from_stdarg_alloca(interface);
2783
2784         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2785 }
2786
2787 /// UNNEEDED by elogind
2788 #if 0
2789 _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
2790         sd_bus_slot *s;
2791         struct node *n;
2792         int r;
2793
2794         assert_return(bus, -EINVAL);
2795         assert_return(object_path_is_valid(path), -EINVAL);
2796         assert_return(!bus_pid_changed(bus), -ECHILD);
2797
2798         n = bus_node_allocate(bus, path);
2799         if (!n)
2800                 return -ENOMEM;
2801
2802         s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
2803         if (!s) {
2804                 r = -ENOMEM;
2805                 goto fail;
2806         }
2807
2808         s->node_object_manager.node = n;
2809         LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
2810         bus->nodes_modified = true;
2811
2812         if (slot)
2813                 *slot = s;
2814
2815         return 0;
2816
2817 fail:
2818         sd_bus_slot_unref(s);
2819         bus_node_gc(bus, n);
2820
2821         return r;
2822 }
2823 #endif // 0