#ident	"@(#)sadmin:admin/menu/diskmgmt/badtrack/redirect	35.4"
#menu#  redirect bad tracks on the disk
#help# 
#help#	Remap bad data tracks on the disk to good data tracks.  This is
#help#	to be used when a track is reported to be damaged and unusable.
#help#  After using this utilitiy, use the fixfsys menu option to get 
#help#  a list of the files which are corrupted (ie: they had contents
#help#  on the track which may now be lost).

# Undo any environmental weirdness wrt the devices or their sizes.
# since hdsetup loops through multiple devices, we'd really need
# 2 sets of env vars (320/360). forget it for now.

flags="-qq -k$$"
trap 'rm -f /tmp/xf_*; exit 1' 1 2 15

ETC=/etc
FMT=${ETC}/dinit
CONV=${ETC}/xformtrk
GEN=${ETC}/fblkgen
FSCK=${ETC}/fsck
MANUF=2
SIZE=2
fmt=2
def_dev=1
WRT_DEF=n
fmtflag=
rmflag=y
SLIPFLAG=n
secslip=NA
file_def=y
TFILE=0
TMPFILE=/tmp/xf_tmp$$
CUTFILE=/tmp/xf_cut$$


validdevs='
	1.  m320_0			13. m327_00
	2.  m320_1			14. m327_10
	3.  m320_1d0 			15. m327_20
	4.  m320_1d1 			16. m327_30
	5.  m360_0 			17. m327_1d00
	6.  m360_2 			18. m327_1d10
	7.  m360_1d0			19. m327_1d20
	8.  m360_1d2			20. m327_1d30
	9.  m323_0 			21. m147_00
	10. m323_1 			22. m147_10
	11. m323_2 			23. m147_20
	12. m323_3 			24. m147_30'

getdevice() {
	echo "\n	Valid Devices Are:\c"
	echo "${validdevs}\n"
	device=`checklist ${flags} -D"${def_dev}" -H "Valid Devices: ${validdevs}"\
	-fe "enter the device (default: ${def_dev}) [q] :" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24`
	case "${device}" in
		'1') device=m320_0 
		     def_dev=1 ;;
		'2') device=m320_1 
		     def_dev=2 ;;
		'3') device=m320_1d0 
		     def_dev=3 ;;
		'4') device=m320_1d1 
		     def_dev=4 ;;
		'5') device=m360_0 
		     def_dev=5 ;;
		'6') device=m360_2 
		     def_dev=6 ;;
		'7') device=m360_1d0 
		     def_dev=7 ;;
		'8') device=m360_1d2 
		     def_dev=8 ;;
		'9') device=m323_0
		     def_dev=9 ;;
		'10') device=m323_1
		     def_dev=10 ;;
		'11') device=m323_2
		     def_dev=11 ;;
		'12') device=m323_3
		     def_dev=12 ;;
		'13') device=m327_00
		     def_dev=13 ;;
		'14') device=m327_10
		     def_dev=14 ;;
		'15') device=m327_20
		     def_dev=15 ;;
		'16') device=m327_30
		     def_dev=16 ;;
		'17') device=m327_1d00
		     def_dev=17 ;;
		'18') device=m327_1d10
		     def_dev=18 ;;
		'19') device=m327_1d20
		     def_dev=19 ;;
		'20') device=m327_1d30
		     def_dev=20 ;;
		'21') device=m147_00
		     def_dev=21 ;;
		'22') device=m147_10
		     def_dev=22 ;;
		'23') device=m147_20
		     def_dev=23 ;;
		'24') device=m147_30
		     def_dev=24 ;;
	esac
	case $device in
	    m320_[01] | m320_1d[01])
		echo '
	Valid Disk Sizes are:
	1. 40 Megabyte
	2. 70 Megabyte\n'
		SIZE=`checklist ${flags} -D"${SIZE}" -ef "What size is your disk (default: ${SIZE})?" 1 2 `
		case "${SIZE}" in
			'1') Sz=40 
			     pr_sz='40  Meg';;
			'2') Sz=70 
			     pr_sz='70  Meg';;
		esac
		DTYPE=m320${Sz}
		echo '
	Valid Manufacturers are:
	1. Toshiba
	2. Micropolis
	3. Miniscribe
	4. Priam\n'
		MANUF=`checklist ${flags} -D"${MANUF}" -ef "Who Manufactures your Winchester (default: ${MANUF})?" 1 2 3 4`
		case "${MANUF}" in
			'1') Mfg=t 
			     pr_man=Toshiba ;;
			'2') Mfg=m 
			     pr_man=Micropolis ;;
			'3') Mfg=s 
			     pr_man=Miniscribe ;;
			'4') Mfg=p 
			     pr_man=Priam ;;
		esac
		DTYPE=${DTYPE}${Mfg}
		;;

	    m360_[02] | m360_1d[02])
		if checkyn ${flags} -D"${SLIPFLAG}" -H"
