# functions	This file contains functions to be used by most or all
#		shell scripts in the /etc/init.d directory.
#
# $Id: functions,v 1.61 2000/12/09 12:02:47 mkochano Exp $
#
# Author:	Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
# Hacked by:    Greg Galloway and Marc Ewing
# Modified for PLD by:
#		Marek Obuchowicz <elephant@pld.org.pl>
#		Arkadiusz Mikiewicz <misiek@pld.org.pl> 
#		Micha Kochanowicz <mkochano@pld.org.pl>

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

# Set defaults
INIT_COL=67

# Source configuration if available - may override default values
[ -f /etc/sysconfig/system ] && . /etc/sysconfig/system

[ -z "$COLUMNS" ] && COLUMNS=80

# Colors workaround
termput() 
{
	if [ ! -d /usr/share/terminfo ] || \
	     [ ! -x /usr/bin/tput -a ! -x /bin/tput ]; then
		case "$1" in
		  hpa)
		  	echo -ne "\033[$(($2+1))G"
			;;
		  cuu*)
		  	echo -ne "\033[${2}A"
			;;
		  el)
		  	echo -ne "\033[0K"
			;;
		  setaf)
		  	is_yes "$COLOR_INIT" && echo -ne "\033[0;3${2}m"
		  	;;
		  op)
		  	termput setaf 9
			;;
		  esac
	else
		tput "$@"
	fi
}

# printf equivalent
printf_()
{
	local text m
	text="$1" ;
	shift ;
	if [ $# -gt 0 ]; then
		m="$1";
        	shift;
		while [ $# -gt 0 ]; do
			m="$m\",\"$1" ;
			shift ;
		done
	fi
	awk "BEGIN {printf \"$text\", \"$m\"; }"
}
			    
# National language support function
nls()
{
	local msg_echo old_nls_domain text message
	msg_echo='\n'
	old_nls_domain="$NLS_DOMAIN"
	# parse command line
	# don't use -o instead || here - this will broke ksh --misiek
	while [ "$1" != "${1##-}" ] || [ "$1" != "${1##+}" ]; do
		case "$1" in
			--nls-domain)
				shift
				NLS_DOMAIN="$1"
				shift
				;;
			-n)
				msg_echo=''
				shift
				;;
		esac
	done
	message="$1"
	shift
	# empty message, so we return --misiek
	if [ -z "$message" ]; then
		NLS_DOMAIN="$old_nls_domain"
		echo -en "$msg_echo"
		return
	fi
			
	if [ -x /bin/gettext -o -x /usr/bin/gettext ]; then
		text=$(TEXTDOMAINDIR="/etc/sysconfig/locale" gettext -e --domain="${NLS_DOMAIN:-rc-scripts}" "$message")
		printf_ "$text" "$@"
	else
		printf_ "$message" "$@"
	fi
	
	echo -en "$msg_echo"
	NLS_DOMAIN="$old_nls_domain"
}

msg_network_down()
{
	nls "ERROR: Networking is down. %s can't be run." "$1"
}

msg_starting()
{
	show "Starting %s service" "$1"
}

msg_already_running()
{
	nls "%s service is already running." "$1"
}

msg_stopping()
{
	show "Stopping %s service" "$1"
}

msg_not_running()
{
	nls "%s service is not running." "$1"
}

msg_reloading()
{
	show "Reloading %s service" "$1"
}

msg_usage()
{
	nls "Usage: %s" "$*"
}

# Some functions to handle PLD-style messages
show() 
{	
	local text
	text=$(nls "$@")
	echo -n "$text"
	awk "BEGIN { for (j=length(\"$text\"); j<$INIT_COL; j++) printf \".\" }"
}

# Displays message in square brackests ("[ DONE ]"). Takes two arguments.
# First is the text to display, second is color number to use (argument to
# tput setaf). If second argument is not given, default (2, green) will be
# used).
progress()
{
	local COLOR
	if [ -n "$2" ]; then COLOR="$2"; else COLOR="2"; fi
	deltext
	echo -n "$(termput setaf 6)[$(termput setaf "$COLOR") $(nls --nls-domain rc-scripts "$1") $(termput setaf 6)]$(termput op)"
}

busy() 
{
	progress "BUSY" 5
}

ok() 
{
	progress "DONE"
	echo
}

started()
{
	progress "WORK"
	echo
}

fail() 
{
	progress "FAIL" 1
	echo
	return 1
}

died() 
{
	progress "DIED" 1
	echo
	return 1
}

deltext() 
{
	termput hpa $INIT_COL
}

