#!/bin/sh
#
# Remove diskless client on Solbourne server
#
# Copyright (c) 1989 Solbourne Computer, Inc.


#
# Global variables
#

Myname=`basename "$0"`
Usage="[-v] [-x] [-e] [-p pid] client [client] ...
Where:
	'-v'	 - turns on verbose output mode
	'-x'	 - turns on shell execution trace
	'-e'	 - specifies that server's exports file will NOT be modified
	'-p pid	 - specifies process id of sysadmin install tool
		   (should be used only by tool)
	'client' - name of the diskless client to be removed"
Vflag=:
Xflag=
NO_EXPORTS=no

#
# Filesystem specific pathnames
#

EXPORT_DIR=${EXPORT_DIR-/export}
EXPORT_ROOT=${EXPORT_ROOT-${EXPORT_DIR}/root}
EXPORT_USR=${EXPORT_USR-${EXPORT_DIR}/exec}
EXPORT_SWAP=${EXPORT_SWAP-${EXPORT_DIR}/swap}
EXPORT_CRASH=${EXPORT_CRASH-${EXPORT_DIR}/crash}
EXPORT_FILE=${EXPORT_FILE-/etc/exports}
LOG=${LOG-/var/log/diskless_log}
MYPATH=${MYPATH-/usr/etc/setup}
SERVER_HOME=${SERVER_HOME-/home}
SERVER_HOSTS=${SERVER_HOSTS-/etc/hosts}
SERVER_BOOT=${SERVER_BOOT-/etc/bootparams}
CLIENT_HOME=${CLIENT_HOME-/home}
TMP_ERR=/tmp/ins_err$$

#
# Sysadmin too variables
#

ADMPID=""
TMP_ADMOUT=/tmp/ins_cs$$

#
# Set up default path
#

PATH=/bin:/usr/bin:/usr/ucb:${MYPATH}
export PATH

