:
#	@(#) ptty.sh 25.2 92/09/30 
#
#	Copyright (C) 1991-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/ptty - Pseudo-ttys Configuration
#

PATH=/etc:/bin:/usr/bin
export PATH 

# Set change to NO
change=NO
tmp=/tmp/pt$$

# Set driver variables

# Pseudo ttys ------------------------------------------------------------
MPTDRVR=mpt					# master driver name
SPTDRVR=spt					# slave driver name

PTYP=ptyp					# master /dev entry prefix
TTYP=ttyp					# slave /dev entry prefix

mpt_fns="${MPTDRVR}open ${MPTDRVR}close ${MPTDRVR}read ${MPTDRVR}write ${MPTDRVR}ioctl"
spt_fns="${SPTDRVR}open ${SPTDRVR}close ${SPTDRVR}read ${SPTDRVR}write ${SPTDRVR}ioctl"

# Pseudo mice ------------------------------------------------------------
MPMDRVR=mpm					# master driver name
SPMDRVR=spm					# slave driver name

PMP=pmp						# master /dev entry prefix
MP=mp						# slave /dev entry prefix

mpm_fns="${MPMDRVR}open ${MPMDRVR}close ${MPMDRVR}write"
spm_fns="${SPMDRVR}open ${SPMDRVR}close ${SPMDRVR}read ${SPMDRVR}ioctl"

# Event and event line descipline ----------------------------------------
EVDRVR=ev				# event driver name
EVLDDRVR=evld				# event line descipline driver name

EVENT=event					# event driver /dev entry prefix

ev_fns="${EVDRVR}init ${EVDRVR}open ${EVDRVR}close ${EVDRVR}read ${EVDRVR}ioctl"
evld_fns="${EVLDDRVR}open ${EVLDDRVR}close ${EVLDDRVR}read ${EVLDDRVR}ioctl ${EVLDDRVR}write"

# ------------------------------------------------------------------------

EVNTT=/usr/lib/event/ttys
EVNTD=/usr/lib/event/devices

abrt_add="\nPseudo tty(s) creation aborted after user's request"
abrt_rmv="\nPseudo tty(s) removing aborted after user's request"

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

# 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
	de_empty "/usr/lib/event/devices"
	[ "$tmp" ] && rm -f $tmp*
	exit $1
}

# Aborts process and exits with the status passed as first argument
# and print the message passed as second argument
abort () {
	abort_stat=$1
	shift
	echo $* >&2
	cleanup $abort_stat
}

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

# removes more than one consecutive lines from the
# file whose name is passed as an argument
de_empty () {
	awk -e		\
	"BEGIN	{ OFS=\"\"	}
	 \$0 == \"\"	{ 
				while ( (ret=(getline x)) > 0 && x == \"\");
				if (ret > 0)
					printf \"\\n%s\\n\", x
			}
	 \$0 != \"\"	{ print }"		\
	 			$1 > $tmp.awk || {
					error "awk failed to update $1 file"
				}
	
	mv_tmpfile "$tmp.awk" "$1" bin bin 644

}

# 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
}

# Prompt with mesg, return non-zero on q
# Called as:	getnumber <a message to prompt for the number>
getnumber() {
	while	echo "\n$*or enter q to quit: \c" >&2
	do	read a_num
		case $a_num in
		[1-9]*) [ 0 -lt `expr $a_num : '^[1-9][0-9]*$'` ] && 
			echo $a_num || {
				echo Please type a proper number >&2
				continue
					}
			 return
				;;
		    q|Q) echo $NEG
			 return
				;;
		     "") [ "$accpt_nl" = "yes" ] && echo 9999 && return
			 echo Please type a positive integer >&2
				;;
		      *) echo Please type a positive integer >&2
			 continue
				;;
		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."
}

# Move <file name$1> to <file name$2> and change the owner, group and rwx 
# flags of the new file according to the passed arguments.
# Called as:
#	mv_tmpfile <file from> <file to> <owner> <group> <rwx-flags>
mv_tmpfile () {
	rm -f $2
	mv $1 $2
	[ -n "$3" ] && chown $3 $2
	[ -n "$4" ] && chgrp $4 $2
	[ -n "$5" ] && chmod $5 $2
}

# Move <file name>.tmp to <file name> and change the owner, group and rwx 
# flags of the new file according to the passed arguments.
# Called as:
#	mv_tmpfile <file> <owner> <group> <rwx-flags>
#mv_tmpfile () {
#	rm -f $1
#	mv $1.tmp $1
#	[ -n "$2" ] && chown $2 $1
#	[ -n "$3" ] && chgrp $3 $1
#	[ -n "$4" ] && chmod $4 $1
#}

# 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.

# Main function to add the required nodes
# Called as:
#		addpsdttys <No of extra entries to be created in /dev>
addpsdttys () {
	# Check system configuration files.
	sconfigchk
	# Modify system configuration files.
	sconfigmod
	# Modify system configuration files creating extra entries
	# for the extended minor device numbers if necessary.
	sconfigxtr $1
	# Create the nodes for the pseudo ttys.
	psdndscrt $1
	# Update /usr/lib/events/ttys and /usr/lib/events/devices file.
	evntsupd $1 $mnum
	# Add any newly created ttys to the terminal control database
	/bin/grep "^TCBFILES=OFF" /etc/default/security >/dev/null 2>&1 ||
		/tcb/bin/ale /etc/auth/system/ttys pttyupd
}