Sector slipping is available as a form of bad track management.  If your 
drive was formatted initally to use it, answer yes.  If you guess
incorrectly, the redirection will fail and you can try again." \
	-ef "Was device formatted to use sector slip (default: ${SLIPFLAG})? "
		then
			DTYPE=m360337s
			secslip=yes
		else
			DTYPE=m360337
			secslip=no
		fi
		pr_man=NA
	 	pr_sz=NA
		;;

	    m323_[0123])
		typedefault=1
		pr_man="CDC"
		diskselect
		if checkyn ${flags} -D"${SLIPFLAG}" -H"
Sector slipping is available as a form of bad track management.  If your 
drive was formatted initally to use it, answer yes.  If you guess
incorrectly, the redirection will fail and you can try again." \
	-ef "Was device formatted to use sector slip (default: ${SLIPFLAG})? "
		then
			DTYPE=${DTYPE}s
			secslip=yes
		else
			secslip=no
		fi
		;;
	    m327_0? | m327_1d0? )
		DTYPE=m327cdcIII
		typedefault=1
		Sz=NA
		secslip="NA"
		pr_man="CDC"
		pr_sz="NA"
		diskselect
		;;
	    m327_1? | m327_1d1? )
		DTYPE=m327micro
		typedefault=2
		Sz=NA
		secslip="NA"
		pr_man="Micropolis"
		pr_sz="NA"
		diskselect
		;;
	    m327_2? | m327_1d2? )
		DTYPE=m327cdcIV
		typedefault=3
		Sz=NA
		secslip="NA"
		pr_man="CDC"
		pr_sz="NA"
		diskselect
		;;
	    m327_3? | m327_1d3? )
		DTYPE=m327sea80
		typedefault=4
		Sz=NA
		secslip="NA"
		pr_man="Seagate"
		pr_sz="NA"
		diskselect
		;;
	    m147_0? )
		DTYPE=m147cdcIII
		typedefault=1
		Sz=NA
		secslip="NA"
		pr_man="CDC"
		pr_sz="NA"
		diskselect
		;;
	    m147_1? )
		DTYPE=m147micro
		typedefault=2
		Sz=NA
		secslip="NA"
		pr_man="Micropolis"
		pr_sz="NA"
		diskselect
		;;
	    m147_2? )
		DTYPE=m147cdcIV
		typedefault=3
		Sz=NA
		secslip="NA"
		pr_man="CDC"
		pr_sz="NA"
		diskselect
		;;
	    m147_3? )
		DTYPE=m147sea80
		typedefault=4
		Sz=NA
		secslip="NA"
		pr_man="Seagate"
		pr_sz="NA"
		diskselect
		;;
	    *)
		    ;;
	esac
    if [ ${TFILE} = '0' ]
    then
    	if [ -f ${ETC}/badtracks/${device} ]
    	then
    		TFILE=${ETC}/badtracks/${device}
	else
	  	TFILE=NONE
    	fi
    fi
    FMTDEV=/dev/rdsk/${device}s7
}

