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