01grub 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #!/bin/bash
  2. #
  3. # Stefan Seyfried, SUSE Linux Products GmbH 2006, GPL v2
  4. # mostly taken from the powersave project.
  5. GRUBONCE="/usr/sbin/grubonce"
  6. GRUBDEFAULT="/boot/grub/default"
  7. GRUBDEFSAVE="/run/suspend.grubonce.default"
  8. #####################################################################
  9. # gets a list of available kernels from /boot/grub/menu.lst
  10. # kernels are in the array $KERNELS, output to stdout to be eval-ed.
  11. getkernels()
  12. {
  13. # DEBUG "Running getkernels()" INFO
  14. local MENU_LST="/boot/grub/menu.lst"
  15. local I DUMMY MNT ROOTDEV
  16. declare -i I=0 J=-1
  17. # we need the root partition later to decide if this is the kernel to select
  18. while read ROOTDEV MNT DUMMY; do
  19. [ "$ROOTDEV" = "rootfs" ] && continue # not what we are searching for
  20. if [ "$MNT" = "/" ]; then
  21. break
  22. fi
  23. done < /proc/mounts
  24. # build an array KERNELS with all the kernels in /boot/grub/menu.lst
  25. # the array MENU_ENTRIES contains the corresponding menu entry numbers
  26. # DEFAULT_BOOT contains the default entry.
  27. while read LINE; do
  28. case $LINE in
  29. title*)
  30. let J++ # increase for every menu entry, even for non-linux
  31. # DEBUG "Found grub menu entry #${J}: '${LINE}'" INFO
  32. ;;
  33. default*)
  34. DUMMY=($LINE) # "default 0 #maybe a comment"
  35. echo "DEFAULT_BOOT=${DUMMY[1]}" # ^^[0]^^ 1 ^^[2]^ 3 ^^[4]^^
  36. # DEBUG "Default boot entry is '${DUMMY[1]}'" INFO
  37. ;;
  38. kernel*noresume*)
  39. # we probably found the "failsafe" kernel that won't resume...
  40. echo " Skipping grub entry #${J}, because it has the noresume option" >&2
  41. ;;
  42. kernel*root=*)
  43. local ROOT
  44. ROOT=${LINE#*root=}
  45. DUMMY=($ROOT)
  46. ROOT=${DUMMY[0]}
  47. if [ "$(echo $ROOT | grep LABEL)" ]; then
  48. LABEL=`echo $ROOT | cut -d"=" -f2`
  49. ROOT=`readlink -f /dev/disk/by-label/$LABEL`
  50. elif [ "$(echo $ROOT | grep UUID)" ]; then
  51. UUID=`echo $ROOT | cut -d"=" -f2`
  52. ROOT=`readlink -f /dev/disk/by-uuid/$UUID`
  53. fi
  54. if [ "$(stat -Lc '%t:%T' $ROOT)" != "$(stat -Lc '%t:%T' $ROOTDEV)" ]; then
  55. echo " Skipping grub entry #${J}, because its root= parameter ($ROOT)" >&2
  56. echo " does not match the current root device ($ROOTDEV)." >&2
  57. continue
  58. fi
  59. DUMMY=($LINE) # kernel (hd0,1)/boot/latestkernel-ABC root=/dev/hda2
  60. echo "KERNELS[$I]='${DUMMY[1]##*/}'" # latestkernel-ABC
  61. echo "MENU_ENTRIES[$I]=$J"
  62. # DEBUG "Found kernel entry #${I}: '${DUMMY[1]##*/}'" INFO
  63. let I++
  64. ;;
  65. kernel*)
  66. # a kernel without "root="? We better skip that one...
  67. echo " Skipping grub entry #${J}, because it has no root= option" >&2
  68. ;;
  69. *) ;;
  70. esac
  71. done < $MENU_LST
  72. }
  73. #############################################################
  74. # runs grubonce from the grub package to select which kernel
  75. # to boot on next startup
  76. grub-once()
  77. {
  78. if [ -x "$GRUBONCE" ]; then
  79. rm -f "$GRUBDEFSAVE"
  80. if [ -e "$GRUBDEFAULT" ]; then
  81. echo " saving original $GRUBDEFAULT"
  82. cp "$GRUBDEFAULT" "$GRUBDEFSAVE"
  83. fi
  84. echo " running '$GRUBONCE $1'"
  85. $GRUBONCE $1
  86. else
  87. echo "WARNING: $GRUBONCE not found, not preparing bootloader"
  88. fi
  89. }
  90. #############################################################
  91. # restore grub default after (eventually failed) resume
  92. grub-once-restore()
  93. {
  94. echo "INFO: running grub-once-restore"
  95. rm -f "$GRUBDEFAULT"
  96. if [ -e "$GRUBDEFSAVE" ]; then
  97. echo " restoring original $GRUBDEFAULT"
  98. mv "$GRUBDEFSAVE" "$GRUBDEFAULT"
  99. fi
  100. }
  101. #############################################################################
  102. # try to find a kernel image that matches the actually running kernel.
  103. # We need this, if more than one kernel is installed. This works reasonably
  104. # well with grub, if all kernels are named "kernel-`uname -r`" and are
  105. # located in /boot. If they are not, good luck ;-)
  106. find-kernel-entry()
  107. {
  108. NEXT_BOOT=-1
  109. ARCH=`uname -m`
  110. declare -i I=0
  111. # DEBUG "running kernel: $RUNNING" DIAG
  112. while [ -n "${KERNELS[$I]}" ]; do
  113. BOOTING="${KERNELS[$I]}"
  114. if IMAGE=`readlink /boot/$BOOTING` && [ -e "/boot/${IMAGE##*/}" ]; then
  115. # DEBUG "Found kernel symlink $BOOTING => $IMAGE" INFO
  116. BOOTING=$IMAGE
  117. fi
  118. case $ARCH in
  119. ppc*) BOOTING="${BOOTING#*vmlinux-}" ;;
  120. *) BOOTING="${BOOTING#*kernel-}" ;;
  121. esac
  122. if [ "$RUNNING" == "$BOOTING" ]; then
  123. NEXT_BOOT=${MENU_ENTRIES[$I]}
  124. echo " running kernel is grub menu entry $NEXT_BOOT (${KERNELS[$I]})"
  125. break
  126. fi
  127. let I++
  128. done
  129. # if we have not found a kernel, issue a warning.
  130. # if we have found a kernel, we'll do "grub-once" later, after
  131. # prepare_suspend finished.
  132. if [ $NEXT_BOOT -eq -1 ]; then
  133. echo "WARNING: no kernelfile matching the running kernel found"
  134. fi
  135. }
  136. #############################################################################
  137. # if we did not find a kernel (or BOOT_LOADER is not GRUB) check,
  138. # if the running kernel is still the one that will (probably) be booted for
  139. # resume (default entry in menu.lst or, if there is none, the kernel file
  140. # /boot/latestkernel points to.)
  141. # This will only work, if you use "original" SUSE kernels.
  142. # you can always override with the config variable set to "yes"
  143. prepare-grub()
  144. {
  145. echo "INFO: running prepare-grub"
  146. eval `getkernels`
  147. RUNNING=`uname -r`
  148. find-kernel-entry
  149. RET=0
  150. if [ $NEXT_BOOT -eq -1 ]; then
  151. # which kernel is booted with the default entry?
  152. BOOTING="${KERNELS[$DEFAULT_BOOT]}"
  153. # if there is no default entry (no menu.lst?) we fall back to
  154. # the default of /boot/latestkernel.
  155. [ -z "$BOOTING" ] && BOOTING="latestkernel"
  156. if IMAGE=`readlink /boot/$BOOTING` && [ -e "/boot/${IMAGE##*/}" ]; then
  157. BOOTING=$IMAGE
  158. fi
  159. BOOTING="${BOOTING#*kernel-}"
  160. echo "running kernel: '$RUNNING', probably booting kernel: '$BOOTING'"
  161. if [ "$BOOTING" != "$RUNNING" ]; then
  162. echo "ERROR: kernel version mismatch, cannot suspend to disk"
  163. echo "running: $RUNNING booting: $BOOTING" >> $INHIBIT
  164. RET=1
  165. fi
  166. else
  167. # set the bootloader to the running kernel
  168. echo " preparing boot-loader: selecting entry $NEXT_BOOT, kernel /boot/$BOOTING"
  169. T1=`date +"%s%N"`
  170. sync; sync; sync # this is needed to speed up grub-once on reiserfs
  171. T2=`date +"%s%N"`
  172. echo " grub-once: `grub-once $NEXT_BOOT`"
  173. T3=`date +"%s%N"`
  174. S=$(((T2-T1)/100000000)); S="$((S/10)).${S:0-1}"
  175. G=$(((T3-T2)/100000000)); G="$((G/10)).${G:0-1}"
  176. echo " time needed for sync: $S seconds, time needed for grub: $G seconds."
  177. fi
  178. return $RET
  179. }
  180. ###### main()
  181. case $1 in
  182. hibernate)
  183. prepare-grub
  184. ;;
  185. thaw)
  186. grub-once-restore
  187. ;;
  188. esac