#!/bin/sh
# $Id$
#
# Description:	UFS/NFS filesystem failover script
#		Reads <RSFDIR>/etc/fs/vfstab.<service> for filesystems to (un)mount
#
# Platform:	Solaris
#
# Author:	High-Availability.Com Ltd
#

#
# standard variables and functions
#
. /opt/HAC/bin/rsf.sh

service=${RSF_SERVICE:-"servicename"}
vfstab="${PRODUCT_ETC}/fs/vfstab.${service}"	# filesystem table
dfstab="${PRODUCT_ETC}/fs/dfstab.${service}"	# NFS exports table

# functions

#
# checkfs
# - Check Solaris filesystems with fsck
# args: filesystem type, device to check (raw)
# ret: standard RSF-1 exit codes
#
checkfs()
{
	_fstype=$1
	_checkdev=$2
	
	# sanity check
	fsck -F ${_fstype} -m ${_checkdev} >/dev/null 2>&1
	fsckret1=$?

	case ${fsckret1} in
	0)
		# OK
		echo "done."
		;;
	32)
		# corruption, check deeper
		echo "checking deeper ... \c"
		case "${_fstype}" in
		vxfs)
			# always someone who has to be different...
			fsck -F ${_fstype} -y ${_checkdev} >/dev/null 2>&1
			fsckret2=$?
			;;
		*)
			# UFS and all others
			fsckout=`fsck -F ${_fstype} -o p ${_checkdev} 2>&1`
			fsckret2=$?
			;;
		esac

		case ${fsckret2} in

		0 | 40)
			# OK
			echo "done."
			;;
		36 | 37 | 39)
			# failed
			echo "failed!"
			dated_echo "*** ERROR - Unable to repair ${_checkdev} ***"
			dated_echo ${fsckout}
			dated_echo "Run fsck manually (fsck -F ${_fstype} ${_checkdev})"
			dated_echo "Aborting ${state}"
			return ${COMPANY_ABORT}
			;;
		34)
			# couldn't stat device
			echo "failed!"
			dated_echo "*** ERROR - Unable to access ${_checkdev} ***"
			dated_echo "Aborting ${state}"
			return ${COMPANY_ABORT}
			;;
		*)
			# misc errors
			echo "failed!"
			dated_echo "*** ERROR - second fsck returned ${fsckret2} ***"
			dated_echo ${fsckout}
			dated_echo "Fix the problem manually before proceeding"
			dated_echo "Aborting ${state}"
			return ${COMPANY_ABORT}
			;;
		esac
		;;
	33)
		# already mounted
		echo "already mounted, proceeding"
		break
		;;
	*)
		# unknown error
		echo "failed!"
		dated_echo "*** ERROR - initial fsck returned ${fsckret1} ***"
		dated_echo "Fix the problem manually before proceeding"
		dated_echo "Aborting ${state}"
		return ${COMPANY_ABORT}
		;;
	esac
}

#
# mountfs
# - Mount a filesystem
# args: filesystem, mount point, mount options
# ret: standard RSF-1 exit codes
#
mountfs()
{
	_fstype=$1
	_dev=$2
	_mntpt=$3
	_mntopts=$4

	case "${_mntpt}" in
	"-")
		# do nothing
		:
		;;
	*)
		if [ ! -d "${_mntpt}" ]; then
			dated_echo "creating mount point ... \c"
			mkdir -p "${_mntpt}"
			if [ $? -ne 0 ]; then
				echo "failed!"
				dated_echo "Failed to create mount point for ${_mntpt}, aborting"
				return ${COMPANY_ABORT}
			fi
		fi


                if [ "${_mntopts}" = "-" ]; then
		  mountout=`mount -F ${_fstype} -O ${_dev} ${_mntpt} 2>&1`
                else 
		  mountout=`mount -F ${_fstype} -O -o ${_mntopts} ${_dev} ${_mntpt} 2>&1`
                fi

		case $? in
		0)
			echo "done"
			;;
		16)	# 16 - vxfs
			echo "already mounted, proceeding"
			;;
		32 | 33)
			echo "mount point is busy, assuming already mounted and proceeding"
			echo "Message from $mountout"
			;;
		*)
			echo "failed!"
			dated_echo "Failed to mount ${_mntpt}:"
			dated_echo ${mountout}
			dated_echo "Aborting ${state}"
			return ${COMPANY_ABORT}
			;;
		esac
		;;
	esac
}

