:
#	@(#) mouse.sh 22.3 90/06/07 
#
#	Copyright (C) The Santa Cruz Operation, 1988, 1989.
#	This Module contains Proprietary Information of
#	The Santa Cruz Operation, and should be treated as Confidential.
#
#	Graphic Input Device initialization script
#       

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

DEVFILE=/usr/lib/event/devices
TTYFILE=/usr/lib/event/ttys

# Default values for event kernel arrays
NDEVICES=16
NQUEUES=8

tmp=/tmp/ms$$

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

# FUNCTIONS
#########################

# ---------- STANDARD ROUTINES -------- These routines are commen 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
}

# 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 function
prompt () { 
    while echo "\n${mesg}$quit \c" >&2
    do
        read cmd
        case $cmd in
            Q|q)
                return $FAIL
                ;;
            +x|-x)
                set $cmd
                ;;
            !*)
                eval `expr "$cmd" : "!\(.*\)"`
                ;;
            "") # "quit" is null when prompt is "press return to continue"
                [ -z "$quit" ] && return $OK
                # if there is an argument use it as the default
                # else loop until cmd is set
                [ "$1" ] && { 
                    cmd=$1
                    return $OK
                }
                error Invalid response
                ;;
            *)  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
	elif [ -f /etc/perms/inst ]; then
		PERM=/etc/perms/inst
	else
		error "Cannot locate linkkit permlist 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
}

# ---------- MENU ROUTINES ------------ These routines build a menu and
#					select GIN. 

# build one of two menus: all supported devices or current configuration
buildmenu () {
	# for main menu option "add", set supported-devices menu header
	if [ "$maincmd" = "2" ]
	then
		# if supported devices menu already built, don't rebuild it
		[ "$menuyet" = "yes" ] && {
  			mesg="$avmenu\nSelect an option"
       	 		quit=" or enter q to return to the previous menu:"
			return $OK
		}
		avmenu="\nThe following $GIN devices are supported:\n\n"
		avcnt=1 avlast=0  
	# for all other main menu options, set current config menu header
	else
		comenu="\nThe following devices and terminals are\
 configured:\n\n"
		cocnt=1 colast=0  
	fi
	[ -r "$DEVFILE" ] || {
  		echo "$DEVFILE not readable" >&2
  		return $FAIL
	}

	#duplicate stdin so that variables set during read loop may be used
	exec 3>&0 < $DEVFILE
	while read key devpath devclass type parms
	    do
   	        case $key in
			\#*|"") continue ;;
    	 	esac

		# For supported devices menu, don't put a second device of 
		# same kind (indicated by "_") in menu
		if [ "$maincmd" = "2" ]
		then
			[ `expr "$key" : ".*\(_\).*"` ] && continue
		fi

  	        case $devclass in
			$CLASS) 			          ;;
			   # relative devices can be of class REL or RELb
			   REL)	[ "$CLASS" = "RELb" ] || continue ;;
			     *) continue		          ;;
	        esac
    		STTY= INIT= NAME= SENSITIVITY=
		if [ "$maincmd" = "2" ]
		# build a menu of supported devices
		then
   	       		eval avkey$avcnt=$key avdevpath$avcnt=$devpath 
			eval avdevclass$avcnt=$devclass
    			eval $parms
    	       		eval avname$avcnt=\"${NAME:=$key}\"
   	       		avmenu="$avmenu$avcnt. $NAME\n"
  	       		avlast=$avcnt
   	       		avcnt=`expr $avcnt + 1`
		# build a current configuration menu
		else
			eval cokey$cocnt=$key 
			# Note the match() hides the psuedo mice
			ASSOCTTYS=`awk '{ if ( !match(key,/^_p/) && \
					$2 == key || $3 == key )\
				printf "%s\\\n", $1 }' key=$key $TTYFILE`
			if [ "$ASSOCTTYS" ]
			then    
				eval codevpath$cocnt=$devpath 
    				eval codevclass$cocnt=$devclass
    				eval $parms
         	       		eval coname$cocnt=\"${NAME:=$key}\"
        	       		comenu="$comenu$cocnt. $NAME\n"
                        	comenu="$comenu   is attached to $devpath \
and is associated with these ttys:\n"
       		                comenu=\
