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