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