#!/bin/bash

export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/lib/pm-utils/bin

# Default values go here.  It is important to _not_ initialize some
# variables here.  They are:
#
# PM_CMDLINE
# RESUME_MODULES
#
HIBERNATE_RESUME_POST_VIDEO=no
INHIBIT=/var/run/pm-utils.inhibit
PM_LOGFILE=${PM_LOGFILE:=/var/log/pm-suspend.log}
SUSPEND_MODULES=""

[ -f /usr/lib/pm-utils/defaults ] && . /usr/lib/pm-utils/defaults

GLOBAL_CONFIG_VARIABLES=""
add_global() {
	export $1
	GLOBAL_CONFIG_VARIABLES="$GLOBAL_CONFIG_VARIABLES $1"
}

# export them all here
add_global HIBERNATE_RESUME_POST_VIDEO
add_global INHIBIT
add_global PM_LOGFILE
add_global PM_CMDLINE
add_global RESUME_MODULES
add_global SUSPEND_MODULES

source_configs()
{
	cfgs="/etc/pm/config.d/*[^~]"
	for cfg in $cfgs ; do
		[ -x $cfg ] || continue
		while read LINE ; do
			case "$GLOBAL_CONFIG_VARIABLES " in
				*" ${LINE%=*} "*) continue ;;
				*) eval $LINE ;;
			esac
		done < $cfg
	done
}

source_configs

take_suspend_lock()
{
	VT=$(fgconsole)
	chvt 63
	if [ -f /.suspended ]; then
		read pid < /.suspended
		if [ -d /proc/$pid ]; then
			return 1
		fi
	fi
        echo "$$" > /.suspended
	rm -f /var/run/pm-suspend
	touch /var/run/pm-suspend
	return 0
}

remove_suspend_lock()
{
	rm -f /var/run/pm-suspend
	chvt 1
	chvt $VT
	openvt -- sh -c "usleep $1 ; rm -f /.suspended >/dev/null 2>&1 0<&1" >/dev/null 2>&1 0<&1 &
}

find_sleepd_files()
{
	flist="/etc/pm/sleep.d/*[^~] /usr/lib/pm-utils/sleep.d/*[^~]"
	bases=$(for file in $flist ; do echo $(basename $file) ; done | sort -n)
	for base in $bases ; do
		if [ -e "/etc/pm/sleep.d/$base" ]; then
			if [ -x "/etc/pm/sleep.d/$base" ]; then
				echo /etc/pm/sleep.d/$base
			fi
		elif [ -x "/usr/lib/pm-utils/sleep.d/$base" ]; then
			echo /usr/lib/pm-utils/sleep.d/$base
		fi
	done
}

run_hooks()
{
	[ -z "$1" ] && return 0

	[ -f /var/run/pm-suspend ] && . /var/run/pm-suspend
	rm -f /var/run/pm-suspend

	echo "$(date): running $1 hooks."

	files=$(find_sleepd_files)
	if [ "$2" = "reverse" ]; then
		filea=($files)
		filen=${#filea[*]}
		while [ "$filen" -gt 0 ]; do
			let filen--
			file="${filea[$filen]}"
			echo "===== $(date): running hook: $file ====="
			$file $1
		done
	else
		for file in $files ; do
			echo "===== $(date): running hook: $file ====="
			$file $1
		done
	fi

	echo "$(date): done running $1 hooks."
}

get_power_status()
{
	RETVAL=0
	on_ac_power
	case "$?" in
		"0")
			echo "ac"
			;;
		"1")
			echo "battery"
			;;
		"255")
			echo "error"
			RETVAL=1
			;;
	esac
	return $RETVAL
}

do_suspend()
{
	pm-pmu --suspend || echo -n "mem" > /sys/power/state
}

do_hibernate()
{
	echo -n "platform" > /sys/power/disk
	echo -n "disk" > /sys/power/state
}

do_suspend_hybrid()
{
	return 1
}

pm_main()
{
	if [ -n "$PM_LOGFILE" ]; then
		[ -f "$PM_LOGFILE" ] && rm -f "$PM_LOGFILE"
		exec > "$PM_LOGFILE" 2>&1
	fi
	take_suspend_lock || exit 1

	rm -f "$INHIBIT"

	run_hooks "$1"

	if [ ! -e "$INHIBIT" -a "$(type -t "do_$1")" == "function" ]; then
		sync ; sync ; sync
		"do_$1"
	fi

	run_hooks "$2" reverse

	remove_suspend_lock 200

	return 0
}

_rmmod() {
	if modprobe -r $1; then
		echo "export RESUME_MODULES=\"$1 \$RESUME_MODULES\"" \
						>> /var/run/pm-suspend
		return 0
	else
		echo "# could not unload '$1', usage count was $2"
		return 1
	fi
}

# this recursively unloads the given modules and all that depend on it
# first parameter is the module to be unloaded
modunload()
{
	local MOD D C USED MODS I
	local UNL=$1 RET=1
	UNL=$(echo $UNL | sed -e 's/[_-]/\[_-\]/g')
	# RET is the return code.
	# If at least one module was unloaded, return 0.
	# if the module was not loaded, also return 0 since this is no error.
	# if no module was unloaded successfully, return 1
	while read MOD D C USED D; do
		[[ "$MOD" =~ "$UNL" ]] || continue
		if [ "$USED" == "-" ]; then
			_rmmod $MOD $C
			RET=$?
		else
			USED=${USED//,/ }
			MODS=($USED)
			# it seems slightly more likely to rmmod in one pass,
			# if we try backwards.
			for I in `seq $[${#MODS[@]}-1] -1 0`; do
				MOD=${MODS[$I]}
				modunload $MOD && RET=0
			done
			# if we unloaded at least one module, then let's
			# try again!
			[ $RET -eq 0 ] && modunload $MOD
			RET=$?
		fi
		return $RET
	done < /proc/modules
	# if we came this far, there was nothing to do, 
	# the module is no longer loaded.
	return 0
}

modreload()
{
	if [ "$(eval echo \$${1}_MODULE_LOAD)" == "yes" ]; then
		modprobe "$1" >/dev/null 2>&1
	fi
}

stopservice()
{
	service "$1" status 2>/dev/null | grep -c -q running
	if [ "$?" == "0" -a -x "/etc/init.d/$1" ]; then
		echo "export ${1}_SERVICE_ACTIVATE=yes" >> /var/run/pm-suspend
		"/etc/init.d/$1" stop 2>&1
	fi
}

restartservice()
{
	if [ "x$(eval echo \$${1}_SERVICE_ACTIVATE)" == "xyes" \
			-a -x "/etc/init.d/$1" ]; then
		"/etc/init.d/$1" start 2>&1
	fi
}

savestate()
{
	echo "export ${1}_STATE=$2" >> /var/run/pm-suspend
}

restorestate()
{
	eval echo \$${1}_STATE
}