# Check if in mdevice file exists entry for the two device drivers.
# This routine sets mpt_state, spt_state and the device major number 
# if applicable. 
# Possible values for mpt_state, spt_state, mpm_state and spm_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.
sconfigchk () {
	cd /etc/conf/cf.d

	# master pseudo tty ---------------------------------------
	val=
	mpt_state=NO
	mpt_maj=`./configure -j $MPTDRVR`	&&
		mpt_state=PART ||	{
		getyn "
Master pseudo tty driver entry does not exist in mdevice file.
Do you wish to continue and have a default entry created?"	|| 
		abort $FAIL $abrt_add
	}
	if [ -f ../sdevice.d/$MPTDRVR ]
		then
			val=`awk '{print $2}' ../sdevice.d/$MPTDRVR` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
		else
			getyn "
Master pseudo tty driver entry does not exist in sdevice file.
Do you wish to continue and have a default entry created?"	||
				abort $FAIL $abrt_add
		fi
		[ "$val" = "Y" ] && [ "$mpt_state" = "PART" ] && mpt_state=YES

	# slave pseudo tty ---------------------------------------
	val=
	spt_state=NO
	spt_maj=`./configure -j $SPTDRVR`	&&
		spt_state=PART ||	{
		getyn "
Slave pseudo tty driver entry does not exist in mdevice file.
Do you wish to continue and have a default entry created?"	||
		abort $FAIL $abrt_add
	}
	if [ -f ../sdevice.d/$SPTDRVR ]
		then
			val=`awk '{print $2}' ../sdevice.d/$SPTDRVR` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
		else
			getyn "
Slave pseudo tty driver entry does not exist in sdevice file.
Do you wish to continue and have a default entry created?"	||
			abort $FAIL $abrt_add
		fi
		[ "$val" = "Y" ] && [ "$spt_state" = "PART" ] && spt_state=YES

	# master pseudo mouse -------------------------------------
	val=
	mpm_state=NO
	mpm_maj=`./configure -j $MPMDRVR`	&& mpm_state=PART
	if [ -f ../sdevice.d/$MPMDRVR ]
		then
			val=`awk '{print $2}' ../sdevice.d/$MPMDRVR` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
		fi
		[ "$val" = "Y" ] && [ "$mpm_state" = "PART" ] && mpm_state=YES

	# slave pseudo mouse -------------------------------------
	val=
	spm_state=NO
	spm_maj=`./configure -j $SPMDRVR`	&& spm_state=PART
	if [ -f ../sdevice.d/$SPMDRVR ]
		then
			val=`awk '{print $2}' ../sdevice.d/$SPMDRVR` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
		fi
		[ "$val" = "Y" ] && [ "$spm_state" = "PART" ] && spm_state=YES

	# event driver --------------------------------------------
	val=
	ev_state=NO
	ev_maj=`./configure -j $EVDRVR`	&& ev_state=PART
	if [ -f ../sdevice.d/$EVDRVR ]
		then
			val=`awk '{print $2}' ../sdevice.d/$EVDRVR` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
		fi
		[ "$val" = "Y" ] && [ "$ev_state" = "PART" ] && ev_state=YES


}