# Usage run_cmd Message command_to_run
run_cmd()
{
	local exit_code errors message force_err
	typeset -i force_err=0
	typeset -i exit_code=0
	case "$1" in
		-a)
			force_err=1
			shift
			;;
	esac
	message=$1
	show "$message"; busy
	shift
	if errors=$(HOME=/tmp TMPDIR=/tmp initlog -c "$*" 2>&1); then
		ok
		log_success "$1 $message"
	else
		fail
		log_failed "$1 $message"
		exit_code=1
	fi
	[ -n "$errors" ] && [ $exit_code -eq 1 -o $force_err -eq 1 ] && echo "$errors"
	return $exit_code
}

# A function to start a program (now it's usefull on read-only filesystem too)
daemon() 
{
	local nicelevel exit_code errors prog
	typeset -i nicelevel=0
	typeset -i exit_code=0
	[ -z "$DEFAULT_SERVICE_RUN_NICE_LEVEL" ] && DEFAULT_SERVICE_RUN_NICE_LEVEL=0
	# Test syntax. Don't use -o instead || here - this will broke ksh --misiek
	while [ "$1" != "${1##-}" ] || [ "$1" != "${1##+}" ]; do
		case $1 in
		'')	msg_usage " daemon [--user user] [+/-nicelevel] {program}"
			return 1
			;;
		--check)
			# for compatibility with redhat/mandrake
			nls "warning: --check option is ignored!"
			shift
			shift
			;;
		--user)
			shift
			prog="/bin/su $1 -c"
			shift
			;;
		-*|+*) SERVICE_RUN_NICE_LEVEL=$1
			shift;;
		esac
	done
	prog="$prog "$*""

	# make sure it doesn't core dump anywhere; while this could mask
	# problems with the daemon, it also closes some security problems
	ulimit -c 0

	# And start it up.
	busy
	if errors=$(HOME=/tmp TMPDIR=/tmp nice -n ${SERVICE_RUN_NICE_LEVEL:-$DEFAULT_SERVICE_RUN_NICE_LEVEL} initlog -c "$prog" 2>&1); then
		log_success "$1 startup"
		ok
	else
		exit_code=1
		fail
		log_failed "$1 startup"
		[ -n "$errors" ] && echo "$errors"
	fi
	return $exit_code
}

# A function to stop a program.
killproc() 
{
	local notset killlevel base pid
	# Test syntax.
	if [ $# = 0 ]; then
		msg_usage " killproc {program} [signal]"
		return 1
	fi

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

        # Save basename.
        base=$(basename $1)

        # Find pid.
        pid=$(pidofproc $base)

        # Kill it.
        if [ -n "$pid" ] ; then
		if [ "$notset" = "1" ] ; then
			if ps h $pid>/dev/null 2>&1; then
				# TERM first, then KILL if not dead
				kill -TERM $pid >/dev/null 2>&1
				usleep 100000
				if ps h $pid >/dev/null 2>&1 ; then
					sleep 1
					if ps h $pid >/dev/null 2>&1 ; then
						sleep 3
						if ps h $pid >/dev/null 2>&1 ; then
							kill -KILL $pid >/dev/null 2>&1
						fi
					fi
				fi
				if (ps h $pid >/dev/null 2>&1); then
				   fail
				   log_failed "$1 shutdown"
				else
				   ok
				   log_success "$1 shutdown"
				fi
			else
				died
				log_failed "$1 shutdown"
			fi
		# use specified level only
		else
			if ps h $pid >/dev/null 2>&1; then
				if (kill $killlevel $pid); then
				   ok
				   log_success "$1 shutdown"
				else
				   fail
				   log_failed "$1 shutdown"
				fi
			else
				died
				log_failed "$1 shutdown"
			fi
		fi
	else
		died
		log_failed "$1 shutdown"
	fi

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

# A function to find the pid of a program.
pidofproc() 
{
	local pid
	# Test syntax.
	if [ $# = 0 ] ; then
		msg_usage " pidofproc {program}"
		return 1
	fi

	# First try "/var/run/*.pid" files
	if [ -f /var/run/$1.pid ] ; then
	        pid=$(head -1 /var/run/$1.pid)
	        if [ -n "$pid" ] ; then
	                echo $pid
	                return 0
	        fi
	fi

	# Next try "pidof"
	pid=$(pidof -o $$ -o $PPID -o %PPID -x $1)
	if [ -n "$pid" ] ; then
	        echo $pid
	        return 0
	fi

        # Finally try to extract it from ps
        ps ax | awk 'BEGIN { prog=ARGV[1]; ARGC=1 }
                           { if ((prog == $5) || (("(" prog ")") == $5) ||
                             (("[" prog "]") == $5) ||
                           ((prog ":") == $5)) { print $1 ; exit 0 } }' $1
}

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

	# First try "pidof"
	pid=$(pidof -o $$ -o $PPID -o %PPID -x $1)
	if [ -n "$pid" ] ; then
	        nls "%s (pid %s) is running..." "$1" "$pid"
	        return 0
        else
                pid=`ps ax | awk 'BEGIN { prog=ARGV[1]; ARGC=1 }
                           { if ((prog == $5) || (("(" prog ")") == $5) ||
                             (("[" prog "]") == $5) ||
                           ((prog ":") == $5)) { print $1 ; exit 0 } }' $1`
                if [ "$pid" != "" ] ; then
                        nls "%s (pid %s) is running..." "$1" "$pid"
                        return 0
                fi
	fi

	# Next try "/var/run/*.pid" files
	if [ -f /var/run/$1.pid ] ; then
	        pid=$(head -1 /var/run/$1.pid)
	        if [ -n "$pid" ] ; then
	                nls "%s dead but pid file exists" "$1"
	                return 1
	        fi
	fi
	# See if /var/lock/subsys/$1 exists
	if [ -f /var/lock/subsys/$1 ]; then
		nls "%s dead but subsys locked" "$1"
		return 2
	fi
	nls "%s is stopped" "$1"
	return 3
}

# Confirm whether we really want to run this service
confirm() {
	local answer
	nls -n "Start service %s (Y)es/(N)o/(C)ontinue? [Y] " "$1"
	read answer
	case $answer in
		y|Y|t|T|j|J|"")
			return 0
		;;
		c|C|k|K|w|W)
			return 2
		;;
		n|N)
			return 1
		;;
		*)
			confirm $1
			return $?
		;;
	esac
}

