#!/bin/sh # vim:noexpandtab 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 # set -a HIBERNATE_MODE="platform" HIBERNATE_RESUME_POST_VIDEO=no INHIBIT=/var/run/pm-utils.inhibit PM_LOGFILE=${PM_LOGFILE:=/var/log/pm-suspend.log} SUSPEND_MODULES="" TEMPORARY_CPUFREQ_GOVERNOR="performance" LOCK="/var/run/pm-utils/lock" STORAGEDIR="/var/run/pm-utils/storage" # Use c sort order export LC_COLLATE=C [ -f /usr/lib/pm-utils/defaults ] && . /usr/lib/pm-utils/defaults set +a source_configs() { for cfg in /etc/pm/config.d/*[!~] ; do [ -f "$cfg" ] || continue set -a . "${cfg}" set +a done } source_configs # try to take the lock. Fail if we cannot get it. try_lock() { # $1 = file to use as lockfile # $2 (optional) content to write to the lockfile, # extra newline will be appended # make sure the directory where the lockfile should be exists mkdir -p ${1%/*} # we use noclobber to make sure there are no race conditions (set -o noclobber; echo "${2}" > "${1}") 2> /dev/null || return 1 return 0 } # spin waiting for the lock with optional timeout. # return once we have it, or the timeout has expired spin_lock() { # $1 = lockfile # $2 = optional timeout local elapsed=0 while ! try_lock $1; do [ "x$2" != "x" ] && [ $(( $elapsed == $2 )) -ne 0 ] && return 1 elapsed=$(($elapsed + 1)) sleep 1; done } # release the lock release_lock() { # $1 = lockfile # make sure it is ours first. rm -rf "$1" return $? } take_suspend_lock() { VT=$(fgconsole) chvt 63 try_lock "$LOCK" || return 1 mkdir -p "${STORAGEDIR}" return 0 } remove_suspend_lock() { rm -rf "${STORAGEDIR}" chvt 1 chvt $VT release_lock "${LOCK}" } command_exists() { # $1 = command to test for. It can be an executable in the path, # a shell function, or a shell builtin. type "$1" >/dev/null 2>&1 return $? } find_hooks() { # $1 = type of hook to find. # Currently only power and sleep are meaningful. local syshooks="/etc/pm/$1.d" local phooks="/usr/lib/pm-utils/$1.d" local base for base in $(for f in $syshooks/*[!~] $phooks/*[!~]; do [ -f "$f" ] && echo ${f##*/} ; done | sort | uniq) ; do if [ -x "$syshooks/$base" ]; then echo $syshooks/$base elif [ -x "$phooks/$base" ]; then echo $phooks/$base fi done } run_hooks() { # $1 = hooks to run # $2 = parameters to pass to hooks # $3 = if $3 = "reverse", then also run the hooks that ran sucessfully # backwards with parameters in $4 # $4 = parameters to pass to scripts when running backwards echo "$(date): running $1 hooks." local hooks="$1" local params="$2" shift; shift local revhooks local file for file in $(find_hooks "${hooks}"); do echo "===== $(date): running hook: $file $params =====" "$file" $params && revhooks="${file}${revhooks:+" ${revhooks}"}" done echo "$(date): done running $hooks:$params hooks." if [ "x$1" = "xreverse" ]; then echo "$(date): running $hooks hooks backwards." for file in $revhooks; do echo "===== $(date): running hook :$file $2 =====" "${file}" $2 done echo "$(date): done running $hooks:$2 backwards" fi } 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 "${HIBERNATE_MODE}" > /sys/power/disk echo -n "disk" > /sys/power/state } do_suspend_hybrid() { return 1 } init_logfile() { if [ -n "$1" ]; then exec > "$1" 2>&1 fi } pm_main() { init_logfile "$PM_LOGFILE" take_suspend_lock || exit 1 # make sure that our locks are unlocked no matter how the script exits trap remove_suspend_lock 0 rm -f "$INHIBIT" run_hooks sleep "$1" reverse "$2" return 0 } _rmmod() { if modprobe -r $1; then touch "${STORAGEDIR}/module:$1" 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="$(echo $1 |tr - _)" RET=1 while read MOD D C USED D; do [ "$MOD" = "$UNL" ] || continue if [ "$USED" = "-" ]; then # no dependent modules, just try to remove this one. _rmmod "$MOD" $C RET=$? else # modules depend on this one. try to remove them first. MODS="${USED%%*,}" while [ "${MODS}" ]; do # try to unload the last one first MOD="${MODS##*,}" modunload $MOD && RET=0 # prune the last one from the list MODS="${MODS%,*}" 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 } # reload all the modules in no particular order. modreload() { for x in ${STORAGEDIR}/module:* ; do [ -f "${x}" ] && modprobe "${x##*:}" >/dev/null 2>&1 done } if ! command_exists service; then service() { if [ -x "/etc/init.d/$1" ]; then "/etc/init.d/$@" else echo "$1" $": unrecognized service" 1>&2 return 1 fi } fi stopservice() { if service "$1" status 2>/dev/null | grep -c -q running; then touch "${STORAGEDIR}/service:$1" service "$1" stop fi } restartservice() { [ -f "${STORAGEDIR}/service:$1" ] && service "$1" start } savestate() { echo "$2" > "${STORAGEDIR}/state:$1" } restorestate() { cat "${STORAGEDIR}/state:${1}" }