# Adjust the mdevice and sdevice system files
sconfigmod () {
	# master pseudo tty -------------------------------------
	case $mpt_state in
	NO)	mpt_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $mpt_fns -P -m $mpt_maj > conflog &&
		./configure -c -d -H -R -m $mpt_maj >> conflog || {
			conferr
			cleanup $FAIL
		}	
		chmod 644 /etc/conf/sdevice.d/$MPTDRVR
			;;
	PART)	./configure -c -a -Y -P -m $mpt_maj > conflog	&&
		./configure -c -d -H -m $mpt_maj >> conflog || {
			conferr
			cleanup $FAIL
		}	;;
	YES)	./configure -c -a -P -m $mpt_maj > conflog || {
			conferr
			cleanup $FAIL
		}	;;
	esac

	# slave pseudo tty -------------------------------------
	case $spt_state in
	NO)	spt_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $spt_fns -m $spt_maj > conflog &&
		./configure -c -d -H -R -m $spt_maj >> conflog	&&
		conf_tflag $spt_maj "t" || {
			conferr
			cleanup $FAIL
		}	
		chmod 644 /etc/conf/sdevice.d/$SPTDRVR
			;;
	PART)	./configure -c -a -Y -m $spt_maj > conflog	&&
		./configure -c -d -H -m $spt_maj >> conflog	&&
		conf_tflag $spt_maj "t" ||	{
			conferr
			cleanup $FAIL
		}	;;
	YES)		;;
	esac

	# master pseudo mouse -----------------------------------
	case $mpm_state in
	NO)	mpm_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $mpm_fns -P -m $mpm_maj > conflog	&&
		./configure -c -d -H -R -m $mpm_maj >> conflog	|| {
			conferr
			cleanup $FAIL
		}	
		chmod 644 /etc/conf/sdevice.d/$MPMDRVR
			;;
	PART)	./configure -c -a -Y -P -m $mpm_maj > conflog	&&
		./configure -c -d -H -m $mpm_maj >> conflog	|| {
			conferr
			cleanup $FAIL
		}	;;
	YES)	./configure -c -a -P -m $mpm_maj > conflog	|| {
			conferr
			cleanup $FAIL
		}	;;
	esac

	# slave pseudo mouse -----------------------------------
	case $spm_state in
	NO)	spm_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $spm_fns -m $spm_maj > conflog	&&
		./configure -c -d -H -R -m $spm_maj >> conflog	&&
		conf_tflag $spm_maj "t" || {
			conferr
			cleanup $FAIL
		}	
		chmod 644 /etc/conf/sdevice.d/$SPMDRVR
			;;
	PART)	./configure -c -a -Y -m $spm_maj > conflog	&&
		./configure -c -d -H -m $spm_maj >> conflog	&&
		conf_tflag $spm_maj "t" ||	{
			conferr
			cleanup $FAIL
		}	;;
	YES)		;;
	esac

	# event driver ------------------------------------------
	case $ev_state in
	NO)	ev_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $ev_fns -R -M 1 1 -m $ev_maj > conflog &&
		./configure -c -d -R -H -m $ev_maj >> conflog &&
		conf_tflag $ev_maj "o" || {
			conferr
			cleanup $FAIL
		}	
		chmod 644 /etc/conf/sdevice.d/$EVDRVR
			;;
	PART)	./configure -a -c -m $ev_maj -Y -R > conflog	&&
		./configure -c -d -H -m $ev_maj >> conflog &&
		conf_tflag $ev_maj "o" || {
			conferr
			cleanup $FAIL
		}	;;
	YES)		;;
	esac

	# event line descipline driver --------------------------
	# Configure cannot add line disciplines. Must do it by hand. 
	cd /etc/conf/sdevice.d
	sed "s/N/Y/" evld > $tmp.ld || { 
		error "\nsed unable to edit /etc/conf/sdevice.d/evld."
		return $FAIL
	}
	unset_trap
	mv $tmp.ld evld
	set_trap
	change=yes
	cd /etc/conf/cf.d
	# -------------------------------------------------------

	[ -z "`fgrep keyboard /etc/conf/cf.d/sevent`" ] &&
		echo "keyboard" >> /etc/conf/cf.d/sevent

	[ -z "`fgrep pseudomouse /etc/conf/cf.d/sevent`" ] &&
		echo "pseudomouse" >> /etc/conf/cf.d/sevent

	last_tty $PTYP
	mnum=$tmplast	# The last /dev tty master entry number is assigned

	last_tty $TTYP
	snum=$tmplast	# The last /dev tty slave entry number is assigned

	[ "$mnum" -ne "$snum" ] && {
		error "Master and Slave ttys in /etc/conf/node.d not equal"
		cleanup $FAIL
	}

	last_tty $PMP
	mmcnum=$tmplast	# The last /dev mouse master entry number is assigned

	last_tty $MP
	smcnum=$tmplast	# The last /dev mouse slave entry number is assigned

	[ "$mmcnum" -ne "$smcnum" ] && {
		error "Master and Slave mice in /etc/conf/node.d not equal"
		cleanup $FAIL
	}
}

# If extra entries are necessary to accommodate devices with
# extended minor device number then this functions creates them
# by calling sconfigxtr_mdev() for the four different devices required.
# Called as:	sconfigxtr <No of devices asked to be created>
sconfigxtr () {
	sconfigxtr_mdev $1 1
	sconfigxtr_mdev $1 2
	sconfigxtr_mdev $1 3
	sconfigxtr_mdev $1 4
}

# If extra entries are necessary to accommodate devices with
# extended minor device number then this functions creates them.
# This functions is doing this job by being called separately for 
# the master and slave ttys and mice drivers.
# Called as:	sconfigxtr <No of devices asked to be created> <1,2,3, or 4>
sconfigxtr_mdev () {
	case "$2" in
		1) dev_name=$MPTDRVR
		   dev_num=$mnum
		   dev_flg2="ocrwi"
		   dev_flg3="icIM"
		   dev_maj=$mpt_maj
				;;
		2) dev_name=$SPTDRVR
		   dev_num=$snum
		   dev_flg2="ocrwi"
		   dev_flg3="ictM"
		   dev_maj=$spt_maj
				;;
		3) dev_name=$MPMDRVR
		   dev_num=$mnum
		   dev_flg2="ocw"
		   dev_flg3="icIM"
		   dev_maj=$mpm_maj
				;;
		4) dev_name=$SPMDRVR
		   dev_num=$snum
		   dev_flg2="ocri"
		   dev_flg3="ictM"
		   dev_maj=$spm_maj
				;;
	esac

	last_mdev $dev_name

	entr_exs=$cntd_entr
		# mdevice entries existing so far
	entr_req=`expr \( $dev_num + $1 \) / 256 + 1`
		# mdevice entries to exist after the creation of the extra nodes
	entr_xtr=`expr $entr_req - $entr_exs`
		# mdevice entries to be added in mdevice after 
		# the creation of the extra nodes

	if [ "$entr_xtr" -gt 0 ]
	 then
		i=0
		while [ "$i" -lt "$entr_xtr" ]
		do
			next_maj=`./configure -j NEXTMAJOR`
			off_set=`expr \( $entr_exs + $i \) \* 256`
			entry="$dev_name\t$dev_flg2\t$dev_flg3\t$dev_name\t0\t$next_maj\t$dev_maj\t$off_set\t-1"
			echo $entry >> /etc/conf/cf.d/mdevice
			i=`expr $i + 1`
		done
	 fi
}

# It returns the number of entries in the mdevice file with first field
# equal to the string passed as first argument.
last_mdev () {
	cntd_entr=0

	cntd_entr=`awk -e		\
	'BEGIN	{ entries = 0 }
	 \$1 == "'"$1"'"	{ entries ++ }
	 END	{ print entries }'	mdevice`

	 return 
}

