:
#	@(#) btldinstall 23.7 91/11/25 
#
#	Copyright (C) 1991 The Santa Cruz Operation, Inc.
#		All Rights Reserved.
#	The information in this file is provided for the exclusive use of
#	the licensees of The Santa Cruz Operation, Inc.  Such users have the
#	right to use, modify, and incorporate this code into other products
#	for purposes authorized by the license agreement provided they include
#	this notice and the associated copyright notice with any such product.
#	The information in this file is provided "AS IS" without warranty.
#
# usage:	btldinstall <mntdir>
# function:	install packages from a Boot Time Loadable Drivers disk
#		mounted on <mntdir>; unwind changes in the event of an error


# Define return values
: ${OK=0} ${FAIL=1} ${STOP=10} ${HALT=11} ${NEG=-1}

# Remove temp files and exit with the status passed as argument
cleanup() 
{
	trap '' 1 2 3 15
	exit $1
}

################################################################################
#reverse:	reverse(file)
#		reverse the order of lines in ${file} and cat the result
################################################################################
reverse()
{
	file=$1
	[ -s ${file} ] && \
	awk ' { aline[NR] =$0 } END { do print aline[NR]; while (NR-- > 0) }' \
		${file} 

}

################################################################################
#getyn:
#	prompts the user for a yes or no answer
#
################################################################################
getyn() {
	while	echo "\n$* (y/n) \c">&2
	do	read yn rest
		case $yn in
		[yY])	return $OK 			;;
		[nN])	return $FAIL			;;
		*)	echo "Please answer y or n" >&2	;;
		esac
	done
}

################################################################################
#unwind:	unwind
#		for each pkg in /etc/.btld_safe/.packages
#			delete each file copied from /pkg/new to /
#			copy each file from /etc/.btld_safe/pkg/new as /
#			delete each device listed in /etc/.btld_safe/.dev_add
#			add each device listed in /etc/.btld_safe/.dev_del
#			remove /usr/options/pkg.name
#		done
################################################################################

unwind()
{
	msgid=$1
	case "${msgid}"
	in
		E )	echo "An error has occured in \c"
			echo "the installation.";;
		Q )	echo "User interrupt during installation.";;
		S )	echo "Signal received during installation.";;
	esac
	echo "Unwinding of changes made to the Link Kit is being attempted..."

	# first check for /etc/.last_dev_add or /etc/.last_dev_del
	if [ -f /etc/.last_dev_add ]
	then
		DEV=`cat /etc/.last_dev_add`
		${CONF}/bin/idinstall -d $DEV > /dev/null
	elif [ -d /etc/.last_dev_del ]
	then
		rstr_drvr ${ROOT}/etc/.last_dev_del
	fi

	# unwind from /etc/.btld_safe
	cd ${ROOT}/etc/.btld_safe
	for pkg in `reverse ${ROOT}/etc/.btld_safe/.packages`
	do
		echo "\nUnwinding package: ${pkg}"
		# remove any files copied over
		if [ -f "${pkg}/.files" ]
		then
			echo "Removing the following files:"
			for file in `cat ${pkg}/.files`
			do
				echo ${file}
				rm -f ${file} > /dev/null
			done
		fi

		# restore preserved files
		if [ -d "${pkg}/new" ]
		then
			if expr `ls -a ${pkg}/new | wc -l` \> 2 >/dev/null
			then
				echo "Restoring the following files:"
				cd ${pkg}/new
				find ./ -print 2>/dev/null | cpio -pvudm / 2>/dev/null
			fi
			cd ${ROOT}/etc/.btld_safe
		fi

		# delete any drivers added
		if [ -f "${pkg}/.dev_add" ]
		then
			for device in `reverse ${pkg}/.dev_add`
			do
				echo "Deleting device: ${device}"
				${CONF}/bin/idinstall -d ${device} >/dev/null
			done
		fi

		# add any drivers deleted
		if [ -f "${pkg}/.dev_del" ]
		then
			for device in `reverse ${pkg}/.dev_del`
			do
				echo "Restoring device: ${device}"
				rstr_drvr ${ROOT}/etc/.btld_safe/${pkg}/driver/${device}
			done
		fi
	done

	echo "\nUnwinding complete."
}

################################################################################
#routine:	rstr_drvr(directory name)
#		cd ${directory name}
#		mv ${device components} ${link kit}
#		finish
################################################################################

