]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus.c
cgroup: downgrade error message when we cannot remove a cgroup to debug
[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>
4139c1b2 26#include <dbus/dbus.h>
ea430986
LP
27
28#include "dbus.h"
29#include "log.h"
30#include "strv.h"
49e942b2 31#include "mkdir.h"
4db17f29 32#include "missing.h"
4139c1b2
LP
33#include "dbus-unit.h"
34#include "dbus-job.h"
35#include "dbus-manager.h"
4288f619
LP
36#include "dbus-service.h"
37#include "dbus-socket.h"
38#include "dbus-target.h"
39#include "dbus-device.h"
40#include "dbus-mount.h"
41#include "dbus-automount.h"
42#include "dbus-snapshot.h"
43#include "dbus-swap.h"
871d7de4 44#include "dbus-timer.h"
01f78473 45#include "dbus-path.h"
398ef8ba 46#include "bus-errors.h"
8f6df3fa 47#include "special.h"
bfebab7f 48#include "dbus-common.h"
4288f619 49
417b1a62 50#define CONNECTIONS_MAX 512
5e8d1c9a 51
cbd37330
MS
52/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
53#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
54/* Only used as a fallback */
55#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
56
4288f619
LP
57static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
58static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
59
60const char *const bus_interface_table[] = {
61 "org.freedesktop.DBus.Properties", bus_properties_interface,
62 "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
63 "org.freedesktop.systemd1.Manager", bus_manager_interface,
64 "org.freedesktop.systemd1.Job", bus_job_interface,
65 "org.freedesktop.systemd1.Unit", bus_unit_interface,
66 "org.freedesktop.systemd1.Service", bus_service_interface,
67 "org.freedesktop.systemd1.Socket", bus_socket_interface,
68 "org.freedesktop.systemd1.Target", bus_target_interface,
69 "org.freedesktop.systemd1.Device", bus_device_interface,
70 "org.freedesktop.systemd1.Mount", bus_mount_interface,
71 "org.freedesktop.systemd1.Automount", bus_automount_interface,
72 "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface,
73 "org.freedesktop.systemd1.Swap", bus_swap_interface,
871d7de4 74 "org.freedesktop.systemd1.Timer", bus_timer_interface,
01f78473 75 "org.freedesktop.systemd1.Path", bus_path_interface,
4288f619
LP
76 NULL
77};
ea430986 78
5e8d1c9a
LP
79static void bus_done_api(Manager *m);
80static void bus_done_system(Manager *m);
81static void bus_done_private(Manager *m);
923f8d76 82static void shutdown_connection(Manager *m, DBusConnection *c);
0034c15c 83
5e8d1c9a 84static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
8e274523
LP
85 Manager *m = data;
86
87 assert(bus);
88 assert(m);
2e317f52 89
5e8d1c9a
LP
90 /* We maintain two sets, one for those connections where we
91 * requested a dispatch, and another where we didn't. And then,
92 * we move the connections between the two sets. */
8e274523 93
5e8d1c9a
LP
94 if (status == DBUS_DISPATCH_COMPLETE)
95 set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
96 else
97 set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
8e274523
LP
98}
99
ea430986
LP
100void bus_watch_event(Manager *m, Watch *w, int events) {
101 assert(m);
102 assert(w);
103
104 /* This is called by the event loop whenever there is
105 * something happening on D-Bus' file handles. */
106
8e274523 107 if (!dbus_watch_get_enabled(w->data.bus_watch))
ea430986
LP
108 return;
109
3df5bf61 110 dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
ea430986
LP
111}
112
113static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
114 Manager *m = data;
115 Watch *w;
116 struct epoll_event ev;
117
118 assert(bus_watch);
119 assert(m);
120
121 if (!(w = new0(Watch, 1)))
122 return FALSE;
123
124 w->fd = dbus_watch_get_unix_fd(bus_watch);
125 w->type = WATCH_DBUS_WATCH;
126 w->data.bus_watch = bus_watch;
127
128 zero(ev);
129 ev.events = bus_flags_to_events(bus_watch);
130 ev.data.ptr = w;
131
132 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
133
134 if (errno != EEXIST) {
135 free(w);
136 return FALSE;
137 }
138
139 /* Hmm, bloody D-Bus creates multiple watches on the
140 * same fd. epoll() does not like that. As a dirty
141 * hack we simply dup() the fd and hence get a second
142 * one we can safely add to the epoll(). */
143
144 if ((w->fd = dup(w->fd)) < 0) {
145 free(w);
146 return FALSE;
147 }
148
149 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
ea430986 150 close_nointr_nofail(w->fd);
da19d5c1 151 free(w);
ea430986
LP
152 return FALSE;
153 }
154
155 w->fd_is_dupped = true;
156 }
157
158 dbus_watch_set_data(bus_watch, w, NULL);
159
160 return TRUE;
161}
162
163static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
164 Manager *m = data;
165 Watch *w;
166
167 assert(bus_watch);
168 assert(m);
169
3df5bf61
LP
170 w = dbus_watch_get_data(bus_watch);
171 if (!w)
ea430986
LP
172 return;
173
174 assert(w->type == WATCH_DBUS_WATCH);
175 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
176
177 if (w->fd_is_dupped)
178 close_nointr_nofail(w->fd);
179
180 free(w);
181}
182
183static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
184 Manager *m = data;
185 Watch *w;
186 struct epoll_event ev;
187
188 assert(bus_watch);
189 assert(m);
190
3df5bf61
LP
191 w = dbus_watch_get_data(bus_watch);
192 if (!w)
193 return;
194
ea430986
LP
195 assert(w->type == WATCH_DBUS_WATCH);
196
197 zero(ev);
198 ev.events = bus_flags_to_events(bus_watch);
199 ev.data.ptr = w;
200
201 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
202}
203
204static int bus_timeout_arm(Manager *m, Watch *w) {
b92bea5d 205 struct itimerspec its = {};
ea430986
LP
206
207 assert(m);
208 assert(w);
209
ea430986
LP
210 if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
211 timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
da19d5c1 212 its.it_interval = its.it_value;
ea430986
LP
213 }
214
215 if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
216 return -errno;
217
218 return 0;
219}
220
221void bus_timeout_event(Manager *m, Watch *w, int events) {
222 assert(m);
223 assert(w);
224
225 /* This is called by the event loop whenever there is
226 * something happening on D-Bus' file handles. */
227
228 if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
229 return;
230
231 dbus_timeout_handle(w->data.bus_timeout);
232}
233
234static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
235 Manager *m = data;
236 Watch *w;
237 struct epoll_event ev;
238
239 assert(timeout);
240 assert(m);
241
242 if (!(w = new0(Watch, 1)))
243 return FALSE;
244
da19d5c1 245 if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
ea430986
LP
246 goto fail;
247
248 w->type = WATCH_DBUS_TIMEOUT;
249 w->data.bus_timeout = timeout;
250
251 if (bus_timeout_arm(m, w) < 0)
252 goto fail;
253
254 zero(ev);
255 ev.events = EPOLLIN;
256 ev.data.ptr = w;
257
258 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
259 goto fail;
260
261 dbus_timeout_set_data(timeout, w, NULL);
262
263 return TRUE;
264
265fail:
266 if (w->fd >= 0)
267 close_nointr_nofail(w->fd);
268
269 free(w);
270 return FALSE;
271}
272
273static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
274 Manager *m = data;
275 Watch *w;
276
277 assert(timeout);
278 assert(m);
279
3df5bf61
LP
280 w = dbus_timeout_get_data(timeout);
281 if (!w)
ea430986
LP
282 return;
283
284 assert(w->type == WATCH_DBUS_TIMEOUT);
3df5bf61 285
ea430986
LP
286 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
287 close_nointr_nofail(w->fd);
288 free(w);
289}
290
291static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
292 Manager *m = data;
293 Watch *w;
294 int r;
295
296 assert(timeout);
297 assert(m);
298
3df5bf61
LP
299 w = dbus_timeout_get_data(timeout);
300 if (!w)
301 return;
302
ea430986
LP
303 assert(w->type == WATCH_DBUS_TIMEOUT);
304
305 if ((r = bus_timeout_arm(m, w)) < 0)
306 log_error("Failed to rearm timer: %s", strerror(-r));
307}
308
cf3e2471 309static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
c1e1601e
LP
310 Manager *m = data;
311 DBusError error;
0034c15c 312 DBusMessage *reply = NULL;
c1e1601e
LP
313
314 assert(connection);
315 assert(message);
316 assert(m);
317
318 dbus_error_init(&error);
319
1e001f52
LP
320 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
321 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
322 log_debug("Got D-Bus request: %s.%s() on %s",
323 dbus_message_get_interface(message),
324 dbus_message_get_member(message),
325 dbus_message_get_path(message));
c1e1601e
LP
326
327 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
9028d0ec 328 log_debug("API D-Bus connection terminated.");
f278026d 329 bus_done_api(m);
c1e1601e
LP
330
331 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
05e343b7 332 const char *name, *old_owner, *new_owner;
c1e1601e
LP
333
334 if (!dbus_message_get_args(message, &error,
335 DBUS_TYPE_STRING, &name,
05e343b7
LP
336 DBUS_TYPE_STRING, &old_owner,
337 DBUS_TYPE_STRING, &new_owner,
c1e1601e 338 DBUS_TYPE_INVALID))
a2e52832 339 log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
c1e1601e 340 else {
a567261a
LP
341 if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
342 log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
05e343b7
LP
343
344 if (old_owner[0] == 0)
345 old_owner = NULL;
346
347 if (new_owner[0] == 0)
348 new_owner = NULL;
349
350 manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
c1e1601e 351 }
0034c15c
LP
352 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
353 const char *name;
354
355 if (!dbus_message_get_args(message, &error,
356 DBUS_TYPE_STRING, &name,
357 DBUS_TYPE_INVALID))
a2e52832 358 log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
0034c15c
LP
359 else {
360 int r;
361 Unit *u;
362
46018844
LP
363 log_debug("Got D-Bus activation request for %s", name);
364
31afa0a4
LP
365 if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
366 manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
8f6df3fa
LP
367 r = -EADDRNOTAVAIL;
368 dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
369 } else {
370 r = manager_load_unit(m, name, NULL, &error, &u);
0034c15c 371
ac155bb8 372 if (r >= 0 && u->refuse_manual_start)
8f6df3fa 373 r = -EPERM;
0034c15c 374
8f6df3fa
LP
375 if (r >= 0)
376 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
377 }
0034c15c
LP
378
379 if (r < 0) {
380 const char *id, *text;
381
2a8cd298 382 log_debug("D-Bus activation failed for %s: %s", name, strerror(-r));
af25ec12 383
0034c15c
LP
384 if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
385 goto oom;
386
bfebab7f 387 id = error.name ? error.name : bus_errno_to_dbus(r);
398ef8ba 388 text = bus_error(&error, r);
0034c15c
LP
389
390 if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
391 !dbus_message_append_args(reply,
392 DBUS_TYPE_STRING, &name,
393 DBUS_TYPE_STRING, &id,
394 DBUS_TYPE_STRING, &text,
395 DBUS_TYPE_INVALID))
396 goto oom;
397 }
398
35b8ca3a 399 /* On success we don't do anything, the service will be spawned now */
0034c15c 400 }
c1e1601e
LP
401 }
402
403 dbus_error_free(&error);
0034c15c
LP
404
405 if (reply) {
c6a818c8 406 if (!bus_maybe_send_reply(connection, message, reply))
0034c15c
LP
407 goto oom;
408
409 dbus_message_unref(reply);
410 }
411
c1e1601e 412 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
0034c15c
LP
413
414oom:
415 if (reply)
416 dbus_message_unref(reply);
417
418 dbus_error_free(&error);
419
420 return DBUS_HANDLER_RESULT_NEED_MEMORY;
c1e1601e
LP
421}
422
cf3e2471 423static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
8e274523
LP
424 Manager *m = data;
425 DBusError error;
426
427 assert(connection);
428 assert(message);
429 assert(m);
430
431 dbus_error_init(&error);
432
1e001f52
LP
433 if (m->api_bus != m->system_bus &&
434 (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
435 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL))
436 log_debug("Got D-Bus request on system bus: %s.%s() on %s",
437 dbus_message_get_interface(message),
438 dbus_message_get_member(message),
439 dbus_message_get_path(message));
8e274523
LP
440
441 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
91805b3b 442 log_debug("System D-Bus connection terminated.");
f278026d 443 bus_done_system(m);
8e274523 444
67445f4e 445 } else if (m->running_as != SYSTEMD_SYSTEM &&
53c6a358
LP
446 dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
447
8e274523
LP
448 const char *cgroup;
449
450 if (!dbus_message_get_args(message, &error,
451 DBUS_TYPE_STRING, &cgroup,
452 DBUS_TYPE_INVALID))
19bc719e 453 log_error("Failed to parse Released message: %s", bus_error_message(&error));
8e274523 454 else
4ad49000 455 manager_notify_cgroup_empty(m, cgroup);
8e274523
LP
456 }
457
458 dbus_error_free(&error);
459 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
460}
461
5e8d1c9a
LP
462static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
463 Manager *m = data;
3c661fad 464 DBusError error;
5e8d1c9a
LP
465
466 assert(connection);
467 assert(message);
468 assert(m);
469
3c661fad
LP
470 dbus_error_init(&error);
471
1e001f52
LP
472 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
473 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
474 log_debug("Got D-Bus request: %s.%s() on %s",
475 dbus_message_get_interface(message),
476 dbus_message_get_member(message),
477 dbus_message_get_path(message));
5e8d1c9a 478
923f8d76
LP
479 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
480 shutdown_connection(m, connection);
67445f4e 481 else if (m->running_as == SYSTEMD_SYSTEM &&
53c6a358
LP
482 dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
483
3c661fad
LP
484 const char *cgroup;
485
486 if (!dbus_message_get_args(message, &error,
487 DBUS_TYPE_STRING, &cgroup,
488 DBUS_TYPE_INVALID))
a2e52832 489 log_error("Failed to parse Released message: %s", bus_error_message(&error));
3c661fad 490 else
4ad49000 491 manager_notify_cgroup_empty(m, cgroup);
53c6a358
LP
492
493 /* Forward the message to the system bus, so that user
494 * instances are notified as well */
495
496 if (m->system_bus)
497 dbus_connection_send(m->system_bus, message, NULL);
3c661fad
LP
498 }
499
500 dbus_error_free(&error);
5e8d1c9a
LP
501
502 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
503}
504
c1e1601e 505unsigned bus_dispatch(Manager *m) {
5e8d1c9a
LP
506 DBusConnection *c;
507
ea430986
LP
508 assert(m);
509
a16e1123
LP
510 if (m->queued_message) {
511 /* If we cannot get rid of this message we won't
512 * dispatch any D-Bus messages, so that we won't end
513 * up wanting to queue another message. */
514
7b97f477
LP
515 if (m->queued_message_connection)
516 if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL))
5e8d1c9a 517 return 0;
a16e1123
LP
518
519 dbus_message_unref(m->queued_message);
520 m->queued_message = NULL;
7b97f477 521 m->queued_message_connection = NULL;
a16e1123
LP
522 }
523
5e8d1c9a
LP
524 if ((c = set_first(m->bus_connections_for_dispatch))) {
525 if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE)
526 set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c);
fd18e1f4
LP
527
528 return 1;
529 }
c1e1601e 530
8e274523 531 return 0;
ea430986
LP
532}
533
05e343b7 534static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
61902ea3
LP
535 DBusMessage *reply;
536 DBusError error;
537
538 dbus_error_init(&error);
539
540 assert_se(reply = dbus_pending_call_steal_reply(pending));
541
542 switch (dbus_message_get_type(reply)) {
543
544 case DBUS_MESSAGE_TYPE_ERROR:
545
546 assert_se(dbus_set_error_from_message(&error, reply));
a2e52832 547 log_warning("RequestName() failed: %s", bus_error_message(&error));
61902ea3
LP
548 break;
549
550 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
551 uint32_t r;
552
553 if (!dbus_message_get_args(reply,
554 &error,
555 DBUS_TYPE_UINT32, &r,
556 DBUS_TYPE_INVALID)) {
a2e52832 557 log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error));
61902ea3
LP
558 break;
559 }
560
561 if (r == 1)
562 log_debug("Successfully acquired name.");
563 else
564 log_error("Name already owned.");
565
566 break;
567 }
568
569 default:
570 assert_not_reached("Invalid reply message");
571 }
572
573 dbus_message_unref(reply);
574 dbus_error_free(&error);
575}
576
ea430986 577static int request_name(Manager *m) {
ea430986 578 const char *name = "org.freedesktop.systemd1";
b23de6af
LP
579 /* Allow replacing of our name, to ease implementation of
580 * reexecution, where we keep the old connection open until
581 * after the new connection is set up and the name installed
582 * to allow clients to synchronously wait for reexecution to
583 * finish */
584 uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
05e343b7
LP
585 DBusMessage *message = NULL;
586 DBusPendingCall *pending = NULL;
ea430986
LP
587
588 if (!(message = dbus_message_new_method_call(
589 DBUS_SERVICE_DBUS,
590 DBUS_PATH_DBUS,
591 DBUS_INTERFACE_DBUS,
592 "RequestName")))
05e343b7 593 goto oom;
ea430986
LP
594
595 if (!dbus_message_append_args(
596 message,
597 DBUS_TYPE_STRING, &name,
598 DBUS_TYPE_UINT32, &flags,
05e343b7
LP
599 DBUS_TYPE_INVALID))
600 goto oom;
ea430986 601
05e343b7
LP
602 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
603 goto oom;
ea430986 604
05e343b7
LP
605 if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
606 goto oom;
ea430986
LP
607
608 dbus_message_unref(message);
61902ea3
LP
609 dbus_pending_call_unref(pending);
610
611 /* We simple ask for the name and don't wait for it. Sooner or
612 * later we'll have it. */
613
ea430986 614 return 0;
05e343b7
LP
615
616oom:
617 if (pending) {
618 dbus_pending_call_cancel(pending);
619 dbus_pending_call_unref(pending);
620 }
621
622 if (message)
623 dbus_message_unref(message);
624
625 return -ENOMEM;
ea430986
LP
626}
627
6dded4c7
LP
628static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
629 DBusMessage *reply;
630 DBusError error;
631 Manager *m = userdata;
632
633 assert(m);
634
635 dbus_error_init(&error);
636
637 assert_se(reply = dbus_pending_call_steal_reply(pending));
638
639 switch (dbus_message_get_type(reply)) {
640
641 case DBUS_MESSAGE_TYPE_ERROR:
642
643 assert_se(dbus_set_error_from_message(&error, reply));
a2e52832 644 log_warning("ListNames() failed: %s", bus_error_message(&error));
6dded4c7
LP
645 break;
646
647 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
648 int r;
649 char **l;
650
651 if ((r = bus_parse_strv(reply, &l)) < 0)
652 log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
653 else {
654 char **t;
655
656 STRV_FOREACH(t, l)
657 /* This is a bit hacky, we say the
658 * owner of the name is the name
659 * itself, because we don't want the
660 * extra traffic to figure out the
661 * real owner. */
662 manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
663
664 strv_free(l);
665 }
666
667 break;
668 }
669
670 default:
671 assert_not_reached("Invalid reply message");
672 }
673
674 dbus_message_unref(reply);
675 dbus_error_free(&error);
676}
677
678static int query_name_list(Manager *m) {
679 DBusMessage *message = NULL;
680 DBusPendingCall *pending = NULL;
681
682 /* Asks for the currently installed bus names */
683
684 if (!(message = dbus_message_new_method_call(
685 DBUS_SERVICE_DBUS,
686 DBUS_PATH_DBUS,
687 DBUS_INTERFACE_DBUS,
688 "ListNames")))
689 goto oom;
690
691 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
692 goto oom;
693
694 if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
695 goto oom;
696
697 dbus_message_unref(message);
698 dbus_pending_call_unref(pending);
699
700 /* We simple ask for the list and don't wait for it. Sooner or
701 * later we'll get it. */
702
703 return 0;
704
705oom:
706 if (pending) {
707 dbus_pending_call_cancel(pending);
708 dbus_pending_call_unref(pending);
709 }
710
711 if (message)
712 dbus_message_unref(message);
713
714 return -ENOMEM;
715}
716
8e274523
LP
717static int bus_setup_loop(Manager *m, DBusConnection *bus) {
718 assert(m);
719 assert(bus);
720
721 dbus_connection_set_exit_on_disconnect(bus, FALSE);
fd18e1f4 722
8e274523 723 if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
0d0f0c50
SL
724 !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
725 return log_oom();
8e274523 726
0d0f0c50
SL
727 if (set_put(m->bus_connections_for_dispatch, bus) < 0)
728 return log_oom();
5e8d1c9a
LP
729
730 dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL);
8e274523
LP
731 return 0;
732}
733
be81bfc4
LP
734static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
735 return uid == 0 || uid == geteuid();
5e8d1c9a
LP
736}
737
738static void bus_new_connection(
739 DBusServer *server,
740 DBusConnection *new_connection,
741 void *data) {
742
743 Manager *m = data;
744
745 assert(m);
746
747 if (set_size(m->bus_connections) >= CONNECTIONS_MAX) {
748 log_error("Too many concurrent connections.");
749 return;
750 }
751
be81bfc4 752 dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
5e8d1c9a
LP
753
754 if (bus_setup_loop(m, new_connection) < 0)
755 return;
756
757 if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
758 !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
759 !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
760 !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) {
0d0f0c50 761 log_oom();
5e8d1c9a
LP
762 return;
763 }
764
765 log_debug("Accepted connection on private bus.");
766
767 dbus_connection_ref(new_connection);
768}
769
cbd37330
MS
770static int init_registered_system_bus(Manager *m) {
771 char *id;
f278026d 772
0d0f0c50
SL
773 if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL))
774 return log_oom();
c1e1601e 775
67445f4e 776 if (m->running_as != SYSTEMD_SYSTEM) {
cbd37330
MS
777 DBusError error;
778
779 dbus_error_init(&error);
780
53c6a358
LP
781 dbus_bus_add_match(m->system_bus,
782 "type='signal',"
783 "interface='org.freedesktop.systemd1.Agent',"
784 "member='Released',"
785 "path='/org/freedesktop/systemd1/agent'",
786 &error);
787
788 if (dbus_error_is_set(&error)) {
a2e52832 789 log_error("Failed to register match: %s", bus_error_message(&error));
cbd37330
MS
790 dbus_error_free(&error);
791 return -1;
53c6a358 792 }
ea430986
LP
793 }
794
cbd37330
MS
795 log_debug("Successfully connected to system D-Bus bus %s as %s",
796 strnull((id = dbus_connection_get_server_id(m->system_bus))),
797 strnull(dbus_bus_get_unique_name(m->system_bus)));
798 dbus_free(id);
f278026d 799
f278026d
LP
800 return 0;
801}
802
cbd37330 803static int init_registered_api_bus(Manager *m) {
f278026d
LP
804 int r;
805
f278026d
LP
806 if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
807 !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
808 !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
0d0f0c50
SL
809 !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL))
810 return log_oom();
f278026d 811
0034c15c 812 /* Get NameOwnerChange messages */
f278026d 813 dbus_bus_add_match(m->api_bus,
8e274523 814 "type='signal',"
f278026d
LP
815 "sender='"DBUS_SERVICE_DBUS"',"
816 "interface='"DBUS_INTERFACE_DBUS"',"
fd0d7f7a 817 "member='NameOwnerChanged',"
f278026d 818 "path='"DBUS_PATH_DBUS"'",
cbd37330 819 NULL);
8e274523 820
0034c15c
LP
821 /* Get activation requests */
822 dbus_bus_add_match(m->api_bus,
823 "type='signal',"
824 "sender='"DBUS_SERVICE_DBUS"',"
825 "interface='org.freedesktop.systemd1.Activator',"
cf3e2471 826 "member='ActivationRequest',"
0034c15c 827 "path='"DBUS_PATH_DBUS"'",
cbd37330 828 NULL);
0034c15c 829
cbd37330
MS
830 r = request_name(m);
831 if (r < 0)
832 return r;
ea430986 833
cbd37330
MS
834 r = query_name_list(m);
835 if (r < 0)
836 return r;
6dded4c7 837
67445f4e 838 if (m->running_as == SYSTEMD_USER) {
9014a8bd 839 char *id;
91805b3b 840 log_debug("Successfully connected to API D-Bus bus %s as %s",
9014a8bd
LP
841 strnull((id = dbus_connection_get_server_id(m->api_bus))),
842 strnull(dbus_bus_get_unique_name(m->api_bus)));
843 dbus_free(id);
cbd37330
MS
844 } else
845 log_debug("Successfully initialized API on the system bus");
846
847 return 0;
848}
849
850static void bus_register_cb(DBusPendingCall *pending, void *userdata) {
851 Manager *m = userdata;
852 DBusConnection **conn;
853 DBusMessage *reply;
854 DBusError error;
855 const char *name;
856 int r = 0;
857
858 dbus_error_init(&error);
859
860 conn = dbus_pending_call_get_data(pending, m->conn_data_slot);
861 assert(conn == &m->system_bus || conn == &m->api_bus);
862
863 reply = dbus_pending_call_steal_reply(pending);
864
865 switch (dbus_message_get_type(reply)) {
866 case DBUS_MESSAGE_TYPE_ERROR:
867 assert_se(dbus_set_error_from_message(&error, reply));
868 log_warning("Failed to register to bus: %s", bus_error_message(&error));
869 r = -1;
870 break;
871 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
872 if (!dbus_message_get_args(reply, &error,
873 DBUS_TYPE_STRING, &name,
874 DBUS_TYPE_INVALID)) {
875 log_error("Failed to parse Hello reply: %s", bus_error_message(&error));
876 r = -1;
877 break;
878 }
879
880 log_debug("Received name %s in reply to Hello", name);
881 if (!dbus_bus_set_unique_name(*conn, name)) {
882 log_error("Failed to set unique name");
883 r = -1;
884 break;
885 }
886
887 if (conn == &m->system_bus) {
888 r = init_registered_system_bus(m);
67445f4e 889 if (r == 0 && m->running_as == SYSTEMD_SYSTEM)
cbd37330
MS
890 r = init_registered_api_bus(m);
891 } else
892 r = init_registered_api_bus(m);
893
894 break;
895 default:
896 assert_not_reached("Invalid reply message");
897 }
898
899 dbus_message_unref(reply);
900 dbus_error_free(&error);
901
902 if (r < 0) {
903 if (conn == &m->system_bus) {
904 log_debug("Failed setting up the system bus");
905 bus_done_system(m);
906 } else {
907 log_debug("Failed setting up the API bus");
908 bus_done_api(m);
909 }
910 }
911}
912
913static int manager_bus_async_register(Manager *m, DBusConnection **conn) {
914 DBusMessage *message = NULL;
915 DBusPendingCall *pending = NULL;
916
917 message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
918 DBUS_PATH_DBUS,
919 DBUS_INTERFACE_DBUS,
920 "Hello");
921 if (!message)
922 goto oom;
923
924 if (!dbus_connection_send_with_reply(*conn, message, &pending, -1))
925 goto oom;
926
927 if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL))
928 goto oom;
929
930 if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL))
931 goto oom;
932
933 dbus_message_unref(message);
934 dbus_pending_call_unref(pending);
935
936 return 0;
937oom:
938 if (pending) {
939 dbus_pending_call_cancel(pending);
940 dbus_pending_call_unref(pending);
941 }
942
943 if (message)
944 dbus_message_unref(message);
945
946 return -ENOMEM;
947}
948
949static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) {
950 const char *address;
951 DBusConnection *connection;
952 DBusError error;
953
954 switch (type) {
955 case DBUS_BUS_SYSTEM:
4db17f29 956 address = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
cbd37330
MS
957 if (!address || !address[0])
958 address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
959 break;
960 case DBUS_BUS_SESSION:
4db17f29 961 address = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
cbd37330
MS
962 if (!address || !address[0])
963 address = DBUS_SESSION_BUS_DEFAULT_ADDRESS;
964 break;
965 default:
966 assert_not_reached("Invalid bus type");
967 }
968
969 dbus_error_init(&error);
970
971 connection = dbus_connection_open_private(address, &error);
972 if (!connection) {
973 log_warning("Failed to open private bus connection: %s", bus_error_message(&error));
974 goto fail;
975 }
976
977 return connection;
4dd1de72 978
cbd37330 979fail:
cbd37330
MS
980 dbus_error_free(&error);
981 return NULL;
982}
983
984static int bus_init_system(Manager *m) {
985 int r;
986
987 if (m->system_bus)
988 return 0;
989
990 m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM);
991 if (!m->system_bus) {
992 log_debug("Failed to connect to system D-Bus, retrying later");
993 r = 0;
994 goto fail;
9014a8bd 995 }
8e274523 996
cbd37330
MS
997 r = bus_setup_loop(m, m->system_bus);
998 if (r < 0)
999 goto fail;
1000
1001 r = manager_bus_async_register(m, &m->system_bus);
1002 if (r < 0)
1003 goto fail;
1004
5e8d1c9a 1005 return 0;
cbd37330
MS
1006fail:
1007 bus_done_system(m);
1008
1009 return r;
1010}
1011
1012static int bus_init_api(Manager *m) {
1013 int r;
1014
1015 if (m->api_bus)
1016 return 0;
1017
67445f4e 1018 if (m->running_as == SYSTEMD_SYSTEM) {
cbd37330
MS
1019 m->api_bus = m->system_bus;
1020 /* In this mode there is no distinct connection to the API bus,
1021 * the API is published on the system bus.
1022 * bus_register_cb() is aware of that and will init the API
1023 * when the system bus gets registered.
1024 * No need to setup anything here. */
1025 return 0;
1026 }
1027
1028 m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION);
1029 if (!m->api_bus) {
1030 log_debug("Failed to connect to API D-Bus, retrying later");
1031 r = 0;
1032 goto fail;
1033 }
1034
1035 r = bus_setup_loop(m, m->api_bus);
1036 if (r < 0)
1037 goto fail;
5e8d1c9a 1038
cbd37330
MS
1039 r = manager_bus_async_register(m, &m->api_bus);
1040 if (r < 0)
1041 goto fail;
1042
1043 return 0;
5e8d1c9a
LP
1044fail:
1045 bus_done_api(m);
5e8d1c9a
LP
1046
1047 return r;
1048}
1049
1050static int bus_init_private(Manager *m) {
1051 DBusError error;
1052 int r;
166de425 1053 static const char *const external_only[] = {
5e8d1c9a
LP
1054 "EXTERNAL",
1055 NULL
1056 };
1057
1058 assert(m);
1059
1060 dbus_error_init(&error);
1061
1062 if (m->private_bus)
1063 return 0;
1064
67445f4e 1065 if (m->running_as == SYSTEMD_SYSTEM) {
be81bfc4
LP
1066
1067 /* We want the private bus only when running as init */
1068 if (getpid() != 1)
1069 return 0;
1070
1071 unlink("/run/systemd/private");
1072 m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
1073 } else {
1074 const char *e;
1075 char *p;
92f30349 1076 char *escaped;
be81bfc4 1077
4db17f29 1078 e = secure_getenv("XDG_RUNTIME_DIR");
be81bfc4
LP
1079 if (!e)
1080 return 0;
1081
92f30349 1082 if (asprintf(&p, "%s/systemd/private", e) < 0) {
0d0f0c50 1083 r = log_oom();
be81bfc4
LP
1084 goto fail;
1085 }
1086
92f30349
SM
1087 mkdir_parents_label(p, 0755);
1088 unlink(p);
1089 free(p);
1090
1091 escaped = dbus_address_escape_value(e);
1092 if (!escaped) {
1093 r = log_oom();
1094 goto fail;
1095 }
1096 if (asprintf(&p, "unix:path=%s/systemd/private", escaped) < 0) {
1097 dbus_free(escaped);
1098 r = log_oom();
1099 goto fail;
1100 }
1101 dbus_free(escaped);
1102
be81bfc4
LP
1103 m->private_bus = dbus_server_listen(p, &error);
1104 free(p);
1105 }
5e8d1c9a 1106
be81bfc4 1107 if (!m->private_bus) {
a2e52832 1108 log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
5e8d1c9a
LP
1109 r = -EIO;
1110 goto fail;
1111 }
1112
1113 if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) ||
1114 !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
1115 !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
0d0f0c50 1116 r = log_oom();
5e8d1c9a
LP
1117 goto fail;
1118 }
1119
1120 dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL);
1121
54165a39 1122 log_debug("Successfully created private D-Bus server.");
5e8d1c9a
LP
1123
1124 return 0;
1125
1126fail:
1127 bus_done_private(m);
1128 dbus_error_free(&error);
1129
1130 return r;
1131}
1132
3996fbe2 1133int bus_init(Manager *m, bool try_bus_connect) {
5e8d1c9a
LP
1134 int r;
1135
1136 if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
cbd37330
MS
1137 set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
1138 goto oom;
5e8d1c9a
LP
1139
1140 if (m->name_data_slot < 0)
cbd37330
MS
1141 if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
1142 goto oom;
1143
1144 if (m->conn_data_slot < 0)
1145 if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot))
1146 goto oom;
5e8d1c9a 1147
a567261a 1148 if (m->subscribed_data_slot < 0)
cbd37330
MS
1149 if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot))
1150 goto oom;
a567261a 1151
3996fbe2
LP
1152 if (try_bus_connect) {
1153 if ((r = bus_init_system(m)) < 0 ||
1154 (r = bus_init_api(m)) < 0)
1155 return r;
1156 }
1157
1158 if ((r = bus_init_private(m)) < 0)
5e8d1c9a 1159 return r;
f278026d 1160
ea430986 1161 return 0;
cbd37330 1162oom:
0d0f0c50 1163 return log_oom();
ea430986
LP
1164}
1165
fae20b11 1166static void shutdown_connection(Manager *m, DBusConnection *c) {
a567261a
LP
1167 Set *s;
1168 Job *j;
1169 Iterator i;
1170
97e6a119
MS
1171 HASHMAP_FOREACH(j, m->jobs, i) {
1172 JobBusClient *cl, *nextcl;
1173 LIST_FOREACH_SAFE(client, cl, nextcl, j->bus_client_list) {
1174 if (cl->bus == c) {
1175 LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
1176 free(cl);
1177 }
a567261a 1178 }
97e6a119 1179 }
a567261a 1180
fae20b11
LP
1181 set_remove(m->bus_connections, c);
1182 set_remove(m->bus_connections_for_dispatch, c);
1183
a567261a
LP
1184 if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
1185 char *t;
1186
1187 while ((t = set_steal_first(s)))
1188 free(t);
1189
1190 set_free(s);
1191 }
1192
7b97f477
LP
1193 if (m->queued_message_connection == c) {
1194 m->queued_message_connection = NULL;
1195
1196 if (m->queued_message) {
1197 dbus_message_unref(m->queued_message);
1198 m->queued_message = NULL;
1199 }
1200 }
1201
5e8d1c9a 1202 dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
9721b199 1203 /* system manager cannot afford to block on DBus */
67445f4e 1204 if (m->running_as != SYSTEMD_SYSTEM)
9721b199 1205 dbus_connection_flush(c);
5e8d1c9a
LP
1206 dbus_connection_close(c);
1207 dbus_connection_unref(c);
1208}
1209
1210static void bus_done_api(Manager *m) {
cbd37330
MS
1211 if (!m->api_bus)
1212 return;
f278026d 1213
67445f4e 1214 if (m->running_as == SYSTEMD_USER)
fae20b11 1215 shutdown_connection(m, m->api_bus);
c1e1601e 1216
cbd37330 1217 m->api_bus = NULL;
05e343b7 1218
cbd37330
MS
1219 if (m->queued_message) {
1220 dbus_message_unref(m->queued_message);
1221 m->queued_message = NULL;
1222 }
ea430986
LP
1223}
1224
5e8d1c9a 1225static void bus_done_system(Manager *m) {
cbd37330
MS
1226 if (!m->system_bus)
1227 return;
f278026d 1228
67445f4e 1229 if (m->running_as == SYSTEMD_SYSTEM)
f278026d
LP
1230 bus_done_api(m);
1231
cbd37330
MS
1232 shutdown_connection(m, m->system_bus);
1233 m->system_bus = NULL;
f278026d
LP
1234}
1235
5e8d1c9a 1236static void bus_done_private(Manager *m) {
cbd37330
MS
1237 if (!m->private_bus)
1238 return;
5e8d1c9a 1239
cbd37330
MS
1240 dbus_server_disconnect(m->private_bus);
1241 dbus_server_unref(m->private_bus);
1242 m->private_bus = NULL;
5e8d1c9a
LP
1243}
1244
1245void bus_done(Manager *m) {
1246 DBusConnection *c;
1247
1248 bus_done_api(m);
1249 bus_done_system(m);
1250 bus_done_private(m);
1251
1252 while ((c = set_steal_first(m->bus_connections)))
fae20b11 1253 shutdown_connection(m, c);
5e8d1c9a
LP
1254
1255 while ((c = set_steal_first(m->bus_connections_for_dispatch)))
fae20b11 1256 shutdown_connection(m, c);
5e8d1c9a
LP
1257
1258 set_free(m->bus_connections);
1259 set_free(m->bus_connections_for_dispatch);
1260
1261 if (m->name_data_slot >= 0)
1262 dbus_pending_call_free_data_slot(&m->name_data_slot);
a567261a 1263
cbd37330
MS
1264 if (m->conn_data_slot >= 0)
1265 dbus_pending_call_free_data_slot(&m->conn_data_slot);
1266
a567261a 1267 if (m->subscribed_data_slot >= 0)
d83685ac 1268 dbus_connection_free_data_slot(&m->subscribed_data_slot);
5e8d1c9a
LP
1269}
1270
05e343b7
LP
1271static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
1272 Manager *m = userdata;
1273 DBusMessage *reply;
1274 DBusError error;
1275 const char *name;
1276
1277 dbus_error_init(&error);
1278
a567261a 1279 assert_se(name = BUS_PENDING_CALL_NAME(m, pending));
05e343b7
LP
1280 assert_se(reply = dbus_pending_call_steal_reply(pending));
1281
1282 switch (dbus_message_get_type(reply)) {
1283
1284 case DBUS_MESSAGE_TYPE_ERROR:
1285
1286 assert_se(dbus_set_error_from_message(&error, reply));
a2e52832 1287 log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error));
05e343b7
LP
1288 break;
1289
1290 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
1291 uint32_t r;
1292
1293 if (!dbus_message_get_args(reply,
1294 &error,
1295 DBUS_TYPE_UINT32, &r,
1296 DBUS_TYPE_INVALID)) {
a2e52832 1297 log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error));
05e343b7
LP
1298 break;
1299 }
1300
1301 manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
1302 break;
1303 }
1304
1305 default:
1306 assert_not_reached("Invalid reply message");
1307 }
1308
1309 dbus_message_unref(reply);
1310 dbus_error_free(&error);
1311}
1312
1313int bus_query_pid(Manager *m, const char *name) {
1314 DBusMessage *message = NULL;
1315 DBusPendingCall *pending = NULL;
1316 char *n = NULL;
1317
1318 assert(m);
1319 assert(name);
1320
1321 if (!(message = dbus_message_new_method_call(
1322 DBUS_SERVICE_DBUS,
1323 DBUS_PATH_DBUS,
1324 DBUS_INTERFACE_DBUS,
1325 "GetConnectionUnixProcessID")))
1326 goto oom;
1327
1328 if (!(dbus_message_append_args(
1329 message,
1330 DBUS_TYPE_STRING, &name,
1331 DBUS_TYPE_INVALID)))
1332 goto oom;
1333
1334 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
1335 goto oom;
1336
1337 if (!(n = strdup(name)))
1338 goto oom;
1339
1340 if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
1341 goto oom;
1342
1343 n = NULL;
1344
1345 if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
1346 goto oom;
1347
1348 dbus_message_unref(message);
1349 dbus_pending_call_unref(pending);
1350
1351 return 0;
1352
1353oom:
1354 free(n);
1355
1356 if (pending) {
1357 dbus_pending_call_cancel(pending);
1358 dbus_pending_call_unref(pending);
1359 }
1360
1361 if (message)
1362 dbus_message_unref(message);
1363
1364 return -ENOMEM;
1365}
1366
5e8d1c9a
LP
1367int bus_broadcast(Manager *m, DBusMessage *message) {
1368 bool oom = false;
1369 Iterator i;
1370 DBusConnection *c;
1371
1372 assert(m);
1373 assert(message);
1374
1375 SET_FOREACH(c, m->bus_connections_for_dispatch, i)
67445f4e 1376 if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM)
5e8d1c9a
LP
1377 oom = !dbus_connection_send(c, message, NULL);
1378
1379 SET_FOREACH(c, m->bus_connections, i)
67445f4e 1380 if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM)
5e8d1c9a
LP
1381 oom = !dbus_connection_send(c, message, NULL);
1382
1383 return oom ? -ENOMEM : 0;
1384}
1385
a567261a
LP
1386bool bus_has_subscriber(Manager *m) {
1387 Iterator i;
1388 DBusConnection *c;
1389
1390 assert(m);
1391
1392 SET_FOREACH(c, m->bus_connections_for_dispatch, i)
1393 if (bus_connection_has_subscriber(m, c))
1394 return true;
1395
1396 SET_FOREACH(c, m->bus_connections, i)
1397 if (bus_connection_has_subscriber(m, c))
1398 return true;
1399
1400 return false;
1401}
1402
1403bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
1404 assert(m);
1405 assert(c);
1406
1407 return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
1408}
b23de6af
LP
1409
1410int bus_fdset_add_all(Manager *m, FDSet *fds) {
1411 Iterator i;
1412 DBusConnection *c;
1413
1414 assert(m);
1415 assert(fds);
1416
1417 /* When we are about to reexecute we add all D-Bus fds to the
1418 * set to pass over to the newly executed systemd. They won't
1419 * be used there however, except that they are closed at the
1420 * very end of deserialization, those making it possible for
44143309 1421 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1422 * simply waiting for disconnection */
1423
1424 SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
1425 int fd;
1426
1427 if (dbus_connection_get_unix_fd(c, &fd)) {
1428 fd = fdset_put_dup(fds, fd);
1429
1430 if (fd < 0)
1431 return fd;
1432 }
1433 }
1434
1435 SET_FOREACH(c, m->bus_connections, i) {
1436 int fd;
1437
1438 if (dbus_connection_get_unix_fd(c, &fd)) {
1439 fd = fdset_put_dup(fds, fd);
1440
1441 if (fd < 0)
1442 return fd;
1443 }
1444 }
1445
1446 return 0;
1447}
18fa6b27
LP
1448
1449void bus_broadcast_finished(
1450 Manager *m,
915b3753
LP
1451 usec_t firmware_usec,
1452 usec_t loader_usec,
18fa6b27
LP
1453 usec_t kernel_usec,
1454 usec_t initrd_usec,
1455 usec_t userspace_usec,
1456 usec_t total_usec) {
1457
1458 DBusMessage *message;
1459
1460 assert(m);
1461
1462 message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
1463 if (!message) {
0d0f0c50 1464 log_oom();
18fa6b27
LP
1465 return;
1466 }
1467
1468 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
1469 if (!dbus_message_append_args(message,
915b3753
LP
1470 DBUS_TYPE_UINT64, &firmware_usec,
1471 DBUS_TYPE_UINT64, &loader_usec,
18fa6b27
LP
1472 DBUS_TYPE_UINT64, &kernel_usec,
1473 DBUS_TYPE_UINT64, &initrd_usec,
1474 DBUS_TYPE_UINT64, &userspace_usec,
1475 DBUS_TYPE_UINT64, &total_usec,
1476 DBUS_TYPE_INVALID)) {
0d0f0c50 1477 log_oom();
18fa6b27
LP
1478 goto finish;
1479 }
1480
1481
1482 if (bus_broadcast(m, message) < 0) {
0d0f0c50 1483 log_oom();
18fa6b27
LP
1484 goto finish;
1485 }
1486
1487finish:
c99ddfaa 1488 if (message)
18fa6b27
LP
1489 dbus_message_unref(message);
1490}