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