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