chiark / gitweb /
bus: properly generate GetAll reply
[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         size_t pl;
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         pl = strlen(path);
867         if (pl > 1) {
868                 char p[pl + 1];
869                 strcpy(p, path);
870
871                 for (;;) {
872                         char *e;
873
874                         e = strrchr(p, '/');
875                         if (e == p || !e)
876                                 break;
877
878                         *e = 0;
879
880                         r = object_manager_serialize_path(bus, reply, p, path, true, error);
881                         if (r < 0)
882                                 return r;
883
884                         if (sd_bus_error_is_set(error))
885                                 return 0;
886                 }
887         }
888
889         return 0;
890 }
891
892 static int process_get_managed_objects(
893                 sd_bus *bus,
894                 sd_bus_message *m,
895                 struct node *n,
896                 bool require_fallback,
897                 bool *found_object) {
898
899         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
900         _cleanup_set_free_free_ Set *s = NULL;
901         bool empty;
902         int r;
903
904         assert(bus);
905         assert(m);
906         assert(n);
907         assert(found_object);
908
909         if (!bus_node_with_object_manager(bus, n))
910                 return 0;
911
912         r = get_child_nodes(bus, m->path, n, &s);
913         if (r < 0)
914                 return r;
915
916         r = sd_bus_message_new_method_return(bus, m, &reply);
917         if (r < 0)
918                 return r;
919
920         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
921         if (r < 0)
922                 return r;
923
924         empty = set_isempty(s);
925         if (empty) {
926                 struct node_vtable *c;
927
928                 /* Hmm, so we have no children? Then let's check
929                  * whether we exist at all, i.e. whether at least one
930                  * vtable exists. */
931
932                 LIST_FOREACH(vtables, c, n->vtables) {
933
934                         if (require_fallback && !c->is_fallback)
935                                 continue;
936
937                         if (r < 0)
938                                 return r;
939                         if (r == 0)
940                                 continue;
941
942                         empty = false;
943                         break;
944                 }
945
946                 if (empty)
947                         return 0;
948         } else {
949                 Iterator i;
950                 char *path;
951
952                 SET_FOREACH(path, s, i) {
953                         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
954
955                         r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
956                         if (r < 0)
957                                 return -ENOMEM;
958
959                         if (sd_bus_error_is_set(&error)) {
960                                 r = sd_bus_reply_method_error(bus, m, &error);
961                                 if (r < 0)
962                                         return r;
963
964                                 return 1;
965                         }
966                 }
967         }
968
969         r = sd_bus_message_close_container(reply);
970         if (r < 0)
971                 return r;
972
973         r = sd_bus_send(bus, reply, NULL);
974         if (r < 0)
975                 return r;
976
977         return 1;
978 }
979
980 static int object_find_and_run(
981                 sd_bus *bus,
982                 sd_bus_message *m,
983                 const char *p,
984                 bool require_fallback,
985                 bool *found_object) {
986
987         struct node *n;
988         struct vtable_member vtable_key, *v;
989         int r;
990
991         assert(bus);
992         assert(m);
993         assert(p);
994         assert(found_object);
995
996         n = hashmap_get(bus->nodes, p);
997         if (!n)
998                 return 0;
999
1000         /* First, try object callbacks */
1001         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
1002         if (r != 0)
1003                 return r;
1004
1005         if (!m->interface || !m->member)
1006                 return 0;
1007
1008         /* Then, look for a known method */
1009         vtable_key.path = (char*) p;
1010         vtable_key.interface = m->interface;
1011         vtable_key.member = m->member;
1012
1013         v = hashmap_get(bus->vtable_methods, &vtable_key);
1014         if (v) {
1015                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
1016                 if (r != 0)
1017                         return r;
1018         }
1019
1020         /* Then, look for a known property */
1021         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
1022                 bool get = false;
1023
1024                 get = streq(m->member, "Get");
1025
1026                 if (get || streq(m->member, "Set")) {
1027
1028                         r = sd_bus_message_rewind(m, true);
1029                         if (r < 0)
1030                                 return r;
1031
1032                         vtable_key.path = (char*) p;
1033
1034                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
1035                         if (r < 0)
1036                                 return r;
1037
1038                         v = hashmap_get(bus->vtable_properties, &vtable_key);
1039                         if (v) {
1040                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
1041                                 if (r != 0)
1042                                         return r;
1043                         }
1044
1045                 } else if (streq(m->member, "GetAll")) {
1046                         const char *iface;
1047
1048                         r = sd_bus_message_rewind(m, true);
1049                         if (r < 0)
1050                                 return r;
1051
1052                         r = sd_bus_message_read(m, "s", &iface);
1053                         if (r < 0)
1054                                 return r;
1055
1056                         if (iface[0] == 0)
1057                                 iface = NULL;
1058
1059                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
1060                         if (r != 0)
1061                                 return r;
1062                 }
1063
1064         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1065
1066                 r = process_introspect(bus, m, n, require_fallback, found_object);
1067                 if (r != 0)
1068                         return r;
1069
1070         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
1071
1072                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
1073                 if (r != 0)
1074                         return r;
1075         }
1076
1077         if (!*found_object) {
1078                 r = bus_node_exists(bus, n, m->path, require_fallback);
1079                 if (r < 0)
1080                         return r;
1081
1082                 if (r > 0)
1083                         *found_object = true;
1084         }
1085
1086         return 0;
1087 }
1088
1089 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
1090         int r;
1091         size_t pl;
1092         bool found_object = false;
1093
1094         assert(bus);
1095         assert(m);
1096
1097         if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
1098                 return 0;
1099
1100         if (!m->path)
1101                 return 0;
1102
1103         if (hashmap_isempty(bus->nodes))
1104                 return 0;
1105
1106         pl = strlen(m->path);
1107         do {
1108                 char p[pl+1];
1109
1110                 bus->nodes_modified = false;
1111
1112                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1113                 if (r != 0)
1114                         return r;
1115
1116                 /* Look for fallback prefixes */
1117                 strcpy(p, m->path);
1118                 for (;;) {
1119                         char *e;
1120
1121                         if (streq(p, "/"))
1122                                 break;
1123
1124                         if (bus->nodes_modified)
1125                                 break;
1126
1127                         e = strrchr(p, '/');
1128                         assert(e);
1129                         if (e == p)
1130                                 *(e+1) = 0;
1131                         else
1132                                 *e = 0;
1133
1134                         r = object_find_and_run(bus, m, p, true, &found_object);
1135                         if (r != 0)
1136                                 return r;
1137                 }
1138
1139         } while (bus->nodes_modified);
1140
1141         if (!found_object)
1142                 return 0;
1143
1144         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1145             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1146                 r = sd_bus_reply_method_errorf(
1147                                 bus, m,
1148                                 "org.freedesktop.DBus.Error.UnknownProperty",
1149                                 "Unknown property or interface.");
1150         else
1151                 r = sd_bus_reply_method_errorf(
1152                                 bus, m,
1153                                 "org.freedesktop.DBus.Error.UnknownMethod",
1154                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1155
1156         if (r < 0)
1157                 return r;
1158
1159         return 1;
1160 }
1161
1162 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1163         struct node *n, *parent;
1164         const char *e;
1165         char *s, *p;
1166         int r;
1167
1168         assert(bus);
1169         assert(path);
1170         assert(path[0] == '/');
1171
1172         n = hashmap_get(bus->nodes, path);
1173         if (n)
1174                 return n;
1175
1176         r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
1177         if (r < 0)
1178                 return NULL;
1179
1180         s = strdup(path);
1181         if (!s)
1182                 return NULL;
1183
1184         if (streq(path, "/"))
1185                 parent = NULL;
1186         else {
1187                 e = strrchr(path, '/');
1188                 assert(e);
1189
1190                 p = strndupa(path, MAX(1, path - e));
1191
1192                 parent = bus_node_allocate(bus, p);
1193                 if (!parent) {
1194                         free(s);
1195                         return NULL;
1196                 }
1197         }
1198
1199         n = new0(struct node, 1);
1200         if (!n)
1201                 return NULL;
1202
1203         n->parent = parent;
1204         n->path = s;
1205
1206         r = hashmap_put(bus->nodes, s, n);
1207         if (r < 0) {
1208                 free(s);
1209                 free(n);
1210                 return NULL;
1211         }
1212
1213         if (parent)
1214                 LIST_PREPEND(struct node, siblings, parent->child, n);
1215
1216         return n;
1217 }
1218
1219 static void bus_node_gc(sd_bus *b, struct node *n) {
1220         assert(b);
1221
1222         if (!n)
1223                 return;
1224
1225         if (n->child ||
1226             n->callbacks ||
1227             n->vtables ||
1228             n->enumerators ||
1229             n->object_manager)
1230                 return;
1231
1232         assert(hashmap_remove(b->nodes, n->path) == n);
1233
1234         if (n->parent)
1235                 LIST_REMOVE(struct node, siblings, n->parent->child, n);
1236
1237         free(n->path);
1238         bus_node_gc(b, n->parent);
1239         free(n);
1240 }
1241
1242 static int bus_add_object(
1243                 sd_bus *bus,
1244                 bool fallback,
1245                 const char *path,
1246                 sd_bus_message_handler_t callback,
1247                 void *userdata) {
1248
1249         struct node_callback *c;
1250         struct node *n;
1251         int r;
1252
1253         assert_return(bus, -EINVAL);
1254         assert_return(object_path_is_valid(path), -EINVAL);
1255         assert_return(callback, -EINVAL);
1256         assert_return(!bus_pid_changed(bus), -ECHILD);
1257
1258         n = bus_node_allocate(bus, path);
1259         if (!n)
1260                 return -ENOMEM;
1261
1262         c = new0(struct node_callback, 1);
1263         if (!c) {
1264                 r = -ENOMEM;
1265                 goto fail;
1266         }
1267
1268         c->node = n;
1269         c->callback = callback;
1270         c->userdata = userdata;
1271         c->is_fallback = fallback;
1272
1273         LIST_PREPEND(struct node_callback, callbacks, n->callbacks, c);
1274         return 0;
1275
1276 fail:
1277         free(c);
1278         bus_node_gc(bus, n);
1279         return r;
1280 }
1281
1282 static int bus_remove_object(
1283                 sd_bus *bus,
1284                 bool fallback,
1285                 const char *path,
1286                 sd_bus_message_handler_t callback,
1287                 void *userdata) {
1288
1289         struct node_callback *c;
1290         struct node *n;
1291
1292         assert_return(bus, -EINVAL);
1293         assert_return(object_path_is_valid(path), -EINVAL);
1294         assert_return(callback, -EINVAL);
1295         assert_return(!bus_pid_changed(bus), -ECHILD);
1296
1297         n = hashmap_get(bus->nodes, path);
1298         if (!n)
1299                 return 0;
1300
1301         LIST_FOREACH(callbacks, c, n->callbacks)
1302                 if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
1303                         break;
1304         if (!c)
1305                 return 0;
1306
1307         LIST_REMOVE(struct node_callback, callbacks, n->callbacks, c);
1308         free(c);
1309
1310         bus_node_gc(bus, n);
1311
1312         return 1;
1313 }
1314
1315 int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
1316         return bus_add_object(bus, false, path, callback, userdata);
1317 }
1318
1319 int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
1320         return bus_remove_object(bus, false, path, callback, userdata);
1321 }
1322
1323 int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
1324         return bus_add_object(bus, true, prefix, callback, userdata);
1325 }
1326
1327 int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
1328         return bus_remove_object(bus, true, prefix, callback, userdata);
1329 }
1330
1331 static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
1332         assert(bus);
1333
1334         if (!w)
1335                 return;
1336
1337         if (w->interface && w->node && w->vtable) {
1338                 const sd_bus_vtable *v;
1339
1340                 for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
1341                         struct vtable_member *x = NULL;
1342
1343                         switch (v->type) {
1344
1345                         case _SD_BUS_VTABLE_METHOD: {
1346                                 struct vtable_member key;
1347
1348                                 key.path = w->node->path;
1349                                 key.interface = w->interface;
1350                                 key.member = v->x.method.member;
1351
1352                                 x = hashmap_remove(bus->vtable_methods, &key);
1353                                 break;
1354                         }
1355
1356                         case _SD_BUS_VTABLE_PROPERTY:
1357                         case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
1358                                 struct vtable_member key;
1359
1360                                 key.path = w->node->path;
1361                                 key.interface = w->interface;
1362                                 key.member = v->x.property.member;
1363                                 x = hashmap_remove(bus->vtable_properties, &key);
1364                                 break;
1365                         }}
1366
1367                         free(x);
1368                 }
1369         }
1370
1371         free(w->interface);
1372         free(w);
1373 }
1374
1375 static unsigned vtable_member_hash_func(const void *a) {
1376         const struct vtable_member *m = a;
1377
1378         assert(m);
1379
1380         return
1381                 string_hash_func(m->path) ^
1382                 string_hash_func(m->interface) ^
1383                 string_hash_func(m->member);
1384 }
1385
1386 static int vtable_member_compare_func(const void *a, const void *b) {
1387         const struct vtable_member *x = a, *y = b;
1388         int r;
1389
1390         assert(x);
1391         assert(y);
1392
1393         r = strcmp(x->path, y->path);
1394         if (r != 0)
1395                 return r;
1396
1397         r = strcmp(x->interface, y->interface);
1398         if (r != 0)
1399                 return r;
1400
1401         return strcmp(x->member, y->member);
1402 }
1403
1404 static int add_object_vtable_internal(
1405                 sd_bus *bus,
1406                 const char *path,
1407                 const char *interface,
1408                 const sd_bus_vtable *vtable,
1409                 bool fallback,
1410                 sd_bus_object_find_t find,
1411                 void *userdata) {
1412
1413         struct node_vtable *c = NULL, *i;
1414         const sd_bus_vtable *v;
1415         struct node *n;
1416         int r;
1417
1418         assert_return(bus, -EINVAL);
1419         assert_return(object_path_is_valid(path), -EINVAL);
1420         assert_return(interface_name_is_valid(interface), -EINVAL);
1421         assert_return(vtable, -EINVAL);
1422         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1423         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1424         assert_return(!bus_pid_changed(bus), -ECHILD);
1425
1426         r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
1427         if (r < 0)
1428                 return r;
1429
1430         r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
1431         if (r < 0)
1432                 return r;
1433
1434         n = bus_node_allocate(bus, path);
1435         if (!n)
1436                 return -ENOMEM;
1437
1438         LIST_FOREACH(vtables, i, n->vtables) {
1439                 if (streq(i->interface, interface)) {
1440                         r = -EEXIST;
1441                         goto fail;
1442                 }
1443
1444                 if (i->is_fallback != fallback) {
1445                         r = -EPROTOTYPE;
1446                         goto fail;
1447                 }
1448         }
1449
1450         c = new0(struct node_vtable, 1);
1451         if (!c) {
1452                 r = -ENOMEM;
1453                 goto fail;
1454         }
1455
1456         c->node = n;
1457         c->is_fallback = fallback;
1458         c->vtable = vtable;
1459         c->userdata = userdata;
1460         c->find = find;
1461
1462         c->interface = strdup(interface);
1463         if (!c->interface) {
1464                 r = -ENOMEM;
1465                 goto fail;
1466         }
1467
1468         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1469
1470                 switch (v->type) {
1471
1472                 case _SD_BUS_VTABLE_METHOD: {
1473                         struct vtable_member *m;
1474
1475                         if (!member_name_is_valid(v->x.method.member) ||
1476                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1477                             !signature_is_valid(strempty(v->x.method.result), false) ||
1478                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1479                             v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) {
1480                                 r = -EINVAL;
1481                                 goto fail;
1482                         }
1483
1484                         m = new0(struct vtable_member, 1);
1485                         if (!m) {
1486                                 r = -ENOMEM;
1487                                 goto fail;
1488                         }
1489
1490                         m->parent = c;
1491                         m->path = n->path;
1492                         m->interface = c->interface;
1493                         m->member = v->x.method.member;
1494                         m->vtable = v;
1495
1496                         r = hashmap_put(bus->vtable_methods, m, m);
1497                         if (r < 0) {
1498                                 free(m);
1499                                 goto fail;
1500                         }
1501
1502                         break;
1503                 }
1504
1505                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1506
1507                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1508                                 r = -EINVAL;
1509                                 goto fail;
1510                         }
1511
1512                         /* Fall through */
1513
1514                 case _SD_BUS_VTABLE_PROPERTY: {
1515                         struct vtable_member *m;
1516
1517                         if (!member_name_is_valid(v->x.property.member) ||
1518                             !signature_is_single(v->x.property.signature, false) ||
1519                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0])) ||
1520                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1521                             (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))) {
1522                                 r = -EINVAL;
1523                                 goto fail;
1524                         }
1525
1526
1527                         m = new0(struct vtable_member, 1);
1528                         if (!m) {
1529                                 r = -ENOMEM;
1530                                 goto fail;
1531                         }
1532
1533                         m->parent = c;
1534                         m->path = n->path;
1535                         m->interface = c->interface;
1536                         m->member = v->x.property.member;
1537                         m->vtable = v;
1538
1539                         r = hashmap_put(bus->vtable_properties, m, m);
1540                         if (r < 0) {
1541                                 free(m);
1542                                 goto fail;
1543                         }
1544
1545                         break;
1546                 }
1547
1548                 case _SD_BUS_VTABLE_SIGNAL:
1549
1550                         if (!member_name_is_valid(v->x.signal.member) ||
1551                             !signature_is_single(strempty(v->x.signal.signature), false)) {
1552                                 r = -EINVAL;
1553                                 goto fail;
1554                         }
1555
1556                         break;
1557
1558                 default:
1559                         r = -EINVAL;
1560                         goto fail;
1561                 }
1562         }
1563
1564         LIST_PREPEND(struct node_vtable, vtables, n->vtables, c);
1565         return 0;
1566
1567 fail:
1568         if (c)
1569                 free_node_vtable(bus, c);
1570
1571         bus_node_gc(bus, n);
1572         return r;
1573 }
1574
1575 static int remove_object_vtable_internal(
1576                 sd_bus *bus,
1577                 const char *path,
1578                 const char *interface,
1579                 bool fallback) {
1580
1581         struct node_vtable *c;
1582         struct node *n;
1583
1584         assert_return(bus, -EINVAL);
1585         assert_return(object_path_is_valid(path), -EINVAL);
1586         assert_return(interface_name_is_valid(interface), -EINVAL);
1587         assert_return(!bus_pid_changed(bus), -ECHILD);
1588
1589         n = hashmap_get(bus->nodes, path);
1590         if (!n)
1591                 return 0;
1592
1593         LIST_FOREACH(vtables, c, n->vtables)
1594                 if (streq(c->interface, interface) && c->is_fallback == fallback)
1595                         break;
1596
1597         if (!c)
1598                 return 0;
1599
1600         LIST_REMOVE(struct node_vtable, vtables, n->vtables, c);
1601
1602         free_node_vtable(bus, c);
1603         bus_node_gc(bus, n);
1604
1605         return 1;
1606 }
1607
1608 int sd_bus_add_object_vtable(
1609                 sd_bus *bus,
1610                 const char *path,
1611                 const char *interface,
1612                 const sd_bus_vtable *vtable,
1613                 void *userdata) {
1614
1615         return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1616 }
1617
1618 int sd_bus_remove_object_vtable(
1619                 sd_bus *bus,
1620                 const char *path,
1621                 const char *interface) {
1622
1623         return remove_object_vtable_internal(bus, path, interface, false);
1624 }
1625
1626 int sd_bus_add_fallback_vtable(
1627                 sd_bus *bus,
1628                 const char *path,
1629                 const char *interface,
1630                 const sd_bus_vtable *vtable,
1631                 sd_bus_object_find_t find,
1632                 void *userdata) {
1633
1634         return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1635 }
1636
1637 int sd_bus_remove_fallback_vtable(
1638                 sd_bus *bus,
1639                 const char *path,
1640                 const char *interface) {
1641
1642         return remove_object_vtable_internal(bus, path, interface, true);
1643 }
1644
1645 int sd_bus_add_node_enumerator(
1646                 sd_bus *bus,
1647                 const char *path,
1648                 sd_bus_node_enumerator_t callback,
1649                 void *userdata) {
1650
1651         struct node_enumerator *c;
1652         struct node *n;
1653         int r;
1654
1655         assert_return(bus, -EINVAL);
1656         assert_return(object_path_is_valid(path), -EINVAL);
1657         assert_return(callback, -EINVAL);
1658         assert_return(!bus_pid_changed(bus), -ECHILD);
1659
1660         n = bus_node_allocate(bus, path);
1661         if (!n)
1662                 return -ENOMEM;
1663
1664         c = new0(struct node_enumerator, 1);
1665         if (!c) {
1666                 r = -ENOMEM;
1667                 goto fail;
1668         }
1669
1670         c->node = n;
1671         c->callback = callback;
1672         c->userdata = userdata;
1673
1674         LIST_PREPEND(struct node_enumerator, enumerators, n->enumerators, c);
1675         return 0;
1676
1677 fail:
1678         free(c);
1679         bus_node_gc(bus, n);
1680         return r;
1681 }
1682
1683 int sd_bus_remove_node_enumerator(
1684                 sd_bus *bus,
1685                 const char *path,
1686                 sd_bus_node_enumerator_t callback,
1687                 void *userdata) {
1688
1689         struct node_enumerator *c;
1690         struct node *n;
1691
1692         assert_return(bus, -EINVAL);
1693         assert_return(object_path_is_valid(path), -EINVAL);
1694         assert_return(callback, -EINVAL);
1695         assert_return(!bus_pid_changed(bus), -ECHILD);
1696
1697         n = hashmap_get(bus->nodes, path);
1698         if (!n)
1699                 return 0;
1700
1701         LIST_FOREACH(enumerators, c, n->enumerators)
1702                 if (c->callback == callback && c->userdata == userdata)
1703                         break;
1704
1705         if (!c)
1706                 return 0;
1707
1708         LIST_REMOVE(struct node_enumerator, enumerators, n->enumerators, c);
1709         free(c);
1710
1711         bus_node_gc(bus, n);
1712
1713         return 1;
1714 }
1715
1716 static int emit_properties_changed_on_interface(
1717                 sd_bus *bus,
1718                 const char *prefix,
1719                 const char *path,
1720                 const char *interface,
1721                 bool require_fallback,
1722                 char **names) {
1723
1724         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1725         bool has_invalidating = false;
1726         struct vtable_member key;
1727         struct node_vtable *c;
1728         struct node *n;
1729         char **property;
1730         void *u = NULL;
1731         int r;
1732
1733         assert(bus);
1734         assert(prefix);
1735         assert(path);
1736         assert(interface);
1737
1738         n = hashmap_get(bus->nodes, prefix);
1739         if (!n)
1740                 return 0;
1741
1742         LIST_FOREACH(vtables, c, n->vtables) {
1743                 if (require_fallback && !c->is_fallback)
1744                         continue;
1745
1746                 if (streq(c->interface, interface))
1747                         break;
1748         }
1749
1750         if (!c)
1751                 return 0;
1752
1753         r = node_vtable_get_userdata(bus, path, c, &u);
1754         if (r <= 0)
1755                 return r;
1756
1757         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
1758         if (r < 0)
1759                 return r;
1760
1761         r = sd_bus_message_append(m, "s", interface);
1762         if (r < 0)
1763                 return r;
1764
1765         r = sd_bus_message_open_container(m, 'a', "{sv}");
1766         if (r < 0)
1767                 return r;
1768
1769         key.path = prefix;
1770         key.interface = interface;
1771
1772         STRV_FOREACH(property, names) {
1773                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1774                 struct vtable_member *v;
1775
1776                 assert_return(member_name_is_valid(*property), -EINVAL);
1777
1778                 key.member = *property;
1779                 v = hashmap_get(bus->vtable_properties, &key);
1780                 if (!v)
1781                         return -ENOENT;
1782
1783                 assert(c == v->parent);
1784                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM);
1785
1786                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
1787                         has_invalidating = true;
1788                         continue;
1789                 }
1790
1791                 r = sd_bus_message_open_container(m, 'e', "sv");
1792                 if (r < 0)
1793                         return r;
1794
1795                 r = sd_bus_message_append(m, "s", *property);
1796                 if (r < 0)
1797                         return r;
1798
1799                 r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
1800                 if (r < 0)
1801                         return r;
1802
1803                 r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
1804                 if (r < 0)
1805                         return r;
1806
1807                 if (sd_bus_error_is_set(&error))
1808                         return bus_error_to_errno(&error);
1809
1810                 r = sd_bus_message_close_container(m);
1811                 if (r < 0)
1812                         return r;
1813
1814                 r = sd_bus_message_close_container(m);
1815                 if (r < 0)
1816                         return r;
1817         }
1818
1819         r = sd_bus_message_close_container(m);
1820         if (r < 0)
1821                 return r;
1822
1823         r = sd_bus_message_open_container(m, 'a', "s");
1824         if (r < 0)
1825                 return r;
1826
1827         if (has_invalidating) {
1828                 STRV_FOREACH(property, names) {
1829                         struct vtable_member *v;
1830
1831                         key.member = *property;
1832                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
1833                         assert(c == v->parent);
1834
1835                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
1836                                 continue;
1837
1838                         r = sd_bus_message_append(m, "s", *property);
1839                         if (r < 0)
1840                                 return r;
1841                 }
1842         }
1843
1844         r = sd_bus_message_close_container(m);
1845         if (r < 0)
1846                 return r;
1847
1848         r = sd_bus_send(bus, m, NULL);
1849         if (r < 0)
1850                 return r;
1851
1852         return 1;
1853 }
1854
1855 int sd_bus_emit_properties_changed_strv(
1856                 sd_bus *bus,
1857                 const char *path,
1858                 const char *interface,
1859                 char **names) {
1860
1861         size_t pl;
1862         int r;
1863
1864         assert_return(bus, -EINVAL);
1865         assert_return(object_path_is_valid(path), -EINVAL);
1866         assert_return(interface_name_is_valid(interface), -EINVAL);
1867         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1868         assert_return(!bus_pid_changed(bus), -ECHILD);
1869
1870         if (strv_isempty(names))
1871                 return 0;
1872
1873         r = emit_properties_changed_on_interface(bus, path, path, interface, false, names);
1874         if (r != 0)
1875                 return r;
1876
1877         pl = strlen(path);
1878         if (pl > 1 ) {
1879                 char p[pl+1];
1880
1881                 strcpy(p, path);
1882                 for (;;) {
1883                         char *e;
1884
1885                         if (streq(p, "/"))
1886                                 break;
1887
1888                         e = strrchr(p, '/');
1889                         assert(e);
1890                         if (e == p)
1891                                 *(e+1) = 0;
1892                         else
1893                                 *e = 0;
1894
1895                         r = emit_properties_changed_on_interface(bus, p, path, interface, true, names);
1896                         if (r != 0)
1897                                 return r;
1898                 }
1899         }
1900
1901         return -ENOENT;
1902 }
1903
1904 int sd_bus_emit_properties_changed(
1905                 sd_bus *bus,
1906                 const char *path,
1907                 const char *interface,
1908                 const char *name, ...)  {
1909
1910         _cleanup_strv_free_ char **names = NULL;
1911         va_list ap;
1912
1913         assert_return(bus, -EINVAL);
1914         assert_return(object_path_is_valid(path), -EINVAL);
1915         assert_return(interface_name_is_valid(interface), -EINVAL);
1916         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1917         assert_return(!bus_pid_changed(bus), -ECHILD);
1918
1919         if (!name)
1920                 return 0;
1921
1922         va_start(ap, name);
1923         names = strv_new_ap(name, ap);
1924         va_end(ap);
1925
1926         if (!names)
1927                 return -ENOMEM;
1928
1929         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
1930 }
1931
1932 int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interfaces, ...) {
1933         return -ENOSYS;
1934 }
1935
1936 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interfaces, ...) {
1937         return -ENOSYS;
1938 }
1939
1940 int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
1941         struct node *n;
1942
1943         assert_return(bus, -EINVAL);
1944         assert_return(object_path_is_valid(path), -EINVAL);
1945         assert_return(!bus_pid_changed(bus), -ECHILD);
1946
1947         n = bus_node_allocate(bus, path);
1948         if (!n)
1949                 return -ENOMEM;
1950
1951         n->object_manager = true;
1952         return 0;
1953 }
1954
1955 int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
1956         struct node *n;
1957
1958         assert_return(bus, -EINVAL);
1959         assert_return(object_path_is_valid(path), -EINVAL);
1960         assert_return(!bus_pid_changed(bus), -ECHILD);
1961
1962         n = hashmap_get(bus->nodes, path);
1963         if (!n)
1964                 return 0;
1965
1966         if (!n->object_manager)
1967                 return 0;
1968
1969         n->object_manager = false;
1970         bus_node_gc(bus, n);
1971
1972         return 1;
1973 }