#!/bin/sh 

# safe_clamd - a script to start clamd and restart if it dies unexpectedly
# Please report bugs at https://wwws.clamav.net/bugzilla/show_bug.cgi?id=2026
# Usage:
# start with ./safe_clamd
# stop by sending a TERM signal to the safe_clamd process

{
####################### CONFIGURATION #######################
# path to clamd.conf
CLAMDCONF='/usr/local/etc/clamd.conf'
# path to clamd binary
CLAMDBIN='/usr/local/sbin/clamd'
# interval between checks
SLEEPINTERVAL=3
# after a successful restart, sleep for $THROTTLE secs before attempting to restart clamd again
THROTTLE=30
##################### END CONFIGURATION #####################

# Do not touch anything below this line, unless you know what you are doing
trap "signalClamd HUP" SIGHUP
trap "signalClamd TERM" SIGTERM
trap "signalClamd USR2" SIGUSR2

getPid() {
	PIDFILE=`grep ^PidFile $CLAMDCONF | sed -e 's/^PidFile\s*//'`
	if [ -z "PIDFILE" ]
	then
		# missing PidFile directive
		echo "Please enable the PidFile directive in $CLAMDCONF. See man clamd.conf for more info."
		exit 1
	fi
	CLAMDPID=`cat $PIDFILE 2>/dev/null | grep -Eo '^[0-9]+$'` 
	if [ -z "$CLAMDPID" ]
	then
		# empty pidfile
		CLAMDPID=0
		return
	fi
	if ps p $CLAMDPID | grep -v grep | grep $CLAMDBIN > /dev/null
	then 
		# good pid
		return
	fi
	# invalid pid
	CLAMDPID=0
}

startClamd() {
	rm -f $PIDFILE 
	if test -f $PIDFILE
	then 
		echo "ERROR: cannot remove $PIDFILE" 
		exit 1 
	else
		$CLAMDBIN $args
		if [ $? -ne 0 ]
		then
			exit $?
		fi
		sleep $THROTTLE
	fi 
}

signalClamd() {
	getPid
	if [ $CLAMDPID -gt 0 ]; then
		echo "Sending $1 to pid $CLAMDPID..."
		kill -$1 $CLAMDPID
	else
		echo "$CLAMDBIN is not running."
	fi
	if [ "$1" == "TERM" ]; then
		echo Exiting $0 ...
		exit
	fi
}

args=$@

# start clamd
# if it start successfully, enter loop
# every 5 secs, find pid, verify it belongs to clamd, kill -0 
# restart it if dead
while [ true ]; do
	if test -r "$CLAMDCONF" 
	then 
		if test	-x "$CLAMDBIN"
		then
			# retrieve pid
			getPid
			# pid found?
			if [ $CLAMDPID -gt 0 ]
			then
				if kill -0 $CLAMDPID > /dev/null 2>/dev/null
	      			then 
					# pid is alive, sleep before next check
					sleep $SLEEPINTERVAL
	    			else
					# stale pid
					rm -f $PIDFILE
					startClamd
	    			fi
			else
				# pid does not belong to clamd 
				startClamd
			fi 
		else	
			echo $CLAMDBIN not found
			exit 1
		fi 
	else
		echo $CLAMDCONF not found
		exit 1
	fi
done

} &
