#!/bin/bash
#
# Functions defined in this file are used by many rc scripts.
# 
# Author:	Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
# Hacked by:	Greg Galloway and Marc Ewing
# Changed by:	Dmitry V. Levin

# Set the initial default search path for use by startup scripts.
export PATH="/sbin:/usr/sbin:/usr/local/sbin:/lib/initrd/bin:/bin:/usr/bin:/usr/local/bin"

. shell-error
. shell-var

SourceIfExists()     { [ -f "$1" ] && . "$@"; }
SourceIfExecutable() { [ -x "$1" ] && . "$@"; }
SourceIfNotEmpty()   { [ -s "$1" ] && . "$@"; }
ExecIfExecutable()   { [ -x "$1" ] && "$@"; }
absolute() { { command -v "$@"; } 2>/dev/null; }

message_time=1
SHOW_TIMESTAMP=1
QUIET=no
LANG=C

SourceIfNotEmpty /etc/sysconfig/init

LANGUAGE="$LANG"
LC_ALL="$LANG"

export LANG LANGUAGE LC_ALL

TO_COL=
COLOR_BANNER=
COLOR_FAILURE=
COLOR_INFO=
COLOR_NORMAL=
COLOR_SUCCESS=
COLOR_WARNING=

BOOTUP="${BOOTUP:-color}"
CONSOLETYPE=$(absolute consoletype) && [ "$($CONSOLETYPE)" = serial ] &&
	BOOTUP=serial

[ "$BOOTUP" != color ] ||
	SourceIfNotEmpty /etc/init.d/outformat

[ "${LOGLEVEL:--1}" -ge 0 ] 2>/dev/null ||
	LOGLEVEL=1

if [ -z "${RUN_INITRD-}" ] && [ -z "${RDLOG-}" ]; then
	! grep -qs rdlog=console /proc/cmdline ||
		export RDLOG=console
fi

start_daemon()
{
	# Process options.
	local FLAGS ANNOUNCE=1 BACKGROUND='' BASENAME='' CHECK='' CMDNAME='' DISPNAME='' LOCKFILE='' MAKE_PIDFILE='' NICE=0 PIDFILE='' STATUS='' WHICH=''

	while [ "$1" != "${1##[-+]}" ]; do
		case "$1" in
		--) shift
			break
			;;
		--announce)
			ANNOUNCE=1
			;;
		--no-announce)
			ANNOUNCE=
			;;
		--background)
			BACKGROUND='--background'
			;;
		--check) shift
			CHECK="$1"
			;;
		--displayname) shift
			DISPNAME="$1"
			;;
		--expect-user) shift
			;;
		--lockfile) shift
			LOCKFILE="$1"
			;;
		--make-pidfile)
			BACKGROUND='--background'
			MAKE_PIDFILE='--make-pidfile'
			;;
		--name) shift
			CMDNAME="$1"
			;;
		--pidfile) shift
			PIDFILE="$1"
			;;
		--user|--set-user) shift
			;;
		[-+][0-9]*)
			NICE="$1"
			;;
		*)
			echo "start_daemon: unrecognized option: $1" >&2
			return 1
			;;
		esac
		shift
	done

	if [ -z "$1" ]; then
		msg_usage "start_daemon [options]... {program}..."
		return 1
	fi

	if [ -n "$CHECK" ] && [ -n "$CMDNAME" ]; then
		echo >&2 "start_daemon: --check and --name are mutually exclusive options"
		return 1
	fi

	if [ -n "$CMDNAME" ] && [ -z "$PIDFILE" ]; then
		echo >&2 "start_daemon: --name is set but --pidfile is not set"
		return 1
	fi

	# We need the absolute pathname.
	[ -z "$CHECK" ] ||
		CHECK="$(absolute "$CHECK")" ||
		return 1

	WHICH="$(absolute "$1")" ||
		return 1

	if [ -n "$CMDNAME" ]; then
		BASENAME="${CMDNAME##*/}"
	elif [ -n "$CHECK" ]; then
		BASENAME="${CHECK##*/}"
	else
		BASENAME="${1##*/}"
	fi
	shift

	[ -n "$BASENAME" ] ||
		return 1

	DISPNAME="${DISPNAME:-$BASENAME}"

	[ "${RDLOG-}" != 'console' ] ||
		ANNOUNCE=''

	FLAGS=("--start" "-N" "$NICE")

	if [ -n "$CMDNAME" ]; then
		FLAGS+=("--startas" "$WHICH" "--name" "$CMDNAME")
	elif [ -n "$CHECK" ]; then
		FLAGS+=("--exec" "$CHECK" "--startas" "$WHICH")
	else
		FLAGS+=("--exec" "$WHICH")
	fi
	[ -z "$PIDFILE"      ] || FLAGS+=("--pidfile" "$PIDFILE")
	[ -z "$BACKGROUND"   ] || FLAGS+=("$BACKGROUND")
	[ -z "$MAKE_PIDFILE" ] || FLAGS+=("$MAKE_PIDFILE")

	# Announce the action.
	[ -z "$ANNOUNCE" ] ||
		msg_starting "$DISPNAME"

	# Actually start the daemon.
	start-stop-daemon "${FLAGS[@]}" -- "$@"
	STATUS=$?

	if [ $STATUS = 0 ]; then
		[ -z "$LOCKFILE" ] || touch "$LOCKFILE"
		[ "$BOOTUP" != verbose ] || echo -n " $DISPNAME "
		success "$BASENAME startup"
	else
		failure "$BASENAME startup"
	fi

	return $STATUS
}

