return 0;
}
-static int bus_init_api(Manager *m) {
+int bus_init_api(Manager *m) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
int r;
return 0;
}
-static int bus_init_system(Manager *m) {
+int bus_init_system(Manager *m) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
int r;
return 0;
}
-static int bus_init_private(Manager *m) {
+int bus_init_private(Manager *m) {
_cleanup_close_ int fd = -1;
union sockaddr_union sa = {
.un.sun_family = AF_UNIX
return 0;
}
-int bus_init(Manager *m, bool try_bus_connect) {
- int r;
-
- if (try_bus_connect) {
- r = bus_init_system(m);
- if (r < 0)
- return log_error_errno(r, "Failed to initialize D-Bus connection: %m");
-
- r = bus_init_api(m);
- if (r < 0)
- return log_error_errno(r, "Error occured during D-Bus APIs initialization: %m");
- }
-
- r = bus_init_private(m);
- if (r < 0)
- return log_error_errno(r, "Failed to create private D-Bus server: %m");
-
- return 0;
-}
-
static void destroy_bus(Manager *m, sd_bus **bus) {
Iterator i;
Unit *u;
return 0;
}
-static int manager_connect_bus(Manager *m, bool reexecuting) {
- bool try_bus_connect;
- Unit *u = NULL;
-
- assert(m);
-
- if (m->test_run_flags)
- return 0;
-
- u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
-
- try_bus_connect =
- (u && SERVICE(u)->deserialized_state == SERVICE_RUNNING) &&
- (reexecuting ||
- (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS")));
-
- /* Try to connect to the buses, if possible. */
- return bus_init(m, try_bus_connect);
-}
-
static unsigned manager_dispatch_cleanup_queue(Manager *m) {
Unit *u;
unsigned n = 0;
}
}
+static bool manager_dbus_is_running(Manager *m, bool deserialized) {
+ Unit *u;
+
+ assert(m);
+
+ /* This checks whether the dbus instance we are supposed to expose our APIs on is up. We check both the socket
+ * and the service unit. If the 'deserialized' parameter is true we'll check the deserialized state of the unit
+ * rather than the current one. */
+
+ if (m->test_run_flags != 0)
+ return false;
+
+ /* If we are in the user instance, and the env var is already set for us, then this means D-Bus is ran
+ * somewhere outside of our own logic. Let's use it */
+ if (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"))
+ return true;
+
+ u = manager_get_unit(m, SPECIAL_DBUS_SOCKET);
+ if (!u)
+ return false;
+ if ((deserialized ? SOCKET(u)->deserialized_state : SOCKET(u)->state) != SOCKET_RUNNING)
+ return false;
+
+ u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
+ if (!u)
+ return false;
+ if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state), SERVICE_RUNNING, SERVICE_RELOAD))
+ return false;
+
+ return true;
+}
+
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
int r;
/* This shouldn't fail, except if things are really broken. */
return r;
- /* Let's connect to the bus now. */
- (void) manager_connect_bus(m, !!serialization);
+ /* Let's set up our private bus connection now, unconditionally */
+ (void) bus_init_private(m);
+
+ /* If we are in --user mode also connect to the system bus now */
+ if (MANAGER_IS_USER(m))
+ (void) bus_init_system(m);
+
+ /* Let's connect to the bus now, but only if the unit is supposed to be up */
+ if (manager_dbus_is_running(m, !!serialization)) {
+ (void) bus_init_api(m);
+ if (MANAGER_IS_SYSTEM(m))
+ (void) bus_init_system(m);
+ }
+
+ /* Now that we are connected to all possible busses, let's deserialize who is tracking us. */
(void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
/* This is a nop on non-init */
break;
- case SIGUSR1: {
- Unit *u;
+ case SIGUSR1:
- u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
-
- if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
+ if (manager_dbus_is_running(m, false)) {
log_info("Trying to reconnect to bus...");
- bus_init(m, true);
- }
- if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
- log_info("Loading D-Bus service...");
+ (void) bus_init_api(m);
+
+ if (MANAGER_IS_SYSTEM(m))
+ (void) bus_init_system(m);
+ } else {
+ log_info("Starting D-Bus service...");
manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
}
break;
- }
case SIGUSR2: {
_cleanup_free_ char *dump = NULL;
exec_runtime_vacuum(m);
- /* It might be safe to log to the journal now. */
+ /* It might be safe to log to the journal now and connect to dbus */
manager_recheck_journal(m);
+ manager_recheck_dbus(m);
/* Sync current state of bus names with our set of listening units */
if (m->api_bus)
return 0;
}
+void manager_recheck_dbus(Manager *m) {
+ assert(m);
+
+ /* Connects to the bus if the dbus service and socket are running. If we are running in user mode this is all
+ * it does. In system mode we'll also connect to the system bus (which will most likely just reuse the
+ * connection of the API bus). That's because the system bus after all runs as service of the system instance,
+ * while in the user instance we can assume it's already there. */
+
+ if (manager_dbus_is_running(m, false)) {
+ (void) bus_init_api(m);
+
+ if (MANAGER_IS_SYSTEM(m))
+ (void) bus_init_system(m);
+ } else {
+ (void) bus_done_api(m);
+
+ if (MANAGER_IS_SYSTEM(m))
+ (void) bus_done_system(m);
+ }
+}
+
static bool manager_journal_is_running(Manager *m) {
Unit *u;
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
- Manager *m;
bool unexpected;
+ Manager *m;
assert(u);
assert(os < _UNIT_ACTIVE_STATE_MAX);
assert(ns < _UNIT_ACTIVE_STATE_MAX);
- /* Note that this is called for all low-level state changes,
- * even if they might map to the same high-level
- * UnitActiveState! That means that ns == os is an expected
- * behavior here. For example: if a mount point is remounted
- * this function will be called too! */
+ /* Note that this is called for all low-level state changes, even if they might map to the same high-level
+ * UnitActiveState! That means that ns == os is an expected behavior here. For example: if a mount point is
+ * remounted this function will be called too! */
m = u->manager;
/* Some names are special */
if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
- if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
- /* The bus might have just become available,
- * hence try to connect to it, if we aren't
- * yet connected. */
- bus_init(m, true);
-
if (u->type == UNIT_SERVICE &&
!UNIT_IS_ACTIVE_OR_RELOADING(os) &&
!MANAGER_IS_RELOADING(m)) {
manager_send_unit_plymouth(m, u);
} else {
- /* We don't care about D-Bus going down here, since we'll get an asynchronous notification for it
- * anyway. */
if (UNIT_IS_INACTIVE_OR_FAILED(ns) &&
!UNIT_IS_INACTIVE_OR_FAILED(os)
}
manager_recheck_journal(m);
+ manager_recheck_dbus(m);
unit_trigger_notify(u);
if (!MANAGER_IS_RELOADING(u->manager)) {
- /* Maybe we finished startup and are now ready for
- * being stopped because unneeded? */
+ /* Maybe we finished startup and are now ready for being stopped because unneeded? */
unit_check_unneeded(u);
- /* Maybe we finished startup, but something we needed
- * has vanished? Let's die then. (This happens when
- * something BindsTo= to a Type=oneshot unit, as these
- * units go directly from starting to inactive,
+ /* Maybe we finished startup, but something we needed has vanished? Let's die then. (This happens when
+ * something BindsTo= to a Type=oneshot unit, as these units go directly from starting to inactive,
* without ever entering started.) */
unit_check_binds_to(u);