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