#
# Main function - test arguments and verify valid call
#
main()
{

	# Get optional argument

	while getopts "vxep:" arg
	do
		case "$arg" in
		v)
			Vflag= ;;
		x)
			set -x;;
		e)	NO_EXPORTS="yes";;
		p)	ADMPID="$OPTARG"
			TMP_ADMOUT=/tmp/ins_cs${ADMPID};;
		*)
			usage ;;
		esac
	done

	shift `expr $OPTIND - 1`

	# Test to see if client name specified

	if [ $# -lt 1 ]
	then
		usage
	fi

	# Test to see if we are running as root

	am_i_root || fatal "Must be run by the super user"

	# Loop through each client specified

	while [ $# -gt 0 ]
	do
		$Vflag echo "Removing client \"$1\""
		(remove "$1")
		shift
	done

	if [ "$NO_EXPORTS" = "no" ]
	then
		# Run /usr/etc/exportfs to read in new exports info

		/usr/etc/exportfs -a || error "Check ${EXPORT_FILE}"

		$Vflag echo "Complete"
	fi
}

#
# High level remove script.  Set values based on current client name
#

remove()
{
	CLIENT=${1-unknown}
	SWAPFILE=${EXPORT_SWAP}/${CLIENT}/swap.${CLIENT}

	# Verify client exists in hosts file and get hex equivalent

	DOMAIN=`/bin/domainname` || fatal "Can not determine domainname"

	if [ "${DOMAIN}" = "" ]
	then
		DOMAIN="noname"
	fi

	if [ "${DOMAIN}" != "noname" ]
	then
		Yp="ypmatch ${CLIENT} hosts"
	else
		Yp="grep ${CLIENT} ${SERVER_HOSTS}"
	fi

	INETADDR=`${Yp} | sed -e "s/${CLIENT}//"`

	if [ "${INETADDR}" = "" ]
	then
		fatal "Client internet address not found.  Check /etc/hosts or yp"
	fi

	HEXADDR=`hex_inet ${INETADDR}` || fatal "Can not convert internet address"

	# Arguments okay.  Record start in log and catch signals

	log "========== Removing diskless client =========="
	log "$* Started `date`"
	trap "sig_abort; wrapup 1" 1 2 3 15

	# Do real work in a sub-shell, to capture error output for log
	# Redirect standard input to /dev/null, just in case something
	# tries to read.

	if [ "$ADMPID" != "" ]
	then
		do_cmd ${1+"$@"} >${TMP_ERR} 2>&1
	else
		(
			do_cmd ${1+"$@"} 2>&1
		) </dev/null | tee ${TMP_ERR}
	fi

	# Record any error output to log, and display to user
	# If there was an error, pass exit status up

	cmp -s ${TMP_ERR} /dev/null
	wrapup $?
}

#
# Verify client name and directories, and do operation
#

do_cmd()
{
	trap 1 2 3 15

	if [ "$NO_EXPORTS" = "no" ]
	then
		# Remove client permissions from /etc/exports

		update_exports -d ${CLIENT}

		# Unexport any current directories that are no longer
		# in the /etc/exports file.  Ignore any errors

		for fs in `awk '{ print $1 }' /etc/xtab`
		do
			grep -s "$fs" ${EXPORT_FILE} || /usr/etc/exportfs -u "$fs"
		done 	>/dev/null 2>/dev/null

		# Now export/reexport everything in exports file
		/usr/etc/exportfs -a 2>/dev/null
	fi

	# Remove client root directory and possible symbolic link

	if [ -d ${EXPORT_ROOT}/${CLIENT} ]
	then
		cd ${EXPORT_ROOT}/${CLIENT} &&
			rm -rf `ls -a|egrep -v '^\.$|^\.\.$'` &&
			cd / &&
			rm -rf ${EXPORT_ROOT}/${CLIENT}
		if [ $? -ne 0 ]
		then
			fatal "Can not remove client root directory"
		fi
	fi

	# Remove client swap file

	if [ -f ${SWAPFILE} ]
	then
		rm -rf ${SWAPFILE} || 
			fatal "Can not remove client swap file"
	else
		SWAPFILE=`get_swapfile`

		if [ -f ${EXPORT_SWAP}/${CLIENT}/${SWAPFILE} ]
		then
			rm -rf ${EXPORT_SWAP}/${CLIENT}/${SWAPFILE}
		fi
	fi

	rm -rf ${EXPORT_SWAP}/${CLIENT}

	# Remove client crash directory

	rm -rf ${EXPORT_CRASH}/${CLIENT}

	# Remove entry from /tftpboot

	tftpboot_link || exit 1

	# Remove client info from /etc/bootparams

	update_bootparams || exit 1
}

#
# Get non-standard swap file name from /etc/bootparams
#

get_swapfile()
{
	if [ ! -f ${SERVER_BOOT} ]
	then
		return
	else
		expr `grep "${EXPORT_SWAP}/${CLIENT}" ${SERVER_BOOT} | \
		awk '{print $1}'` : '.*\/\(.*\)' 2>/dev/null 
	fi
}

#
# Remove boot file link from server's /tftpboot directory
#

tftpboot_link()
{
	rm -f /tftpboot/${HEXADDR}* 2>/dev/null
}

#
# Update server /etc/bootparams file by deleting client info
#

update_bootparams()
{
	if [ ! -f ${SERVER_BOOT} ]
	then
		return
	fi

	echo "# ${CLIENT}" >>${SERVER_BOOT}
	ed - ${SERVER_BOOT} <<-_EOF_
		H
		g/${CLIENT}/d
		w
		q
	_EOF_

	# If null file remains, remove it

	cmp -s /dev/null ${SERVER_BOOT} && rm -f ${SERVER_BOOT}
}

#
# Convert class A, B, or C internet addressed to hex
#
# Argument address is filtered by "sed(1)" and modified to
# give appropriate input to the "dc(1)" command.
# This result is forced to be 9 digits long,
# and "expr(1)" is used to remove the first character
# so that the final answer is a zero padded 8 characters long
#

hex_inet()
{
	expr `echo ${1-0} + + p | sed -e 's/\([0-9]*\)\.*/16o 0 256 \1 + 256 * 256 * 256 * 0 /' \
		-e 's/\./+ 256 */g' | dc` : '.\(.*\)'
}

#
# fatal error - print message and exit
#

fatal()
{
	error "$*"
	wrapup 1
	exit 1
}

#
# error() prints an error message to stderr
#

error()
{
	if [ "${ADMPID}" != "" ]
	then
		if [ -f ${TMP_ERR} ]
		then
			Errout="`cat ${TMP_ERR}`
$Myname: $*"
			rm -f ${TMP_ERR}
		else
			Errout="$Myname: $*"
		fi
		sysadm_display NOWAIT "$Errout"
	else
		echo "$Myname: $*" 1>&2
	fi
}

#
# usage() prints a usage message (usage is in the variable Usage)
#

usage()
{
	if [ "${ADMPID}" != "" ]
	then
		sysadm_display NOWAIT "usage: $Myname $Usage"
	else
		echo "usage: $Myname $Usage" 1>&2
	fi
	exit 2
}

#
# Let sysadmin installation tool handle display to user
#

sysadm_display()
{
	# First argument signals WAIT/NOWAIT/EXIT; print on separate line
	echo "$1" >${TMP_ADMOUT}
	shift
	echo "$*" >>${TMP_ADMOUT}

	while
		kill -0 ${ADMPID:-x} 2>/dev/null || break
		test -f ${TMP_ADMOUT}
	do
		sleep 2
	done

	if [ -f ${TMP_ADMOUT} ]
	then
		echo "$*" >/dev/tty
		rm -f ${TMP_ADMOUT}
	fi
}


#
# Signal cleanup.  Print message to user and to log
#

sig_abort()
{
	log "Aborted by signal"
	echo >/dev/tty
}

#
# Record message in installation log
#
log()
{
	echo "$Myname: $*" >>${LOG}
}

#
# Final command wrap up.  Record errors and completion in log.
# Remove temporary files
#

wrapup()
{
	trap '' 1 2 3 15

	Errout="Failed due to error."
	if [ -f ${TMP_ERR} ]
	then
		cat ${TMP_ERR} >>${LOG}
		if [ "$ADMPID" != "" ]
		then
			Errout="`cat ${TMP_ERR}`
$Errout"
		fi
		rm -f ${TMP_ERR}
	fi

	log "Completed with status $1 `date`"
	if [ "$1" != "0" ]
	then
		log "***** Failed due to error. *****"
		error "$Errout"
		if [ "$ADMPID" != "" ]
		then
			sysadm_display EXIT "Client Removal Failed"
		fi
	else
		rm -f ${TMP_ERR}
		if [ "$ADMPID" != "" ]
		then
			sysadm_display EXIT "Client Removed Successfully"
		fi
	fi
	exit $1
}

#
# am_i_root is the equivalent of
#   (id | grep 'uid=0') > /dev/null
# which cannot be relied on because id is SysV only
#
am_i_root()
{
	if [ `whoami` = "root" ]
	then
		return 0
	else
		return 1
	fi
}

#
# Perform main function
#

main $*
exit 0
