On Tue, Oct 10, 2006 at 07:53:40PM -0400, Peter Jones wrote:

> > And since every distro has a little bit different tweaks for grub (or
> > maybe just plain simple naming conventions for the boot entries or such),
> > i think the grub hook belongs in the grub package.
> 
> For now, I'd just as soon leave this here, but make it call some script
> we can mutually decide on to set/unset the next boot option.

On SUSE i can just copy /boot/grub/default to a safe place and restore it
during thaw(), and everything will be fine. I have however no idea if this
is a solution that only works due to some suse-specific grub patch or if
this is a generic solution.
 
> > I have a pretty complicated logic to find out which kernel to boot next
> > in powersaved scripts, that is apparently obsoleted by /sbin/grubby on
> > fedora and that also will not work on other distros due to different
> > naming conventions for the kernel binary.
> 
> Yeah, this way is just how we do it on Fedora; I'm perfectly willing to
> change it to be more generic.

I'll attach my current grub hook which does:
(during suspend)
- parse /boot/grub/menu.lst to find the available menu entries and
  put them into an array
- check if there is an entry that matches /boot/vmlinuz-$(uname -r)
- if there is none, touch /var/run/pm-utils.inhibit, this is checked later
  to prevent suspending when we already know we cannot resume.
- copy /boot/grub/default to /var/run/pm-utils.grubonce.default
- call grubonce with the entry number found before
(during resume)
- move /var/run/pm-utils.grubonce.default to /boot/grub/default

I have my doubts that this will work anywhere besides a SUSE system since
it makes some assumptions about the layout of /boot/grub/menu.lst and about
the names of the kernel binaries, and i do not think that these are valid on
other systems.
This is also a pretty raw port of the corresponding powersave script, since
pm-utils do not have any logging / debugging infrastructure yet, every hook
has to roll its own for now.

So this is just a "look how i think that it could be done" and not a "please
include" :-)

Regards,

    Stefan
-- 
Stefan Seyfried
QA / R&D Team Mobile Devices        |              "Any ideas, John?"
SUSE LINUX Products GmbH, Nürnberg  | "Well, surrounding them's out." 
#!/bin/bash
#
# Stefan Seyfried, SUSE Linux Products GmbH 2006, GPL v2
# mostly taken from the powersave project.

GRUBONCE="/usr/sbin/grubonce"
GRUBDEFAULT="/boot/grub/default"
GRUBDEFSAVE="/var/run/pm-utils.grubonce.default"
LOGFILE="/var/log/pm-utils.$1.log"
INHIBIT="/var/run/pm-utils.inhibit"

#####################################################################
# gets a list of available kernels from /boot/grub/menu.lst
# kernels are in the array $KERNELS, output to stdout to be eval-ed.
getkernels()
{
        # DEBUG "Running getkernels()" INFO
        local MENU_LST="/boot/grub/menu.lst"
        local I DUMMY
        declare -i I=0 J=-1
        
        # build an array KERNELS with all the kernels in /boot/grub/menu.lst
        # the array MENU_ENTRIES contains the corresponding menu entry numbers
        # DEFAULT_BOOT contains the default entry.
        while read LINE; do
                case $LINE in
                title*)
                        let J++ # increase for every menu entry, even for 
non-linux
                        # DEBUG "Found grub menu entry #${J}: '${LINE}'" INFO
                        ;;
                default*)
                        DUMMY=($LINE)                   # "default 0 #maybe a 
comment"
                        echo "DEFAULT_BOOT=${DUMMY[1]}" #  ^^[0]^^ 1 ^^[2]^ 3 
^^[4]^^
                        # DEBUG "Default boot entry is '${DUMMY[1]}'" INFO
                        ;;
                kernel*)
                        DUMMY=($LINE) # kernel (hd0,1)/boot/vmlinuz-ABC 
root=/dev/hda2
                        echo "KERNELS[$I]='${DUMMY[1]##*/}'" # vmlinuz-ABC
                        echo "MENU_ENTRIES[$I]=$J"
                        # DEBUG "Found kernel entry #${I}: '${DUMMY[1]##*/}'" 
INFO
                        let I++
                        ;;
                *)  ;;
                esac
        done < $MENU_LST
}

#############################################################
# runs grubonce from the grub package to select which kernel
# to boot on next startup
grub-once()
{
        if [ -x "$GRUBONCE" ]; then
                rm -f "$GRUBDEFSAVE"
                if [ -e "$GRUBDEFAULT" ]; then
                        echo "saving original $GRUBDEFAULT" >> $LOGFILE
                        cp "$GRUBDEFAULT" "$GRUBDEFSAVE"
                fi
                echo "running '$GRUBONCE $1'" >> $LOGFILE
                $GRUBONCE $1
        else
                echo "$GRUBONCE not found, not preparing bootloader" >> $LOGFILE
        fi
}

