chiark / gitweb /
bus: unify code to find parents of an object path with
[elogind.git] / src / libsystemd-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-objects.h"
30
31 static int node_vtable_get_userdata(
32                 sd_bus *bus,
33                 const char *path,
34                 struct node_vtable *c,
35                 void **userdata) {
36
37         void *u;
38         int r;
39
40         assert(bus);
41         assert(path);
42         assert(c);
43
44         u = c->userdata;
45         if (c->find) {
46                 r = c->find(bus, path, c->interface, &u, u);
47                 if (r <= 0)
48                         return r;
49         }
50
51         if (userdata)
52                 *userdata = u;
53
54         return 1;
55 }
56
57 static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
58         assert(p);
59
60         return (uint8_t*) u + p->x.property.offset;
61 }
62
63 static int vtable_property_get_userdata(
64                 sd_bus *bus,
65                 const char *path,
66                 struct vtable_member *p,
67                 void **userdata) {
68
69         void *u;
70         int r;
71
72         assert(bus);
73         assert(path);
74         assert(p);
75         assert(userdata);
76
77         r = node_vtable_get_userdata(bus, path, p->parent, &u);
78         if (r <= 0)
79                 return r;
80
81         *userdata = vtable_property_convert_userdata(p->vtable, u);
82         return 1;
83 }
84
85 static int add_enumerated_to_set(
86                 sd_bus *bus,
87                 const char *prefix,
88                 struct node_enumerator *first,
89                 Set *s) {
90
91         struct node_enumerator *c;
92         int r;
93
94         assert(bus);
95         assert(prefix);
96         assert(s);
97
98         LIST_FOREACH(enumerators, c, first) {
99                 char **children = NULL, **k;
100
101                 r = c->callback(bus, prefix, &children, c->userdata);
102                 if (r < 0)
103                         return r;
104
105                 STRV_FOREACH(k, children) {
106                         if (r < 0) {
107                                 free(*k);
108                                 continue;
109                         }
110
111                         if (!object_path_is_valid(*k) && object_path_startswith(*k, prefix)) {
112                                 free(*k);
113                                 r = -EINVAL;
114                                 continue;
115                         }
116
117                         r = set_consume(s, *k);
118                 }
119
120                 free(children);
121                 if (r < 0)
122                         return r;
123         }
124
125         return 0;
126 }
127
128 static int add_subtree_to_set(
129                 sd_bus *bus,
130                 const char *prefix,
131                 struct node *n,
132                 Set *s) {
133
134         struct node *i;
135         int r;
136
137         assert(bus);
138         assert(prefix);
139         assert(n);
140         assert(s);
141
142         r = add_enumerated_to_set(bus, prefix, n->enumerators, s);
143         if (r < 0)
144                 return r;
145
146         LIST_FOREACH(siblings, i, n->child) {
147                 char *t;
148
149                 t = strdup(i->path);
150                 if (!t)
151                         return -ENOMEM;
152
153                 r = set_consume(s, t);
154                 if (r < 0 && r != -EEXIST)
155                         return r;
156
157                 r = add_subtree_to_set(bus, prefix, i, s);
158                 if (r < 0)
159                         return r;
160         }
161
162         return 0;
163 }
164
165 static int get_child_nodes(
166                 sd_bus *bus,
167                 const char *prefix,
168                 struct node *n,
169                 Set **_s) {
170
171         Set *s = NULL;
172         int r;
173
174         assert(bus);
175         assert(prefix);
176         assert(n);
177         assert(_s);
178
179         s = set_new(string_hash_func, string_compare_func);
180         if (!s)
181                 return -ENOMEM;
182
183         r = add_subtree_to_set(bus, prefix, n, s);
184         if (r < 0) {
185                 set_free_free(s);
186                 return r;
187         }
188
189         *_s = s;
190         return 0;
191 }
192
193 static int node_callbacks_run(
194                 sd_bus *bus,
195                 sd_bus_message *m,
196                 struct node_callback *first,
197                 bool require_fallback,
198                 bool *found_object) {
199
200         struct node_callback *c;
201         int r;
202
203         assert(bus);
204         assert(m);
205         assert(found_object);
206
207         LIST_FOREACH(callbacks, c, first) {
208                 if (require_fallback && !c->is_fallback)
209                         continue;
210
211                 *found_object = true;
212
213                 if (c->last_iteration == bus->iteration_counter)
214                         continue;
215
216                 r = sd_bus_message_rewind(m, true);
217                 if (r < 0)
218                         return r;
219
220                 r = c->callback(bus, m, c->userdata);
221                 if (r != 0)
222                         return r;
223         }
224
225         return 0;
226 }
227
228 static int method_callbacks_run(
229                 sd_bus *bus,
230                 sd_bus_message *m,
231                 struct vtable_member *c,
232                 bool require_fallback,
233                 bool *found_object) {
234
235         const char *signature;
236         void *u;
237         int r;
238
239         assert(bus);
240         assert(m);
241         assert(c);
242         assert(found_object);
243
244         if (require_fallback && !c->parent->is_fallback)
245                 return 0;
246
247         r = node_vtable_get_userdata(bus, m->path, c->parent, &u);
248         if (r <= 0)
249                 return r;
250
251         *found_object = true;
252
253         r = sd_bus_message_rewind(m, true);
254         if (r < 0)
255                 return r;
256
257         r = sd_bus_message_get_signature(m, true, &signature);
258         if (r < 0)
259                 return r;
260
261         if (!streq(strempty(c->vtable->x.method.signature), signature)) {
262                 r = sd_bus_reply_method_errorf(bus, m,
263                                                "org.freedesktop.DBus.Error.InvalidArgs",
264                                                "Invalid arguments '%s' to call %s:%s, expecting '%s'.",
265                                                signature, c->interface, c->member, strempty(c->vtable->x.method.signature));
266                 if (r < 0)
267                         return r;
268
269                 return 1;
270         }
271
272         if (c->vtable->x.method.handler)
273                 return c->vtable->x.method.handler(bus, m, u);
274
275         /* If the method callback is NULL, make this a successful NOP */
276         r = sd_bus_reply_method_return(bus, m, NULL);
277         if (r < 0)
278                 return r;
279
280         return 1;
281 }
282
283 static int invoke_property_get(
284                 sd_bus *bus,
285                 const sd_bus_vtable *v,
286                 const char *path,
287                 const char *interface,
288                 const char *property,
289                 sd_bus_message *m,
290                 sd_bus_error *error,
291                 void *userdata) {
292
293         int r;
294         void *p;
295
296         assert(bus);
297         assert(v);
298         assert(path);
299         assert(interface);
300         assert(property);
301         assert(m);
302
303         if (v->x.property.get)
304                 return v->x.property.get(bus, path, interface, property, m, error, userdata);
305
306         /* Automatic handling if no callback is defined. */
307
308         assert(signature_is_single(v->x.property.signature, false));
309         assert(bus_type_is_basic(v->x.property.signature[0]));
310
311         switch (v->x.property.signature[0]) {
312
313         case SD_BUS_TYPE_STRING:
314         case SD_BUS_TYPE_OBJECT_PATH:
315         case SD_BUS_TYPE_SIGNATURE:
316                 p = *(char**) userdata;
317                 break;
318
319         default:
320                 p = userdata;
321                 break;
322         }
323
324         r = sd_bus_message_append_basic(m, v->x.property.signature[0], p);
325         if (r < 0)
326                 return r;
327
328         return 1;
329 }
330
331 static int invoke_property_set(
332                 sd_bus *bus,
333                 const sd_bus_vtable *v,
334                 const char *path,
335                 const char *interface,
336                 const char *property,
337                 sd_bus_message *value,
338                 sd_bus_error *error,
339                 void *userdata) {
340
341         int r;
342
343         assert(bus);
344         assert(v);
345         assert(path);
346         assert(interface);
347         assert(property);
348         assert(value);
349
350         if (v->x.property.set)
351                 return v->x.property.set(bus, path, interface, property, value, error, userdata);
352
353         /*  Automatic handling if no callback is defined. */
354
355         assert(signature_is_single(v->x.property.signature, false));
356         assert(bus_type_is_basic(v->x.property.signature[0]));
357
358         switch (v->x.property.signature[0]) {
359
360         case SD_BUS_TYPE_STRING:
361         case SD_BUS_TYPE_OBJECT_PATH:
362         case SD_BUS_TYPE_SIGNATURE: {
363                 const char *p;
364                 char *n;
365
366                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p);
367                 if (r < 0)
368                         return r;
369
370                 n = strdup(p);
371                 if (!n)
372                         return -ENOMEM;
373
374                 free(*(char**) userdata);
375                 *(char**) userdata = n;
376
377                 break;
378         }
379
380         default:
381                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata);
382                 if (r < 0)
383                         return r;
384
385                 break;
386         }
387
388         return 1;
389 }
390
391 static int property_get_set_callbacks_run(
392                 sd_bus *bus,
393                 sd_bus_message *m,
394                 struct vtable_member *c,
395                 bool require_fallback,
396                 bool is_get,
397                 bool *found_object) {
398
399         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
400         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
401         void *u;
402         int r;
403
404         assert(bus);
405         assert(m);
406         assert(c);
407         assert(found_object);
408
409         if (require_fallback && !c->parent->is_fallback)
410                 return 0;
411
412         r = vtable_property_get_userdata(bus, m->path, c, &u);
413         if (r <= 0)
414                 return r;
415
416         *found_object = true;
417
418         r = sd_bus_message_new_method_return(bus, m, &reply);
419         if (r < 0)
420                 return r;
421
422         c->last_iteration = bus->iteration_counter;
423
424         if (is_get) {
425                 r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature);
426                 if (r < 0)
427                         return r;
428
429                 r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, &error, u);
430                 if (r < 0)
431                         return r;
432
433                 if (sd_bus_error_is_set(&error)) {
434                         r = sd_bus_reply_method_error(bus, m, &error);
435                         if (r < 0)
436                                 return r;
437
438                         return 1;
439                 }
440
441                 r = sd_bus_message_close_container(reply);
442                 if (r < 0)
443                         return r;
444
445         } else {
446                 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
447                         sd_bus_error_setf(&error, "org.freedesktop.DBus.Error.PropertyReadOnly", "Property '%s' is not writable.", c->member);
448                 else  {
449                         r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
450                         if (r < 0)
451                                 return r;
452
453                         r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, &error, u);
454                         if (r < 0)
455                                 return r;
456                 }
457
458                 if (sd_bus_error_is_set(&error)) {
459                         r = sd_bus_reply_method_error(bus, m, &error);
460                         if (r < 0)
461                                 return r;
462
463                         return 1;
464                 }
465
466                 r = sd_bus_message_exit_container(m);
467                 if (r < 0)
468                         return r;
469         }
470
471         r = sd_bus_send(bus, reply, NULL);
472         if (r < 0)
473                 return r;
474
475         return 1;
476 }
477
478 static int vtable_append_all_properties(
479                 sd_bus *bus,
480                 sd_bus_message *reply,
481                 const char *path,
482                 struct node_vtable *c,
483                 void *userdata,
484                 sd_bus_error *error) {
485
486         const sd_bus_vtable *v;
487         int r;
488
489         assert(bus);
490         assert(reply);
491         assert(path);
492         assert(c);
493
494         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
495                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
496                         continue;
497
498                 r = sd_bus_message_open_container(reply, 'e', "sv");
499                 if (r < 0)
500                         return r;
501
502                 r = sd_bus_message_append(reply, "s", v->x.property.member);
503                 if (r < 0)
504                         return r;
505
506                 r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
507                 if (r < 0)
508                         return r;
509
510                 r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, error, vtable_property_convert_userdata(v, userdata));
511                 if (r < 0)
512                         return r;
513
514                 if (sd_bus_error_is_set(error))
515                         return 0;
516
517                 r = sd_bus_message_close_container(reply);
518                 if (r < 0)
519                         return r;
520
521                 r = sd_bus_message_close_container(reply);
522                 if (r < 0)
523                         return r;
524         }
525
526         return 1;
527 }
528
529 static int property_get_all_callbacks_run(
530                 sd_bus *bus,
531                 sd_bus_message *m,
532                 struct node_vtable *first,
533                 bool require_fallback,
534                 const char *iface,
535                 bool *found_object) {
536
537         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
538         struct node_vtable *c;
539         bool found_interface = false;
540         int r;
541
542         assert(bus);
543         assert(m);
544         assert(found_object);
545
546         r = sd_bus_message_new_method_return(bus, m, &reply);
547         if (r < 0)
548                 return r;
549
550         r = sd_bus_message_open_container(reply, 'a', "{sv}");
551         if (r < 0)
552                 return r;
553
554         LIST_FOREACH(vtables, c, first) {
555                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
556                 void *u;
557
558                 if (require_fallback && !c->is_fallback)
559                         continue;
560
561                 r = node_vtable_get_userdata(bus, m->path, c, &u);
562                 if (r < 0)
563                         return r;
564                 if (r == 0)
565                         continue;
566
567                 *found_object = true;
568
569                 if (iface && !streq(c->interface, iface))
570                         continue;
571                 found_interface = true;
572
573                 c->last_iteration = bus->iteration_counter;
574
575                 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
576                 if (r < 0)
577                         return r;
578
579                 if (sd_bus_error_is_set(&error)) {
580                         r = sd_bus_reply_method_error(bus, m, &error);
581                         if (r < 0)
582                                 return r;
583
584                         return 1;
585                 }
586         }
587
588         if (!found_interface) {
589                 r = sd_bus_reply_method_errorf(
590                                 bus, m,
591                                 "org.freedesktop.DBus.Error.UnknownInterface",
592                                 "Unknown interface '%s'.", iface);
593                 if (r < 0)
594                         return r;
595
596                 return 1;
597         }
598
599         r = sd_bus_message_close_container(reply);
600         if (r < 0)
601                 return r;
602
603         r = sd_bus_send(bus, reply, NULL);
604         if (r < 0)
605                 return r;
606
607         return 1;
608 }
609
610 static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
611         assert(bus);
612         assert(n);
613
614         if (n->object_manager)
615                 return true;
616
617         if (n->parent)
618                 return bus_node_with_object_manager(bus, n->parent);
619
620         return false;
621 }
622
623 static bool bus_node_exists(
624                 sd_bus *bus,
625                 struct node *n,
626                 const char *path,
627                 bool require_fallback) {
628
629         struct node_vtable *c;
630         struct node_callback *k;
631
632         assert(bus);
633         assert(n);
634         assert(path);
635
636         /* Tests if there's anything attached directly to this node
637          * for the specified path */
638
639         LIST_FOREACH(callbacks, k, n->callbacks) {
640                 if (require_fallback && !k->is_fallback)
641                         continue;
642
643                 return true;
644         }
645
646         LIST_FOREACH(vtables, c, n->vtables) {
647
648                 if (require_fallback && !c->is_fallback)
649                         continue;
650
651                 if (node_vtable_get_userdata(bus, path, c, NULL) > 0)
652                         return true;
653         }
654
655         return !require_fallback && (n->enumerators || n->object_manager);
656 }
657
658 static int process_introspect(
659                 sd_bus *bus,
660                 sd_bus_message *m,
661                 struct node *n,
662                 bool require_fallback,
663                 bool *found_object) {
664
665         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
666         _cleanup_set_free_free_ Set *s = NULL;
667         struct introspect intro;
668         struct node_vtable *c;
669         bool empty;
670         int r;
671
672         assert(bus);
673         assert(m);
674         assert(n);
675         assert(found_object);
676
677         r = get_child_nodes(bus, m->path, n, &s);
678         if (r < 0)
679                 return r;
680
681         r = introspect_begin(&intro);
682         if (r < 0)
683                 return r;
684
685         r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
686         if (r < 0)
687                 return r;
688
689         empty = set_isempty(s);
690
691         LIST_FOREACH(vtables, c, n->vtables) {
692                 if (require_fallback && !c->is_fallback)
693                         continue;
694
695                 r = node_vtable_get_userdata(bus, m->path, c, NULL);
696                 if (r < 0)
697                         return r;
698                 if (r == 0)
699                         continue;
700
701                 empty = false;
702
703                 r = introspect_write_interface(&intro, c->interface, c->vtable);
704                 if (r < 0)
705                         goto finish;
706         }
707
708         if (empty) {
709                 /* Nothing?, let's see if we exist at all, and if not
710                  * refuse to do anything */
711                 r = bus_node_exists(bus, n, m->path, require_fallback);
712                 if (r < 0)
713                         return r;
714
715                 if (r == 0)
716                         goto finish;
717         }
718
719         *found_object = true;
720
721         r = introspect_write_child_nodes(&intro, s, m->path);
722         if (r < 0)
723                 goto finish;
724
725         r = introspect_finish(&intro, bus, m, &reply);
726         if (r < 0)
727                 goto finish;
728
729         r = sd_bus_send(bus, reply, NULL);
730         if (r < 0)
731                 goto finish;
732
733         r = 1;
734
735 finish:
736         introspect_free(&intro);
737         return r;
738 }
739
740 static int object_manager_serialize_vtable(
741                 sd_bus *bus,
742                 sd_bus_message *reply,
743                 const char *path,
744                 struct node_vtable *c,
745                 sd_bus_error *error) {
746
747         void *u;
748         int r;
749
750         assert(bus);
751         assert(reply);
752         assert(path);
753         assert(c);
754         assert(error);
755
756         r = node_vtable_get_userdata(bus, path, c, &u);
757         if (r <= 0)
758                 return r;
759
760         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
761         if (r < 0)
762                 return r;
763
764         r = sd_bus_message_append(reply, "s", c->interface);
765         if (r < 0)
766                 return r;
767
768         r = sd_bus_message_open_container(reply, 'a', "{sv}");
769         if (r < 0)
770                 return r;
771
772         r = vtable_append_all_properties(bus, reply, path, c, u, error);
773         if (r < 0)
774                 return r;
775
776         r = sd_bus_message_close_container(reply);
777         if (r < 0)
778                 return r;
779
780         r = sd_bus_message_close_container(reply);
781         if (r < 0)
782                 return r;
783
784         return 0;
785 }
786
787 static int object_manager_serialize_path(
788                 sd_bus *bus,
789                 sd_bus_message *reply,
790                 const char *prefix,
791                 const char *path,
792                 bool require_fallback,
793                 sd_bus_error *error) {
794
795         struct node_vtable *i;
796         struct node *n;
797         int r;
798
799         assert(bus);
800         assert(reply);
801         assert(prefix);
802         assert(path);
803         assert(error);
804
805         n = hashmap_get(bus->nodes, prefix);
806         if (!n)
807                 return 0;
808
809         r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
810         if (r < 0)
811                 return r;
812
813         r = sd_bus_message_append(reply, "o", path);
814         if (r < 0)
815                 return r;
816
817         r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
818         if (r < 0)
819                 return r;
820
821         LIST_FOREACH(vtables, i, n->vtables) {
822
823                 if (require_fallback && !i->is_fallback)
824                         continue;
825
826                 r = object_manager_serialize_vtable(bus, reply, path, i, error);
827                 if (r < 0)
828                         return r;
829                 if (sd_bus_error_is_set(error))
830                         return 0;
831         }
832
833         r = sd_bus_message_close_container(reply);
834         if (r < 0)
835                 return r;
836
837         r = sd_bus_message_close_container(reply);
838         if (r < 0)
839                 return r;
840
841         return 1;
842 }
843
844 static int object_manager_serialize_path_and_fallbacks(
845                 sd_bus *bus,
846                 sd_bus_message *reply,
847                 const char *path,
848                 sd_bus_error *error) {
849
850         char *prefix;
851         int r;
852
853         assert(bus);
854         assert(reply);
855         assert(path);
856         assert(error);
857
858         /* First, add all vtables registered for this path */
859         r = object_manager_serialize_path(bus, reply, path, path, false, error);
860         if (r < 0)
861                 return r;
862         if (sd_bus_error_is_set(error))
863                 return 0;
864
865         /* Second, add fallback vtables registered for any of the prefixes */
866         prefix = alloca(strlen(path) + 1);
867         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
868                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
869                 if (r < 0)
870                         return r;
871
872                 if (sd_bus_error_is_set(error))
873                         return 0;
874         }
875
876         return 0;
877 }
878
879 static int process_get_managed_objects(
880                 sd_bus *bus,
881                 sd_bus_message *m,
882                 struct node *n,
883                 bool require_fallback,
884                 bool *found_object) {
885
886         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
887         _cleanup_set_free_free_ Set *s = NULL;
888         bool empty;
889         int r;
890
891         assert(bus);
892         assert(m);
893         assert(n);
894         assert(found_object);
895
896         if (!bus_node_with_object_manager(bus, n))
897                 return 0;
898
899         r = get_child_nodes(bus, m->path, n, &s);
900         if (r < 0)
901                 return r;
902
903         r = sd_bus_message_new_method_return(bus, m, &reply);
904         if (r < 0)
905                 return r;
906
907         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
908         if (r < 0)
909                 return r;
910
911         empty = set_isempty(s);
912         if (empty) {
913                 struct node_vtable *c;
914
915                 /* Hmm, so we have no children? Then let's check
916                  * whether we exist at all, i.e. whether at least one
917                  * vtable exists. */
918
919                 LIST_FOREACH(vtables, c, n->vtables) {
920
921                         if (require_fallback && !c->is_fallback)
922                                 continue;
923
924                         if (r < 0)
925                                 return r;
926                         if (r == 0)
927                                 continue;
928
929                         empty = false;
930                         break;
931                 }
932
933                 if (empty)
934                         return 0;
935         } else {
936                 Iterator i;
937                 char *path;
938
939                 SET_FOREACH(path, s, i) {
940                         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
941
942                         r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
943                         if (r < 0)
944                                 return -ENOMEM;
945
946                         if (sd_bus_error_is_set(&error)) {
947                                 r = sd_bus_reply_method_error(bus, m, &error);
948                                 if (r < 0)
949                                         return r;
950
951                                 return 1;
952                         }
953                 }
954         }
955
956         r = sd_bus_message_close_container(reply);
957         if (r < 0)
958                 return r;
959
960         r = sd_bus_send(bus, reply, NULL);
961         if (r < 0)
962                 return r;
963
964         return 1;
965 }
966
967 static int object_find_and_run(
968                 sd_bus *bus,
969                 sd_bus_message *m,
970                 const char *p,
971                 bool require_fallback,
972                 bool *found_object) {
973
974         struct node *n;
975         struct vtable_member vtable_key, *v;
976         int r;
977
978         assert(bus);
979         assert(m);
980         assert(p);
981         assert(found_object);
982
983         n = hashmap_get(bus->nodes, p);
984         if (!n)
985                 return 0;
986
987         /* First, try object callbacks */
988         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
989         if (r != 0)
990                 return r;
991
992         if (!m->interface || !m->member)
993                 return 0;
994
995         /* Then, look for a known method */
996         vtable_key.path = (char*) p;
997         vtable_key.interface = m->interface;
998         vtable_key.member = m->member;
999
1000         v = hashmap_get(bus->vtable_methods, &vtable_key);
1001         if (v) {
1002                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1003                 if (r != 0)
1004                         return r;
1005         }
1006
1007         /* Then, look for a known property */
1008         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1009                 bool get = false;
1010
1011                 get = streq(m->member, "Get");
1012
1013                 if (get || streq(m->member, "Set")) {
1014
1015                         r = sd_bus_message_rewind(m, true);
1016                         if (r < 0)
1017                                 return r;
1018
1019                         vtable_key.path = (char*) p;
1020
1021                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1022                         if (r < 0)
1023                                 return r;
1024
1025                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1026                         if (v) {
1027                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1028                                 if (r != 0)
1029                                         return r;
1030                         }
1031
1032                 } else if (streq(m->member, "GetAll")) {
1033                         const char *iface;
1034
1035                         r = sd_bus_message_rewind(m, true);
1036                         if (r < 0)
1037                                 return r;
1038
1039                         r = sd_bus_message_read(m, "s", &iface);
1040                         if (r < 0)
1041                                 return r;
1042
1043                         if (iface[0] == 0)
1044                                 iface = NULL;
1045
1046                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1047                         if (r != 0)
1048                                 return r;
1049                 }
1050
1051         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1052
1053                 r = process_introspect(bus, m, n, require_fallback, found_object);
1054                 if (r != 0)
1055                         return r;
1056
1057         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
1058
1059                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
1060                 if (r != 0)
1061                         return r;
1062         }
1063
1064         if (!*found_object) {
1065                 r = bus_node_exists(bus, n, m->path, require_fallback);
1066                 if (r < 0)
1067                         return r;
1068
1069                 if (r > 0)
1070                         *found_object = true;
1071         }
1072
1073         return 0;
1074 }
1075
1076 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1077         int r;
1078         size_t pl;
1079         bool found_object = false;
1080
1081         assert(bus);
1082         assert(m);
1083
1084         if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
1085                 return 0;
1086
1087         if (!m->path)
1088                 return 0;
1089
1090         if (hashmap_isempty(bus->nodes))
1091                 return 0;
1092
1093         pl = strlen(m->path);
1094         do {
1095                 char prefix[pl+1];
1096
1097                 bus->nodes_modified = false;
1098
1099                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1100                 if (r != 0)
1101                         return r;
1102
1103                 /* Look for fallback prefixes */
1104                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1105
1106                         if (bus->nodes_modified)
1107                                 break;
1108
1109                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1110                         if (r != 0)
1111                                 return r;
1112                 }
1113
1114         } while (bus->nodes_modified);
1115
1116         if (!found_object)
1117                 return 0;
1118
1119         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1120             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1121                 r = sd_bus_reply_method_errorf(
1122                                 bus, m,
1123                                 "org.freedesktop.DBus.Error.UnknownProperty",
1124                                 "Unknown property or interface.");
1125         else
1126                 r = sd_bus_reply_method_errorf(
1127                                 bus, m,
1128                                 "org.freedesktop.DBus.Error.UnknownMethod",
1129                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1130
1131         if (r < 0)
1132                 return r;
1133
1134         return 1;
1135 }
1136
1137 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1138         struct node *n, *parent;
1139         const char *e;
1140         char *s, *p;
1141         int r;
1142
1143         assert(bus);
1144         assert(path);
1145         assert(path[0] == '/');
1146
1147         n = hashmap_get(bus->nodes, path);
1148         if (n)
1149                 return n;
1150
1151         r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
1152         if (r < 0)
1153                 return NULL;
1154
1155         s = strdup(path);
1156         if (!s)
1157                 return NULL;
1158
1159         if (streq(path, "/"))
1160                 parent = NULL;
1161         else {
1162                 e = strrchr(path, '/');
1163                 assert(e);
1164
1165                 p = strndupa(path, MAX(1, path - e));
1166
1167                 parent = bus_node_allocate(bus, p);
1168                 if (!parent) {
1169                         free(s);
1170                         return NULL;
1171                 }
1172         }
1173
1174         n = new0(struct node, 1);
1175         if (!n)
1176                 return NULL;
1177
1178         n->parent = parent;
1179         n->path = s;
1180
1181         r = hashmap_put(bus->nodes, s, n);
1182         if (r < 0) {
1183                 free(s);
1184                 free(n);
1185                 return NULL;
1186         }
1187
1188         if (parent)
1189                 LIST_PREPEND(struct node, siblings, parent->child, n);
1190
1191         return n;
1192 }
1193
1194 static void bus_node_gc(sd_bus *b, struct node *n) {
1195         assert(b);
1196
1197         if (!n)
1198                 return;
1199
1200         if (n->child ||
1201             n->callbacks ||
1202             n->vtables ||
1203             n->enumerators ||
1204             n->object_manager)
1205                 return;
1206
1207         assert(hashmap_remove(b->nodes, n->path) == n);
1208
1209         if (n->parent)
1210                 LIST_REMOVE(struct node, siblings, n->parent->child, n);
1211
1212         free(n->path);
1213         bus_node_gc(b, n->parent);
1214         free(n);
1215 }
1216
1217 static int bus_add_object(
1218                 sd_bus *bus,
1219                 bool fallback,
1220                 const char *path,
1221                 sd_bus_message_handler_t callback,
1222                 void *userdata) {
1223
1224         struct node_callback *c;
1225         struct node *n;
1226         int r;
1227
1228         assert_return(bus, -EINVAL);
1229         assert_return(object_path_is_valid(path), -EINVAL);
1230         assert_return(callback, -EINVAL);
1231         assert_return(!bus_pid_changed(bus), -ECHILD);
1232
1233         n = bus_node_allocate(bus, path);
1234         if (!n)
1235                 return -ENOMEM;
1236
1237         c = new0(struct node_callback, 1);
1238         if (!c) {
1239                 r = -ENOMEM;
1240                 goto fail;
1241         }
1242
1243         c->node = n;
1244         c->callback = callback;
1245         c->userdata = userdata;
1246         c->is_fallback = fallback;
1247
1248         LIST_PREPEND(struct node_callback, callbacks, n->callbacks, c);
1249         return 0;
1250
1251 fail:
1252         free(c);
1253         bus_node_gc(bus, n);
1254         return r;
1255 }
1256
1257 static int bus_remove_object(
1258                 sd_bus *bus,
1259                 bool fallback,
1260                 const char *path,
1261                 sd_bus_message_handler_t callback,
1262                 void *userdata) {
1263
1264         struct node_callback *c;
1265         struct node *n;
1266
1267         assert_return(bus, -EINVAL);
1268         assert_return(object_path_is_valid(path), -EINVAL);
1269         assert_return(callback, -EINVAL);
1270         assert_return(!bus_pid_changed(bus), -ECHILD);
1271
1272         n = hashmap_get(bus->nodes, path);
1273         if (!n)
1274                 return 0;
1275
1276         LIST_FOREACH(callbacks, c, n->callbacks)
1277                 if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
1278                         break;
1279         if (!c)
1280                 return 0;
1281
1282         LIST_REMOVE(struct node_callback, callbacks, n->callbacks, c);
1283         free(c);
1284
1285         bus_node_gc(bus, n);
1286
1287         return 1;
1288 }
1289
1290 int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
1291         return bus_add_object(bus, false, path, callback, userdata);
1292 }
1293
1294 int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
1295         return bus_remove_object(bus, false, path, callback, userdata);
1296 }
1297
1298 int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
1299         return bus_add_object(bus, true, prefix, callback, userdata);
1300 }
1301
1302 int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
1303         return bus_remove_object(bus, true, prefix, callback, userdata);
1304 }
1305
1306 static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
1307         assert(bus);
1308
1309         if (!w)
1310                 return;
1311
1312         if (w->interface && w->node && w->vtable) {
1313                 const sd_bus_vtable *v;
1314
1315                 for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
1316                         struct vtable_member *x = NULL;
1317
1318                         switch (v->type) {
1319
1320                         case _SD_BUS_VTABLE_METHOD: {
1321                                 struct vtable_member key;
1322
1323                                 key.path = w->node->path;
1324                                 key.interface = w->interface;
1325                                 key.member = v->x.method.member;
1326
1327                                 x = hashmap_remove(bus->vtable_methods, &key);
1328                                 break;
1329                         }
1330
1331                         case _SD_BUS_VTABLE_PROPERTY:
1332                         case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
1333                                 struct vtable_member key;
1334
1335                                 key.path = w->node->path;
1336                                 key.interface = w->interface;
1337                                 key.member = v->x.property.member;
1338                                 x = hashmap_remove(bus->vtable_properties, &key);
1339                                 break;
1340                         }}
1341
1342                         free(x);
1343                 }
1344         }
1345
1346         free(w->interface);
1347         free(w);
1348 }
1349
1350 static unsigned vtable_member_hash_func(const void *a) {
1351         const struct vtable_member *m = a;
1352
1353         assert(m);
1354
1355         return
1356                 string_hash_func(m->path) ^
1357                 string_hash_func(m->interface) ^
1358                 string_hash_func(m->member);
1359 }
1360
1361 static int vtable_member_compare_func(const void *a, const void *b) {
1362         const struct vtable_member *x = a, *y = b;
1363         int r;
1364
1365         assert(x);
1366         assert(y);
1367
1368         r = strcmp(x->path, y->path);
1369         if (r != 0)
1370                 return r;
1371
1372         r = strcmp(x->interface, y->interface);
1373         if (r != 0)
1374                 return r;
1375
1376         return strcmp(x->member, y->member);
1377 }
1378
1379 static int add_object_vtable_internal(
1380                 sd_bus *bus,
1381                 const char *path,
1382                 const char *interface,
1383                 const sd_bus_vtable *vtable,
1384                 bool fallback,
1385                 sd_bus_object_find_t find,
1386                 void *userdata) {
1387
1388         struct node_vtable *c = NULL, *i;
1389         const sd_bus_vtable *v;
1390         struct node *n;
1391         int r;
1392
1393         assert_return(bus, -EINVAL);
1394         assert_return(object_path_is_valid(path), -EINVAL);
1395         assert_return(interface_name_is_valid(interface), -EINVAL);
1396         assert_return(vtable, -EINVAL);
1397         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1398         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1399         assert_return(!bus_pid_changed(bus), -ECHILD);
1400
1401         r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
1402         if (r < 0)
1403                 return r;
1404
1405         r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
1406         if (r < 0)
1407                 return r;
1408
1409         n = bus_node_allocate(bus, path);
1410         if (!n)
1411                 return -ENOMEM;
1412
1413         LIST_FOREACH(vtables, i, n->vtables) {
1414                 if (streq(i->interface, interface)) {
1415                         r = -EEXIST;
1416                         goto fail;
1417                 }
1418
1419                 if (i->is_fallback != fallback) {
1420                         r = -EPROTOTYPE;
1421                         goto fail;
1422                 }
1423         }
1424
1425         c = new0(struct node_vtable, 1);
1426         if (!c) {
1427                 r = -ENOMEM;
1428                 goto fail;
1429         }
1430
1431         c->node = n;
1432         c->is_fallback = fallback;
1433         c->vtable = vtable;
1434         c->userdata = userdata;
1435         c->find = find;
1436
1437         c->interface = strdup(interface);
1438         if (!c->interface) {
1439                 r = -ENOMEM;
1440                 goto fail;
1441         }
1442
1443         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1444
1445                 switch (v->type) {
1446
1447                 case _SD_BUS_VTABLE_METHOD: {
1448                         struct vtable_member *m;
1449
1450                         if (!member_name_is_valid(v->x.method.member) ||
1451                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1452                             !signature_is_valid(strempty(v->x.method.result), false) ||
1453                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1454                             v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) {
1455                                 r = -EINVAL;
1456                                 goto fail;
1457                         }
1458
1459                         m = new0(struct vtable_member, 1);
1460                         if (!m) {
1461                                 r = -ENOMEM;
1462                                 goto fail;
1463                         }
1464
1465                         m->parent = c;
1466                         m->path = n->path;
1467                         m->interface = c->interface;
1468                         m->member = v->x.method.member;
1469                         m->vtable = v;
1470
1471                         r = hashmap_put(bus->vtable_methods, m, m);
1472                         if (r < 0) {
1473                                 free(m);
1474                                 goto fail;
1475                         }
1476
1477                         break;
1478                 }
1479
1480                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1481
1482                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1483                                 r = -EINVAL;
1484                                 goto fail;
1485                         }
1486
1487                         /* Fall through */
1488
1489                 case _SD_BUS_VTABLE_PROPERTY: {
1490                         struct vtable_member *m;
1491
1492                         if (!member_name_is_valid(v->x.property.member) ||
1493                             !signature_is_single(v->x.property.signature, false) ||
1494                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0])) ||
1495                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1496                             (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))) {
1497                                 r = -EINVAL;
1498                                 goto fail;
1499                         }
1500
1501
1502                         m = new0(struct vtable_member, 1);
1503                         if (!m) {
1504                                 r = -ENOMEM;
1505                                 goto fail;
1506                         }
1507
1508                         m->parent = c;
1509                         m->path = n->path;
1510                         m->interface = c->interface;
1511                         m->member = v->x.property.member;
1512                         m->vtable = v;
1513
1514                         r = hashmap_put(bus->vtable_properties, m, m);
1515                         if (r < 0) {
1516                                 free(m);
1517                                 goto fail;
1518                         }
1519
1520                         break;
1521                 }
1522
1523                 case _SD_BUS_VTABLE_SIGNAL:
1524
1525                         if (!member_name_is_valid(v->x.signal.member) ||
1526                             !signature_is_single(strempty(v->x.signal.signature), false)) {
1527                                 r = -EINVAL;
1528                                 goto fail;
1529                         }
1530
1531                         break;
1532
1533                 default:
1534                         r = -EINVAL;
1535                         goto fail;
1536                 }
1537         }
1538
1539         LIST_PREPEND(struct node_vtable, vtables, n->vtables, c);
1540         return 0;
1541
1542 fail:
1543         if (c)
1544                 free_node_vtable(bus, c);
1545
1546         bus_node_gc(bus, n);
1547         return r;
1548 }
1549
1550 static int remove_object_vtable_internal(
1551                 sd_bus *bus,
1552                 const char *path,
1553                 const char *interface,
1554                 bool fallback) {
1555
1556         struct node_vtable *c;
1557         struct node *n;
1558
1559         assert_return(bus, -EINVAL);
1560         assert_return(object_path_is_valid(path), -EINVAL);
1561         assert_return(interface_name_is_valid(interface), -EINVAL);
1562         assert_return(!bus_pid_changed(bus), -ECHILD);
1563
1564         n = hashmap_get(bus->nodes, path);
1565         if (!n)
1566                 return 0;
1567
1568         LIST_FOREACH(vtables, c, n->vtables)
1569                 if (streq(c->interface, interface) && c->is_fallback == fallback)
1570                         break;
1571
1572         if (!c)
1573                 return 0;
1574
1575         LIST_REMOVE(struct node_vtable, vtables, n->vtables, c);
1576
1577         free_node_vtable(bus, c);
1578         bus_node_gc(bus, n);
1579
1580         return 1;
1581 }
1582
1583 int sd_bus_add_object_vtable(
1584                 sd_bus *bus,
1585                 const char *path,
1586                 const char *interface,
1587                 const sd_bus_vtable *vtable,
1588                 void *userdata) {
1589
1590         return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1591 }
1592
1593 int sd_bus_remove_object_vtable(
1594                 sd_bus *bus,
1595                 const char *path,
1596                 const char *interface) {
1597
1598         return remove_object_vtable_internal(bus, path, interface, false);
1599 }
1600
1601 int sd_bus_add_fallback_vtable(
1602                 sd_bus *bus,
1603                 const char *path,
1604                 const char *interface,
1605                 const sd_bus_vtable *vtable,
1606                 sd_bus_object_find_t find,
1607                 void *userdata) {
1608
1609         return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1610 }
1611
1612 int sd_bus_remove_fallback_vtable(
1613                 sd_bus *bus,
1614                 const char *path,
1615                 const char *interface) {
1616
1617         return remove_object_vtable_internal(bus, path, interface, true);
1618 }
1619
1620 int sd_bus_add_node_enumerator(
1621                 sd_bus *bus,
1622                 const char *path,
1623                 sd_bus_node_enumerator_t callback,
1624                 void *userdata) {
1625
1626         struct node_enumerator *c;
1627         struct node *n;
1628         int r;
1629
1630         assert_return(bus, -EINVAL);
1631         assert_return(object_path_is_valid(path), -EINVAL);
1632         assert_return(callback, -EINVAL);
1633         assert_return(!bus_pid_changed(bus), -ECHILD);
1634
1635         n = bus_node_allocate(bus, path);
1636         if (!n)
1637                 return -ENOMEM;
1638
1639         c = new0(struct node_enumerator, 1);
1640         if (!c) {
1641                 r = -ENOMEM;
1642                 goto fail;
1643         }
1644
1645         c->node = n;
1646         c->callback = callback;
1647         c->userdata = userdata;
1648
1649         LIST_PREPEND(struct node_enumerator, enumerators, n->enumerators, c);
1650         return 0;
1651
1652 fail:
1653         free(c);
1654         bus_node_gc(bus, n);
1655         return r;
1656 }
1657
1658 int sd_bus_remove_node_enumerator(
1659                 sd_bus *bus,
1660                 const char *path,
1661                 sd_bus_node_enumerator_t callback,
1662                 void *userdata) {
1663
1664         struct node_enumerator *c;
1665         struct node *n;
1666
1667         assert_return(bus, -EINVAL);
1668         assert_return(object_path_is_valid(path), -EINVAL);
1669         assert_return(callback, -EINVAL);
1670         assert_return(!bus_pid_changed(bus), -ECHILD);
1671
1672         n = hashmap_get(bus->nodes, path);
1673         if (!n)
1674                 return 0;
1675
1676         LIST_FOREACH(enumerators, c, n->enumerators)
1677                 if (c->callback == callback && c->userdata == userdata)
1678                         break;
1679
1680         if (!c)
1681                 return 0;
1682
1683         LIST_REMOVE(struct node_enumerator, enumerators, n->enumerators, c);
1684         free(c);
1685
1686         bus_node_gc(bus, n);
1687
1688         return 1;
1689 }
1690
1691 static int emit_properties_changed_on_interface(
1692                 sd_bus *bus,
1693                 const char *prefix,
1694                 const char *path,
1695                 const char *interface,
1696                 bool require_fallback,
1697                 char **names) {
1698
1699         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1700         bool has_invalidating = false;
1701         struct vtable_member key;
1702         struct node_vtable *c;
1703         struct node *n;
1704         char **property;
1705         void *u = NULL;
1706         int r;
1707
1708         assert(bus);
1709         assert(prefix);
1710         assert(path);
1711         assert(interface);
1712
1713         n = hashmap_get(bus->nodes, prefix);
1714         if (!n)
1715                 return 0;
1716
1717         LIST_FOREACH(vtables, c, n->vtables) {
1718                 if (require_fallback && !c->is_fallback)
1719                         continue;
1720
1721                 if (streq(c->interface, interface))
1722                         break;
1723         }
1724
1725         if (!c)
1726                 return 0;
1727
1728         r = node_vtable_get_userdata(bus, path, c, &u);
1729         if (r <= 0)
1730                 return r;
1731
1732         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
1733         if (r < 0)
1734                 return r;
1735
1736         r = sd_bus_message_append(m, "s", interface);
1737         if (r < 0)
1738                 return r;
1739
1740         r = sd_bus_message_open_container(m, 'a', "{sv}");
1741         if (r < 0)
1742                 return r;
1743
1744         key.path = prefix;
1745         key.interface = interface;
1746
1747         STRV_FOREACH(property, names) {
1748                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1749                 struct vtable_member *v;
1750
1751                 assert_return(member_name_is_valid(*property), -EINVAL);
1752
1753                 key.member = *property;
1754                 v = hashmap_get(bus->vtable_properties, &key);
1755                 if (!v)
1756                         return -ENOENT;
1757
1758                 assert(c == v->parent);
1759                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM);
1760
1761                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
1762                         has_invalidating = true;
1763                         continue;
1764                 }
1765
1766                 r = sd_bus_message_open_container(m, 'e', "sv");
1767                 if (r < 0)
1768                         return r;
1769
1770                 r = sd_bus_message_append(m, "s", *property);
1771                 if (r < 0)
1772                         return r;
1773
1774                 r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
1775                 if (r < 0)
1776                         return r;
1777
1778                 r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
1779                 if (r < 0)
1780                         return r;
1781
1782                 if (sd_bus_error_is_set(&error))
1783                         return bus_error_to_errno(&error);
1784
1785                 r = sd_bus_message_close_container(m);
1786                 if (r < 0)
1787                         return r;
1788
1789                 r = sd_bus_message_close_container(m);
1790                 if (r < 0)
1791                         return r;
1792         }
1793
1794         r = sd_bus_message_close_container(m);
1795         if (r < 0)
1796                 return r;
1797
1798         r = sd_bus_message_open_container(m, 'a', "s");
1799         if (r < 0)
1800                 return r;
1801
1802         if (has_invalidating) {
1803                 STRV_FOREACH(property, names) {
1804                         struct vtable_member *v;
1805
1806                         key.member = *property;
1807                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
1808                         assert(c == v->parent);
1809
1810                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
1811                                 continue;
1812
1813                         r = sd_bus_message_append(m, "s", *property);
1814                         if (r < 0)
1815                                 return r;
1816                 }
1817         }
1818
1819         r = sd_bus_message_close_container(m);
1820         if (r < 0)
1821                 return r;
1822
1823         r = sd_bus_send(bus, m, NULL);
1824         if (r < 0)
1825                 return r;
1826
1827         return 1;
1828 }
1829
1830 int sd_bus_emit_properties_changed_strv(
1831                 sd_bus *bus,
1832                 const char *path,
1833                 const char *interface,
1834                 char **names) {
1835
1836         char *prefix;
1837         int r;
1838
1839         assert_return(bus, -EINVAL);
1840         assert_return(object_path_is_valid(path), -EINVAL);
1841         assert_return(interface_name_is_valid(interface), -EINVAL);
1842         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1843         assert_return(!bus_pid_changed(bus), -ECHILD);
1844
1845         if (strv_isempty(names))
1846                 return 0;
1847
1848         r = emit_properties_changed_on_interface(bus, path, path, interface, false, names);
1849         if (r != 0)
1850                 return r;
1851
1852         prefix = alloca(strlen(path) + 1);
1853         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1854                 r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, names);
1855                 if (r != 0)
1856                         return r;
1857         }
1858
1859         return -ENOENT;
1860 }
1861
1862 int sd_bus_emit_properties_changed(
1863                 sd_bus *bus,
1864                 const char *path,
1865                 const char *interface,
1866                 const char *name, ...)  {
1867
1868         _cleanup_strv_free_ char **names = NULL;
1869         va_list ap;
1870
1871         assert_return(bus, -EINVAL);
1872         assert_return(object_path_is_valid(path), -EINVAL);
1873         assert_return(interface_name_is_valid(interface), -EINVAL);
1874         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1875         assert_return(!bus_pid_changed(bus), -ECHILD);
1876
1877         if (!name)
1878                 return 0;
1879
1880         va_start(ap, name);
1881         names = strv_new_ap(name, ap);
1882         va_end(ap);
1883
1884         if (!names)
1885                 return -ENOMEM;
1886
1887         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
1888 }
1889
1890 int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interfaces, ...) {
1891         return -ENOSYS;
1892 }
1893
1894 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interfaces, ...) {
1895         return -ENOSYS;
1896 }
1897
1898 int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
1899         struct node *n;
1900
1901         assert_return(bus, -EINVAL);
1902         assert_return(object_path_is_valid(path), -EINVAL);
1903         assert_return(!bus_pid_changed(bus), -ECHILD);
1904
1905         n = bus_node_allocate(bus, path);
1906         if (!n)
1907                 return -ENOMEM;
1908
1909         n->object_manager = true;
1910         return 0;
1911 }
1912
1913 int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
1914         struct node *n;
1915
1916         assert_return(bus, -EINVAL);
1917         assert_return(object_path_is_valid(path), -EINVAL);
1918         assert_return(!bus_pid_changed(bus), -ECHILD);
1919
1920         n = hashmap_get(bus->nodes, path);
1921         if (!n)
1922                 return 0;
1923
1924         if (!n->object_manager)
1925                 return 0;
1926
1927         n->object_manager = false;
1928         bus_node_gc(bus, n);
1929
1930         return 1;
1931 }