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