# After the defaults had been set when choosing the device name, the
# real type is now selected.
diskselect() {
   case $device in
   m323* )
	valtypes='
	1.  m323182	- CDC 182Mb
	2.  m323390	- Wren V'
	echo "${valtypes}\n"
	newtype=`checklist ${flags} -D"${typedefault}" -ef "What is the disk type (default: ${typedefault})? " 1 2`
	case "${newtype}" in
		'1') DTYPE=m323182
		     pr_sz="182Mb" ;;
		'2') DTYPE=m323390
		     pr_sz="390Mb" ;;
	esac
	;;
   m327* )
	valtypes='
	1.  m327cdcIII	- Wren III
	2.  m327micro	- Micropolis
	3.  m327cdcIV	- Wren IV
	4.  m327sea40	- Seagate 48Mb
	5.  m327sea80	- Seagate 85Mb
	6.  m327maxtor	- Maxtor'
	echo "${valtypes}\n"
	newtype=`checklist ${flags} -D"${typedefault}" -ef "What is the disk type (default: ${typedefault})? " 1 2 3 4 5 6`
	case "${newtype}" in
		'1') DTYPE=m327cdcIII
		     pr_man=CDC ;;
		'2') DTYPE=m327micro
		     pr_man=Micropolis ;;
		'3') DTYPE=m327cdcIV
		     pr_man=CDC ;;
		'4') DTYPE=m327sea40
		     pr_man=Seagate ;;
		'5') DTYPE=m327sea80
		     pr_man=Seagate ;;
		'6') DTYPE=m327maxtor
		     pr_man=Maxtor ;;
	esac
	;;
   m147* )
	valtypes='
	1.  m147cdcIII	- Wren III
	2.  m147micro	- Micropolis
	3.  m147cdcIV	- Wren IV
	4.  m147sea40	- Seagate 48Mb
	5.  m147sea80	- Seagate 85Mb
	6.  m147maxtor	- Maxtor'
	echo "${valtypes}\n"
	newtype=`checklist ${flags} -D"${typedefault}" -ef "What is the disk type (default: ${typedefault})? " 1 2 3 4 5 6`
	case "${newtype}" in
		'1') DTYPE=m147cdcIII
		     pr_man=CDC ;;
		'2') DTYPE=m147micro
		     pr_man=Micropolis ;;
		'3') DTYPE=m147cdcIV
		     pr_man=CDC ;;
		'4') DTYPE=m147sea40
		     pr_man=Seagate ;;
		'5') DTYPE=m147sea80
		     pr_man=Seagate ;;
		'6') DTYPE=m147maxtor
		     pr_man=Maxtor ;;
	esac
	;;
   *)
	return ;;
   esac
}

get320fmt() {
	echo '
	Valid file formats are:
	1. <Track>
	2. <Head> <Cylinder>
	3. <Log Device> <Block>\n'
	fmt=`checklist ${flags} -D"${fmt}" -ef "In what format is the bad track file (default: ${fmt})? " 1 2 3`
	case "${fmt}" in
		'1') prfmt='<TRACK>' 
		     fmtflag=t ;;
		'2') prfmt='<HEAD><CYL>' 
		     fmtflag=c ;;
		'3') prfmt='<DEV><BLOCK>'
		     fmtflag=d ;;
	esac
}

getffmt() {
	echo '
	Valid file formats are:
	1. <Head> <Cylinder> <Log Sector>
	2. <Log Device> <Block>\n'
	fmt=`checklist ${flags} -D"${fmt}" -ef "In what format is the bad track file (default: ${fmt})? " 1 2`
	case "${fmt}" in
		'1') prfmt='<HEAD><CYL><LSECT>'
		     fmtflag=b ;;
		'2') prfmt='<DEV><BLOCK>'
		     fmtflag=d ;;
	esac
}

getbfile() {
	found=false
	while [ $found -eq false ]
	do
		echo
		bfile=`checkre ${flags} -fe -D"${TFILE}" \
		"Enter full path name of bad track file (default: ${TFILE}) [q]: 
	" \
		'.' ' ' \
		'^[^ ;	][^ ;	]*$' 'Blanks or tabs not permitted in the path name.' \
		'^/' 'A full path name must begin with "/".' \
		'[^/]$' 'No trailing "/" may be in the path name.' \
		'/[^/]\{1,14\}$' 'No more than 14 characters in a file name.'`
		if [ ! -f ${bfile} ]
		then
			if [ ${TFILE} = 'NONE' ]
			then
				echo "	There is no default file.\n"
			else
				echo "	Cannot find file '${bfile}'.\n"
			fi
		else
			TFILE=${bfile}
			return
		fi
	done
}

get320inpfmt() {
	echo '
	Valid input formats are:
	1. <Track>
	2. <Head> <Cylinder>
	3. <Log Device> <Block>\n'
	fmt=`checklist ${flags} -D"${fmt}" -ef "In what format will you enter the data (default: ${fmt})? " 1 2 3`
	case "${fmt}" in
		'1') prfmt='<TRACK>' 
		     fmtflag=t ;;
		'2') prfmt='<HEAD><CYL>'
		     fmtflag=c ;;
		'3') prfmt='<DEV><BLOCK>'
		     fmtflag=d ;;
	esac
}

