diff --git a/docs/configuration.md b/docs/configuration.md index 2bb7eab..c0fae93 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -276,6 +276,10 @@ Importing this module will run `btrfs device scan` and pull btrfs modules. When enabled, attempts to resume after hibernation if resume= is passed on the kernel command line. +> Please use the following option with **CAUTION** as it can be unstable in certain configurations! Any writes to disks that occur pre-resume run the risk of causing system instability! For more information have a read of the warnings in the [kernel docs](https://www.kernel.org/doc/html/latest/power/swsusp.html). + +* `late_resume` (true) When enabled will attempt to resume from hibernation after decryption and device mapping, allowing resume from encrypted or otherwise hidden swap devices. + ### Cryptographic modules Several cryptographic modules are provided, mostly to assist in mounting encrypted volumes and handling keyfiles. diff --git a/src/ugrd/fs/resume.py b/src/ugrd/fs/resume.py index 38f5ddd..5425449 100644 --- a/src/ugrd/fs/resume.py +++ b/src/ugrd/fs/resume.py @@ -1,7 +1,8 @@ __version__ = "0.4.0" +from zenlib.util import contains, unset -def handle_resume(self) -> None: +def resume(self) -> None: """Returns a bash script handling resume from hibernation. Checks that /sys/power/resume is writable, resume= is set, and noresume is not set, if so, checks if PARTUUID= is in the resume var, and tries to use blkid to find the resume device. @@ -15,23 +16,48 @@ def handle_resume(self) -> None: Distinguising between a fresh boot and missing/borked hibernation image is not possible at run time. """ return [ - "resumeval=$(readvar resume)", # read the cmdline resume var - 'if ! check_var noresume && [ -n "$resumeval" ] && [ -w /sys/power/resume ]; then', - ' if echo "$resumeval" | grep -q "PARTUUID="; then', # resolve partuuid to device + # Check resume support + '[ -n "$1" ] || (ewarn "No device?" ; return 1)', + '[ -w /sys/power/resume ] || (ewarn "Kernel does not support resume!" ; return 1)', + '[[ ! "$(cat /sys/power/resume)" == "0:0" ]] || ewarn "/sys/power/resume not empty, resume has already been attempted!"', + + # Safety checks + 'if ! [ -z $(lsblk -Q MOUNTPOINT)] ; then', + r' eerror "Cannot safely resume with mounted block devices:\n$(lsblk -Q MOUNTPOINT -no PATH)"', + ' return 1', + 'fi', + + '[ -b "$1" ] || (ewarn "\'$1\' is not a valid block device!" ; return 1)', + + 'einfo "Attempting resume from: $1"', + 'echo -n "$1" > /sys/power/resume', + 'einfo "No image on $resume"', + 'return 0', + ] + +def handle_early_resume(self) -> None: + return [ + 'resumeval=$(readvar resume)', + 'if ! check_var noresume && [ -n "$resumeval" ] ; then', + ' if echo "$resumeval" | grep -qE "^PARTUUID=|^UUID="; then', ' resume=$(blkid -t "$resumeval" -o device)', - " else", - " resume=$resumeval", - " fi", - ' if [ -e "$resume" ]; then', # Check if the resume device exists - ' einfo "Resuming from: $resume"', - ' echo -n "$resume" > /sys/power/resume', # Attempt to resume - ' ewarn "Failed to resume from: $resume"', - " else", - ' ewarn "Resume device not found: $resume)"', # Warn if the resume device does not exist - r' eerror "Block devices:\n$(blkid)"', - ' eerror "If you wish to continue booting, remove the resume= kernel parameter."', - ''' eerror " or run 'setvar noresume 1' from the recovery shell to skip resuming."''', - ' rd_fail "Failed to resume from $(readvar resume)."', - " fi", - "fi", + ' else', + ' resume="$resumeval"', + ' fi', + + ' if ! [ -z $resume ] ; then', + ' if ! resume "$resume" ; then', + ' eerror "If you wish to continue booting, remove the resume= kernel parameter."', + ''' eerror " or run 'setvar noresume 1' from the recovery shell to skip resuming."''', + ' rd_fail "Failed to resume from $(readvar resume)."', + ' fi', + ' else', + ' einfo "Resume device \'$resumeval\' not found"', + ' fi', + 'fi', ] + +@contains('late_resume') +def handle_late_resume(self) -> None: + self.logger.warning("[late_resume] enabled, this can result in data loss if filesystems are modified before resuming. Read the docs for more info.") + return handle_early_resume(self) # At the moment it's the same code but delayed, will change when more features are added \ No newline at end of file diff --git a/src/ugrd/fs/resume.toml b/src/ugrd/fs/resume.toml index c4732dd..a3ea830 100644 --- a/src/ugrd/fs/resume.toml +++ b/src/ugrd/fs/resume.toml @@ -1,4 +1,15 @@ cmdline_strings = [ "resume" ] +binaries = [ 'lsblk' ] + [imports.init_early] -"ugrd.fs.resume" = [ "handle_resume" ] +"ugrd.fs.resume" = [ "handle_early_resume" ] + +[imports.init_premount] +"ugrd.fs.resume" = [ "handle_late_resume"] + +[imports.functions] +"ugrd.fs.resume" = ["resume"] + +[custom_parameters] +late_resume = "bool" \ No newline at end of file