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