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