#! /bin/sh
#
# $Id: nsr_shutdown.sh,v 6.36.6.4.2.1.4.4 2005/02/09 17:21:03 slattery Exp $ Copyright (c) 2005, LEGATO Software, a division of EMC.
#

# 
# Copyright (c) 2005, LEGATO Software, a division of EMC.
# 
# All rights reserved.  This is an UNPUBLISHED work, and
# comprises proprietary and confidential information of LEGATO.
# Unauthorized use, disclosure, and distribution are strictly
# prohibited.  Use, duplication, or disclosure of the software
# and documentation by the U.S. Government is subject to
# restrictions set forth in a license agreement between the
# Government and LEGATO or other written agreement specifying
# the Government's rights to use the software and any applicable
# FAR provisions, such as FAR 52.227-19.
#

#
# Kill off all the processes associated with networker, this includes
# 	networker daemons
#		ansrd, nsrd, nsrmmd, nsrmmdbd, nsrindxd, nsrexecd, nsrhsmd,
#		nsrhsmrc nsrib nsriba hagentd
#	licensing daemon
#		lgtolmd
#	networker commands
#		nsrexec, savegrp
# 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=7.2.2.Build.422


# 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.
#
#
# additionally some OSes on a shutdown reset PATH to something completely
# different (like HP uses /sbin) which will result in the basename and 
# expr calls failing because they are not on the PATH 
# So set PATH in two stages 

PATH=/usr/ucb:/usr/bsd:/bin:/usr/bin:/etc:/usr/etc:/usr/sbin:$PATH
mypath="`expr X\"${0}\" : X'\(.*\)/.*' \| X\"${0}\" : X'\(/\)[^/]*$' \| '.'`"
PATH=$mypath:$PATH
export PATH
myname=`basename $0`

# default values
productname=NetWorker

# nsrindexd 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 hagentd nsrd nsrindex nsrindxd nsrmmd nsrmmdbd nsrexecd nsrib nsriba nsrhsmd nsrhsmrc"
lic_daemons="lgtolmd"
savegroup_procs="savegrou nsrexec nsrssc 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
lic_ps=false
clu_host=false
id=id

killarch=y
killsg=y
killnsr=y
kill_sig=

# 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.
#
if [ "X${uname}" = "XSunOS" ]; then
	sun=y
	clu_host=true
	#
	# Can't count on the BSD stuff being there (Solaris 9 minimal
	# install does not install the BSD stuff), so test if it is
	# there before commiting to using it. It appears that echo is
	# a shell built in for Solaris sh which acts like BSD echo.
	#
	if [ -f /usr/ucb/ps ]; then
		bsd_ps=true
	else
		bsd_ps=false
	fi
	if [ -f /usr/ucb/whoami ]; then
		id=whoami
	fi
	#
	# We don't use /bin/echo here because the sun386 /bin/echo
	# will drop lines after seeing a return within double quotes!
	#
elif [ "X${uname}" = "XAIX" ]; then
	bsd_echo=false
	bsd_ps=false
	lic_ps=true
	clu_host=true
elif [ "X${uname}" = "XDarwin" ]; then
	bsd_echo=true
	bsd_ps=true
elif [ "X${uname}" = "XDYNIX/ptx" ]; then
	bsd_echo=false
	bsd_ps=false
	lic_ps=true
elif [ "X${uname}" = "XOSF1" ]; then
	bsd_echo=false
	bsd_ps=false
	clu_host=true
	lic_ps=true
