#!/sbin/sh
#
# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# ident	"@(#)install-recovery.sh	1.2	06/03/21 SMI"

#
# This script looks for installed Solaris instances to facilitate
# user recovery of corrupt rootfs
#

validate_ckyorn()
{
	if [ $1 = y ] || [ $1 = Y ] || [ $1 = yes ] || [ $1 = Yes ] || \
	    [ $1 = yEs ] || [ $1 = YEs ] || [ $1 = yeS ] || [ $1 = YeS ] || \
	    [ $1 = yES ] || [ $1 = YES ] ; then
		echo y
	else
		echo n
	fi
}

update_archive()
{
	dev=$1

	printf "\nAn out of sync boot archive was detected on $dev.\n"

	printf "The boot archive is a cache of files used during boot and\n"
	printf "should be kept in sync to ensure proper system"
	printf " operation.\n"

	help="This will fsck if needed, mount, and update the boot archive"
	prompt="Do you wish to automatically update this boot archive?"
	ans=`/usr/bin/ckyorn -Q -p "${prompt}" -h "${help}"`
	ans=`validate_ckyorn $ans`
	if [ "$ans" = "y" ] ; then
		umount /a 2> /dev/null
		fsck_and_mount $dev
		echo Updating boot archive on $dev.
		bootadm update-archive -R /a > /dev/null
		# If bootadm fails, it's pretty verbose on stderr. If it
		# succeeds, it is silent. In this case however, clear
		# positive indication of success is desirable:
		if [ $? = 0 ] ; then
			echo The boot archive on $dev was updated successfully.
		fi
		umount /a
	fi
}

update_md_msg()
{
	printf "To manually recover the boot archive on a root mirror,"
	printf "mount the first\nside (the one that the system boots from)"
	printf " and run:\n\n\tbootadm update-archive -R <mount_point>"
	printf "\n\n"
}

find_OS_roots()
{
	for Dev in /dev/dsk/*s[0-7]; do
		Typ=`/usr/sbin/fstyp $Dev 2> /dev/null`
		if [ "X${Typ}" = Xufs ]; then
			/sbin/mount -o ro -F ufs $Dev /a
			status=$?

			if [ ${status} != 0 ]; then
				echo "Failed to mount $Dev read-only: skipping."
				continue;
			fi

			if [ -f /a/etc/release ]; then
				/sbin/bootadm update-archive -n -R /a \
				    > /dev/null 2>&1
				if [ $? = 0 ] ; then
					ARCHIVE=synced
				else
					ARCHIVE=faulted
				fi

				# Check if this root is under md control.
				# If it is, leave it alone.
				MD=`grep "[	 ]/[ 	]" /a/etc/vfstab | \
				    grep "^/dev/md"`
				if [ -n "$MD" ] ; then
					echo $Dev is under md control, skipping.
					if [ $ARCHIVE = faulted ] ; then
						update_md_msg
					fi
					umount /a
					continue;
				fi

				OS_found=`expr $OS_found + 1`
				rel=`sed -n '1s/^ *//p' /a/etc/release`

				if [ $ARCHIVE = faulted ] ; then
					update_archive $Dev
				fi

				echo $rel >> $rel_list

				OS_rootdevs="$OS_rootdevs $Dev"
			fi
			umount /a 2> /dev/null
		fi
	done
}

fsck_and_mount()
{
	dsk=$1
	rdsk=`echo $dsk | sed "s#/dsk/#/rdsk/#"`

	fsck -m -F ufs $rdsk > /dev/null 2>&1
	if [ $? != 0 ] ; then
		fsck -F ufs $rdsk
	fi
	umount /a 2> /dev/null
	mount $dsk /a
}

OS_found=0
OS_rootdevs=

rel_list=/tmp/rel_list.$$

mnthelp="Check and mount the selected root device read-write."
mntprompt="Do you wish to have it mounted read-write on /a?"

echo "Searching for installed OS instances..."
find_OS_roots

if [ $OS_found -eq 0 ]; then
	echo "No installed OS instance found."
elif [ $OS_found -eq 1 ]; then
	dev=`echo $OS_rootdevs`
	rel=`cat $rel_list`
	printf "\n$rel was found on $dev."
	ans=`/usr/bin/ckyorn -Q -p "${mntprompt}" -h "${mnthelp}"`
	ans=`validate_ckyorn $ans`
	if [ "$ans" = "y" ] ; then
		echo "mounting $dev on /a"
		fsck_and_mount $dev
	fi
else
	printf "\nMultiple OS instances were found. To check and mount "
	printf "one of them\nread-write under /a, select it from the "
	printf "following list. To not mount\nany, select 'q'.\n"

	item=1
	itemlist=/tmp/itemlist_$$
	rm -f $itemlist
	for dev in $OS_rootdevs ; do
		rel=`head -$item $rel_list | tail -1`
		printf "$dev\t$rel\n" >> $itemlist
		item=`expr $item + 1`
	done

	prompt="Please select a device to be mounted (q for none)"
	dev=`/usr/bin/ckitem -p "${prompt}" -h "${mnthelp}" -f $itemlist`
	rm $itemlist
	if [ "$dev" != "q" ] ; then
		echo "mounting $dev on /a"
		fsck_and_mount $dev
		break
	fi
fi

rm -f $rel_list

printf "\nStarting shell.\n"
/sbin/sulogin
