1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/epoll.h>
23 #include <sys/timerfd.h>
26 #include <dbus/dbus.h>
34 #include "dbus-unit.h"
36 #include "dbus-manager.h"
37 #include "dbus-service.h"
38 #include "dbus-socket.h"
39 #include "dbus-target.h"
40 #include "dbus-device.h"
41 #include "dbus-mount.h"
42 #include "dbus-automount.h"
43 #include "dbus-snapshot.h"
44 #include "dbus-swap.h"
45 #include "dbus-timer.h"
46 #include "dbus-path.h"
47 #include "bus-errors.h"
49 #include "dbus-common.h"
51 #define CONNECTIONS_MAX 52
53 /* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
54 #define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
55 /* Only used as a fallback */
56 #define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
58 static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
59 static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
61 const char *const bus_interface_table[] = {
62 "org.freedesktop.DBus.Properties", bus_properties_interface,
63 "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
64 "org.freedesktop.systemd1.Manager", bus_manager_interface,
65 "org.freedesktop.systemd1.Job", bus_job_interface,
66 "org.freedesktop.systemd1.Unit", bus_unit_interface,
67 "org.freedesktop.systemd1.Service", bus_service_interface,
68 "org.freedesktop.systemd1.Socket", bus_socket_interface,
69 "org.freedesktop.systemd1.Target", bus_target_interface,
70 "org.freedesktop.systemd1.Device", bus_device_interface,
71 "org.freedesktop.systemd1.Mount", bus_mount_interface,
72 "org.freedesktop.systemd1.Automount", bus_automount_interface,
73 "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface,
74 "org.freedesktop.systemd1.Swap", bus_swap_interface,
75 "org.freedesktop.systemd1.Timer", bus_timer_interface,
76 "org.freedesktop.systemd1.Path", bus_path_interface,
80 static void bus_done_api(Manager *m);
81 static void bus_done_system(Manager *m);
82 static void bus_done_private(Manager *m);
83 static void shutdown_connection(Manager *m, DBusConnection *c);
85 static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
91 /* We maintain two sets, one for those connections where we
92 * requested a dispatch, and another where we didn't. And then,
93 * we move the connections between the two sets. */
95 if (status == DBUS_DISPATCH_COMPLETE)
96 set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
98 set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
101 void bus_watch_event(Manager *m, Watch *w, int events) {
105 /* This is called by the event loop whenever there is
106 * something happening on D-Bus' file handles. */
108 if (!dbus_watch_get_enabled(w->data.bus_watch))
111 dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
114 static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
117 struct epoll_event ev;
122 if (!(w = new0(Watch, 1)))
125 w->fd = dbus_watch_get_unix_fd(bus_watch);
126 w->type = WATCH_DBUS_WATCH;
127 w->data.bus_watch = bus_watch;
130 ev.events = bus_flags_to_events(bus_watch);
133 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
135 if (errno != EEXIST) {
140 /* Hmm, bloody D-Bus creates multiple watches on the
141 * same fd. epoll() does not like that. As a dirty
142 * hack we simply dup() the fd and hence get a second
143 * one we can safely add to the epoll(). */
145 if ((w->fd = dup(w->fd)) < 0) {
150 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
151 close_nointr_nofail(w->fd);
156 w->fd_is_dupped = true;
159 dbus_watch_set_data(bus_watch, w, NULL);
164 static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
171 w = dbus_watch_get_data(bus_watch);
175 assert(w->type == WATCH_DBUS_WATCH);
176 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
179 close_nointr_nofail(w->fd);
184 static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
187 struct epoll_event ev;
192 w = dbus_watch_get_data(bus_watch);
196 assert(w->type == WATCH_DBUS_WATCH);
199 ev.events = bus_flags_to_events(bus_watch);
202 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
205 static int bus_timeout_arm(Manager *m, Watch *w) {
206 struct itimerspec its;
213 if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
214 timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
215 its.it_interval = its.it_value;
218 if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
224 void bus_timeout_event(Manager *m, Watch *w, int events) {
228 /* This is called by the event loop whenever there is
229 * something happening on D-Bus' file handles. */
231 if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
234 dbus_timeout_handle(w->data.bus_timeout);
237 static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
240 struct epoll_event ev;
245 if (!(w = new0(Watch, 1)))
248 if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
251 w->type = WATCH_DBUS_TIMEOUT;
252 w->data.bus_timeout = timeout;
254 if (bus_timeout_arm(m, w) < 0)
261 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
264 dbus_timeout_set_data(timeout, w, NULL);
270 close_nointr_nofail(w->fd);
276 static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
283 w = dbus_timeout_get_data(timeout);
287 assert(w->type == WATCH_DBUS_TIMEOUT);
289 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
290 close_nointr_nofail(w->fd);
294 static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
302 w = dbus_timeout_get_data(timeout);
306 assert(w->type == WATCH_DBUS_TIMEOUT);
308 if ((r = bus_timeout_arm(m, w)) < 0)
309 log_error("Failed to rearm timer: %s", strerror(-r));
312 static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
315 DBusMessage *reply = NULL;
321 dbus_error_init(&error);
323 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
324 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
325 log_debug("Got D-Bus request: %s.%s() on %s",
326 dbus_message_get_interface(message),
327 dbus_message_get_member(message),
328 dbus_message_get_path(message));
330 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
331 log_debug("API D-Bus connection terminated.");
334 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
335 const char *name, *old_owner, *new_owner;
337 if (!dbus_message_get_args(message, &error,
338 DBUS_TYPE_STRING, &name,
339 DBUS_TYPE_STRING, &old_owner,
340 DBUS_TYPE_STRING, &new_owner,
342 log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
344 if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
345 log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
347 if (old_owner[0] == 0)
350 if (new_owner[0] == 0)
353 manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
355 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
358 if (!dbus_message_get_args(message, &error,
359 DBUS_TYPE_STRING, &name,
361 log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
366 log_debug("Got D-Bus activation request for %s", name);
368 if (manager_unit_pending_inactive(m, SPECIAL_DBUS_SERVICE) ||
369 manager_unit_pending_inactive(m, SPECIAL_DBUS_SOCKET)) {
371 dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
373 r = manager_load_unit(m, name, NULL, &error, &u);
375 if (r >= 0 && u->refuse_manual_start)
379 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
383 const char *id, *text;
385 log_debug("D-Bus activation failed for %s: %s", name, strerror(-r));
387 if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
390 id = error.name ? error.name : bus_errno_to_dbus(r);
391 text = bus_error(&error, r);
393 if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
394 !dbus_message_append_args(reply,
395 DBUS_TYPE_STRING, &name,
396 DBUS_TYPE_STRING, &id,
397 DBUS_TYPE_STRING, &text,
402 /* On success we don't do anything, the service will be spawned now */
406 dbus_error_free(&error);
409 if (!dbus_connection_send(connection, reply, NULL))
412 dbus_message_unref(reply);
415 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
419 dbus_message_unref(reply);
421 dbus_error_free(&error);
423 return DBUS_HANDLER_RESULT_NEED_MEMORY;
426 static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
434 dbus_error_init(&error);
436 if (m->api_bus != m->system_bus &&
437 (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
438 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL))
439 log_debug("Got D-Bus request on system bus: %s.%s() on %s",
440 dbus_message_get_interface(message),
441 dbus_message_get_member(message),
442 dbus_message_get_path(message));
444 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
445 log_debug("System D-Bus connection terminated.");
448 } else if (m->running_as != SYSTEMD_SYSTEM &&
449 dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
453 if (!dbus_message_get_args(message, &error,
454 DBUS_TYPE_STRING, &cgroup,
456 log_error("Failed to parse Released message: %s", bus_error_message(&error));
458 cgroup_notify_empty(m, cgroup);
461 dbus_error_free(&error);
462 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
465 static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
473 dbus_error_init(&error);
475 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
476 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
477 log_debug("Got D-Bus request: %s.%s() on %s",
478 dbus_message_get_interface(message),
479 dbus_message_get_member(message),
480 dbus_message_get_path(message));
482 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
483 shutdown_connection(m, connection);
484 else if (m->running_as == SYSTEMD_SYSTEM &&
485 dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
489 if (!dbus_message_get_args(message, &error,
490 DBUS_TYPE_STRING, &cgroup,
492 log_error("Failed to parse Released message: %s", bus_error_message(&error));
494 cgroup_notify_empty(m, cgroup);
496 /* Forward the message to the system bus, so that user
497 * instances are notified as well */
500 dbus_connection_send(m->system_bus, message, NULL);
503 dbus_error_free(&error);
505 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
508 unsigned bus_dispatch(Manager *m) {
513 if (m->queued_message) {
514 /* If we cannot get rid of this message we won't
515 * dispatch any D-Bus messages, so that we won't end
516 * up wanting to queue another message. */
518 if (m->queued_message_connection)
519 if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL))
522 dbus_message_unref(m->queued_message);
523 m->queued_message = NULL;
524 m->queued_message_connection = NULL;
527 if ((c = set_first(m->bus_connections_for_dispatch))) {
528 if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE)
529 set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c);
537 static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
541 dbus_error_init(&error);
543 assert_se(reply = dbus_pending_call_steal_reply(pending));
545 switch (dbus_message_get_type(reply)) {
547 case DBUS_MESSAGE_TYPE_ERROR:
549 assert_se(dbus_set_error_from_message(&error, reply));
550 log_warning("RequestName() failed: %s", bus_error_message(&error));
553 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
556 if (!dbus_message_get_args(reply,
558 DBUS_TYPE_UINT32, &r,
559 DBUS_TYPE_INVALID)) {
560 log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error));
565 log_debug("Successfully acquired name.");
567 log_error("Name already owned.");
573 assert_not_reached("Invalid reply message");
576 dbus_message_unref(reply);
577 dbus_error_free(&error);
580 static int request_name(Manager *m) {
581 const char *name = "org.freedesktop.systemd1";
582 /* Allow replacing of our name, to ease implementation of
583 * reexecution, where we keep the old connection open until
584 * after the new connection is set up and the name installed
585 * to allow clients to synchronously wait for reexecution to
587 uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
588 DBusMessage *message = NULL;
589 DBusPendingCall *pending = NULL;
591 if (!(message = dbus_message_new_method_call(
598 if (!dbus_message_append_args(
600 DBUS_TYPE_STRING, &name,
601 DBUS_TYPE_UINT32, &flags,
605 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
608 if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
611 dbus_message_unref(message);
612 dbus_pending_call_unref(pending);
614 /* We simple ask for the name and don't wait for it. Sooner or
615 * later we'll have it. */
621 dbus_pending_call_cancel(pending);
622 dbus_pending_call_unref(pending);
626 dbus_message_unref(message);
631 static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
634 Manager *m = userdata;
638 dbus_error_init(&error);
640 assert_se(reply = dbus_pending_call_steal_reply(pending));
642 switch (dbus_message_get_type(reply)) {
644 case DBUS_MESSAGE_TYPE_ERROR:
646 assert_se(dbus_set_error_from_message(&error, reply));
647 log_warning("ListNames() failed: %s", bus_error_message(&error));
650 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
654 if ((r = bus_parse_strv(reply, &l)) < 0)
655 log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
660 /* This is a bit hacky, we say the
661 * owner of the name is the name
662 * itself, because we don't want the
663 * extra traffic to figure out the
665 manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
674 assert_not_reached("Invalid reply message");
677 dbus_message_unref(reply);
678 dbus_error_free(&error);
681 static int query_name_list(Manager *m) {
682 DBusMessage *message = NULL;
683 DBusPendingCall *pending = NULL;
685 /* Asks for the currently installed bus names */
687 if (!(message = dbus_message_new_method_call(
694 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
697 if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
700 dbus_message_unref(message);
701 dbus_pending_call_unref(pending);
703 /* We simple ask for the list and don't wait for it. Sooner or
704 * later we'll get it. */
710 dbus_pending_call_cancel(pending);
711 dbus_pending_call_unref(pending);
715 dbus_message_unref(message);
720 static int bus_setup_loop(Manager *m, DBusConnection *bus) {
724 dbus_connection_set_exit_on_disconnect(bus, FALSE);
726 if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
727 !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
730 if (set_put(m->bus_connections_for_dispatch, bus) < 0)
733 dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL);
737 static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
738 return uid == 0 || uid == geteuid();
741 static void bus_new_connection(
743 DBusConnection *new_connection,
750 if (set_size(m->bus_connections) >= CONNECTIONS_MAX) {
751 log_error("Too many concurrent connections.");
755 dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
757 if (bus_setup_loop(m, new_connection) < 0)
760 if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
761 !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
762 !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
763 !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) {
768 log_debug("Accepted connection on private bus.");
770 dbus_connection_ref(new_connection);
773 static int init_registered_system_bus(Manager *m) {
776 if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL))
779 if (m->running_as != SYSTEMD_SYSTEM) {
782 dbus_error_init(&error);
784 dbus_bus_add_match(m->system_bus,
786 "interface='org.freedesktop.systemd1.Agent',"
788 "path='/org/freedesktop/systemd1/agent'",
791 if (dbus_error_is_set(&error)) {
792 log_error("Failed to register match: %s", bus_error_message(&error));
793 dbus_error_free(&error);
798 log_debug("Successfully connected to system D-Bus bus %s as %s",
799 strnull((id = dbus_connection_get_server_id(m->system_bus))),
800 strnull(dbus_bus_get_unique_name(m->system_bus)));
806 static int init_registered_api_bus(Manager *m) {
809 if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
810 !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
811 !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
812 !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL))
815 /* Get NameOwnerChange messages */
816 dbus_bus_add_match(m->api_bus,
818 "sender='"DBUS_SERVICE_DBUS"',"
819 "interface='"DBUS_INTERFACE_DBUS"',"
820 "member='NameOwnerChanged',"
821 "path='"DBUS_PATH_DBUS"'",
824 /* Get activation requests */
825 dbus_bus_add_match(m->api_bus,
827 "sender='"DBUS_SERVICE_DBUS"',"
828 "interface='org.freedesktop.systemd1.Activator',"
829 "member='ActivationRequest',"
830 "path='"DBUS_PATH_DBUS"'",
837 r = query_name_list(m);
841 if (m->running_as == SYSTEMD_USER) {
843 log_debug("Successfully connected to API D-Bus bus %s as %s",
844 strnull((id = dbus_connection_get_server_id(m->api_bus))),
845 strnull(dbus_bus_get_unique_name(m->api_bus)));
848 log_debug("Successfully initialized API on the system bus");
853 static void bus_register_cb(DBusPendingCall *pending, void *userdata) {
854 Manager *m = userdata;
855 DBusConnection **conn;
861 dbus_error_init(&error);
863 conn = dbus_pending_call_get_data(pending, m->conn_data_slot);
864 assert(conn == &m->system_bus || conn == &m->api_bus);
866 reply = dbus_pending_call_steal_reply(pending);
868 switch (dbus_message_get_type(reply)) {
869 case DBUS_MESSAGE_TYPE_ERROR:
870 assert_se(dbus_set_error_from_message(&error, reply));
871 log_warning("Failed to register to bus: %s", bus_error_message(&error));
874 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
875 if (!dbus_message_get_args(reply, &error,
876 DBUS_TYPE_STRING, &name,
877 DBUS_TYPE_INVALID)) {
878 log_error("Failed to parse Hello reply: %s", bus_error_message(&error));
883 log_debug("Received name %s in reply to Hello", name);
884 if (!dbus_bus_set_unique_name(*conn, name)) {
885 log_error("Failed to set unique name");
890 if (conn == &m->system_bus) {
891 r = init_registered_system_bus(m);
892 if (r == 0 && m->running_as == SYSTEMD_SYSTEM)
893 r = init_registered_api_bus(m);
895 r = init_registered_api_bus(m);
899 assert_not_reached("Invalid reply message");
902 dbus_message_unref(reply);
903 dbus_error_free(&error);
906 if (conn == &m->system_bus) {
907 log_debug("Failed setting up the system bus");
910 log_debug("Failed setting up the API bus");
916 static int manager_bus_async_register(Manager *m, DBusConnection **conn) {
917 DBusMessage *message = NULL;
918 DBusPendingCall *pending = NULL;
920 message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
927 if (!dbus_connection_send_with_reply(*conn, message, &pending, -1))
930 if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL))
933 if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL))
936 dbus_message_unref(message);
937 dbus_pending_call_unref(pending);
942 dbus_pending_call_cancel(pending);
943 dbus_pending_call_unref(pending);
947 dbus_message_unref(message);
952 static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) {
954 DBusConnection *connection;
958 case DBUS_BUS_SYSTEM:
959 address = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
960 if (!address || !address[0])
961 address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
963 case DBUS_BUS_SESSION:
964 address = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
965 if (!address || !address[0])
966 address = DBUS_SESSION_BUS_DEFAULT_ADDRESS;
969 assert_not_reached("Invalid bus type");
972 dbus_error_init(&error);
974 connection = dbus_connection_open_private(address, &error);
976 log_warning("Failed to open private bus connection: %s", bus_error_message(&error));
983 dbus_connection_close(connection);
984 dbus_error_free(&error);
988 static int bus_init_system(Manager *m) {
994 m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM);
995 if (!m->system_bus) {
996 log_debug("Failed to connect to system D-Bus, retrying later");
1001 r = bus_setup_loop(m, m->system_bus);
1005 r = manager_bus_async_register(m, &m->system_bus);
1016 static int bus_init_api(Manager *m) {
1022 if (m->running_as == SYSTEMD_SYSTEM) {
1023 m->api_bus = m->system_bus;
1024 /* In this mode there is no distinct connection to the API bus,
1025 * the API is published on the system bus.
1026 * bus_register_cb() is aware of that and will init the API
1027 * when the system bus gets registered.
1028 * No need to setup anything here. */
1032 m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION);
1034 log_debug("Failed to connect to API D-Bus, retrying later");
1039 r = bus_setup_loop(m, m->api_bus);
1043 r = manager_bus_async_register(m, &m->api_bus);
1054 static int bus_init_private(Manager *m) {
1057 const char *const external_only[] = {
1064 dbus_error_init(&error);
1069 if (m->running_as == SYSTEMD_SYSTEM) {
1071 /* We want the private bus only when running as init */
1075 unlink("/run/systemd/private");
1076 m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
1082 e = secure_getenv("XDG_RUNTIME_DIR");
1086 if (asprintf(&p, "%s/systemd/private", e) < 0) {
1091 mkdir_parents_label(p, 0755);
1095 escaped = dbus_address_escape_value(e);
1100 if (asprintf(&p, "unix:path=%s/systemd/private", escaped) < 0) {
1107 m->private_bus = dbus_server_listen(p, &error);
1111 if (!m->private_bus) {
1112 log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
1117 if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) ||
1118 !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
1119 !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
1124 dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL);
1126 log_debug("Successfully created private D-Bus server.");
1131 bus_done_private(m);
1132 dbus_error_free(&error);
1137 int bus_init(Manager *m, bool try_bus_connect) {
1140 if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
1141 set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
1144 if (m->name_data_slot < 0)
1145 if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
1148 if (m->conn_data_slot < 0)
1149 if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot))
1152 if (m->subscribed_data_slot < 0)
1153 if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot))
1156 if (try_bus_connect) {
1157 if ((r = bus_init_system(m)) < 0 ||
1158 (r = bus_init_api(m)) < 0)
1162 if ((r = bus_init_private(m)) < 0)
1170 static void shutdown_connection(Manager *m, DBusConnection *c) {
1175 HASHMAP_FOREACH(j, m->jobs, i) {
1176 JobBusClient *cl, *nextcl;
1177 LIST_FOREACH_SAFE(client, cl, nextcl, j->bus_client_list) {
1179 LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
1185 set_remove(m->bus_connections, c);
1186 set_remove(m->bus_connections_for_dispatch, c);
1188 if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
1191 while ((t = set_steal_first(s)))
1197 if (m->queued_message_connection == c) {
1198 m->queued_message_connection = NULL;
1200 if (m->queued_message) {
1201 dbus_message_unref(m->queued_message);
1202 m->queued_message = NULL;
1206 dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
1207 /* system manager cannot afford to block on DBus */
1208 if (m->running_as != SYSTEMD_SYSTEM)
1209 dbus_connection_flush(c);
1210 dbus_connection_close(c);
1211 dbus_connection_unref(c);
1214 static void bus_done_api(Manager *m) {
1218 if (m->running_as == SYSTEMD_USER)
1219 shutdown_connection(m, m->api_bus);
1223 if (m->queued_message) {
1224 dbus_message_unref(m->queued_message);
1225 m->queued_message = NULL;
1229 static void bus_done_system(Manager *m) {
1233 if (m->running_as == SYSTEMD_SYSTEM)
1236 shutdown_connection(m, m->system_bus);
1237 m->system_bus = NULL;
1240 static void bus_done_private(Manager *m) {
1241 if (!m->private_bus)
1244 dbus_server_disconnect(m->private_bus);
1245 dbus_server_unref(m->private_bus);
1246 m->private_bus = NULL;
1249 void bus_done(Manager *m) {
1254 bus_done_private(m);
1256 while ((c = set_steal_first(m->bus_connections)))
1257 shutdown_connection(m, c);
1259 while ((c = set_steal_first(m->bus_connections_for_dispatch)))
1260 shutdown_connection(m, c);
1262 set_free(m->bus_connections);
1263 set_free(m->bus_connections_for_dispatch);
1265 if (m->name_data_slot >= 0)
1266 dbus_pending_call_free_data_slot(&m->name_data_slot);
1268 if (m->conn_data_slot >= 0)
1269 dbus_pending_call_free_data_slot(&m->conn_data_slot);
1271 if (m->subscribed_data_slot >= 0)
1272 dbus_connection_free_data_slot(&m->subscribed_data_slot);
1275 static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
1276 Manager *m = userdata;
1281 dbus_error_init(&error);
1283 assert_se(name = BUS_PENDING_CALL_NAME(m, pending));
1284 assert_se(reply = dbus_pending_call_steal_reply(pending));
1286 switch (dbus_message_get_type(reply)) {
1288 case DBUS_MESSAGE_TYPE_ERROR:
1290 assert_se(dbus_set_error_from_message(&error, reply));
1291 log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error));
1294 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
1297 if (!dbus_message_get_args(reply,
1299 DBUS_TYPE_UINT32, &r,
1300 DBUS_TYPE_INVALID)) {
1301 log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error));
1305 manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
1310 assert_not_reached("Invalid reply message");
1313 dbus_message_unref(reply);
1314 dbus_error_free(&error);
1317 int bus_query_pid(Manager *m, const char *name) {
1318 DBusMessage *message = NULL;
1319 DBusPendingCall *pending = NULL;
1325 if (!(message = dbus_message_new_method_call(
1328 DBUS_INTERFACE_DBUS,
1329 "GetConnectionUnixProcessID")))
1332 if (!(dbus_message_append_args(
1334 DBUS_TYPE_STRING, &name,
1335 DBUS_TYPE_INVALID)))
1338 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
1341 if (!(n = strdup(name)))
1344 if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
1349 if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
1352 dbus_message_unref(message);
1353 dbus_pending_call_unref(pending);
1361 dbus_pending_call_cancel(pending);
1362 dbus_pending_call_unref(pending);
1366 dbus_message_unref(message);
1371 int bus_broadcast(Manager *m, DBusMessage *message) {
1379 SET_FOREACH(c, m->bus_connections_for_dispatch, i)
1380 if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM)
1381 oom = !dbus_connection_send(c, message, NULL);
1383 SET_FOREACH(c, m->bus_connections, i)
1384 if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM)
1385 oom = !dbus_connection_send(c, message, NULL);
1387 return oom ? -ENOMEM : 0;
1390 bool bus_has_subscriber(Manager *m) {
1396 SET_FOREACH(c, m->bus_connections_for_dispatch, i)
1397 if (bus_connection_has_subscriber(m, c))
1400 SET_FOREACH(c, m->bus_connections, i)
1401 if (bus_connection_has_subscriber(m, c))
1407 bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
1411 return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
1414 int bus_fdset_add_all(Manager *m, FDSet *fds) {
1421 /* When we are about to reexecute we add all D-Bus fds to the
1422 * set to pass over to the newly executed systemd. They won't
1423 * be used there however, except that they are closed at the
1424 * very end of deserialization, those making it possible for
1425 * clients to synchronously wait for systemd to reexec by
1426 * simply waiting for disconnection */
1428 SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
1431 if (dbus_connection_get_unix_fd(c, &fd)) {
1432 fd = fdset_put_dup(fds, fd);
1439 SET_FOREACH(c, m->bus_connections, i) {
1442 if (dbus_connection_get_unix_fd(c, &fd)) {
1443 fd = fdset_put_dup(fds, fd);
1453 void bus_broadcast_finished(
1455 usec_t firmware_usec,
1459 usec_t userspace_usec,
1460 usec_t total_usec) {
1462 DBusMessage *message;
1466 message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
1472 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
1473 if (!dbus_message_append_args(message,
1474 DBUS_TYPE_UINT64, &firmware_usec,
1475 DBUS_TYPE_UINT64, &loader_usec,
1476 DBUS_TYPE_UINT64, &kernel_usec,
1477 DBUS_TYPE_UINT64, &initrd_usec,
1478 DBUS_TYPE_UINT64, &userspace_usec,
1479 DBUS_TYPE_UINT64, &total_usec,
1480 DBUS_TYPE_INVALID)) {
1486 if (bus_broadcast(m, message) < 0) {
1493 dbus_message_unref(message);