:
#	@(#) cdrom.sh 25.1 92/07/14 
#
#	Copyright (C) 1990-1992 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.
#
# 	mkdev/cdrom - CD-ROM and WORM Configuration
#
PATH=/etc:/bin:/usr/bin
LANG=english_us.ascii
export PATH LANG

# Set change to NO
change=NO
tmp=/tmp/cd.$$

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

# Function definitions
##########################

# ---------- STANDARD ROUTINES -------- These routines are common to scripts
#					requiring kernel relinking.

# Define traps for critical and non critical code.
set_trap()  {	
	trap 'echo "Interrupted! Exiting ..."; cleanup 1' 1 2 3 15
}
unset_trap()  {
	trap '' 1 2 3 15
}
 
# Remove temp files and exit with the status passed as argument
cleanup() {
	trap '' 1 2 3 15
	[ "$tmp" ] && rm -f $tmp*
	exit $1
}

# clear the screen if it is supported
clearscr() {
	# check if the terminal environment is set up
	[ "$TERM" ] && clear 2> /dev/null
}

# Prompt for yes or no answer - returns non-zero for no
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
}

# Prompt with mesg, return non-zero on q
prompt() {
	while	echo "\n${mesg}or enter q to ${quit}: \c" >&2
	do	read cmd
		case $cmd in
		+x|-x)	set $cmd					;;
		Q|q)	return $FAIL					;;
		!*)	eval `expr "$cmd" : "!\(.*\)"`			;;
		"")	# If there is an argument use it as the default
			# else loop until 'cmd' is set
			[ "$1" ] && { 
				cmd=$1
				return $OK
			}
			: continue
			;;
		*)	return $OK					;;
		esac
	done
}

# Print an error message
error() {
	echo "\nError: $*" >&2
	return $FAIL
}

# Configure error message
conferr()  {
	error "\nConfigure failed to update system configuration.
Check /etc/conf/cf.d/conflog for details."
}

# perms list needed if link kit must be installed
permschk () {
	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
	return $OK
}

# test to see if link kit is installed
linkchk()  {
	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 run this program.  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
}

asklink()  {
	getyn "
You must create a new kernel to effect the driver change you specified.
Do you wish to create a new kernel now?"  ||  {
		echo "
To create a new kernel execute /etc/conf/cf.d/link_unix. Then you
must reboot your system by executing  /etc/shutdown -i0  before the 
changes you have specified will be implemented.\n"
			return $FAIL 
		}
	return $OK
}

# re-link new kernel
klink() {
	cd /etc/conf/cf.d
	./link_unix || { 
		echo "\nError: Kernel link failed."
		cleanup $FAIL
	}
	return $OK
}
 
# ---------- CONFIGURE ROUTINES ------- These routines extract information 
#					from and modify kernel configuration
#					files and parameters.

# This routine sets cf_state and the device major number if applicable. 
# Possible values for cf_state are as follows. 
# 	NO: Device not present in mdevice file and therefore has
#	      no major number.
# 	PART: Device present in mdevice file but the -Y option in the configure
#      	      field of the sdevice file is not set. This causes the driver to 
#	      be excluded from the next reconfiguration.
# 	All:  Device has a major number and the -Y option is set in  
#	      the sdevice file.
confchk () {
	name=$1
	cf_state= 	major=
	cd /etc/conf/cf.d
	major=`./configure -j $name` || {
		cf_state=NO
		return $FAIL
	}
	cf_state=PART
	if [ -f ../sdevice.d/$name ] 
	then
		fieldval=`awk '{print $2}' ../sdevice.d/$name` || {
			error "awk failed to read sdevice file."
			cleanup $FAIL
		}
		[ "$fieldval" = "Y" ] && {
			cf_state=YES
			return $OK
		}
	else
		getyn "
This device has an entry in the master device file but no corresponding
system device entry. Do you wish to continue and have a default 
entry created?" || cleanup $FAIL
	fi
	return $FAIL
}

# Add driver according to cf_state. 
# Global variables used and where set:
# 	$fns: add routines; $cf_state: confchk(); 
#	$major: confchk() or add routine
confadd() {
	
	cd /etc/conf/cf.d
	case $cf_state in

	NO) 	echo "\nAdding device to system configuration files ...\c" >&2
		[ "$ipl" ] && IPL="-l $ipl"
		[ "$iv" ] && IV="-v $iv"
		./configure -a $fns $devchar -m $major $IPL $IV > conflog 2>&1 || {
			conferr
			return $FAIL
		}
		./configure -d $devchar -m $major -R > conflog 2>&1 || {
			conferr
			return $FAIL
		}
	        ./configure -a $devchar -m $major -Y > conflog ||  {
			conferr
			return $FAIL
		} ;;
	PART)   echo "\nUpdating system configuration ...\c" >&2
	        ./configure -a $devchar -m $major -Y > conflog ||  {
			conferr
			return $FAIL
		} ;;
	esac
	echo "\n\nSystem files have been successfully updated."
	change=YES
	rm -f conflog
	return $OK
}