# Sets the passed-flag of the third field in mdevice file
# Called as conf_tflag <major number> <flag to be set(o/t)>
conf_tflag () {
	awk -e		\
	"BEGIN	{ OFS=\"\t\"	}
	 \$6 == $1 	{
				i = index(\$3,\"$2\")
				if (i == 0)
					\$3 = sprintf(\"%s%s\",\$3,\"$2\")
				print
			}
	 \$6 != $1	{	print	}" mdevice > $tmp.mdv || {
		error "awk cannot set $2- flag in mdevice file"
		cleanup $FAIL
	}
	mv_tmpfile "$tmp.mdv" mdevice root other 644
	return $OK
}

# Returns the numerical suffix of the last alphabetically tty entry 
# in the /etc/conf/node.d directory.
# If no entries exist then $NEG is returned.
# The prefix of the tty node is passed as the argument
# Function is called as
#		last_tty <prefix of the nodes to be searched>
last_tty () {
	tmplast=$NEG
	case $1 in
	$PTYP) search_file=/etc/conf/node.d/$MPTDRVR
			tmp_re="^$PTYP"
			;;
	$TTYP) search_file=/etc/conf/node.d/$SPTDRVR
			tmp_re="^$TTYP"
			;;
	 $PMP) search_file=/etc/conf/node.d/$MPMDRVR
			tmp_re="^mouse\\/$PMP"
			;;
	  $MP) search_file=/etc/conf/node.d/$SPMDRVR
			tmp_re="^mouse\\/$MP"
			;;
	   *) error "Entry is asked for not supported pseudo ttys\n"
		  cleanup $FAIL
			;;
	esac

	[ -f "$search_file" ]	&&
	tmplast=`awk -e		\
	'BEGIN		{ last_='"$NEG"' }
	 $2 ~ /'"$tmp_re"'[0-9]+$/	{
				if (last_ < $4)
					last_ = $4
			}
	 END		{ print last_ }' $search_file`

	 return
}

# Creating the entries in /dev directory
# Function gets called as:
# 			psdndscrt <Num of nodes to be created>
psdndscrt () {
	addtune_chk `expr $mnum + 1 + $1` $1

	i="$1"
	tmpmnum="$mnum"
	while [ "$i" -ne 0 ]
	do
		tmpmnum=`expr $tmpmnum + 1`
		mk_nodes $tmpmnum
		i=`expr $i - 1`
	done
	mk_event
	nodes_mode
}

# It creates the entries in /etc/conf/node.d/$MPTDRVR and
#                           /etc/conf/node.d/$SPTDRVR files.
# Called as: 
#	mk_nodes <No to be appended to $TTYP and $PTYP to form the node name>
mk_nodes () {
	echo "$MPTDRVR	$PTYP$1	c	$1" >> /etc/conf/node.d/$MPTDRVR
	echo "$SPTDRVR	$TTYP$1	c	$1" >> /etc/conf/node.d/$SPTDRVR
	if [ "$1" -gt "$mmcnum" ]
	 then
	echo "$MPMDRVR	mouse/$PMP$1	c	$1" >> /etc/conf/node.d/$MPMDRVR
	echo "$SPMDRVR	mouse/$MP$1	c	$1" >> /etc/conf/node.d/$SPMDRVR
	 fi
}

# It creates the entries in /etc/conf/node.d/$EVDRVR file.
mk_event () {
	echo "$EVDRVR	$EVENT	c	0" > /etc/conf/node.d/$EVDRVR
	echo "$EVDRVR	ev_mrg	c	255" >> /etc/conf/node.d/$EVDRVR
}

# Sets the mode for the node.d master and slave files to rw-r--r--
nodes_mode () {
	chmod 644 /etc/conf/node.d/$MPTDRVR
	chgrp other /etc/conf/node.d/$MPTDRVR
	chmod 644 /etc/conf/node.d/$SPTDRVR
	chgrp other /etc/conf/node.d/$SPTDRVR
	chmod 644 /etc/conf/node.d/$MPMDRVR
	chgrp other /etc/conf/node.d/$MPMDRVR
	chmod 644 /etc/conf/node.d/$SPMDRVR
	chgrp other /etc/conf/node.d/$SPMDRVR
	chmod 644 /etc/conf/node.d/$EVDRVR
	chgrp other /etc/conf/node.d/$EVDRVR
}


