:
#ident	"@(#)idaddld	1.2	90/08/16"
#ident "@(#)idaddld	1.2 89/09/29"
#	@(#) idaddld 1.1 89/08/15 
#
#	Copyright (C) The Santa Cruz Operation, 1989.
#	This Module contains Proprietary Information of
#	The Santa Cruz Operation and is Confidential.
#
# idaddld - UNIX 3.2 line discipline interface
#
PATH=/etc:/bin:/usr/bin
LANG=english_us.ascii
export PATH LANG

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

tmp="/tmp/ld$$"

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

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

usage() {
	error "Usage: $0 [-a name routine1 ... routine8] [-dc name]"
}

# perms list needed if link kit must be installed
permschk () {
	if [ -f /etc/perms/inst ]; then
		PERM=/etc/perms/inst
	else
		error "Cannot locate /etc/perms/inst. 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."
		[ -f $tmp.bak ] && {
			echo "\nRestoring space.c"
			cd /etc/conf/pack.d/kernel
			mv $tmp.bak space.c
		}
		cleanup $FAIL
	}
	return $OK
}
 
# ------ LINE DISCIPLINE ROUTINES ---- 	These routines update the line 
#					discipline switch table in the
#					space.c file. 


# This routine extracts the line discipline information into a tmp file.
extract()  {
	[ $argc -eq 0 ] && echo "
Line Discipline information is being extracted from configuration files ..."
	[ $tmp ] && rm -f $tmp*
	# Use a here document with ed to extract what we need.
	ed - << eof > /dev/null 2>&1  || return $FAIL
		r space.c
		/Discipline/
		/extern/
		kx
		/linecnt/
		ky
		1,'x-1w $tmp.beg
		'x,'yw $tmp
		'y+1,\$w $tmp.end
		q
eof
return $OK
}

# This routine splits the tmp file created by extract into a file of
# routine declarations and a file containing switch table entries.
split() {
	# Create a file of routine declarations.
	> $tmp.decl
	for token in `cat $tmp | grep "()"`
	do
		echo $token | grep "()" | sed 's/[;,]//p' >> $tmp.decl
	done

	# Create a formatted file of actual table entries. 
	sed -n '/struct/,/};/p' $tmp | sed '/struct/d;/};/d;s/,//' | \
	awk '{
		if ($1 == "/*") printf("\n%s   ", $2)
		else printf("%s ",$1 )
	     }
		END {print}
	' | sed '/^$/d' > $tmp.tab || return $FAIL
	[ $argc -eq 0 ] && echo 
	return $OK
}

# This routine formats the entries in tmp.tab and prints them.
print_tab() {
	awk 'BEGIN { 
		printf("\nPrefix\t       List of Routines\n")
		printf("-----------------------------------------------------------------------------\n")
	     }
	     {
		b1=sprintf("%-4s | ", $1)
		b2=sprintf("%-7s  %-7s  %-7s  %-7s  ", $2, $3, $4, $5)
		b3=sprintf("%-7s  %-7s  %-7s  %-7s \n", $6, $7, $8, $9)
		buf=sprintf("%s%s%s", b1, b2, b3)
		if (length(buf) <= 80) printf("%s", buf)
		else printf("%s", substr(buf,1,80))
		printf("-----------------------------------------------------------------------------\n")
	     }' $tmp.tab || return $FAIL
	echo
	return $OK
}
	
# Prompt user for line discipline details.
get_funcs()  {
	# Local variable
	j=

	while echo "
Please enter the list of routines you would like configured into the
line discipline switch table. There must be eight routines each seperated
by spaces. If there is no corresponding routine for one of the positions,
enter \"nulldev\". Please enter them in the order as defined below and press
<Return> when you are finished or enter q to quit.

order: 
open 	close 	read 	write 	ioctl 	rxint 	txint 	modemint
"
	do 
		read funcs
		case $funcs in
		q|Q)	return $FAIL  ;;
		*) 	j=0
			for i in `echo $funcs` ; do
				j=`expr $j + 1`
			done
			if [ $j -ne 8 ] ; then
				echo "
There must be eight routines. Try again."
				continue
			else
				getyn "
This is the list of routines you have entered:\n
$funcs\n
Do you wish to continue? " || continue
				mesg="Please enter the driver prefix\n" 
				prompt || return $FAIL
				name=$cmd
				break
			fi	;;
		esac
	done
	func_list="$name  $funcs"
	return $OK
}

get_name() {
	mesg="Please enter the driver prefix of the line discipline you
would like removed "
	while :
	do prompt || return $FAIL
		if grep "$cmd" $tmp.tab > /dev/null 2>&1 
		then
			name=$cmd
			break
		else
			echo "\n$cmd is not a valid prefix."
		fi
	done
	return $OK
}	

do_add()  {
	[ -f $tmp.bak ] || cp space.c $tmp.bak
	name=`echo $func_list | awk '{print $1}'`
	grep "^$name  " $tmp.tab > /dev/null 2>&1 && {
		error "Line Discipline with prefix $name already exists"
		return $FAIL
	}
	echo $func_list >> $tmp.tab
	for i in `echo $func_list | \
		awk '{ print $2" "$3" "$4" "$5" "$6" "$7" "$8" "$9 }'`
	do
		grep $i $tmp.decl > /dev/null 2>&1 || echo "$i()" >> $tmp.decl
	done
	return $OK
}

