#!/bin/bash


# first get helper functions (e.g. DEBUG, load_scheme, ...)
. "${0%/*}/helper_functions"
. "${SCRIPT_DIR}/sleep_helper_functions"
. "${SCRIPT_DIR}/sleep_helper_messages"

set_variables "suspend2disk"
declare -i PERCENT
export PERCENT=0    # ugly global variable, but the easiest way to go.
export STEP=5

##EV_ID="$4" # event id, needed for SCRIPT_RETURN, set in helper_functions

progress ""

#############################################################################
# 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 ;-)

declare -a KERNELS MENU_ENTRIES
declare -i DEFAULT_BOOT
eval `get_kernels`  # works only with grub, but we have no other
                    # choice anyway for now.
NEXT_BOOT=""
RUNNING=`uname -r`
ARCH=`uname -m`
let PERCENT+=$STEP
if [ "${BOOT_LOADER:-GRUB}" == "GRUB" ]; then
    progress "${_M01}"
    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 corresponds to grub menu entry $NEXT_BOOT" DIAG
            DEBUG "kernel filename: '${KERNELS[$I]}'" DIAG
            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 [ -z "$NEXT_BOOT" ]; then
        DEBUG "no kernelfile matching the running kernel found" WARN
    fi
fi

let PERCENT+=$STEP
progress "${_M01}"

#############################################################################
# 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"
if [ -z "$NEXT_BOOT" \
     -a "$SUSPEND2DISK_IGNORE_KERNEL_MISMATCH" != "yes" ]; then
    # which kernel is booted with the default entry?
    BOOTING="${KERNELS[$DEFAULT_BOOT]}"
    # if there is no default entry (no menu.lst? Using LILO?) 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', (probably) booting kernel: '$BOOTING'" DIAG
    if [ "$BOOTING" != "$RUNNING" ]; then
        notify 'The kernel version "'$BOOTING'" in /boot does not match the running kernel
version "'$RUNNING'". Resuming with this kernel will not work. If you know
what you are doing, you can override this in /etc/sysconfig/powersave/sleep
with the variable SUSPEND2DISK_IGNORE_KERNEL_MISMATCH=yes.' ERROR CONTINUE "$EV_ID"
        progress_finish
        $SCRIPT_RETURN $EV_ID 1 "kernel version mismatch, cannot suspend to disk."
        EXIT 1
    fi
fi

let PERCENT+=$STEP
progress "${_M02}"

################################################################
# we need exactly one swap partition. Now that APM also uses
# swsusp, this can be tested unconditionally.
#
# do we have a swap partition?
if [ -z "$(grep partition /proc/swaps)" ] ; then # no partition to swap to.
    DEBUG "swsusp needs a swap partition, none available." ERROR
    notify "No swap partition, cannot suspend to disk." ERROR CONTINUE "$EV_ID"
    progress_finish
    $SCRIPT_RETURN $EV_ID 1 "No swap partition, cannot suspend to disk."
    EXIT 1
#
# do we have more than one swap partition or a partition and a swapfile?
elif [ `egrep -c 'partition|file' /proc/swaps` -ne 1 ]; then
    DEBUG "swsusp needs exactly one swap partiton to suspend." ERROR
    notify "More than one swap partition, cannot suspend to disk." ERROR CONTINUE "$EV_ID" 
    progress_finish
    $SCRIPT_RETURN $EV_ID 1 "More than one swap partition, cannot suspend to disk."
    rm -f $STATE
    EXIT 1
fi

let PERCENT+=$STEP
progress ""
prepare_sleep "suspend2disk"

let PERCENT+=$STEP
progress ""

# set the bootloader to the running kernel
if [ -n "$NEXT_BOOT" ]; then
    progress "${_M09}"
    echo "preparing boot-loader: selecting entry $NEXT_BOOT, kernel /boot/$BOOTING" >> $LSMOD_LOG
    T1=`date +"%s%N"`
    sync; sync; sync # this is needed to speed up grub-once on reiserfs
    T2=`date +"%s%N"`
    let PERCENT+=$STEP
    progress "${_M10}"
    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." >> $LSMOD_LOG
else
    let PERCENT=+$STEP
fi

progress ""

# SET THE SHUTDOWN METHOD ######################################
# "platform" -> "real" S4, default.
# "shutdown" -> S5
# "firmware" -> S4bios, not really supported.
# "reboot" -> just reboot, only useful for debugging
# we do a sanity check after setting this since there are still
# kernels out there getting this wrong.
echo -n "${SUSPEND2DISK_SHUTDOWN_MODE:-platform}" > /sys/power/disk
RET=$?
if [ $RET -ne 0 ]; then
    DEBUG "could not set shutdown mode. errno: '$RET'" WARN
    DEBUG "a software-suspend enabled kernel is needed for suspend to disk" WARN
fi

switch_to_vt

progress_finish
$SCRIPT_RETURN $EV_ID 0 "prepare_sleep finished successfully for $1"

EXIT 0
