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