# Called as: 
# 	addtune_chk <No of total entries in /dev if the new entries get created>
#				<No of extra entries to be created>
# It also sets the change global variable to YES
# so that later on relink of the kernel to be required
addtune_chk () {
	stun_ln=`awk '$1 == param {print; exit}' param=NSPTTYS stune`
	if [ -n "$stun_ln" ]
	  then
		stun_val=`echo $stun_ln | awk '{print $2}'`
	  else
		stun_val=`./configure -y NSPTTYS`
	  fi
	
	if [ "$1" -gt "$stun_val" ]
	  then
		mtun_ln=`awk '$1 == param {print; exit}' param=NSPTTYS mtune`
		[ -z "$mtun_ln" ] && {
			error "NSPTTYS not found in mtune file"
			cleanup $FAIL
		}
		mtun_val=`echo $mtun_ln | awk '{print $4}'`
		[ "$1" -gt "$mtun_val" ] && {
			getyn "
Number of pseudo ttys to be created is greater than the currently allowed value
Do you want to change the current limit? " || abort $FAIL $abrt_add
			mtun_max $1 NSPTTYS
		}
		change=YES
		/etc/conf/bin/idtune -f NSPTTYS $1
	  fi

	# EVQUEUES update -------------------------------------
	stun_ln=`awk '$1 == param {print; exit}' param=EVQUEUES stune`
	if [ -n "$stun_ln" ]
	  then
		stun_val=`echo $stun_ln | awk '{print $2}'`
	  else
		stun_val=`./configure -y EVQUEUES`
	  fi
	stun_val=`expr $stun_val + $2`
	mtun_ln=`awk '$1 == param {print; exit}' param=EVQUEUES mtune`
	[ -z "$mtun_ln" ] && {
		error "EVQUEUES not found in mtune file"
		cleanup $FAIL
	}
	mtun_val=`echo $mtun_ln | awk '{print $4}'`
	[ "$stun_val" -gt "$mtun_val" ] && mtun_max $stun_val EVQUEUES
	change=YES
	/etc/conf/bin/idtune -f EVQUEUES $stun_val
	
	# EVDEVS update ---------------------------------------
	stun_ln=`awk '$1 == param {print; exit}' param=EVDEVS stune`
	if [ -n "$stun_ln" ]
	  then
		stun_val=`echo $stun_ln | awk '{print $2}'`
	  else
		stun_val=`./configure -y EVDEVS`
	  fi
	stun_val=`expr $stun_val + $2`
	mtun_ln=`awk '$1 == param {print; exit}' param=EVDEVS mtune`
	[ -z "$mtun_ln" ] && {
		error "EVDEVS not found in mtune file"
		cleanup $FAIL
	}
	mtun_val=`echo $mtun_ln | awk '{print $4}'`
	[ "$stun_val" -gt "$mtun_val" ] && mtun_max $stun_val EVDEVS
	change=YES
	/etc/conf/bin/idtune -f EVDEVS $stun_val
	
	return $OK
}

# Change the value of the fourth field in mtune file for the $2 entry.
# Called as:
#		mtun_max <New fourth field value> <System param name>
mtun_max () {
	awk -e			\
	"BEGIN	{ OFS=\"\t\"	}
	 \$1 == \"$2\"	{	\$4=$1
				print	}
	 \$1 != \"$2\"	{	print	}"	mtune > $tmp.mtn || {
		error "awk failed to update mtune file"
		cleanup $FAIL
	}
	mv_tmpfile "$tmp.mtn" mtune root sys 644
}

# Update /usr/lib/events/ttys file
# Called as:
#	evntsupd <No of extra entries to be created> <Last existing entry>
evntsupd () {
	# /usr/lib/event/ttys update -----------------------------------------
	awk -e		\
	"BEGIN		{ IFS=\"\"
			  limit = $2 + $1
			  for(i=$2+1;i<=limit;i++)
				mice_num[i] = 1
			}
	 \$0 ~ 	/$TTYP/	{
				if ( match(\$0,/$TTYP[0-9][0-9]*/) ) {
					l = length(\"$TTYP\")
					minor = substr(\$0,RSTART+l,RLENGTH-l)
					mice_num[minor] = 1
				}
				else
					print
			}
	 \$0 !~	/$TTYP/	{	print	}
	 END		{
				for (i=0;i<=999;i++)
					if (mice_num[i] == 1) {
						minor = i
		printf \"%s%d\\t%s%d\\n\", \"$TTYP\", minor, \"_pmouse\", minor
			  		}
			}"	$EVNTT	> $tmp.evt || {
					error "awk failed to update $EVNTT file"
					cleanup $FAIL
					}
	mv_tmpfile "$tmp.evt" "$EVNTT" bin bin 644

	# /usr/lib/event/devices update --------------------------------------
	dvms="/dev/mouse/"
	awk -e		\
	"BEGIN		{	IFS=\"\"
				limit = $2 + $1
				for(i=$2+1;i<=limit;i++)
					mice_num[i] = 1
			}
	 \$0 ~  /. SCO Pseudo Mouse\$/	{
				getline x
				if ( match(x,/_pmouse[0-9][0-9]*/) ) {
					minor = substr(x,RSTART+7,RLENGTH-7)
					mice_num[minor] = 1
				}
				else
			  		if ( match(x,/_pmouse[a-z][a-z]*/) ) {
					    minor = substr(x,RSTART+7,RLENGTH-7)
					    mice_let[minor] = 1
					}
				}
	 \$0 !~  /. Pseudo Mouse\$/ { print	}
	 END		{
		for (i=0;i<=999;i++)
			if (mice_num[i] == 1) {
				printf \"\\n%s\\n\", \"# SCO Pseudo Mouse\"
				minor = i
	printf \"%s%d %s%s%d \", \"_pmouse\", minor, \"$dvms\", \"$MP\", minor
	printf \"%s\\n\", \"RELb pseudomouse NAME=\\\"Pseudo Mouse\\\"\"
	  		}

		for (i in mice_let)
			if (mice_let[i] == 1) {
				printf \"\\n%s\\n\", \"# SCO Pseudo Mouse\"
				minor = i
	printf \"%s%s %s%s%s \", \"_pmouse\", minor, \"$dvms\", \"$MP\", minor
	printf \"%s\\n\", \"RELb pseudomouse NAME=\\\"Pseudo Mouse\\\"\"
	  		}

			}"	$EVNTD	> $tmp.evd || {
					error "awk failed to update $EVNTD file"
					cleanup $FAIL
				}
	mv_tmpfile "$tmp.evd" "$EVNTD" bin bin 644
}