#
# Main
#

script="`basename $0`"
state=$1
attempts=${2:-'1'}	# no of attempts at this action

# abort after three attempts
if [ ${attempts} -gt 3 ]; then
	# fail after three goes
	dated_echo "Too many retries on ${state}, aborting"
	exit ${COMPANY_ABORT}	# abort code
fi

# check filesys table is present
if [ ! -f "${vfstab}" ]; then
	dated_echo "No ${vfstab} file present, aborting"
	exit ${COMPANY_ABORT}
fi

#
# decide action based on first argument
#
case "${state}" in

'start')
	dated_echo "Checking and mounting filesystems in ${vfstab}"
	# read vfstab file, line by line
	exec < ${vfstab}
	while read dev checkdev mount fstype pass mntboot opts; do
		case ${dev} in
		'#'* | '' | '-')
			continue
			;;
		esac

		if [ "${checkdev}" != "-" ]; then
			dated_echo "Checking ${checkdev} ... \c"
			checkfs ${fstype} ${checkdev}
			checkret=$?
			if [ ${checkret} -gt 1 ]; then
				exit ${checkret}
			fi
		fi

		dated_echo "Mounting ${mount} ... \c"
		mountfs ${fstype} ${dev} ${mount} ${opts}
		mntret=$?
		if [ ${mntret} -gt 1 ]; then
			exit ${mntret}
		fi
	done

	if [ -f "${dfstab}" ]; then	# NFS
		dated_echo "Sharing filesystems in ${dfstab}"
		shareall ${dfstab} >/dev/null 2>&1
	fi

	;;

'stop')
	dated_echo "Unmounting filesystems in ${vfstab}"
	abort=0	# flag
	for mount in `awk '!/^#/ { print $3 }' ${vfstab}`; do
		case ${mount} in
		'-')
			continue
			;;
		esac

		unshare ${mount} >/dev/null 2>&1
		dated_echo "Unmounting ${mount} ... \c"
		mount -p | egrep -s " ${mount} "
		if [ $? -ne 0 ]; then
			echo "not mounted, skipping"
			continue
		fi

		umount ${mount} >/dev/null 2>&1
		if [ $? -eq 0 ]; then
			echo "done"
		else
			echo " failed, attempting to kill active processes ... \c"
			fuser -c -k ${mount} >/dev/null 2>&1
			sleep 3
			umntout=`umount ${mount} 2>&1`
			if [ $? -eq 0 ]; then
				echo "done"
			else
				echo "failed!"
				dated_echo "Attempting forceable unmount ... \c"
                                umntout=`umount -f ${mount} 2>&1`
                                if [ $? -eq 0 ]; then
					echo "done"
				else
					echo "failed!"
					dated_echo "*** WARNING - cannot unmount ${mount} ***"
					dated_echo "Error was:"
					dated_echo ${umntout}
					dated_echo "*** Please check! ***"
					abort=1	# abort after all unmounts
				fi
			fi
		fi
	done

	# signal abort if we partially failed
	if [ ${abort} -eq 1 ]; then
		dated_echo " *** Aborting ${state} because one or more filesystems could not be unmounted"
		exit ${COMPANY_ABORT}
	fi

	;;

*)
	echo "Usage: $0 <start|stop>"
	exit ${COMPANY_WARN}	# warning code
	;;

esac

exit ${COMPANY_OK}	# OK code (default)
