diff --git a/man/systemctl.xml b/man/systemctl.xml
index 287decffb2..def2f8e011 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -1843,6 +1843,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
Suspend the system. This will trigger activation of the special target unit
suspend.target. This command is asynchronous, and will return after the suspend
operation is successfully enqueued. It will not wait for the suspend/resume cycle to complete.
+
+ If is specified, and systemd-logind returned
+ error for the operation, the error will be ignored and the operation will be tried again directly
+ through starting the target unit.
@@ -1853,6 +1857,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
Hibernate the system. This will trigger activation of the special target unit
hibernate.target. This command is asynchronous, and will return after the hibernation
operation is successfully enqueued. It will not wait for the hibernate/thaw cycle to complete.
+
+ This command honors in the same way as suspend.
@@ -1864,6 +1870,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
hybrid-sleep.target. This command is asynchronous, and will return after the hybrid
sleep operation is successfully enqueued. It will not wait for the sleep/wake-up cycle to complete.
+ This command honors in the same way as suspend.
+
@@ -1872,12 +1880,15 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
suspend-then-hibernate
- Suspend the system and hibernate it after the delay specified in systemd-sleep.conf.
- This will trigger activation of the special target unit suspend-then-hibernate.target.
- This command is asynchronous, and will return after the hybrid sleep operation is successfully enqueued.
+ Suspend the system and hibernate it when the battery is low, or when the delay specified
+ in systemd-sleep.conf elapsed. This will trigger activation of the special
+ target unit suspend-then-hibernate.target. This command is asynchronous,
+ and will return after the hybrid sleep operation is successfully enqueued.
It will not wait for the sleep/wake-up or hibernate/thaw cycle to complete.
-
+ This command honors in the same way as suspend.
+
+
@@ -2531,25 +2542,27 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
- When used with enable, overwrite
- any existing conflicting symlinks.
+ When used with enable, overwrite any existing conflicting symlinks.
- When used with edit, create all of the
- specified units which do not already exist.
+ When used with edit, create all of the specified units which do not already exist.
- When used with halt, poweroff, reboot or
- kexec, execute the selected operation without shutting down all units. However, all
- processes will be killed forcibly and all file systems are unmounted or remounted read-only. This is hence a
- drastic but relatively safe option to request an immediate reboot. If is specified
- twice for these operations (with the exception of kexec), they will be executed
- immediately, without terminating any processes or unmounting any file systems.
+ When used with suspend, hibernate, hybrid-sleep,
+ or suspend-then-hibernate, the error returned by systemd-logind
+ will be ignored, and the operation will be performed directly through starting the corresponding units.
+
+
+ When used with halt, poweroff, reboot,
+ or kexec, execute the selected operation without shutting down all units. However,
+ all processes will be killed forcibly and all file systems are unmounted or remounted read-only.
+ This is hence a drastic but relatively safe option to request an immediate reboot. If
+ is specified twice for these operations (with the exception of kexec), they will
+ be executed immediately, without terminating any processes or unmounting any file systems.
- Specifying
- twice with any of these operations might result in data loss. Note that when
- is specified twice the selected operation is executed by
- systemctl itself, and the system manager is not contacted. This means the command should
- succeed even when the system manager has crashed.
+ Specifying twice with any of these operations might result in data loss.
+ Note that when is specified twice the selected operation is executed by
+ systemctl itself, and the system manager is not contacted. This means the command
+ should succeed even when the system manager has crashed.
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 38bfaa56be..53e966562e 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2156,6 +2156,14 @@ static int method_do_shutdown_or_sleep(
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Not running on EFI and resume= is not set, or noresume is set. No available method to resume from hibernation");
+ case SLEEP_RESUME_DEVICE_MISSING:
+ return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "Specified resume device is missing or is not an active swap device");
+
+ case SLEEP_RESUME_MISCONFIGURED:
+ return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "Invalid resume config: resume= is not populated yet resume_offset= is");
+
case SLEEP_NOT_ENOUGH_SWAP_SPACE:
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Not enough suitable swap space for hibernation available on compatible block devices and file systems");
diff --git a/src/shared/hibernate-util.c b/src/shared/hibernate-util.c
index cb26a9ab27..7c21157580 100644
--- a/src/shared/hibernate-util.c
+++ b/src/shared/hibernate-util.c
@@ -159,7 +159,7 @@ static int read_resume_config(dev_t *ret_devno, uint64_t *ret_offset) {
}
if (devno == 0 && offset > 0 && offset != UINT64_MAX)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
"Found populated /sys/power/resume_offset (%" PRIu64 ") but /sys/power/resume is not set, refusing.",
offset);
@@ -394,7 +394,7 @@ int find_suitable_hibernation_device_full(HibernationDevice *ret_device, uint64_
if (!entry) {
/* No need to check n_swaps == 0, since it's rejected early */
assert(resume_config_devno > 0);
- return log_debug_errno(SYNTHETIC_ERRNO(ENOSPC), "Cannot find swap entry corresponding to /sys/power/resume.");
+ return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Cannot find swap entry corresponding to /sys/power/resume.");
}
if (ret_device) {
@@ -452,11 +452,11 @@ int hibernation_is_safe(void) {
bypass_space_check = getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0;
r = find_suitable_hibernation_device_full(NULL, &size, &used);
- if (r == -ENOSPC && bypass_space_check)
- /* If we don't have any available swap space at all, and SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK
- * is set, skip all remaining checks since we can't do that properly anyway. It is quite
- * possible that the user is using a setup similar to #30083. When we actually perform
- * hibernation in sleep.c we'll check everything again. */
+ if (IN_SET(r, -ENOSPC, -ESTALE) && bypass_space_check)
+ /* If we don't have any available swap space at all, or the specified resume device is missing,
+ * and $SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK is set, skip all remaining checks since
+ * we can't do that properly anyway. It is quite possible that the user is using a setup
+ * similar to #30083. When we actually perform hibernation in sleep.c we'll check everything again. */
return 0;
if (r < 0)
return r;
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index aac145836b..3d4d331710 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -368,16 +368,28 @@ static int sleep_supported_internal(
}
r = hibernation_is_safe();
- if (r == -ENOTRECOVERABLE) {
+ switch (r) {
+
+ case -ENOTRECOVERABLE:
*ret_support = SLEEP_RESUME_NOT_SUPPORTED;
return false;
- }
- if (r == -ENOSPC) {
+
+ case -ESTALE:
+ *ret_support = SLEEP_RESUME_DEVICE_MISSING;
+ return false;
+
+ case -ENOMEDIUM:
+ *ret_support = SLEEP_RESUME_MISCONFIGURED;
+ return false;
+
+ case -ENOSPC:
*ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE;
return false;
+
+ default:
+ if (r < 0)
+ return r;
}
- if (r < 0)
- return r;
} else
assert(!sleep_config->modes[operation]);
diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h
index 75d9c4a622..b59bce8fc4 100644
--- a/src/shared/sleep-config.h
+++ b/src/shared/sleep-config.h
@@ -59,6 +59,8 @@ typedef enum SleepSupport {
SLEEP_NOT_CONFIGURED, /* SleepConfig.states is not configured */
SLEEP_STATE_OR_MODE_NOT_SUPPORTED, /* SleepConfig.states/modes are not supported by kernel */
SLEEP_RESUME_NOT_SUPPORTED,
+ SLEEP_RESUME_DEVICE_MISSING, /* resume= is specified, but the device cannot be found in /proc/swaps */
+ SLEEP_RESUME_MISCONFIGURED, /* resume= is not set yet resume_offset= is configured */
SLEEP_NOT_ENOUGH_SWAP_SPACE,
SLEEP_ALARM_NOT_SUPPORTED, /* CLOCK_BOOTTIME_ALARM is unsupported by kernel (only used by s2h) */
} SleepSupport;
diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c
index 4b99d0c629..95cf00fc81 100644
--- a/src/systemctl/systemctl-start-special.c
+++ b/src/systemctl/systemctl-start-special.c
@@ -223,8 +223,11 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
case ACTION_HYBRID_SLEEP:
case ACTION_SUSPEND_THEN_HIBERNATE:
+ /* For sleep operations, do not automatically fall back to low-level operation for
+ * errors other than logind not available. There's a high chance that logind did
+ * some extra sanity check and that didn't pass. */
r = logind_reboot(a);
- if (r >= 0 || IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ if (r >= 0 || (r != -ENOSYS && arg_force == 0))
return r;
arg_no_block = true;