# Main function to remove the required nodes
# Called as:
#		rmvpsdttys <No of entries to be removed from /dev>
rmvpsdttys () {
	# Check the number of remaining nodes in /dev and modify
	# system configuration files if necessary
	numndschk $1 && rmvdrvr

	# Remove $1 nodes of pseudo ttys starting from <tty>$mnum
	psdndsrmv $1 $mnum

	if [ "$can_rmved" -gt 0 ]
	 then
		# Remove $can_rmved entries from /usr/lib/event/ttys file
		# starting from <tty>$mnum
		# $can_rmved contains the no of entries that is possible 
		# to be deleted
		evnttrmv $can_rmved $mnum

		# Remove $can_rmved entries from /usr/lib/event/devices file
		# starting from <_pmouse>$mnum
		# $can_rmved contains the no of entries that is possible 
		# to be deleted
		evntdrmv $can_rmved $mnum
	 fi
}

# Checks if the number of pseudo ttys requested to be removed is
# greater than the number of the currently existing ones in the /dev
# Returns $OK if the sdevice files Y/N flag is to change and $FAIL otherwise.
# Called as:
#		numndschk <No of nodes requested to be removed>
numndschk () {
	cd /etc/conf/cf.d

	mpt_maj=`./configure -j $MPTDRVR`	||	{
		error "Master pseudo tty driver entry not in mdevice file"
		cleanup $FAIL
	}

	spt_maj=`./configure -j $SPTDRVR`	||	{
		error "Slave pseudo tty driver entry not in mdevice file"
		cleanup $FAIL
	}

	mpm_maj=`./configure -j $MPMDRVR`	||	{
		error "Master pseudo mouse driver entry not in mdevice file"
		cleanup $FAIL
	}

	spm_maj=`./configure -j $SPMDRVR`	||	{
		error "Master pseudo mouse driver entry not in mdevice file"
		cleanup $FAIL
	}

	last_tty $PTYP
	mnum=$tmplast

	last_tty $TTYP
	snum=$tmplast

	[ $mnum -ne $snum ] && {
		error "Master and Slave tty counts in /dev are not equal"
		cleanup $FAIL
	}

	a=`expr $mnum + 1`
	numtogo=$1
	[ $numtogo -eq 9999 ] && numtogo=$a
	if [ "$numtogo" -ge "$a" ]
	  then
		[ "$numtogo" -eq "$a" ] && ex_onl="exactly" || ex_onl="only"
		getyn "There are $ex_onl $a entries in /dev
Do you want to proceed?" || abort $FAIL $abrt_rmv
		getyn "Do you want to remove the driver?" &&
		return $OK								# Driver should be set to N
	  fi
	return $FAIL								# Driver should not be affected
}

# find the number of pseudo ttys configured in the system.
# Called as:
#		numndschk <No of nodes requested to be removed>
pttyno () {
	cd /etc/conf/cf.d

	mpt_maj=`./configure -j $MPTDRVR`	||	{
		error "Master pseudo tty driver entry not in mdevice file"
		cleanup $FAIL
	}

	spt_maj=`./configure -j $SPTDRVR`	||	{
		error "Slave pseudo tty driver entry not in mdevice file"
		cleanup $FAIL
	}

	mpm_maj=`./configure -j $MPMDRVR`	||	{
		error "Master pseudo mouse driver entry not in mdevice file"
		cleanup $FAIL
	}

	spm_maj=`./configure -j $SPMDRVR`	||	{
		error "Master pseudo mouse driver entry not in mdevice file"
		cleanup $FAIL
	}

	last_tty $PTYP
	mnum=$tmplast

	last_tty $TTYP
	snum=$tmplast

	a=`expr $mnum + 1`
	if [ $mnum -ne $snum ] 
	then {
		error "Master and Slave tty counts in /dev are not equal"
		cleanup $FAIL
	}
	else
		echo "\n`expr $mnum + 1` pseudo ttys are currently configured in the system"
	fi
}

# It sets the driver second field in sdevice files to N
# Called as:	rmvdrvr
rmvdrvr () {
	./configure -d -c -Y -m $mpt_maj > conflog	||	conferr
	rmvdrvr_mul $MPTDRVR $mpt_maj

	./configure -d -c -Y -m $spt_maj >> conflog	||	conferr
	rmvdrvr_mul $SPTDRVR $spt_maj

	./configure -d -c -Y -m $mpm_maj >> conflog	||	conferr
	rmvdrvr_mul $MPMDRVR $mpm_maj

	./configure -d -c -Y -m $spm_maj >> conflog	||	conferr
	rmvdrvr_mul $SPMDRVR $spm_maj

	sed -e '/pseudomouse/d' /etc/conf/cf.d/sevent > $tmp.sev
	mv_tmpfile "$tmp.sev" "/etc/conf/cf.d/sevent" root sys 644

	change=YES
}

# It removes the mdevice entries corresponding to extended minor device
# numbered devices. It does not touch the entry with the base major number.
# Called as:	rmvdrvr_mul	<driver name> <base major no>
rmvdrvr_mul () {
	awk '$1 == dvr {print $6}' dvr=$1 mdevice | \
	while read tmp_majno
	do
		[ "$tmp_majno" -ne "$2" ] && {
			./configure -d -c -Z -m $tmp_majno >> conflog || conferr 
		}
	done
}

