#! /bin/sh
#
# @(#)nsr_shutdown.sh 6.1 95/12/15 Copyright (c) 1995, Legato Systems, Inc.
#
# All rights reserved.
#

#
# Kill off all the processes associated with networker, this includes
# 	networker daemons
#		ansrd, nsrd, nsrmmd, nsrmmdbd, nsrindxd, nsrexecd, nsrib, nsriba
#	networker commands
#		asavegrp, savegrp
#	rap daemons
#		rapd, rapserv, rapcheck and perhaps rapla
# The names are shortened to 8 letters, since sys V machines show only
# the first 8 letters of the name of the process in the ps output.
#

RELEASE=4.2

mypath="`expr X\"${0}\" : X'\(.*\)/.*' \| X\"${0}\" : X'\(/\)[^/]*$' \| '.'`"
myname=`basename $0`

# NOTE: some systems put "Berkeley" utilities in /usr/ucb, others (e.g. SGI)
# put them in /usr/bsd.  Also, some systems use /usr/etc and other use
# /usr/sbin.  We include all variants in addition to the path to this
# program to be safe.
#
PATH=/usr/ucb:/usr/bsd:/bin:/usr/bin:/etc:/usr/etc:/usr/sbin:$mypath:$PATH
export PATH

# default values
productname=NetWorker

# nsrindexd, asavegroup and savegroup were shortened since
# Sys V machines only produce 8 character process names in ps
# Note that these command names were shortened for 8.3 systems,
# but were left long here in case someone tries to use a new
# nsr_shutdown to kill old daemons.
nsr_daemons="ansrd nsrd nsrindex nsrindxd nsrmmd nsrmmdbd nsrexecd nsrib nsriba"
rap_daemons="rapd rapcheck"
savegroup_procs="asavegro savegrou asavegrp savegrp"
archive_procs="nsralist"

if [ -f /bin/hostname ]; then
	host=`/bin/hostname`
elif [ -f /usr/ucb/hostname ]; then
	host=`/usr/ucb/hostname`
elif [ -f /usr/bsd/hostname ]; then
	host=`/usr/bsd/hostname`
elif [ -f /usr/local/bin/hostname ]; then
	host=`/usr/local/bin/hostname`
else
	host=
fi
if [ X${host} = X ]; then
	host=`uname -n`
fi

nflag=n
qflag=n
debug=n

bsd_kill=kill
bsd_echo=true
bsd_ps=true
id=id

killarch=y
killsg=y
killnsr=y
killrap=n

# save the args
ARGS="$*"

# find the binary type of /bin/sh
set X `file /bin/sh`
shift
# for some shells, the above 'set' results in 'X' being $0 and '/bin/sh:'
# in $1 so check for that and shift if it is true
if [ X"$1" = X/bin/sh: ]; then
	shift
fi
if [ X"$1" = Xsymbolic ]; then
	set X `file -L /bin/sh`
	shift
fi
bin_type="$1"
set X $ARGS
shift

#
# get O/S name to see later if it's OSF/1
#
uname=`uname`

#
# DEC's standard version of test doesn't know
# about -x option, so just use the -r option.
# note that we cannot use "elif", since this may be a bsd sh (news)!
#
if [ -r /usr/bin/arch ]; then
	sun=y
	id=whoami
	#
	# Since we explicitly set the PATH ourselves w/o the sys5 stuff,
	# we shouldn't get the sys5 echo behaviour from the shell.  We
	# don't use /bin/echo here because the sun386 /bin/echo will drop
	# lines after seeing a return within double quotes!
	#
else if [ -d /usr/sony ]; then
	if [ "X${SHUTDOWN_SHELL}" != "X/usr/5bin/sh" ]; then
		SHUTDOWN_SHELL=/usr/5bin/sh
		export SHUTDOWN_SHELL
		exec ${SHUTDOWN_SHELL} $0 $*
	fi
	news=y
	id=whoami
	bsd_echo=false
elif [ "X${uname}" = "XOSF1" ]; then
	bsd_echo=false
	bsd_ps=false