elif [ -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
elif [ "X${uname}" = "XNetBSD" ]; then
	bsd_ps=true
	bsd_echo=true
elif [ "X${uname}" = "XFreeBSD" ]; then
	bsd_ps=true
	bsd_echo=true
elif [ "X${uname}" = "XBSD/OS" ]; then
	bsd_ps=true
	bsd_echo=true
elif [ "X${uname}" = "XLinux" ]; then
	bsd_ps=false
	bsd_echo=true
	clu_host=true
elif [ "X${uname}" = "XHP-UX" ]; then
        bsd_echo=false
        bsd_ps=false
	clu_host=true
	lic_ps=true
elif [ "X${uname}" = "XIRIX" ]; then
        bsd_ps=false
	lic_ps=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

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

ps_all()
{
	if [ $bsd_ps = true ]; then
		ps_output="`ps ax | egrep 'nsr|save|lgto|hagentd'`"
	elif [ 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|save|lgto|hagentd'`"
	else
		ps_output="`ps -ef | egrep 'nsr|save|lgto|hagentd'`"
	fi

	# determine relative positions of needed fields which would be
	# derived from either bsd or non-bsd style ps ( ps -ax or ps -ef )
	# nothing else
	# because some daemons will have been up less than 24 hours while
	# others may have been more this confuses the matter
	if [ $bsd_ps = true ]; then
	        #
	        # bsd style output is the easiest
	        #
	        ps_name_nsrd='$5'
	        ps_name_lgtlolmd='$5'
	        ps_name_saveg='$5'
	        ps_name_arch='$5'
	        ps_pid='$1'
	        lic_version='$9'
	        lic_retry='$12'
	else
	        ps_pid='$2'

	        # stime can be hh:mm:ss or mm dd - either one field or two
	        # but this could vary between daemons.  The only ones that need
	        # absolute positions are nsrd, lgtolmd and savegrp
	        ps_stime_nsrd="`ps -ef  | egrep 'nsrd' | awk '{ print $8 }' | egrep 'nsrd'`"
		ps_stime_lgtolmd="`ps -ef  | egrep 'lgto' | awk '{ print $8 }' | egrep 'lgto'`"
	        ps_stime_saveg="`ps -ef  | egrep 'saveg' | awk '{ print $8 }' |
egrep 'saveg'`"
	        ps_stime_arch="`ps -ef  | egrep 'nsralist' | awk '{ print $8 }' | egrep 'nsralist'`"
	        if [ ! -z "$ps_stime_nsrd" ]; then
	                # stime for nsrd is less than 24 hours
	                ps_name_nsrd='$8'
	        else
	                ps_name_nsrd='$9'
	        fi
	        if [ ! -z "$ps_stime_lgtolmd" ]; then
	                # stime for lgtolmd is less than 24 hours
	                ps_name_lgtolmd='$8'
	                lic_version='$12'
	                lic_retry='$12'
	        else
	                ps_name_lgtolmd='$9'
	                lic_retry='$13'
	                lic_version='$13'
	        fi
	        if [ ! -z "$ps_stime_saveg" ]; then
	                # stime for savegrp is less than 24 hours
	                ps_name_saveg='$8'
	        else
	                ps_name_saveg='$9'
	        fi
	        if [ ! -z "$ps_stime_arch" ]; then
	                # stime for nsralist is less than 24 hours
	                ps_name_arch='$8'
	        else
	                ps_name_arch='$9'
	        fi
	fi
}

zero_worklist()
{
	ps_all
	# we set this here to force find_nsrdaemons to do its thing
	cached_killnsr=$killnsr
	killnsr=y
	find_nsrdaemons
	if [ "`echo ${nsrdaemons} | grep nsrd`" ]; then

		NSRGROUPS=`nsradmin -s ${host} -i - <<-EOC | grep name | \
			awk ' { for(i=2; i<= NF; i++) printf "%s ",$i }  { print "" } '

			. type :nsr group
			show name
			print
			EOC` 
		
		while [ "$NSRGROUPS" ]; do

			GROUP=`echo $NSRGROUPS | cut -d";" -f1`

			nsradmin -s ${host} <<-EOC>/dev/null
				. type:nsr group; name: $GROUP
				update progress file name:
				y
				q
EOC

			NSRGROUPS=`echo $NSRGROUPS | sed -e "s/$GROUP;//"` 
		done
        fi
	killnsr=$cached_killnsr
}

#
# 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}" | sed -e 's/nsrexecd//' |
			awk '/awk/	{ next }
			$0 ~ /'"$sg_pat"'/ { print $0 }'`"
	else
		sgprocs=
	fi
}

#
# See if the any of the known ${productname} daemons are currently running.
#
# INPUTS:
#	killnsr=	y if daemons should be killed
#
# 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
}

#
# See if the any of the known ${productname} daemons are currently running.
#
# INPUTS:
#	killnsr=	y if daemons should be killed
#
# Outputs:
#	The licensing daemons are in ${licdaemons}.  Only those with
#	RPC version number 1 ( -n 1 flag) are legitimate.
#
find_licdaemons()
{
	# build up an egrep style pattern we can feed to awk which will match
	# all the various daemons.
	if [ ${killnsr} = y ]; then
		if [ -z "${lic_pat}" ]; then
			for daemon in $lic_daemons
			do
				if [ -z "${lic_pat}" ]; then
					lic_pat='[0-9] [-a-zA-Z\+\/._0-9]*('"${daemon}"
				else
					lic_pat="${lic_pat}|${daemon}"
				fi
			done
			lic_pat="${lic_pat}"')'
		fi
		temp="`echo "${ps_output}" | awk '/awk/	{ next }
				$0 ~ /'"$lic_pat"'/ { print $0 }'`"
		licdaemons="`echo "${temp}" | \
			awk "$lic_version"' ~ /'"1"'/ { print $0 }'`"
		if [ -z "${licdaemons}" ]; then
			licdaemons="`echo "${temp}" | \
				awk "$lic_retry"' ~ /'"1"'/ { print $0 }'`"
			lic_version="$lic_retry"
		fi
	else
		licdaemons=
	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 almost all daemons, not just nsrd and nsrexecd.
			# Ignore nsrhsmrc's which are recalling migrated files.
			pid=`echo "${nsrdaemons}" | awk '/nsrhsmrc|nsrib/ {next} {print '"$ps_pid"'}'`
		else
			pid=`echo "${nsrdaemons}" | \
				awk "$ps_name_nsrd"' ~ /nsrd/ { print '"$ps_pid"' } /nsrexecd/ { print '"$ps_pid"' } /hagentd/ { print '"$ps_pid"' }'`
		fi

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

#
# Kill lgtolmd
#
# INPUTS:
#	killnsr=	y if daemons should be killed
#	kill_sig=	signal to use (blank for default)
#
killlgtolmd()
{
	if [ ${killnsr} = y -a ! -z "${licdaemons}" ]; then
		qecho "	* * * Killing Licensing daemons"
		pid=`echo "${licdaemons}" | \
			awk "$lic_version"' ~ /'"1"'/ { print '"$ps_pid"' }'`
		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] [-c] [-d] [-n] [-q] [-s] [-v]"
	exit 1
}

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

while [ $# -gt 0 ]; do
	case "$1" in
	-q)
		qflag=y
		shift
		;;
	-a)
		argarch=y
		argsg=y
		argnsr=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
		;;
	-c)    
		shift
		if [ "${clu_host}" = true ]; then
		    keepworklist=yes
		else
		    usage
		fi
		;;
	-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 $argsg = y -o $argarch = y ]; then
	killnsr=$argnsr
	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_licdaemons

#
# 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 "${licdaemons}" ]; then
		echo "${licdaemons}"
	fi
	exit 0
fi

if [ -z "${archprocs}" -a -z "${sgprocs}" -a -z "${nsrdaemons}" -a \
     -z "${licdaemons}" ]; 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 "${licdaemons}" ]; then
	qecho "${licdaemons}"
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_arch"' ~ /nsralist/ { print '"$ps_pid"' }'`
	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_saveg"' ~ /savegr/ { print '"$ps_pid"' }'`
	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

if [ ${killsg} = y -a ${keepworklist} = "no" ]; then
	zero_worklist
fi

kill_sig=
killnsrd
killlgtolmd

sleep 5
ps_all
find_nsrdaemons
find_licdaemons

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

	sleep 10 
	ps_all
	find_nsrdaemons
	find_licdaemons
done

if [ "X${uname}" = "XOSF1" -a "${worklist}" = "yes" ]; then
        exit 0
fi

exit 0
