chiark / gitweb /
core: the cgroup properties are not actually const
[elogind.git] / src / libsystemd-bus / bus-objects.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <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 vtable_member_hash_func(const void *a) {
1597         const struct vtable_member *m = a;
1598
1599         assert(m);
1600
1601         return
1602                 string_hash_func(m->path) ^
1603                 string_hash_func(m->interface) ^
1604                 string_hash_func(m->member);
1605 }
1606
1607 static int vtable_member_compare_func(const void *a, const void *b) {
1608         const struct vtable_member *x = a, *y = b;
1609         int r;
1610
1611         assert(x);
1612         assert(y);
1613
1614         r = strcmp(x->path, y->path);
1615         if (r != 0)
1616                 return r;
1617
1618         r = strcmp(x->interface, y->interface);
1619         if (r != 0)
1620                 return r;
1621
1622         return strcmp(x->member, y->member);
1623 }
1624
1625 static int add_object_vtable_internal(
1626                 sd_bus *bus,
1627                 const char *path,
1628                 const char *interface,
1629                 const sd_bus_vtable *vtable,
1630                 bool fallback,
1631                 sd_bus_object_find_t find,
1632                 void *userdata) {
1633
1634         struct node_vtable *c = NULL, *i, *existing = NULL;
1635         const sd_bus_vtable *v;
1636         struct node *n;
1637         int r;
1638
1639         assert_return(bus, -EINVAL);
1640         assert_return(object_path_is_valid(path), -EINVAL);
1641         assert_return(interface_name_is_valid(interface), -EINVAL);
1642         assert_return(vtable, -EINVAL);
1643         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
1644         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
1645         assert_return(!bus_pid_changed(bus), -ECHILD);
1646         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
1647                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
1648                       !streq(interface, "org.freedesktop.DBus.Peer") &&
1649                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
1650
1651         r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
1652         if (r < 0)
1653                 return r;
1654
1655         r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
1656         if (r < 0)
1657                 return r;
1658
1659         n = bus_node_allocate(bus, path);
1660         if (!n)
1661                 return -ENOMEM;
1662
1663         LIST_FOREACH(vtables, i, n->vtables) {
1664                 if (i->is_fallback != fallback) {
1665                         r = -EPROTOTYPE;
1666                         goto fail;
1667                 }
1668
1669                 if (streq(i->interface, interface)) {
1670
1671                         if (i->vtable == vtable) {
1672                                 r = -EEXIST;
1673                                 goto fail;
1674                         }
1675
1676                         existing = i;
1677                 }
1678         }
1679
1680         c = new0(struct node_vtable, 1);
1681         if (!c) {
1682                 r = -ENOMEM;
1683                 goto fail;
1684         }
1685
1686         c->node = n;
1687         c->is_fallback = fallback;
1688         c->vtable = vtable;
1689         c->userdata = userdata;
1690         c->find = find;
1691
1692         c->interface = strdup(interface);
1693         if (!c->interface) {
1694                 r = -ENOMEM;
1695                 goto fail;
1696         }
1697
1698         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
1699
1700                 switch (v->type) {
1701
1702                 case _SD_BUS_VTABLE_METHOD: {
1703                         struct vtable_member *m;
1704
1705                         if (!member_name_is_valid(v->x.method.member) ||
1706                             !signature_is_valid(strempty(v->x.method.signature), false) ||
1707                             !signature_is_valid(strempty(v->x.method.result), false) ||
1708                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
1709                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
1710                                 r = -EINVAL;
1711                                 goto fail;
1712                         }
1713
1714                         m = new0(struct vtable_member, 1);
1715                         if (!m) {
1716                                 r = -ENOMEM;
1717                                 goto fail;
1718                         }
1719
1720                         m->parent = c;
1721                         m->path = n->path;
1722                         m->interface = c->interface;
1723                         m->member = v->x.method.member;
1724                         m->vtable = v;
1725
1726                         r = hashmap_put(bus->vtable_methods, m, m);
1727                         if (r < 0) {
1728                                 free(m);
1729                                 goto fail;
1730                         }
1731
1732                         break;
1733                 }
1734
1735                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
1736
1737                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
1738                                 r = -EINVAL;
1739                                 goto fail;
1740                         }
1741
1742                         /* Fall through */
1743
1744                 case _SD_BUS_VTABLE_PROPERTY: {
1745                         struct vtable_member *m;
1746
1747                         if (!member_name_is_valid(v->x.property.member) ||
1748                             !signature_is_single(v->x.property.signature, false) ||
1749                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
1750                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
1751                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
1752                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
1753                                 r = -EINVAL;
1754                                 goto fail;
1755                         }
1756
1757                         m = new0(struct vtable_member, 1);
1758                         if (!m) {
1759                                 r = -ENOMEM;
1760                                 goto fail;
1761                         }
1762
1763                         m->parent = c;
1764                         m->path = n->path;
1765                         m->interface = c->interface;
1766                         m->member = v->x.property.member;
1767                         m->vtable = v;
1768
1769                         r = hashmap_put(bus->vtable_properties, m, m);
1770                         if (r < 0) {
1771                                 free(m);
1772                                 goto fail;
1773                         }
1774
1775                         break;
1776                 }
1777
1778                 case _SD_BUS_VTABLE_SIGNAL:
1779
1780                         if (!member_name_is_valid(v->x.signal.member) ||
1781                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
1782                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
1783                                 r = -EINVAL;
1784                                 goto fail;
1785                         }
1786
1787                         break;
1788
1789                 default:
1790                         r = -EINVAL;
1791                         goto fail;
1792                 }
1793         }
1794
1795         LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
1796         bus->nodes_modified = true;
1797
1798         return 0;
1799
1800 fail:
1801         if (c)
1802                 free_node_vtable(bus, c);
1803
1804         bus_node_gc(bus, n);
1805         return r;
1806 }
1807
1808 static int remove_object_vtable_internal(
1809                 sd_bus *bus,
1810                 const char *path,
1811                 const char *interface,
1812                 const sd_bus_vtable *vtable,
1813                 bool fallback,
1814                 sd_bus_object_find_t find,
1815                 void *userdata) {
1816
1817         struct node_vtable *c;
1818         struct node *n;
1819
1820         assert_return(bus, -EINVAL);
1821         assert_return(object_path_is_valid(path), -EINVAL);
1822         assert_return(interface_name_is_valid(interface), -EINVAL);
1823         assert_return(!bus_pid_changed(bus), -ECHILD);
1824
1825         n = hashmap_get(bus->nodes, path);
1826         if (!n)
1827                 return 0;
1828
1829         LIST_FOREACH(vtables, c, n->vtables)
1830                 if (streq(c->interface, interface) &&
1831                     c->is_fallback == fallback &&
1832                     c->vtable == vtable &&
1833                     c->find == find &&
1834                     c->userdata == userdata)
1835                         break;
1836
1837         if (!c)
1838                 return 0;
1839
1840         LIST_REMOVE(vtables, n->vtables, c);
1841
1842         free_node_vtable(bus, c);
1843         bus_node_gc(bus, n);
1844
1845         bus->nodes_modified = true;
1846
1847         return 1;
1848 }
1849
1850 _public_ int sd_bus_add_object_vtable(
1851                 sd_bus *bus,
1852                 const char *path,
1853                 const char *interface,
1854                 const sd_bus_vtable *vtable,
1855                 void *userdata) {
1856
1857         return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1858 }
1859
1860 _public_ int sd_bus_remove_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 remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
1868 }
1869
1870 _public_ int sd_bus_add_fallback_vtable(
1871                 sd_bus *bus,
1872                 const char *path,
1873                 const char *interface,
1874                 const sd_bus_vtable *vtable,
1875                 sd_bus_object_find_t find,
1876                 void *userdata) {
1877
1878         return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1879 }
1880
1881 _public_ int sd_bus_remove_fallback_vtable(
1882                 sd_bus *bus,
1883                 const char *path,
1884                 const char *interface,
1885                 const sd_bus_vtable *vtable,
1886                 sd_bus_object_find_t find,
1887                 void *userdata) {
1888
1889         return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
1890 }
1891
1892 _public_ int sd_bus_add_node_enumerator(
1893                 sd_bus *bus,
1894                 const char *path,
1895                 sd_bus_node_enumerator_t callback,
1896                 void *userdata) {
1897
1898         struct node_enumerator *c;
1899         struct node *n;
1900         int r;
1901
1902         assert_return(bus, -EINVAL);
1903         assert_return(object_path_is_valid(path), -EINVAL);
1904         assert_return(callback, -EINVAL);
1905         assert_return(!bus_pid_changed(bus), -ECHILD);
1906
1907         n = bus_node_allocate(bus, path);
1908         if (!n)
1909                 return -ENOMEM;
1910
1911         c = new0(struct node_enumerator, 1);
1912         if (!c) {
1913                 r = -ENOMEM;
1914                 goto fail;
1915         }
1916
1917         c->node = n;
1918         c->callback = callback;
1919         c->userdata = userdata;
1920
1921         LIST_PREPEND(enumerators, n->enumerators, c);
1922
1923         bus->nodes_modified = true;
1924
1925         return 0;
1926
1927 fail:
1928         free(c);
1929         bus_node_gc(bus, n);
1930         return r;
1931 }
1932
1933 _public_ int sd_bus_remove_node_enumerator(
1934                 sd_bus *bus,
1935                 const char *path,
1936                 sd_bus_node_enumerator_t callback,
1937                 void *userdata) {
1938
1939         struct node_enumerator *c;
1940         struct node *n;
1941
1942         assert_return(bus, -EINVAL);
1943         assert_return(object_path_is_valid(path), -EINVAL);
1944         assert_return(callback, -EINVAL);
1945         assert_return(!bus_pid_changed(bus), -ECHILD);
1946
1947         n = hashmap_get(bus->nodes, path);
1948         if (!n)
1949                 return 0;
1950
1951         LIST_FOREACH(enumerators, c, n->enumerators)
1952                 if (c->callback == callback && c->userdata == userdata)
1953                         break;
1954
1955         if (!c)
1956                 return 0;
1957
1958         LIST_REMOVE(enumerators, n->enumerators, c);
1959         free(c);
1960
1961         bus_node_gc(bus, n);
1962
1963         bus->nodes_modified = true;
1964
1965         return 1;
1966 }
1967
1968 static int emit_properties_changed_on_interface(
1969                 sd_bus *bus,
1970                 const char *prefix,
1971                 const char *path,
1972                 const char *interface,
1973                 bool require_fallback,
1974                 char **names) {
1975
1976         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1977         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1978         bool has_invalidating = false, has_changing = false;
1979         struct vtable_member key = {};
1980         struct node_vtable *c;
1981         struct node *n;
1982         char **property;
1983         void *u = NULL;
1984         int r;
1985
1986         assert(bus);
1987         assert(prefix);
1988         assert(path);
1989         assert(interface);
1990
1991         n = hashmap_get(bus->nodes, prefix);
1992         if (!n)
1993                 return 0;
1994
1995         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
1996         if (r < 0)
1997                 return r;
1998
1999         r = sd_bus_message_append(m, "s", interface);
2000         if (r < 0)
2001                 return r;
2002
2003         r = sd_bus_message_open_container(m, 'a', "{sv}");
2004         if (r < 0)
2005                 return r;
2006
2007         key.path = prefix;
2008         key.interface = interface;
2009
2010         LIST_FOREACH(vtables, c, n->vtables) {
2011                 if (require_fallback && !c->is_fallback)
2012                         continue;
2013
2014                 if (!streq(c->interface, interface))
2015                         continue;
2016
2017                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2018                 if (r < 0)
2019                         return r;
2020                 if (bus->nodes_modified)
2021                         return 0;
2022                 if (r == 0)
2023                         continue;
2024
2025                 if (names) {
2026                         /* If the caller specified a list of
2027                          * properties we include exactly those in the
2028                          * PropertiesChanged message */
2029
2030                         STRV_FOREACH(property, names) {
2031                                 struct vtable_member *v;
2032
2033                                 assert_return(member_name_is_valid(*property), -EINVAL);
2034
2035                                 key.member = *property;
2036                                 v = hashmap_get(bus->vtable_properties, &key);
2037                                 if (!v)
2038                                         return -ENOENT;
2039
2040                                 /* If there are two vtables for the same
2041                                  * interface, let's handle this property when
2042                                  * we come to that vtable. */
2043                                 if (c != v->parent)
2044                                         continue;
2045
2046                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
2047                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
2048
2049                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
2050
2051                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2052                                         has_invalidating = true;
2053                                         continue;
2054                                 }
2055
2056                                 has_changing = true;
2057
2058                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
2059                                 if (r < 0)
2060                                         return r;
2061                                 if (bus->nodes_modified)
2062                                         return 0;
2063                         }
2064                 } else {
2065                         const sd_bus_vtable *v;
2066
2067                         /* If the caller specified no properties list
2068                          * we include all properties that are marked
2069                          * as changing in the message. */
2070
2071                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2072                                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2073                                         continue;
2074
2075                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
2076                                         continue;
2077
2078                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
2079                                         has_invalidating = true;
2080                                         continue;
2081                                 }
2082
2083                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
2084                                         continue;
2085
2086                                 has_changing = true;
2087
2088                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
2089                                 if (r < 0)
2090                                         return r;
2091                                 if (bus->nodes_modified)
2092                                         return 0;
2093                         }
2094                 }
2095         }
2096
2097         if (!has_invalidating && !has_changing)
2098                 return 0;
2099
2100         r = sd_bus_message_close_container(m);
2101         if (r < 0)
2102                 return r;
2103
2104         r = sd_bus_message_open_container(m, 'a', "s");
2105         if (r < 0)
2106                 return r;
2107
2108         if (has_invalidating) {
2109                 LIST_FOREACH(vtables, c, n->vtables) {
2110                         if (require_fallback && !c->is_fallback)
2111                                 continue;
2112
2113                         if (!streq(c->interface, interface))
2114                                 continue;
2115
2116                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
2117                         if (r < 0)
2118                                 return r;
2119                         if (bus->nodes_modified)
2120                                 return 0;
2121                         if (r == 0)
2122                                 continue;
2123
2124                         if (names) {
2125                                 STRV_FOREACH(property, names) {
2126                                         struct vtable_member *v;
2127
2128                                         key.member = *property;
2129                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
2130                                         assert(c == v->parent);
2131
2132                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2133                                                 continue;
2134
2135                                         r = sd_bus_message_append(m, "s", *property);
2136                                         if (r < 0)
2137                                                 return r;
2138                                 }
2139                         } else {
2140                                 const sd_bus_vtable *v;
2141
2142                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2143                                         if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2144                                                 continue;
2145
2146                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
2147                                                 continue;
2148
2149                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
2150                                                 continue;
2151
2152                                         r = sd_bus_message_append(m, "s", v->x.property.member);
2153                                         if (r < 0)
2154                                                 return r;
2155                                 }
2156                         }
2157                 }
2158         }
2159
2160         r = sd_bus_message_close_container(m);
2161         if (r < 0)
2162                 return r;
2163
2164         r = sd_bus_send(bus, m, NULL);
2165         if (r < 0)
2166                 return r;
2167
2168         return 1;
2169 }
2170
2171 _public_ int sd_bus_emit_properties_changed_strv(
2172                 sd_bus *bus,
2173                 const char *path,
2174                 const char *interface,
2175                 char **names) {
2176
2177         BUS_DONT_DESTROY(bus);
2178         char *prefix;
2179         int r;
2180
2181         assert_return(bus, -EINVAL);
2182         assert_return(object_path_is_valid(path), -EINVAL);
2183         assert_return(interface_name_is_valid(interface), -EINVAL);
2184         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2185         assert_return(!bus_pid_changed(bus), -ECHILD);
2186
2187
2188         /* A non-NULL but empty names list means nothing needs to be
2189            generated. A NULL list OTOH indicates that all properties
2190            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
2191            included in the PropertiesChanged message. */
2192         if (names && names[0] == NULL)
2193                 return 0;
2194
2195         do {
2196                 bus->nodes_modified = false;
2197
2198                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, names);
2199                 if (r != 0)
2200                         return r;
2201                 if (bus->nodes_modified)
2202                         continue;
2203
2204                 prefix = alloca(strlen(path) + 1);
2205                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2206                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, names);
2207                         if (r != 0)
2208                                 return r;
2209                         if (bus->nodes_modified)
2210                                 break;
2211                 }
2212
2213         } while (bus->nodes_modified);
2214
2215         return -ENOENT;
2216 }
2217
2218 _public_ int sd_bus_emit_properties_changed(
2219                 sd_bus *bus,
2220                 const char *path,
2221                 const char *interface,
2222                 const char *name, ...)  {
2223
2224         char **names;
2225
2226         assert_return(bus, -EINVAL);
2227         assert_return(object_path_is_valid(path), -EINVAL);
2228         assert_return(interface_name_is_valid(interface), -EINVAL);
2229         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2230         assert_return(!bus_pid_changed(bus), -ECHILD);
2231
2232         if (!name)
2233                 return 0;
2234
2235         names = strv_from_stdarg_alloca(name);
2236
2237         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
2238 }
2239
2240 static int interfaces_added_append_one_prefix(
2241                 sd_bus *bus,
2242                 sd_bus_message *m,
2243                 const char *prefix,
2244                 const char *path,
2245                 const char *interface,
2246                 bool require_fallback) {
2247
2248         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2249         bool found_interface = false;
2250         struct node_vtable *c;
2251         struct node *n;
2252         void *u = NULL;
2253         int r;
2254
2255         assert(bus);
2256         assert(m);
2257         assert(prefix);
2258         assert(path);
2259         assert(interface);
2260
2261         n = hashmap_get(bus->nodes, prefix);
2262         if (!n)
2263                 return 0;
2264
2265         LIST_FOREACH(vtables, c, n->vtables) {
2266                 if (require_fallback && !c->is_fallback)
2267                         continue;
2268
2269                 if (!streq(c->interface, interface))
2270                         continue;
2271
2272                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
2273                 if (r < 0)
2274                         return r;
2275                 if (bus->nodes_modified)
2276                         return 0;
2277                 if (r == 0)
2278                         continue;
2279
2280                 if (!found_interface) {
2281                         r = sd_bus_message_append_basic(m, 's', interface);
2282                         if (r < 0)
2283                                 return r;
2284
2285                         r = sd_bus_message_open_container(m, 'a', "{sv}");
2286                         if (r < 0)
2287                                 return r;
2288
2289                         found_interface = true;
2290                 }
2291
2292                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
2293                 if (r < 0)
2294                         return r;
2295                 if (bus->nodes_modified)
2296                         return 0;
2297         }
2298
2299         if (found_interface) {
2300                 r = sd_bus_message_close_container(m);
2301                 if (r < 0)
2302                         return r;
2303         }
2304
2305         return found_interface;
2306 }
2307
2308 static int interfaces_added_append_one(
2309                 sd_bus *bus,
2310                 sd_bus_message *m,
2311                 const char *path,
2312                 const char *interface) {
2313
2314         char *prefix;
2315         int r;
2316
2317         assert(bus);
2318         assert(m);
2319         assert(path);
2320         assert(interface);
2321
2322         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
2323         if (r != 0)
2324                 return r;
2325         if (bus->nodes_modified)
2326                 return 0;
2327
2328         prefix = alloca(strlen(path) + 1);
2329         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
2330                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
2331                 if (r != 0)
2332                         return r;
2333                 if (bus->nodes_modified)
2334                         return 0;
2335         }
2336
2337         return -ENOENT;
2338 }
2339
2340 _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
2341         BUS_DONT_DESTROY(bus);
2342
2343         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2344         char **i;
2345         int r;
2346
2347         assert_return(bus, -EINVAL);
2348         assert_return(object_path_is_valid(path), -EINVAL);
2349         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2350         assert_return(!bus_pid_changed(bus), -ECHILD);
2351
2352         if (strv_isempty(interfaces))
2353                 return 0;
2354
2355         do {
2356                 bus->nodes_modified = false;
2357
2358                 if (m)
2359                         m = sd_bus_message_unref(m);
2360
2361                 r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
2362                 if (r < 0)
2363                         return r;
2364
2365                 r = sd_bus_message_append_basic(m, 'o', path);
2366                 if (r < 0)
2367                         return r;
2368
2369                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
2370                 if (r < 0)
2371                         return r;
2372
2373                 STRV_FOREACH(i, interfaces) {
2374                         assert_return(interface_name_is_valid(*i), -EINVAL);
2375
2376                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
2377                         if (r < 0)
2378                                 return r;
2379
2380                         r = interfaces_added_append_one(bus, m, path, *i);
2381                         if (r < 0)
2382                                 return r;
2383
2384                         if (bus->nodes_modified)
2385                                 break;
2386
2387                         r = sd_bus_message_close_container(m);
2388                         if (r < 0)
2389                                 return r;
2390                 }
2391
2392                 if (bus->nodes_modified)
2393                         continue;
2394
2395                 r = sd_bus_message_close_container(m);
2396                 if (r < 0)
2397                         return r;
2398
2399         } while (bus->nodes_modified);
2400
2401         return sd_bus_send(bus, m, NULL);
2402 }
2403
2404 _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
2405         char **interfaces;
2406
2407         assert_return(bus, -EINVAL);
2408         assert_return(object_path_is_valid(path), -EINVAL);
2409         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2410         assert_return(!bus_pid_changed(bus), -ECHILD);
2411
2412         interfaces = strv_from_stdarg_alloca(interface);
2413
2414         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
2415 }
2416
2417 _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
2418         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
2419         int r;
2420
2421         assert_return(bus, -EINVAL);
2422         assert_return(object_path_is_valid(path), -EINVAL);
2423         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2424         assert_return(!bus_pid_changed(bus), -ECHILD);
2425
2426         if (strv_isempty(interfaces))
2427                 return 0;
2428
2429         r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
2430         if (r < 0)
2431                 return r;
2432
2433         r = sd_bus_message_append_basic(m, 'o', path);
2434         if (r < 0)
2435                 return r;
2436
2437         r = sd_bus_message_append_strv(m, interfaces);
2438         if (r < 0)
2439                 return r;
2440
2441         return sd_bus_send(bus, m, NULL);
2442 }
2443
2444 _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
2445         char **interfaces;
2446
2447         assert_return(bus, -EINVAL);
2448         assert_return(object_path_is_valid(path), -EINVAL);
2449         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
2450         assert_return(!bus_pid_changed(bus), -ECHILD);
2451
2452         interfaces = strv_from_stdarg_alloca(interface);
2453
2454         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
2455 }
2456
2457 _public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
2458         struct node *n;
2459
2460         assert_return(bus, -EINVAL);
2461         assert_return(object_path_is_valid(path), -EINVAL);
2462         assert_return(!bus_pid_changed(bus), -ECHILD);
2463
2464         n = bus_node_allocate(bus, path);
2465         if (!n)
2466                 return -ENOMEM;
2467
2468         n->object_manager = true;
2469         bus->nodes_modified = true;
2470         return 0;
2471 }
2472
2473 _public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
2474         struct node *n;
2475
2476         assert_return(bus, -EINVAL);
2477         assert_return(object_path_is_valid(path), -EINVAL);
2478         assert_return(!bus_pid_changed(bus), -ECHILD);
2479
2480         n = hashmap_get(bus->nodes, path);
2481         if (!n)
2482                 return 0;
2483
2484         if (!n->object_manager)
2485                 return 0;
2486
2487         n->object_manager = false;
2488         bus->nodes_modified = true;
2489         bus_node_gc(bus, n);
2490
2491         return 1;
2492 }