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