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