getinpfmt() {
	echo '
	Valid input formats are:
	1. <Head> <Cylinder> <Log Sector>
	2. <Log Device> <Block>\n'
	fmt=`checklist ${flags} -D"${fmt}" -ef "In what format will you enter the data (default: ${fmt})? " 1 2`
	case "${fmt}" in
		'1') prfmt='<HEAD><CYL><LSECT>'
		     fmtflag=b ;;
		'2') prfmt='<DEV><BLOCK>'
		     fmtflag=d ;;
	esac
}

enter320data() {
	${CONV} -I ${fmtflag} -O c  ${DTYPE} ${device} 2>/dev/null
	if [ $? != 0 ]
	then
		echo "\n\tCan't get new input.  Check that"
		echo "\tdisktype is defined in dskdefs file.\n"
		exit 1
	fi
	mv /tmp/xf_${device} ${TFILE}
}

enterdata() {
	> ${TFILE}		# clear the file
	if [ ${fmtflag} = 'b' ]
	then
		echo "\nEnter bad track numbers as <head> <cylinder> <log sector>  (Use -1 for an"
		echo "unknown sector field);  End with a period (.): "
		while read INP 
		do
			if [ "${INP}" = "." ]
			then
				break
			fi
			set ${INP}
			if [ $# -ne 3 ]
			then
				echo "Bad input: enter as <head> <cylinder> <log sector>"
			else
				echo $1 $2 $3 >> ${TFILE}
			fi
		done
	else
		${CONV} -I ${fmtflag} -O c  ${DTYPE} ${device} 2>/dev/null
		if [ $? != 0 ]
		then
			echo "\n\tCan't get new input.  Check that"
			echo "\tdisktype is defined in dskdefs file.\n"
			exit 1
		fi
		mv /tmp/xf_${device} ${TFILE}
	fi
}

# fblkgen cannot handle the extra field used by dinit (sector).  Just lop it
# off and use head/cylinder only.  Input is in $TFILE.
cutfile() {
	> ${TMPFILE}
	while read HD CYL LSECT
	do
		echo "$HD $CYL" >> ${TMPFILE}
	done < ${TFILE}
	mv ${TMPFILE} ${CUTFILE}
}

# START MAIN
echo '\nAnytime you want to quit, type "q".
If you are not sure how to answer any prompt, type "?" for help,
or see the Administrator\047s Guide.
\nIf a default appears in the question, press <RETURN> for the default.
'
while  true
do
	if checkyn ${flags} -D"${WRT_DEF}" -H"
	If you answer no to this, the disk format will continue in a
	non-destructive mode.  You will be able to see what would happen
	without actually doing it.  Because the disk is not checked, if the
	track values are not unique and unknown previously, you may get some
	some files listed as potentially damaged which aren't.  To avoid this,
	make sure the list you enter has unique values and none of them are
	already known to the disk." \
	-ef "Do you wish to WRITE (default: ${WRT_DEF})? "
	then
		WFLAG=yes
	else
		WFLAG=no
	fi
	getdevice
	if checkyn ${flags} -D"${file_def}" -H"
	If the bad track information is contained within a file, it will be
	read automatically, otherwise you must enter the information by hand.
	The numbers you type in will be added to the permanent bad track file
	at the end so they will not be lost." \
	-ef "Will the track information be from a file (default:${file_def})? "
	then
		case $device in
	    	m320_[01] | m320_1d[01])
		getbfile
		get320fmt
			;;
	    	m360_[02] | m360_1d[02] | m323_[0123] | m327_[0123]? | m327_1d[0123]? | m147_[0123]? )
			getbfile	# this sets TFILE
			getffmt
			;;
	    	*)
		    	;;
		esac
	else
		bfile=interactive
		file_def=n
		case $device in
	    	m320_[01] | m320_1d[01])
			get320inpfmt
			;;
	    	m360_[02] | m360_1d[02] | m323_[0123] | m327_[0123]? | m327_1d[0123]? | m147_[0123]? )
			getinpfmt
			;;
	    	*)
		    	;;
		esac
	fi

	echo "\nThis is the information for the track redirection:\n
	entered device:	${device}
	manufacturer:	${pr_man}
	disk size:    	${pr_sz}
	badtrack file:	${bfile}
	file format:	${prfmt}
	device name:	${FMTDEV}
	device type:	${DTYPE}
	write:      	${WFLAG}
	sector slip:	${secslip}\n"
	case `checklist ${flags} -fep 'Do you want to begin redirection, or change this data [b, c, q]?' begin change ` in
	begin )
		fslist=`ls ${ETC}/badtracks/F.* 2>/dev/null`
		if [ -n "${fslist}" ]
		then
			echo "\nThese fsck input files exist:\n"
			echo "${fslist} \n"
			if checkyn ${flags} -D"${rmflag}" -H"
	You must remove these files before you can run this utility.  The
	information within them is old and not usable.  However, if you 
	have any use for them, you should save them somewhere else first." \
			-ef "Delete them (default: ${rmflag})? "
			then
				rm -f ${ETC}/badtracks/F.*
			else
				exit 0
			fi
		fi
		if [ "${bfile}" = "interactive" ]
		then
			case $device in
	    		m320_[01] | m320_1d[01])
				enter320data
				;;
	    		m360_[02] | m360_1d[02] | m323_[0123] | m327_[0123]? | m327_1d[0123]? | m147_[0123]? )
				enterdata
				;;
			esac
		else
			if [ ${fmtflag} != 'b' ]
			then
				# make sure file is in head/cylinder format
				${CONV} -I ${fmtflag} -O c -t ${bfile} ${DTYPE} ${device} >/dev/null 2>&1
		   		if [ $? != 0 ]
		   		then
					echo "\n\tCan't interpret input data.  Check"
					echo "\tthat disktype is defined in dskdefs file.\n"
					exit 1
		   		fi
				TFILE="/tmp/xf_${device}"
			fi
		fi
	
		if [ ${WFLAG} = 'yes' ]
			then
			while read HD CYL LSECT
			do
				if [ "${HD}" = "." ]
		   		then
					break
		   		fi
				echo "\n\tBegin redirection of ${HD}/${CYL}/${LSECT}:\n"
				echo "$HD $CYL $LSECT" | ${FMT} -n ${DTYPE} ${FMTDEV} 1>/dev/null 2>&1
			if [ $? -ne 0 ]
			then
				echo "\nThe track redirection failed.  No files are updated.\n"
					rm -f /tmp/xf_*
				exit 1
			fi
			rm -f ${ETC}/badtracks/F.${device}*
			echo "$HD $CYL" | ${GEN} ${DTYPE} ${device} 1>/dev/null 2>&1
			if [ -f ${ETC}/badtracks/F.${device}* ]
			then
