99-limine_hibernate 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #!/usr/bin/env bash
  2. # NAME: Configure hibernation for CachyOS with Limine bootloader
  3. # REQUIRES: sudo interactive
  4. set -euo pipefail
  5. # Source common functions
  6. source "$(dirname "$0")/../common.sh" || {
  7. echo "[ERROR] Could not source common.sh" >&2
  8. exit 1
  9. }
  10. readonly LIMINE_CONFIG="/etc/default/limine"
  11. readonly MKINITCPIO_CONFIG="/etc/mkinitcpio.conf"
  12. check_requirements() {
  13. local swap_uuid
  14. swap_uuid=$(blkid -t TYPE=swap -o value -s UUID | head -n1)
  15. if [[ -z "$swap_uuid" ]]; then
  16. log_error "No swap partition found"
  17. log_info "Please create a swap partition or swapfile before running this script"
  18. exit 1
  19. fi
  20. log_info "Found swap partition UUID: $swap_uuid"
  21. readonly SWAP_UUID="$swap_uuid"
  22. }
  23. escape_for_sed() {
  24. printf '%s\n' "$1" | sed 's/[[\.*^$()+?{|]/\\&/g'
  25. }
  26. show_diff_and_confirm() {
  27. local file="$1"
  28. local description="$2"
  29. local temp_file="$3"
  30. log_info "Proposed changes for $description"
  31. log_info "File: $file"
  32. echo
  33. if command_exists colordiff; then
  34. colordiff -u "$file" "$temp_file" || true
  35. else
  36. diff -u "$file" "$temp_file" || true
  37. fi
  38. echo
  39. confirm "Apply these changes?"
  40. }
  41. update_limine_config() {
  42. log_info "Updating Limine configuration"
  43. backup_file "$LIMINE_CONFIG"
  44. local current_cmdline new_cmdline changes_made=false
  45. current_cmdline=$(grep 'KERNEL_CMDLINE\[default\]' "$LIMINE_CONFIG" | cut -d'"' -f2)
  46. log_info "Current kernel cmdline: $current_cmdline"
  47. new_cmdline="$current_cmdline"
  48. if [[ ! "$new_cmdline" =~ resume= ]]; then
  49. new_cmdline="$new_cmdline resume=UUID=$SWAP_UUID"
  50. log_info "Adding resume parameter"
  51. changes_made=true
  52. fi
  53. if [[ ! "$new_cmdline" =~ ipv6.disable= ]]; then
  54. new_cmdline="$new_cmdline ipv6.disable=1"
  55. log_info "Adding ipv6.disable parameter"
  56. changes_made=true
  57. fi
  58. new_cmdline=$(echo "$new_cmdline" | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
  59. if [[ "$changes_made" == "true" ]]; then
  60. log_info "New kernel cmdline: $new_cmdline"
  61. local new_cmdline_escaped temp_file
  62. new_cmdline_escaped=$(escape_for_sed "$new_cmdline")
  63. temp_file=$(mktemp)
  64. sed "s|KERNEL_CMDLINE\[default\]=\".*\"|KERNEL_CMDLINE[default]=\"$new_cmdline_escaped\"|" "$LIMINE_CONFIG" >"$temp_file"
  65. if show_diff_and_confirm "$LIMINE_CONFIG" "LIMINE CONFIGURATION" "$temp_file"; then
  66. cp "$temp_file" "$LIMINE_CONFIG"
  67. log_info "Limine configuration updated successfully"
  68. rm "$temp_file"
  69. return 0
  70. else
  71. log_info "Skipping Limine configuration update"
  72. log_info "You can manually add: resume=UUID=$SWAP_UUID to your kernel cmdline"
  73. rm "$temp_file"
  74. return 1
  75. fi
  76. else
  77. log_info "Limine configuration already contains required parameters"
  78. return 1
  79. fi
  80. }
  81. update_mkinitcpio_config() {
  82. log_info "Updating mkinitcpio configuration"
  83. backup_file "$MKINITCPIO_CONFIG"
  84. if grep -q '^HOOKS=.*resume' "$MKINITCPIO_CONFIG"; then
  85. log_info "Resume hook already present in mkinitcpio.conf"
  86. return 1
  87. fi
  88. log_info "Adding resume hook to mkinitcpio.conf"
  89. local current_hooks new_hooks temp_file
  90. current_hooks=$(grep '^HOOKS=' "$MKINITCPIO_CONFIG")
  91. log_info "Current HOOKS: $current_hooks"
  92. new_hooks=$(echo "$current_hooks" | sed 's/filesystems/filesystems resume/' | sed 's/resume resume/resume/')
  93. if [[ ! "$new_hooks" =~ resume ]]; then
  94. new_hooks=$(echo "$current_hooks" | sed 's/)/ resume)/')
  95. fi
  96. log_info "New HOOKS: $new_hooks"
  97. local new_hooks_escaped
  98. new_hooks_escaped=$(escape_for_sed "$new_hooks")
  99. temp_file=$(mktemp)
  100. sed "s|^HOOKS=.*|$new_hooks_escaped|" "$MKINITCPIO_CONFIG" >"$temp_file"
  101. if show_diff_and_confirm "$MKINITCPIO_CONFIG" "MKINITCPIO CONFIGURATION" "$temp_file"; then
  102. cp "$temp_file" "$MKINITCPIO_CONFIG"
  103. log_info "mkinitcpio.conf updated successfully"
  104. rm "$temp_file"
  105. return 0
  106. else
  107. log_info "Skipping mkinitcpio.conf update"
  108. log_info "You can manually add 'resume' to your HOOKS array"
  109. rm "$temp_file"
  110. return 1
  111. fi
  112. }
  113. apply_system_changes() {
  114. local limine_updated="$1"
  115. local mkinitcpio_updated="$2"
  116. local operations_needed=()
  117. log_info "System updates required"
  118. if [[ "$mkinitcpio_updated" == "true" ]]; then
  119. operations_needed+=("Regenerate initramfs (mkinitcpio -P)")
  120. fi
  121. if [[ "$limine_updated" == "true" ]]; then
  122. operations_needed+=("Update Limine bootloader (limine-update)")
  123. fi
  124. if [[ ${#operations_needed[@]} -eq 0 ]]; then
  125. log_info "No system updates needed - configuration is already up to date"
  126. return 0
  127. fi
  128. log_info "The following operations need to be performed:"
  129. for i in "${!operations_needed[@]}"; do
  130. log_info " $((i + 1)). ${operations_needed[$i]}"
  131. done
  132. if ! confirm "Apply all pending system changes?" "y"; then
  133. log_warn "Skipping system updates"
  134. log_warn "Configuration files have been updated but system changes were not applied"
  135. log_info "You will need to manually run:"
  136. if [[ "$mkinitcpio_updated" == "true" ]]; then
  137. log_info " mkinitcpio -P"
  138. fi
  139. if [[ "$limine_updated" == "true" ]]; then
  140. log_info " limine-update"
  141. fi
  142. log_warn "Hibernation will not work until these commands are executed"
  143. return 1
  144. fi
  145. log_info "Applying system changes"
  146. if [[ "$mkinitcpio_updated" == "true" ]]; then
  147. log_info "Regenerating initramfs"
  148. if ! mkinitcpio -P; then
  149. log_error "Failed to regenerate initramfs"
  150. log_info "Please check the configuration and run 'mkinitcpio -P' manually"
  151. exit 1
  152. fi
  153. log_info "Initramfs regenerated successfully"
  154. fi
  155. if [[ "$limine_updated" == "true" ]]; then
  156. log_info "Updating Limine configuration"
  157. if ! limine-update; then
  158. log_error "Failed to update Limine bootloader"
  159. log_info "Please run 'limine-update' manually"
  160. exit 1
  161. fi
  162. log_info "Limine bootloader updated successfully"
  163. fi
  164. return 0
  165. }
  166. show_completion_summary() {
  167. local limine_updated="$1"
  168. local mkinitcpio_updated="$2"
  169. log_info "Hibernation configuration completed successfully"
  170. echo
  171. log_info "Configuration details:"
  172. log_info " - Swap UUID: $SWAP_UUID"
  173. if [[ "$limine_updated" == "true" ]]; then
  174. log_info " - Resume parameter added to kernel cmdline"
  175. log_info " - IPv6 disabled (optional optimization)"
  176. else
  177. log_info " - Kernel cmdline already configured"
  178. fi
  179. if [[ "$mkinitcpio_updated" == "true" ]]; then
  180. log_info " - Resume hook added to initramfs"
  181. else
  182. log_info " - Resume hook already present in initramfs"
  183. fi
  184. echo
  185. log_info "Backups created:"
  186. log_info " - $LIMINE_CONFIG.backup.*"
  187. log_info " - $MKINITCPIO_CONFIG.backup.*"
  188. echo
  189. log_info "Next steps:"
  190. log_info " 1. Reboot your system"
  191. log_info " 2. Test hibernation with: systemctl hibernate"
  192. log_info " 3. Wake up and verify everything works correctly"
  193. echo
  194. log_info "If you encounter issues, restore backups with:"
  195. log_info " cp $LIMINE_CONFIG.backup.* $LIMINE_CONFIG"
  196. log_info " cp $MKINITCPIO_CONFIG.backup.* $MKINITCPIO_CONFIG"
  197. log_info " mkinitcpio -P && limine-update"
  198. }
  199. main() {
  200. init_script
  201. check_requirements
  202. local limine_updated mkinitcpio_updated
  203. if update_limine_config; then
  204. limine_updated="true"
  205. else
  206. limine_updated="false"
  207. fi
  208. if update_mkinitcpio_config; then
  209. mkinitcpio_updated="true"
  210. else
  211. mkinitcpio_updated="false"
  212. fi
  213. if apply_system_changes "$limine_updated" "$mkinitcpio_updated"; then
  214. show_completion_summary "$limine_updated" "$mkinitcpio_updated"
  215. finish_script 0
  216. else
  217. finish_script 1
  218. fi
  219. }
  220. main "$@"