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