chiark / gitweb /
bus: never report nodes as children that do not have the right prefix
[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 int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
1393         return bus_add_object(bus, false, path, callback, userdata);
1394 }
1395
1396 int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
1397         return bus_remove_object(bus, false, path, callback, userdata);
1398 }
1399
1400 int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
1401         return bus_add_object(bus, true, prefix, callback, userdata);
1402 }
1403
1404 int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
1405         return bus_remove_object(bus, true, prefix, callback, userdata);
1406 }
1407
1408 static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
1409         assert(bus);
1410
1411         if (!w)
1412                 return;
1413
1414         if (w->interface && w->node && w->vtable) {
1415                 const sd_bus_vtable *v;
1416
1417                 for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
1418                         struct vtable_member *x = NULL;
1419
1420                         switch (v->type) {
1421
1422                         case _SD_BUS_VTABLE_METHOD: {
1423                                 struct vtable_member key;
1424
1425                                 key.path = w->node->path;
1426                                 key.interface = w->interface;
1427                                 key.member = v->x.method.member;
1428
1429                                 x = hashmap_remove(bus->vtable_methods, &key);
1430                                 break;
1431                         }
1432
1433                         case _SD_BUS_VTABLE_PROPERTY:
1434                         case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
1435                                 struct vtable_member key;
1436
1437                                 key.path = w->node->path;
1438                                 key.interface = w->interface;
1439                                 key.member = v->x.property.member;
1440                                 x = hashmap_remove(bus->vtable_properties, &key);
1441                                 break;
1442                         }}
1443
1444                         free(x);
1445                 }
1446         }
1447
1448         free(w->interface);
1449         free(w);
1450 }
1451
1452 static unsigned vtable_member_hash_func(const void *a) {
1453         const struct vtable_member *m = a;
1454
1455         assert(m);
1456
1457         return
1458                 string_hash_func(m->path) ^
1459                 string_hash_func(m->interface) ^
1460                 string_hash_func(m->member);
1461 }
1462
1463 static int vtable_member_compare_func(const void *a, const void *b) {
1464         const struct vtable_member *x = a, *y = b;
1465         int r;
1466
1467         assert(x);
1468         assert(y);
1469
1470         r = strcmp(x->path, y->path);
1471         if (r != 0)
1472                 return r;
1473
1474         r = strcmp(x->interface, y->interface);
1475         if (r != 0)
1476                 return r;
1477
1478         return strcmp(x->member, y->member);
1479 }
1480
1481 static int add_object_vtable_internal(
1482                 sd_bus *bus,
1483                 const char *path,
1484                 const char *interface,
1485                 const sd_bus_vtable *vtable,
1486                 bool fallback,
1487                 sd_bus_object_find_t find,
1488                 void *userdata) {
1489
1490         struct node_vtable *c = NULL, *i;
1491         const sd_bus_vtable *v;
1492         struct node *n;
1493         int r;
1494
1495         assert_return(bus, -EINVAL);
1496         assert_return(object_path_is_valid(path), -EINVAL);
1497         assert_return(interface_name_is_valid(interface), -EINVAL);
1498         assert_return(vtable, -EINVAL);
1499         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1500         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1501         assert_return(!bus_pid_changed(bus), -ECHILD);
1502
1503         r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
1504         if (r < 0)
1505                 return r;
1506
1507         r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
1508         if (r < 0)
1509                 return r;
1510
1511         n = bus_node_allocate(bus, path);
1512         if (!n)
1513                 return -ENOMEM;
1514
1515         LIST_FOREACH(vtables, i, n->vtables) {
1516                 if (streq(i->interface, interface)) {
1517                         r = -EEXIST;
1518                         goto fail;
1519                 }
1520
1521                 if (i->is_fallback != fallback) {
1522                         r = -EPROTOTYPE;
1523                         goto fail;
1524                 }
1525         }
1526
1527         c = new0(struct node_vtable, 1);
1528         if (!c) {
1529                 r = -ENOMEM;
1530                 goto fail;
1531         }
1532
1533         c->node = n;
1534         c->is_fallback = fallback;
1535         c->vtable = vtable;
1536         c->userdata = userdata;
1537         c->find = find;
1538
1539         c->interface = strdup(interface);
1540         if (!c->interface) {
1541                 r = -ENOMEM;
1542                 goto fail;
1543         }
1544
1545         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1546
1547                 switch (v->type) {
1548
1549                 case _SD_BUS_VTABLE_METHOD: {
1550                         struct vtable_member *m;
1551
1552                         if (!member_name_is_valid(v->x.method.member) ||
1553                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1554                             !signature_is_valid(strempty(v->x.method.result), false) ||
1555                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1556                             v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) {
1557                                 r = -EINVAL;
1558                                 goto fail;
1559                         }
1560
1561                         m = new0(struct vtable_member, 1);
1562                         if (!m) {
1563                                 r = -ENOMEM;
1564                                 goto fail;
1565                         }
1566
1567                         m->parent = c;
1568                         m->path = n->path;
1569                         m->interface = c->interface;
1570                         m->member = v->x.method.member;
1571                         m->vtable = v;
1572
1573                         r = hashmap_put(bus->vtable_methods, m, m);
1574                         if (r < 0) {
1575                                 free(m);
1576                                 goto fail;
1577                         }
1578
1579                         break;
1580                 }
1581
1582                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1583
1584                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1585                                 r = -EINVAL;
1586                                 goto fail;
1587                         }
1588
1589                         /* Fall through */
1590
1591                 case _SD_BUS_VTABLE_PROPERTY: {
1592                         struct vtable_member *m;
1593
1594                         if (!member_name_is_valid(v->x.property.member) ||
1595                             !signature_is_single(v->x.property.signature, false) ||
1596                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1597                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1598                             (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))) {
1599                                 r = -EINVAL;
1600                                 goto fail;
1601                         }
1602
1603
1604                         m = new0(struct vtable_member, 1);
1605                         if (!m) {
1606                                 r = -ENOMEM;
1607                                 goto fail;
1608                         }
1609
1610                         m->parent = c;
1611                         m->path = n->path;
1612                         m->interface = c->interface;
1613                         m->member = v->x.property.member;
1614                         m->vtable = v;
1615
1616                         r = hashmap_put(bus->vtable_properties, m, m);
1617                         if (r < 0) {
1618                                 free(m);
1619                                 goto fail;
1620                         }
1621
1622                         break;
1623                 }
1624
1625                 case _SD_BUS_VTABLE_SIGNAL:
1626
1627                         if (!member_name_is_valid(v->x.signal.member) ||
1628                             !signature_is_valid(strempty(v->x.signal.signature), false)) {
1629                                 r = -EINVAL;
1630                                 goto fail;
1631                         }
1632
1633                         break;
1634
1635                 default:
1636                         r = -EINVAL;
1637                         goto fail;
1638                 }
1639         }
1640
1641         LIST_PREPEND(vtables, n->vtables, c);
1642         bus->nodes_modified = true;
1643
1644         return 0;
1645
1646 fail:
1647         if (c)
1648                 free_node_vtable(bus, c);
1649
1650         bus_node_gc(bus, n);
1651         return r;
1652 }
1653
1654 static int remove_object_vtable_internal(
1655                 sd_bus *bus,
1656                 const char *path,
1657                 const char *interface,
1658                 bool fallback) {
1659
1660         struct node_vtable *c;
1661         struct node *n;
1662
1663         assert_return(bus, -EINVAL);
1664         assert_return(object_path_is_valid(path), -EINVAL);
1665         assert_return(interface_name_is_valid(interface), -EINVAL);
1666         assert_return(!bus_pid_changed(bus), -ECHILD);
1667
1668         n = hashmap_get(bus->nodes, path);
1669         if (!n)
1670                 return 0;
1671
1672         LIST_FOREACH(vtables, c, n->vtables)
1673                 if (streq(c->interface, interface) && c->is_fallback == fallback)
1674                         break;
1675
1676         if (!c)
1677                 return 0;
1678
1679         LIST_REMOVE(vtables, n->vtables, c);
1680
1681         free_node_vtable(bus, c);
1682         bus_node_gc(bus, n);
1683
1684         bus->nodes_modified = true;
1685
1686         return 1;
1687 }
1688
1689 int sd_bus_add_object_vtable(
1690                 sd_bus *bus,
1691                 const char *path,
1692                 const char *interface,
1693                 const sd_bus_vtable *vtable,
1694                 void *userdata) {
1695
1696         return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1697 }
1698
1699 int sd_bus_remove_object_vtable(
1700                 sd_bus *bus,
1701                 const char *path,
1702                 const char *interface) {
1703
1704         return remove_object_vtable_internal(bus, path, interface, false);
1705 }
1706
1707 int sd_bus_add_fallback_vtable(
1708                 sd_bus *bus,
1709                 const char *path,
1710                 const char *interface,
1711                 const sd_bus_vtable *vtable,
1712                 sd_bus_object_find_t find,
1713                 void *userdata) {
1714
1715         return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1716 }
1717
1718 int sd_bus_remove_fallback_vtable(
1719                 sd_bus *bus,
1720                 const char *path,
1721                 const char *interface) {
1722
1723         return remove_object_vtable_internal(bus, path, interface, true);
1724 }
1725
1726 int sd_bus_add_node_enumerator(
1727                 sd_bus *bus,
1728                 const char *path,
1729                 sd_bus_node_enumerator_t callback,
1730                 void *userdata) {
1731
1732         struct node_enumerator *c;
1733         struct node *n;
1734         int r;
1735
1736         assert_return(bus, -EINVAL);
1737         assert_return(object_path_is_valid(path), -EINVAL);
1738         assert_return(callback, -EINVAL);
1739         assert_return(!bus_pid_changed(bus), -ECHILD);
1740
1741         n = bus_node_allocate(bus, path);
1742         if (!n)
1743                 return -ENOMEM;
1744
1745         c = new0(struct node_enumerator, 1);
1746         if (!c) {
1747                 r = -ENOMEM;
1748                 goto fail;
1749         }
1750
1751         c->node = n;
1752         c->callback = callback;
1753         c->userdata = userdata;
1754
1755         LIST_PREPEND(enumerators, n->enumerators, c);
1756
1757         bus->nodes_modified = true;
1758
1759         return 0;
1760
1761 fail:
1762         free(c);
1763         bus_node_gc(bus, n);
1764         return r;
1765 }
1766
1767 int sd_bus_remove_node_enumerator(
1768                 sd_bus *bus,
1769                 const char *path,
1770                 sd_bus_node_enumerator_t callback,
1771                 void *userdata) {
1772
1773         struct node_enumerator *c;
1774         struct node *n;
1775
1776         assert_return(bus, -EINVAL);
1777         assert_return(object_path_is_valid(path), -EINVAL);
1778         assert_return(callback, -EINVAL);
1779         assert_return(!bus_pid_changed(bus), -ECHILD);
1780
1781         n = hashmap_get(bus->nodes, path);
1782         if (!n)
1783                 return 0;
1784
1785         LIST_FOREACH(enumerators, c, n->enumerators)
1786                 if (c->callback == callback && c->userdata == userdata)
1787                         break;
1788
1789         if (!c)
1790                 return 0;
1791
1792         LIST_REMOVE(enumerators, n->enumerators, c);
1793         free(c);
1794
1795         bus_node_gc(bus, n);
1796
1797         bus->nodes_modified = true;
1798
1799         return 1;
1800 }
1801
1802 static int emit_properties_changed_on_interface(
1803                 sd_bus *bus,
1804                 const char *prefix,
1805                 const char *path,
1806                 const char *interface,
1807                 bool require_fallback,
1808                 char **names) {
1809
1810         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1811         bool has_invalidating = false;
1812         struct vtable_member key;
1813         struct node_vtable *c;
1814         struct node *n;
1815         char **property;
1816         void *u = NULL;
1817         int r;
1818
1819         assert(bus);
1820         assert(prefix);
1821         assert(path);
1822         assert(interface);
1823
1824         n = hashmap_get(bus->nodes, prefix);
1825         if (!n)
1826                 return 0;
1827
1828         LIST_FOREACH(vtables, c, n->vtables) {
1829                 if (require_fallback && !c->is_fallback)
1830                         continue;
1831
1832                 if (streq(c->interface, interface))
1833                         break;
1834         }
1835
1836         if (!c)
1837                 return 0;
1838
1839         r = node_vtable_get_userdata(bus, path, c, &u);
1840         if (r <= 0)
1841                 return r;
1842         if (bus->nodes_modified)
1843                 return 0;
1844
1845         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
1846         if (r < 0)
1847                 return r;
1848
1849         r = sd_bus_message_append(m, "s", interface);
1850         if (r < 0)
1851                 return r;
1852
1853         r = sd_bus_message_open_container(m, 'a', "{sv}");
1854         if (r < 0)
1855                 return r;
1856
1857         key.path = prefix;
1858         key.interface = interface;
1859
1860         STRV_FOREACH(property, names) {
1861                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1862                 struct vtable_member *v;
1863
1864                 assert_return(member_name_is_valid(*property), -EINVAL);
1865
1866                 key.member = *property;
1867                 v = hashmap_get(bus->vtable_properties, &key);
1868                 if (!v)
1869                         return -ENOENT;
1870
1871                 assert(c == v->parent);
1872                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM);
1873
1874                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
1875                         has_invalidating = true;
1876                         continue;
1877                 }
1878
1879                 r = sd_bus_message_open_container(m, 'e', "sv");
1880                 if (r < 0)
1881                         return r;
1882
1883                 r = sd_bus_message_append(m, "s", *property);
1884                 if (r < 0)
1885                         return r;
1886
1887                 r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
1888                 if (r < 0)
1889                         return r;
1890
1891                 r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
1892                 if (r < 0)
1893                         return r;
1894                 if (bus->nodes_modified)
1895                         return 0;
1896
1897                 r = sd_bus_message_close_container(m);
1898                 if (r < 0)
1899                         return r;
1900
1901                 r = sd_bus_message_close_container(m);
1902                 if (r < 0)
1903                         return r;
1904         }
1905
1906         r = sd_bus_message_close_container(m);
1907         if (r < 0)
1908                 return r;
1909
1910         r = sd_bus_message_open_container(m, 'a', "s");
1911         if (r < 0)
1912                 return r;
1913
1914         if (has_invalidating) {
1915                 STRV_FOREACH(property, names) {
1916                         struct vtable_member *v;
1917
1918                         key.member = *property;
1919                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
1920                         assert(c == v->parent);
1921
1922                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
1923                                 continue;
1924
1925                         r = sd_bus_message_append(m, "s", *property);
1926                         if (r < 0)
1927                                 return r;
1928                 }
1929         }
1930
1931         r = sd_bus_message_close_container(m);
1932         if (r < 0)
1933                 return r;
1934
1935         r = sd_bus_send(bus, m, NULL);
1936         if (r < 0)
1937                 return r;
1938
1939         return 1;
1940 }
1941
1942 int sd_bus_emit_properties_changed_strv(
1943                 sd_bus *bus,
1944                 const char *path,
1945                 const char *interface,
1946                 char **names) {
1947
1948         BUS_DONT_DESTROY(bus);
1949         char *prefix;
1950         int r;
1951
1952         assert_return(bus, -EINVAL);
1953         assert_return(object_path_is_valid(path), -EINVAL);
1954         assert_return(interface_name_is_valid(interface), -EINVAL);
1955         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1956         assert_return(!bus_pid_changed(bus), -ECHILD);
1957
1958         if (strv_isempty(names))
1959                 return 0;
1960
1961         do {
1962                 bus->nodes_modified = false;
1963
1964                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, names);
1965                 if (r != 0)
1966                         return r;
1967                 if (bus->nodes_modified)
1968                         continue;
1969
1970                 prefix = alloca(strlen(path) + 1);
1971                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
1972                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, names);
1973                         if (r != 0)
1974                                 return r;
1975                         if (bus->nodes_modified)
1976                                 break;
1977                 }
1978
1979         } while (bus->nodes_modified);
1980
1981         return -ENOENT;
1982 }
1983
1984 int sd_bus_emit_properties_changed(
1985                 sd_bus *bus,
1986                 const char *path,
1987                 const char *interface,
1988                 const char *name, ...)  {
1989
1990         char **names;
1991
1992         assert_return(bus, -EINVAL);
1993         assert_return(object_path_is_valid(path), -EINVAL);
1994         assert_return(interface_name_is_valid(interface), -EINVAL);
1995         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1996         assert_return(!bus_pid_changed(bus), -ECHILD);
1997
1998         if (!name)
1999                 return 0;
2000
2001         names = strv_from_stdarg_alloca(name);
2002
2003         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2004 }
2005
2006 static int interfaces_added_append_one_prefix(
2007                 sd_bus *bus,
2008                 sd_bus_message *m,
2009                 const char *prefix,
2010                 const char *path,
2011                 const char *interface,
2012                 bool require_fallback) {
2013
2014         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2015         struct node_vtable *c;
2016         struct node *n;
2017         void *u = NULL;
2018         int r;
2019
2020         assert(bus);
2021         assert(m);
2022         assert(prefix);
2023         assert(path);
2024         assert(interface);
2025
2026         n = hashmap_get(bus->nodes, prefix);
2027         if (!n)
2028                 return 0;
2029
2030         LIST_FOREACH(vtables, c, n->vtables) {
2031                 if (require_fallback && !c->is_fallback)
2032                         continue;
2033
2034                 if (streq(c->interface, interface))
2035                         break;
2036         }
2037
2038         if (!c)
2039                 return 0;
2040
2041         r = node_vtable_get_userdata(bus, path, c, &u);
2042         if (r <= 0)
2043                 return r;
2044         if (bus->nodes_modified)
2045                 return 0;
2046
2047         r = sd_bus_message_append_basic(m, 's', interface);
2048         if (r < 0)
2049                 return r;
2050
2051         r = sd_bus_message_open_container(m, 'a', "{sv}");
2052         if (r < 0)
2053                 return r;
2054
2055         r = vtable_append_all_properties(bus, m,path, c, u, &error);
2056         if (r < 0)
2057                 return r;
2058         if (bus->nodes_modified)
2059                 return 0;
2060
2061         r = sd_bus_message_close_container(m);
2062         if (r < 0)
2063                 return r;
2064
2065         return 1;
2066 }
2067
2068 static int interfaces_added_append_one(
2069                 sd_bus *bus,
2070                 sd_bus_message *m,
2071                 const char *path,
2072                 const char *interface) {
2073
2074         char *prefix;
2075         int r;
2076
2077         assert(bus);
2078         assert(m);
2079         assert(path);
2080         assert(interface);
2081
2082         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2083         if (r != 0)
2084                 return r;
2085         if (bus->nodes_modified)
2086                 return 0;
2087
2088         prefix = alloca(strlen(path) + 1);
2089         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2090                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2091                 if (r != 0)
2092                         return r;
2093                 if (bus->nodes_modified)
2094                         return 0;
2095         }
2096
2097         return -ENOENT;
2098 }
2099
2100 int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2101         BUS_DONT_DESTROY(bus);
2102
2103         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2104         char **i;
2105         int r;
2106
2107         assert_return(bus, -EINVAL);
2108         assert_return(object_path_is_valid(path), -EINVAL);
2109         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2110         assert_return(!bus_pid_changed(bus), -ECHILD);
2111
2112         if (strv_isempty(interfaces))
2113                 return 0;
2114
2115         do {
2116                 bus->nodes_modified = false;
2117
2118                 if (m)
2119                         m = sd_bus_message_unref(m);
2120
2121                 r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
2122                 if (r < 0)
2123                         return r;
2124
2125                 r = sd_bus_message_append_basic(m, 'o', path);
2126                 if (r < 0)
2127                         return r;
2128
2129                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2130                 if (r < 0)
2131                         return r;
2132
2133                 STRV_FOREACH(i, interfaces) {
2134                         assert_return(interface_name_is_valid(*i), -EINVAL);
2135
2136                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2137                         if (r < 0)
2138                                 return r;
2139
2140                         r = interfaces_added_append_one(bus, m, path, *i);
2141                         if (r < 0)
2142                                 return r;
2143
2144                         if (bus->nodes_modified)
2145                                 break;
2146
2147                         r = sd_bus_message_close_container(m);
2148                         if (r < 0)
2149                                 return r;
2150                 }
2151
2152                 if (bus->nodes_modified)
2153                         continue;
2154
2155                 r = sd_bus_message_close_container(m);
2156                 if (r < 0)
2157                         return r;
2158
2159         } while (bus->nodes_modified);
2160
2161         return sd_bus_send(bus, m, NULL);
2162 }
2163
2164 int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2165         char **interfaces;
2166
2167         assert_return(bus, -EINVAL);
2168         assert_return(object_path_is_valid(path), -EINVAL);
2169         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2170         assert_return(!bus_pid_changed(bus), -ECHILD);
2171
2172         interfaces = strv_from_stdarg_alloca(interface);
2173
2174         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2175 }
2176
2177 int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2178         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2179         int r;
2180
2181         assert_return(bus, -EINVAL);
2182         assert_return(object_path_is_valid(path), -EINVAL);
2183         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2184         assert_return(!bus_pid_changed(bus), -ECHILD);
2185
2186         if (strv_isempty(interfaces))
2187                 return 0;
2188
2189         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
2190         if (r < 0)
2191                 return r;
2192
2193         r = sd_bus_message_append_basic(m, 'o', path);
2194         if (r < 0)
2195                 return r;
2196
2197         r = sd_bus_message_append_strv(m, interfaces);
2198         if (r < 0)
2199                 return r;
2200
2201         return sd_bus_send(bus, m, NULL);
2202 }
2203
2204 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2205         char **interfaces;
2206
2207         assert_return(bus, -EINVAL);
2208         assert_return(object_path_is_valid(path), -EINVAL);
2209         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2210         assert_return(!bus_pid_changed(bus), -ECHILD);
2211
2212         interfaces = strv_from_stdarg_alloca(interface);
2213
2214         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2215 }
2216
2217 int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
2218         struct node *n;
2219
2220         assert_return(bus, -EINVAL);
2221         assert_return(object_path_is_valid(path), -EINVAL);
2222         assert_return(!bus_pid_changed(bus), -ECHILD);
2223
2224         n = bus_node_allocate(bus, path);
2225         if (!n)
2226                 return -ENOMEM;
2227
2228         n->object_manager = true;
2229         bus->nodes_modified = true;
2230         return 0;
2231 }
2232
2233 int sd_bus_remove_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 = hashmap_get(bus->nodes, path);
2241         if (!n)
2242                 return 0;
2243
2244         if (!n->object_manager)
2245                 return 0;
2246
2247         n->object_manager = false;
2248         bus->nodes_modified = true;
2249         bus_node_gc(bus, n);
2250
2251         return 1;
2252 }