else if [ -r /usr/bin/sh5 -o X"${bin_type}" = Xmipsel ]; then
	#
	# Assume this is a DEC box
	#

	#
	# The standard DEC sh doesn't handle functions, we
	# need to make sure that we are using the sh5 shell.
	#
	if [ "X${SHUTDOWN_SHELL}" != "X/usr/bin/sh5" ]; then
		SHUTDOWN_SHELL=/usr/bin/sh5
		export SHUTDOWN_SHELL
		exec ${SHUTDOWN_SHELL} $0 $*
	fi
	bsd_echo=false
else if [ "X${uname}" = XLinux ]; then
	bsd_ps=true
	bsd_echo=true
else
	# On DG/UX, we must use uname -m because the value returned by uname
	# can be modified by the user.
	uname=`uname -m`
	if [ "X${uname}" = XAViiON ]; then
		#DG/UX has both V.4 and BSD characteristics.
		bsd_ps=false
	else
		# Generic System V
		if [ -f /usr/ucb/echo ]; then
			bsd_echo=true
		else
			bsd_echo=false
		fi
		if [ -f /usr/ucb/ps ]; then
			bsd_ps=true
		else
			bsd_ps=false
		fi
	fi	# AViiON
fi	# linux
fi	# dec
fi	# news
fi	# sun

umask 22


#
# qecho
#	quite echo:  if the qflag is no, then echo all arguments,
#	otherwise don't.
#
qecho()
{
	if [ ${qflag} = n ]; then
		echo "$*"
	fi
}

if [ $bsd_echo = true ]; then
	echo_n()
	{
		echo -n "$*"
	}
else
	echo_n()
	{
		echo "$*\c"
	}
fi


if [ $bsd_ps = true ]; then
	ps_name='$5'
else
	ps_name='$4'
fi

ps_all() {
	if [ $bsd_ps = true ]; then
		ps_output="`ps -ax | egrep 'nsr|rap|save'`"
#
# Of course, DEC OSF/1 had to be different in its ps output
#
	elif [ "X${uname}" = "XOSF1" ]; then
		ps_output="`ps -eopid,tt,time,comm | egrep 'nsr|rap|save'`"
	else if [ X${uname} = XAViiON ]; then
		#
		# On DG/UX, use ps -ef, then send it through awk to
		# format it like ps -e output.  (Necessary because 
		# ps -e truncates command names to eight characters.)
		#
		ps_output="`ps -ef | awk '
			{
			    if ($5 ~ /^[A-Za-z].*/) {
				printf \"%6u %-9s%5s %s\\n\", $2, $7, $8, $9;
			    }
			    else {
				printf \"%6u %-9s%5s %s\\n\", $2, $6, $7, $8;
			    }
			}'| egrep 'nsr|rap|save'`"
	else
		ps_output="`ps -e | egrep 'nsr|rap|save'`"
	fi
	fi
}

zero_worklist() {
	ps_all
	# we set this here to force find_nsrdaemons to do its thing
	killnsr=y
	find_nsrdaemons
	# if nsrd is up use rap against it
	# if it isn't use rap on the res file.
	if [ ! -z "${nsrdaemons}" ]; then
		RESFILE="-s ${host}"
	else
		if [ ! -f /nsr/res/nsr.res ]; then
			return;
		fi
		RESFILE="-f /nsr/res/nsr.res"
	fi
	rm -f /tmp/nsrsh$$
	echo '. type: nsr group' > /tmp/nsrsh$$
	echo 'update work list:; completion:' >> /tmp/nsrsh$$
	nsradmin ${RESFILE} -i - < /tmp/nsrsh$$ > /dev/null
	rm -f /tmp/nsrsh$$
}

