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