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