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