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