:
#	@(#) shl.sh 22.1 90/01/09 
#
#	Copyright (C) The Santa Cruz Operation, 1986, 1989.
#	This Module contains Proprietary Information of
#	The Santa Cruz Operation and is Confidential.
#
# shl - UNIX 3.2 Shell Layers Initialization
#

PATH=/etc:/bin:/usr/bin
LANG=english_us.ascii
export PATH LANG

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

# Define driver dependents
name=sxt
funcs="sxtopen sxtclose sxtread sxtwrite sxtioctl"

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

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

# Define traps for critical and non critical code.
set_trap()  {	
	trap 'echo "\nInterrupted! 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 "$* (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. Needed to verify
 linkkit installation"
		cleanup $FAIL
	fi
}

# 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 "\nDo 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
}
 
# ---------- DEVICE ROUTINES ---------  These routines create and remove
#					devices.

# Create appropriate devices.  
# usage:  mkdevice name major# minor#
mkdevice() {
	[ -c /dev/sxt/$1 ] && return $OK
	mknod /dev/sxt/$1 c $2 $3 || {
		error "mknod failed to create /dev/sxt/$1."
		return $FAIL
	}
	chmod 622 /dev/sxt/$1
	return $OK
}

# Create new devices.
# Usage: add_devices <current_number> <desired_number>
add_devices()  {
	old_num=$1
	new_num=$2

	# initialize loop variables
	# level corresponds to the session number (1 session <-> level 0)
	# level starts at new_num (bigger number) and goes down to old_num
	# minor is the minor device number
	# count is the number of times through the inside loop (each inside 
	# loop is done 8 times, since there are always 8 session layers )
	level=`expr $new_num - 1`
	minor=`expr $level \* 8`
	count=0
	# keep creating devices until you get to the level which already
	# has devices.  since levels and numbers are off by one (levels start
	# at zero, whereas numbers start at 1), the case where level = num
	# is the final loop
	while	[ $level -ge $old_num ]
	do	while 	[ $count -lt 8 ]	# this loops through 8 (layers)
		do
			case ${level} in
			[0-9]) mkdevice 0${level}${count} $major $minor ;;
			*)   mkdevice ${level}${count} $major $minor	;;
			esac
			minor=`expr $minor + 1`
			count=`expr $count + 1`
		done
		count=0
		level=`expr $level - 1`
		minor=`expr $level \* 8`
	done
}

rm_devices()  {
	old_num=$1
	new_num=$2
	# level corresponds to the session number (1 session - level 0)
	# level starts at old_num (bigger number) and goes down to new_num
	level=`expr $old_num - 1`
	while	[ $level -ge $new_num ]
	do	rm -f /dev/sxt/0${level}*
		level=`expr $level - 1`
	done
}

# ---------- 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. 
# It returns OK only if driver is fully installed.
# 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.
# 	YES:  Device has a major number and the -Y option is set in  
#	      the sdevice file.
# Where variables are set:
# name: script start	
confchk () {
	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. 
# Where variables are set:
# name: script start	funcs: script start	cf_state: confchk()
# major: confchk() if cf_state=PART
confadd() {
	
	cd /etc/conf/cf.d
	case $cf_state in

	NO) 	echo "\nAdding device to system configuration files ...\c" >&2
		major=`./configure -j NEXTMAJOR`
		./configure -c -a $funcs -m $major -R > conflog ||  {
			conferr
			return $FAIL
		} ;;
	PART)   echo "\nUpdating system configuration ...\c" >&2
	        ./configure -a -c -m $major -Y -R > conflog ||  {
			conferr
			return $FAIL
		} ;;
	esac
	echo "\n\nSystem configuration files have been successfully modified."
	change=YES
	rm -f conflog
	return $OK
}

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

# change session number parameter via configure
# usage: confmod newnum
confmod() {
	echo "\nUpdating system configuration ...\c"
	cd /etc/conf/cf.d
	./configure NUMSXT=$1 > conflog 2>&1 || {
		conferr
		return $FAIL
	}
	rm -f conflog
	echo "\n\nSystem configuration files have been successfully modified."
	return $OK
}

# ---------- MAIN ROUTINES ---------- 	These routines execute the flow of 
#					events to complete the task 
#					corresponding to the main menu.

shladd()  {

	cd /etc/conf/cf.d
	# Check the state of the driver in system configuration files.
	confchk && {
 		getyn "
Driver is already present in system configuration files. 
Do you wish to relink the kernel ?" && {
			klink
			cleanup $OK
		}
		return
	}

	# Modify system configuration files to include driver.
	confadd || cleanup $FAIL

	# Create initial devices. 
	defnum=`./configure -y NUMSXT` 
	if [ -c /dev/sxt/* ] 
	then
		echo "\nVerifying device node information ...\c"
	else
		echo "\nCreating initial device nodes ...\c" 
	fi
	add_devices 0 $defnum
	echo

	echo "
Devices have been created to support $defnum shell layer sessions.
If you wish to change this value select option 3."
	change=YES
	return 
}

shlrm()  {
	confchk || {
		echo "
Shell layers modules are not currently linked to the kernel."
		return 
	}
	# Use configure to set flag in sdevice which prevents the
	# driver from being linked into the kernel.
	confrm || cleanup $FAIL

	getyn "
Would you like to remove the associated devices" && {
		echo "\nReducing associated devices ...\c"
		rm -f /dev/sxt/*
		echo
	}
	change=YES
}

shlmod()  {
	# Go to configuration directory and check to see how any 
	# sessions are set.
	confchk || {
		echo "
Shell layers modules are not currently linked to the kernel."
		return 
	}
	oldnum=`./configure -y NUMSXT` 

	getyn "
Your system parameters are currently configured for $oldnum session(s).
Do you wish to change this? " || return 

	mesg="How many shell layer sessions would you like?
	Select a number from 1 to 6 "

	while :
	do 	prompt || { 
			return $OK 
		}
		case $cmd in
		[1-6])	newnum=$cmd
			break					;;
		*)	error "$cmd is not valid. Try again." 	;;
		esac
	done

	[ $oldnum -eq $newnum ] && {
		echo "\nNumber of shell layer sessions unchanged."
		return 
	}

	# Change tunable kernel parameter NUMSXT.
	confmod $newnum || cleanup $FAIL

	if [ $oldnum -gt $newnum ]
	then	getyn "
Would you like to remove the associated device nodes" && {
			echo "\nReducing associated device nodes...\c"
			rm_devices $oldnum $newnum 
			echo
		}
	else	
		echo "\nAdding associated device nodes...\c"
		add_devices $oldnum $newnum 
		echo
	fi
	change=YES
	return
}

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

set_trap
cd /
permschk
linkchk
# Make sure the device directory exists
[ -d /dev/sxt ] || {
	mkdir /dev/sxt
	chgrp bin /dev/sxt
	chown bin /dev/sxt
	chmod 755 /dev/sxt
}

clearscr
while
    mesg="\n\n\nShell layers Initialization Program \n
	1. Add shell layers modules to the kernel.
	2. Remove shell layers modules from the kernel.
	3. Change the number of available shell layer sessions.
	
Select an option "
do
	prompt || break
  	case $cmd in
		1) shladd  ;;

		2) shlrm   ;;

		3) shlmod  ;;
	esac
done
	
if [ "$change" = "YES" ] 
then

	if [ "$_RELINK" -o "$_NOPROMPT" ]
	then
		klink
	else
		asklink && klink  
	fi
fi

cleanup $OK