do_rm()  {
	[ -f $tmp.bak ] || cp space.c $tmp.bak
	flist=`grep "^$name  " $tmp.tab`
	[ -z "$flist" ] && return $FAIL
	sed "/^$name  /d" $tmp.tab > $tmp.rm
	mv $tmp.rm $tmp.tab
	for i in `echo $flist | \
		awk '{ print $2" "$3" "$4" "$5" "$6" "$7" "$8" "$9 }'`
	do
		grep $i $tmp.tab > /dev/null 2>&1 || {
			sed "/$i()/d" $tmp.decl > $tmp.rd
			mv $tmp.rd $tmp.decl
		}
	done
	return $OK
}

# Create a new line discipline switch table from modified tmp files.
unsplit() {
	awk ' 	BEGIN { i=1 }
		{ buf[i]=$0; i++ }
		END  {
			j=1
			printf("extern int\t%s,\n", buf[j])
			for (j=2; j<(i-1); j++) printf("\t\t%s,\n", buf[j])
			printf("\t\t%s;\n\n", buf[j])
		}' $tmp.decl > $tmp.mid || return $FAIL

	awk ' 	BEGIN { print "struct	linesw	linesw[] = {" }
		{ 	printf("/*\t%s ------------- */\n", $1) 
			printf("\t\t\t%s,\n\t\t\t%s,\n",$2, $3)
			printf("\t\t\t%s,\n\t\t\t%s,\n",$4, $5)
			printf("\t\t\t%s,\n\t\t\t%s,\n",$6, $7)
			printf("\t\t\t%s,\n\t\t\t%s,\n",$8, $9)
		}
		END  {	print "};" 
		} ' $tmp.tab >> $tmp.mid || return $FAIL
	cnt=`grep -c " " $tmp.tab`
	echo "int 	linecnt=$cnt;" >> $tmp.mid
	return $OK
}

do_cat() {
	cd /etc/conf/pack.d/kernel
	unset_trap
	mv space.c $tmp.space
	cat $tmp.beg $tmp.mid $tmp.end > space.c || {
 		mv $tmp.space space.c
 		echo "cat failed to concantenate tmp files."  
 		return $FAIL
	}
	set trap
	[ $argc -eq 0 ] && \
	echo "\n\nLine discipline declarations have been successfully modified."
	return $OK
}

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

ld_add()  {
	cd /etc/conf/pack.d/kernel
	extract || {
		error "Can't extract information from space.c" 
		return $FAIL
	}
	split		|| return $FAIL
	get_funcs	|| return $FAIL
	do_add 		|| return $FAIL
	unsplit		|| return $FAIL
	do_cat 		|| return $FAIL
	change="YES"
	return $OK
}

ld_rm()  {
	cd /etc/conf/pack.d/kernel
	extract || {
		error "Can't extract information from space.c" 
		return $FAIL
	}
	split		|| return $FAIL
	print_tab	|| return $FAIL
	get_name 	|| return $FAIL
	do_rm 		|| return $FAIL
	unsplit		|| return $FAIL
	do_cat 		|| return $FAIL
	change="YES"
	return $OK
}

show_config()  {
	cd /etc/conf/pack.d/kernel
	extract || {
		error "Can't extract information from space.c" 
		return $FAIL
	}
	split	   || return $FAIL
	print_tab  || return $FAIL
	echo "Press <Return> to continue \c"
	read x
	return $OK
}

# Non-Interactive addition of a line discipline.
ni_ld_add()  {
	cd /etc/conf/pack.d/kernel
	extract || {
		error "Can't extract information from space.c" 
		return $FAIL
	}
	split	|| return $FAIL
	func_list=`echo $argv | sed 's/-a//p'`
	do_add 	|| return $FAIL
	unsplit	|| return $FAIL
	do_cat 	|| return $FAIL
	change="YES"
	return $OK
}

# Non-Interactive removal of a line discipline.
ni_ld_rm()  {
	cd /etc/conf/pack.d/kernel
	extract || {
		error "Can't extract information from space.c" 
		return $FAIL
	}
	split		|| return $FAIL
	name=`echo $argv | awk '{print $2}'`
	do_rm 		|| return $FAIL
	unsplit		|| return $FAIL
	do_cat 		|| return $FAIL
	return $OK
}

ni_chk() {
	name=`echo $argv | awk '{print $2}'`
	cd /etc/conf/pack.d/kernel
	extract || {
		error "Can't extract information from space.c" 
		return $FAIL
	}
	grep '\-------' $tmp | grep "$name " > /dev/null 2>&1 && return $OK
	return $FAIL
}

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

cd /
set_trap
permschk
linkchk

# Interactive use
argc=$# 
argv=$*	
case $argc in
0)
	clear
	while :
	do
	mesg="\nLine Discipline Configuration Program \n
	1. Add line discipline to the system
	2. Remove line discipline from the system
	3. Show current configuration
	
Select an option "

		prompt || break 
		case $cmd in
      			1) ld_add || cleanup $FAIL	
		   	continue			;;
			2) ld_rm  || cleanup $FAIL  	
		   	continue			;;
			3) show_config || cleanup $FAIL 
		   	continue			;;
		esac
	done
	if [ "$change" = "YES" ]
	then
		asklink && klink
	fi
	;;

# Non-Interactive use
2)	case $1 in 
		-c)	ni_chk  && cleanup $OK
			cleanup $FAIL ;;
		-d)	ni_ld_rm  || cleanup $FAIL ;;
		*)	usage
			cleanup $FAIL ;;
	esac
	;;
10) 	case $1 in
		-a) 	ni_ld_add || cleanup $FAIL ;;
		*)	usage
			cleanup $FAIL ;;
	esac
	;;
*) 	usage
	cleanup $FAIL
	;;
esac
       		  	   
cleanup $OK
