:
#	@(#)fs.sh	1.3 91/02/28
#
#	Copyright (C) The Santa Cruz Operation, 1986, 1989.
#	This Module contains Proprietary Information of
#	The Santa Cruz Operation and is Confidential.
#
# FS - UNIX 3.2 File System Initialization
#
PATH=/etc:/bin:/usr/bin
LANG=english_us.ascii
export PATH LANG

fstab=/etc/default/filesys
checklist=/etc/checklist
tmp=/tmp/fs$$

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

# FUNCTION DEFINITIONS
#########################

# Define traps for critical and non critical code.
set_trap()  {	
	trap 'echo "\n\tInterrupted! 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
}

getyn() {
	while	echo "\n\t$* (y/n): \c" >&2
	do	read yn rest
		case $yn in
		[yY])	return $OK 				;;
		[nN])	return $FAIL				;;
		*)	echo "\n\tPlease answer y or n" >&2	;;
		esac
	done
}

# Prompt with mesg, return non-zero on q. Also allows setting -x and +x,
# shell escapes and the passing of default values
prompt() {
	mesg=$1
	while	echo "\n\t${mesg}or enter q to quit: \c" >&2
	do	read cmd
		case $cmd in
		+x|-x)	set $cmd					;;
		-v)	# Print the values of requested variables
			read x
			for var in $x
			do
				eval echo "\t\$$var"
			done
			;;
		Q|q)	return $FAIL					;;
		!*)	eval `expr "$cmd" : "!\(.*\)"`			;;
		"")	# If there is a second argument use it
			# as the default, else loop until 'cmd' is set
			[ "$2" ] && { 
				cmd=$2
				return $OK
			}
			: continue
			;;
		*)	return $OK					;;
		esac
	done
}

