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