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