#############################################################
# restore grub default after (eventually failed) resume
grub-once-restore()
{
        rm -f "$GRUBDEFAULT"
        if [ -e "$GRUBDEFSAVE" ]; then
                echo "restoring original $GRUBDEFAULT" >> $LOGFILE
                mv "$GRUBDEFSAVE" "$GRUBDEFAULT"
        fi
}

#############################################################################
# try to find a kernel image that matches the actually running kernel.
# We need this, if more than one kernel is installed. This works reasonably
# well with grub, if all kernels are named "vmlinuz-`uname -r`" and are
# located in /boot. If they are not, good luck ;-)
find-kernel-entry()
{
        NEXT_BOOT=-1
        ARCH=`uname -m`
        declare -i I=0
        # DEBUG "running kernel: $RUNNING" DIAG
        while [ -n "${KERNELS[$I]}" ]; do
                BOOTING="${KERNELS[$I]}"
                if IMAGE=`readlink /boot/$BOOTING` && [ -e "/boot/${IMAGE##*/}" 
]; then
                        # DEBUG "Found kernel symlink $BOOTING => $IMAGE" INFO
                        BOOTING=$IMAGE
                fi
                case $ARCH in
                        ppc*)   BOOTING="${BOOTING#*vmlinux-}" ;;
                        *)      BOOTING="${BOOTING#*vmlinuz-}" ;;
                esac
                if [ "$RUNNING" == "$BOOTING" ]; then
                        NEXT_BOOT=${MENU_ENTRIES[$I]}
                        # DEBUG "running kernel is grub menu entry $NEXT_BOOT" 
DIAG
                        # DEBUG "kernel filename: '${KERNELS[$I]}'" DIAG
                        echo "running kernel is grub menu entry $NEXT_BOOT 
(${KERNELS[$I]})" \
                                >> $LOGFILE
                        break
                fi
                let I++
        done
        # if we have not found a kernel, issue a warning.
        # if we have found a kernel, we'll do "grub-once" later, after
        # prepare_suspend finished.
        if [ $NEXT_BOOT -eq -1 ]; then
                # DEBUG "no kernelfile matching the running kernel found" WARN
                echo "no kernelfile matching the running kernel found" >> 
$LOGFILE
        fi
}

#############################################################################
# if we did not find a kernel (or BOOT_LOADER is not GRUB) check,
# if the running kernel is still the one that will (probably) be booted for
# resume (default entry in menu.lst or, if there is none, the kernel file
# /boot/vmlinuz points to.)
# This will only work, if you use "original" SUSE kernels.
# you can always override with the config variable set to "yes"
prepare-grub()
{
        eval `getkernels`
        RUNNING=`uname -r`
        find-kernel-entry

        RET=0

        echo "next boot: $NEXT_BOOT"
        
        if [ $NEXT_BOOT -eq -1 ]; then
                # which kernel is booted with the default entry?
                BOOTING="${KERNELS[$DEFAULT_BOOT]}"
                # if there is no default entry (no menu.lst?) we fall back to
                # the default of /boot/vmlinuz.
                [ -z "$BOOTING" ] && BOOTING="vmlinuz"
                if IMAGE=`readlink /boot/$BOOTING` && [ -e "/boot/${IMAGE##*/}" 
]; then
                        BOOTING=$IMAGE
                fi
                BOOTING="${BOOTING#*vmlinuz-}"
                # DEBUG "running kernel: '$RUNNING', booting kernel: 
'$BOOTING'" DIAG
                echo  "running kernel: '$RUNNING', probably booting kernel: 
'$BOOTING'" \
                        >> $LOGFILE
                if [ "$BOOTING" != "$RUNNING" ]; then
                        echo "kernel version mismatch, cannot suspend to disk" 
>> $LOGFILE
                        echo "running: $RUNNING booting: $BOOTING" >> $INHIBIT
                        RET=1
                fi
        else
                # set the bootloader to the running kernel
                echo "preparing boot-loader: selecting entry $NEXT_BOOT, kernel 
/boot/$BOOTING" \
                        >> $LOGFILE
                T1=`date +"%s%N"`
                sync; sync; sync # this is needed to speed up grub-once on 
reiserfs
                T2=`date +"%s%N"`
                grub-once $NEXT_BOOT > /dev/null 2>&1
                T3=`date +"%s%N"`
                S=$(((T2-T1)/100000000)); S="$((S/10)).${S:0-1}"
                G=$(((T3-T2)/100000000)); G="$((G/10)).${G:0-1}"
                echo "  time needed for sync: $S seconds, time needed for grub: 
$G seconds." \
                        >> $LOGFILE
        fi

        return $RET
}


###### main()

case $1 in
        hibernate)
                prepare-grub
                ;;
        thaw)
                grub-once-restore
                ;;
esac
_______________________________________________
Pm-utils mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pm-utils

Reply via email to