is_yes()
{
	# Test syntax	
	if [ $# = 0 ] ; then
		msg_usage " is_yes {value}"
		return 2
	fi

	# Check value
	case "$1" in
		yes|Yes|YES|true|True|TRUE|on|On|ON|Y|y|1)
			# true returns zero
			return 0
		;;
		*)
			# false returns one
			return 1
		;;
	esac
}

is_no()
{
	# Test syntax
	if [ $# = 0 ] ; then
		msg_usage " is_no {value}"
		return 2
	fi

	# It's important that is_no() should always return logical
	# negation of is_yes(). Really ALWAYS. --misiek
	# NOTE: This means that passing value which mean neither "yes" nor
	# "no" will return "true", beacause it does not mean "yes". Weird,
	# isn't it? :) --mkochano
	if is_yes "$1" ; then
		return 1
	else
		return 0
	fi
}

# module is needed (ie. is requested, is available and isn't loaded already)
is_module()
{
	# module name without .o at end
	if ! (lsmod | grep -q "$1"); then
		if (ls -R /lib/modules/$(uname -r)/ 2> /dev/null | grep -q "${1}.o"); then
			# true
			return 0
		fi
	fi
	# false
	return 1
}

_modprobe()
{
	local parsed single die args foo result
	parsed=no
	while is_no "$parsed" ; do
		case "$1" in
			"single")
				single=yes
				shift
				;;
			"die")
				die=yes
				shift
				;;
			-*)
				args="$args $1"
				shift
				;;
			*)
				parsed=yes
				;;
		esac
	done
	if is_yes "${single}" ; then
		foo="$@"
		show "Loading %s kernel module(s)" "$foo"
		busy
	fi
	if [ -x /sbin/modprobe ] ; then
		/sbin/modprobe -s $args "$@"
		result=$?
	else
		deltext ; fail
		result=1
	fi
	if is_yes "${single}" ; then
		deltext
		if [ $result == "0" ] ; then
			is_yes "$single" && ok
		else
			fail
			if is_yes "$die" ; then
				nls "Could not load %s kernel module(s)" "$@"
				exit 1
			fi
		fi
	fi
}

log_success ()
{
	initlog -n $0 -s "$1 $2" -e 1
}

log_failed ()
{
	initlog -n $0 -s "$1 $2" -e 2
}

# RedHat/Mandrake specific functions
action () { STRING=$1; shift; run_cmd "$STRING" "$*"; }
success () { return 0; }
failure () { return 1; }

# Will be removed in the future
msg_Network_Down () { msg_network_down "$*"; }
msg_Already_Running () { msg_already_running "$*"; }
msg_Not_Running () { msg_not_running "$*"; }
msg_Usage () { msg_usage "$*"; }

# This must be last line !
# vi:syntax=sh:tw=78:ts=8:sw=4