# Configure driver out of system configuration files by unsetting -Y option.
# Global variables used and where set:
#	$major: confchk() 
confrm() {
	cd /etc/conf/cf.d
	echo "\nUpdating system files to effect removal of driver ...\c"
	./configure $devchar -d -m $major -Y > conflog 2>&1 || {
		conferr
		return $FAIL
	}
	echo "\n\nSystem files have been updated."
	rm -f conflog
	change=YES
	return $OK
}

# ------- Add Drivers -------- 	These routines add drivers to configuration
#				files and create necessary devices

# -------CD-ROM SPECIFIC ROUTINES ------- These routines are specific to the 
#					  CD-ROM driver
#					

# This program examines the mscsi file and finds out the number of
# SCSI cd-rom devices configured. SCSIpos is used to calculate minor
# device numbers for SCSI cd-roms.
# Global variables set: 
#	SCSIpos
find_SCSIpos() {
	[ -r /etc/conf/cf.d/mscsi ] || {
		error "\nCannot read /etc/conf/cf.d/mscsi."
		cleanup $FAIL
	}

	num=`sed '/^*/d' /etc/conf/cf.d/mscsi | grep -c "$DRIVER"` 
	[ -n "$num" ] || {
		error "\nGrep failed to read /etc/conf/cf.d/mscsi."
		cleanup $FAIL
	}

	# calculate total number of driver units configured
	# SCSI numbering starts at 0.
	SCSIpos=`expr $num - 1`
	return $OK
}

# Create all non-default devices. 
# Global variables used and where set:
# 	$SCSIpos: find_SCSIpos(); $MINIpos: find_MINIpos()
mk_nodes() {
	minor=`expr 0 + $SCSIpos` 
	echo "$DRIVER	$DEVNAME$minor	b	$minor"	>> /etc/conf/node.d/$DRIVER
	echo "$DRIVER	r$DEVNAME$minor	c	$minor"	>> /etc/conf/node.d/$DRIVER
}

