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