"$comenu`echo $ASSOCTTYS | pr -o3 -6 -t` \n\n" 
	 		        colast=$cocnt
	 		        cocnt=`expr $cocnt + 1`
			fi
		 fi
            done
	exec 0<&3 3>&-
	# set prompts for the supported devices menu 
	if [ "$maincmd" = "2" ]
	then
  		mesg="$avmenu\nSelect an option"
       	 	quit=" or enter q to return to the previous menu:"
		menuyet=yes

		# if menu has more than 9 entries, set vars for case processing
       		avtotal=$avlast
       		[ $avlast -gt 9 ] && {
       			avtens="[1-`expr $avlast / 10`]"
       			avones="[0-`expr $avlast - 10`]"
       			avlast=9
		}
	# set prompts for current configuration menu
	else
		# nothing is configured yet
		if [ "$colast" -eq 0 ]
		then
			[ "$maincmd" = "6" ] && return
       			mesg="\nThere are no devices or terminals currently\
 configured.\n\nPress return to continue: "
			quit=
			prompt || return $FAIL
		# something is already configured
		elif [ "$maincmd" = "1" ]
		# buildmenu was called by "display current configuration"
		then
			mesg="${comenu}Press return to continue: \c"
			quit=
			prompt 
		# buildmenu was called by main menu options 3,4 or 5
		else
			[ "$maincmd" = "6" ] && return
			mesg="$comenu\nSelect a $GIN "
			quit="or enter q to return to the previous menu:"
		fi

		# if menu has more than 9 entries, set vars for case processing
       		cototal=$colast
       		[ $colast -gt 9 ] && {
       			cotens="[1-`expr $colast / 10`]"
       			coones="[0-`expr $colast - 10`]"
       			colast=9
		}
	fi
return $OK
}
	
# menu selection
selectgin() {
	while :
        do
       		prompt ||  return $FAIL 
	 	if [ "$maincmd" = "2" ]
	 	# assign vars from supported devices menu
	 	then
			case $cmd in
       		     		[1-$avlast]|$avtens$avones)
					eval THISDEV=\$avdevpath$cmd
				        eval THISNAME=\$avname$cmd
				        eval THISKEY=\$avkey$cmd
				        eval THISCLASS=\$avdevclass$cmd
       		      	    	        break ;;
		    		 *) if [ "$avtotal" = "1" ]
				    then
				        echo "\nSelect number 1"
				    elif [ "$avtotal" = "2" ]
				    then
					echo "\nSelect either 1 or 2"
				    else
					echo "\nSelect a number between 1 and\
 $cototal" >&2
				    fi 
				    continue ;;
			esac 
	 	# assign vars from current configuration menu
	        else
			case $cmd in
       		    		 [1-$colast]|$cotens$coones)
		   		       eval THISDEV=\$codevpath$cmd
		     		       eval THISNAME=\$coname$cmd
				       eval THISKEY=\$cokey$cmd
				       eval THISCLASS=\$codevclass$cmd
       		      	    	       break ;;
		    		 *) if [ "$cototal" = "1" ]
				    then
				        echo "\nSelect number 1"
				    elif [ "$cototal" = "2" ]
				    then
					echo "\nSelect either 1 or 2"
				    else
					echo "\nSelect a number between 1 and\
 $cototal" >&2
				    fi
		       	 	    continue  ;;
	                esac 
	        fi
	done
	return $OK
}

# ----- MOUSE DEVICE ROUTINES --------  These routines create and remove
#					devices and modify device information
#					files.

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

confdevice () {
	[ -d /dev/mouse ] || {
		/bin/mkdir /dev/mouse 
		chown bin /dev/mouse
		chgrp bin /dev/mouse
		chmod 755 /dev/mouse
	}
	mkdevice event $ev_maj 0 
	mkdevice mouse/bus0 $mous_maj 0 
	mkdevice mouse/vpix0 $mous_maj 1 
}

# issue error if they want to attach two GINs to the same tty
chkdev () {
	dblcheck=
	grep -v "#" $TTYFILE > $tmp.chk
	dbl=`tr '\040' '\012' < $tmp.chk | grep -v tty | sort -u` 
	for keyword in $dbl
	do
		dblcheck=`awk "/$keyword$/ || /$keyword[ 	]/ \
						{print \\$2}" $DEVFILE`
		[ "$dblcheck" = "${NEWDEV:-$THISDEV}" ] && {
			error Another graphic input device is already \
attached to this tty.
		return $FAIL
		}
	done
	return $OK
}