rm_nodes() {
	minor=`expr 0 + $SCSIpos` 
	cp /etc/conf/node.d/$DRIVER /tmp/$DRIVER.$$
	grep -v $DEVNAME$minor /tmp/$DRIVER.$$ > /etc/conf/node.d/$DRIVER
	rm /tmp/$DRIVER.$$
	rm -f /dev/*$DEVNAME$SCSIpos 
}

# Create all non-default devices. 
# Global variables used and where set:
# 	$DRIVER, $DESCR: menu routines; $major: confchk() or confadd() 
# 	$SCSIpos: find_SCSIpos()
# Global variables set:
# 	dev_major, change
install () {
	# Check for the presence of the link kit. Install if it not present.
	permschk && linkchk

	# Configure the driver if necessary.
	confchk "$DRIVER"  || {
		# Add scsi driver to config files.
		fns=$FNS
		devchar=$DEVCHAR
		major=$MAJOR
		confadd || cleanup $FAIL
	}
	find_SCSIpos ; oSCSIpos=$SCSIpos
	[ $oSCSIpos -ge $MAXUNIT ] && {
		echo "
Sorry, the maximum of $MAXUNIT $NAME Drives has been reached. Unable to
configure another one."
		return $FAIL
	}
	getyn "The $NAME Driver must be configured before use. 
Do you wish to configure the $NAME Driver now?" || {
		echo "
The SCSI $NAME Driver has been added to system configuration files.
However, /etc/conf/cf.d/mscsi must also be updated before using
a SCSI $NAME Drive. It is advisable to reinvoke mkdev $MYNAME to 
accomplish this."
		return $FAIL
}
	# Make sure mscsi and node.d are in synch:
	# in particular, after installation there may be
	# cdt nodes and Srom in mscsi, but no Srom cd nodes:
	# remove Srom from mscsi so we can add successfully
	# (possibly with a different ID or whatever)
	#
	if	[ -s /etc/conf/node.d/$DRIVER ]
	then	[ $SCSIpos -ge 0 ] || rm -f /etc/conf/node.d/$DRIVER
	elif	[ $SCSIpos -ge 0 ]
	then	cp /etc/conf/cf.d/mscsi /tmp/$DRIVER.$$
		grep -v $DRIVER /tmp/$DRIVER.$$ > /etc/conf/cf.d/mscsi
		rm -f /tmp/$DRIVER.$$
		SCSIpos=-1; oSCSIpos=-1
	fi

	# Edit /etc/conf/cf.d/mscsi
	/bin/sh /usr/lib/mkdev/.scsi -a $DEVTYPE -n || return $FAIL

	while :
	do 	find_SCSIpos ; nSCSIpos=$SCSIpos
	 	differ=`expr $nSCSIpos - $oSCSIpos`
	 	case $differ in
	 	0) 	
			getyn "
The number of SCSI $NAME Drives has not been changed.
Do you wish to try again?" || return $FAIL
			;;
		*)
			[ $SCSIpos -lt $MAXUNIT ] && break;
			echo "
A maximum of $MAXUNIT SCSI $NAME Drives are allowed. Please reconfigure."
			;;
		esac
		echo "
Invoking the interface to the master SCSI device file."
		/bin/sh /usr/lib/mkdev/.scsi || return $FAIL
	done
	change=YES

	# Set dev_major for use in mkdevice(). 
	dev_major=$major

	SCSIpos=$oSCSIpos
	while [ $SCSIpos -lt $nSCSIpos ]
	do
		SCSIpos=`expr $SCSIpos + 1`
		# Create pure scsi devices.
		mk_nodes "$DRIVER"
	done

	if [ "$MYNAME" = "cdrom" ]
	then
		# first unit configured
		[ "$oSCSIpos" -eq -1 ]	&& {
			getyn "Do you want to configure a $CDTNAME installation device?" &&
			{
				cdtinstall || cleanup $FAIL
			}
		}
	fi

	# don't bother with the kernel linking with -l option
	getyn "Do you want to add/configure the $HSFILSYS file system?" && {
		/bin/sh /usr/lib/mkdev/$HSFILSYS -l
	}

	return $OK
}


# 	$DRIVER, $DESCR: menu routines; 
# 	$SCSIpos: find_SCSIpos() 
remove() {
	confchk "$DRIVER" || {
		echo "
The $NAME Driver is not currently configured.\n"
		return $FAIL
	}
	find_SCSIpos ; oSCSIpos=$SCSIpos
	if [ $oSCSIpos -lt 0 ] 
	then
		getyn "
There are currently no SCSI $NAME Drives configured in the /etc/conf/cf.d/mscsi
file. Do you wish to continue."	|| return $FAIL
		# Pretend we have 4 so we can remove any nodes created and
		# remove scsi driver from kernel.
		oSCSIpos=$MAXUNIT
	else
		# Edit /etc/conf/cf.d/mscsi
		/bin/sh /usr/lib/mkdev/.scsi -r $DEVTYPE -n || return $FAIL
	fi
	find_SCSIpos ; nSCSIpos=$SCSIpos
	differ=`expr $oSCSIpos - $nSCSIpos`
	case $differ in
 	0) 	
		echo "
The number of SCSI $NAME Drives has not been changed."
		return $FAIL
		;;
	esac
	change=YES

	SCSIpos=$oSCSIpos
	while [ $SCSIpos -gt $nSCSIpos ]
	do
		rm_nodes
		SCSIpos=`expr $SCSIpos - 1`
	done

	[ $SCSIpos -eq -1 ] && { 
		permschk && linkchk
		devchar=$DEVCHAR
		confrm || cleanup $FAIL
		echo "
The SCSI $NAME Driver and associated devices have been removed."
	}

	if [ "$MYNAME" = "cdrom" ]
	then
		[ $SCSIpos -eq -1 ] && { 
			cdtremove
		}
	
		confchk "$DRIVER"  && {
			echo "
$NAME device unit 0 (first $NAME device in /etc/conf/cf.d/mscsi) is
configured as the $CDTNAME installation device."
		}
	fi

	# don't bother with the kernel linking with -l option
	getyn "Do you want to remove the $HSFILSYS file system?" && {
		/bin/sh /usr/lib/mkdev/$HSFILSYS -l
	}

	return $OK
}

# -------CD-ROM/TAPE SPECIFIC ROUTINES ------- These routines are specific
#					       to the CD-ROM/TAPE driver
#					
cdtedit() {
	[ -r /etc/conf/pack.d/$CDTDRIVER/space.c ] || {
		error "\nCannot read /etc/conf/pack.d/$CDTDRIVER/space.c."
		cleanup $FAIL
	}

	ed - /etc/conf/pack.d/$CDTDRIVER/space.c <<-EOF
		/phydrv_name/s?= "[A-Za-z].*";?= "$DRIVER";?
		/cdt_unitnum/s?num = [0-9]*;?num = $unitnum;?
		w
		q
	EOF

}

cdtmk_nodes() {
	nodefile="/etc/conf/node.d/$CDTDRIVER"
	rm -f $nodefile
	> $nodefile
	minor=`expr 0 + $unitnum` 
	echo "$CDTDRIVER	r$CDTDRIVER$unitnum	c	$minor"	>> $nodefile
	minor=`expr 128 + $unitnum` 
	echo "$CDTDRIVER	x$CDTDRIVER$unitnum	c	$minor"	>> $nodefile
	minor=`expr 8 + $unitnum` 
	echo "$CDTDRIVER	nr$CDTDRIVER$unitnum	c	$minor"	>> $nodefile
}

cdtrm_nodes() {
	rm -f /etc/conf/node.d/$CDTDRIVER
	# since the author deleted all entries in node.d there
	# seems little point leaving any device files around.
	rm -f /dev/*cdt*
}

cdtinstall() {
	# Check for the presence of the link kit. Install if it not present.
	permschk && linkchk

	# Check for presence of CD-ROM driver. Fail if not present.
	confchk "$DRIVER"  || {
		echo "\nThe $NAME Driver is not configured currently.
It must be configured before the $CDTNAME Driver is used."
		return $FAIL
	}

	# Check for presence of CD-ROM device configured. Fail if not present.
	find_SCSIpos
	[ "$SCSIpos" -lt 0 ] && {
		echo "
The SCSI $NAME Driver has been added to system configuration files.
However, no $NAME devices are configured in /etc/conf/cf.d/mscsi.
Install the $NAME driver again to accomplish this."
		return $FAIL
	}

	echo "\nConfiguring $CDTDRIVER driver ..."

	# Configure the driver if necessary.
	confchk "$CDTDRIVER"  || {
		# Add scsi driver to config files.
		fns=$CDTFNS
		devchar=$CDTDEVCHAR
		major=$CDTMAJOR
		confadd || cleanup $FAIL
	}

	unitnum=0

	# edit /etc/conf/pack.d/$CDTDRIVER/space.c
	cdtedit		

	# Create driver devices.
	cdtmk_nodes 

	echo "
$NAME device unit 0 (first $NAME device in /etc/conf/cf.d/mscsi) is
configured as the $CDTNAME installation device."

	change=YES
	return $OK
}

cdtremove() {
	permschk && linkchk

	confchk "$CDTDRIVER" || {
		echo "
The $CDTNAME Driver is not currently configured.\n"
		return $FAIL
	}

	echo "\nRemoving $CDTDRIVER driver ..."
	devchar=$CDTDEVCHAR
	confrm || cleanup $FAIL
	cdtrm_nodes
	echo "
The $CDTNAME Driver and associated devices have been removed."
	return $OK
}

# main()
#########################

set_trap
cd /
clearscr
MYNAME=`basename $0`
HSFILSYS="high-sierra"
case $MYNAME in
	cdrom)
		# CD-ROM driver
		DRIVER=Srom
		NAME=CD-ROM
		DEVNAME=cd
		DEVTYPE=-c
		DEVCHAR="-b -c"
		MAJOR=51
		MAXUNIT=256
		FNS="Srominit Sromopen Sromclose Sromread Sromstrategy Sromioctl"
		# CD-ROM/TAPE driver
		CDTDRIVER=cdt
		CDTNAME=CD-ROM/TAPE
		CDTFNS="cdtopen cdtclose cdtread cdtioctl"
		CDTDEVCHAR="-c"
		CDTMAJOR=50

		# Configuration options
		MESG="\n\n$NAME Configuration Program \n
	1. Install a $NAME Drive
	2. Remove a $NAME Drive
	3. Install a $CDTNAME Driver
	4. Remove a $CDTNAME Driver

	Select an option "
		break
		;;
	worm)
		DRIVER=Swrm
		NAME=WORM
		DEVNAME=worm
		DEVTYPE=-w
		DEVCHAR="-b -c"
		MAXUNIT=8
		FNS="Swrminit Swrmopen Swrmclose Swrmread Swrmwrite Swrmstrategy Swrmioctl"
		MESG="\n\n$NAME Configuration Program \n
	1. Install a $NAME Drive
	2. Remove a $NAME Drive

	Select an option "
		break
		;;
	*)
		echo "configuration of `basename $0` not supported"
		exit $FAIL
esac

while	mesg=$MESG
	quit="quit"
do prompt || break
# reset these flags prior to each pass through menu
major=
IPL=
IV=
select=$cmd

if [ "$MYNAME" = "cdrom" ]
then
	case $select in
		1) install		;;
		2) remove		;;
		3) cdtinstall		;;
		4) cdtremove 		;;
		*) echo "\n	Please select 1, 2, 3 or 4."
		   continue		;;
	esac
else
	case $select in
	1) install		;;
	2) remove		;;
	*) echo "\n	Please select either 1 or 2."
	   continue		;;
	esac
fi
done

if [ "$change" = "YES" -a ! "$_RELINK" ] 
then
	asklink && klink  
fi

cleanup $OK
