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