get_dev() {
	while	echo "
	Enter a device name and press <Return> 
	or q to quit: \c"
	do	read dev
		case $dev in
			"")	continue	;;
			q|Q)	cleanup $OK	;;
			/dev/*)	break		;;
			/*)	dev=/dev$dev	;;
			*)	dev=/dev/$dev	;;
		esac
		echo "\n\tDevice name modified to $dev"
		getyn "Do you wish to continue? " && break
	done
	cdev=`echo $dev | sed 's^/dev/^/dev/r^'`
	return
}

get_dir()  {
	while	echo "
	Enter a directory name and press <Return> 
	or q to quit: \c"
	do	read dir
		case $dir in
			"")	continue	;;
			q|Q)	cleanup $OK	;;
			/*)	break		;;
			*)	dir=/$dir	;;
		esac
		echo "\n\tDirectory name was modified to $dir."
		getyn "Do you wish to continue? " && break
	done
	[ -b $dev ] || {
		echo "\n\tWarning: $dev is not a block special device."
		getyn "Do you wish to continue? " || cleanup $FAIL
	}
	return
}

get_type()  {
	fstype="-f `/etc/fstyp $dev`" || {
		while :
		do prompt "Please enter the file system type of $dev from 
	<AFS, S51K, XENIX> " || cleanup $FAIL
			case $cmd in
				AFS|S51K|XENIX)	fstype="-f $cmd"; break	   ;;
				*)	echo "\n\t$cmd is not valid"; continue ;;
			esac
		done
	}
	return
}

fsadd()  {
	get_dev
	get_dir
	grep -s "$dev " $fstab > /dev/null && { 
		echo "
	Warning: There is already an entry for $dev in 
	$fstab.  This may cause conflict during autoboot 
	and when entering multiuser mode."
		getyn "Do you wish to continue? " || cleanup $FAIL
	}
	get_type

	# If mount point does not exist then create it and set correct 
	# ownership and permissions.  (If it exists, then leave the 
	# permissions as they are.)
	[ -d $dir ] || { 
		mkdir $dir
		chmod 775 $dir
		chown root $dir
		chgrp auth $dir
	}

	# mount $dir file structure, clean if necessary
	max=0
	until	/etc/mount $fstype $dev $dir > $tmp 2>&1
	do	case $? in
		2)	echo "\n\tCleaning $dev ... \c"
			fsck -y -t $tmp.fsck $dev >> $tmp 2>&1
			# If fsck can't clean fs in two rounds, give it up.
			max=`expr $max + 1`
			[ $max -gt 1 ] && {
				mv $tmp /tmp/fs.LOG
				echo "
	Unable to mount $dev. See /tmp/fs.LOG for details.  
	Exiting ... \n"
				cleanup $FAIL
			}
			;;
		*)	/etc/umount 2>> $tmp && continue
			echo "
	Sorry, cannot access $dev. See /tmp/fs.LOG for details."
			mv $tmp /tmp/fs.LOG
			cleanup $FAIL
			;;
		esac
	done

	# If lost+found does not exist then create it and set correct 
	# ownership and permissions.  (If it exists, then leave the 
	# permissions as they are.)
	[ -d $dir/lost+found ] || { 
		mkdir $dir/lost+found
		chmod 700 $dir/lost+found
		chown bin $dir/lost+found
		chgrp bin $dir/lost+found
	}
	# Make 62 empty entries in lost+found
	# This allocates inodes for the directory, so that if the filesys is
	# corrupted and runs out of inodes, fsck is still able to recover files.
	echo "\n\tReserving slots in lost+found directory ...\c"
	for i in 1 2 3 4 5 6 7 8
	do	for j in 1 2 3 4 5 6 7 
		do	> $dir/lost+found/x$i$j
		done
	done
	for i in 1 2 3 4 5 6
	do  > $dir/lost+found/xz$i
	done
	rm -f $dir/lost+found/x??
	echo

	# unmount $dir file structure
	/etc/umount $dev

	# Add the device to fsck checklist
	grep -s "$dev\$" $checklist > /dev/null || {
		unset_trap
		echo $dev >> $checklist
		set_trap
	}

	# Add pertinent information to fs file
	while echo "
	When entering multiuser mode: 

		1. Always mount $dev.  
		2. Never mount $dev. 
		3. Prompt before mounting $dev. 

	Select an option: \c" >&2
	do
	     read answer rest
	     case $answer in
		     1)  mountstring="rcmount=yes"		;;
		     2)  mountstring="rcmount=no"		;;
		     3)  mountstring="rcmount=prompt"	;;
		     *)  echo "\n\tEnter either 1, 2 or 3." >&2
		     continue				;;
	     esac
	     if getyn "Do you want to allow users to mount this file system? " 
	     then
		 u_mnt="yes" 
	     else
		 u_mnt="no" 
	     fi	
	     echo "\n\tUpdating system files ...\c"
	     unset_trap
	     echo "bdev=$dev cdev=$cdev mountdir=$dir $mountstring mount=$u_mnt fsckflags=-y" >> $fstab
	     set_trap
	     break
	done
	echo "\n\n\tFilesystem has been successfully added.\n"
	return
}

fsrm()  {
	[ "$bdev" ] || {
		echo "
	The following devices are currently listed in $fstab:
"
		for var in `grep -v "^#" $fstab | grep "bdev="`
		do
			echo $var | grep "bdev=" > /dev/null && {
				eval $var
				echo "\t$bdev"
			}
		done
		get_dev
	}

	# If filesystem is a virtual disk, tell user to use
	# 'vdutil' instead.
	mdevice_entry=`grep "^vd[ 	]" /etc/conf/cf.d/mdevice`
	if [ "$mdevice_entry" != "" ]
	then
		set $mdevice_entry
		VDMAJOR=$5
		if [ -b $dev ]
		then
			set `altos/bin/vdinfo -b $dev`
			if [ $2 = $VDMAJOR ]
			then
				echo "
	$dev is a virtual disk filesystem.  You must 
	use 'vdutil' to remove it.
"
				return
			fi
		fi
	fi

	echo "\n\tUpdating system files ...\c"

	# Remove pertinent information from fs file.
	token=`echo $dev | sed 's/\/dev\///'`
	sed "/$token /d" $fstab > $tmp
	unset_trap
	mv $tmp $fstab
	set_trap

	# Remove the device from fsck checklist
	sed "/$token\$/d" $checklist > $tmp
	unset_trap
	mv $tmp $checklist
	set_trap

	echo "
	Filesystem successfully removed from system files.\n"
	return
}
# main()
#########################

set_trap
cd /

while :
do prompt "`clearscr`

	Filesystem Initialization Program

	This program performs maintenance tasks required 
	to add or delete an existing filesystem. Would you 
	like to:

		1. Add a new filesystem to system.
		2. Remove a filesystem. 
	
	Select an option " || break
  	case $cmd in
		1) fsadd  
		   break     ;;

		2) fsrm   
		   break     ;;

		*) echo "\n\t$cmd is not valid. Try again."
		   sleep 2
		   continue  ;;
	esac
done
	
cleanup $OK

