#!/bin/sh
#
# $Id: functions,v 1.28 2002/12/08 17:56:27 ldv Exp $
#
# functions	This file contains functions to be used by most or all
#		shell scripts in the /etc/init.d directory.
#
# Version:	@(#) /etc/init.d/functions 1.01 26-Oct-1993
#
# Author:	Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
# Hacked by:    Greg Galloway and Marc Ewing
#
# i18n originally by: 	Arnaldo Carvalho de Melo <acme@conectiva.com.br>,
#			Wanderlei Antonio Cavassin

# First set up a default search path.
export PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"

SourceIfExists()
{
	local f="$1"
	shift
	[ -f "$f" ] && . "$f" "$@"
}

SourceIfExecutable()
{
	local f="$1"
	shift
	[ -x "$f" ] && . "$f" "$@"
}

SourceIfNotEmpty()
{
	local f="$1"
	shift
	[ -s "$f" ] && . "$f" "$@"
}

ExecIfExecutable()
{
	local f="$1"
	shift
	[ -x "$f" ] && "$f" "$@"
}

if [ "$UID" = 0 ]; then
	LANG=POSIX
	LC_ALL=POSIX
	LINGUAS=POSIX
	LANGUAGE=POSIX
elif [ -z "$NOLOCALE" ]; then
	TEXTDOMAIN=initscripts
	TEXTDOMAINDIR=/etc/locale
	SourceIfNotEmpty /etc/sysconfig/i18n
fi

# Read in our configuration
if [ -z "$BOOTUP" ]; then
	SourceIfNotEmpty /etc/sysconfig/init
	[ -n "$BOOTUP" ] || BOOTUP=color
fi

if [ -x /sbin/consoletype ] && [ "`consoletype`" = "serial" ]; then
	BOOTUP=serial
fi

if [ "$BOOTUP" != "color" ]; then
	MOVE_TO_COL(){ :; }
	SETCOLOR_SUCCESS(){ :; }
	SETCOLOR_FAILURE(){ :; }
	SETCOLOR_WARNING(){ :; }
	SETCOLOR_NORMAL(){ :; }
else
	. /etc/init.d/outformat
fi

if [ "$BOOTUP" != "verbose" ]; then
   INITLOG_ARGS="-q"
else
   INITLOG_ARGS=
fi

[ -n "$LOGLEVEL" ] && [ "$LOGLEVEL" -ge 0 ] 2>/dev/null || LOGLEVEL=1

# Check if $pid (could be plural) are running
checkpid()
{
	while [ -n "$1" ]; do
		[ -d "/proc/$1" ] && return 0 || shift
	done
	return 1
}

# A function to start a program.
daemon()
{
	# Test syntax.
	local base=
	local bg=
	local gotbase=
	local user=
	local daemon_user=
	local nicelevel=0
	while [ "$1" != "${1##[-+]}" ]; do
		case $1 in
			--check)
				shift
				base=$1
				gotbase=yes
				shift
				;;
			--user)
				shift
				daemon_user=$1
				shift
				;;
			--bg|--background)
				bg='&'
				shift
				;;
			[-+][0-9]*)
				nicelevel=$1
				shift
				;;
			'')
				break
				;;
			*)
				echo 'Usage: daemon [+/-nicelevel] {program}' >&2
				return 1
				;;
		esac
	done

	# Save basename.
	[ -n "$gotbase" ] || base="${1##*/}"

	# See if it's already running.
	local pidlist=`pidofproc "$1"`

	local pid= p
	for p in $pidlist; do
		if checkpid "$p"; then
			[ -z "$pid" ] && pid="$p" || pid="$pid $p"
		fi
	done

	# Echo daemon
	if [ "$BOOTUP" = "verbose" ]; then echo -n "$base "; fi

	[ -z "$pid" ] || { echo_passed; return; }

	# make sure it doesn't core dump anywhere; while this could mask
	# problems with the daemon, it also closes some security problems
	ulimit -Sc 0 &>/dev/null

	# And start it up.
	if [ -z "$daemon_user" ]; then
		nice -n $nicelevel initlog $INITLOG_ARGS -n "$base" -c "sh -c '$*$bg'"
	else
		nice -n $nicelevel initlog $INITLOG_ARGS -n "$base" -c "su -s /bin/sh -l $daemon_user -c '$*$bg'"
	fi
	[ $? = 0 ] && success "$base startup" || failure "$base startup"
}