guess_basename_dispname()
{
	[ -n "$CMDNAME" ] &&
		BASENAME="${CMDNAME##*/}" ||
		BASENAME="${NAME##*/}" ||
		return 1

	DISPNAME="${DISPNAME:-$BASENAME}"
}

guess_pidfile()
{
	# Try to guess the PID file if one isn't specified manually.
	if [ -z "$PIDFILE" ]; then
		PIDFILE="/var/run/$BASENAME.pid"
		[ -f "$PIDFILE" ] || PIDFILE=
	elif [ "$PIDFILE" = none ]; then
		PIDFILE=
	fi
}

stop_daemon()
{
	# Process options.
	local FLAGS ANNOUNCE=1 BASENAME='' CMDNAME='' DEFAULT=true DISPNAME='' LOCKFILE='' MESSAGE='' NAME='' PIDFILE='' RETRY='' SIGNAL='' STATUS='' WHICH=''

	# start-stop-daemon wants a signal number.
	SIGNAL="$(/bin/kill -l TERM)" || SIGNAL=15

	while [ $# -ge 1 ]; do
		case "$1" in
		--) shift
			[ -z "$NAME" ] || return 1
			NAME="$1"
			break
			;;
		--announce)
			ANNOUNCE=1
			;;
		--no-announce)
			ANNOUNCE=
			;;
		--displayname) shift
			DISPNAME="$1"
			;;
		--expect-user) shift
			;;
		--lockfile) shift
			LOCKFILE="$1"
			;;
		--name) shift
			CMDNAME="$1"
			;;
		--pidfile) shift
			PIDFILE="$1"
			;;
		--retry) shift
			RETRY="$1"
			;;
		-[0-9]*)
			SIGNAL="${1##-}"
			DEFAULT=false
			;;
		-*)
			SIGNAL="${1##-}"
			SIGNAL="$(/bin/kill -l -- "$SIGNAL")" || return 1
			DEFAULT=false
			ANNOUNCE=
			;;
		# Allow the process name to be in any argument for Red Hat compatibility.
		*)
			[ -z "$NAME" ] || return 1
			NAME="$1"
			;;
		esac
		shift
	done

	# We need the absolute pathname for /proc/*/exe checks.
	if [ -z "$NAME" ]; then
		msg_usage "stop_daemon [options]... {program}..."
		return 1
	fi

	WHICH="$(absolute "$NAME")" ||
		return 1

	[ "${RDLOG-}" != 'console' ] ||
		ANNOUNCE=''

	guess_basename_dispname
	guess_pidfile

	if [ -n "$CMDNAME" ] && [ -z "$PIDFILE" ]; then
		echo "stop_daemon: --name is set but --pidfile is not set" >&2
		return 1
	fi

	FLAGS=("--stop" "-q")

	[ -z "$CMDNAME" ] &&
		FLAGS+=("--exec" "$WHICH") ||
		FLAGS+=("--name" "$CMDNAME")

	[ -z "$PIDFILE" ] ||
		FLAGS+=("--pidfile" "$PIDFILE")

	# Announce the action.
	[ -z "$ANNOUNCE" ] ||
		msg_stopping "$DISPNAME"

	# Actually tell the daemon to stop.
	start-stop-daemon "${FLAGS[@]}" --signal "$SIGNAL"
	STATUS=$?

	[ "$DEFAULT" = true ] &&
		MESSAGE="$BASENAME shutdown" ||
		MESSAGE="sending signal $SIGNAL to $BASENAME"

	if [ $STATUS = 0 ]; then
		[ -z "$PIDFILE"  ] || rm -f "$PIDFILE"
		[ -z "$LOCKFILE" ] || rm -f "$LOCKFILE"
		[ "$BOOTUP" != verbose ] || echo -n " $DISPNAME "
		success "$MESSAGE"
	else
		failure "$MESSAGE"
	fi

	return $STATUS
}

