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