#
# See if the any archive lists are running
#
# Outputs:
#	The archive list procs are in ${archprocs}
#
find_archprocs() {
	if [ ${killarch} = y ]; then
		if [ -z "${arch_pat}" ]; then
			for daemon in $archive_procs
			do
				if [ -z "${arch_pat}" ]; then
					arch_pat='[0-9] [-a-zA-Z\/._0-9]*('"${daemon}"
				else
					arch_pat="${arch_pat}|${daemon}"
				fi
			done
			arch_pat="${arch_pat}"')'
		fi
		archprocs="`echo "${ps_output}" | awk '/awk/	{ next }
				$0 ~ /'"$arch_pat"'/ { print $0 }'`"
	else
		archprocs=
	fi
}

#
# See if the any savegroups are running
#
# Outputs:
#	The savegroup procs are in ${sgprocs}
#
find_sgprocs() {
	if [ ${killsg} = y ]; then
		if [ -z "${sg_pat}" ]; then
			for daemon in $savegroup_procs
			do
				if [ -z "${sg_pat}" ]; then
					sg_pat='[0-9] [-a-zA-Z\/._0-9]*('"${daemon}"
				else
					sg_pat="${sg_pat}|${daemon}"
				fi
			done
			sg_pat="${sg_pat}"')'
		fi
		sgprocs="`echo "${ps_output}" | awk '/awk/	{ next }
				$0 ~ /'"$sg_pat"'/ { print $0 }'`"
	else
		sgprocs=
	fi
}

#
# See if the any of the RAP daemons are currently running.
#
# Outputs:
#	The rap daemons are in ${rapdaemons}
#
find_rapdaemons() {
	if [ ${killrap} = y ]; then
		if [ -z "${rap_pat}" ]; then
			for daemon in $rap_daemons
			do
				if [ -z "${rap_pat}" ]; then
					rap_pat='[0-9] [-a-zA-Z\/._0-9]*('"${daemon}"
				else
					rap_pat="${rap_pat}|${daemon}"
				fi
			done
			rap_pat="${rap_pat}"')'
		fi
		rapdaemons="`echo "${ps_output}" | awk '/awk/	{ next }
			$0 ~ /'"$rap_pat"'/ { print $0; next }'`"
	else
		rapdaemons=
	fi
}

#
# See if the any of the known ${productname} daemons are currently running.
#
# Outputs:
#	The networker daemons are in ${nsrdaemons}
#
find_nsrdaemons() {
	# build up an egrep style pattern we can feed to awk which will match
	# all the various daemons.
	if [ ${killnsr} = y ]; then
		if [ -z "${nsr_pat}" ]; then
			for daemon in $nsr_daemons
			do
				if [ -z "${nsr_pat}" ]; then
					nsr_pat='[0-9] [-a-zA-Z\/._0-9]*('"${daemon}"
				else
					nsr_pat="${nsr_pat}|${daemon}"
				fi
			done
			nsr_pat="${nsr_pat}"')'
		fi
		nsrdaemons="`echo "${ps_output}" | awk '/awk/	{ next }
				$0 ~ /'"$nsr_pat"'/ { print $0 }'`"
	else
		nsrdaemons=
	fi
}

#
# Kill nsrd (and nsrexecd), and their children.
#
# INPUTS:
#	killnsr=	y if daemons should be killed
#	productname=	e.g. NetWorker
#	kill_sig=	signal to use (blank for default)
#
killnsrd() {
	if [ ${killnsr} = y -a ! -z "${nsrdaemons}" ]; then
		qecho "	* * * Killing ${productname} daemons"
		if [ "X${kill_sig}" = "X-9" ]; then
			# kill all daemons, not just nsrd
			pid=`echo "${nsrdaemons}" | awk '{print $1}'`
		else
			pid=`echo "${nsrdaemons}" | \
				awk "$ps_name"' ~ /nsrd/ { print $1 } /nsrexecd/ { print $1 }'`
		fi

		if [ ! -z "${pid}" ]; then
			${bsd_kill} ${kill_sig} ${pid}
		fi
	fi
}