status()
{
	# Test syntax.
	if [ $# = 0 ]; then
		msg_usage "status [options]... {program}"
		return 1
	fi

	# Process options.
	local FLAGS BASENAME='' CMDNAME='' DISPNAME='' LOCKFILE='' PIDFILE='' WHICH=''

	while [ "$1" != "${1##-}" ]; do
		case "$1" in
		--) shift
			break
			;;
		--displayname) shift
			DISPNAME="$1"
			;;
		--expect-user) shift
			;;
		--lockfile) shift
			LOCKFILE="$1"
			;;
		--name) shift
			CMDNAME="$1"
			;;
		--pidfile) shift
			PIDFILE="$1"
			;;
		*)
			echo "status: unrecognized option: $1" >&2
			return 1
			;;
		esac
		shift
	done

	# We need the absolute pathname for /proc/*/exe checks.
	if [ -z "$1" ]; then
		msg_usage "status [options]... {program}"
		return 1
	fi

	WHICH="$(absolute "$1")" ||
		return 1

	guess_basename_dispname
	guess_pidfile

	if [ -n "$CMDNAME" ] && [ -z "$PIDFILE" ]; then
		echo "status: --name is set but --pidfile is not set" >&2
		return 1
	fi

	# Actually determine the status.
	FLAGS=("--stop" "--test")

	[ -n "$CMDNAME" ] &&
		FLAGS+=("--name" "$CMDNAME") ||
		FLAGS+=("--exec" "$WHICH")

	[ -z "$PIDFILE" ] ||
		FLAGS+=("--pidfile" "$PIDFILE")

	# Report it.
	if start-stop-daemon "${FLAGS[@]}" >/dev/null; then
		echo "$DISPNAME is running"
		return 0
	fi

	if [ -n "$PIDFILE" ] && [ -f "$PIDFILE" ]; then
		echo "$DISPNAME is dead, but stale PID file exists"
		return 1
	fi

	if [ -f "${LOCKFILE:-/var/lock/subsys/$BASENAME}" ]; then
		echo "$DISPNAME is dead, but subsystem is locked"
		return 2
	fi

	echo "$DISPNAME is stopped"
	return 3
}

