#!/bin/bash
############################################################################
##
## Copyright (c) 2000-2001 BalaBit IT Ltd, Budapest, Hungary
## All rights reserved.
##
## $Id: zorpctl.in,v 1.41 2004/05/19 09:32:43 sasa Exp $
##
############################################################################

prefix=/usr
pkglibdir=${prefix}/lib/zorp
pkgdatadir=${prefix}/share/zorp
sysconfdir=/etc/zorp
pidfiledir=/var/run/zorp

#export LD_LIBRARY_PATH=$pkglibdir
export PYTHONPATH=$pkgdatadir/pylib:$sysconfdir
ZORP=$pkglibdir/zorp
INSTANCES=$sysconfdir/instances.conf
DEFAULTS=$sysconfdir/zorpctl.conf

AUTO_RESTART=1
AUTO_RESTART_TIME_THRESHOLD=60
AUTO_RESTART_MAX_COUNT=3
PROCESS_LIMIT_THRESHOLD=2
PROCESS_LIMIT_MIN=256
FD_LIMIT_THRESHOLD=4
FD_LIMIT_MIN=1024
APPEND_ARGS=""
CHECK_PERMS=1

ulimit -s 65535

exit_code=0

if [ -r $DEFAULTS ]; then
	. $DEFAULTS
fi

read_instances()
{
	while read spec
	do
		if echo $spec | egrep -q '^#|^$' ; then
			continue
		fi
		if echo $spec | egrep -q '^[a-zA-Z0-9_]*[[:blank:]]*.*([[:blank:]]+--[[:blank:]]+.*)?$'; then
			if echo $spec | egrep -q ' -- '; then
				# we have some ctl params
				eval `echo $spec | sed -e 's/^\([a-zA-Z0-9_]*\)[[:blank:]]*\(.*\)[[:blank:]][[:blank:]]*--[[:blank:]][[:blank:]]*\(.*\)$/name="\1"; zorp_args_\1="\2"; zorp_ctl_\1="\3"/'`
			else
				# we don't have ctl params
				eval `echo $spec | sed -e 's/^\([a-zA-Z0-9_]*\)[[:blank:]]*\(.*\)$/name="\1"; zorp_args_\1="\2"; zorp_ctl_\1=""/'`
			fi

			instances="$instances $name"
		else
			write_error "Invalid line in instances.conf: [$spec]"
		fi
	done < $INSTANCES
}

write_error()
{
	errors=$errors$'\n'$1
}

log_errors()
{
	if [ "x$errors" != "x" ]; then
		echo -e "\nThe following errors occurred so far: " >&2
		echo $errors >&2
		errors=""
	fi
}

safe_start()
{
	local auto_restart=$1
	local bad_restarts=0
	local prev
	local now

	shift
	if [ "x$auto_restart" = "x1" ]; then
		prev=`date +%s`
		(exec < /dev/null >/dev/null 2> /dev/null;
		while true; do
			$ZORP $@
			rc=$?
			if [ "$rc" -lt 128 ]; then
				# if not terminated by signal, break
				break
			fi
			now=`date +%s`
			if [ $(($now - $prev)) -lt "$AUTO_RESTART_TIME_THRESHOLD" ]; then
				bad_restarts=$(($bad_restarts + 1))
				if [ "$bad_restarts" -ge "$AUTO_RESTART_MAX_COUNT" ]; then
					logger -t zorpctl "Excessive number of restarts more," \
						"than $AUTO_RESTART_MAX_COUNT " \
						"within $AUTO_RESTART_TIME_THRESHOLD seconds, exiting..."
					exit
				fi
			else
				logger -t zorpctl "Zorp exited due to a signal (exitcode=$rc), restarting..."
				sleep 1
				bad_restarts=0
			fi
		done;
		logger -t zorpctl "Zorp exited gracefully, exitcode=$rc") &
	else
		$ZORP $@ &
	fi
}

