]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/sd-bus.c
bus: if a a Set() vtable callback of a writable is left NULL, try to do the right...
[thirdparty/systemd.git] / src / libsystemd-bus / sd-bus.c
CommitLineData
de1c301e
LP
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 <endian.h>
23#include <assert.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <netdb.h>
27#include <sys/poll.h>
28#include <byteswap.h>
63edf05e 29#include <sys/mman.h>
45fbe937 30#include <pthread.h>
de1c301e
LP
31
32#include "util.h"
33#include "macro.h"
2fd9ae2e 34#include "strv.h"
0a72c2bd 35#include "set.h"
6c03089c 36#include "missing.h"
de1c301e
LP
37
38#include "sd-bus.h"
39#include "bus-internal.h"
40#include "bus-message.h"
41#include "bus-type.h"
a7e3212d 42#include "bus-socket.h"
6629161f 43#include "bus-kernel.h"
392d5b37 44#include "bus-control.h"
29ddb38f
LP
45#include "bus-introspect.h"
46#include "bus-signature.h"
de1c301e 47
e3017af9
LP
48static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
49
f54514f3
LP
50static void bus_close_fds(sd_bus *b) {
51 assert(b);
52
53 if (b->input_fd >= 0)
54 close_nointr_nofail(b->input_fd);
55
56 if (b->output_fd >= 0 && b->output_fd != b->input_fd)
57 close_nointr_nofail(b->output_fd);
58
59 b->input_fd = b->output_fd = -1;
60}
61
29ddb38f
LP
62static void bus_node_destroy(sd_bus *b, struct node *n) {
63 struct node_callback *c;
64 struct node_vtable *v;
65 struct node_enumerator *e;
66
67 assert(b);
68
69 if (!n)
70 return;
71
72 while (n->child)
73 bus_node_destroy(b, n->child);
74
75 while ((c = n->callbacks)) {
76 LIST_REMOVE(struct node_callback, callbacks, n->callbacks, c);
77 free(c);
78 }
79
80 while ((v = n->vtables)) {
81 LIST_REMOVE(struct node_vtable, vtables, n->vtables, v);
82 free(v->interface);
83 free(v);
84 }
85
86 while ((e = n->enumerators)) {
87 LIST_REMOVE(struct node_enumerator, enumerators, n->enumerators, e);
88 free(e);
89 }
90
91 if (n->parent)
92 LIST_REMOVE(struct node, siblings, n->parent->child, n);
93
94 assert_se(hashmap_remove(b->nodes, n->path) == n);
95 free(n->path);
96 free(n);
97}
98
de1c301e
LP
99static void bus_free(sd_bus *b) {
100 struct filter_callback *f;
29ddb38f 101 struct node *n;
89ffcd2a 102 unsigned i;
de1c301e
LP
103
104 assert(b);
105
f54514f3 106 bus_close_fds(b);
de1c301e 107
63edf05e
LP
108 if (b->kdbus_buffer)
109 munmap(b->kdbus_buffer, KDBUS_POOL_SIZE);
110
de1c301e 111 free(b->rbuffer);
89ffcd2a 112 free(b->unique_name);
2181a7f5 113 free(b->auth_buffer);
89ffcd2a 114 free(b->address);
e9a967f9 115 free(b->kernel);
89ffcd2a 116
2fd9ae2e
LP
117 free(b->exec_path);
118 strv_free(b->exec_argv);
119
2c93b4ef
LP
120 close_many(b->fds, b->n_fds);
121 free(b->fds);
122
89ffcd2a
LP
123 for (i = 0; i < b->rqueue_size; i++)
124 sd_bus_message_unref(b->rqueue[i]);
de1c301e 125 free(b->rqueue);
89ffcd2a
LP
126
127 for (i = 0; i < b->wqueue_size; i++)
128 sd_bus_message_unref(b->wqueue[i]);
de1c301e 129 free(b->wqueue);
de1c301e
LP
130
131 hashmap_free_free(b->reply_callbacks);
e3017af9 132 prioq_free(b->reply_callbacks_prioq);
de1c301e
LP
133
134 while ((f = b->filter_callbacks)) {
135 LIST_REMOVE(struct filter_callback, callbacks, b->filter_callbacks, f);
136 free(f);
137 }
138
392d5b37
LP
139 bus_match_free(&b->match_callbacks);
140
29ddb38f
LP
141 hashmap_free_free(b->vtable_methods);
142 hashmap_free_free(b->vtable_properties);
143
144 while ((n = hashmap_first(b->nodes)))
145 bus_node_destroy(b, n);
146
147 hashmap_free(b->nodes);
148
bc7fd8cd
LP
149 bus_kernel_flush_memfd(b);
150
45fbe937
LP
151 assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0);
152
de1c301e
LP
153 free(b);
154}
155
021a1e78 156int sd_bus_new(sd_bus **ret) {
de1c301e
LP
157 sd_bus *r;
158
021a1e78
LP
159 if (!ret)
160 return -EINVAL;
161
de1c301e
LP
162 r = new0(sd_bus, 1);
163 if (!r)
021a1e78 164 return -ENOMEM;
de1c301e 165
e4ee6e5c 166 r->n_ref = REFCNT_INIT;
e82c9509 167 r->input_fd = r->output_fd = -1;
de1c301e 168 r->message_version = 1;
264ad849 169 r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
d5a2b9a6 170 r->original_pid = getpid();
de1c301e 171
45fbe937
LP
172 assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0);
173
de1c301e
LP
174 /* We guarantee that wqueue always has space for at least one
175 * entry */
176 r->wqueue = new(sd_bus_message*, 1);
177 if (!r->wqueue) {
178 free(r);
021a1e78 179 return -ENOMEM;
de1c301e
LP
180 }
181
021a1e78
LP
182 *ret = r;
183 return 0;
184}
185
186int sd_bus_set_address(sd_bus *bus, const char *address) {
187 char *a;
188
189 if (!bus)
190 return -EINVAL;
191 if (bus->state != BUS_UNSET)
192 return -EPERM;
193 if (!address)
194 return -EINVAL;
d5a2b9a6
LP
195 if (bus_pid_changed(bus))
196 return -ECHILD;
021a1e78
LP
197
198 a = strdup(address);
199 if (!a)
200 return -ENOMEM;
201
202 free(bus->address);
203 bus->address = a;
204
205 return 0;
206}
207
e82c9509 208int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
021a1e78
LP
209 if (!bus)
210 return -EINVAL;
211 if (bus->state != BUS_UNSET)
212 return -EPERM;
e82c9509
LP
213 if (input_fd < 0)
214 return -EINVAL;
215 if (output_fd < 0)
021a1e78 216 return -EINVAL;
d5a2b9a6
LP
217 if (bus_pid_changed(bus))
218 return -ECHILD;
021a1e78 219
e82c9509
LP
220 bus->input_fd = input_fd;
221 bus->output_fd = output_fd;
021a1e78
LP
222 return 0;
223}
224
2fd9ae2e
LP
225int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
226 char *p, **a;
227
228 if (!bus)
229 return -EINVAL;
230 if (bus->state != BUS_UNSET)
231 return -EPERM;
232 if (!path)
233 return -EINVAL;
234 if (strv_isempty(argv))
235 return -EINVAL;
d5a2b9a6
LP
236 if (bus_pid_changed(bus))
237 return -ECHILD;
2fd9ae2e
LP
238
239 p = strdup(path);
240 if (!p)
241 return -ENOMEM;
242
243 a = strv_copy(argv);
244 if (!a) {
245 free(p);
246 return -ENOMEM;
247 }
248
249 free(bus->exec_path);
250 strv_free(bus->exec_argv);
251
252 bus->exec_path = p;
253 bus->exec_argv = a;
254
255 return 0;
256}
257
94bbf1ba 258int sd_bus_set_bus_client(sd_bus *bus, int b) {
021a1e78
LP
259 if (!bus)
260 return -EINVAL;
261 if (bus->state != BUS_UNSET)
262 return -EPERM;
d5a2b9a6
LP
263 if (bus_pid_changed(bus))
264 return -ECHILD;
021a1e78 265
94bbf1ba 266 bus->bus_client = !!b;
021a1e78
LP
267 return 0;
268}
269
264ad849 270int sd_bus_negotiate_fds(sd_bus *bus, int b) {
021a1e78
LP
271 if (!bus)
272 return -EINVAL;
273 if (bus->state != BUS_UNSET)
274 return -EPERM;
d5a2b9a6
LP
275 if (bus_pid_changed(bus))
276 return -ECHILD;
021a1e78 277
264ad849
LP
278 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b);
279 return 0;
280}
281
282int sd_bus_negotiate_attach_comm(sd_bus *bus, int b) {
283 if (!bus)
284 return -EINVAL;
285 if (bus->state != BUS_UNSET)
286 return -EPERM;
287 if (bus_pid_changed(bus))
288 return -ECHILD;
289
290 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_COMM, b);
291 return 0;
292}
293
294int sd_bus_negotiate_attach_exe(sd_bus *bus, int b) {
295 if (!bus)
296 return -EINVAL;
297 if (bus->state != BUS_UNSET)
298 return -EPERM;
299 if (bus_pid_changed(bus))
300 return -ECHILD;
301
302 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_EXE, b);
303 return 0;
304}
305
306int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b) {
307 if (!bus)
308 return -EINVAL;
309 if (bus->state != BUS_UNSET)
310 return -EPERM;
311 if (bus_pid_changed(bus))
312 return -ECHILD;
313
314 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CMDLINE, b);
315 return 0;
316}
317
318int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b) {
319 if (!bus)
320 return -EINVAL;
321 if (bus->state != BUS_UNSET)
322 return -EPERM;
323 if (bus_pid_changed(bus))
324 return -ECHILD;
325
326 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CGROUP, b);
327 return 0;
328}
329
330int sd_bus_negotiate_attach_caps(sd_bus *bus, int b) {
331 if (!bus)
332 return -EINVAL;
333 if (bus->state != BUS_UNSET)
334 return -EPERM;
335 if (bus_pid_changed(bus))
336 return -ECHILD;
337
338 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CAPS, b);
339 return 0;
340}
341
342int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b) {
343 if (!bus)
344 return -EINVAL;
345 if (bus->state != BUS_UNSET)
346 return -EPERM;
347 if (bus_pid_changed(bus))
348 return -ECHILD;
349
350 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_SECLABEL, b);
351 return 0;
352}
353
354int sd_bus_negotiate_attach_audit(sd_bus *bus, int b) {
355 if (!bus)
356 return -EINVAL;
357 if (bus->state != BUS_UNSET)
358 return -EPERM;
359 if (bus_pid_changed(bus))
360 return -ECHILD;
361
362 SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_AUDIT, b);
021a1e78
LP
363 return 0;
364}
de1c301e 365
98178d39 366int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
2181a7f5
LP
367 if (!bus)
368 return -EINVAL;
98178d39 369 if (!b && !sd_id128_equal(server_id, SD_ID128_NULL))
2181a7f5
LP
370 return -EINVAL;
371 if (bus->state != BUS_UNSET)
372 return -EPERM;
d5a2b9a6
LP
373 if (bus_pid_changed(bus))
374 return -ECHILD;
2181a7f5
LP
375
376 bus->is_server = !!b;
98178d39 377 bus->server_id = server_id;
2181a7f5
LP
378 return 0;
379}
380
381int sd_bus_set_anonymous(sd_bus *bus, int b) {
382 if (!bus)
383 return -EINVAL;
384 if (bus->state != BUS_UNSET)
385 return -EPERM;
d5a2b9a6
LP
386 if (bus_pid_changed(bus))
387 return -ECHILD;
2181a7f5
LP
388
389 bus->anonymous_auth = !!b;
390 return 0;
391}
392
eb01ba5d 393static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
de1c301e
LP
394 const char *s;
395 int r;
396
397 assert(bus);
021a1e78 398 assert(bus->state == BUS_HELLO);
de1c301e
LP
399 assert(reply);
400
eb01ba5d
LP
401 r = bus_message_to_errno(reply);
402 if (r < 0)
403 return r;
404
de1c301e
LP
405 r = sd_bus_message_read(reply, "s", &s);
406 if (r < 0)
407 return r;
408
dafb7591
LP
409 if (!service_name_is_valid(s) || s[0] != ':')
410 return -EBADMSG;
411
de1c301e
LP
412 bus->unique_name = strdup(s);
413 if (!bus->unique_name)
414 return -ENOMEM;
415
dafb7591
LP
416 bus->state = BUS_RUNNING;
417
de1c301e
LP
418 return 1;
419}
420
421static int bus_send_hello(sd_bus *bus) {
422 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
423 int r;
424
425 assert(bus);
426
6629161f 427 if (!bus->bus_client || bus->is_kernel)
021a1e78
LP
428 return 0;
429
de1c301e
LP
430 r = sd_bus_message_new_method_call(
431 bus,
432 "org.freedesktop.DBus",
433 "/",
434 "org.freedesktop.DBus",
435 "Hello",
436 &m);
437 if (r < 0)
438 return r;
439
9d373862 440 return sd_bus_send_with_reply(bus, m, hello_callback, NULL, 0, &bus->hello_serial);
de1c301e
LP
441}
442
a7e3212d 443int bus_start_running(sd_bus *bus) {
de1c301e
LP
444 assert(bus);
445
f08838da 446 if (bus->bus_client && !bus->is_kernel) {
de1c301e 447 bus->state = BUS_HELLO;
e3017af9 448 return 1;
de1c301e
LP
449 }
450
451 bus->state = BUS_RUNNING;
e3017af9 452 return 1;
de1c301e
LP
453}
454
455static int parse_address_key(const char **p, const char *key, char **value) {
456 size_t l, n = 0;
457 const char *a;
458 char *r = NULL;
459
460 assert(p);
461 assert(*p);
de1c301e
LP
462 assert(value);
463
2fd9ae2e
LP
464 if (key) {
465 l = strlen(key);
466 if (strncmp(*p, key, l) != 0)
467 return 0;
de1c301e 468
2fd9ae2e
LP
469 if ((*p)[l] != '=')
470 return 0;
de1c301e 471
2fd9ae2e
LP
472 if (*value)
473 return -EINVAL;
de1c301e 474
2fd9ae2e
LP
475 a = *p + l + 1;
476 } else
477 a = *p;
478
479 while (*a != ';' && *a != ',' && *a != 0) {
de1c301e
LP
480 char c, *t;
481
482 if (*a == '%') {
483 int x, y;
484
485 x = unhexchar(a[1]);
486 if (x < 0) {
487 free(r);
488 return x;
489 }
490
491 y = unhexchar(a[2]);
492 if (y < 0) {
493 free(r);
494 return y;
495 }
496
de1c301e 497 c = (char) ((x << 4) | y);
89ffcd2a
LP
498 a += 3;
499 } else {
de1c301e 500 c = *a;
89ffcd2a
LP
501 a++;
502 }
de1c301e 503
89ffcd2a 504 t = realloc(r, n + 2);
de1c301e
LP
505 if (!t) {
506 free(r);
507 return -ENOMEM;
508 }
509
510 r = t;
511 r[n++] = c;
512 }
513
89ffcd2a
LP
514 if (!r) {
515 r = strdup("");
516 if (!r)
517 return -ENOMEM;
518 } else
519 r[n] = 0;
520
521 if (*a == ',')
522 a++;
523
de1c301e 524 *p = a;
2fd9ae2e
LP
525
526 free(*value);
de1c301e 527 *value = r;
2fd9ae2e 528
de1c301e
LP
529 return 1;
530}
531
532static void skip_address_key(const char **p) {
533 assert(p);
534 assert(*p);
535
89ffcd2a
LP
536 *p += strcspn(*p, ",");
537
538 if (**p == ',')
539 (*p) ++;
de1c301e
LP
540}
541
2fd9ae2e
LP
542static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
543 _cleanup_free_ char *path = NULL, *abstract = NULL;
544 size_t l;
de1c301e
LP
545 int r;
546
547 assert(b);
2fd9ae2e
LP
548 assert(p);
549 assert(*p);
550 assert(guid);
de1c301e 551
2fd9ae2e
LP
552 while (**p != 0 && **p != ';') {
553 r = parse_address_key(p, "guid", guid);
554 if (r < 0)
555 return r;
556 else if (r > 0)
557 continue;
de1c301e 558
2fd9ae2e
LP
559 r = parse_address_key(p, "path", &path);
560 if (r < 0)
561 return r;
562 else if (r > 0)
563 continue;
de1c301e 564
2fd9ae2e
LP
565 r = parse_address_key(p, "abstract", &abstract);
566 if (r < 0)
567 return r;
568 else if (r > 0)
569 continue;
de1c301e 570
2fd9ae2e
LP
571 skip_address_key(p);
572 }
de1c301e 573
2fd9ae2e
LP
574 if (!path && !abstract)
575 return -EINVAL;
de1c301e 576
2fd9ae2e
LP
577 if (path && abstract)
578 return -EINVAL;
579
580 if (path) {
581 l = strlen(path);
582 if (l > sizeof(b->sockaddr.un.sun_path))
583 return -E2BIG;
de1c301e 584
2fd9ae2e
LP
585 b->sockaddr.un.sun_family = AF_UNIX;
586 strncpy(b->sockaddr.un.sun_path, path, sizeof(b->sockaddr.un.sun_path));
587 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l;
588 } else if (abstract) {
589 l = strlen(abstract);
590 if (l > sizeof(b->sockaddr.un.sun_path) - 1)
591 return -E2BIG;
592
593 b->sockaddr.un.sun_family = AF_UNIX;
594 b->sockaddr.un.sun_path[0] = 0;
595 strncpy(b->sockaddr.un.sun_path+1, abstract, sizeof(b->sockaddr.un.sun_path)-1);
596 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
597 }
598
599 return 0;
600}
601
602static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
603 _cleanup_free_ char *host = NULL, *port = NULL, *family = NULL;
2fd9ae2e 604 int r;
b92bea5d
ZJS
605 struct addrinfo *result, hints = {
606 .ai_socktype = SOCK_STREAM,
607 .ai_flags = AI_ADDRCONFIG,
608 };
2fd9ae2e
LP
609
610 assert(b);
611 assert(p);
612 assert(*p);
613 assert(guid);
614
615 while (**p != 0 && **p != ';') {
616 r = parse_address_key(p, "guid", guid);
617 if (r < 0)
618 return r;
619 else if (r > 0)
620 continue;
621
622 r = parse_address_key(p, "host", &host);
623 if (r < 0)
624 return r;
625 else if (r > 0)
626 continue;
627
628 r = parse_address_key(p, "port", &port);
629 if (r < 0)
630 return r;
631 else if (r > 0)
632 continue;
633
634 r = parse_address_key(p, "family", &family);
635 if (r < 0)
636 return r;
637 else if (r > 0)
638 continue;
639
640 skip_address_key(p);
641 }
642
643 if (!host || !port)
644 return -EINVAL;
645
2fd9ae2e
LP
646 if (family) {
647 if (streq(family, "ipv4"))
648 hints.ai_family = AF_INET;
649 else if (streq(family, "ipv6"))
650 hints.ai_family = AF_INET6;
651 else
652 return -EINVAL;
653 }
654
655 r = getaddrinfo(host, port, &hints, &result);
656 if (r == EAI_SYSTEM)
657 return -errno;
658 else if (r != 0)
659 return -EADDRNOTAVAIL;
660
661 memcpy(&b->sockaddr, result->ai_addr, result->ai_addrlen);
662 b->sockaddr_size = result->ai_addrlen;
663
664 freeaddrinfo(result);
665
666 return 0;
667}
668
669static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
670 char *path = NULL;
671 unsigned n_argv = 0, j;
672 char **argv = NULL;
673 int r;
674
675 assert(b);
676 assert(p);
677 assert(*p);
678 assert(guid);
679
680 while (**p != 0 && **p != ';') {
681 r = parse_address_key(p, "guid", guid);
682 if (r < 0)
683 goto fail;
684 else if (r > 0)
685 continue;
686
687 r = parse_address_key(p, "path", &path);
688 if (r < 0)
689 goto fail;
690 else if (r > 0)
691 continue;
692
693 if (startswith(*p, "argv")) {
694 unsigned ul;
695
696 errno = 0;
697 ul = strtoul(*p + 4, (char**) p, 10);
8333c77e 698 if (errno > 0 || **p != '=' || ul > 256) {
2fd9ae2e
LP
699 r = -EINVAL;
700 goto fail;
701 }
702
703 (*p) ++;
704
705 if (ul >= n_argv) {
706 char **x;
707
708 x = realloc(argv, sizeof(char*) * (ul + 2));
709 if (!x) {
710 r = -ENOMEM;
711 goto fail;
712 }
713
714 memset(x + n_argv, 0, sizeof(char*) * (ul - n_argv + 2));
715
716 argv = x;
717 n_argv = ul + 1;
718 }
719
720 r = parse_address_key(p, NULL, argv + ul);
de1c301e 721 if (r < 0)
2fd9ae2e 722 goto fail;
de1c301e 723
2fd9ae2e 724 continue;
de1c301e
LP
725 }
726
2fd9ae2e
LP
727 skip_address_key(p);
728 }
de1c301e 729
5a0f6033
LP
730 if (!path) {
731 r = -EINVAL;
2fd9ae2e 732 goto fail;
5a0f6033 733 }
de1c301e 734
2fd9ae2e
LP
735 /* Make sure there are no holes in the array, with the
736 * exception of argv[0] */
737 for (j = 1; j < n_argv; j++)
738 if (!argv[j]) {
739 r = -EINVAL;
740 goto fail;
741 }
742
743 if (argv && argv[0] == NULL) {
744 argv[0] = strdup(path);
745 if (!argv[0]) {
746 r = -ENOMEM;
747 goto fail;
748 }
749 }
de1c301e 750
2fd9ae2e
LP
751 b->exec_path = path;
752 b->exec_argv = argv;
753 return 0;
de1c301e 754
2fd9ae2e
LP
755fail:
756 for (j = 0; j < n_argv; j++)
757 free(argv[j]);
758
759 free(argv);
760 free(path);
761 return r;
762}
763
6629161f
LP
764static int parse_kernel_address(sd_bus *b, const char **p, char **guid) {
765 _cleanup_free_ char *path = NULL;
766 int r;
767
768 assert(b);
769 assert(p);
770 assert(*p);
771 assert(guid);
772
773 while (**p != 0 && **p != ';') {
774 r = parse_address_key(p, "guid", guid);
775 if (r < 0)
776 return r;
777 else if (r > 0)
778 continue;
779
780 r = parse_address_key(p, "path", &path);
781 if (r < 0)
782 return r;
783 else if (r > 0)
784 continue;
785
786 skip_address_key(p);
787 }
788
789 if (!path)
790 return -EINVAL;
791
792 free(b->kernel);
793 b->kernel = path;
794 path = NULL;
795
796 return 0;
797}
798
2fd9ae2e
LP
799static void bus_reset_parsed_address(sd_bus *b) {
800 assert(b);
801
802 zero(b->sockaddr);
803 b->sockaddr_size = 0;
804 strv_free(b->exec_argv);
805 free(b->exec_path);
806 b->exec_path = NULL;
807 b->exec_argv = NULL;
98178d39 808 b->server_id = SD_ID128_NULL;
6629161f
LP
809 free(b->kernel);
810 b->kernel = NULL;
2fd9ae2e
LP
811}
812
813static int bus_parse_next_address(sd_bus *b) {
814 _cleanup_free_ char *guid = NULL;
815 const char *a;
816 int r;
817
818 assert(b);
819
820 if (!b->address)
821 return 0;
822 if (b->address[b->address_index] == 0)
823 return 0;
824
825 bus_reset_parsed_address(b);
826
827 a = b->address + b->address_index;
de1c301e 828
2fd9ae2e 829 while (*a != 0) {
de1c301e 830
2fd9ae2e
LP
831 if (*a == ';') {
832 a++;
833 continue;
de1c301e
LP
834 }
835
2fd9ae2e
LP
836 if (startswith(a, "unix:")) {
837 a += 5;
de1c301e 838
2fd9ae2e 839 r = parse_unix_address(b, &a, &guid);
de1c301e
LP
840 if (r < 0)
841 return r;
2fd9ae2e 842 break;
de1c301e 843
2fd9ae2e 844 } else if (startswith(a, "tcp:")) {
de1c301e 845
2fd9ae2e
LP
846 a += 4;
847 r = parse_tcp_address(b, &a, &guid);
de1c301e
LP
848 if (r < 0)
849 return r;
de1c301e 850
2fd9ae2e
LP
851 break;
852
853 } else if (startswith(a, "unixexec:")) {
854
855 a += 9;
856 r = parse_exec_address(b, &a, &guid);
de1c301e
LP
857 if (r < 0)
858 return r;
de1c301e 859
2fd9ae2e 860 break;
de1c301e 861
6629161f
LP
862 } else if (startswith(a, "kernel:")) {
863
864 a += 7;
865 r = parse_kernel_address(b, &a, &guid);
866 if (r < 0)
867 return r;
868
869 break;
de1c301e
LP
870 }
871
2fd9ae2e
LP
872 a = strchr(a, ';');
873 if (!a)
874 return 0;
de1c301e
LP
875 }
876
877 if (guid) {
98178d39 878 r = sd_id128_from_string(guid, &b->server_id);
de1c301e
LP
879 if (r < 0)
880 return r;
881 }
882
2fd9ae2e 883 b->address_index = a - b->address;
de1c301e
LP
884 return 1;
885}
886
a7e3212d 887static int bus_start_address(sd_bus *b) {
2fd9ae2e
LP
888 int r;
889
890 assert(b);
891
892 for (;;) {
e82c9509 893 sd_bus_close(b);
2fd9ae2e
LP
894
895 if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
a7e3212d
LP
896
897 r = bus_socket_connect(b);
2fd9ae2e
LP
898 if (r >= 0)
899 return r;
900
901 b->last_connect_error = -r;
902
903 } else if (b->exec_path) {
904
a7e3212d 905 r = bus_socket_exec(b);
2fd9ae2e
LP
906 if (r >= 0)
907 return r;
908
6629161f
LP
909 b->last_connect_error = -r;
910 } else if (b->kernel) {
911
912 r = bus_kernel_connect(b);
913 if (r >= 0)
914 return r;
915
2fd9ae2e
LP
916 b->last_connect_error = -r;
917 }
918
919 r = bus_parse_next_address(b);
920 if (r < 0)
921 return r;
922 if (r == 0)
923 return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED;
de1c301e
LP
924 }
925}
926
a7e3212d
LP
927int bus_next_address(sd_bus *b) {
928 assert(b);
929
930 bus_reset_parsed_address(b);
931 return bus_start_address(b);
932}
933
021a1e78 934static int bus_start_fd(sd_bus *b) {
6629161f 935 struct stat st;
021a1e78
LP
936 int r;
937
938 assert(b);
e82c9509
LP
939 assert(b->input_fd >= 0);
940 assert(b->output_fd >= 0);
021a1e78 941
e82c9509 942 r = fd_nonblock(b->input_fd, true);
021a1e78
LP
943 if (r < 0)
944 return r;
945
e82c9509 946 r = fd_cloexec(b->input_fd, true);
021a1e78
LP
947 if (r < 0)
948 return r;
949
e82c9509
LP
950 if (b->input_fd != b->output_fd) {
951 r = fd_nonblock(b->output_fd, true);
952 if (r < 0)
953 return r;
954
955 r = fd_cloexec(b->output_fd, true);
956 if (r < 0)
957 return r;
958 }
959
6629161f
LP
960 if (fstat(b->input_fd, &st) < 0)
961 return -errno;
962
963 if (S_ISCHR(b->input_fd))
964 return bus_kernel_take_fd(b);
965 else
966 return bus_socket_take_fd(b);
021a1e78
LP
967}
968
969int sd_bus_start(sd_bus *bus) {
970 int r;
971
972 if (!bus)
973 return -EINVAL;
974 if (bus->state != BUS_UNSET)
975 return -EPERM;
d5a2b9a6
LP
976 if (bus_pid_changed(bus))
977 return -ECHILD;
021a1e78
LP
978
979 bus->state = BUS_OPENING;
980
2181a7f5
LP
981 if (bus->is_server && bus->bus_client)
982 return -EINVAL;
983
e82c9509 984 if (bus->input_fd >= 0)
021a1e78 985 r = bus_start_fd(bus);
6629161f 986 else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel)
a7e3212d 987 r = bus_start_address(bus);
021a1e78
LP
988 else
989 return -EINVAL;
990
991 if (r < 0)
992 return r;
993
994 return bus_send_hello(bus);
995}
996
de1c301e
LP
997int sd_bus_open_system(sd_bus **ret) {
998 const char *e;
999 sd_bus *b;
1000 int r;
1001
1002 if (!ret)
1003 return -EINVAL;
1004
021a1e78
LP
1005 r = sd_bus_new(&b);
1006 if (r < 0)
1007 return r;
1008
6c03089c 1009 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
de1c301e 1010 if (e) {
021a1e78 1011 r = sd_bus_set_address(b, e);
de1c301e 1012 if (r < 0)
021a1e78 1013 goto fail;
89ffcd2a 1014 } else {
89ffcd2a
LP
1015 b->sockaddr.un.sun_family = AF_UNIX;
1016 strncpy(b->sockaddr.un.sun_path, "/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
1017 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/dbus/system_bus_socket") - 1;
89ffcd2a 1018 }
de1c301e 1019
94bbf1ba 1020 b->bus_client = true;
021a1e78
LP
1021
1022 r = sd_bus_start(b);
1023 if (r < 0)
1024 goto fail;
de1c301e
LP
1025
1026 *ret = b;
1027 return 0;
021a1e78
LP
1028
1029fail:
1030 bus_free(b);
1031 return r;
de1c301e
LP
1032}
1033
1034int sd_bus_open_user(sd_bus **ret) {
1035 const char *e;
1036 sd_bus *b;
1037 size_t l;
1038 int r;
1039
1040 if (!ret)
1041 return -EINVAL;
1042
021a1e78
LP
1043 r = sd_bus_new(&b);
1044 if (r < 0)
1045 return r;
1046
6c03089c 1047 e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
de1c301e 1048 if (e) {
021a1e78 1049 r = sd_bus_set_address(b, e);
de1c301e 1050 if (r < 0)
021a1e78 1051 goto fail;
89ffcd2a 1052 } else {
6c03089c 1053 e = secure_getenv("XDG_RUNTIME_DIR");
021a1e78
LP
1054 if (!e) {
1055 r = -ENOENT;
1056 goto fail;
1057 }
de1c301e 1058
89ffcd2a 1059 l = strlen(e);
021a1e78
LP
1060 if (l + 4 > sizeof(b->sockaddr.un.sun_path)) {
1061 r = -E2BIG;
1062 goto fail;
1063 }
de1c301e 1064
89ffcd2a
LP
1065 b->sockaddr.un.sun_family = AF_UNIX;
1066 memcpy(mempcpy(b->sockaddr.un.sun_path, e, l), "/bus", 4);
1067 b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l + 4;
de1c301e
LP
1068 }
1069
94bbf1ba 1070 b->bus_client = true;
de1c301e 1071
021a1e78 1072 r = sd_bus_start(b);
2571ead1
LP
1073 if (r < 0)
1074 goto fail;
de1c301e
LP
1075
1076 *ret = b;
1077 return 0;
2571ead1
LP
1078
1079fail:
021a1e78 1080 bus_free(b);
2571ead1 1081 return r;
de1c301e
LP
1082}
1083
1084void sd_bus_close(sd_bus *bus) {
1085 if (!bus)
1086 return;
d5a2b9a6
LP
1087 if (bus->state == BUS_CLOSED)
1088 return;
1089 if (bus_pid_changed(bus))
f54514f3
LP
1090 return;
1091
1092 bus->state = BUS_CLOSED;
e82c9509 1093
f54514f3
LP
1094 if (!bus->is_kernel)
1095 bus_close_fds(bus);
1096
1097 /* We'll leave the fd open in case this is a kernel bus, since
1098 * there might still be memblocks around that reference this
1099 * bus, and they might need to invoke the
1100 * KDBUS_CMD_MSG_RELEASE ioctl on the fd when they are
1101 * freed. */
de1c301e
LP
1102}
1103
1104sd_bus *sd_bus_ref(sd_bus *bus) {
1105 if (!bus)
1106 return NULL;
1107
e4ee6e5c 1108 assert_se(REFCNT_INC(bus->n_ref) >= 2);
de1c301e 1109
de1c301e
LP
1110 return bus;
1111}
1112
1113sd_bus *sd_bus_unref(sd_bus *bus) {
1114 if (!bus)
1115 return NULL;
1116
e4ee6e5c 1117 if (REFCNT_DEC(bus->n_ref) <= 0)
de1c301e
LP
1118 bus_free(bus);
1119
1120 return NULL;
1121}
1122
e3017af9
LP
1123int sd_bus_is_open(sd_bus *bus) {
1124 if (!bus)
1125 return -EINVAL;
d5a2b9a6
LP
1126 if (bus_pid_changed(bus))
1127 return -ECHILD;
e3017af9 1128
f54514f3 1129 return BUS_IS_OPEN(bus->state);
e3017af9
LP
1130}
1131
d728d708
LP
1132int sd_bus_can_send(sd_bus *bus, char type) {
1133 int r;
1134
de1c301e
LP
1135 if (!bus)
1136 return -EINVAL;
f54514f3 1137 if (bus->state == BUS_UNSET)
021a1e78 1138 return -ENOTCONN;
d5a2b9a6
LP
1139 if (bus_pid_changed(bus))
1140 return -ECHILD;
de1c301e 1141
d728d708 1142 if (type == SD_BUS_TYPE_UNIX_FD) {
264ad849 1143 if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD))
021a1e78
LP
1144 return 0;
1145
20902f3e 1146 r = bus_ensure_running(bus);
d728d708
LP
1147 if (r < 0)
1148 return r;
de1c301e 1149
d728d708
LP
1150 return bus->can_fds;
1151 }
1152
1153 return bus_type_is_valid(type);
de1c301e
LP
1154}
1155
98178d39 1156int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) {
d728d708 1157 int r;
de1c301e
LP
1158
1159 if (!bus)
1160 return -EINVAL;
98178d39 1161 if (!server_id)
d728d708 1162 return -EINVAL;
d5a2b9a6
LP
1163 if (bus_pid_changed(bus))
1164 return -ECHILD;
de1c301e 1165
20902f3e 1166 r = bus_ensure_running(bus);
d728d708
LP
1167 if (r < 0)
1168 return r;
de1c301e 1169
98178d39 1170 *server_id = bus->server_id;
d728d708 1171 return 0;
de1c301e
LP
1172}
1173
1174static int bus_seal_message(sd_bus *b, sd_bus_message *m) {
1175 assert(m);
1176
89ffcd2a
LP
1177 if (m->header->version > b->message_version)
1178 return -EPERM;
1179
de1c301e
LP
1180 if (m->sealed)
1181 return 0;
1182
9a17484d 1183 return bus_message_seal(m, ++b->serial);
de1c301e
LP
1184}
1185
de1c301e 1186static int dispatch_wqueue(sd_bus *bus) {
e3017af9 1187 int r, ret = 0;
de1c301e
LP
1188
1189 assert(bus);
89ffcd2a 1190 assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
de1c301e 1191
de1c301e
LP
1192 while (bus->wqueue_size > 0) {
1193
6629161f
LP
1194 if (bus->is_kernel)
1195 r = bus_kernel_write_message(bus, bus->wqueue[0]);
1196 else
1197 r = bus_socket_write_message(bus, bus->wqueue[0], &bus->windex);
1198
de1c301e
LP
1199 if (r < 0) {
1200 sd_bus_close(bus);
1201 return r;
1202 } else if (r == 0)
e3017af9
LP
1203 /* Didn't do anything this time */
1204 return ret;
6629161f 1205 else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
de1c301e
LP
1206 /* Fully written. Let's drop the entry from
1207 * the queue.
1208 *
1209 * This isn't particularly optimized, but
1210 * well, this is supposed to be our worst-case
1211 * buffer only, and the socket buffer is
1212 * supposed to be our primary buffer, and if
1213 * it got full, then all bets are off
1214 * anyway. */
1215
1216 sd_bus_message_unref(bus->wqueue[0]);
1217 bus->wqueue_size --;
1218 memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
1219 bus->windex = 0;
1220
e3017af9 1221 ret = 1;
de1c301e
LP
1222 }
1223 }
1224
e3017af9 1225 return ret;
de1c301e
LP
1226}
1227
1228static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
2bf938c1 1229 sd_bus_message *z = NULL;
e3017af9 1230 int r, ret = 0;
de1c301e
LP
1231
1232 assert(bus);
1233 assert(m);
89ffcd2a 1234 assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
de1c301e 1235
de1c301e
LP
1236 if (bus->rqueue_size > 0) {
1237 /* Dispatch a queued message */
1238
1239 *m = bus->rqueue[0];
1240 bus->rqueue_size --;
1241 memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
1242 return 1;
1243 }
1244
1245 /* Try to read a new message */
e3017af9 1246 do {
6629161f
LP
1247 if (bus->is_kernel)
1248 r = bus_kernel_read_message(bus, &z);
1249 else
1250 r = bus_socket_read_message(bus, &z);
1251
e3017af9
LP
1252 if (r < 0) {
1253 sd_bus_close(bus);
1254 return r;
1255 }
1256 if (r == 0)
1257 return ret;
de1c301e 1258
2e8d788c 1259 ret = 1;
e3017af9
LP
1260 } while (!z);
1261
1262 *m = z;
2e8d788c 1263 return ret;
de1c301e
LP
1264}
1265
1266int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
1267 int r;
1268
1269 if (!bus)
1270 return -EINVAL;
f54514f3 1271 if (!BUS_IS_OPEN(bus->state))
de1c301e
LP
1272 return -ENOTCONN;
1273 if (!m)
1274 return -EINVAL;
d5a2b9a6
LP
1275 if (bus_pid_changed(bus))
1276 return -ECHILD;
021a1e78
LP
1277
1278 if (m->n_fds > 0) {
1279 r = sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD);
1280 if (r < 0)
1281 return r;
1282 if (r == 0)
1283 return -ENOTSUP;
1284 }
de1c301e 1285
29f6aadd
LP
1286 /* If the serial number isn't kept, then we know that no reply
1287 * is expected */
1288 if (!serial && !m->sealed)
1289 m->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
1290
de1c301e
LP
1291 r = bus_seal_message(bus, m);
1292 if (r < 0)
1293 return r;
1294
5407f2de
LP
1295 /* If this is a reply and no reply was requested, then let's
1296 * suppress this, if we can */
1297 if (m->dont_send && !serial)
1298 return 0;
1299
89ffcd2a 1300 if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
de1c301e
LP
1301 size_t idx = 0;
1302
6629161f
LP
1303 if (bus->is_kernel)
1304 r = bus_kernel_write_message(bus, m);
1305 else
1306 r = bus_socket_write_message(bus, m, &idx);
1307
de1c301e
LP
1308 if (r < 0) {
1309 sd_bus_close(bus);
1310 return r;
6629161f 1311 } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) {
de1c301e
LP
1312 /* Wasn't fully written. So let's remember how
1313 * much was written. Note that the first entry
1314 * of the wqueue array is always allocated so
1315 * that we always can remember how much was
1316 * written. */
1317 bus->wqueue[0] = sd_bus_message_ref(m);
1318 bus->wqueue_size = 1;
1319 bus->windex = idx;
1320 }
1321 } else {
1322 sd_bus_message **q;
1323
1324 /* Just append it to the queue. */
1325
25220239 1326 if (bus->wqueue_size >= BUS_WQUEUE_MAX)
de1c301e
LP
1327 return -ENOBUFS;
1328
1329 q = realloc(bus->wqueue, sizeof(sd_bus_message*) * (bus->wqueue_size + 1));
1330 if (!q)
1331 return -ENOMEM;
1332
1333 bus->wqueue = q;
1334 q[bus->wqueue_size ++] = sd_bus_message_ref(m);
1335 }
1336
1337 if (serial)
1338 *serial = BUS_MESSAGE_SERIAL(m);
1339
1340 return 0;
1341}
1342
1343static usec_t calc_elapse(uint64_t usec) {
1344 if (usec == (uint64_t) -1)
1345 return 0;
1346
1347 if (usec == 0)
e3017af9 1348 usec = BUS_DEFAULT_TIMEOUT;
de1c301e
LP
1349
1350 return now(CLOCK_MONOTONIC) + usec;
1351}
1352
e3017af9
LP
1353static int timeout_compare(const void *a, const void *b) {
1354 const struct reply_callback *x = a, *y = b;
1355
1356 if (x->timeout != 0 && y->timeout == 0)
1357 return -1;
1358
1359 if (x->timeout == 0 && y->timeout != 0)
1360 return 1;
1361
1362 if (x->timeout < y->timeout)
1363 return -1;
1364
1365 if (x->timeout > y->timeout)
1366 return 1;
1367
1368 return 0;
1369}
1370
de1c301e
LP
1371int sd_bus_send_with_reply(
1372 sd_bus *bus,
1373 sd_bus_message *m,
52f3ba91 1374 sd_bus_message_handler_t callback,
de1c301e
LP
1375 void *userdata,
1376 uint64_t usec,
1377 uint64_t *serial) {
1378
1379 struct reply_callback *c;
1380 int r;
1381
1382 if (!bus)
1383 return -EINVAL;
f54514f3 1384 if (!BUS_IS_OPEN(bus->state))
de1c301e
LP
1385 return -ENOTCONN;
1386 if (!m)
1387 return -EINVAL;
1388 if (!callback)
1389 return -EINVAL;
89ffcd2a 1390 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
de1c301e 1391 return -EINVAL;
89ffcd2a
LP
1392 if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
1393 return -EINVAL;
d5a2b9a6
LP
1394 if (bus_pid_changed(bus))
1395 return -ECHILD;
89ffcd2a
LP
1396
1397 r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func);
1398 if (r < 0)
1399 return r;
de1c301e 1400
e3017af9
LP
1401 if (usec != (uint64_t) -1) {
1402 r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare);
1403 if (r < 0)
1404 return r;
1405 }
1406
de1c301e
LP
1407 r = bus_seal_message(bus, m);
1408 if (r < 0)
1409 return r;
1410
eba8617e 1411 c = new0(struct reply_callback, 1);
de1c301e
LP
1412 if (!c)
1413 return -ENOMEM;
1414
1415 c->callback = callback;
1416 c->userdata = userdata;
1417 c->serial = BUS_MESSAGE_SERIAL(m);
1418 c->timeout = calc_elapse(usec);
1419
1420 r = hashmap_put(bus->reply_callbacks, &c->serial, c);
1421 if (r < 0) {
1422 free(c);
1423 return r;
1424 }
1425
e3017af9
LP
1426 if (c->timeout != 0) {
1427 r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
1428 if (r < 0) {
1429 c->timeout = 0;
1430 sd_bus_send_with_reply_cancel(bus, c->serial);
1431 return r;
1432 }
1433 }
1434
de1c301e
LP
1435 r = sd_bus_send(bus, m, serial);
1436 if (r < 0) {
e3017af9 1437 sd_bus_send_with_reply_cancel(bus, c->serial);
de1c301e
LP
1438 return r;
1439 }
1440
1441 return r;
1442}
1443
1444int sd_bus_send_with_reply_cancel(sd_bus *bus, uint64_t serial) {
e3017af9 1445 struct reply_callback *c;
de1c301e
LP
1446
1447 if (!bus)
1448 return -EINVAL;
1449 if (serial == 0)
1450 return -EINVAL;
d5a2b9a6
LP
1451 if (bus_pid_changed(bus))
1452 return -ECHILD;
de1c301e
LP
1453
1454 c = hashmap_remove(bus->reply_callbacks, &serial);
1455 if (!c)
1456 return 0;
1457
e3017af9
LP
1458 if (c->timeout != 0)
1459 prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
1460
de1c301e
LP
1461 free(c);
1462 return 1;
1463}
1464
20902f3e 1465int bus_ensure_running(sd_bus *bus) {
89ffcd2a
LP
1466 int r;
1467
1468 assert(bus);
1469
f54514f3 1470 if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED)
021a1e78 1471 return -ENOTCONN;
d728d708
LP
1472 if (bus->state == BUS_RUNNING)
1473 return 1;
89ffcd2a
LP
1474
1475 for (;;) {
1476 r = sd_bus_process(bus, NULL);
1477 if (r < 0)
1478 return r;
d728d708
LP
1479 if (bus->state == BUS_RUNNING)
1480 return 1;
e3017af9
LP
1481 if (r > 0)
1482 continue;
89ffcd2a
LP
1483
1484 r = sd_bus_wait(bus, (uint64_t) -1);
1485 if (r < 0)
1486 return r;
1487 }
1488}
1489
de1c301e
LP
1490int sd_bus_send_with_reply_and_block(
1491 sd_bus *bus,
1492 sd_bus_message *m,
1493 uint64_t usec,
1494 sd_bus_error *error,
1495 sd_bus_message **reply) {
1496
1497 int r;
1498 usec_t timeout;
1499 uint64_t serial;
1500 bool room = false;
1501
1502 if (!bus)
1503 return -EINVAL;
f54514f3 1504 if (!BUS_IS_OPEN(bus->state))
021a1e78 1505 return -ENOTCONN;
de1c301e
LP
1506 if (!m)
1507 return -EINVAL;
89ffcd2a 1508 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
de1c301e 1509 return -EINVAL;
89ffcd2a 1510 if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
de1c301e 1511 return -EINVAL;
89ffcd2a
LP
1512 if (bus_error_is_dirty(error))
1513 return -EINVAL;
d5a2b9a6
LP
1514 if (bus_pid_changed(bus))
1515 return -ECHILD;
89ffcd2a 1516
20902f3e 1517 r = bus_ensure_running(bus);
89ffcd2a
LP
1518 if (r < 0)
1519 return r;
de1c301e
LP
1520
1521 r = sd_bus_send(bus, m, &serial);
1522 if (r < 0)
1523 return r;
1524
1525 timeout = calc_elapse(usec);
1526
1527 for (;;) {
1528 usec_t left;
e3017af9 1529 sd_bus_message *incoming = NULL;
de1c301e
LP
1530
1531 if (!room) {
1532 sd_bus_message **q;
1533
25220239
LP
1534 if (bus->rqueue_size >= BUS_RQUEUE_MAX)
1535 return -ENOBUFS;
1536
de1c301e
LP
1537 /* Make sure there's room for queuing this
1538 * locally, before we read the message */
1539
1540 q = realloc(bus->rqueue, (bus->rqueue_size + 1) * sizeof(sd_bus_message*));
1541 if (!q)
1542 return -ENOMEM;
1543
1544 bus->rqueue = q;
1545 room = true;
1546 }
1547
6629161f
LP
1548 if (bus->is_kernel)
1549 r = bus_kernel_read_message(bus, &incoming);
1550 else
1551 r = bus_socket_read_message(bus, &incoming);
de1c301e
LP
1552 if (r < 0)
1553 return r;
e3017af9 1554 if (incoming) {
89ffcd2a 1555
de1c301e
LP
1556 if (incoming->reply_serial == serial) {
1557 /* Found a match! */
1558
1559 if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_RETURN) {
b7f247e0
LP
1560
1561 if (reply)
1562 *reply = incoming;
1563 else
1564 sd_bus_message_unref(incoming);
1565
de1c301e
LP
1566 return 0;
1567 }
1568
1569 if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR) {
1570 int k;
1571
1572 r = sd_bus_error_copy(error, &incoming->error);
1573 if (r < 0) {
1574 sd_bus_message_unref(incoming);
1575 return r;
1576 }
1577
1578 k = bus_error_to_errno(&incoming->error);
1579 sd_bus_message_unref(incoming);
1580 return k;
1581 }
1582
1583 sd_bus_message_unref(incoming);
1584 return -EIO;
1585 }
1586
1587 /* There's already guaranteed to be room for
1588 * this, so need to resize things here */
1589 bus->rqueue[bus->rqueue_size ++] = incoming;
1590 room = false;
1591
1592 /* Try to read more, right-away */
1593 continue;
1594 }
e3017af9
LP
1595 if (r != 0)
1596 continue;
de1c301e
LP
1597
1598 if (timeout > 0) {
1599 usec_t n;
1600
1601 n = now(CLOCK_MONOTONIC);
1602 if (n >= timeout)
1603 return -ETIMEDOUT;
1604
1605 left = timeout - n;
1606 } else
1607 left = (uint64_t) -1;
1608
e3017af9 1609 r = bus_poll(bus, true, left);
de1c301e
LP
1610 if (r < 0)
1611 return r;
1612
1613 r = dispatch_wqueue(bus);
1614 if (r < 0)
1615 return r;
1616 }
1617}
1618
1619int sd_bus_get_fd(sd_bus *bus) {
1620 if (!bus)
1621 return -EINVAL;
f54514f3 1622 if (!BUS_IS_OPEN(bus->state))
89ffcd2a 1623 return -ENOTCONN;
e82c9509
LP
1624 if (bus->input_fd != bus->output_fd)
1625 return -EPERM;
d5a2b9a6
LP
1626 if (bus_pid_changed(bus))
1627 return -ECHILD;
de1c301e 1628
e82c9509 1629 return bus->input_fd;
de1c301e
LP
1630}
1631
1632int sd_bus_get_events(sd_bus *bus) {
1633 int flags = 0;
1634
1635 if (!bus)
1636 return -EINVAL;
f54514f3 1637 if (!BUS_IS_OPEN(bus->state))
89ffcd2a 1638 return -ENOTCONN;
d5a2b9a6
LP
1639 if (bus_pid_changed(bus))
1640 return -ECHILD;
de1c301e
LP
1641
1642 if (bus->state == BUS_OPENING)
1643 flags |= POLLOUT;
89ffcd2a
LP
1644 else if (bus->state == BUS_AUTHENTICATING) {
1645
2181a7f5 1646 if (bus_socket_auth_needs_write(bus))
89ffcd2a
LP
1647 flags |= POLLOUT;
1648
1649 flags |= POLLIN;
1650
1651 } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) {
de1c301e
LP
1652 if (bus->rqueue_size <= 0)
1653 flags |= POLLIN;
1654 if (bus->wqueue_size > 0)
1655 flags |= POLLOUT;
1656 }
1657
1658 return flags;
1659}
1660
e3017af9
LP
1661int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
1662 struct reply_callback *c;
1663
1664 if (!bus)
1665 return -EINVAL;
1666 if (!timeout_usec)
1667 return -EINVAL;
f54514f3 1668 if (!BUS_IS_OPEN(bus->state))
e3017af9 1669 return -ENOTCONN;
d5a2b9a6
LP
1670 if (bus_pid_changed(bus))
1671 return -ECHILD;
e3017af9
LP
1672
1673 if (bus->state == BUS_AUTHENTICATING) {
1674 *timeout_usec = bus->auth_timeout;
1675 return 1;
1676 }
1677
adee69fa
LP
1678 if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) {
1679 *timeout_usec = (uint64_t) -1;
e3017af9 1680 return 0;
adee69fa 1681 }
e3017af9
LP
1682
1683 c = prioq_peek(bus->reply_callbacks_prioq);
adee69fa
LP
1684 if (!c) {
1685 *timeout_usec = (uint64_t) -1;
e3017af9 1686 return 0;
adee69fa 1687 }
e3017af9
LP
1688
1689 *timeout_usec = c->timeout;
1690 return 1;
1691}
1692
1693static int process_timeout(sd_bus *bus) {
eb01ba5d 1694 _cleanup_bus_message_unref_ sd_bus_message* m = NULL;
e3017af9
LP
1695 struct reply_callback *c;
1696 usec_t n;
1697 int r;
1698
1699 assert(bus);
1700
1701 c = prioq_peek(bus->reply_callbacks_prioq);
1702 if (!c)
1703 return 0;
1704
1705 n = now(CLOCK_MONOTONIC);
1706 if (c->timeout > n)
1707 return 0;
1708
eb01ba5d
LP
1709 r = bus_message_new_synthetic_error(
1710 bus,
1711 c->serial,
1712 &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.Timeout", "Timed out"),
1713 &m);
1714 if (r < 0)
1715 return r;
1716
e3017af9
LP
1717 assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
1718 hashmap_remove(bus->reply_callbacks, &c->serial);
1719
eb01ba5d 1720 r = c->callback(bus, m, c->userdata);
e3017af9
LP
1721 free(c);
1722
1723 return r < 0 ? r : 1;
1724}
1725
9d373862
LP
1726static int process_hello(sd_bus *bus, sd_bus_message *m) {
1727 assert(bus);
1728 assert(m);
1729
1730 if (bus->state != BUS_HELLO)
1731 return 0;
1732
1733 /* Let's make sure the first message on the bus is the HELLO
1734 * reply. But note that we don't actually parse the message
2181a7f5
LP
1735 * here (we leave that to the usual handling), we just verify
1736 * we don't let any earlier msg through. */
9d373862
LP
1737
1738 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
1739 m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
1740 return -EIO;
1741
1742 if (m->reply_serial != bus->hello_serial)
1743 return -EIO;
1744
1745 return 0;
1746}
1747
a652755d
LP
1748static int process_reply(sd_bus *bus, sd_bus_message *m) {
1749 struct reply_callback *c;
1750 int r;
1751
1752 assert(bus);
1753 assert(m);
1754
1755 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
1756 m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
1757 return 0;
1758
1759 c = hashmap_remove(bus->reply_callbacks, &m->reply_serial);
1760 if (!c)
1761 return 0;
1762
1763 if (c->timeout != 0)
1764 prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
1765
88fe224c
LP
1766 r = sd_bus_message_rewind(m, true);
1767 if (r < 0)
1768 return r;
1769
eb01ba5d 1770 r = c->callback(bus, m, c->userdata);
a652755d
LP
1771 free(c);
1772
1773 return r;
1774}
1775
1776static int process_filter(sd_bus *bus, sd_bus_message *m) {
1777 struct filter_callback *l;
1778 int r;
1779
392d5b37
LP
1780 assert(bus);
1781 assert(m);
1782
7286037f
LP
1783 do {
1784 bus->filter_callbacks_modified = false;
1785
1786 LIST_FOREACH(callbacks, l, bus->filter_callbacks) {
1787
1788 if (bus->filter_callbacks_modified)
1789 break;
1790
1791 /* Don't run this more than once per iteration */
1792 if (l->last_iteration == bus->iteration_counter)
1793 continue;
1794
1795 l->last_iteration = bus->iteration_counter;
1796
88fe224c
LP
1797 r = sd_bus_message_rewind(m, true);
1798 if (r < 0)
1799 return r;
1800
eb01ba5d 1801 r = l->callback(bus, m, l->userdata);
7286037f
LP
1802 if (r != 0)
1803 return r;
1804
1805 }
1806
1807 } while (bus->filter_callbacks_modified);
a652755d
LP
1808
1809 return 0;
1810}
1811
392d5b37 1812static int process_match(sd_bus *bus, sd_bus_message *m) {
7286037f
LP
1813 int r;
1814
392d5b37
LP
1815 assert(bus);
1816 assert(m);
1817
7286037f
LP
1818 do {
1819 bus->match_callbacks_modified = false;
1820
eb01ba5d 1821 r = bus_match_run(bus, &bus->match_callbacks, m);
7286037f
LP
1822 if (r != 0)
1823 return r;
1824
1825 } while (bus->match_callbacks_modified);
1826
1827 return 0;
392d5b37
LP
1828}
1829
b9bf7e2b
LP
1830static int process_builtin(sd_bus *bus, sd_bus_message *m) {
1831 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1832 int r;
1833
1834 assert(bus);
1835 assert(m);
1836
1837 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
1838 return 0;
1839
1840 if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
1841 return 0;
1842
1843 if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
1844 return 1;
1845
1846 if (streq_ptr(m->member, "Ping"))
1847 r = sd_bus_message_new_method_return(bus, m, &reply);
1848 else if (streq_ptr(m->member, "GetMachineId")) {
1849 sd_id128_t id;
1850 char sid[33];
1851
1852 r = sd_id128_get_machine(&id);
1853 if (r < 0)
1854 return r;
1855
1856 r = sd_bus_message_new_method_return(bus, m, &reply);
1857 if (r < 0)
1858 return r;
1859
1860 r = sd_bus_message_append(reply, "s", sd_id128_to_string(id, sid));
1861 } else {
29ddb38f
LP
1862 r = sd_bus_message_new_method_errorf(
1863 bus, m, &reply,
1864 "org.freedesktop.DBus.Error.UnknownMethod",
b9bf7e2b 1865 "Unknown method '%s' on interface '%s'.", m->member, m->interface);
b9bf7e2b
LP
1866 }
1867
1868 if (r < 0)
1869 return r;
1870
1871 r = sd_bus_send(bus, reply, NULL);
1872 if (r < 0)
1873 return r;
1874
1875 return 1;
1876}
1877
29ddb38f
LP
1878static int node_vtable_get_userdata(
1879 sd_bus *bus,
1880 const char *path,
1881 struct node_vtable *c,
1882 void **userdata) {
1883
1884 void *u;
e3017af9
LP
1885 int r;
1886
1887 assert(bus);
29ddb38f
LP
1888 assert(path);
1889 assert(c);
29ddb38f
LP
1890
1891 u = c->userdata;
1892 if (c->find) {
1893 r = c->find(bus, path, c->interface, &u, u);
1894 if (r <= 0)
1895 return r;
1896 }
e3017af9 1897
486e950b
LP
1898 if (userdata)
1899 *userdata = u;
1900
29ddb38f
LP
1901 return 1;
1902}
e3017af9 1903
29ddb38f
LP
1904static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
1905 assert(p);
e3017af9 1906
29ddb38f
LP
1907 return (uint8_t*) u + p->property.offset;
1908}
a652755d 1909
29ddb38f
LP
1910static int vtable_property_get_userdata(
1911 sd_bus *bus,
1912 const char *path,
1913 struct vtable_member *p,
1914 void **userdata) {
e3017af9 1915
29ddb38f
LP
1916 void *u;
1917 int r;
a652755d 1918
29ddb38f
LP
1919 assert(bus);
1920 assert(path);
1921 assert(p);
1922 assert(userdata);
a652755d 1923
29ddb38f
LP
1924 r = node_vtable_get_userdata(bus, path, p->parent, &u);
1925 if (r <= 0)
1926 return r;
a652755d 1927
29ddb38f
LP
1928 *userdata = vtable_property_convert_userdata(p->vtable, u);
1929 return 1;
1930}
88fe224c 1931
29ddb38f
LP
1932static int add_enumerated_to_set(sd_bus *bus, const char *prefix, struct node_enumerator *first, Set *s) {
1933 struct node_enumerator *c;
1934 int r;
a652755d 1935
29ddb38f
LP
1936 assert(bus);
1937 assert(prefix);
1938 assert(s);
7286037f 1939
29ddb38f
LP
1940 LIST_FOREACH(enumerators, c, first) {
1941 char **children = NULL, **k;
7286037f 1942
29ddb38f
LP
1943 r = c->callback(bus, prefix, &children, c->userdata);
1944 if (r < 0)
1945 return r;
7286037f 1946
29ddb38f
LP
1947 STRV_FOREACH(k, children) {
1948 if (r < 0) {
1949 free(*k);
1950 continue;
1951 }
7286037f 1952
29ddb38f
LP
1953 if (!object_path_is_valid(*k) && object_path_startswith(*k, prefix)) {
1954 free(*k);
1955 r = -EINVAL;
1956 continue;
1957 }
7286037f 1958
29ddb38f
LP
1959 r = set_consume(s, *k);
1960 }
7286037f 1961
29ddb38f
LP
1962 free(children);
1963 if (r < 0)
1964 return r;
1965 }
7286037f 1966
29ddb38f
LP
1967 return 0;
1968}
88fe224c 1969
29ddb38f
LP
1970static int add_subtree_to_set(sd_bus *bus, const char *prefix, struct node *n, Set *s) {
1971 struct node *i;
1972 int r;
7286037f 1973
29ddb38f
LP
1974 assert(bus);
1975 assert(prefix);
1976 assert(n);
1977 assert(s);
7286037f 1978
29ddb38f
LP
1979 r = add_enumerated_to_set(bus, prefix, n->enumerators, s);
1980 if (r < 0)
1981 return r;
e3017af9 1982
29ddb38f
LP
1983 LIST_FOREACH(siblings, i, n->child) {
1984 char *t;
a652755d 1985
29ddb38f
LP
1986 t = strdup(i->path);
1987 if (!t)
1988 return -ENOMEM;
a652755d 1989
29ddb38f
LP
1990 r = set_consume(s, t);
1991 if (r < 0 && r != -EEXIST)
1992 return r;
a652755d 1993
29ddb38f
LP
1994 r = add_subtree_to_set(bus, prefix, i, s);
1995 if (r < 0)
1996 return r;
1997 }
e3017af9 1998
29ddb38f 1999 return 0;
a652755d
LP
2000}
2001
29ddb38f
LP
2002static int get_child_nodes(sd_bus *bus, const char *prefix, struct node *n, Set **_s) {
2003 Set *s = NULL;
0a72c2bd
LP
2004 int r;
2005
2006 assert(bus);
29ddb38f
LP
2007 assert(n);
2008 assert(_s);
0a72c2bd
LP
2009
2010 s = set_new(string_hash_func, string_compare_func);
2011 if (!s)
2012 return -ENOMEM;
2013
29ddb38f
LP
2014 r = add_subtree_to_set(bus, prefix, n, s);
2015 if (r < 0) {
2016 set_free_free(s);
2017 return r;
0a72c2bd
LP
2018 }
2019
29ddb38f
LP
2020 *_s = s;
2021 return 0;
2022}
0a72c2bd 2023
29ddb38f
LP
2024static int node_callbacks_run(
2025 sd_bus *bus,
2026 sd_bus_message *m,
2027 struct node_callback *first,
2028 bool require_fallback,
2029 bool *found_object) {
0a72c2bd 2030
29ddb38f
LP
2031 struct node_callback *c;
2032 int r;
0a72c2bd 2033
29ddb38f
LP
2034 assert(bus);
2035 assert(m);
2036 assert(found_object);
0a72c2bd 2037
29ddb38f
LP
2038 LIST_FOREACH(callbacks, c, first) {
2039 if (require_fallback && !c->is_fallback)
2040 continue;
0a72c2bd 2041
29ddb38f 2042 *found_object = true;
0a72c2bd 2043
29ddb38f
LP
2044 if (c->last_iteration == bus->iteration_counter)
2045 continue;
0a72c2bd 2046
29ddb38f
LP
2047 r = sd_bus_message_rewind(m, true);
2048 if (r < 0)
2049 return r;
0a72c2bd 2050
29ddb38f
LP
2051 r = c->callback(bus, m, c->userdata);
2052 if (r != 0)
2053 return r;
2054 }
0a72c2bd 2055
29ddb38f 2056 return 0;
0a72c2bd
LP
2057}
2058
29ddb38f
LP
2059static int method_callbacks_run(
2060 sd_bus *bus,
2061 sd_bus_message *m,
2062 struct vtable_member *c,
2063 bool require_fallback,
2064 bool *found_object) {
2065
2066 const char *signature;
2067 void *u;
a652755d
LP
2068 int r;
2069
2070 assert(bus);
2071 assert(m);
29ddb38f
LP
2072 assert(c);
2073 assert(found_object);
a652755d 2074
29ddb38f
LP
2075 if (require_fallback && !c->parent->is_fallback)
2076 return 0;
7286037f 2077
29ddb38f
LP
2078 r = node_vtable_get_userdata(bus, m->path, c->parent, &u);
2079 if (r <= 0)
9d373862
LP
2080 return r;
2081
29ddb38f 2082 *found_object = true;
a652755d 2083
29ddb38f
LP
2084 r = sd_bus_message_rewind(m, true);
2085 if (r < 0)
a652755d
LP
2086 return r;
2087
29ddb38f
LP
2088 r = sd_bus_message_get_signature(m, true, &signature);
2089 if (r < 0)
392d5b37
LP
2090 return r;
2091
9db76355 2092 if (!streq(strempty(c->vtable->method.signature), signature)) {
29ddb38f
LP
2093 r = sd_bus_reply_method_errorf(bus, m,
2094 "org.freedesktop.DBus.Error.InvalidArgs",
2095 "Invalid arguments '%s' to call %s:%s, expecting '%s'.",
9db76355 2096 signature, c->interface, c->member, strempty(c->vtable->method.signature));
29ddb38f
LP
2097 if (r < 0)
2098 return r;
a652755d 2099
29ddb38f
LP
2100 return 1;
2101 }
0a72c2bd 2102
43a43f50
LP
2103 if (c->vtable->method.handler)
2104 return c->vtable->method.handler(bus, m, u);
2105
2106 /* If the method callback is NULL, make this a successful NOP */
2107 r = sd_bus_reply_method_return(bus, m, NULL);
2108 if (r < 0)
2109 return r;
2110
2111 return 1;
e3017af9
LP
2112}
2113
adcdb374
LP
2114static int invoke_property_get(
2115 sd_bus *bus,
2116 const sd_bus_vtable *v,
2117 const char *path,
2118 const char *interface,
2119 const char *property,
2120 sd_bus_message *m,
2121 sd_bus_error *error,
2122 void *userdata) {
2123
2124 int r;
2125 void *p;
2126
2127 assert(bus);
2128 assert(v);
2129
2130 if (v->property.get)
2131 return v->property.get(bus, path, interface, property, m, error, userdata);
2132
2133 /* Automatic handling if no callback is defined. */
2134
9db76355
LP
2135 assert(bus_type_is_basic(v->property.signature[0]));
2136
adcdb374
LP
2137 switch (v->property.signature[0]) {
2138
2139 case SD_BUS_TYPE_STRING:
2140 case SD_BUS_TYPE_OBJECT_PATH:
2141 case SD_BUS_TYPE_SIGNATURE:
2142 p = *(char**) userdata;
2143 break;
2144
2145 default:
2146 p = userdata;
9db76355 2147 break;
adcdb374
LP
2148 }
2149
2150 r = sd_bus_message_append_basic(m, v->property.signature[0], p);
2151 if (r < 0)
2152 return r;
2153
2154 return 1;
2155}
2156
9db76355
LP
2157static int invoke_property_set(
2158 sd_bus *bus,
2159 const sd_bus_vtable *v,
2160 const char *path,
2161 const char *interface,
2162 const char *property,
2163 sd_bus_message *value,
2164 sd_bus_error *error,
2165 void *userdata) {
2166
2167 int r;
2168
2169 assert(bus);
2170 assert(v);
2171
2172 if (v->property.set)
2173 return v->property.set(bus, path, interface, property, value, error, userdata);
2174
2175 /* Automatic handling if no callback is defined. */
2176
2177 assert(signature_is_single(v->property.signature, false));
2178 assert(bus_type_is_basic(v->property.signature[0]));
2179
2180 switch (v->property.signature[0]) {
2181
2182 case SD_BUS_TYPE_STRING:
2183 case SD_BUS_TYPE_OBJECT_PATH:
2184 case SD_BUS_TYPE_SIGNATURE: {
2185 const char *p;
2186 char *n;
2187
2188 r = sd_bus_message_read_basic(value, v->property.signature[0], &p);
2189 if (r < 0)
2190 return r;
2191
2192 n = strdup(p);
2193 if (!n)
2194 return -ENOMEM;
2195
2196 free(*(char**) userdata);
2197 *(char**) userdata = n;
2198
2199 break;
2200 }
2201
2202 default:
2203 r = sd_bus_message_read_basic(value, v->property.signature[0], userdata);
2204 if (r < 0)
2205 return r;
2206
2207 break;
2208 }
2209
2210 return 1;
2211}
2212
29ddb38f
LP
2213static int property_get_set_callbacks_run(
2214 sd_bus *bus,
2215 sd_bus_message *m,
2216 struct vtable_member *c,
2217 bool require_fallback,
2218 bool is_get,
2219 bool *found_object) {
2220
2221 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2222 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2223 void *u;
de1c301e
LP
2224 int r;
2225
a7e3212d 2226 assert(bus);
29ddb38f
LP
2227 assert(m);
2228 assert(found_object);
de1c301e 2229
29ddb38f
LP
2230 if (require_fallback && !c->parent->is_fallback)
2231 return 0;
de1c301e 2232
29ddb38f
LP
2233 r = vtable_property_get_userdata(bus, m->path, c, &u);
2234 if (r <= 0)
2235 return r;
de1c301e 2236
29ddb38f
LP
2237 *found_object = true;
2238
2239 r = sd_bus_message_new_method_return(bus, m, &reply);
a7e3212d
LP
2240 if (r < 0)
2241 return r;
de1c301e 2242
29ddb38f 2243 c->last_iteration = bus->iteration_counter;
de1c301e 2244
29ddb38f
LP
2245 if (is_get) {
2246 r = sd_bus_message_open_container(reply, 'v', c->vtable->property.signature);
88fe224c
LP
2247 if (r < 0)
2248 return r;
2249
adcdb374
LP
2250 r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, &error, u);
2251 if (r < 0)
2252 return r;
de1c301e 2253
29ddb38f
LP
2254 if (sd_bus_error_is_set(&error)) {
2255 r = sd_bus_reply_method_error(bus, m, &error);
2256 if (r < 0)
2257 return r;
de1c301e 2258
29ddb38f
LP
2259 return 1;
2260 }
de1c301e 2261
29ddb38f 2262 r = sd_bus_message_close_container(reply);
a7e3212d
LP
2263 if (r < 0)
2264 return r;
de1c301e 2265
29ddb38f
LP
2266 } else {
2267 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2268 sd_bus_error_setf(&error, "org.freedesktop.DBus.Error.PropertyReadOnly", "Property '%s' is not writable.", c->member);
2269 else {
2270 r = sd_bus_message_enter_container(m, 'v', c->vtable->property.signature);
2271 if (r < 0)
2272 return r;
2273
9db76355
LP
2274 r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, &error, u);
2275 if (r < 0)
2276 return r;
29ddb38f
LP
2277 }
2278
2279 if (sd_bus_error_is_set(&error)) {
2280 r = sd_bus_reply_method_error(bus, m, &error);
2281 if (r < 0)
2282 return r;
2283
2284 return 1;
2285 }
2286
2287 r = sd_bus_message_exit_container(m);
a7e3212d
LP
2288 if (r < 0)
2289 return r;
2290 }
e3017af9 2291
29ddb38f
LP
2292 r = sd_bus_send(bus, reply, NULL);
2293 if (r < 0)
2294 return r;
de1c301e 2295
29ddb38f 2296 return 1;
a7e3212d 2297}
e3017af9 2298
29ddb38f
LP
2299static int vtable_append_all_properties(
2300 sd_bus *bus,
2301 sd_bus_message *reply,
2302 const char *path,
2303 struct node_vtable *c,
2304 void *userdata,
2305 sd_bus_error *error) {
2306
2307 const sd_bus_vtable *v;
a7e3212d 2308 int r;
de1c301e 2309
29ddb38f
LP
2310 assert(bus);
2311 assert(reply);
2312 assert(c);
2313
2314 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
2315 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
2316 continue;
2317
2318 r = sd_bus_message_open_container(reply, 'e', "sv");
2319 if (r < 0)
2320 return r;
2321
2322 r = sd_bus_message_append(reply, "s", c->interface);
2323 if (r < 0)
2324 return r;
2325
2326 r = sd_bus_message_open_container(reply, 'v', v->property.signature);
2327 if (r < 0)
2328 return r;
2329
adcdb374 2330 r = invoke_property_get(bus, v, path, c->interface, v->property.member, reply, error, vtable_property_convert_userdata(v, userdata));
29ddb38f
LP
2331 if (r < 0)
2332 return r;
2333
2334 if (sd_bus_error_is_set(error))
2335 return 0;
2336
2337 r = sd_bus_message_close_container(reply);
2338 if (r < 0)
2339 return r;
2340
2341 r = sd_bus_message_close_container(reply);
2342 if (r < 0)
2343 return r;
2344 }
2345
2346 return 1;
2347}
2348
2349static int property_get_all_callbacks_run(
2350 sd_bus *bus,
2351 sd_bus_message *m,
2352 struct node_vtable *first,
2353 bool require_fallback,
2354 const char *iface,
2355 bool *found_object) {
2356
2357 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2358 struct node_vtable *c;
2359 bool found_interface = false;
2360 int r;
2361
2362 assert(bus);
2363 assert(m);
2364 assert(found_object);
2365
2366 r = sd_bus_message_new_method_return(bus, m, &reply);
2367 if (r < 0)
2368 return r;
2369
2370 r = sd_bus_message_open_container(reply, 'a', "{sv}");
2371 if (r < 0)
2372 return r;
2373
2374 LIST_FOREACH(vtables, c, first) {
2375 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2376 void *u;
2377
2378 if (require_fallback && !c->is_fallback)
2379 continue;
2380
2381 r = node_vtable_get_userdata(bus, m->path, c, &u);
2382 if (r < 0)
2383 return r;
2384 if (r == 0)
2385 continue;
2386
2387 *found_object = true;
2388
2389 if (iface && !streq(c->interface, iface))
2390 continue;
2391 found_interface = true;
2392
2393 c->last_iteration = bus->iteration_counter;
2394
2395 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
2396 if (r < 0)
2397 return r;
2398
2399 if (sd_bus_error_is_set(&error)) {
2400 r = sd_bus_reply_method_error(bus, m, &error);
2401 if (r < 0)
2402 return r;
2403
2404 return 1;
2405 }
2406 }
2407
2408 if (!found_interface) {
2409 r = sd_bus_reply_method_errorf(
2410 bus, m,
2411 "org.freedesktop.DBus.Error.UnknownInterface",
2412 "Unknown interface '%s'.", iface);
2413 if (r < 0)
2414 return r;
2415
2416 return 1;
2417 }
2418
2419 r = sd_bus_message_close_container(reply);
2420 if (r < 0)
2421 return r;
2422
2423 r = sd_bus_send(bus, reply, NULL);
2424 if (r < 0)
2425 return r;
2426
2427 return 1;
2428}
2429
2430static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
2431 assert(bus);
2432
2433 if (n->object_manager)
2434 return true;
2435
2436 if (n->parent)
2437 return bus_node_with_object_manager(bus, n->parent);
2438
2439 return false;
2440}
2441
2442static bool bus_node_exists(sd_bus *bus, struct node *n, const char *path, bool require_fallback) {
2443 struct node_vtable *c;
2444 struct node_callback *k;
2445
2446 assert(bus);
2447 assert(n);
2448
486e950b
LP
2449 /* Tests if there's anything attached directly to this node
2450 * for the specified path */
29ddb38f
LP
2451
2452 LIST_FOREACH(callbacks, k, n->callbacks) {
2453 if (require_fallback && !k->is_fallback)
2454 continue;
2455
2456 return true;
2457 }
2458
2459 LIST_FOREACH(vtables, c, n->vtables) {
2460
2461 if (require_fallback && !c->is_fallback)
2462 continue;
2463
486e950b
LP
2464 if (node_vtable_get_userdata(bus, path, c, NULL) > 0)
2465 return true;
29ddb38f
LP
2466 }
2467
2468 return !require_fallback && (n->enumerators || n->object_manager);
29ddb38f
LP
2469}
2470
2471static int process_introspect(
2472 sd_bus *bus,
2473 sd_bus_message *m,
2474 struct node *n,
2475 bool require_fallback,
2476 bool *found_object) {
2477
2478 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2479 _cleanup_set_free_free_ Set *s = NULL;
2480 struct introspect intro;
2481 struct node_vtable *c;
2482 bool empty;
2483 int r;
2484
2485 assert(bus);
2486 assert(m);
2487 assert(n);
2488 assert(found_object);
2489
2490 r = get_child_nodes(bus, m->path, n, &s);
2491 if (r < 0)
2492 return r;
2493
2494 r = introspect_begin(&intro);
2495 if (r < 0)
2496 return r;
2497
2498 r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
2499 if (r < 0)
2500 return r;
2501
2502 empty = set_isempty(s);
2503
2504 LIST_FOREACH(vtables, c, n->vtables) {
29ddb38f
LP
2505 if (require_fallback && !c->is_fallback)
2506 continue;
2507
486e950b 2508 r = node_vtable_get_userdata(bus, m->path, c, NULL);
29ddb38f
LP
2509 if (r < 0)
2510 return r;
2511 if (r == 0)
2512 continue;
2513
2514 empty = false;
2515
2516 r = introspect_write_interface(&intro, c->interface, c->vtable);
2517 if (r < 0)
2518 goto finish;
2519 }
2520
2521 if (empty) {
2522 /* Nothing?, let's see if we exist at all, and if not
2523 * refuse to do anything */
2524 r = bus_node_exists(bus, n, m->path, require_fallback);
2525 if (r < 0)
2526 return r;
2527
2528 if (r == 0)
2529 goto finish;
2530 }
2531
2532 *found_object = true;
2533
2534 r = introspect_write_child_nodes(&intro, s, m->path);
2535 if (r < 0)
2536 goto finish;
2537
2538 r = introspect_finish(&intro, bus, m, &reply);
2539 if (r < 0)
2540 goto finish;
2541
2542 r = sd_bus_send(bus, reply, NULL);
2543 if (r < 0)
2544 goto finish;
2545
2546 r = 1;
2547
2548finish:
2549 introspect_free(&intro);
2550 return r;
2551}
2552
2553static int object_manager_serialize_vtable(
2554 sd_bus *bus,
2555 sd_bus_message *reply,
2556 const char *path,
2557 struct node_vtable *c,
2558 sd_bus_error *error) {
2559
2560 void *u;
2561 int r;
2562
2563 assert(bus);
2564 assert(reply);
2565 assert(path);
2566 assert(c);
2567 assert(error);
2568
2569 r = node_vtable_get_userdata(bus, path, c, &u);
2570 if (r <= 0)
2571 return r;
2572
2573 r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
2574 if (r < 0)
2575 return r;
2576
2577 r = sd_bus_message_append(reply, "s", c->interface);
2578 if (r < 0)
2579 return r;
2580
2581 r = sd_bus_message_open_container(reply, 'a', "{sv}");
2582 if (r < 0)
2583 return r;
2584
2585 r = vtable_append_all_properties(bus, reply, path, c, u, error);
2586 if (r < 0)
2587 return r;
2588
2589 r = sd_bus_message_close_container(reply);
2590 if (r < 0)
2591 return r;
2592
2593 r = sd_bus_message_close_container(reply);
2594 if (r < 0)
2595 return r;
2596
2597 return 0;
2598}
2599
2600static int object_manager_serialize_path(
2601 sd_bus *bus,
2602 sd_bus_message *reply,
5d12cc3e 2603 const char *prefix,
29ddb38f
LP
2604 const char *path,
2605 bool require_fallback,
2606 sd_bus_error *error) {
2607
2608 struct node_vtable *i;
2609 struct node *n;
2610 int r;
2611
2612 assert(bus);
2613 assert(reply);
5d12cc3e 2614 assert(prefix);
29ddb38f
LP
2615 assert(path);
2616 assert(error);
2617
5d12cc3e 2618 n = hashmap_get(bus->nodes, prefix);
29ddb38f
LP
2619 if (!n)
2620 return 0;
2621
2622 r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
2623 if (r < 0)
2624 return r;
2625
2626 r = sd_bus_message_append(reply, "o", path);
2627 if (r < 0)
2628 return r;
2629
2630 r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
2631 if (r < 0)
2632 return r;
2633
2634 LIST_FOREACH(vtables, i, n->vtables) {
2635
2636 if (require_fallback && !i->is_fallback)
2637 continue;
2638
2639 r = object_manager_serialize_vtable(bus, reply, path, i, error);
2640 if (r < 0)
2641 return r;
2642 if (sd_bus_error_is_set(error))
2643 return 0;
2644 }
2645
2646 r = sd_bus_message_close_container(reply);
2647 if (r < 0)
2648 return r;
2649
2650 r = sd_bus_message_close_container(reply);
2651 if (r < 0)
2652 return r;
2653
2654 return 1;
2655}
2656
2657static int object_manager_serialize_path_and_fallbacks(
2658 sd_bus *bus,
2659 sd_bus_message *reply,
2660 const char *path,
2661 sd_bus_error *error) {
2662
2663 size_t pl;
2664 int r;
2665
2666 assert(bus);
2667 assert(reply);
2668 assert(path);
2669 assert(error);
2670
2671 /* First, add all vtables registered for this path */
5d12cc3e 2672 r = object_manager_serialize_path(bus, reply, path, path, false, error);
29ddb38f
LP
2673 if (r < 0)
2674 return r;
2675 if (sd_bus_error_is_set(error))
2676 return 0;
2677
2678 /* Second, add fallback vtables registered for any of the prefixes */
2679 pl = strlen(path);
2680 if (pl > 1) {
2681 char p[pl + 1];
2682 strcpy(p, path);
2683
2684 for (;;) {
2685 char *e;
2686
2687 e = strrchr(p, '/');
2688 if (e == p || !e)
2689 break;
2690
2691 *e = 0;
2692
5d12cc3e 2693 r = object_manager_serialize_path(bus, reply, p, path, true, error);
29ddb38f
LP
2694 if (r < 0)
2695 return r;
2696
2697 if (sd_bus_error_is_set(error))
2698 return 0;
2699 }
2700 }
2701
2702 return 0;
2703}
2704
2705static int process_get_managed_objects(
2706 sd_bus *bus,
2707 sd_bus_message *m,
2708 struct node *n,
2709 bool require_fallback,
2710 bool *found_object) {
2711
2712 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2713 _cleanup_set_free_free_ Set *s = NULL;
2714 bool empty;
2715 int r;
2716
2717 assert(bus);
2718 assert(m);
2719 assert(n);
2720 assert(found_object);
2721
2722 if (!bus_node_with_object_manager(bus, n))
2723 return 0;
2724
2725 r = get_child_nodes(bus, m->path, n, &s);
2726 if (r < 0)
2727 return r;
2728
2729 r = sd_bus_message_new_method_return(bus, m, &reply);
2730 if (r < 0)
2731 return r;
2732
2733 r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
2734 if (r < 0)
2735 return r;
2736
2737 empty = set_isempty(s);
2738 if (empty) {
2739 struct node_vtable *c;
2740
2741 /* Hmm, so we have no children? Then let's check
2742 * whether we exist at all, i.e. whether at least one
2743 * vtable exists. */
2744
2745 LIST_FOREACH(vtables, c, n->vtables) {
2746
2747 if (require_fallback && !c->is_fallback)
2748 continue;
2749
2750 if (r < 0)
2751 return r;
2752 if (r == 0)
2753 continue;
2754
2755 empty = false;
2756 break;
2757 }
2758
2759 if (empty)
2760 return 0;
2761 } else {
2762 Iterator i;
2763 char *path;
2764
2765 SET_FOREACH(path, s, i) {
2766 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2767
2768 r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
2769 if (r < 0)
2770 return -ENOMEM;
2771
2772 if (sd_bus_error_is_set(&error)) {
2773 r = sd_bus_reply_method_error(bus, m, &error);
2774 if (r < 0)
2775 return r;
2776
2777 return 1;
2778 }
2779 }
2780 }
2781
2782 r = sd_bus_message_close_container(reply);
2783 if (r < 0)
2784 return r;
2785
2786 r = sd_bus_send(bus, reply, NULL);
2787 if (r < 0)
2788 return r;
2789
2790 return 1;
2791}
2792
5d12cc3e
LP
2793static int object_find_and_run(
2794 sd_bus *bus,
2795 sd_bus_message *m,
2796 const char *p,
2797 bool require_fallback,
2798 bool *found_object) {
2799
29ddb38f
LP
2800 struct node *n;
2801 struct vtable_member vtable_key, *v;
2802 int r;
2803
2804 assert(bus);
2805 assert(m);
2806 assert(p);
2807 assert(found_object);
2808
2809 n = hashmap_get(bus->nodes, p);
2810 if (!n)
2811 return 0;
2812
2813 /* First, try object callbacks */
2814 r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
2815 if (r != 0)
2816 return r;
2817
2818 if (!m->interface || !m->member)
2819 return 0;
2820
2821 /* Then, look for a known method */
2822 vtable_key.path = (char*) p;
2823 vtable_key.interface = m->interface;
2824 vtable_key.member = m->member;
2825
2826 v = hashmap_get(bus->vtable_methods, &vtable_key);
2827 if (v) {
2828 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
2829 if (r != 0)
2830 return r;
2831 }
2832
2833 /* Then, look for a known property */
2834 if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
2835 bool get = false;
2836
2837 get = streq(m->member, "Get");
2838
2839 if (get || streq(m->member, "Set")) {
2840
2841 r = sd_bus_message_rewind(m, true);
2842 if (r < 0)
2843 return r;
2844
2845 vtable_key.path = (char*) p;
2846
2847 r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
2848 if (r < 0)
2849 return r;
2850
2851 v = hashmap_get(bus->vtable_properties, &vtable_key);
2852 if (v) {
2853 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
2854 if (r != 0)
2855 return r;
2856 }
2857
2858 } else if (streq(m->member, "GetAll")) {
2859 const char *iface;
2860
2861 r = sd_bus_message_rewind(m, true);
2862 if (r < 0)
2863 return r;
2864
2865 r = sd_bus_message_read(m, "s", &iface);
2866 if (r < 0)
2867 return r;
2868
2869 if (iface[0] == 0)
2870 iface = NULL;
2871
2872 r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
2873 if (r != 0)
2874 return r;
2875 }
2876
2877 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2878
2879 r = process_introspect(bus, m, n, require_fallback, found_object);
2880 if (r != 0)
2881 return r;
2882
2883 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
2884
2885 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
2886 if (r != 0)
2887 return r;
2888 }
2889
2890 if (!*found_object) {
2891 r = bus_node_exists(bus, n, m->path, require_fallback);
2892 if (r < 0)
2893 return r;
2894
2895 if (r > 0)
2896 *found_object = true;
2897 }
2898
2899 return 0;
2900}
2901
2902static int process_object(sd_bus *bus, sd_bus_message *m) {
2903 int r;
2904 size_t pl;
2905 bool found_object = false;
2906
2907 assert(bus);
2908 assert(m);
2909
2910 if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
2911 return 0;
2912
2913 if (!m->path)
2914 return 0;
2915
2916 if (hashmap_isempty(bus->nodes))
2917 return 0;
2918
2919 pl = strlen(m->path);
2920 do {
2921 char p[pl+1];
2922
2923 bus->nodes_modified = false;
2924
2925 r = object_find_and_run(bus, m, m->path, false, &found_object);
2926 if (r != 0)
2927 return r;
2928
2929 /* Look for fallback prefixes */
2930 strcpy(p, m->path);
2931 for (;;) {
2932 char *e;
2933
2934 if (streq(p, "/"))
2935 break;
2936
2937 if (bus->nodes_modified)
2938 break;
2939
2940 e = strrchr(p, '/');
2941 assert(e);
2942 if (e == p)
2943 *(e+1) = 0;
2944 else
2945 *e = 0;
2946
2947 r = object_find_and_run(bus, m, p, true, &found_object);
2948 if (r != 0)
2949 return r;
2950 }
2951
2952 } while (bus->nodes_modified);
2953
2954 if (!found_object)
2955 return 0;
2956
2957 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
2958 sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
2959 r = sd_bus_reply_method_errorf(
2960 bus, m,
2961 "org.freedesktop.DBus.Error.UnknownProperty",
2962 "Unknown property or interface.");
2963 else
2964 r = sd_bus_reply_method_errorf(
2965 bus, m,
2966 "org.freedesktop.DBus.Error.UnknownMethod",
2967 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
2968
2969 if (r < 0)
2970 return r;
2971
2972 return 1;
2973}
2974
2975static int process_message(sd_bus *bus, sd_bus_message *m) {
2976 int r;
2977
2978 assert(bus);
2979 assert(m);
2980
2981 bus->iteration_counter++;
2982
2983 r = process_hello(bus, m);
2984 if (r != 0)
2985 return r;
2986
2987 r = process_reply(bus, m);
2988 if (r != 0)
2989 return r;
2990
2991 r = process_filter(bus, m);
2992 if (r != 0)
2993 return r;
2994
2995 r = process_match(bus, m);
2996 if (r != 0)
2997 return r;
2998
2999 r = process_builtin(bus, m);
3000 if (r != 0)
3001 return r;
3002
3003 return process_object(bus, m);
3004}
3005
3006static int process_running(sd_bus *bus, sd_bus_message **ret) {
3007 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
3008 int r;
3009
3010 assert(bus);
3011 assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
3012
3013 r = process_timeout(bus);
3014 if (r != 0)
3015 goto null_message;
3016
3017 r = dispatch_wqueue(bus);
3018 if (r != 0)
3019 goto null_message;
3020
3021 r = dispatch_rqueue(bus, &m);
3022 if (r < 0)
3023 return r;
3024 if (!m)
3025 goto null_message;
3026
3027 r = process_message(bus, m);
3028 if (r != 0)
3029 goto null_message;
3030
3031 if (ret) {
3032 r = sd_bus_message_rewind(m, true);
3033 if (r < 0)
3034 return r;
3035
3036 *ret = m;
3037 m = NULL;
3038 return 1;
3039 }
3040
3041 if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
3042
3043 r = sd_bus_reply_method_errorf(
3044 bus, m,
3045 "org.freedesktop.DBus.Error.UnknownObject",
3046 "Unknown object '%s'.", m->path);
3047 if (r < 0)
3048 return r;
3049 }
3050
3051 return 1;
3052
3053null_message:
3054 if (r >= 0 && ret)
3055 *ret = NULL;
3056
3057 return r;
3058}
3059
3060int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
3061 int r;
3062
3063 /* Returns 0 when we didn't do anything. This should cause the
3064 * caller to invoke sd_bus_wait() before returning the next
a7e3212d
LP
3065 * time. Returns > 0 when we did something, which possibly
3066 * means *ret is filled in with an unprocessed message. */
de1c301e 3067
29ddb38f
LP
3068 if (!bus)
3069 return -EINVAL;
3070 if (bus_pid_changed(bus))
3071 return -ECHILD;
3072
3073 /* We don't allow recursively invoking sd_bus_process(). */
3074 if (bus->processing)
3075 return -EBUSY;
3076
3077 switch (bus->state) {
3078
3079 case BUS_UNSET:
3080 case BUS_CLOSED:
3081 return -ENOTCONN;
3082
3083 case BUS_OPENING:
3084 r = bus_socket_process_opening(bus);
3085 if (r < 0)
3086 return r;
3087 if (ret)
3088 *ret = NULL;
3089 return r;
3090
3091 case BUS_AUTHENTICATING:
3092
3093 r = bus_socket_process_authenticating(bus);
3094 if (r < 0)
3095 return r;
3096 if (ret)
3097 *ret = NULL;
3098 return r;
3099
3100 case BUS_RUNNING:
3101 case BUS_HELLO:
3102
3103 bus->processing = true;
3104 r = process_running(bus, ret);
3105 bus->processing = false;
3106
3107 return r;
3108 }
3109
3110 assert_not_reached("Unknown state");
3111}
3112
3113static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
3114 struct pollfd p[2] = {};
3115 int r, e, n;
3116 struct timespec ts;
3117 usec_t until, m;
3118
3119 assert(bus);
3120
3121 if (!BUS_IS_OPEN(bus->state))
3122 return -ENOTCONN;
3123
3124 e = sd_bus_get_events(bus);
3125 if (e < 0)
3126 return e;
3127
3128 if (need_more)
3129 e |= POLLIN;
3130
3131 r = sd_bus_get_timeout(bus, &until);
3132 if (r < 0)
3133 return r;
3134 if (r == 0)
3135 m = (uint64_t) -1;
3136 else {
3137 usec_t nw;
3138 nw = now(CLOCK_MONOTONIC);
3139 m = until > nw ? until - nw : 0;
3140 }
3141
3142 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
3143 m = timeout_usec;
3144
3145 p[0].fd = bus->input_fd;
3146 if (bus->output_fd == bus->input_fd) {
3147 p[0].events = e;
3148 n = 1;
3149 } else {
3150 p[0].events = e & POLLIN;
3151 p[1].fd = bus->output_fd;
3152 p[1].events = e & POLLOUT;
3153 n = 2;
3154 }
3155
3156 r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
3157 if (r < 0)
3158 return -errno;
3159
3160 return r > 0 ? 1 : 0;
3161}
3162
3163int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
3164
3165 if (!bus)
3166 return -EINVAL;
3167 if (!BUS_IS_OPEN(bus->state))
3168 return -ENOTCONN;
3169 if (bus_pid_changed(bus))
3170 return -ECHILD;
3171
3172 if (bus->rqueue_size > 0)
3173 return 0;
3174
3175 return bus_poll(bus, false, timeout_usec);
3176}
3177
3178int sd_bus_flush(sd_bus *bus) {
3179 int r;
3180
3181 if (!bus)
3182 return -EINVAL;
3183 if (!BUS_IS_OPEN(bus->state))
3184 return -ENOTCONN;
3185 if (bus_pid_changed(bus))
3186 return -ECHILD;
3187
3188 r = bus_ensure_running(bus);
3189 if (r < 0)
3190 return r;
3191
3192 if (bus->wqueue_size <= 0)
3193 return 0;
3194
3195 for (;;) {
3196 r = dispatch_wqueue(bus);
3197 if (r < 0)
3198 return r;
3199
3200 if (bus->wqueue_size <= 0)
3201 return 0;
3202
3203 r = bus_poll(bus, false, (uint64_t) -1);
3204 if (r < 0)
3205 return r;
3206 }
3207}
3208
3209int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata) {
3210 struct filter_callback *f;
3211
3212 if (!bus)
3213 return -EINVAL;
3214 if (!callback)
3215 return -EINVAL;
3216 if (bus_pid_changed(bus))
3217 return -ECHILD;
3218
3219 f = new0(struct filter_callback, 1);
3220 if (!f)
3221 return -ENOMEM;
3222 f->callback = callback;
3223 f->userdata = userdata;
3224
3225 bus->filter_callbacks_modified = true;
3226 LIST_PREPEND(struct filter_callback, callbacks, bus->filter_callbacks, f);
3227 return 0;
3228}
3229
3230int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata) {
3231 struct filter_callback *f;
3232
3233 if (!bus)
3234 return -EINVAL;
3235 if (!callback)
3236 return -EINVAL;
3237 if (bus_pid_changed(bus))
3238 return -ECHILD;
3239
3240 LIST_FOREACH(callbacks, f, bus->filter_callbacks) {
3241 if (f->callback == callback && f->userdata == userdata) {
3242 bus->filter_callbacks_modified = true;
3243 LIST_REMOVE(struct filter_callback, callbacks, bus->filter_callbacks, f);
3244 free(f);
3245 return 1;
3246 }
3247 }
3248
3249 return 0;
3250}
3251
3252static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
3253 struct node *n, *parent;
3254 const char *e;
3255 char *s, *p;
3256 int r;
3257
3258 assert(bus);
3259 assert(path);
3260 assert(path[0] == '/');
3261
3262 n = hashmap_get(bus->nodes, path);
3263 if (n)
3264 return n;
3265
3266 r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
3267 if (r < 0)
3268 return NULL;
3269
3270 s = strdup(path);
3271 if (!s)
3272 return NULL;
3273
3274 if (streq(path, "/"))
3275 parent = NULL;
3276 else {
3277 e = strrchr(path, '/');
3278 assert(e);
3279
3280 p = strndupa(path, MAX(1, path - e));
3281
3282 parent = bus_node_allocate(bus, p);
3283 if (!parent) {
3284 free(s);
3285 return NULL;
3286 }
3287 }
3288
3289 n = new0(struct node, 1);
3290 if (!n)
3291 return NULL;
3292
3293 n->parent = parent;
3294 n->path = s;
3295
3296 r = hashmap_put(bus->nodes, s, n);
3297 if (r < 0) {
3298 free(s);
3299 free(n);
3300 return NULL;
3301 }
3302
3303 if (parent)
3304 LIST_PREPEND(struct node, siblings, parent->child, n);
3305
3306 return n;
3307}
3308
3309static void bus_node_gc(sd_bus *b, struct node *n) {
3310 assert(b);
3311
3312 if (!n)
3313 return;
3314
3315 if (n->child ||
3316 n->callbacks ||
3317 n->vtables ||
3318 n->enumerators ||
3319 n->object_manager)
3320 return;
3321
3322 assert(hashmap_remove(b->nodes, n->path) == n);
3323
3324 if (n->parent)
3325 LIST_REMOVE(struct node, siblings, n->parent->child, n);
3326
3327 free(n->path);
3328 bus_node_gc(b, n->parent);
3329 free(n);
3330}
3331
3332static int bus_add_object(
3333 sd_bus *b,
3334 bool fallback,
3335 const char *path,
3336 sd_bus_message_handler_t callback,
3337 void *userdata) {
3338
3339 struct node_callback *c;
3340 struct node *n;
3341 int r;
3342
3343 if (!b)
3344 return -EINVAL;
3345 if (!object_path_is_valid(path))
3346 return -EINVAL;
3347 if (!callback)
3348 return -EINVAL;
3349 if (bus_pid_changed(b))
3350 return -ECHILD;
3351
3352 n = bus_node_allocate(b, path);
3353 if (!n)
3354 return -ENOMEM;
3355
3356 c = new0(struct node_callback, 1);
3357 if (!c) {
3358 r = -ENOMEM;
3359 goto fail;
3360 }
3361
3362 c->node = n;
3363 c->callback = callback;
3364 c->userdata = userdata;
3365 c->is_fallback = fallback;
3366
3367 LIST_PREPEND(struct node_callback, callbacks, n->callbacks, c);
3368 return 0;
3369
3370fail:
3371 free(c);
3372 bus_node_gc(b, n);
3373 return r;
3374}
3375
3376static int bus_remove_object(
3377 sd_bus *bus,
3378 bool fallback,
3379 const char *path,
3380 sd_bus_message_handler_t callback,
3381 void *userdata) {
3382
3383 struct node_callback *c;
3384 struct node *n;
3385
3386 if (!bus)
3387 return -EINVAL;
3388 if (!object_path_is_valid(path))
3389 return -EINVAL;
3390 if (!callback)
3391 return -EINVAL;
3392 if (bus_pid_changed(bus))
3393 return -ECHILD;
3394
3395 n = hashmap_get(bus->nodes, path);
3396 if (!n)
3397 return 0;
3398
3399 LIST_FOREACH(callbacks, c, n->callbacks)
3400 if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
3401 break;
3402 if (!c)
3403 return 0;
3404
3405 LIST_REMOVE(struct node_callback, callbacks, n->callbacks, c);
3406 free(c);
3407
3408 bus_node_gc(bus, n);
3409
3410 return 1;
3411}
3412
3413int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
3414 return bus_add_object(bus, false, path, callback, userdata);
3415}
3416
3417int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) {
3418 return bus_remove_object(bus, false, path, callback, userdata);
3419}
3420
3421int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
3422 return bus_add_object(bus, true, prefix, callback, userdata);
3423}
3424
3425int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) {
3426 return bus_remove_object(bus, true, prefix, callback, userdata);
3427}
3428
3429int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata) {
3430 struct bus_match_component *components = NULL;
3431 unsigned n_components = 0;
3432 uint64_t cookie = 0;
3433 int r = 0;
3434
3435 if (!bus)
3436 return -EINVAL;
3437 if (!match)
3438 return -EINVAL;
3439 if (bus_pid_changed(bus))
3440 return -ECHILD;
3441
3442 r = bus_match_parse(match, &components, &n_components);
3443 if (r < 0)
3444 goto finish;
3445
3446 if (bus->bus_client) {
3447 cookie = ++bus->match_cookie;
3448
3449 r = bus_add_match_internal(bus, match, components, n_components, cookie);
3450 if (r < 0)
3451 goto finish;
3452 }
3453
3454 bus->match_callbacks_modified = true;
3455 r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL);
3456 if (r < 0) {
3457 if (bus->bus_client)
3458 bus_remove_match_internal(bus, match, cookie);
3459 }
3460
3461finish:
3462 bus_match_parse_free(components, n_components);
3463 return r;
3464}
3465
3466int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata) {
3467 struct bus_match_component *components = NULL;
3468 unsigned n_components = 0;
3469 int r = 0, q = 0;
3470 uint64_t cookie = 0;
3471
3472 if (!bus)
3473 return -EINVAL;
3474 if (!match)
3475 return -EINVAL;
3476 if (bus_pid_changed(bus))
3477 return -ECHILD;
3478
3479 r = bus_match_parse(match, &components, &n_components);
3480 if (r < 0)
3481 return r;
3482
3483 bus->match_callbacks_modified = true;
3484 r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie);
3485
3486 if (bus->bus_client)
3487 q = bus_remove_match_internal(bus, match, cookie);
3488
3489 bus_match_parse_free(components, n_components);
3490
3491 return r < 0 ? r : q;
3492}
3493
3494int sd_bus_emit_signal(
3495 sd_bus *bus,
3496 const char *path,
3497 const char *interface,
3498 const char *member,
3499 const char *types, ...) {
3500
3501 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
29ddb38f
LP
3502 int r;
3503
3504 if (!bus)
3505 return -EINVAL;
3506 if (!BUS_IS_OPEN(bus->state))
3507 return -ENOTCONN;
3508 if (bus_pid_changed(bus))
3509 return -ECHILD;
3510
3511 r = sd_bus_message_new_signal(bus, path, interface, member, &m);
3512 if (r < 0)
3513 return r;
3514
5a037827
LP
3515 if (!isempty(types)) {
3516 va_list ap;
3517
3518 va_start(ap, types);
3519 r = bus_message_append_ap(m, types, ap);
3520 va_end(ap);
3521 if (r < 0)
3522 return r;
3523 }
29ddb38f
LP
3524
3525 return sd_bus_send(bus, m, NULL);
3526}
3527
3528int sd_bus_call_method(
3529 sd_bus *bus,
3530 const char *destination,
3531 const char *path,
3532 const char *interface,
3533 const char *member,
3534 sd_bus_error *error,
3535 sd_bus_message **reply,
3536 const char *types, ...) {
3537
3538 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
29ddb38f
LP
3539 int r;
3540
3541 if (!bus)
3542
3543 return -EINVAL;
3544 if (!BUS_IS_OPEN(bus->state))
3545 return -ENOTCONN;
3546 if (bus_pid_changed(bus))
3547 return -ECHILD;
3548
3549 r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
3550 if (r < 0)
3551 return r;
3552
5a037827
LP
3553 if (!isempty(types)) {
3554 va_list ap;
3555
3556 va_start(ap, types);
3557 r = bus_message_append_ap(m, types, ap);
3558 va_end(ap);
3559 if (r < 0)
3560 return r;
3561 }
29ddb38f
LP
3562
3563 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
3564}
3565
3566int sd_bus_reply_method_return(
3567 sd_bus *bus,
3568 sd_bus_message *call,
3569 const char *types, ...) {
3570
3571 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
29ddb38f
LP
3572 int r;
3573
3574 if (!bus)
3575 return -EINVAL;
3576 if (!call)
3577 return -EINVAL;
3578 if (!call->sealed)
3579 return -EPERM;
3580 if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
3581 return -EINVAL;
3582 if (!BUS_IS_OPEN(bus->state))
3583 return -ENOTCONN;
3584 if (bus_pid_changed(bus))
3585 return -ECHILD;
3586
3587 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
3588 return 0;
3589
3590 r = sd_bus_message_new_method_return(bus, call, &m);
3591 if (r < 0)
3592 return r;
3593
5a037827
LP
3594 if (!isempty(types)) {
3595 va_list ap;
3596
3597 va_start(ap, types);
3598 r = bus_message_append_ap(m, types, ap);
3599 va_end(ap);
3600 if (r < 0)
3601 return r;
3602 }
29ddb38f
LP
3603
3604 return sd_bus_send(bus, m, NULL);
3605}
3606
3607int sd_bus_reply_method_error(
3608 sd_bus *bus,
3609 sd_bus_message *call,
3610 const sd_bus_error *e) {
3611
3612 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
3613 int r;
3614
3615 if (!bus)
3616 return -EINVAL;
3617 if (!call)
3618 return -EINVAL;
3619 if (!call->sealed)
3620 return -EPERM;
3621 if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
3622 return -EINVAL;
3623 if (!sd_bus_error_is_set(e))
3624 return -EINVAL;
3625 if (!BUS_IS_OPEN(bus->state))
3626 return -ENOTCONN;
3627 if (bus_pid_changed(bus))
3628 return -ECHILD;
3629
3630 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
3631 return 0;
3632
3633 r = sd_bus_message_new_method_error(bus, call, e, &m);
3634 if (r < 0)
3635 return r;
3636
3637 return sd_bus_send(bus, m, NULL);
3638}
3639
3640int sd_bus_reply_method_errorf(
3641 sd_bus *bus,
3642 sd_bus_message *call,
3643 const char *name,
3644 const char *format,
3645 ...) {
3646
3647 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3648 char *n, *m;
3649 va_list ap;
3650 int r;
3651
3652 n = strdup(name);
3653 if (!n)
3654 return -ENOMEM;
3655
3656 if (format) {
3657 va_start(ap, format);
3658 r = vasprintf(&m, format, ap);
3659 va_end(ap);
3660
3661 if (r < 0) {
3662 free(n);
3663 return -ENOMEM;
3664 }
3665 }
3666
3667 error.name = n;
3668 error.message = m;
3669 error.need_free = true;
3670
3671 return sd_bus_reply_method_error(bus, call, &error);
3672}
3673
3674bool bus_pid_changed(sd_bus *bus) {
3675 assert(bus);
3676
3677 /* We don't support people creating a bus connection and
3678 * keeping it around over a fork(). Let's complain. */
3679
3680 return bus->original_pid != getpid();
3681}
3682
3683static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
3684 assert(bus);
3685
3686 if (!w)
3687 return;
3688
3689 if (w->interface && w->node && w->vtable) {
3690 const sd_bus_vtable *v;
3691
adcdb374 3692 for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
29ddb38f
LP
3693 struct vtable_member *x = NULL;
3694
3695 switch (v->type) {
3696
3697 case _SD_BUS_VTABLE_METHOD: {
3698 struct vtable_member key;
3699
3700 key.path = w->node->path;
3701 key.interface = w->interface;
3702 key.member = v->method.member;
3703
3704 x = hashmap_remove(bus->vtable_methods, &key);
3705 break;
3706 }
3707
3708 case _SD_BUS_VTABLE_PROPERTY:
3709 case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
3710 struct vtable_member key;
3711
3712 key.path = w->node->path;
3713 key.interface = w->interface;
3714 key.member = v->property.member;
3715 x = hashmap_remove(bus->vtable_properties, &key);
3716 break;
3717 }}
3718
3719 free(x);
3720 }
3721 }
3722
3723 free(w->interface);
3724 free(w);
3725}
3726
3727static unsigned vtable_member_hash_func(const void *a) {
3728 const struct vtable_member *m = a;
3729
3730 return
3731 string_hash_func(m->path) ^
3732 string_hash_func(m->interface) ^
3733 string_hash_func(m->member);
3734}
3735
3736static int vtable_member_compare_func(const void *a, const void *b) {
3737 const struct vtable_member *x = a, *y = b;
3738 int r;
3739
3740 r = strcmp(x->path, y->path);
3741 if (r != 0)
3742 return r;
3743
3744 r = strcmp(x->interface, y->interface);
3745 if (r != 0)
3746 return r;
3747
3748 return strcmp(x->member, y->member);
3749}
3750
3751static int add_object_vtable_internal(
3752 sd_bus *bus,
3753 const char *path,
3754 const char *interface,
3755 const sd_bus_vtable *vtable,
3756 bool fallback,
3757 sd_bus_object_find_t find,
3758 void *userdata) {
3759
753eff03 3760 struct node_vtable *c = NULL, *i;
29ddb38f
LP
3761 const sd_bus_vtable *v;
3762 struct node *n;
3763 int r;
3764
3765 if (!bus)
3766 return -EINVAL;
3767 if (!object_path_is_valid(path))
3768 return -EINVAL;
3769 if (!interface_name_is_valid(interface))
3770 return -EINVAL;
3771 if (!vtable || vtable[0].type != _SD_BUS_VTABLE_START || vtable[0].start.element_size != sizeof(struct sd_bus_vtable))
3772 return -EINVAL;
3773 if (bus_pid_changed(bus))
3774 return -ECHILD;
3775
3776 r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
3777 if (r < 0)
3778 return r;
3779
3780 r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
3781 if (r < 0)
3782 return r;
3783
3784 n = bus_node_allocate(bus, path);
3785 if (!n)
3786 return -ENOMEM;
3787
3788 LIST_FOREACH(vtables, i, n->vtables) {
3789 if (streq(i->interface, interface)) {
3790 r = -EEXIST;
3791 goto fail;
3792 }
3793
3794 if (i->is_fallback != fallback) {
3795 r = -EPROTOTYPE;
3796 goto fail;
3797 }
3798 }
3799
3800 c = new0(struct node_vtable, 1);
3801 if (!c) {
3802 r = -ENOMEM;
3803 goto fail;
3804 }
de1c301e 3805
29ddb38f
LP
3806 c->node = n;
3807 c->is_fallback = fallback;
3808 c->vtable = vtable;
3809 c->userdata = userdata;
3810 c->find = find;
6807947e 3811
29ddb38f
LP
3812 c->interface = strdup(interface);
3813 if (!c->interface) {
3814 r = -ENOMEM;
3815 goto fail;
3816 }
de1c301e 3817
29ddb38f 3818 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
de1c301e 3819
29ddb38f 3820 switch (v->type) {
b9bf7e2b 3821
29ddb38f
LP
3822 case _SD_BUS_VTABLE_METHOD: {
3823 struct vtable_member *m;
89ffcd2a 3824
29ddb38f 3825 if (!member_name_is_valid(v->method.member) ||
9db76355
LP
3826 !signature_is_valid(strempty(v->method.signature), false) ||
3827 !signature_is_valid(strempty(v->method.result), false) ||
43a43f50 3828 !(v->method.handler || (isempty(v->method.signature) && isempty(v->method.result))) ||
29ddb38f
LP
3829 v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) {
3830 r = -EINVAL;
3831 goto fail;
3832 }
89ffcd2a 3833
29ddb38f
LP
3834 m = new0(struct vtable_member, 1);
3835 if (!m) {
3836 r = -ENOMEM;
3837 goto fail;
3838 }
89ffcd2a 3839
29ddb38f
LP
3840 m->parent = c;
3841 m->path = n->path;
3842 m->interface = c->interface;
3843 m->member = v->method.member;
3844 m->vtable = v;
6807947e 3845
29ddb38f
LP
3846 r = hashmap_put(bus->vtable_methods, m, m);
3847 if (r < 0) {
3848 free(m);
3849 goto fail;
3850 }
de1c301e 3851
29ddb38f
LP
3852 break;
3853 }
de1c301e 3854
9db76355
LP
3855 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
3856
3857 if (!(v->property.set || bus_type_is_basic(v->property.signature[0]))) {
3858 r = -EINVAL;
3859 goto fail;
3860 }
3861
3862 /* Fall through */
3863
3864 case _SD_BUS_VTABLE_PROPERTY: {
29ddb38f 3865 struct vtable_member *m;
e3017af9 3866
29ddb38f
LP
3867 if (!member_name_is_valid(v->property.member) ||
3868 !signature_is_single(v->property.signature, false) ||
adcdb374 3869 !(v->property.get || bus_type_is_basic(v->property.signature[0])) ||
29ddb38f
LP
3870 v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
3871 (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))) {
3872 r = -EINVAL;
3873 goto fail;
3874 }
de1c301e 3875
89ffcd2a 3876
29ddb38f
LP
3877 m = new0(struct vtable_member, 1);
3878 if (!m) {
3879 r = -ENOMEM;
3880 goto fail;
3881 }
de1c301e 3882
29ddb38f
LP
3883 m->parent = c;
3884 m->path = n->path;
3885 m->interface = c->interface;
3886 m->member = v->property.member;
3887 m->vtable = v;
e3017af9 3888
29ddb38f
LP
3889 r = hashmap_put(bus->vtable_properties, m, m);
3890 if (r < 0) {
3891 free(m);
3892 goto fail;
3893 }
e3017af9 3894
29ddb38f
LP
3895 break;
3896 }
e3017af9 3897
29ddb38f
LP
3898 case _SD_BUS_VTABLE_SIGNAL:
3899
3900 if (!member_name_is_valid(v->signal.member) ||
9db76355 3901 !signature_is_single(strempty(v->signal.signature), false)) {
29ddb38f
LP
3902 r = -EINVAL;
3903 goto fail;
3904 }
3905
3906 break;
3907
3908 default:
3909 r = -EINVAL;
3910 goto fail;
3911 }
e82c9509 3912 }
de1c301e 3913
29ddb38f
LP
3914 LIST_PREPEND(struct node_vtable, vtables, n->vtables, c);
3915 return 0;
de1c301e 3916
29ddb38f
LP
3917fail:
3918 if (c)
3919 free_node_vtable(bus, c);
3920
3921 bus_node_gc(bus, n);
adcdb374 3922 return r;
e3017af9
LP
3923}
3924
29ddb38f
LP
3925static int remove_object_vtable_internal(
3926 sd_bus *bus,
3927 const char *path,
3928 const char *interface,
3929 bool fallback) {
3930
3931 struct node_vtable *c;
3932 struct node *n;
e3017af9
LP
3933
3934 if (!bus)
3935 return -EINVAL;
29ddb38f
LP
3936 if (!object_path_is_valid(path))
3937 return -EINVAL;
3938 if (!interface_name_is_valid(interface))
3939 return -EINVAL;
d5a2b9a6
LP
3940 if (bus_pid_changed(bus))
3941 return -ECHILD;
3942
29ddb38f
LP
3943 n = hashmap_get(bus->nodes, path);
3944 if (!n)
e3017af9
LP
3945 return 0;
3946
29ddb38f
LP
3947 LIST_FOREACH(vtables, c, n->vtables)
3948 if (streq(c->interface, interface) && c->is_fallback == fallback)
3949 break;
de1c301e 3950
29ddb38f
LP
3951 if (!c)
3952 return 0;
de1c301e 3953
29ddb38f 3954 LIST_REMOVE(struct node_vtable, vtables, n->vtables, c);
de1c301e 3955
29ddb38f
LP
3956 free_node_vtable(bus, c);
3957 return 1;
3958}
89ffcd2a 3959
29ddb38f
LP
3960int sd_bus_add_object_vtable(
3961 sd_bus *bus,
3962 const char *path,
3963 const char *interface,
3964 const sd_bus_vtable *vtable,
3965 void *userdata) {
de1c301e 3966
29ddb38f
LP
3967 return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
3968}
de1c301e 3969
29ddb38f
LP
3970int sd_bus_remove_object_vtable(
3971 sd_bus *bus,
3972 const char *path,
3973 const char *interface) {
de1c301e 3974
29ddb38f 3975 return remove_object_vtable_internal(bus, path, interface, false);
de1c301e
LP
3976}
3977
29ddb38f
LP
3978int sd_bus_add_fallback_vtable(
3979 sd_bus *bus,
3980 const char *path,
3981 const char *interface,
3982 const sd_bus_vtable *vtable,
3983 sd_bus_object_find_t find,
3984 void *userdata) {
de1c301e 3985
29ddb38f
LP
3986 return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
3987}
de1c301e 3988
29ddb38f
LP
3989int sd_bus_remove_fallback_vtable(
3990 sd_bus *bus,
3991 const char *path,
3992 const char *interface) {
de1c301e 3993
29ddb38f 3994 return remove_object_vtable_internal(bus, path, interface, true);
de1c301e
LP
3995}
3996
29ddb38f
LP
3997int sd_bus_add_node_enumerator(
3998 sd_bus *bus,
3999 const char *path,
4000 sd_bus_node_enumerator_t callback,
4001 void *userdata) {
4002
4003 struct node_enumerator *c;
4004 struct node *n;
4005 int r;
de1c301e
LP
4006
4007 if (!bus)
4008 return -EINVAL;
29ddb38f
LP
4009 if (!object_path_is_valid(path))
4010 return -EINVAL;
de1c301e
LP
4011 if (!callback)
4012 return -EINVAL;
d5a2b9a6
LP
4013 if (bus_pid_changed(bus))
4014 return -ECHILD;
de1c301e 4015
29ddb38f
LP
4016 n = bus_node_allocate(bus, path);
4017 if (!n)
4018 return -ENOMEM;
4019
4020 c = new0(struct node_enumerator, 1);
4021 if (!c) {
4022 r = -ENOMEM;
4023 goto fail;
de1c301e
LP
4024 }
4025
29ddb38f
LP
4026 c->node = n;
4027 c->callback = callback;
4028 c->userdata = userdata;
4029
4030 LIST_PREPEND(struct node_enumerator, enumerators, n->enumerators, c);
de1c301e 4031 return 0;
29ddb38f
LP
4032
4033fail:
4034 free(c);
4035 bus_node_gc(bus, n);
4036 return r;
de1c301e 4037}
a652755d 4038
29ddb38f 4039int sd_bus_remove_node_enumerator(
a652755d 4040 sd_bus *bus,
a652755d 4041 const char *path,
29ddb38f 4042 sd_bus_node_enumerator_t callback,
a652755d
LP
4043 void *userdata) {
4044
29ddb38f
LP
4045 struct node_enumerator *c;
4046 struct node *n;
a652755d
LP
4047
4048 if (!bus)
4049 return -EINVAL;
29ddb38f 4050 if (!object_path_is_valid(path))
a652755d
LP
4051 return -EINVAL;
4052 if (!callback)
4053 return -EINVAL;
d5a2b9a6
LP
4054 if (bus_pid_changed(bus))
4055 return -ECHILD;
a652755d 4056
29ddb38f
LP
4057 n = hashmap_get(bus->nodes, path);
4058 if (!n)
4059 return 0;
4060
4061 LIST_FOREACH(enumerators, c, n->enumerators)
4062 if (c->callback == callback && c->userdata == userdata)
4063 break;
4064
4065 if (!c)
4066 return 0;
4067
4068 LIST_REMOVE(struct node_enumerator, enumerators, n->enumerators, c);
4069 free(c);
4070
4071 bus_node_gc(bus, n);
4072
4073 return 1;
4074}
4075
4076static int emit_properties_changed_on_interface(
4077 sd_bus *bus,
4078 const char *prefix,
4079 const char *path,
4080 const char *interface,
4081 bool require_fallback,
4082 char **names) {
4083
4084 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4085 bool has_invalidating = false;
4086 struct vtable_member key;
4087 struct node_vtable *c;
4088 struct node *n;
4089 char **property;
486e950b 4090 void *u = NULL;
29ddb38f
LP
4091 int r;
4092
4093 assert(bus);
4094 assert(path);
4095 assert(interface);
4096
4097 n = hashmap_get(bus->nodes, prefix);
4098 if (!n)
4099 return 0;
4100
4101 LIST_FOREACH(vtables, c, n->vtables) {
4102 if (require_fallback && !c->is_fallback)
4103 continue;
4104
4105 if (streq(c->interface, interface))
4106 break;
29ddb38f
LP
4107 }
4108
4109 if (!c)
4110 return 0;
4111
62b5c2ae
LP
4112 r = node_vtable_get_userdata(bus, path, c, &u);
4113 if (r <= 0)
4114 return r;
4115
4116 r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
29ddb38f
LP
4117 if (r < 0)
4118 return r;
4119
4120 r = sd_bus_message_append(m, "s", interface);
4121 if (r < 0)
4122 return r;
4123
4124 r = sd_bus_message_open_container(m, 'a', "{sv}");
a652755d
LP
4125 if (r < 0)
4126 return r;
4127
29ddb38f
LP
4128 key.path = prefix;
4129 key.interface = interface;
a652755d 4130
29ddb38f
LP
4131 STRV_FOREACH(property, names) {
4132 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4133 struct vtable_member *v;
a652755d 4134
29ddb38f
LP
4135 key.member = *property;
4136 v = hashmap_get(bus->vtable_properties, &key);
4137 if (!v)
4138 return -ENOENT;
a652755d 4139
29ddb38f 4140 assert(c == v->parent);
a652755d 4141
29ddb38f
LP
4142 if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
4143 return -EDOM;
4144 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
4145 has_invalidating = true;
4146 continue;
4147 }
a652755d 4148
29ddb38f
LP
4149 r = sd_bus_message_open_container(m, 'e', "sv");
4150 if (r < 0)
4151 return r;
a652755d 4152
62b5c2ae 4153 r = sd_bus_message_append(m, "s", *property);
29ddb38f
LP
4154 if (r < 0)
4155 return r;
a652755d 4156
29ddb38f
LP
4157 r = sd_bus_message_open_container(m, 'v', v->vtable->property.signature);
4158 if (r < 0)
4159 return r;
a652755d 4160
adcdb374 4161 r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
29ddb38f
LP
4162 if (r < 0)
4163 return r;
a652755d 4164
29ddb38f
LP
4165 if (sd_bus_error_is_set(&error))
4166 return bus_error_to_errno(&error);
a652755d 4167
29ddb38f
LP
4168 r = sd_bus_message_close_container(m);
4169 if (r < 0)
4170 return r;
a652755d 4171
29ddb38f
LP
4172 r = sd_bus_message_close_container(m);
4173 if (r < 0)
4174 return r;
4175 }
a652755d 4176
29ddb38f
LP
4177 r = sd_bus_message_close_container(m);
4178 if (r < 0)
4179 return r;
a652755d 4180
29ddb38f
LP
4181 r = sd_bus_message_open_container(m, 'a', "s");
4182 if (r < 0)
4183 return r;
a652755d 4184
29ddb38f
LP
4185 if (has_invalidating) {
4186 STRV_FOREACH(property, names) {
4187 struct vtable_member *v;
a652755d 4188
29ddb38f
LP
4189 key.member = *property;
4190 assert_se(v = hashmap_get(bus->vtable_properties, &key));
4191 assert(c == v->parent);
a652755d 4192
29ddb38f
LP
4193 if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
4194 continue;
4195
4196 r = sd_bus_message_append(m, "s", *property);
4197 if (r < 0)
4198 return r;
4199 }
4200 }
4201
4202 r = sd_bus_message_close_container(m);
4203 if (r < 0)
4204 return r;
4205
4206 r = sd_bus_send(bus, m, NULL);
4207 if (r < 0)
4208 return r;
4209
4210 return 1;
a652755d 4211}
392d5b37 4212
29ddb38f
LP
4213int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names) {
4214 size_t pl;
4215 int r;
392d5b37
LP
4216
4217 if (!bus)
4218 return -EINVAL;
29ddb38f
LP
4219 if (!object_path_is_valid(path))
4220 return -EINVAL;
4221 if (!interface_name_is_valid(interface))
392d5b37
LP
4222 return -EINVAL;
4223
29ddb38f
LP
4224 r = emit_properties_changed_on_interface(bus, path, path, interface, false, names);
4225 if (r != 0)
4226 return r;
c7819669 4227
29ddb38f
LP
4228 pl = strlen(path);
4229 if (pl > 1 ) {
4230 char p[pl+1];
c7819669 4231
29ddb38f
LP
4232 strcpy(p, path);
4233 for (;;) {
4234 char *e;
392d5b37 4235
29ddb38f
LP
4236 if (streq(p, "/"))
4237 break;
4238
4239 e = strrchr(p, '/');
4240 assert(e);
4241 if (e == p)
4242 *(e+1) = 0;
4243 else
4244 *e = 0;
4245
4246 r = emit_properties_changed_on_interface(bus, p, path, interface, true, names);
4247 if (r != 0)
4248 return r;
4249 }
392d5b37
LP
4250 }
4251
29ddb38f 4252 return -ENOENT;
392d5b37
LP
4253}
4254
29ddb38f
LP
4255int sd_bus_emit_properties_changed(sd_bus *bus, const char *path, const char *interface, const char *name, ...) {
4256 _cleanup_strv_free_ char **names = NULL;
4257 va_list ap;
392d5b37 4258
29ddb38f
LP
4259 va_start(ap, name);
4260 names = strv_new_ap(name, ap);
4261 va_end(ap);
c7819669 4262
29ddb38f
LP
4263 if (!names)
4264 return -ENOMEM;
c7819669 4265
29ddb38f
LP
4266 return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
4267}
392d5b37 4268
29ddb38f
LP
4269int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interfaces, ...) {
4270 return -ENOSYS;
4271}
392d5b37 4272
29ddb38f
LP
4273int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interfaces, ...) {
4274 return -ENOSYS;
392d5b37 4275}
917b5dc7 4276
29ddb38f 4277int sd_bus_get_property(
917b5dc7 4278 sd_bus *bus,
29ddb38f 4279 const char *destination,
917b5dc7
LP
4280 const char *path,
4281 const char *interface,
4282 const char *member,
29ddb38f
LP
4283 sd_bus_error *error,
4284 sd_bus_message **reply,
4285 const char *type) {
917b5dc7 4286
29ddb38f 4287 sd_bus_message *rep = NULL;
917b5dc7
LP
4288 int r;
4289
29ddb38f
LP
4290 if (interface && !interface_name_is_valid(interface))
4291 return -EINVAL;
4292 if (!member_name_is_valid(member))
4293 return -EINVAL;
4294 if (!signature_is_single(type, false))
4295 return -EINVAL;
4296 if (!reply)
917b5dc7
LP
4297 return -EINVAL;
4298
29ddb38f 4299 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
917b5dc7
LP
4300 if (r < 0)
4301 return r;
4302
29ddb38f
LP
4303 r = sd_bus_message_enter_container(rep, 'v', type);
4304 if (r < 0) {
4305 sd_bus_message_unref(rep);
917b5dc7 4306 return r;
29ddb38f 4307 }
917b5dc7 4308
29ddb38f
LP
4309 *reply = rep;
4310 return 0;
917b5dc7
LP
4311}
4312
29ddb38f 4313int sd_bus_set_property(
917b5dc7
LP
4314 sd_bus *bus,
4315 const char *destination,
4316 const char *path,
4317 const char *interface,
4318 const char *member,
4319 sd_bus_error *error,
29ddb38f 4320 const char *type, ...) {
917b5dc7
LP
4321
4322 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4323 va_list ap;
4324 int r;
4325
29ddb38f
LP
4326 if (interface && !interface_name_is_valid(interface))
4327 return -EINVAL;
4328 if (!member_name_is_valid(member))
4329 return -EINVAL;
4330 if (!signature_is_single(type, false))
917b5dc7
LP
4331 return -EINVAL;
4332
29ddb38f 4333 r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
917b5dc7
LP
4334 if (r < 0)
4335 return r;
4336
29ddb38f
LP
4337 r = sd_bus_message_append(m, "ss", strempty(interface), member);
4338 if (r < 0)
4339 return r;
4340
4341 r = sd_bus_message_open_container(m, 'v', type);
4342 if (r < 0)
4343 return r;
4344
4345 va_start(ap, type);
4346 r = bus_message_append_ap(m, type, ap);
917b5dc7
LP
4347 va_end(ap);
4348 if (r < 0)
4349 return r;
4350
29ddb38f
LP
4351 r = sd_bus_message_close_container(m);
4352 if (r < 0)
4353 return r;
f10dda3b 4354
29ddb38f
LP
4355 return sd_bus_send_with_reply_and_block(bus, m, 0, error, NULL);
4356}
f10dda3b 4357
29ddb38f
LP
4358int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
4359 struct node *n;
f10dda3b
LP
4360
4361 if (!bus)
4362 return -EINVAL;
29ddb38f 4363 if (!object_path_is_valid(path))
f10dda3b 4364 return -EINVAL;
d5a2b9a6
LP
4365 if (bus_pid_changed(bus))
4366 return -ECHILD;
f10dda3b 4367
29ddb38f
LP
4368 n = bus_node_allocate(bus, path);
4369 if (!n)
4370 return -ENOMEM;
f10dda3b 4371
29ddb38f
LP
4372 n->object_manager = true;
4373 return 0;
f10dda3b
LP
4374}
4375
29ddb38f
LP
4376int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
4377 struct node *n;
f10dda3b
LP
4378
4379 if (!bus)
4380 return -EINVAL;
29ddb38f 4381 if (!object_path_is_valid(path))
f10dda3b 4382 return -EINVAL;
d5a2b9a6
LP
4383 if (bus_pid_changed(bus))
4384 return -ECHILD;
f10dda3b 4385
29ddb38f
LP
4386 n = hashmap_get(bus->nodes, path);
4387 if (!n)
f10dda3b
LP
4388 return 0;
4389
29ddb38f
LP
4390 if (!n->object_manager)
4391 return 0;
d5a2b9a6 4392
29ddb38f
LP
4393 n->object_manager = false;
4394 bus_node_gc(bus, n);
4395 return 1;
d5a2b9a6 4396}