echo "\n\tFsck will now be run on the disk to repair any"
echo "\tdamage done by redirecting ${HD}/${CYL}/${LSECT} "
echo "\tbefore any other redirections are attempted."
				FSCKFILE=`ls ${ETC}/badtracks/F.${device}*`
				filesys=`echo ${FSCKFILE} | cut -d'.' -f2`
    				fsckdev=/dev/rdsk/${filesys}
				${FSCK} ${fsckdev}
				rm -f ${ETC}/badtracks/F.${device}*
			else
echo "\n\tTrack not in filesystem;  No file system repair needed.\n"

			fi
			done < ${TFILE}
			rm -f /tmp/xf_*
			case $device in
	    		m327_[0123]? | m327_1d[0123]? | m147_[0123]? )
				;;
			*)
		    		# update the bad track list in ${ETC}/badtracks
				list=`${FMT} -r ${DTYPE} ${FMTDEV} 2>/dev/null` 
				if [ $? != 0 ]
				then
					echo "\n\tCan't read disk bad track list.  The file"
					echo "\t'${ETC}/badtracks/${device}' has not been updated."
				else
					echo "${list}" >> ${ETC}/badtracks/${device}
					echo "\n\tThe file '${ETC}/badtracks/${device}' has been"
					echo "\tupdated to reflect the bad track list contained on the disk.\n"
				fi
				;;
			esac
		else
			# Make the files with block numbers for fsck
			case $device in
	    		m320_[01] | m320_1d[01])
				cp ${TFILE} ${CUTFILE}  # no change to file
				;;
	    		*)
				cutfile		# get rid of sector field
		    		;;
			esac
			${GEN} -t ${CUTFILE} ${DTYPE} ${device} >/dev/null 2>&1
			if [ $? != 0 ]
			then
				echo "\n\tCan't generate file system block numbers."
				exit 1
			fi
			rm -f /tmp/xf_*
			fslist=`ls ${ETC}/badtracks/F.* 2>/dev/null`
			if [ -n "${fslist}" ]
			then
				echo "\nThese fsck input files have been created:\n"
				echo "${fslist} \n"
				echo "\nYou may now select the 'fixfsys' option of this menu to find"
				echo "out which files will be affected by a track redirection.\n"
			else
				echo "\nNo file systems will be affected by a track redirection\n"
			fi
		fi
		exit 0
		;;
	change )
		;;
	esac
done