show_tstamp()
{
	[ -z "${SHOW_TIMESTAMP-}" ] || /sbin/timestamp boottime
}

is_quiet()
{
	! shell_var_is_no "$QUIET"
}

msg()
{
	! is_quiet || return 0
	show_tstamp
	printf '%s\n' "$*"
}

__SERVICE_MESSAGE=
__SERVICE_STATUS=

echo_msg()
{
	[ -n "$*" ] || return 0
	__msg()
	{
		show_tstamp
		printf '%s ' "$*"
	}
	is_quiet && __SERVICE_MESSAGE="$(__msg "$@")" && return ||:
	__msg "$@"
}

echo_newline()
{
	! is_quiet || [ "$__SERVICE_STATUS" = failure ] || return 0
	__SERVICE_STATUS=
	echo
}

echo_success()
{
	__SERVICE_STATUS=success
	! is_quiet || return 0
	[ "${#__SERVICE_MESSAGE}" = 0 ] || printf '%s ' "$__SERVICE_MESSAGE"
	printf '%s[ %sDONE%s ]\r' "$TO_COL" "$COLOR_SUCCESS" "$COLOR_NORMAL"
}

echo_failure()
{
	__SERVICE_STATUS=failure
	[ "${#__SERVICE_MESSAGE}" = 0 ] || printf '%s ' "$__SERVICE_MESSAGE"
	printf '%s[%sFAILED%s]\r' "$TO_COL" "$COLOR_FAILURE" "$COLOR_NORMAL"
	return 1
}

echo_passed()
{
	__SERVICE_STATUS=passed
	! is_quiet || return 1
	[ "${#__SERVICE_MESSAGE}" = 0 ] || printf '%s ' "$__SERVICE_MESSAGE"
	printf '%s[%sPASSED%s]\r' "$TO_COL" "$COLOR_WARNING" "$COLOR_NORMAL"
	return 1
}

msg_starting()        { echo_msg "Starting $1 service: "; }
msg_stopping()        { echo_msg "Stopping $1 service: "; }
msg_reloading()       { echo_msg "Reloading $1 service: "; }
msg_already_running() { echo_msg "Service $1 is already running."; }
msg_not_running()     { echo_msg "Service $1 is not running."; }
msg_usage()           { printf "Usage: %s\n" "$*" >&2; }

# Log that something succeeded
success()
{
	if [ "${RDLOG-}" = 'console' ]; then
		[ -z "${INITLOG_FILE-}" ] ||
			message "$1 succeeded" >"$INITLOG_FILE"
		return 0
	fi
	echo_success
	echo_newline
	return 0
}

# Log that something failed
failure()
{
	local rc=$?
	if [ "${RDLOG-}" = 'console' ]; then
		[ -z "${INITLOG_FILE-}" ] ||
			message "$1 failed" >"$INITLOG_FILE"
		return $rc
	fi
	echo_failure
	echo_newline
	return $rc
}

# Log that something passed, but may have had errors. Useful for fsck
passed()
{
	local rc=$?
	if [ "${RDLOG-}" = 'console' ]; then
		[ -z "${INITLOG_FILE-}" ] ||
			message "$1 passed" >"$INITLOG_FILE"
		return $rc
	fi
	echo_passed
	echo_newline
	return $rc
}

# Run some action. Log its output.
action()
{
	local STRING rc
	STRING="$1"
	shift
	[ "${RDLOG-}" = 'console' ] || echo_msg "$STRING"
	"$@"
	rc=$?
	[ $rc -eq 0 ] && success "$STRING" || failure "$STRING"
	return $rc
}

action_shell()
{
	local STRING rc
	STRING="$1"
	shift
	[ "${RDLOG-}" = 'console' ] || echo_msg "$STRING"
	("$@")
	rc=$?
	[ $rc -eq 0 ] && success "$STRING" || failure "$STRING"
	return $rc
}