#
# Kill rapd and its children.  This function is provided for backward
# compatibility with older versions of nsr_shutdown.
#
# INPUTS:
#	killrap=	y if rap daemons should be killed
#	kill_sig=	signal to use (blank for default)
#
killrapd() {
	if [ ${killrap} = y -a ! -z "${rapdaemons}" ]; then
		qecho "	* * * Killing RAP daemons"
		pid=`echo "${rapdaemons}" | \
			awk "$ps_name"' ~ /rap/ { print $1 }'`
		if [ ! -z "${pid}" ]; then
			${bsd_kill} ${kill_sig} ${pid}
		fi
	fi
}

#
# yesno function
#
# Generic function to get yes/no answer
#
# inputs:
#	prompt=		string to prompt with (excluding default value)
#	default=	name of default value if no response
#
# outputs:
#	result=		'y' or 'n'
#
yesno() {
	if [ $debug = y ]; then
		notreally="(not really) "
	else
		notreally=
	fi
	while true
	do
		if [ -z "${default}" ]; then
			echo_n "${prompt}${notreally}? "
			read ans
		elif [ ${qflag} = n ]; then
			echo_n "${prompt} ${notreally}[${default}]? "
			read ans
		else
			ans=
		fi
		if [ "X${ans}" = X ]; then
			result="${default}"
		else
			result="${ans}"
		fi

		if [ `expr "X${result}" : 'X[yY]'` -ne 0 ]; then
			result=y
			break
		elif [ `expr "X${result}" : 'X[nN]'` -ne 0 ]; then
			result=n
			break
		else
			echo "Please respond \`yes' or \`no'"
		fi
	done
}

#
# usage function - prints out a usage message and exits
#
usage() {
	echo ""
	echo "usage: ${myname} [-a] [-A] [-d] [-n] [-q] [-r] [-s] [-v]"
	exit 1
}

#
# Process arguments.  Set tmp args here so we know if
# we have to reset defaults.
#
argsg=n
argnsr=n
argrap=n
argarch=n

while [ $# -gt 0 ]; do
	case "$1" in
	-q)
		qflag=y
		shift
		;;
	-a)
		argarch=y
		argsg=y
		argnsr=y
		argrap=y
		shift
		;;
	-A)
		argarch=y
		shift
		;;
	-d)	# killing nsrd implies killing savegroup and archive lists
		argarch=y
		argsg=y
		argnsr=y
		shift
		;;
	-n)
		nflag=y
		shift
		;;
	-D)
		bsd_kill="echo kill"
		debug=y
		shift
		;;
	-r)
		argrap=y
		shift
		;;
	-s)
		argsg=y
		shift
		;;
	-v)
		set -x
		shift
		;;
	-??*)
		# rip apart the concatenated argument, reset 'em, and reloop.
		first_opt="`expr substr "$1" 2 1`"
		rest_opts="`expr substr "$1" 3 255`"
		shift
		set -- "-$first_opt" "-$rest_opts" $*
		;;
	*)
		echo $1
		usage
		;;
	esac
done

#
# If any kill args were set toss defaults and use the
# arg values
#
if [ $argnsr = y -o $argrap = y -o $argsg = y -o $argarch = y ]; then
	killnsr=$argnsr
	killrap=$argrap
	killsg=$argsg
	killarch=$argarch
fi

#
# If not running in "do nothing mode" (or not debugging),
# insist on being run by the Super user.
#


if [ X${uname} = XAViiON ]; then
	#
	# This way is better than default way.  Must *really* have uid of 0.
        # This should work for Solaris, too.
	#
	whoiam="`id | awk '{print $1}'`"
	whoiam="`expr $whoiam : 'uid=\([0-9][0-9]*\)'`"
	if [ "$debug" = "n" -a $whoiam != 0 ]; then
		echo ""
		echo "${myname} must be run by the Super user!"
		exit 1
	fi
else
	#
	# This method has a hole.  If user or group name has substring of
	# "root", they get access!
	#
	whoiam=`${id} | grep root`
	if [ "$debug" = "n" -a -z "$whoiam" ]; then
		echo ""
		echo "${myname} must be run by the Super user!"
		exit 1
	fi
fi