# Remove $1 nodes of pseudo ttys starting from <tty>$mnum
# and going backwards in the alphabetical order.
# It stores in $can_rmved the number of entries that can be removed.
# Called as:
#	psdndsrmv <No of nodes to be removed> <Minor no of node to start from>
psdndsrmv () {
	left=`expr $2 + 1 - $1`
	if [ "$left" -lt 0 ]
	  then
		left=0
		i=`expr $2 + 1`
	  else
		left=`expr $2 + 1 - $1`
		i="$1"
	  fi

	can_rmved=$i && [ "$can_rmved" -le 0 ] && return

	rmvtune_nsp $left $i
	rmvtune_evq_evd $left $i EVQUEUES
	rmvtune_evq_evd $left $i EVDEVS

	# If we're removing all the nodes, just delete the files
	if [ $left -eq 0 ]
	then
		rm -f /etc/conf/node.d/$MPTDRVR
		rm -f /etc/conf/node.d/$SPTDRVR
		rm -f /etc/conf/node.d/$MPMDRVR
		rm -f /etc/conf/node.d/$SPMDRVR
	else # Edit the node.d files
		rm_nodes 1 `expr $2 - $i + 1` $2
		rm_nodes 2 `expr $2 - $i + 1` $2
		rm_nodes 3 `expr $2 - $i + 1` $2
		rm_nodes 4 `expr $2 - $i + 1` $2
	fi
	rm_devs `expr $2 - $i + 1` $2
}

# Removes the pseudo tty and mouse entries from files 
#			/etc/conf/node.d/$MPTDRVR,
#                        /etc/conf/node.d/$SPTDRVR,
#                        /etc/conf/node.d/$MPMDRVR and
#                        /etc/conf/node.d/$SPMDRVR
# for the entries with minor device no in the passed interval.
# Called as:
#		rm_nodes <1,2,3 or 4> <low limit> <upper limit> 
# of the nodes to be removed (the limits are inclusive)
rm_nodes () {
	case $1 in
		1)	tmp_re="^$PTYP"
			tmp_drv="$MPTDRVR"
			tmp_nd="$PTYP"
			;;
		2)	tmp_re="^$TTYP"
			tmp_drv="$SPTDRVR"
			tmp_nd="$TTYP"
			;;
		3)	tmp_re="^mouse\\/$PMP"
			tmp_drv="$MPMDRVR"
			tmp_nd="mouse/$PMP"
			;;
		4)	tmp_re="^mouse\\/$MP"
			tmp_drv="$SPMDRVR"
			tmp_nd="mouse/$MP"
			;;
		esac
	
	awk -e		\
	"BEGIN	{ OFS=\"\t\"	}
	 \$2 ~	/$tmp_re/	{ 
			l = length(\$2)
			if ( match(\$2,/$tmp_re/) ) {
				minor = substr(\$2,RSTART+RLENGTH,l-RLENGTH)
				minor = minor + 0
				if (minor<$2 || minor>$3)
					print
			  }
		}
	 \$2 !~	/$tmp_re/	{	print	}"		\
	 /etc/conf/node.d/$tmp_drv > $tmp.$tmp_drv || {
		error "awk failed to update /etc/conf/node.d/$tmp_drv file"
		cleanup $FAIL
	}
	
	mv_tmpfile "$tmp.$tmp_drv" "/etc/conf/node.d/$tmp_drv" root other 644
}

# Removes the pseudo tty and mouse entries from /dev.
# for the entries with minor device no in the passed interval.
# Called as:
#		rm_devs  <low limit> <upper limit> 
# of the nodes to be removed (the limits are inclusive)
rm_devs () {
	awk "BEGIN	{
		for ( i=$1 ; i<=$2 ; i++ )
printf \"/dev/$PTYP%d /dev/$TTYP%d /dev/mouse/$PMP%d /dev/mouse/$MP%d\\n\",
				i, i, i, i }"  |  xargs rm -f
}

# Checks the NSPTTYS value in connection with the new count of the remaining
# ttys.
# Called as:	rmvtune_nsp <Count of remaining pseudo ttys> 
#			    <Count of nodes that can be removed>
rmvtune_nsp () {
	mtun_val=`awk '$1 == param {print $2; exit}' param=NSPTTYS mtune`
	if [ "$1" -le "$mtun_val" ]
	 then
		sed -e	"/^NSPTTYS/d"	stune > $tmp.stn    # remove stune entry
		mv_tmpfile "$tmp.stn" stune root sys 644
		mtun_max `expr 2 \* $mtun_val` NSPTTYS 
	 else
		mtun_max NSPTTYS "$1"
		/etc/conf/bin/idtune -f NSPTTYS $1
	 fi
	change=YES
}

# Checks the $3 value in connection with the new count of the remaining
# ttys.
# Called as:	rmvtune_evq <Count of remaining pseudo ttys> 
#			    <Count of nodes that can be removed>
#			    <Name of system parameter to change>
rmvtune_evq_evd () {
	stun_ln=`awk '$1 == param {print; exit}' param=$3 stune`
	[ -z "$stun_ln" ] && return
	stun_val=`echo $stun_ln | awk '{print $2}'`
	stun_val=`expr $stun_val - $2`

	mtun_ln=`awk '$1 == param {print; exit}' param=$3 mtune`
	[ -z "$mtun_ln" ] && {
		error "$3 not found in mtune file"
		cleanup $FAIL
	}
	mtun_val=`echo $mtun_ln | awk '{print $2}'`

	if [ "$stun_val" -gt "$mtun_val" ]
	 then
		mtun_max "$3" "$stun_val"
		/etc/conf/bin/idtune -f $3 $stun_val
	 else
		sed -e	"/^$3/d"	stune > $tmp.stn    # remove stune entry
		mv_tmpfile "$tmp.stn" stune root sys 644
		mtun_max `expr 2 \* $mtun_val` "$3"
	 fi

	change=YES
}