# usage: wait_pid <w_times> <w_delay> pidlist
wait_pid()
{
	local w_times="$1"
	shift
	local w_delay="$1"
	shift

	local i=0
	while [ $i -lt "$w_times" ]; do
		checkpid "$@" &>/dev/null || return 0
		usleep "$w_delay"
		i=$[1+i]
	done
	! checkpid "$@"
}

# A function to stop a program.
killproc()
{
	local RC=0
	# Test syntax.
	if [ $# = 0 ]; then
		echo "Usage: killproc {program} [signal]" >&2
		return 1
	fi

	local notset=0
	local killlevel='-9'
	# check for second arg to be kill level
	if [ -n "$2" ]; then
		killlevel=$2
	else
		notset=1
	fi

	# Save basename.
	local base="${1##*/}"

	# Find pid.
	local pidlist=`pidofproc "$1"`

	local pid= p
	for p in $pidlist; do
		if checkpid "$p"; then
			[ -z "$pid" ] && pid="$p" || pid="$pid $p"
		fi
	done

	# Kill it.
	if [ -n "$pid" ]; then
		[ "$BOOTUP" != "verbose" ] || echo -n "$base "
		if [ "$notset" = "1" ]; then
			if checkpid $pid &>/dev/null; then
				# TERM first, then KILL if not dead
				kill -TERM -- $pid
				if ! wait_pid 30 100000 $pid; then
					kill -KILL -- $pid
					usleep 100000
				fi
			fi
			checkpid $pid &>/dev/null
			RC=$?
			[ $RC -eq 0 ] && failure "$base shutdown" || success "$base shutdown"
			RC=$((! $RC))
		# use specified level only
		else
			if checkpid $pid &>/dev/null; then
				kill "$killlevel" -- $pid
				RC=$?
				[ $RC -eq 0 ] && success "$base $killlevel" || failure "$base $killlevel"
			fi
		fi
	else
		failure "$base shutdown"
	fi

	# Remove pid file if any.
	if [ "$notset" = "1" ]; then
		rm -f "/var/run/$base.pid"
	fi
	return $RC
}

# A function to find the pid of a program.
pidfileofproc()
{
	local base="${1##*/}"

	# Test syntax.
	if [ $# != 1 ]; then
		echo "Usage: pidfileofproc {program}" >&2
		return 1
	fi

	# First try "/var/run/*.pid" files
	if [ -s "/var/run/$base.pid" ]; then
		local line p pid=
		read line <"/var/run/$base.pid"
		for p in $line; do
			[ -z "${p//[0-9]}" -a -d "/proc/$p" ] && pid="$pid $p"
		done
		if [ -n "$pid" ]; then
			echo "$pid"
			return 0
		fi
	fi

	return 1
}

# A function to find the pid of a program.
pidofproc()
{
	# Test syntax.
	if [ $# != 1 ]; then
		echo "Usage: pidofproc {program}" >&2
		return 1
	fi

	local base="${1##*/}"

	# First try "/var/run/*.pid" files.
	if [ -s "/var/run/$base.pid" ]; then
		local line p pid=
		read line <"/var/run/$base.pid"
		for p in $line; do
			[ -z "${p//[0-9]}" -a -d "/proc/$p" ] && pid="$pid $p"
		done
		if [ -n "$pid" ]; then
			echo "$pid"
			return 0
		fi
	fi

	# Next try "pidof".
	pidof -o $$ -o $PPID -o %PPID -x "$1" || pidof -o $$ -o $PPID -o %PPID -x "$base"
}

status()
{
	# Test syntax.
	if [ $# = 0 ]; then
		echo "Usage: status {program}" >&2
		return 1
	fi

	local base="${1##*/}"

	# First try "pidof"
	local pid=`pidof -o $$ -o $PPID -o %PPID -x "$1" || pidof -o $$ -o $PPID -o %PPID -x "$base"`
	if [ -n "$pid" ]; then
		if [ "$pid" = "${pid// }" ]; then
			echo "$base (pid $pid) is running..."
		else
			echo "$base (pids $pid) are running..."
		fi
		return 0
	fi

	# Next try "/var/run/*.pid" files
	if [ -s "/var/run/$base.pid" ]; then
		local line p pid=
		read line <"/var/run/$base.pid"
		for p in $line; do
			if [ -z "${p//[0-9]}" -a -d "/proc/$p" ]; then
				[ -z "$pid" ] && pid="$p" || pid="$pid $p"
			fi
		done
		if [ -n "$pid" ]; then
			if [ "$pid" = "${pid// }" ]; then
				echo "$base (pid $pid) is running..."
			else
				echo "$base (pids $pid) are running..."
			fi
			return 0
		else
			echo "$base dead but pid file exists"
			return 1
		fi
	fi

	# See if /var/lock/subsys/$base exists
	if [ -f "/var/lock/subsys/$base" ]; then
		echo "$base dead but subsys locked"
		return 2
	fi

	echo "$base is stopped"
	return 3
}

echo_success()
{
	MOVE_TO_COL
	echo -n '[  '
	SETCOLOR_SUCCESS
	echo -n 'OK'
	SETCOLOR_NORMAL
	echo -n '  ]'
	return 0
}

echo_failure()
{
	MOVE_TO_COL
	echo -n '['
	SETCOLOR_FAILURE
	echo -n 'FAILED'
	SETCOLOR_NORMAL
	echo -n ']'
	# Echo for LPP
	if [ -f /proc/progress ]; then
		echo f > /proc/progress
	fi
	return 1
}

echo_passed()
{
	MOVE_TO_COL
	echo -n '['
	SETCOLOR_WARNING
	echo -n 'PASSED'
	SETCOLOR_NORMAL
	echo -n ']'
	# Echo for LPP
	if [ -f /proc/progress ]; then
		echo w > /proc/progress
	fi
	return 1
}

# Log that something succeeded
success()
{
	if [ -z "$IN_INITLOG" ]; then
		initlog $INITLOG_ARGS -n $0 -s "$1" -e 1
	else
		local opipe=`trap -p SIGPIPE`
		trap '' SIGPIPE
		echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21
		$opipe
	fi
	echo_success
	return 0
}

# Log that something failed
failure()
{
	rc=$?
	if [ -z "$IN_INITLOG" ]; then
		initlog $INITLOG_ARGS -n $0 -s "$1" -e 2
	else
		local opipe=`trap -p SIGPIPE`
		trap '' SIGPIPE
		echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 2" >&21
		$opipe
	fi
	echo_failure
	return $rc
}

# Log that something passed, but may have had errors. Useful for fsck
passed()
{
	local rc=$?
	if [ -z "$IN_INITLOG" ]; then
		initlog $INITLOG_ARGS -n $0 -s "$1" -e 1
	else
		local opipe=`trap -p SIGPIPE`
		trap '' SIGPIPE
		echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21
		$opipe
	fi
	echo_passed
	return $rc
}

# Run some action. Log its output.
action()
{
	local STRING="$1"
	echo -n "$STRING "
	shift
	initlog $INITLOG_ARGS -c "$*" && success "$STRING" || failure "$STRING"
	local rc=$?
	echo -e '\r'
	return $rc
}

# Returns OK if $1 contains $2.
strstr()
{
	[ "$1" = "$2" ] && return 0
	slice=${1#*$2*}
	[ "$slice" != "$1" ]
}

# Confirm whether we really want to run this service.
confirm()
{
	local YES="yY"
	local NO="nN"
	local CONT="cC"

	while :; do
		local answer
		echo -n "Start service $1 (Y)es/(N)o/(C)ontinue? [Y] "
		read answer
		if strstr "$YES" "$answer" || [ -z "$answer" ]; then
			return 0
		elif strstr "$CONT" "$answer"; then
			return 2
		elif strstr "$NO" "$answer"; then
			return 1
		fi
	done
}

FindFile()
{
	local n f
	for n in "$@"; do
		for f in "$n"*; do
			if [ -r "$f" ]; then
				echo "$f"
				return 0
			fi
		done
	done
	return 1
}

# Unmount file systems, killing processes if we have to.
UnmountFilesystems()
{
	local sig=
	local retry="$1"
	shift
	local delay="$1"
	shift
	local pattern="$1"
	shift
	local message1="$1"
	shift
	local message2="$1"
	shift

	local remaining=`awk "$pattern" /proc/mounts`
	while [ -n "$remaining" -a "$retry" -gt 0 ]; do
		local rem1=`echo "$remaining" |/bin/grep '^/.*/' |LC_COLLATE=C /bin/sort -r`
		local rem2=`echo "$remaining" |/bin/grep -v '^/.*/' |LC_COLLATE=C /bin/sort -r`
		remaining="$rem1
$rem2"
		if [ "$retry" -lt 3 ]; then
			local message="$message2"
		else
			local message="$message1"
		fi
		local point
		for point in $remaining; do
			action "$message [$point]:" umount -f -t noproc "$point"
		done
		remaining=`awk "$pattern" /proc/mounts`
		[ -n "$remaining" ] || break
		/sbin/fuser -k -m $sig $remaining >/dev/null
		sleep $delay
		retry=$[retry-1]
		sig=-9
	done
}
