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