You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
5.1 KiB
131 lines
5.1 KiB
From 30cbb55a8d9fedf07d5c9d792849b723b856cd62 Mon Sep 17 00:00:00 2001
|
|
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
Date: Sun, 12 Feb 2023 12:15:08 +0000
|
|
Subject: [PATCH] sulogin: fix control lost of the current terminal when
|
|
default.target is rescue.target
|
|
|
|
When default.target is rescue.target, exiting from the single-user shell
|
|
results in lost of the control of the current terminal. This is because the
|
|
operation performed to continue to boot is systemctl default but default.target
|
|
is now rescue.target and it is already active. Hence, no new process that
|
|
controls the current terminal is created. Users need to make hardware reset to
|
|
recover the situation.
|
|
|
|
This sounds like a bit corner case issue and some might feel configuring
|
|
default.target as rescue.target is odd because there are several other ways to
|
|
transition to rescue.mode without configuring default.target to rescue.target
|
|
such as systemctl rescue or systemd.unit=rescue.target something like
|
|
that. However, users unfamiliar with systemd operations tend to come up with
|
|
systemctl set-default rescue.target.
|
|
|
|
To fix this issue, let's transition to default.target only when default.target
|
|
is inactive. Otherwise, invoke the single-user shell again to keep control of
|
|
the current terminal for users.
|
|
|
|
This new logic depends on whether D-Bus working well. Exiting without any check
|
|
of result of systemctl default could lead to again the control lost of the
|
|
current terminal. Hence, add checking results of each D-Bus operations
|
|
including systemctl default and invoke the single-user shell if they fail.
|
|
|
|
(cherry picked from commit 937ca8330d11e406b8ef343bead6f4f6244e39c7)
|
|
|
|
Resolves: #2169932
|
|
---
|
|
src/sulogin-shell/sulogin-shell.c | 60 +++++++++++++++++++++++++------
|
|
1 file changed, 50 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c
|
|
index a1ea2333de..8f14ee11bb 100644
|
|
--- a/src/sulogin-shell/sulogin-shell.c
|
|
+++ b/src/sulogin-shell/sulogin-shell.c
|
|
@@ -14,6 +14,8 @@
|
|
#include "process-util.h"
|
|
#include "sd-bus.h"
|
|
#include "signal-util.h"
|
|
+#include "special.h"
|
|
+#include "unit-def.h"
|
|
|
|
static int reload_manager(sd_bus *bus) {
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
@@ -43,6 +45,28 @@ static int reload_manager(sd_bus *bus) {
|
|
return 0;
|
|
}
|
|
|
|
+static int default_target_is_inactive(sd_bus *bus) {
|
|
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
+ _cleanup_free_ char *path = NULL, *state = NULL;
|
|
+ int r;
|
|
+
|
|
+ path = unit_dbus_path_from_name(SPECIAL_DEFAULT_TARGET);
|
|
+ if (!path)
|
|
+ return log_oom();
|
|
+
|
|
+ r = sd_bus_get_property_string(bus,
|
|
+ "org.freedesktop.systemd1",
|
|
+ path,
|
|
+ "org.freedesktop.systemd1.Unit",
|
|
+ "ActiveState",
|
|
+ &error,
|
|
+ &state);
|
|
+ if (r < 0)
|
|
+ return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
|
|
+
|
|
+ return streq_ptr(state, "inactive");
|
|
+}
|
|
+
|
|
static int start_default_target(sd_bus *bus) {
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
int r;
|
|
@@ -95,7 +119,6 @@ int main(int argc, char *argv[]) {
|
|
NULL, /* --force */
|
|
NULL
|
|
};
|
|
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
int r;
|
|
|
|
log_set_target(LOG_TARGET_AUTO);
|
|
@@ -108,17 +131,34 @@ int main(int argc, char *argv[]) {
|
|
/* allows passwordless logins if root account is locked. */
|
|
sulogin_cmdline[1] = "--force";
|
|
|
|
- (void) fork_wait(sulogin_cmdline);
|
|
+ for (;;) {
|
|
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
+
|
|
+ (void) fork_wait(sulogin_cmdline);
|
|
+
|
|
+ r = bus_connect_system_systemd(&bus);
|
|
+ if (r < 0) {
|
|
+ log_warning_errno(r, "Failed to get D-Bus connection: %m");
|
|
+ goto fallback;
|
|
+ }
|
|
|
|
- r = bus_connect_system_systemd(&bus);
|
|
- if (r < 0) {
|
|
- log_warning_errno(r, "Failed to get D-Bus connection: %m");
|
|
- r = 0;
|
|
- } else {
|
|
- (void) reload_manager(bus);
|
|
+ if (reload_manager(bus) < 0)
|
|
+ goto fallback;
|
|
|
|
- r = start_default_target(bus);
|
|
+ r = default_target_is_inactive(bus);
|
|
+ if (r < 0)
|
|
+ goto fallback;
|
|
+ if (!r) {
|
|
+ log_warning(SPECIAL_DEFAULT_TARGET" is not inactive. Please review the "SPECIAL_DEFAULT_TARGET" setting.\n");
|
|
+ goto fallback;
|
|
+ }
|
|
+
|
|
+ if (start_default_target(bus) >= 0)
|
|
+ break;
|
|
+
|
|
+ fallback:
|
|
+ log_warning("Fallback to the single-user shell.\n");
|
|
}
|
|
|
|
- return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
+ return 0;
|
|
}
|