# Remove entries from /usr/lib/event/ttys file
# Called as:
#	evnttrmv <No of actual entries to be removed> <Last existing entry>
evnttrmv () {
	ftogolow=`expr $2 - $1 + 1`	# Alphabetically first entry to go
	ftogoup=$2			# Alphabetically last entry to go
	awk -e		\
	"BEGIN		{	IFS=\"\" }
	 \$0 ~	/$TTYP/	{ 
				  l = length(\"$TTYP\")
				  if ( match(\$0,/$TTYP[0-9][0-9]*/) ) {
					minor = substr(\$0,RSTART+l,RLENGTH-l)
					minor = minor + 0
				  	if (minor<$ftogolow || minor>$ftogoup)
						print
				  } else
					print
			}
	 \$0 !~	/$TTYP/	{	print	}"	$EVNTT	> $tmp.evt || {
		error "awk failed to update /usr/lib/event/ttys file"
		cleanup $FAIL
	}
	mv_tmpfile "$tmp.evt" "$EVNTT" bin bin 644
}

# Remove entries from /usr/lib/event/devices file
# Called as:
#	evntdrmv <No of actual entries to be removed> <Last existing entry>
evntdrmv () {
	ftogolow=`expr $2 - $1 + 1`	# Alphabetically first entry to go
	ftogoup=$2			# Alphabetically last entry to go
	awk -e		\
	"BEGIN		{ IFS=\"\" }
	 \$0 ~  /^. SCO Pseudo Mouse\$/	{ 
				sco_lin = \$0
				getline x
				if ( match(x,/^_pmouse[0-9][0-9]*/) ) {
					minor = substr(x,8,RLENGTH-7)
					minor = minor + 0
					if (minor<$ftogolow || minor>$ftogoup) {
						print sco_lin
						print x
					}
				}
				else
				{
					print sco_lin
					print x
				}
			}
	 \$0 !~ /^. SCO Pseudo Mouse\$/	{	
				print	}"	$EVNTD	> $tmp.evd || {
		error "awk failed to update /usr/lib/event/devices file"
		cleanup $FAIL
	}
	mv_tmpfile "$tmp.evd" "$EVNTD" bin bin 644
}

# Add any newly created BSD-style links to the device assignment database
upddevasg () {
	/bin/grep "^TCBFILES=OFF" /etc/default/security >/dev/null 2>&1 ||
		/tcb/bin/ale /etc/auth/system/devassign pttyxnodes
}

# Create BSD format device node names linked to the exisitng pseudo-tty
# device nodes for use by old versions of Xterm and Scoterm, and links
# them to the appropriate pseudo-mice.
#
makexnodes () {
	node=0
	for i in p q r s t u v w x y z
	do
		for j in 0 1 2 3 4 5 6 7 8 9 a b c d e f
		do
			[ -c /dev/ptyp$node ] || {
				upddevasg
				echo "No more master pseudo-ttys - finished"
				return 0
			}
			[ $i = "p" ] && {
				case $j in
				[0123456789])
					echo "/dev/ptyp$node exists - OK"
					node=`expr $node + 1`
					continue ;;
				*) ;;
				esac
			}
			echo "Linking /dev/pty$i$j to /dev/ptyp$node"
			ln /dev/ptyp$node /dev/pty$i$j
			echo "Linking /dev/tty$i$j to /dev/ttyp$node"
			ln /dev/ttyp$node /dev/tty$i$j
			echo "tty$i$j\t_pmouse$node" >> /usr/lib/event/ttys
			node=`expr $node + 1`
		done
	done
	upddevasg
}


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

addstr="\nEnter how many pseudo ttys you want to be created\n"
rmvstr="\nEnter how many pseudo ttys you want to be removed (default is all)\n"
accpt_nl="no"

set_trap
cd /

if [ $# -eq 0 ]
  then
	clearscr
	while mesg="\n\n
		Pseudo ttys Configuration Program \n
		1. Add Pseudo ttys
		2. Remove Pseudo ttys
		3. Number of Pseudo ttys configured

		Select an option "
		quit="quit"
	do prompt || break
	select=$cmd
	case $select in
		1) addno=`getnumber $addstr`
		   [ "$addno" -gt 0 ] || abort $FAIL $abrt_add
				addpsdttys $addno
				;;
		2) accpt_nl=yes
		   rmvno=`getnumber $rmvstr`
		   accpt_nl=no
		   [ "$rmvno" -gt 0 ] || abort $FAIL $abrt_rmv
				rmvpsdttys $rmvno
				;;
		3) pttyno
		   	;;
		*) echo "\n	Please select either 1, 2 or 3"
		   continue			;;
	esac
	done
  else
	[ "$1" = "xnodes" ] && {
		makexnodes
		cleanup $OK
	}
	[ "$1" = "-s" ] && {
		pttyno
		cleanup $OK
	}
	[ -z "$2" ] && {
		error "Number of pttys undefined" 
		cleanup $FAIL
	}
	[ 0 -eq `expr $2 : '^[1-9][0-9]*$'` ] && {
	error "Second argument should be number of pttys to be added or removed"
		cleanup $FAIL
	}

	case $1 in
		-a)	addpsdttys $2
				;;
		-d)	rmvpsdttys $2
				;;
		 *) echo "\nUsage: mkdev ptty [ -a number | -d number | -s ]" >&2
			cleanup $FAIL
				;;
	esac
  fi

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

cleanup $OK
