#!/bin/sh
# vim:noexpandtab

# Common functionality for the hooks.

# for great debugging!
[ "${PM_DEBUG}" = "true" ] && set -x

# 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 "${LOCKDIR}"
	local lock="${LOCKDIR}/${1##*/}"
	# we use noclobber to make sure there are no race conditions
	(set -o noclobber; echo "${2}" > "${lock}") 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.
	local lock="${LOCKDIR}/${1##*/}"
	rm -f "${lock}"
	return $?
}



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 $?
}

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

# TODO: Module loading and unloading is Linux-specific.  
# Look into modularizing this into an os-specific set of support routines.
_rmmod()
{
	if modprobe -r "$1"; then
		touch "${STORAGEDIR}/module:$1"
		return 0
	else
		log "# 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 [ -n "${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.
# modprobe should take care of loading prerequisites for us.
modreload()
{
	for x in "${STORAGEDIR}"/module:* ; do
		[ -O "${x}" ] || continue
		modprobe "${x##*:}" >/dev/null 2>&1 || \
			log "Could not reload module ${x##*:}."

	done
}

# Service management is sysv dependent.
# TODO: modularize this to make it work with other init systems.
if ! command_exists service; then
	service()
	{
		if [ -x "/etc/init.d/$1" ]; then
			svc="$1"
			shift
			"/etc/init.d/$svc" "$@"
		else
			log "$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()
{
	[ -O "${STORAGEDIR}/service:$1" ] && service "$1" start
}

disablehook()
{
	echo "${2:-${0##*/}}" > "${STORAGEDIR}/disable_hook:${1##*/}"
}

savestate()
{
	if [ -n "$2" ]; then
		echo "$2" > "${STORAGEDIR}/state:$1"
	else
		cat > "${STORAGEDIR}/state:$1"
	fi
}

state_exists()
{
	[ -O "${STORAGEDIR}/state:$1" ]
}


restorestate()
{
	state_exists "$1" && cat "${STORAGEDIR}/state:$1"
}