ps_all
find_archprocs
find_sgprocs
find_nsrdaemons
find_rapdaemons

#
# If -n, just print daemons
#
if [ $nflag = y ]; then
	if [ ! -z "${archprocs}" ]; then
		echo "${archprocs}"
	fi
	if [ ! -z "${sgprocs}" ]; then
		echo "${sgprocs}"
	fi
	if [ ! -z "${nsrdaemons}" ]; then
		echo "${nsrdaemons}"
	fi
	if [ ! -z "${rapdaemons}" ]; then
		echo "${rapdaemons}"
	fi
	exit 0
fi

if [ -z "${archprocs}" -a -z "${sgprocs}" -a -z "${nsrdaemons}" -a -z "${rapdaemons}" ]; then
	qecho "${myname}: NetWorker daemons are already down"
	exit 0
fi

qecho "${myname} will kill the following processes"
if [ ! -z "${archprocs}" ]; then
	qecho "${archprocs}"
fi

if [ ! -z "${sgprocs}" ]; then
	qecho "${sgprocs}"
fi

if [ ! -z "${nsrdaemons}" ]; then
	qecho "${nsrdaemons}"
fi

if [ ! -z "${rapdaemons}" ]; then
	qecho "${rapdaemons}"
fi

prompt="Do you want to continue?"
default="Yes"
yesno

if [ ${result} = n ]; then
	qecho "${myname} exiting"
	exit 1
fi

#
# kill off the daemons then re-test to see if they are there gone
#
if [ ${killarch} = y -a ! -z "${archprocs}" ]; then
	qecho \
"	* * * Killing archive lists"
	pid=`echo "${archprocs}" | \
		awk "$ps_name"' ~ /nsralist/ { print $1 }'`
	if [ ! -z "${pid}" ]; then
		${bsd_kill} ${pid}
	fi
	qecho "	* * * Waiting for archive lists to die."
	sleep 5
	ps_all
	find_archprocs
	ntries=10
	while [ ! -z "${archprocs}" ];
	do
		ntries=`expr $ntries - 1`
		if [ $ntries -eq 0 ]; then
			${bsd_kill} -9 ${pid}
			break
		fi
		if [ ${qflag} = n ]; then
			echo_n  ". "
		fi
		sleep 5
		ps_all
		find_archprocs
	done
	qecho ""
fi

if [ ${killsg} = y -a ! -z "${sgprocs}" ]; then
	qecho \
"	* * * Killing savegrp"
	pid=`echo "${sgprocs}" | \
		awk "$ps_name"' ~ /savegr/ { print $1 }'`
	if [ ! -z "${pid}" ]; then
		${bsd_kill} ${pid}
	fi
	qecho "	* * * Waiting for savegrp to die."
	sleep 5
	ps_all
	find_sgprocs
	ntries=10
	while [ ! -z "${sgprocs}" ];
	do
		ntries=`expr $ntries - 1`
		if [ $ntries -eq 0 ]; then
			${bsd_kill} -9 ${pid}
			break
		fi
		if [ ${qflag} = n ]; then
			echo_n  ". "
		fi
		sleep 5
		ps_all
		find_sgprocs
	done
	qecho ""
fi

kill_sig=
killnsrd
killrapd

sleep 5
ps_all
find_nsrdaemons
find_rapdaemons

ntries=10
while [ ! -z "${nsrdaemons}" -o ! -z "${rapdaemons}" ];
do
	ntries=`expr ${ntries} - 1`
	qecho \
"	* * * daemons not dead yet (trying ${ntries} more times)."
	qecho "${nsrdaemons}"
	qecho "${rapdaemons}"
	if [ $ntries -eq 0 ]; then
		# use a bigger stick
		kill_sig="-9"
	fi
	if [ $ntries -le 6 ]; then
		killnsrd
		killrapd
	fi
	if [ $ntries -eq 0 ]; then
		break
	fi

	sleep 5
	ps_all
	find_nsrdaemons
	find_rapdaemons
done

if [ ${killsg} = y ]; then
	zero_worklist
fi
exit 0
