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