# if user wants to add a GIN of a key which already exists,
# add an entry to DEVFILE for a device which already has at least one
# entry.   It will duplicate the entry original entry with the following
# exceptions:  The commented line before the entry will say the same
# thing as NAME= does.  The key needs to be unique, so if the first 
# instance is key the addtional ones will be key_n, where 'n' starts at 2.
# The device field is input by the user.  The name field will be altered
# to contain 'n' so the user knows which instance we are refering to.
dblgin () {
	LIST=
	# Read $DEVFILE as stdin to build list of instances of same mouse
	# and get type and parms.
	exec 4>&0 < $DEVFILE
	while read key devpath devclass type parms
	do
   	        case $key in
			\#*|"") continue ;;
    	 	esac

		if [ "$key" = "$THISKEY" ]
		then
			THISTYPE=$type
			if [ "$LIST" = "" ]
			then 
				LIST="$devpath"
			else
				LIST="$LIST\n$devpath"
			fi
    			STTY= INIT= SENSITIVITY=
			eval $parms
		else
			BASEKEY=`expr "$key" : "\(.*\)_.*"`
			if [ "$BASEKEY" = "$THISKEY" ]
			then
				if [ "$LIST" = "" ]
				then 
					LIST="$devpath"
				else
					LIST="$LIST\n$devpath"
				fi
			fi
		fi
	done
	exec 0<&4 4>&-
	# This device already is attached to system. 
	# Use routine from editdevice() to get port from user
	NEWDEV=
	echo "\nThere is a $THISKEY on each of the following ports:\n"
echo $LIST | pr -4 -t
	if getyn "\nDo you want to add another $THISNAME on a different port?"
	then
		while echo "\nTo which device (e.g. /dev/tty2a)\
 do you want to attach the\n$THISNAME (enter q to quit): \c"
		do
			read NEWDEV
			if [ "$NEWDEV" = "Q" -o "$NEWDEV" = "q" ]
			then
				return $FAIL
			elif [ `expr "$NEWDEV" : "\(\/dev\/\).*"` ]
			then
				:
			else
				NEWDEV=/dev/$NEWDEV
			fi
                       	case $NEWDEV in
                       	     /dev/*ty*) #warn if other GINs attach here
					chkdev || continue 1
					[ -c $NEWDEV ] && break
					error $NEWDEV is not a device \
file.
					;;
                          /dev/mouse/*) error A serial mouse cannot \
attach to a bus device. 
					;;
			        /dev/*) [ -c $NEWDEV ] && break
					error $NEWDEV is not a device
					;;
				     *) FNEWDEV=/dev/$NEWDEV
					if [ -c $FNEWDEV ]
					then
						NEWDEV=$FNEWDEV
						break
					else
						error $NEWDEV is not a valid\
 device
					fi
			        	;;
     			esac
  		done		
	else
		return $FAIL
	fi
	# Create new key
	LASTKEY=`grep $THISKEY $DEVFILE | awk '{ print $1 }'| sort -r | line`
	if [ "$LASTKEY" = "$THISKEY" ]
	then
		THISKEY=${THISKEY}_2
		NEWNUM=2
	else
		LASTNUM=`expr "$LASTKEY" : ".*_\(.*\)"`
		NEWNUM=`expr $LASTNUM + 1`
		THISKEY=${THISKEY}_${NEWNUM}
	fi

	#  Create new entry for device file
	newentry="\n# $THISNAME\n$THISKEY $NEWDEV $THISCLASS $THISTYPE \\
	NAME=\"Additional $THISNAME\" "
	if [ "$STTY" != "" -o "$INIT" != "" -o "$SENSITIVITY" != "" ]
	then
		newentry="$newentry \\\\\n\t"
		[ "$INIT" ] && newentry="${newentry}INIT=\"$INIT\" "
		[ "$STTY" ] && newentry="${newentry}STTY=\"$STTY\" "
		[ "$SENSITIVITY" ] && \
			newentry="${newentry}SENSITIVITY=\"$SENSITIVITY\""
	fi
	unset_trap
	#  Add entry to file
	echo "$newentry" >> $DEVFILE
	set_trap
	# set up new device
	disable $NEWDEV > /dev/null 2>&1
	# set perms for access
	chmod 666 $NEWDEV
	LINKDEV=$NEWDEV
	# link a serial device in /dev/mouse to the tty
	case $THISKEY in
		mousel0|mousel2) serdev=logitech_ser ;;
			mousems) serdev=microsoft_ser ;;
			mousepc) serdev=mousesys_ser ;;
			      *) return $OK ;;
	esac
	/bin/ln $LINKDEV /dev/mouse/$serdev > /dev/null 2>&1

return $OK
}

# edit device pathname in /usr/lib/event/devices if default entry is not correct
editdevice () {
	while :
		do
		NEWDEV=
		if getyn "\n$THISNAME is currently configured\nto attach to the\
 system on $THISDEV.\n\nDo you want to install this $GIN on a different port? "
		then
			while echo "\nTo which device (e.g. /dev/tty2a) do\
 you want to attach the\n$THISNAME (enter q to quit): \c"
			do
			read NEWDEV
			if [ "$NEWDEV" = "Q" -o "$NEWDEV" = "q" ]
			then
				return $FAIL
			elif [ `expr "$NEWDEV" : "\(\/dev\/\).*"` ]
			then
				:
			else
				NEWDEV=/dev/$NEWDEV
			fi
               	        case $NEWDEV in
          	             /dev/*ty*) #issue warning if other GINs attach here
					chkdev || continue 1
					[ -c $NEWDEV ] && break
					error $NEWDEV is not a device file.
					;;
        	          /dev/mouse/*) error A serial mouse cannot attach\
 to a bus device. 
					;;
			        /dev/*) [ -c $NEWDEV ] && break
					error $NEWDEV is not a device
					;;
              		             *) FNEWDEV=/dev/$NEWDEV
					if [ -c $FNEWDEV ]
					then
						NEWDEV=$FNEWDEV
						break
					else
						error $NEWDEV is not a valid\
 device
					fi
				        ;;
     			esac
  		done		

		# edit the device pathname field in /usr/lib/event/devices
		sed "/$THISKEY$/s:$THISDEV:$NEWDEV:;\
		    /$THISKEY[ 	]/s:$THISDEV:$NEWDEV:" $DEVFILE > $tmp.add
		unset_trap
		cp $tmp.add $DEVFILE
		set_trap
   	       	eval avdevpath$cmd=$NEWDEV 
	        disable $NEWDEV > /dev/null 2>&1
		LINKDEV=$NEWDEV
		break

	# use the default dev field entry in /usr/lib/event/devices
	else
		# q response to getyn goes back to main menu
		[ "$yn" = "q" -o "$yn" = "Q" ] && return $FAIL
		# issue warning if other GINs attach here
		chkdev || continue
		disable $THISDEV > /dev/null 2>&1
		LINKDEV=$THISDEV
		break
	fi
	done
	# link a serial device in /dev/mouse to the tty
	case $THISKEY in
		mousel0|mousel2) serdev=logitech_ser ;;
			mousems) serdev=microsoft_ser ;;
			mousepc) serdev=mousesys_ser ;;
			      *) return $OK ;;
	esac
	/bin/ln $LINKDEV /dev/mouse/$serdev > /dev/null 2>&1
return $OK
}

# associate pty's with the pseudo mice
assocpty() {
    # see if they are already there
    grep "ttyp." $TTYFILE > $tmp.grp
    if grep "_pmouse." $tmp.grp > /dev/null ; then
        return
    fi

    # Add them for all existing ptys
    for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f
    do
	# if there is such a pty
	if [ -c /dev/ttyp$i ] 
        then
	    # add the entry
	    sed "/ttyp$i/s/$/ _pmouse$i/" $TTYFILE > $tmp.tty
	    unset_trap
	    cp $tmp.tty $TTYFILE
	    set_trap
        fi
    done
}

# associate ttys with a GIN
assoctty () {
    # Always associate the pseudo mice with the pseudo ttys
    echo "\nAssociating the pseudo ttys..."
    assocpty

    # Use this flag to make sure they assoc. at least 1 valid tty with a GIN.
    stat=
    while [ "$stat" != "ok" ]
    do
	if [ "$maincmd" = "2" ] 
	then
		echo "\n\
This $GIN may be configured for use on any of the system's\n\
terminals and multiscreens.  The multiscreens and terminals\n\
that will be associated with this $GIN need to be specified.\n\n\
Specify them by entering, at the following prompt, all the\n\
ttys to be associated with this $GIN.  Entering the word\n\
\"multiscreen\" will associate all of the console multiscreens."
	fi

	echo "\nEnter a list of terminals (e.g. tty1a tty2a multiscreen)\n\
or enter q to quit.  Press return when finished: \c"
     	read a 
	[ "$a" = "" ] && {
		echo "\nError:  A mouse must be associated with a terminal or \
mulitscreen."
		continue
		}
     	for i in $a 
        do
        	if [ "$i" = "multiscreen" ] 
        	then
			echo "\nAssociating the multiscreens..."
			for i in tty01 tty02 tty03 tty04 tty05 tty06 tty07\
 tty08 tty09 tty10 tty11 tty12 syscon console
   	 		do
				chktty=$i
				editttys && {
					stat="ok"
					continue
					}
			done

		else 	
			# allow "q" response to return to main menu
			[ "$i" = "q" -o "$i" = "Q" ] && return $FAIL
			# verify that tty is not the GIN's attachment point
      			if [ -n "$NEWDEV" ] 
			then
				CHECKDEV=$NEWDEV
			else
      				CHECKDEV=$THISDEV
			fi
      			[ "/dev/$i" = "$CHECKDEV" ] && {
        			error The $THISNAME cannot be associated"\n"\
with $CHECKDEV. It is already physically attached to that device. 
				continue
			}
			# edit appropriate line in /usr/lib/event/ttys
			chktty=$i
			editttys && {
				stat="ok"
				continue
				}
        	fi
	done
    done
    return $OK
}

editttys () {
	# see if the tty is already in /usr/lib/event/ttys
      	if grep "$chktty" $TTYFILE > $tmp.grp
	then
		# see if the GIN is already associated with the tty
       		if grep "$THISKEY" $tmp.grp > /dev/null
		then
       			echo "\n$THISNAME is already associated\nwith $chktty" 
			return $FAIL
		# see if another keyword of the same class exists for this tty
		elif chkclass
		then
			# class type acceptable, add the entry
               		sed "/$chktty/s/$/ $THISKEY/" $TTYFILE > $tmp.tty
			unset_trap
			cp $tmp.tty $TTYFILE
			set_trap
		else
			# error, duplicate class entries for this tty entry
			return $FAIL
                fi 
	# the tty is not in /usr/lib/event/ttys. 
	else
      		[ -c /dev/$chktty ] ||  {
      			error $chktty is not a valid device in /dev. 
      			return $FAIL
      		}
		# add tty and keyword to /usr/lib/event/ttys
	  	echo "$chktty $THISKEY" >> $TTYFILE 
	fi
}

assocmore () {
	while getyn "
Do you want to use the $THISNAME on 
any other terminals? "
	do
		assoctty
	done
}

# error message issued by chkclass
errclass () { echo "\n\
Error. $THISNAME cannot be associated\n\
       with $chktty.  There is another graphic input device\n\
       of the same class already associated with this tty."
 }

# verify that this tty line in /usr/lib/event/ttys does not
# have another entry for a GIN of the same class
chkclass () {
	for j in `grep $chktty $TTYFILE`
    	do
		[ "$j" = "$chktty" ] && continue
		tclass=`awk '{ if ( $1 == key ) print $3 }' key=$j $DEVFILE`
		if [ "$tclass" = "$THISCLASS" ]
		then
			errclass
			return $FAIL
		elif
			# relative devices may be class "REL" or "RELb"
			[ "$tclass" = "REL" -o "$tclass" = "RELb" ] && \
			[ "$THISCLASS" = "REL" -o "$THISCLASS" = "RELb" ]
		then
			errclass
			return $FAIL
		fi
    	done
	return $OK
}

# Removes entry from $DEVFILE.  Designed to remove entries 
# created by this script which are always three lines long
# preceeded by a blank line.
rmdev() {
        rmkey=$1
	ed <<- eof > /dev/null 2>&1
		r $DEVFILE
		/$rmkey[ 	]/
		-2,+2d
		w $tmp.ed
		q
	eof
	unset_trap
	cp $tmp.ed $DEVFILE
	set_trap
}
		
# remove a GIN from the configuration by editing /usr/lib/event/ttys
# also call rmdev() to remove its entry from $DEVFILE if not first 
# mouse of its kind.
rmgin() {
	sed "/[ 	]$THISKEY$/s/[ 	]$THISKEY//g;\
	     /[ 	]$THISKEY[	 ]/s/[ 	]$THISKEY//g" \
						$TTYFILE > $tmp.rm
	unset_trap
	cp $tmp.rm $TTYFILE
	set_trap
	# If this is not the first entry for this mouse in $DEVFILE,
	# we'll remove its entry from $DEVFILE.
	if [ `expr "$THISKEY" : ".*\(_\).*"` ]
	then
		rmdev $THISKEY
	fi
	echo "\n$THISNAME\nhas been removed from the system configuration."
}

# disassociate a tty from a GIN
dassoctty() {
	while echo "\nEnter a list of one or more terminals (e.g. tty1a\
 tty1b tty04),\nor enter q to quit.  Press return when finished: \c"  
	do
		read DTTY
		for i in $DTTY
  		do
			# allow q to return to main menu
			[ "$i" = "q" -o "$i" = "Q" ] && return $FAIL
			# see if $i is already associated with this GIN
			if grep "$i.*$THISKEY$" $TTYFILE > /dev/null ||\
				grep "$i.*$THISKEY[ 	]" $TTYFILE > /dev/null
			then
				# delete keyword from the tty line 
       	        		sed "/$i.*$THISKEY$/s/ $THISKEY//;\
				/$i.*$THISKEY[ 	]/s/ $THISKEY//" $TTYFILE\
								> $tmp.sd
				unset_trap
				cp $tmp.sd $TTYFILE
				set_trap
			else
				error Cannot disassociate $i from\
 $THISNAME."\n"This entry is not currently associated with this $GIN. 
			fi
			# see if any more ttys are associated with this GIN
			if grep "$THISKEY$" $TTYFILE > /dev/null ||\
				grep "$THISKEY[ 	]" $TTYFILE > /dev/null
			then
				continue
			else
				echo "\nThere are no other ttys associated\
 with the\n$THISNAME."
			# If this is not the first entry for this mouse in 
			# $DEVFILE, we'll remove its entry from $DEVFILE.
			if [ `expr "$THISKEY" : ".*\(_\).*"` ]
			then
				rmdev $THISKEY
			fi
			echo "\n$THISNAME\nhas been removed from the system \
configuration."
			break 2
			fi
		done
		getyn "
Do you want to disassociate any other terminals from this
$THISNAME ?" || return $OK
	done
}

# remove all keywords from /usr/lib/event/ttys
rmconfig () {
	echo "\nRemoving the current $GIN configuration and $GIN devices from \
the system..." 
	cp $TTYFILE $TTYFILE.00
	trap "mv $TTYFILE.00 $TTYFILE; cleanup" 1 2 3 15
	grep "#" $TTYFILE > $tmp.rc
	awk '{print $1}' $TTYFILE | grep -v "#" > $tmp.2rc
	cat $tmp.2rc >> $tmp.rc
	unset_trap
	cp $tmp.rc $TTYFILE
	set_trap
	# Read $DEVFILE as stdin to build list of additional mice
	LIST=
	exec 5>&0 < $DEVFILE
	while read key devpath devclass type parms
	do
   	        case $key in
			\#*|"") continue ;;

			# Don't delete the pseudo mice
			_p*) continue ;;
    	 	esac

		if [ `expr "$key" : ".*\(_\).*"` ]
		then
			LIST="$LIST $key"
		fi
	done
	exec 0<&5 5>&-
	for i in $LIST
	do
		rmdev $i
	done
	echo "\nConfiguration removed."
}

# removes mouse device nodes
rmdevices () {
	[ -d "/dev/mouse" -o -f "/dev/event" ] && {
	getyn "\nDo you want to remove the $GIN devices from the /dev \
directory?" &&  rm -rf /dev/mouse/* /dev/event /dev/mouse
	}
}


# ------ CONFIGURATION ROUTINES ------- These routines extract information 
#					from and modify kernel configuration
#					files and parameters.

# set functions for configure
setobjfns () {
	mous_fns="mousinit mousclose mousintr mousioctl mousopen mousread"
	spm_fns="spmclose spmioctl spmopen spmread spm_tty"
	mpm_fns="mpmclose mpmopen mpmwrite"
	ev_fns="evclose evinit evioctl evopen evread" 
}

mousconf () {
	cd /etc/conf/pack.d/busmouse
	echo
	./mousconfig || {
		echo "\nThe system must be configured in order to use a\
 mouse driver."
	        cleanup $FAIL
		}  
}

# This routine sets evstate and the device major 
# number if applicable. Possible values for states 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.
confchk() {
	cd /etc/conf/cf.d
	# flags for return value
	evstate=NO
	moustate=NO
	kbmoustate=NO
	spmstate=NO
	mpmstate=NO

	spm_maj=`./configure -j spm` && {
		spmstate=PART 
		if [ -f ../sdevice.d/spm ] 
		then
			val=`awk '{print $2}' ../sdevice.d/spm` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
			[ "$val" = "Y" ] && spmstate=YES 
		else
			getyn "
Mouse 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
	}

	mpm_maj=`./configure -j mpm` && {
		mpmstate=PART 
		if [ -f ../sdevice.d/mpm ] 
		then
			val=`awk '{print $2}' ../sdevice.d/mpm` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
			[ "$val" = "Y" ] && mpmstate=YES 
		else
			getyn "
Mouse 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
	}

	mous_maj=`./configure -j busmouse` && {
		moustate=PART 
		if [ -f ../sdevice.d/busmouse ] 
		then
			val=`awk '{print $2}' ../sdevice.d/busmouse` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
			[ "$val" = "Y" ] && moustate=YES 
		else
			getyn "
Mouse 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
	}

	kbmous_maj=`./configure -j kbmouse` && {
		kbmoustate=PART 
		if [ -f ../sdevice.d/kbmouse ] 
		then
			val=`awk '{print $2}' ../sdevice.d/kbmouse` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
			[ "$val" = "Y" ] && kbmoustate=YES 
		else
			getyn "
Mouse 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
	}

	ev_maj=`./configure -j ev` && {
		evstate=PART 
		if [ -f ../sdevice.d/ev ] 
		then
			val=`awk '{print $2}' ../sdevice.d/ev` || {
				error "awk failed to read sdevice file."
				cleanup $FAIL
			}
			[ "$val" = "Y" ] && evstate=YES 
		else
			getyn "
Event 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
	}
}

# add driver entries to master, via configure
confadd() {
	echo "\nUpdating system configuration... \c">&2
	cd /etc/conf/cf.d

	#  Always add pseudo mouse
	# The pseudo mouse driver has a node.d file so
	# we remove the "required" flag from mdevice.
	# (we would like to not put it there is the first
	#  place but configure seem to allways add them)

	case $spmstate in
	NO) 	spm_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $spm_fns -m $spm_maj > conflog &&
		 ./configure -c -d -R -H -m $spm_maj >> conflog ||  {
			conferr
			cleanup $FAIL
		}  
		chg=yes	;;

	PART) ./configure -a -c -m $spm_maj -Y > conflog &&
		 ./configure -c -d -R -H -m $spm_maj >> conflog ||  {
			conferr
			cleanup $FAIL
		}  
		chg=yes	;;

	YES)	   ;;
	esac  

	case $mpmstate in
	NO) 	mpm_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $mpm_fns -P -m $mpm_maj > conflog &&
		 ./configure -c -d -R -H -m $mpm_maj >> conflog ||  {
			conferr
			cleanup $FAIL
		}  
		chg=yes	;;

	PART) ./configure -a -c -m $mpm_maj -Y -P > conflog &&
		 ./configure -c -d -R -H -m $mpm_maj >> conflog ||  {
			conferr
			cleanup $FAIL
		}  
		chg=yes	;;

	YES)	   ;;
	esac 

	#  Only add busmouse drivers if busmouse
	case "$THISDEV" in
	*bus* )

		case $moustate in
		# This will never be the case since busmouse is in mdevice.
		NO) 	mous_maj=`./configure -j NEXTMAJOR`
			./configure -c -a $mous_fns -R -m $mous_maj \
								> conflog ||  {
				conferr
				cleanup $FAIL
			}  
			chg=yes	;;
	
		PART) ./configure -a -c -m $mous_maj -Y -R > conflog ||  {
				conferr
				cleanup $FAIL
			}  
			chg=yes	;;
	
		YES)	   ;;
		esac  ;;

	#  Only add keyboard mouse drivers if kbmouse
	*kb* )

		# This will never be the case since kbmouse is in mdevice.
		case $kbmoustate in
		NO) 	kbmous_maj=`./configure -j NEXTMAJOR`
			./configure -c -a $mous_fns -R -m $kbmous_maj \
								> conflog ||  {
				conferr
				cleanup $FAIL
			}  
			chg=yes	;;
	
		PART) ./configure -a -c -m $kbmous_maj -Y -R > conflog ||  {
				conferr
				cleanup $FAIL
			}  
			chg=yes	;;
	
		YES)	   ;;
		esac  ;;

	* )  	      ;;
	esac

	case $evstate in
	NO)	ev_maj=`./configure -j NEXTMAJOR`
		./configure -c -a $ev_fns -R -m $ev_maj > conflog ||  {
			conferr
			cleanup $FAIL
		}  
		chg=yes ;;

	PART) ./configure -a -c -m $ev_maj -Y -R > conflog ||  {
			conferr
			cleanup $FAIL
		}  
		chg=yes ;;
	YES)	   ;;
	esac

	# 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
	chg=yes
	cd /etc/conf/cf.d

	# Bump event data structures
	./configure EVDEVS=$NDEVICES EVQUEUES=$NQUEUES > conflog 2>&1 || {
			conferr 
			cleanup  $FAIL
	}
	rm -f conflog
	cd /
}

# add line to event devices table in sevent
seventadd () {
	# flag used in addriver ()
	eventadd=true

#	cd /etc/conf/cf.d
	case $THISKEY in

	       *busmouse) RMKEY="busmouse"    ;;
		mousems*) RMKEY="msoftserial" ;;
		mousepc2*) RMKEY="msoftserial"  ;;
		mousepc*) RMKEY="msysserial"  ;;
		mousel0*) RMKEY="lt0_serial"  ;;
		mousel1*) RMKEY="lt1_serial"  ;;
		mousel2*) RMKEY="lt2_serial"  ;;		 
		mousel3*) RMKEY="lt3_serial"  ;;		 
		mousel4*) RMKEY="lt4_serial"  ;;		 
		mousel5*) RMKEY="lt5_serial"  ;;	
		mousel6*) RMKEY="lt6_serial"  ;;		 
	       summa4mm*) RMKEY="summa4mm"    ;;
	       *kbmouse*)  RMKEY="kbmouse"     ;;
		       *) return $FAIL
	esac
	# add keyboard to device table, unless already there
	grep -s "keyboard" sevent > /dev/null || {
		echo "keyboard" >> sevent
		eventadd=
	}
	# add pseudomouse to device table, unless already there
	grep -s "pseudomouse" sevent > /dev/null || {
		echo "pseudomouse" >> sevent
		eventadd=
	}
	# add new device to device table, unless already there
	grep -s "$RMKEY" sevent > /dev/null || {
		echo "$RMKEY" >> sevent
		eventadd=
	}
	chg=yes
}

# this function is specific to mouse installations
confrm () {
	chg=no
	cd /etc/conf/cf.d
	# if either of the drivers is configured, remove it 
	[ "$evstate" = "YES" ] && {
		chg=yes
		./configure -d -c -R -Y -m $ev_maj > conflog 2>&1 || {
			conferr 
			cleanup $FAIL
		}
		evstate=NO
		# configure down the size of the kernel data structures 
		./configure EVDEVS=1 EVQUEUES=1 > conflog 2>&1 || {
			conferr 
			cleanup $FAIL
		}
	}
	[ "$spmstate" = "YES" ] && {
		chg=yes
		./configure -d -c -R -Y -H -m $spm_maj > conflog 2>&1 || {
			conferr 
			cleanup $FAIL
		}
		spmstate=NO
	}
	[ "$mpmstate" = "YES" ] && {
		chg=yes
		./configure -d -c -R -Y -P -H -m $mpm_maj > conflog 2>&1 || {
			conferr 
			cleanup $FAIL
		}
		mpmstate=NO
	}
	[ "$moustate" = "YES" ] && {
		chg=yes
		./configure -d -c -R -Y -m $mous_maj > conflog 2>&1 || {
			conferr 
			cleanup $FAIL
		}
		moustate=NO
	}
	[ "$kbmoustate" = "YES" ] && {
		chg=yes
		./configure -d -c -R -Y -m $kbmous_maj > conflog 2>&1 || {
			conferr 
			cleanup $FAIL
		}
		kbmoustate=NO
	}
	rm -f conflog
	# Remove line discipline by hand.
	cd /etc/conf/sdevice.d
	sed "s/Y/N/" evld > $tmp.ld || { 
		error "\nsed unable to edit /etc/conf/sdevice.d/evld."
		return $FAIL
	}
	unset trap
	mv $tmp.ld evld
	set_trap
	chg=yes
	cd /etc/conf/cf.d
}

# Remove lines from event devices table in sevent
seventrm () {
	cd /etc/conf/cf.d
	cp sevent $tmp.sev
	for i in "keyboard" "mouse" "serial" "summa"
	do
		sed "/$i/d" $tmp.sev > $tmp.sv2
		mv $tmp.sv2 $tmp.sev
	done
	chg=yes
	unset_trap
	cp $tmp.sev sevent
	set_trap
	return $OK
}

# begin list of functions that handle kernel configuration
#########################

# functions to add graphic input device drivers to the kernel
addriver ()  {
	# Determine state of system configuration files.
	confchk
	# Add event entry to sevent file. 
	seventadd
	# check for /etc/perms/ext
	permschk
	# make sure link kit is installed
	linkchk
	# add drivers via configure
	confadd
	# make the needed GIN devices
	[ -d /dev/mouse ] || {
		/bin/mkdir /dev/mouse 
		chown bin /dev/mouse
		chgrp bin /dev/mouse
		chmod 755 /dev/mouse
	}
	mkdevice event $ev_maj 0 
	case "$THISDEV" in

		*bus*) 	mkdevice mouse/bus0 $mous_maj 0 
			mkdevice mouse/vpix0 $mous_maj 1 
			;;

		*kb*)	mkdevice mouse/kb0 $kbmous_maj 0
			;;

		   *)   ;; 
	esac

	# prompt for kernel relink
	if [ "$chg" = "yes" ] 
	then
		if [ "$_RELINK" -o "$_NOPROMPT" ]
		then
			klink
		else
			asklink && klink  
		fi
	fi
} 

# functions to remove GIN drivers from the kernel
rmdriver () {
	# See if drivers are configured in this kernel.
	confchk
	# If no drivers or evdevsw entries present, return.
	[ "$moustate" != "YES" -a "$evstate" != "YES" \
		-a "$kbmoustate" != "YES" ] && {
		echo "\nNo $GIN drivers are installed. \nKernel does not need \
to be relinked."
		return 
	}
	# prompt for removal of GIN configurations from $TTYFILE
	rmconfig
	# prompt for removal of GIN-related devices from /dev
        rmdevices	
	# remove drivers via configure
	confrm  
	# Update sdevice file.
	seventrm
	# prompt for kernel relink
	if [ "$chg" = "yes" ] 
	then
		if [ "$_RELINK" -o "$_NOPROMPT" ]
		then
			klink
		else
			asklink && klink  
		fi
	fi
} 

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

set_trap

[ -f $DEVFILE ] || { 
	error "$DEVFILE not present. 
This file must exist to initialize a mouse."
	cleanup $FAIL
}

# set CLASS based on the type of device to be configured
case $0 in
         *mouse) CLASS="RELb"
		 GIN=mouse
		 GINCAP=Mouse 
		 ;;
        *bitpad) CLASS="ABSb"
		 GIN=bitpad
		 GINCAP=Bitpad
		;;
esac

# variable used to prevent building the menu of supported devices twice
menuyet=no

# set functions for configure
setobjfns

cd /

while
    quit=" or enter q to quit:"
    mesg="\t$GINCAP Initialization Program\n
	1. Display current configuration
	2. Add a $GIN to the system
	3. Remove a $GIN from the system
	4. Associate a terminal with an existing $GIN
	5. Disassociate a terminal from an existing $GIN
	6. Remove the $GIN drivers from the kernel
	
Select an option"
	do
		prompt || cleanup $OK
		maincmd=$cmd
  		case $maincmd in
      			1) # display complete current configuration
       		  	   buildmenu ;;

     		        2) # display all supported GINs
       		  	   buildmenu 
			   # prompt for a GIN
                           selectgin || continue
			   # if busmouse or keyboard mouse make sure not 
			   # double entry;
			   case "$THISDEV" in

			   *bus* )

				if grep busmouse $TTYFILE > /dev/null
				then
	        			echo "\nOne busmouse has already been \
configured.\nThat is the maxmimum supported number of busmice."
					continue
	    	   	   	# since busmice configure vectors
				else
					mousconf || continue
				fi ;;

			   *kb* )

			   	if grep "$THISKEY" $TTYFILE > /dev/null
				then
	        			echo "\nThe $THISNAME\nhas already been\
 attached to this system."
					continue
				fi ;;

			   # if serial allow them to add multiple mice of
			   # same type
			   * )

			   	if grep "$THISKEY" $TTYFILE > /dev/null
			   	then
			        	# allow addition of two identical 
					# serial GINs
			   		dblgin || continue
			   	else
					editdevice || continue
			   	fi ;;
			   esac
			   # associate ttys with this GIN
        	   	   assoctty || continue
	           	   assocmore
			   # install mouse drivers if not already present
			   addriver ;;

 	    	    [3-5]) # display current configuration
         	   	   buildmenu
		 	   # no current configuration returns to main menu
		   	   [ "$colast" -eq 0 ] && continue
        	  	   selectgin || continue
       		   	   case $maincmd in
        		  	 3) rmgin     ;;
         		   	 4) assoctty || continue
	      		      	    assocmore ;;
        		   	 5) dassoctty ;;
                	   esac ;;

		        6) rmdriver ;;

			*) echo "\nEnter 1, 2, 3, 4, 5 or q" >&2 ;;
  		esac
	done
cleanup $OK
