#!/bin/bash
#
# Stefan Seyfried, SUSE Linux Products GmbH, 2006
# mostly taken from the powersave project

. "${PM_FUNCTIONS}"

# sanity check the environment if resume will be possible after hibernate
checkhibernate()
{
    echo "INFO: checking for suspend-to-disk prerequisites..."
    if [ -z "$IMAGE_SIZE" ]; then
        IMAGE_SIZE="`awk '/^MemTotal:/ { print int($2*1024*.45) }' /proc/meminfo`"
    fi
    # Default to partition style hibernation
    SWAP_TYPE=partition

    read CMDLINE < /proc/cmdline
    for CMD in $CMDLINE; do
        case $CMD in
            resume=*)
                RESUME=${CMD#*=}
                ;;
            resume_offset=*)
                # Swap type is file as resume_offset is given
                SWAP_TYPE=file
                ;;
        esac
    done

    if [ -z "$RESUME" ]; then
        # No resume= given in /proc/cmdline, failing.
        echo "ERROR: no resume parameter on kernel commandline, can not suspend"
        echo "no resume parameter on kernel commandline" >> $INHIBIT
        return 1
    fi
    if [ "$SWAP_TYPE" = file ] && [ "$SLEEP_MODULE" = "uswsusp" ]; then
        # File-style hibernating is not supported by uswsusp
        echo "ERROR: You must use the kernel hibernate method or tuxonice when suspending to swapfile, not uswsusp"
        echo "suspend to swapfile with uswsusp method not kernel" >> $INHIBIT
        return 1
    fi

    # the resume device can be a symlink, e.g. with LVM/EVMS or with
    # /dev/disk/by-id/foo
    RESUME=$(readlink -f $RESUME)

    OK=
    while read DEV TYPE SIZE USED PRI; do
        if [ "$TYPE" = "file" ] && [ "$SWAP_TYPE" = "file" ] && [ "$RESUME" = "$(df "$DEV" | tail -n +2 | cut -d ' ' -f 1)" ]; then
            OK=1
            break
        fi
        [ "$TYPE" != "partition" ] && continue
        [ "$DEV" != "$RESUME" ] && continue
        FREE=$[($SIZE-$USED)*1024]  # get free space on DEV
        if [ $FREE -lt $IMAGE_SIZE ]; then
            IMAGE_SIZE=$[$FREE-10*1024*1024]
        fi
        OK=1
        break   # we found the partition, no need to look further
    done < /proc/swaps

    if [ -z "$OK" ]; then
        if [ "$SWAP_TYPE" = "file" ]; then
            MSG_TYPE="swap file"
        else
            MSG_TYPE="resume partition"
        fi
        echo "ERROR: $MSG_TYPE '$RESUME' not active, can not suspend"
        echo "$MSG_TYPE '$RESUME' not active" >> $INHIBIT
        return 1
    fi

    if [ "$SLEEP_MODULE" = "kernel" ]; then
        echo "  using kernel suspend method"
        read DEV < /sys/power/resume
        if [ "$DEV" = "0:0" ]; then
            echo "ERROR: no resume partition set up in /sys/power/resume"
            # maybe "resume=..." was given, but initrd did not set up
            # /sys/power/resume correctly.
            echo "resume device not correctly setup in /sys/power/resume" >> \
                $INHIBIT
            return 1
        fi

        X=$(stat -Lc '$((0x%t)):$((0x%T))' $RESUME)
        RDEV=$(eval echo $X)
        if [ "$DEV" != "$RDEV" ]; then
            echo "ERROR: /sys/power/resume ($DEV) disagrees with resume= parameter ($RDEV)"
            echo "       can not suspend."
            echo "/sys/power/resume disagrees with resume= parameter" >> \
                $INHIBIT
            return 1
        fi
        if [ -n "$IMAGE_SIZE" -a -w /sys/power/image_size ]; then
            echo "  setting image size to $IMAGE_SIZE"
            echo "$IMAGE_SIZE" > /sys/power/image_size 2>/dev/null
        fi
    fi

    if [ "$SLEEP_MODULE" = "uswsusp" ]; then
        echo "  using userspace suspend method, temp. config file $S2DISK_CONF"
        if [ "$S2DISK_CONF" != "/etc/suspend.conf" ]; then
            rm -f $S2DISK_CONF
            # Generate S2DISK_CONF
            echo "  setting resume device to $RESUME"
            echo "resume device = $RESUME" >> $S2DISK_CONF
            if [ -n "$IMAGE_SIZE" ]; then
                echo "  setting image size to $IMAGE_SIZE"
                echo "image size = $IMAGE_SIZE" >> $S2DISK_CONF
            fi
            # add the parameters from /etc/suspend.conf to /var/lib/s2disk.conf
            if [ -e /etc/suspend.conf ]; then
                echo "# parameters taken from /etc/suspend.conf:" >> $S2DISK_CONF
                sed '/^[[:space:]]*\(#\|$\)/d;' /etc/suspend.conf >> $S2DISK_CONF
                echo "  adding these parameters from /etc/suspend.conf:"
                sed '/^[[:space:]]*\(#\|$\)/d;s/^/    /;' /etc/suspend.conf
            fi
        else
            # don't overwrite the user's config file, but warn about the issue
            echo "WARNING: S2DISK_CONF is set to /etc/suspend.conf"
            echo "    Disabling automatic generation of config file."
            echo "    This is most likely a configuration error and will cause problems"
            echo "    unless you configure /etc/suspend.conf completely on your own!"
        fi
    fi
    return 0
}

# this only makes sense on hibernate or on suspend-hybrid
case $1 in
    hibernate)
        ;;
    suspend)
        if [ "$2" != suspend_hybrid ]; then
            exit 0
        fi
        ;;
    *)
        exit $NA
        ;;
esac

[ -e /etc/pm/config.d/$1 ] && . /etc/pm/config.d/$1

if [ -z "$SLEEP_MODULE" ]; then
    # Decide the SLEEP_MODULE if not given
    if [ -x /usr/sbin/s2disk -a -c /dev/snapshot ]; then
        SLEEP_MODULE="uswsusp"
    else
        SLEEP_MODULE="kernel"
    fi
fi

if ! checkhibernate; then
    echo "WARNING: $INHIBIT will be created to prevent suspending!"
    touch $INHIBIT
    exit 1
fi

exit 0