start() 
{
	local instance_name=$1
	local fd_limit
	local process_limit
	local auto_restart
	local threads
	local args

	eval "args=\$zorp_args_$instance_name; ctl=\$zorp_ctl_$instance_name"

	set -- `getopt --options aAf:p: \
		--longoptions auto-restart,no-auto-restart,fd-limit,process-limit \
		-n zorpctl -- $ctl`

	if echo $args | grep -q -- "--threads"; then
		threads=`echo $args |  sed -e 's/^.*--threads[[:blank:]]*\([[:digit:]]*\).*$/\1/'`
	fi
	if [ "x$threads" = "x" ]; then
		threads=100
	fi

	append_args=$APPEND_ARGS
	auto_restart=$AUTO_RESTART
	process_limit=$(($threads * $PROCESS_LIMIT_THRESHOLD))
	if [ "$process_limit" -lt "$PROCESS_LIMIT_MIN" ]; then
		process_limit=$PROCESS_LIMIT_MIN
	fi
	fd_limit=$(($threads * $FD_LIMIT_THRESHOLD + 64))
	if [ "$fd_limit" -lt "$FD_LIMIT_MIN" ]; then
		fd_limit=$FD_LIMIT_MIN
	fi
	while [ "x$1" != "x" ]; do
		case "$1" in
			--)
				break
				;;
			-A|--auto-restart)
				auto_restart=1
				shift
				;;
			-a|--no-auto-restart)
				auto_restart=0
				shift
				;;
			-f|--fd-limit)
				fd_limit=$2
				shift 2
				;;
			-p|--process-limit)
				process_limit=$2
				shift 2
				;;
			*)
				write_error "Invalid control options on instance $instance_name, $1"
				return
				;;
	
		esac
	done
	ulimit -n $fd_limit
	ulimit -u $process_limit
	
	args="--as $instance_name $args $append_args"
	if [ -r $pidfiledir/zorp-$instance_name.pid ]; then
		pid=`cat $pidfiledir/zorp-$instance_name.pid`
		if kill -CONT $pid >/dev/null 2>/dev/null; then
			# still running
			echo -n "$instance_name! "
			exit_code=1
		else
			rm $pidfiledir/zorp-$instance_name.pid
			safe_start $auto_restart $args
			echo -n "$instance_name "
		fi
	else
		safe_start $auto_restart $args
		echo -n "$instance_name "
	fi

}

stop() {
	instance_name=$1

	if [ -r $pidfiledir/zorp-$instance_name.pid ]; then
		pid=`cat $pidfiledir/zorp-$instance_name.pid`
		if kill -TERM $pid >/dev/null 2>/dev/null; then
			echo -n "$instance_name "
		else
			echo -n "$instance_name! "
			exit_code=2
			rm $pidfiledir/zorp-$instance_name.pid
		fi
	else
		echo -n "$instance_name! "
	fi
}

restart() {
	instance_name=$1
	stop $1 >/dev/null
	sleep 2
	start $1
}

reload() {
	instance_name=$1

	if [ -r $pidfiledir/zorp-$instance_name.pid ]; then
		pid=`cat $pidfiledir/zorp-$instance_name.pid`
		if kill -HUP $pid >/dev/null 2>/dev/null; then
			echo -n "$instance_name "
		else
			echo -n "$instance_name! "
			exit_code=2
			rm $pidfiledir/zorp-$instance_name.pid
		fi
	else
		echo -n "$instance_name! "
	fi
}

status() {
	instance_name=$1
	echo -n "Instance $instance_name: "
	old_IFS=$IFS
	IFS=""
	if [ -r $pidfiledir/zorp-$instance_name.pid ]; then
		pid=`cat $pidfiledir/zorp-$instance_name.pid`
		if kill -CONT $pid >/dev/null 2>/dev/null; then
			if [ "$psaxu" = "" ]; then
				psaxu=`ps axu | grep zorp`
			fi
			threads=`echo $psaxu | grep "zorp --as $instance_name " | grep -v grep | wc -l | sed -e 's/ *\([0-9]*\)$/\1/'`
			echo "running, $threads threads active."
		else
			echo "stale pidfile."
		fi
	else
		echo "not running."
	fi
	IFS=$old_IFS
}


checkperms()
{
	if [ "$CHECK_PERMS" = "1" ]; then 
		x=`ls -ld $sysconfdir | cut -d ' ' -f 1`
		if [ "$x" != "drwx------" -a "$x" != "drwxr-x---" ]; then
			write_error "Permissions of $sysconfdir are bad. It should be 0700 or 0750, fix it!"
		fi
	fi

}

process()
{
	func=$1
	shift
	if [ "x$1" != "x" ]; then
		# start all listed instances
		while [ "x$1" != "x" ]; do
			eval "args=\$zorp_args_$1"   
			if [ "x$args" = "x" ]; then
				write_error "Unknown instance: $1"
				shift
				continue
			fi

			eval "$func $1"
			shift
		done
	else
		# nothing is listed, start all
		for x in $instances; do
			eval "$func $x"
		done
	fi
	echo ''

}


checkperms
read_instances

case "$1" in
	start)
		echo -n "Starting Zorp Firewall Suite: "
		process $@
		;;
	stop)
		echo -n "Stopping Zorp Firewall Suite: "
		process $@
		;;
	restart)
		echo -n "Restarting Zorp Firewall Suite: "
		shift
		process restart $@
		;;
	reload)
		echo -n "Reloading Zorp Firewall Suite: "
		shift
		process reload $@
		;;
	version)
		echo "ZORP=$ZORP"
		$ZORP --version
		;;
	status)
		process $@
		;;
	*)
		echo "Usage: $0 start [instance] |stop [instance] |restart [instance]| status [instance] | version"
		;;
esac

log_errors

exit $exit_code
