]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus.c
core: convert PID 1 to libsystemd-bus
[thirdparty/systemd.git] / src / core / dbus.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ea430986 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986
LP
22#include <sys/epoll.h>
23#include <sys/timerfd.h>
24#include <errno.h>
25#include <unistd.h>
26
718db961 27#include "sd-bus.h"
ea430986
LP
28#include "log.h"
29#include "strv.h"
49e942b2 30#include "mkdir.h"
4db17f29 31#include "missing.h"
4139c1b2
LP
32#include "dbus-unit.h"
33#include "dbus-job.h"
34#include "dbus-manager.h"
718db961
LP
35#include "dbus-execute.h"
36#include "dbus-kill.h"
37#include "dbus-cgroup.h"
8f6df3fa 38#include "special.h"
718db961
LP
39#include "dbus.h"
40#include "bus-util.h"
41#include "bus-error.h"
42#include "bus-errors.h"
43#include "strxcpyx.h"
44#include "dbus-client-track.h"
4288f619 45
417b1a62 46#define CONNECTIONS_MAX 512
5e8d1c9a 47
718db961
LP
48static void destroy_bus(Manager *m, sd_bus **bus);
49
50int bus_send_queued_message(Manager *m) {
51 int r;
8e274523 52
8e274523 53 assert(m);
2e317f52 54
718db961
LP
55 if (!m->queued_message)
56 return 0;
8e274523 57
718db961 58 assert(m->queued_message_bus);
8e274523 59
718db961
LP
60 /* If we cannot get rid of this message we won't dispatch any
61 * D-Bus messages, so that we won't end up wanting to queue
62 * another message. */
ea430986 63
718db961
LP
64 r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
65 if (r < 0)
66 log_warning("Failed to send queued message: %s", strerror(-r));
ea430986 67
718db961
LP
68 m->queued_message = sd_bus_message_unref(m->queued_message);
69 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
ea430986 70
718db961 71 return 0;
ea430986
LP
72}
73
718db961
LP
74static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata) {
75 Manager *m = userdata;
76 const char *cgroup;
77 int r;
ea430986 78
718db961
LP
79 assert(bus);
80 assert(message);
ea430986
LP
81 assert(m);
82
718db961
LP
83 r = sd_bus_message_read(message, "s", &cgroup);
84 if (r < 0) {
85 bus_log_parse_error(r);
86 return 0;
87 }
ea430986 88
718db961 89 manager_notify_cgroup_empty(m, cgroup);
ea430986 90
718db961
LP
91 if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) {
92 /* If we are running as system manager, forward the
93 * message to the system bus */
ea430986 94
718db961
LP
95 r = sd_bus_send(m->system_bus, message, NULL);
96 if (r < 0)
97 log_warning("Failed to forward Released message: %s", strerror(-r));
98 }
ea430986 99
718db961
LP
100 return 0;
101}
ea430986 102
718db961
LP
103static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata) {
104 Manager *m = userdata;
ea430986 105
718db961
LP
106 assert(bus);
107 assert(message);
108 assert(m);
ea430986 109
718db961
LP
110 if (bus == m->api_bus)
111 destroy_bus(m, &m->api_bus);
112 if (bus == m->system_bus)
113 destroy_bus(m, &m->system_bus);
114 if (set_remove(m->private_buses, bus)) {
115 log_debug("Got disconnect on private connection.");
116 destroy_bus(m, &bus);
ea430986
LP
117 }
118
718db961 119 return 0;
ea430986
LP
120}
121
718db961
LP
122static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
123 const char *name, *old_owner, *new_owner;
124 Manager *m = userdata;
125 int r;
ea430986 126
718db961
LP
127 assert(bus);
128 assert(message);
ea430986
LP
129 assert(m);
130
718db961
LP
131 r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
132 if (r < 0) {
133 bus_log_parse_error(r);
134 return 0;
135 }
ea430986 136
718db961
LP
137 manager_dispatch_bus_name_owner_changed(
138 m, name,
139 isempty(old_owner) ? NULL : old_owner,
140 isempty(new_owner) ? NULL : new_owner);
ea430986 141
718db961 142 return 0;
ea430986
LP
143}
144
718db961
LP
145static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata) {
146 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
147 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
148 Manager *m = userdata;
149 const char *name;
150 Unit *u;
151 int r;
ea430986 152
718db961
LP
153 assert(bus);
154 assert(message);
ea430986
LP
155 assert(m);
156
718db961
LP
157 r = sd_bus_message_read(message, "s", &name);
158 if (r < 0) {
159 bus_log_parse_error(r);
160 return 0;
161 }
ea430986 162
718db961
LP
163 if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
164 manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
165 r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
166 goto failed;
167 }
ea430986 168
718db961
LP
169 r = manager_load_unit(m, name, NULL, &error, &u);
170 if (r < 0)
171 goto failed;
ea430986 172
718db961
LP
173 if (u->refuse_manual_start) {
174 r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %u may be requested by dependency only.", u->id);
175 goto failed;
ea430986
LP
176 }
177
718db961
LP
178 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
179 if (r < 0)
180 goto failed;
ea430986 181
718db961 182 /* Successfully queued, that's it for us */
ea430986 183 return 0;
ea430986 184
718db961
LP
185failed:
186 if (!sd_bus_error_is_set(&error))
187 sd_bus_error_set_errno(&error, r);
ea430986 188
718db961 189 log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
ea430986 190
718db961
LP
191 r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure", &reply);
192 if (r < 0) {
193 bus_log_create_error(r);
194 return 0;
195 }
196
197 r = sd_bus_message_append(reply, "sss", error.name, error.message);
198 if (r < 0) {
199 bus_log_create_error(r);
200 return 0;
201 }
202
203 r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
204 if (r < 0) {
205 log_error("Failed to respond with to bus activation request: %s", strerror(-r));
206 return r;
207 }
ea430986 208
718db961 209 return 0;
ea430986
LP
210}
211
718db961
LP
212static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
213 Manager *m = userdata;
214 Job *j;
215 int r;
ea430986 216
718db961
LP
217 assert(bus);
218 assert(path);
219 assert(interface);
220 assert(found);
ea430986
LP
221 assert(m);
222
718db961
LP
223 r = manager_get_job_from_dbus_path(m, path, &j);
224 if (r < 0)
225 return 0;
ea430986 226
718db961
LP
227 *found = j;
228 return 1;
229}
ea430986 230
718db961
LP
231static Unit *find_unit(Manager *m, sd_bus *bus, const char *path) {
232 Unit *u;
233 int r;
ea430986 234
718db961
LP
235 assert(m);
236 assert(bus);
237 assert(path);
ea430986 238
718db961
LP
239 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
240 sd_bus_message *message;
241 pid_t pid;
ea430986 242
718db961
LP
243 message = sd_bus_get_current(bus);
244 if (!message)
245 return NULL;
ea430986 246
718db961
LP
247 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
248 if (r < 0)
249 return NULL;
ea430986 250
718db961
LP
251 u = manager_get_unit_by_pid(m, pid);
252 } else {
253 r = manager_load_unit_from_dbus_path(m, path, NULL, &u);
254 if (r < 0)
255 return NULL;
256 }
ea430986 257
718db961 258 return u;
ea430986
LP
259}
260
718db961
LP
261static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
262 Manager *m = userdata;
263 Unit *u;
ea430986 264
718db961
LP
265 assert(bus);
266 assert(path);
267 assert(interface);
268 assert(found);
ea430986
LP
269 assert(m);
270
718db961
LP
271 u = find_unit(m, bus, path);
272 if (!u)
273 return 0;
3df5bf61 274
718db961
LP
275 *found = u;
276 return 1;
ea430986
LP
277}
278
718db961
LP
279static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
280 Manager *m = userdata;
281 Unit *u;
ea430986 282
718db961
LP
283 assert(bus);
284 assert(path);
285 assert(interface);
286 assert(found);
ea430986
LP
287 assert(m);
288
718db961
LP
289 u = find_unit(m, bus, path);
290 if (!u)
291 return 0;
3df5bf61 292
718db961
LP
293 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
294 return 0;
ea430986 295
718db961
LP
296 *found = u;
297 return 1;
ea430986
LP
298}
299
718db961
LP
300static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
301 Manager *m = userdata;
302 Unit *u;
c1e1601e 303
718db961
LP
304 assert(bus);
305 assert(path);
306 assert(interface);
307 assert(found);
c1e1601e
LP
308 assert(m);
309
718db961
LP
310 u = find_unit(m, bus, path);
311 if (!u)
312 return 0;
05e343b7 313
718db961
LP
314 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
315 return 0;
05e343b7 316
718db961
LP
317 if (!unit_get_cgroup_context(u))
318 return 0;
0034c15c 319
718db961
LP
320 *found = u;
321 return 1;
322}
0034c15c 323
718db961
LP
324static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
325 Manager *m = userdata;
326 CGroupContext *c;
327 Unit *u;
af25ec12 328
718db961
LP
329 assert(bus);
330 assert(path);
331 assert(interface);
332 assert(found);
333 assert(m);
0034c15c 334
718db961
LP
335 u = find_unit(m, bus, path);
336 if (!u)
337 return 0;
0034c15c 338
718db961
LP
339 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
340 return 0;
0034c15c 341
718db961
LP
342 c = unit_get_cgroup_context(u);
343 if (!c)
344 return 0;
c1e1601e 345
718db961
LP
346 *found = c;
347 return 1;
348}
0034c15c 349
718db961
LP
350static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
351 Manager *m = userdata;
352 ExecContext *c;
353 Unit *u;
0034c15c 354
718db961
LP
355 assert(bus);
356 assert(path);
357 assert(interface);
358 assert(found);
359 assert(m);
0034c15c 360
718db961
LP
361 u = find_unit(m, bus, path);
362 if (!u)
363 return 0;
0034c15c 364
718db961
LP
365 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
366 return 0;
0034c15c 367
718db961
LP
368 c = unit_get_exec_context(u);
369 if (!c)
370 return 0;
0034c15c 371
718db961
LP
372 *found = c;
373 return 1;
c1e1601e
LP
374}
375
718db961
LP
376static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
377 Manager *m = userdata;
378 KillContext *c;
379 Unit *u;
8e274523 380
718db961
LP
381 assert(bus);
382 assert(path);
383 assert(interface);
384 assert(found);
8e274523
LP
385 assert(m);
386
718db961
LP
387 u = find_unit(m, bus, path);
388 if (!u)
389 return 0;
8e274523 390
718db961
LP
391 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
392 return 0;
8e274523 393
718db961
LP
394 c = unit_get_kill_context(u);
395 if (!c)
396 return 0;
53c6a358 397
718db961
LP
398 *found = c;
399 return 1;
400}
8e274523 401
718db961
LP
402static int bus_job_enumerate(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
403 _cleanup_free_ char **l = NULL;
404 Manager *m = userdata;
405 unsigned k = 0;
406 Iterator i;
407 Job *j;
8e274523 408
718db961
LP
409 l = new0(char*, hashmap_size(m->jobs)+1);
410 if (!l)
411 return -ENOMEM;
8e274523 412
718db961
LP
413 HASHMAP_FOREACH(j, m->jobs, i) {
414 l[k] = job_dbus_path(j);
415 if (!l[k])
416 return -ENOMEM;
5e8d1c9a 417
718db961
LP
418 k++;
419 }
5e8d1c9a 420
718db961 421 assert(hashmap_size(m->jobs) == k);
3c661fad 422
718db961
LP
423 *nodes = l;
424 l = NULL;
5e8d1c9a 425
718db961
LP
426 return k;
427}
53c6a358 428
718db961
LP
429static int bus_unit_enumerate(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
430 _cleanup_free_ char **l = NULL;
431 Manager *m = userdata;
432 unsigned k = 0;
433 Iterator i;
434 Unit *u;
3c661fad 435
718db961
LP
436 l = new0(char*, hashmap_size(m->units)+1);
437 if (!l)
438 return -ENOMEM;
53c6a358 439
718db961
LP
440 HASHMAP_FOREACH(u, m->units, i) {
441 l[k] = unit_dbus_path(u);
442 if (!l[k])
443 return -ENOMEM;
53c6a358 444
718db961 445 k++;
3c661fad
LP
446 }
447
718db961
LP
448 *nodes = l;
449 l = NULL;
5e8d1c9a 450
718db961 451 return k;
5e8d1c9a
LP
452}
453
718db961
LP
454static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
455 UnitType t;
456 int r;
5e8d1c9a 457
ea430986 458 assert(m);
718db961 459 assert(bus);
ea430986 460
718db961
LP
461 r = sd_bus_add_object_vtable(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
462 if (r < 0) {
463 log_error("Failed to register Manager vtable: %s", strerror(-r));
464 return r;
a16e1123
LP
465 }
466
718db961
LP
467 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
468 if (r < 0) {
469 log_error("Failed to register Job vtable: %s", strerror(-r));
470 return r;
fd18e1f4 471 }
c1e1601e 472
718db961
LP
473 r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
474 if (r < 0) {
475 log_error("Failed to add job enumerator: %s", strerror(-r));
476 return r;
477 }
61902ea3 478
718db961
LP
479 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
480 if (r < 0) {
481 log_error("Failed to register Unit vtable: %s", strerror(-r));
482 return r;
483 }
61902ea3 484
718db961
LP
485 r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
486 if (r < 0) {
487 log_error("Failed to add job enumerator: %s", strerror(-r));
488 return r;
489 }
61902ea3 490
718db961
LP
491 for (t = 0; t < _UNIT_TYPE_MAX; t++) {
492 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
493 if (r < 0) {
494 log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
495 return r;
496 }
61902ea3 497
718db961
LP
498 if (unit_vtable[t]->cgroup_context_offset > 0) {
499 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
500 if (r < 0) {
501 log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
502 return r;
503 }
61902ea3 504
718db961
LP
505 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
506 if (r < 0) {
507 log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
508 return r;
509 }
61902ea3
LP
510 }
511
718db961
LP
512 if (unit_vtable[t]->exec_context_offset > 0) {
513 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
514 if (r < 0) {
515 log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
516 return r;
517 }
518 }
61902ea3 519
718db961
LP
520 if (unit_vtable[t]->kill_context_offset > 0) {
521 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
522 if (r < 0) {
523 log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
524 return r;
525 }
526 }
61902ea3
LP
527 }
528
718db961 529 return 0;
61902ea3
LP
530}
531
718db961
LP
532static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
533 int r;
61902ea3 534
718db961
LP
535 assert(m);
536 assert(bus);
61902ea3 537
718db961
LP
538 r = sd_bus_add_match(
539 bus,
540 "type='signal',"
541 "path='/org/freedesktop/DBus/Local',"
542 "interface='org.freedesktop.DBus.Local',"
543 "member='Disconnected'",
544 signal_disconnected, m);
05e343b7 545
718db961
LP
546 if (r < 0) {
547 log_error("Failed to register match for Disconnected message: %s", strerror(-r));
548 return r;
05e343b7
LP
549 }
550
718db961 551 return 0;
ea430986
LP
552}
553
718db961
LP
554static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
555 _cleanup_bus_unref_ sd_bus *bus = NULL;
556 _cleanup_close_ int nfd = -1;
6dded4c7 557 Manager *m = userdata;
718db961
LP
558 sd_id128_t id;
559 int r;
6dded4c7 560
718db961 561 assert(s);
6dded4c7
LP
562 assert(m);
563
718db961
LP
564 nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
565 if (nfd < 0) {
566 log_warning("Failed to accept private connection, ignoring: %m");
567 return 0;
568 }
6dded4c7 569
718db961
LP
570 if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
571 log_warning("Too many concurrent connections, refusing");
572 return 0;
573 }
6dded4c7 574
718db961
LP
575 r = set_ensure_allocated(&m->private_buses, trivial_hash_func, trivial_compare_func);
576 if (r < 0) {
577 log_oom();
578 return 0;
579 }
6dded4c7 580
718db961
LP
581 r = sd_bus_new(&bus);
582 if (r < 0) {
583 log_warning("Failed to allocate new private connection bus: %s", strerror(-r));
584 return 0;
585 }
6dded4c7 586
718db961
LP
587 r = sd_bus_set_fd(bus, nfd, nfd);
588 if (r < 0) {
589 log_warning("Failed to set fd on new connection bus: %s", strerror(-r));
590 return 0;
591 }
6dded4c7 592
718db961 593 nfd = -1;
6dded4c7 594
718db961
LP
595 r = bus_check_peercred(bus);
596 if (r < 0) {
597 log_warning("Incoming private connection from unprivileged client, refusing: %s", strerror(-r));
598 return 0;
599 }
6dded4c7 600
718db961 601 assert_se(sd_id128_randomize(&id) >= 0);
6dded4c7 602
718db961
LP
603 r = sd_bus_set_server(bus, 1, id);
604 if (r < 0) {
605 log_warning("Failed to enable server support for new connection bus: %s", strerror(-r));
606 return 0;
607 }
6dded4c7 608
718db961
LP
609 r = sd_bus_start(bus);
610 if (r < 0) {
611 log_warning("Failed to start new connection bus: %s", strerror(-r));
612 return 0;
6dded4c7
LP
613 }
614
718db961
LP
615 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
616 if (r < 0) {
617 log_warning("Failed to attach new connection bus to event loop: %s", strerror(-r));
618 return 0;
6dded4c7
LP
619 }
620
718db961
LP
621 if (m->running_as == SYSTEMD_SYSTEM) {
622 /* When we run as system instance we get the Released
623 * signal via a direct connection */
624
625 r = sd_bus_add_match(
626 bus,
627 "type='signal',"
628 "interface='org.freedesktop.systemd1.Agent',"
629 "member='Released',"
630 "path='/org/freedesktop/systemd1/agent'",
631 signal_agent_released, m);
632
633 if (r < 0) {
634 log_warning("Failed to register Released match on new connection bus: %s", strerror(-r));
635 return 0;
636 }
637 }
6dded4c7 638
718db961
LP
639 r = bus_setup_disconnected_match(m, bus);
640 if (r < 0)
641 return 0;
6dded4c7 642
718db961
LP
643 r = bus_setup_api_vtables(m, bus);
644 if (r < 0) {
645 log_warning("Failed to set up API vtables on new connection bus: %s", strerror(-r));
646 return 0;
647 }
6dded4c7 648
718db961
LP
649 r = set_put(m->private_buses, bus);
650 if (r < 0) {
651 log_warning("Failed to add new conenction bus to set: %s", strerror(-r));
652 return 0;
6dded4c7
LP
653 }
654
718db961 655 bus = NULL;
6dded4c7 656
718db961 657 log_debug("Accepted new private connection.");
6dded4c7 658
8e274523
LP
659 return 0;
660}
661
718db961
LP
662static int bus_list_names(Manager *m, sd_bus *bus) {
663 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
664 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
665 const char *name;
666 int r;
5e8d1c9a
LP
667
668 assert(m);
718db961 669 assert(bus);
5e8d1c9a 670
718db961
LP
671 r = sd_bus_call_method(
672 bus,
673 "org.freedesktop.DBus",
674 "/org/freedesktop/DBus",
675 "org.freedesktop.DBus",
676 "ListNames",
677 &error, &reply,
678 NULL);
679 if (r < 0) {
680 log_error("Failed to get initial list of names: %s", bus_error_message(&error, r));
681 return r;
5e8d1c9a
LP
682 }
683
718db961
LP
684 r = sd_bus_message_enter_container(reply, 'a', "s");
685 if (r < 0)
686 return bus_log_parse_error(r);
5e8d1c9a 687
718db961
LP
688 /* This is a bit hacky, we say the owner of the name is the
689 * name itself, because we don't want the extra traffic to
690 * figure out the real owner. */
691 while ((r = sd_bus_message_read(reply, "s", &name)) > 0)
692 manager_dispatch_bus_name_owner_changed(m, name, NULL, name);
693 if (r < 0)
694 return bus_log_parse_error(r);
5e8d1c9a 695
718db961
LP
696 r = sd_bus_message_exit_container(reply);
697 if (r < 0)
698 return bus_log_parse_error(r);
5e8d1c9a 699
718db961 700 return 0;
5e8d1c9a
LP
701}
702
718db961
LP
703static int bus_setup_api(Manager *m, sd_bus *bus) {
704 int r;
f278026d 705
718db961
LP
706 assert(m);
707 assert(bus);
c1e1601e 708
718db961
LP
709 r = bus_setup_api_vtables(m, bus);
710 if (r < 0)
711 return r;
cbd37330 712
718db961
LP
713 r = sd_bus_add_match(
714 bus,
715 "type='signal',"
716 "sender='org.freedesktop.DBus',"
717 "path='/org/freedesktop/DBus',"
718 "interface='org.freedesktop.DBus',"
719 "member='NameOwnerChanged'",
720 signal_name_owner_changed, m);
721 if (r < 0)
722 log_warning("Failed to subscribe to NameOwnerChanged signal: %s", strerror(-r));
723
724 r = sd_bus_add_match(
725 bus,
726 "type='signal',"
727 "sender='org.freedesktop.DBus',"
728 "path='/org/freedesktop/DBus',"
729 "interface='org.freedesktop.systemd1.Activator',"
730 "member='ActivationRequest'",
731 signal_activation_request, m);
732 if (r < 0)
733 log_warning("Failed to subscribe to activation signal: %s", strerror(-r));
cbd37330 734
718db961
LP
735 /* Allow replacing of our name, to ease implementation of
736 * reexecution, where we keep the old connection open until
737 * after the new connection is set up and the name installed
738 * to allow clients to synchronously wait for reexecution to
739 * finish */
740 r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING);
741 if (r < 0) {
742 log_error("Failed to register name: %s", strerror(-r));
743 return r;
744 }
53c6a358 745
718db961
LP
746 if (r != SD_BUS_NAME_PRIMARY_OWNER) {
747 log_error("Failed to acquire name.");
748 return -EEXIST;
ea430986
LP
749 }
750
718db961 751 bus_list_names(m, bus);
f278026d 752
718db961 753 log_debug("Successfully connected to API bus.");
f278026d
LP
754 return 0;
755}
756
718db961
LP
757static int bus_init_api(Manager *m) {
758 _cleanup_bus_unref_ sd_bus *bus = NULL;
f278026d
LP
759 int r;
760
718db961
LP
761 if (m->api_bus)
762 return 0;
cbd37330 763
718db961
LP
764 /* The API and system bus is the same if we are running in system mode */
765 if (m->running_as == SYSTEMD_SYSTEM && m->system_bus)
766 bus = sd_bus_ref(m->system_bus);
767 else {
768 if (m->running_as == SYSTEMD_SYSTEM)
769 r = sd_bus_open_system(&bus);
770 else
771 r = sd_bus_open_user(&bus);
cbd37330 772
718db961
LP
773 if (r < 0) {
774 log_debug("Failed to connect to API bus, retrying later...");
775 return 0;
cbd37330
MS
776 }
777
718db961
LP
778 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
779 if (r < 0) {
780 log_error("Failed to attach API bus to event loop: %s", strerror(-r));
781 return 0;
cbd37330
MS
782 }
783
718db961
LP
784 r = bus_setup_disconnected_match(m, bus);
785 if (r < 0)
786 return 0;
cbd37330
MS
787 }
788
718db961 789 r = bus_setup_api(m, bus);
cbd37330 790 if (r < 0) {
718db961
LP
791 log_error("Failed to set up API bus: %s", strerror(-r));
792 return 0;
cbd37330 793 }
cbd37330 794
718db961
LP
795 m->api_bus = bus;
796 bus = NULL;
cbd37330
MS
797
798 return 0;
cbd37330
MS
799}
800
718db961
LP
801static int bus_setup_system(Manager *m, sd_bus *bus) {
802 int r;
cbd37330 803
718db961
LP
804 assert(m);
805 assert(bus);
cbd37330 806
718db961
LP
807 if (m->running_as == SYSTEMD_SYSTEM)
808 return 0;
cbd37330 809
718db961
LP
810 /* If we are a user instance we get the Released message via
811 * the system bus */
812 r = sd_bus_add_match(
813 bus,
814 "type='signal',"
815 "interface='org.freedesktop.systemd1.Agent',"
816 "member='Released',"
817 "path='/org/freedesktop/systemd1/agent'",
818 signal_agent_released, m);
4dd1de72 819
718db961
LP
820 if (r < 0)
821 log_warning("Failed to register Released match on system bus: %s", strerror(-r));
822
823 log_debug("Successfully connected to system bus.");
824 return 0;
cbd37330
MS
825}
826
827static int bus_init_system(Manager *m) {
718db961 828 _cleanup_bus_unref_ sd_bus *bus = NULL;
cbd37330
MS
829 int r;
830
831 if (m->system_bus)
832 return 0;
833
718db961
LP
834 /* The API and system bus is the same if we are running in system mode */
835 if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) {
836 m->system_bus = sd_bus_ref(m->api_bus);
837 return 0;
9014a8bd 838 }
8e274523 839
718db961
LP
840 r = sd_bus_open_system(&bus);
841 if (r < 0) {
842 log_debug("Failed to connect to system bus, retrying later...");
843 return 0;
844 }
cbd37330 845
718db961 846 r = bus_setup_disconnected_match(m, bus);
cbd37330 847 if (r < 0)
cbd37330
MS
848 return 0;
849
718db961
LP
850 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
851 if (r < 0) {
852 log_error("Failed to attach system bus to event loop: %s", strerror(-r));
cbd37330
MS
853 return 0;
854 }
855
718db961
LP
856 r = bus_setup_system(m, bus);
857 if (r < 0) {
858 log_error("Fauiled to set up system bus: %s", strerror(-r));
859 return 0;
cbd37330
MS
860 }
861
718db961
LP
862 m->system_bus = bus;
863 bus = NULL;
cbd37330
MS
864
865 return 0;
5e8d1c9a
LP
866}
867
868static int bus_init_private(Manager *m) {
718db961
LP
869 _cleanup_close_ int fd = -1;
870 union sockaddr_union sa = {
871 .un.sun_family = AF_UNIX
5e8d1c9a 872 };
718db961
LP
873 sd_event_source *s;
874 socklen_t salen;
875 int r;
5e8d1c9a
LP
876
877 assert(m);
878
718db961 879 if (m->private_listen_fd >= 0)
5e8d1c9a
LP
880 return 0;
881
67445f4e 882 if (m->running_as == SYSTEMD_SYSTEM) {
be81bfc4
LP
883
884 /* We want the private bus only when running as init */
885 if (getpid() != 1)
886 return 0;
887
718db961
LP
888 strcpy(sa.un.sun_path, "/run/systemd/private");
889 salen = offsetof(union sockaddr_union, un.sun_path) + sizeof("/run/systemd/private") - 1;
be81bfc4 890 } else {
718db961
LP
891 size_t left = sizeof(sa.un.sun_path);
892 char *p = sa.un.sun_path;
be81bfc4 893 const char *e;
be81bfc4 894
4db17f29 895 e = secure_getenv("XDG_RUNTIME_DIR");
718db961
LP
896 if (!e) {
897 log_error("Failed to determine XDG_RUNTIME_DIR");
898 return -EHOSTDOWN;
be81bfc4
LP
899 }
900
718db961
LP
901 left = strpcpy(&p, left, e);
902 left = strpcpy(&p, left, "/systemd/private");
92f30349 903
718db961 904 salen = sizeof(sa.un) - left;
92f30349 905
718db961 906 mkdir_parents_label(sa.un.sun_path, 0755);
be81bfc4 907 }
5e8d1c9a 908
718db961
LP
909 unlink(sa.un.sun_path);
910
911 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
912 if (fd < 0) {
913 log_error("Failed to allocate private socket: %m");
914 return -errno;
5e8d1c9a
LP
915 }
916
718db961
LP
917 r = bind(fd, &sa.sa, salen);
918 if (r < 0) {
919 log_error("Failed to bind private socket: %m");
920 return -errno;
5e8d1c9a
LP
921 }
922
718db961
LP
923 r = listen(fd, SOMAXCONN);
924 if (r < 0) {
925 log_error("Failed to make private socket listening: %m");
926 return -errno;
927 }
5e8d1c9a 928
718db961
LP
929 r = sd_event_add_io(m->event, fd, EPOLLIN, bus_on_connection, m, &s);
930 if (r < 0) {
931 log_error("Failed to allocate event source: %s", strerror(-r));
932 return r;
933 }
5e8d1c9a 934
718db961
LP
935 m->private_listen_fd = fd;
936 m->private_listen_event_source = s;
937 fd = -1;
5e8d1c9a 938
718db961 939 log_debug("Successfully created private D-Bus server.");
5e8d1c9a 940
718db961 941 return 0;
5e8d1c9a
LP
942}
943
3996fbe2 944int bus_init(Manager *m, bool try_bus_connect) {
5e8d1c9a
LP
945 int r;
946
3996fbe2 947 if (try_bus_connect) {
718db961
LP
948 r = bus_init_system(m);
949 if (r < 0)
950 return r;
951
952 r = bus_init_api(m);
953 if (r < 0)
3996fbe2
LP
954 return r;
955 }
956
6fa48533
LP
957 r = bus_init_private(m);
958 if (r < 0)
5e8d1c9a 959 return r;
f278026d 960
ea430986
LP
961 return 0;
962}
963
718db961 964static void destroy_bus(Manager *m, sd_bus **bus) {
a567261a 965 Iterator i;
718db961 966 Job *j;
a567261a 967
718db961
LP
968 assert(m);
969 assert(bus);
5e8d1c9a 970
718db961 971 if (!*bus)
cbd37330 972 return;
f278026d 973
718db961
LP
974 /* Get rid of tracked clients on this bus */
975 bus_client_untrack_bus(m->subscribed, *bus);
976 HASHMAP_FOREACH(j, m->jobs, i)
977 bus_client_untrack_bus(j->subscribed, *bus);
c1e1601e 978
718db961
LP
979 /* Get rid of queued message on this bus */
980 if (m->queued_message_bus == *bus) {
981 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
05e343b7 982
718db961
LP
983 if (m->queued_message)
984 m->queued_message = sd_bus_message_unref(m->queued_message);
cbd37330 985 }
f278026d 986
718db961
LP
987 /* Possibly flush unwritten data, but only if we are
988 * unprivileged, since we don't want to sync here */
989 if (m->running_as != SYSTEMD_SYSTEM)
990 sd_bus_flush(*bus);
5e8d1c9a 991
718db961
LP
992 /* And destroy the object */
993 sd_bus_close(*bus);
994 *bus = sd_bus_unref(*bus);
5e8d1c9a
LP
995}
996
997void bus_done(Manager *m) {
718db961 998 sd_bus *b;
05e343b7
LP
999
1000 assert(m);
05e343b7 1001
718db961
LP
1002 if (m->api_bus)
1003 destroy_bus(m, &m->api_bus);
1004 if (m->system_bus)
1005 destroy_bus(m, &m->system_bus);
1006 while ((b = set_steal_first(m->private_buses)))
1007 destroy_bus(m, &b);
05e343b7 1008
718db961
LP
1009 set_free(m->private_buses);
1010 set_free(m->subscribed);
05e343b7 1011
718db961
LP
1012 if (m->private_listen_event_source)
1013 m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
05e343b7 1014
718db961
LP
1015 if (m->private_listen_fd >= 0) {
1016 close_nointr_nofail(m->private_listen_fd);
1017 m->private_listen_fd = -1;
05e343b7 1018 }
a567261a 1019}
b23de6af
LP
1020
1021int bus_fdset_add_all(Manager *m, FDSet *fds) {
1022 Iterator i;
718db961
LP
1023 sd_bus *b;
1024 int fd;
b23de6af
LP
1025
1026 assert(m);
1027 assert(fds);
1028
1029 /* When we are about to reexecute we add all D-Bus fds to the
1030 * set to pass over to the newly executed systemd. They won't
718db961 1031 * be used there however, except thatt they are closed at the
b23de6af 1032 * very end of deserialization, those making it possible for
44143309 1033 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1034 * simply waiting for disconnection */
1035
718db961
LP
1036 if (m->api_bus) {
1037 fd = sd_bus_get_fd(m->api_bus);
1038 if (fd >= 0) {
b23de6af 1039 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1040 if (fd < 0)
1041 return fd;
1042 }
1043 }
1044
718db961
LP
1045 SET_FOREACH(b, m->private_buses, i) {
1046 fd = sd_bus_get_fd(b);
1047 if (fd >= 0) {
b23de6af 1048 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1049 if (fd < 0)
1050 return fd;
1051 }
1052 }
1053
718db961
LP
1054 /* We don't offer any APIs on the system bus (well, unless it
1055 * is the same as the API bus) hence we don't bother with it
1056 * here */
6fa48533 1057
718db961 1058 return 0;
6fa48533
LP
1059}
1060
1061void bus_serialize(Manager *m, FILE *f) {
6fa48533
LP
1062 assert(m);
1063 assert(f);
1064
718db961 1065 bus_client_track_serialize(m, f, m->subscribed);
6fa48533
LP
1066}
1067
1068int bus_deserialize_item(Manager *m, const char *line) {
6fa48533
LP
1069 assert(m);
1070 assert(line);
1071
718db961 1072 return bus_client_track_deserialize_item(m, &m->subscribed, line);
6fa48533 1073}