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