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