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