chiark / gitweb /
libsystemd: split up into subdirs
[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;
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 (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1308                 return 0;
1309
1310         if (hashmap_isempty(bus->nodes))
1311                 return 0;
1312
1313         /* Never respond to broadcast messages */
1314         if (bus->bus_client && !m->destination)
1315                 return 0;
1316
1317         assert(m->path);
1318         assert(m->member);
1319
1320         pl = strlen(m->path);
1321         do {
1322                 char prefix[pl+1];
1323
1324                 bus->nodes_modified = false;
1325
1326                 r = object_find_and_run(bus, m, m->path, false, &found_object);
1327                 if (r != 0)
1328                         return r;
1329
1330                 /* Look for fallback prefixes */
1331                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
1332
1333                         if (bus->nodes_modified)
1334                                 break;
1335
1336                         r = object_find_and_run(bus, m, prefix, true, &found_object);
1337                         if (r != 0)
1338                                 return r;
1339                 }
1340
1341         } while (bus->nodes_modified);
1342
1343         if (!found_object)
1344                 return 0;
1345
1346         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
1347             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
1348                 r = sd_bus_reply_method_errorf(
1349                                 m,
1350                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
1351                                 "Unknown property or interface.");
1352         else
1353                 r = sd_bus_reply_method_errorf(
1354                                 m,
1355                                 SD_BUS_ERROR_UNKNOWN_METHOD,
1356                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
1357
1358         if (r < 0)
1359                 return r;
1360
1361         return 1;
1362 }
1363
1364 static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
1365         struct node *n, *parent;
1366         const char *e;
1367         _cleanup_free_ char *s = NULL;
1368         char *p;
1369         int r;
1370
1371         assert(bus);
1372         assert(path);
1373         assert(path[0] == '/');
1374
1375         n = hashmap_get(bus->nodes, path);
1376         if (n)
1377                 return n;
1378
1379         r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
1380         if (r < 0)
1381                 return NULL;
1382
1383         s = strdup(path);
1384         if (!s)
1385                 return NULL;
1386
1387         if (streq(path, "/"))
1388                 parent = NULL;
1389         else {
1390                 e = strrchr(path, '/');
1391                 assert(e);
1392
1393                 p = strndupa(path, MAX(1, path - e));
1394
1395                 parent = bus_node_allocate(bus, p);
1396                 if (!parent)
1397                         return NULL;
1398         }
1399
1400         n = new0(struct node, 1);
1401         if (!n)
1402                 return NULL;
1403
1404         n->parent = parent;
1405         n->path = s;
1406         s = NULL; /* do not free */
1407
1408         r = hashmap_put(bus->nodes, n->path, n);
1409         if (r < 0) {
1410                 free(n->path);
1411                 free(n);
1412                 return NULL;
1413         }
1414
1415         if (parent)
1416                 LIST_PREPEND(siblings, parent->child, n);
1417
1418         return n;
1419 }
1420
1421 static void bus_node_gc(sd_bus *b, struct node *n) {
1422         assert(b);
1423
1424         if (!n)
1425                 return;
1426
1427         if (n->child ||
1428             n->callbacks ||
1429             n->vtables ||
1430             n->enumerators ||
1431             n->object_manager)
1432                 return;
1433
1434         assert(hashmap_remove(b->nodes, n->path) == n);
1435
1436         if (n->parent)
1437                 LIST_REMOVE(siblings, n->parent->child, n);
1438
1439         free(n->path);
1440         bus_node_gc(b, n->parent);
1441         free(n);
1442 }
1443
1444 static int bus_add_object(
1445                 sd_bus *bus,
1446                 bool fallback,
1447                 const char *path,
1448                 sd_bus_message_handler_t callback,
1449                 void *userdata) {
1450
1451         struct node_callback *c;
1452         struct node *n;
1453         int r;
1454
1455         assert_return(bus, -EINVAL);
1456         assert_return(object_path_is_valid(path), -EINVAL);
1457         assert_return(callback, -EINVAL);
1458         assert_return(!bus_pid_changed(bus), -ECHILD);
1459
1460         n = bus_node_allocate(bus, path);
1461         if (!n)
1462                 return -ENOMEM;
1463
1464         c = new0(struct node_callback, 1);
1465         if (!c) {
1466                 r = -ENOMEM;
1467                 goto fail;
1468         }
1469
1470         c->node = n;
1471         c->callback = callback;
1472         c->userdata = userdata;
1473         c->is_fallback = fallback;
1474
1475         LIST_PREPEND(callbacks, n->callbacks, c);
1476         bus->nodes_modified = true;
1477
1478         return 0;
1479
1480 fail:
1481         free(c);
1482         bus_node_gc(bus, n);
1483         return r;
1484 }
1485
1486 static int bus_remove_object(
1487                 sd_bus *bus,
1488                 bool fallback,
1489                 const char *path,
1490                 sd_bus_message_handler_t callback,
1491                 void *userdata) {
1492
1493         struct node_callback *c;
1494         struct node *n;
1495
1496         assert_return(bus, -EINVAL);
1497         assert_return(object_path_is_valid(path), -EINVAL);
1498         assert_return(callback, -EINVAL);
1499         assert_return(!bus_pid_changed(bus), -ECHILD);
1500
1501         n = hashmap_get(bus->nodes, path);
1502         if (!n)
1503                 return 0;
1504
1505         LIST_FOREACH(callbacks, c, n->callbacks)
1506                 if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
1507                         break;
1508         if (!c)
1509                 return 0;
1510
1511         LIST_REMOVE(callbacks, n->callbacks, c);
1512         free(c);
1513
1514         bus_node_gc(bus, n);
1515         bus->nodes_modified = true;
1516
1517         return 1;
1518 }
1519
1520 _public_ int sd_bus_add_object(sd_bus *bus,
1521                                const char *path,
1522                                sd_bus_message_handler_t callback,
1523                                void *userdata) {
1524
1525         return bus_add_object(bus, false, path, callback, userdata);
1526 }
1527
1528 _public_ int sd_bus_remove_object(sd_bus *bus,
1529                                   const char *path,
1530                                   sd_bus_message_handler_t callback,
1531                                   void *userdata) {
1532
1533         return bus_remove_object(bus, false, path, callback, userdata);
1534 }
1535
1536 _public_ int sd_bus_add_fallback(sd_bus *bus,
1537                                  const char *prefix,
1538                                  sd_bus_message_handler_t callback,
1539                                  void *userdata) {
1540
1541         return bus_add_object(bus, true, prefix, callback, userdata);
1542 }
1543
1544 _public_ int sd_bus_remove_fallback(sd_bus *bus,
1545                                     const char *prefix,
1546                                     sd_bus_message_handler_t callback,
1547                                     void *userdata) {
1548
1549         return bus_remove_object(bus, true, prefix, callback, userdata);
1550 }
1551
1552 static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
1553         assert(bus);
1554
1555         if (!w)
1556                 return;
1557
1558         if (w->interface && w->node && w->vtable) {
1559                 const sd_bus_vtable *v;
1560
1561                 for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
1562                         struct vtable_member *x = NULL;
1563
1564                         switch (v->type) {
1565
1566                         case _SD_BUS_VTABLE_METHOD: {
1567                                 struct vtable_member key;
1568
1569                                 key.path = w->node->path;
1570                                 key.interface = w->interface;
1571                                 key.member = v->x.method.member;
1572
1573                                 x = hashmap_remove(bus->vtable_methods, &key);
1574                                 break;
1575                         }
1576
1577                         case _SD_BUS_VTABLE_PROPERTY:
1578                         case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
1579                                 struct vtable_member key;
1580
1581                                 key.path = w->node->path;
1582                                 key.interface = w->interface;
1583                                 key.member = v->x.property.member;
1584                                 x = hashmap_remove(bus->vtable_properties, &key);
1585                                 break;
1586                         }}
1587
1588                         free(x);
1589                 }
1590         }
1591
1592         free(w->interface);
1593         free(w);
1594 }
1595
1596 static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
1597         const struct vtable_member *m = a;
1598         uint8_t hash_key2[HASH_KEY_SIZE];
1599         unsigned long ret;
1600
1601         assert(m);
1602
1603         ret = string_hash_func(m->path, hash_key);
1604
1605         /* Use a slightly different hash key for the interface */
1606         memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
1607         hash_key2[0]++;
1608         ret ^= string_hash_func(m->interface, hash_key2);
1609
1610         /* And an even different one for the  member */
1611         hash_key2[0]++;
1612         ret ^= string_hash_func(m->member, hash_key2);
1613
1614         return ret;
1615 }
1616
1617 static int vtable_member_compare_func(const void *a, const void *b) {
1618         const struct vtable_member *x = a, *y = b;
1619         int r;
1620
1621         assert(x);
1622         assert(y);
1623
1624         r = strcmp(x->path, y->path);
1625         if (r != 0)
1626                 return r;
1627
1628         r = strcmp(x->interface, y->interface);
1629         if (r != 0)
1630                 return r;
1631
1632         return strcmp(x->member, y->member);
1633 }
1634
1635 static int add_object_vtable_internal(
1636                 sd_bus *bus,
1637                 const char *path,
1638                 const char *interface,
1639                 const sd_bus_vtable *vtable,
1640                 bool fallback,
1641                 sd_bus_object_find_t find,
1642                 void *userdata) {
1643
1644         struct node_vtable *c = NULL, *i, *existing = NULL;
1645         const sd_bus_vtable *v;
1646         struct node *n;
1647         int r;
1648
1649         assert_return(bus, -EINVAL);
1650         assert_return(object_path_is_valid(path), -EINVAL);
1651         assert_return(interface_name_is_valid(interface), -EINVAL);
1652         assert_return(vtable, -EINVAL);
1653         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1654         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1655         assert_return(!bus_pid_changed(bus), -ECHILD);
1656         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1657                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1658                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1659                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1660
1661         r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
1662         if (r < 0)
1663                 return r;
1664
1665         r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
1666         if (r < 0)
1667                 return r;
1668
1669         n = bus_node_allocate(bus, path);
1670         if (!n)
1671                 return -ENOMEM;
1672
1673         LIST_FOREACH(vtables, i, n->vtables) {
1674                 if (i->is_fallback != fallback) {
1675                         r = -EPROTOTYPE;
1676                         goto fail;
1677                 }
1678
1679                 if (streq(i->interface, interface)) {
1680
1681                         if (i->vtable == vtable) {
1682                                 r = -EEXIST;
1683                                 goto fail;
1684                         }
1685
1686                         existing = i;
1687                 }
1688         }
1689
1690         c = new0(struct node_vtable, 1);
1691         if (!c) {
1692                 r = -ENOMEM;
1693                 goto fail;
1694         }
1695
1696         c->node = n;
1697         c->is_fallback = fallback;
1698         c->vtable = vtable;
1699         c->userdata = userdata;
1700         c->find = find;
1701
1702         c->interface = strdup(interface);
1703         if (!c->interface) {
1704                 r = -ENOMEM;
1705                 goto fail;
1706         }
1707
1708         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1709
1710                 switch (v->type) {
1711
1712                 case _SD_BUS_VTABLE_METHOD: {
1713                         struct vtable_member *m;
1714
1715                         if (!member_name_is_valid(v->x.method.member) ||
1716                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1717                             !signature_is_valid(strempty(v->x.method.result), false) ||
1718                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1719                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1720                                 r = -EINVAL;
1721                                 goto fail;
1722                         }
1723
1724                         m = new0(struct vtable_member, 1);
1725                         if (!m) {
1726                                 r = -ENOMEM;
1727                                 goto fail;
1728                         }
1729
1730                         m->parent = c;
1731                         m->path = n->path;
1732                         m->interface = c->interface;
1733                         m->member = v->x.method.member;
1734                         m->vtable = v;
1735
1736                         r = hashmap_put(bus->vtable_methods, m, m);
1737                         if (r < 0) {
1738                                 free(m);
1739                                 goto fail;
1740                         }
1741
1742                         break;
1743                 }
1744
1745                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1746
1747                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1748                                 r = -EINVAL;
1749                                 goto fail;
1750                         }
1751
1752                         /* Fall through */
1753
1754                 case _SD_BUS_VTABLE_PROPERTY: {
1755                         struct vtable_member *m;
1756
1757                         if (!member_name_is_valid(v->x.property.member) ||
1758                             !signature_is_single(v->x.property.signature, false) ||
1759                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1760                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1761                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
1762                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1763                                 r = -EINVAL;
1764                                 goto fail;
1765                         }
1766
1767                         m = new0(struct vtable_member, 1);
1768                         if (!m) {
1769                                 r = -ENOMEM;
1770                                 goto fail;
1771                         }
1772
1773                         m->parent = c;
1774                         m->path = n->path;
1775                         m->interface = c->interface;
1776                         m->member = v->x.property.member;
1777                         m->vtable = v;
1778
1779                         r = hashmap_put(bus->vtable_properties, m, m);
1780                         if (r < 0) {
1781                                 free(m);
1782                                 goto fail;
1783                         }
1784
1785                         break;
1786                 }
1787
1788                 case _SD_BUS_VTABLE_SIGNAL:
1789
1790                         if (!member_name_is_valid(v->x.signal.member) ||
1791                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1792                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1793                                 r = -EINVAL;
1794                                 goto fail;
1795                         }
1796
1797                         break;
1798
1799                 default:
1800                         r = -EINVAL;
1801                         goto fail;
1802                 }
1803         }
1804
1805         LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
1806         bus->nodes_modified = true;
1807
1808         return 0;
1809
1810 fail:
1811         if (c)
1812                 free_node_vtable(bus, c);
1813
1814         bus_node_gc(bus, n);
1815         return r;
1816 }
1817
1818 static int remove_object_vtable_internal(
1819                 sd_bus *bus,
1820                 const char *path,
1821                 const char *interface,
1822                 const sd_bus_vtable *vtable,
1823                 bool fallback,
1824                 sd_bus_object_find_t find,
1825                 void *userdata) {
1826
1827         struct node_vtable *c;
1828         struct node *n;
1829
1830         assert_return(bus, -EINVAL);
1831         assert_return(object_path_is_valid(path), -EINVAL);
1832         assert_return(interface_name_is_valid(interface), -EINVAL);
1833         assert_return(!bus_pid_changed(bus), -ECHILD);
1834
1835         n = hashmap_get(bus->nodes, path);
1836         if (!n)
1837                 return 0;
1838
1839         LIST_FOREACH(vtables, c, n->vtables)
1840                 if (streq(c->interface, interface) &&
1841                     c->is_fallback == fallback &&
1842                     c->vtable == vtable &&
1843                     c->find == find &&
1844                     c->userdata == userdata)
1845                         break;
1846
1847         if (!c)
1848                 return 0;
1849
1850         LIST_REMOVE(vtables, n->vtables, c);
1851
1852         free_node_vtable(bus, c);
1853         bus_node_gc(bus, n);
1854
1855         bus->nodes_modified = true;
1856
1857         return 1;
1858 }
1859
1860 _public_ int sd_bus_add_object_vtable(
1861                 sd_bus *bus,
1862                 const char *path,
1863                 const char *interface,
1864                 const sd_bus_vtable *vtable,
1865                 void *userdata) {
1866
1867         return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1868 }
1869
1870 _public_ int sd_bus_remove_object_vtable(
1871                 sd_bus *bus,
1872                 const char *path,
1873                 const char *interface,
1874                 const sd_bus_vtable *vtable,
1875                 void *userdata) {
1876
1877         return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1878 }
1879
1880 _public_ int sd_bus_add_fallback_vtable(
1881                 sd_bus *bus,
1882                 const char *path,
1883                 const char *interface,
1884                 const sd_bus_vtable *vtable,
1885                 sd_bus_object_find_t find,
1886                 void *userdata) {
1887
1888         return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1889 }
1890
1891 _public_ int sd_bus_remove_fallback_vtable(
1892                 sd_bus *bus,
1893                 const char *path,
1894                 const char *interface,
1895                 const sd_bus_vtable *vtable,
1896                 sd_bus_object_find_t find,
1897                 void *userdata) {
1898
1899         return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1900 }
1901
1902 _public_ int sd_bus_add_node_enumerator(
1903                 sd_bus *bus,
1904                 const char *path,
1905                 sd_bus_node_enumerator_t callback,
1906                 void *userdata) {
1907
1908         struct node_enumerator *c;
1909         struct node *n;
1910         int r;
1911
1912         assert_return(bus, -EINVAL);
1913         assert_return(object_path_is_valid(path), -EINVAL);
1914         assert_return(callback, -EINVAL);
1915         assert_return(!bus_pid_changed(bus), -ECHILD);
1916
1917         n = bus_node_allocate(bus, path);
1918         if (!n)
1919                 return -ENOMEM;
1920
1921         c = new0(struct node_enumerator, 1);
1922         if (!c) {
1923                 r = -ENOMEM;
1924                 goto fail;
1925         }
1926
1927         c->node = n;
1928         c->callback = callback;
1929         c->userdata = userdata;
1930
1931         LIST_PREPEND(enumerators, n->enumerators, c);
1932
1933         bus->nodes_modified = true;
1934
1935         return 0;
1936
1937 fail:
1938         free(c);
1939         bus_node_gc(bus, n);
1940         return r;
1941 }
1942
1943 _public_ int sd_bus_remove_node_enumerator(
1944                 sd_bus *bus,
1945                 const char *path,
1946                 sd_bus_node_enumerator_t callback,
1947                 void *userdata) {
1948
1949         struct node_enumerator *c;
1950         struct node *n;
1951
1952         assert_return(bus, -EINVAL);
1953         assert_return(object_path_is_valid(path), -EINVAL);
1954         assert_return(callback, -EINVAL);
1955         assert_return(!bus_pid_changed(bus), -ECHILD);
1956
1957         n = hashmap_get(bus->nodes, path);
1958         if (!n)
1959                 return 0;
1960
1961         LIST_FOREACH(enumerators, c, n->enumerators)
1962                 if (c->callback == callback && c->userdata == userdata)
1963                         break;
1964
1965         if (!c)
1966                 return 0;
1967
1968         LIST_REMOVE(enumerators, n->enumerators, c);
1969         free(c);
1970
1971         bus_node_gc(bus, n);
1972
1973         bus->nodes_modified = true;
1974
1975         return 1;
1976 }
1977
1978 static int emit_properties_changed_on_interface(
1979                 sd_bus *bus,
1980                 const char *prefix,
1981                 const char *path,
1982                 const char *interface,
1983                 bool require_fallback,
1984                 bool *found_interface,
1985                 char **names) {
1986
1987         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1988         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1989         bool has_invalidating = false, has_changing = false;
1990         struct vtable_member key = {};
1991         struct node_vtable *c;
1992         struct node *n;
1993         char **property;
1994         void *u = NULL;
1995         int r;
1996
1997         assert(bus);
1998         assert(prefix);
1999         assert(path);
2000         assert(interface);
2001         assert(found_interface);
2002
2003         n = hashmap_get(bus->nodes, prefix);
2004         if (!n)
2005                 return 0;
2006
2007         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
2008         if (r < 0)
2009                 return r;
2010
2011         r = sd_bus_message_append(m, "s", interface);
2012         if (r < 0)
2013                 return r;
2014
2015         r = sd_bus_message_open_container(m, 'a', "{sv}");
2016         if (r < 0)
2017                 return r;
2018
2019         key.path = prefix;
2020         key.interface = interface;
2021
2022         LIST_FOREACH(vtables, c, n->vtables) {
2023                 if (require_fallback && !c->is_fallback)
2024                         continue;
2025
2026                 if (!streq(c->interface, interface))
2027                         continue;
2028
2029                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2030                 if (r < 0)
2031                         return r;
2032                 if (bus->nodes_modified)
2033                         return 0;
2034                 if (r == 0)
2035                         continue;
2036
2037                 *found_interface = true;
2038
2039                 if (names) {
2040                         /* If the caller specified a list of
2041                          * properties we include exactly those in the
2042                          * PropertiesChanged message */
2043
2044                         STRV_FOREACH(property, names) {
2045                                 struct vtable_member *v;
2046
2047                                 assert_return(member_name_is_valid(*property), -EINVAL);
2048
2049                                 key.member = *property;
2050                                 v = hashmap_get(bus->vtable_properties, &key);
2051                                 if (!v)
2052                                         return -ENOENT;
2053
2054                                 /* If there are two vtables for the same
2055                                  * interface, let's handle this property when
2056                                  * we come to that vtable. */
2057                                 if (c != v->parent)
2058                                         continue;
2059
2060                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
2061                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
2062
2063                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
2064
2065                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2066                                         has_invalidating = true;
2067                                         continue;
2068                                 }
2069
2070                                 has_changing = true;
2071
2072                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
2073                                 if (r < 0)
2074                                         return r;
2075                                 if (bus->nodes_modified)
2076                                         return 0;
2077                         }
2078                 } else {
2079                         const sd_bus_vtable *v;
2080
2081                         /* If the caller specified no properties list
2082                          * we include all properties that are marked
2083                          * as changing in the message. */
2084
2085                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2086                                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2087                                         continue;
2088
2089                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
2090                                         continue;
2091
2092                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2093                                         has_invalidating = true;
2094                                         continue;
2095                                 }
2096
2097                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
2098                                         continue;
2099
2100                                 has_changing = true;
2101
2102                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
2103                                 if (r < 0)
2104                                         return r;
2105                                 if (bus->nodes_modified)
2106                                         return 0;
2107                         }
2108                 }
2109         }
2110
2111         if (!has_invalidating && !has_changing)
2112                 return 0;
2113
2114         r = sd_bus_message_close_container(m);
2115         if (r < 0)
2116                 return r;
2117
2118         r = sd_bus_message_open_container(m, 'a', "s");
2119         if (r < 0)
2120                 return r;
2121
2122         if (has_invalidating) {
2123                 LIST_FOREACH(vtables, c, n->vtables) {
2124                         if (require_fallback && !c->is_fallback)
2125                                 continue;
2126
2127                         if (!streq(c->interface, interface))
2128                                 continue;
2129
2130                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
2131                         if (r < 0)
2132                                 return r;
2133                         if (bus->nodes_modified)
2134                                 return 0;
2135                         if (r == 0)
2136                                 continue;
2137
2138                         if (names) {
2139                                 STRV_FOREACH(property, names) {
2140                                         struct vtable_member *v;
2141
2142                                         key.member = *property;
2143                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
2144                                         assert(c == v->parent);
2145
2146                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2147                                                 continue;
2148
2149                                         r = sd_bus_message_append(m, "s", *property);
2150                                         if (r < 0)
2151                                                 return r;
2152                                 }
2153                         } else {
2154                                 const sd_bus_vtable *v;
2155
2156                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2157                                         if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2158                                                 continue;
2159
2160                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
2161                                                 continue;
2162
2163                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2164                                                 continue;
2165
2166                                         r = sd_bus_message_append(m, "s", v->x.property.member);
2167                                         if (r < 0)
2168                                                 return r;
2169                                 }
2170                         }
2171                 }
2172         }
2173
2174         r = sd_bus_message_close_container(m);
2175         if (r < 0)
2176                 return r;
2177
2178         r = sd_bus_send(bus, m, NULL);
2179         if (r < 0)
2180                 return r;
2181
2182         return 1;
2183 }
2184
2185 _public_ int sd_bus_emit_properties_changed_strv(
2186                 sd_bus *bus,
2187                 const char *path,
2188                 const char *interface,
2189                 char **names) {
2190
2191         BUS_DONT_DESTROY(bus);
2192         bool found_interface = false;
2193         char *prefix;
2194         int r;
2195
2196         assert_return(bus, -EINVAL);
2197         assert_return(object_path_is_valid(path), -EINVAL);
2198         assert_return(interface_name_is_valid(interface), -EINVAL);
2199         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2200         assert_return(!bus_pid_changed(bus), -ECHILD);
2201
2202
2203         /* A non-NULL but empty names list means nothing needs to be
2204            generated. A NULL list OTOH indicates that all properties
2205            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2206            included in the PropertiesChanged message. */
2207         if (names && names[0] == NULL)
2208                 return 0;
2209
2210         do {
2211                 bus->nodes_modified = false;
2212
2213                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
2214                 if (r != 0)
2215                         return r;
2216                 if (bus->nodes_modified)
2217                         continue;
2218
2219                 prefix = alloca(strlen(path) + 1);
2220                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2221                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
2222                         if (r != 0)
2223                                 return r;
2224                         if (bus->nodes_modified)
2225                                 break;
2226                 }
2227
2228         } while (bus->nodes_modified);
2229
2230         return found_interface ? 0 : -ENOENT;
2231 }
2232
2233 _public_ int sd_bus_emit_properties_changed(
2234                 sd_bus *bus,
2235                 const char *path,
2236                 const char *interface,
2237                 const char *name, ...)  {
2238
2239         char **names;
2240
2241         assert_return(bus, -EINVAL);
2242         assert_return(object_path_is_valid(path), -EINVAL);
2243         assert_return(interface_name_is_valid(interface), -EINVAL);
2244         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2245         assert_return(!bus_pid_changed(bus), -ECHILD);
2246
2247         if (!name)
2248                 return 0;
2249
2250         names = strv_from_stdarg_alloca(name);
2251
2252         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2253 }
2254
2255 static int interfaces_added_append_one_prefix(
2256                 sd_bus *bus,
2257                 sd_bus_message *m,
2258                 const char *prefix,
2259                 const char *path,
2260                 const char *interface,
2261                 bool require_fallback) {
2262
2263         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2264         bool found_interface = false;
2265         struct node_vtable *c;
2266         struct node *n;
2267         void *u = NULL;
2268         int r;
2269
2270         assert(bus);
2271         assert(m);
2272         assert(prefix);
2273         assert(path);
2274         assert(interface);
2275
2276         n = hashmap_get(bus->nodes, prefix);
2277         if (!n)
2278                 return 0;
2279
2280         LIST_FOREACH(vtables, c, n->vtables) {
2281                 if (require_fallback && !c->is_fallback)
2282                         continue;
2283
2284                 if (!streq(c->interface, interface))
2285                         continue;
2286
2287                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2288                 if (r < 0)
2289                         return r;
2290                 if (bus->nodes_modified)
2291                         return 0;
2292                 if (r == 0)
2293                         continue;
2294
2295                 if (!found_interface) {
2296                         r = sd_bus_message_append_basic(m, 's', interface);
2297                         if (r < 0)
2298                                 return r;
2299
2300                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2301                         if (r < 0)
2302                                 return r;
2303
2304                         found_interface = true;
2305                 }
2306
2307                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2308                 if (r < 0)
2309                         return r;
2310                 if (bus->nodes_modified)
2311                         return 0;
2312         }
2313
2314         if (found_interface) {
2315                 r = sd_bus_message_close_container(m);
2316                 if (r < 0)
2317                         return r;
2318         }
2319
2320         return found_interface;
2321 }
2322
2323 static int interfaces_added_append_one(
2324                 sd_bus *bus,
2325                 sd_bus_message *m,
2326                 const char *path,
2327                 const char *interface) {
2328
2329         char *prefix;
2330         int r;
2331
2332         assert(bus);
2333         assert(m);
2334         assert(path);
2335         assert(interface);
2336
2337         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2338         if (r != 0)
2339                 return r;
2340         if (bus->nodes_modified)
2341                 return 0;
2342
2343         prefix = alloca(strlen(path) + 1);
2344         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2345                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2346                 if (r != 0)
2347                         return r;
2348                 if (bus->nodes_modified)
2349                         return 0;
2350         }
2351
2352         return -ENOENT;
2353 }
2354
2355 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2356         BUS_DONT_DESTROY(bus);
2357
2358         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2359         char **i;
2360         int r;
2361
2362         assert_return(bus, -EINVAL);
2363         assert_return(object_path_is_valid(path), -EINVAL);
2364         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2365         assert_return(!bus_pid_changed(bus), -ECHILD);
2366
2367         if (strv_isempty(interfaces))
2368                 return 0;
2369
2370         do {
2371                 bus->nodes_modified = false;
2372
2373                 if (m)
2374                         m = sd_bus_message_unref(m);
2375
2376                 r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
2377                 if (r < 0)
2378                         return r;
2379
2380                 r = sd_bus_message_append_basic(m, 'o', path);
2381                 if (r < 0)
2382                         return r;
2383
2384                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2385                 if (r < 0)
2386                         return r;
2387
2388                 STRV_FOREACH(i, interfaces) {
2389                         assert_return(interface_name_is_valid(*i), -EINVAL);
2390
2391                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2392                         if (r < 0)
2393                                 return r;
2394
2395                         r = interfaces_added_append_one(bus, m, path, *i);
2396                         if (r < 0)
2397                                 return r;
2398
2399                         if (bus->nodes_modified)
2400                                 break;
2401
2402                         r = sd_bus_message_close_container(m);
2403                         if (r < 0)
2404                                 return r;
2405                 }
2406
2407                 if (bus->nodes_modified)
2408                         continue;
2409
2410                 r = sd_bus_message_close_container(m);
2411                 if (r < 0)
2412                         return r;
2413
2414         } while (bus->nodes_modified);
2415
2416         return sd_bus_send(bus, m, NULL);
2417 }
2418
2419 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2420         char **interfaces;
2421
2422         assert_return(bus, -EINVAL);
2423         assert_return(object_path_is_valid(path), -EINVAL);
2424         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2425         assert_return(!bus_pid_changed(bus), -ECHILD);
2426
2427         interfaces = strv_from_stdarg_alloca(interface);
2428
2429         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2430 }
2431
2432 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2433         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2434         int r;
2435
2436         assert_return(bus, -EINVAL);
2437         assert_return(object_path_is_valid(path), -EINVAL);
2438         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2439         assert_return(!bus_pid_changed(bus), -ECHILD);
2440
2441         if (strv_isempty(interfaces))
2442                 return 0;
2443
2444         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
2445         if (r < 0)
2446                 return r;
2447
2448         r = sd_bus_message_append_basic(m, 'o', path);
2449         if (r < 0)
2450                 return r;
2451
2452         r = sd_bus_message_append_strv(m, interfaces);
2453         if (r < 0)
2454                 return r;
2455
2456         return sd_bus_send(bus, m, NULL);
2457 }
2458
2459 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2460         char **interfaces;
2461
2462         assert_return(bus, -EINVAL);
2463         assert_return(object_path_is_valid(path), -EINVAL);
2464         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2465         assert_return(!bus_pid_changed(bus), -ECHILD);
2466
2467         interfaces = strv_from_stdarg_alloca(interface);
2468
2469         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2470 }
2471
2472 _public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
2473         struct node *n;
2474
2475         assert_return(bus, -EINVAL);
2476         assert_return(object_path_is_valid(path), -EINVAL);
2477         assert_return(!bus_pid_changed(bus), -ECHILD);
2478
2479         n = bus_node_allocate(bus, path);
2480         if (!n)
2481                 return -ENOMEM;
2482
2483         n->object_manager = true;
2484         bus->nodes_modified = true;
2485         return 0;
2486 }
2487
2488 _public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
2489         struct node *n;
2490
2491         assert_return(bus, -EINVAL);
2492         assert_return(object_path_is_valid(path), -EINVAL);
2493         assert_return(!bus_pid_changed(bus), -ECHILD);
2494
2495         n = hashmap_get(bus->nodes, path);
2496         if (!n)
2497                 return 0;
2498
2499         if (!n->object_manager)
2500                 return 0;
2501
2502         n->object_manager = false;
2503         bus->nodes_modified = true;
2504         bus_node_gc(bus, n);
2505
2506         return 1;
2507 }