rstr_drvr()
{
	dir=$1
	if [ ! -d "${dir}" ]
	then
		status=1
	else
		cd ${dir}
		DEV=`cat dev`
		if [ -f mdevice ]
		then
			mv mdevice ${ROOT}/etc/conf/cf.d/mdevice
		fi
		if [ -d pack.d ]
		then
			mkdir ${ROOT}/etc/conf/pack.d/$DEV
			mv pack.d/* ${ROOT}/etc/conf/pack.d/${DEV}
		fi
		for REC in  node.d sdevice.d init.d rc.d sd.d mfsys.d sfsys.d
		do
			if [ -f "${REC}" ]
				then mv $REC ${ROOT}/etc/conf/$REC/$DEV
			fi
		done
		status=0
	fi
	return ${status}
}

################################################################################
#main:		btldinstall
################################################################################

if [ ! "${ROOT}" ]
then
	ROOT="/."
fi

PATH=/bin:/usr/bin:/etc; export PATH
CONF=${ROOT}/etc/conf
PROGNAME=btldinstall

mntdir=${1}

# check args
if [ ! -d "${mntdir}" ]
then
	echo "usage: ${PROGNAME} <directory on which BTLD disk is mounted>"
	exit 1
fi

# perms list needed if link kit must be installed
if [ -f /etc/perms/extmd ]; then
	PERM=/etc/perms/extmd
else
	error "Cannot locate /etc/perms/extmd. This file
is needed to verify Link Kit installation."
	cleanup $FAIL
fi

# make sure the link kit is present and if not, ask the user to
# please install it
cd /
until	fixperm -i -d LINK $PERM
do	case $? in
	4)  echo "\nThe Link Kit is not installed." >&2	;;
	5)  echo "\nThe Link Kit is only partially installed." >&2  ;;
	*)  echo "\nError testing for Link Kit.  Exiting." >&2 
		cleanup $FAIL  ;;
	esac

	# Not fully installed. Do so here
	getyn "Do you wish to install it now?" || {
		# answered no
		echo "
The Link Kit must be installed to use your boot-time loadable driver.  Exiting ..."
		cleanup $OK
	}

	# answered yes, so install link kit
	echo "\nInvoking /etc/custom\n"
	/etc/custom -o -i LINK || {
		# custom exited unsuccessfully
		error "custom failed to install Link Kit successfully.  Please try again."
		cleanup $FAIL
	}
done

# get list of packages on disk
cd ${mntdir}

list=`ls -d *`
for file in ${list}
do
	if [ -d "${file}" -a -f "${file}/install/btld" ]
	then
		if [ ! "${pkglist}" ]
		then
			pkglist=${file}
		else
			pkglist="${pkglist}\n${file}"
		fi
	fi
done

pkglist=`echo ${pkglist} | awk '$1 != "install" && $1 != "lost+found" {print}'`
if [ ! "${pkglist}" ]
then
	echo "${PROGNAME}: There are no installable packages on this disk."
	exit
fi

# get BTLD'd packages
if [ -c /dev/string/pkg ]
then
	pkgstrg=`cat /dev/string/pkg`
	# generate default list for user
	pkgdflt=`echo ${pkglist} ${pkgstrg} | tr -cs "[A-Z][a-z][0-9]" "[\012*]" | sort | uniq -d`
fi

# ask which packages to install
thru=0
while [ "${thru}" = 0 ]
do
	echo "The following packages are on this disk:\n"
	echo "\tNAME\t\tDESCRIPTION"
	for pkg in ${pkglist}
	do
		echo "\t${pkg}\c"
		if [ -r "${mntdir}/${pkg}/install/${pkg}.name" ]
		then
			echo "\t\t`cat ${mntdir}/${pkg}/install/${pkg}.name`"
		else
			echo
		fi
	done
	echo "\nPlease enter the names of the packages you"
	echo "wish to install, or q to quit\c"
	if [ "${pkgdflt}" ]
	then
		echo "\n[default: \c"
		echo ${pkgdflt}]" : \c"
	else
		echo ": \c"
	fi
	read ans

	if [ ! "${ans}" ]
	then
		ans=${pkgdflt}
	fi

	if [ "${ans}" = "q" ]
	then
		exit
	elif [ "${ans}" ]
	then
		choicesOK=1
		for choice in ${ans}
		do
			gotit=0
			for pkg in ${pkglist}
			do
				if [ "${pkg}" = "${choice}" ]
				then
					gotit=1
					break
				fi
			done
			if [ "${gotit}" = 0 ]
			then
				choicesOK=0
				echo "\nSorry, package ${choice} is not \c"
				echo "on this disk.\n"
			fi
		done
		if [ "${choicesOK}" = 1 ]
		then
			thru=1
		fi
	else
		echo
	fi
done
pkginst=${ans}

# set up the safe directory
SAFEDIR=${ROOT}/etc/.btld_safe
SAFEPKG=${SAFEDIR}/.packages

rm -rf ${SAFEDIR} >/dev/null
mkdir ${SAFEDIR}

# clear the unwind file/directory used by idinstall
rm -rf ${ROOT}/etc/.last_dev_add ${ROOT}/etc/.last_dev_del

# set up the trap handler
trap "trap '' 1 2 3 15; unwind S; exit 1" 1 2 3 15

# install the selected packages
for pkg in ${pkginst}
do
	pkgpath=${mntdir}/${pkg}
	echo "\nInstalling ${pkg}.\n"
	if [ -x ${pkgpath}/install/copyright ]
	then
		/bin/sh ${pkgpath}/install/copyright
	fi

	if [ -f ${pkgpath}/install/preinstall ]
	then
		. ${pkgpath}/install/preinstall
	fi

	if [ ! -r ${pkgpath}/install/drivers ]
	then
		echo "${PROGNAME}: The file ${pkgpath}/install/drivers is\c"
		echo "missing."
		trap '' 1 2 3 15
		unwind E
		exit 1
	fi

	mvdevs=""
	okdrivers=""
	drivers=`cat ${pkgpath}/install/drivers`
	for driver in ${drivers}
	do
		device=`expr ${driver} : '.*/\(.*\)'`
		if [ ! -d "${mntdir}/${driver}" ]
		then
			echo "${PROGNAME}: The directory ${mntdir}${driver} \c"
			echo "is missing."
			trap '' 1 2 3 15
			unwind E
			exit 1
		fi

		cd ${mntdir}/${driver}
		${CONF}/bin/idcheck -p ${device} -i ${CONF}/cf.d >/dev/null
		if [ "$?" != 0 ]
		then
			ansOK=0
			while [ "${ansOK}" = 0 ]
			do
				echo "There is already a ${device} installed."
				echo "Do you want to replace it with \c"
				echo "the version in ${pkg}? (y/n/q) \c"
				read ans
				case "${ans}"
				in
					y | Y )	mvdevs="${mvdevs} ${device}"
						okdrivers="${okdrivers} ${driver}"
						ansOK=1;;
					n | N ) ansOK=1;;
					q | Q )	trap '' 1 2 3 15
						unwind Q
						exit;;
				esac
			done
		else
			okdrivers="${okdrivers} ${driver}"
		fi
	done

	# do the installation

	DEV_DEL=${SAFEDIR}/${pkg}/.dev_del
	DEV_ADD=${SAFEDIR}/${pkg}/.dev_add
	FILES=${SAFEDIR}/${pkg}/.files
	SAFEFILES=${SAFEDIR}/${pkg}/new

	mkdir ${SAFEDIR}/${pkg}
	mkdir ${SAFEDIR}/${pkg}/driver
	mkdir ${SAFEFILES}

	# note package that is being installed
	echo ${pkg} >> ${SAFEPKG}

	# remove any drivers that are to be replaced
	for device in ${mvdevs}
	do
		cd ${mntdir}/${driver}
		echo "Removing device: ${device}"
		${CONF}/bin/idinstall -d ${device} >/dev/null
		if [ "$?" != 0 ]
		then
			trap '' 1 2 3 15
			unwind E
			exit 1
		else
			# note device removed and preserve device files
			SAFEDEV=${SAFEDIR}/${pkg}/driver/${device}
			mkdir ${SAFEDEV}
			echo ${device} >> ${DEV_DEL}
			cd /etc/.last_dev_del
			find . -print | cpio -pdmu ${SAFEDEV} >/dev/null 2>&1
		fi
	done

	# install the drivers
	for driver in ${okdrivers}
	do
		device=`expr ${driver} : '.*/\(.*\)'`
		cd ${mntdir}/${driver}
		echo "Installing device: ${device}"
		${CONF}/bin/idinstall -a -k ${device} >/dev/null
		if [ "$?" != 0 ]
		then
			trap '' 1 2 3 15
			unwind E
			exit 1
		else
			#note device added
			echo ${device} >> ${DEV_ADD}
		fi
	done

	# copy files from /pkg/new
	if [ -d "${mntdir}/${pkg}/new" ]
	then
		if expr `ls -a ${mntdir}/${pkg}/new | wc -l` \> 2 >/dev/null
		then
			# preserve the (duplicated) files
			echo "\nPreserving the following files:"
			cd ${mntdir}/${pkg}/new
			for file in `find . -type f -print`
			do
				if [ -f "${ROOT}/${file}" ]
				then
					echo "${ROOT}/${file}"
					echo "${ROOT}/${file}" | \
					cpio -pudm ${SAFEFILES} 2>/dev/null
				fi
			done

			# install the files
			echo "\nInstalling the following files:"
			find . -depth -print | while read cur_dir; do
				[ -d $cur_dir -a -d /$cur_dir ] || echo $cur_dir
			done | cpio -pudlvm / 2>/dev/null
		fi
	fi

	# deal with special files
	if [ -f "${mntdir}/${pkg}/install/postinstall" ]
	then
		. ${mntdir}/${pkg}/install/postinstall
	fi

	if [ ! -d ${ROOT}/usr/options ]
	then
		mkdir ${ROOT}/usr/options
		chmod 755 ${ROOT}/usr/options
	fi

	if [ -f ${mntdir}/${pkg}/install/${pkg}.name ]
	then
		cat ${mntdir}/${pkg}/install/${pkg}.name > ${ROOT}/usr/options/${pkg}.name
		chmod 744 ${ROOT}/usr/options/${pkg}.name
	fi

	echo "\nInstalled ${pkg}.\n"
done

