#!/bin/ksh
#
# ident "@(#)utprepmount.ksh	1.18	06/05/23 SMI"
#
# Copyright 2004-2006 Sun Microsystems, Inc.  All Rights Reserved.
# Use is subject to license terms.
#
# utprepmount:
# This script is used by the Sun Ray mounter utility
# It is not meant for general use
#

PATH="/bin:/usr/bin:/usr/sbin"

# Sun Ray paths
SUNWUTPATH=""
SUNWUTSESSIONS=""
SUNWUTSESSUNIT="unit"

# Sun Ray utilities
UTDOMOUNTCMD=""

# command line args
ARG_MOUNT=""
ARG_UMOUNT=""
ARG_BLKDEV=""
ARG_UID=""
ARG_XID=""
ARG_SLICE=""
ARG_FSTYPE=""

# program name
PROGNAME=""

# operating platform
OS=""
ISA=""

# find mount path
# $1 = block device path
#
function getmountpoint
{
	TMPMOUNTPOINT="`mount | $AWKCMD '($p == NBLOCKDEV) { print $d }' p=$PARTITION_COLUMN d=$DIRECTORY_COLUMN NBLOCKDEV=$1`"
	if [[ -z $TMPMOUNTPOINT && "X$OS" = "XSunOS" && "X$ISA" = "Xsparc" ]] then
		# look for pcfs suffixes
		for PSUFFIX in :c :d :e :f
		do
			TMPMOUNTPOINT="`mount | $AWKCMD '($p == NBLOCKDEV) { print $d }' p=$PARTITION_COLUMN d=$DIRECTORY_COLUMN NBLOCKDEV=$1$PSUFFIX`"
			if [[ -n $TMPMOUNTPOINT ]] then
				break
			fi
		done
	fi

	print $TMPMOUNTPOINT
}

# find all mount paths for given device pattern
# $1 = block device pattern
#
function getallmounts
{
	mount | $AWKCMD '($p ~ NBLOCKDEVPAT) { print $d }' p=$PARTITION_COLUMN d=$DIRECTORY_COLUMN NBLOCKDEVPAT=$1
}


# find device mounted on this directory
# $1 = mount point
#
function getmountdev
{
	# should be valid directory name
	if [[ -d $1 ]] then
		mount | $AWKCMD '($d == NMNTPATH) { print $p }' p=$PARTITION_COLUMN d=$DIRECTORY_COLUMN NMNTPATH=$1
	fi
}


# mount block device node
#
function do_mount
{
	USER_ID=$ARG_UID
	BLKDEVPATH=$ARG_BLKDEV
	DISPLAY_ID=$ARG_XID
	SLICENUM=$ARG_SLICE

	if [[ -z $USER_ID ]] then
		print -u2 "$PROGNAME: Invalid user id"
		return 1
	fi

	if [[ -z $DISPLAY_ID ]] then
		print -u2 "$PROGNAME: Invalid display id"
		return 1
	fi

	# is this a valid block device
	if [[ ! -b $BLKDEVPATH ]] then
		print -u2 "$PROGNAME: Invalid device name $BLKDEVPATH"
		return 1
	fi

	# see whether already mounted (shouldn't be)
	MNTPT="`getmountpoint $BLKDEVPATH`"

	if [[ -z $MNTPT ]] then
		# check with session path
		UNITDEVSUFFIX="`echo $BLKDEVPATH \
					| sed -n 's:^.*/\(dev/dsk/.*\):\1:p'`"
		# /tmp/SUNWut/sessions/4/unit/dev/dsk/disk1s4
		BLKSESSPATH=$SUNWUTSESSIONS/$DISPLAY_ID/$SUNWUTSESSUNIT/$UNITDEVSUFFIX
		if [[ -b $BLKSESSPATH ]] then
			MNTPT="`getmountpoint $BLKSESSPATH`"
		fi
	fi

	if [[ -n $MNTPT ]] then
		print -u2 "$PROGNAME: $BLKDEVPATH already mounted at $MNTPT"
		return 1
	fi

	if [[ "X$OS" = "XSunOS" ]] then
		RAWDEVLINK="`echo $BLKDEVPATH \
				| sed -n 's:/dev/dsk/:/dev/rdsk/:p'`"

		# is this a valid raw device
		if [[ ! -c $RAWDEVLINK ]] then
			print -u2 "$PROGNAME: Invalid device name $BLKDEVPATH"
			return 1
		fi
	fi

	# if utprepmount has been invoked using -F option then just try
	# to mount using that filesystem type

	if [[ -n $ARG_FSTYPE ]] then
		$UTDOMOUNTCMD -m -f $ARG_FSTYPE -b $BLKDEVPATH -i $USER_ID -l
		return $?
	fi

	# if utprepmount has not been invoked using -F option then try
	# looking for a filesystem from our list
	STATUS=1
	PREV_MNT_FAILED=""
	for FS in $FST_LIST
	do
		FSTYPE="`/usr/lib/fs/$FS/fstyp $RAWDEVLINK`"
		STATUS=$?
		if [[ ( $STATUS -eq 0 ) && ( -n $FSTYPE ) ]] then
			# run mount command
			$UTDOMOUNTCMD -m -f $FSTYPE -b $BLKDEVPATH \
							-i $USER_ID -l
			STATUS=$?
			if [[ $STATUS -eq 0 ]] then
				if [[ -n $PREV_MNT_FAILED ]] then
					print "Successfully mounted $FSTYPE on $BLOCKDEVPATH"
				fi
				break
			else
				PREV_MNT_FAILED="1"
			fi
		fi
	done

	PREV_MNT_FAILED=""
	if [[ ( $STATUS -ne 0 ) ]] then
		# try to mount a filesystem from our list
		for FS in $FSM_LIST
		do
			# run mount command
			$UTDOMOUNTCMD -m -f $FS -b $BLKDEVPATH -i $USER_ID -l
			STATUS=$?
			if [[ $STATUS -eq 0 ]] then
				if [[ -n $PREV_MNT_FAILED ]] then
					print "Successfully mounted $FS on $BLOCKDEVPATH"
				fi
				break
			else
				PREV_MNT_FAILED="1"
			fi
		done
	fi

	return $STATUS
}


# unmount filesystem from given block device node
# note that mount point could exist even though block device does not exist
# This script is called when the device is unplugged & links removed
#
function do_umount
{
	USER_ID=$ARG_UID
	BLKDEVPATH=$ARG_BLKDEV
	DISPLAY_ID=$ARG_XID

	if [[ -z $USER_ID ]] then
		print -u2 "$PROGNAME: Invalid user id"
		return 1
	fi

	if [[ -z $DISPLAY_ID ]] then
		print -u2 "$PROGNAME: Invalid display id"
		return 1
	fi

	# strip path prefix to get base name
	DEVBASENAME=${BLKDEVPATH##*/}

	# get device alias by removing partition suffix
	if [[ "X$OS" = "XSunOS" && "X$ISA" = "Xi386" ]] then
		DEVALIAS=${DEVBASENAME%p[0-9]}
	elif [[ "X$OS" = "XSunOS" && "X$ISA" = "Xsparc" ]] then
		DEVALIAS=${DEVBASENAME%s[0-9]}
	elif [[ "X$OS" = "XLinux" ]] then
		DEVALIAS=${DEVBASENAME%p[0-9]}
	else
		print -u2 "$PROGNAME: Unknown platform OS=$OS ISA=$ISA"
		return 1
	fi

	# remove name suffix to get path
	DEVROOT=${BLKDEVPATH%/*}

	if [[ -z $DEVALIAS || -z $DEVROOT ]] then
		print -u2 "$PROGNAME: Invalid device name $BLKDEVPATH"
		return 1
	fi

	# when matching mount points, make sure device name is distinguishable
	# we don't want to match disk11 for disk1, so append suffixes 'p' & 's'

	# unmount all slices
	if [[ "X$OS" = "XSunOS" ]] then
		SLICEPATTERN=${DEVROOT}/${DEVALIAS}"s"
		for i in `getallmounts $SLICEPATTERN`
		do
			# run umount command
			$UTDOMOUNTCMD -u -p $i -i $USER_ID
		done
		# check with session path
		# E.g. /tmp/SUNWut/sessions/4/unit/dev/dsk/disk1s4
		BLKSESSPATH=$SUNWUTSESSIONS/$DISPLAY_ID/$SUNWUTSESSUNIT/dev/dsk/$DEVALIAS"s"
		for i in `getallmounts $BLKSESSPATH`
		do
			# run umount command
			$UTDOMOUNTCMD -u -p $i -i $USER_ID
		done
	fi

	# unmount all fdisk partitions
	PARTPATTERN=${DEVROOT}/${DEVALIAS}"p"
	for i in `getallmounts $PARTPATTERN`
	do
		# run umount command
		$UTDOMOUNTCMD -u -p $i -i $USER_ID
	done
	# check with session path
	# E.g. /tmp/SUNWut/sessions/4/unit/dev/dsk/disk1p4
	BLKSESSPATH=$SUNWUTSESSIONS/$DISPLAY_ID/$SUNWUTSESSUNIT/dev/dsk/$DEVALIAS"p"
	for i in `getallmounts $BLKSESSPATH`
	do
		# run umount command
		$UTDOMOUNTCMD -u -p $i -i $USER_ID
	done

	# On Linux, check specifically whether suffixless whole disk is mounted
	# This name cannot be used for pattern search, so do an exact match
	if [[ "X$OS" = "XLinux" ]] then
		# whole disk node has no suffix
		PARTNAME=${DEVROOT}/${DEVALIAS}
		MNTPT="`getmountpoint $PARTNAME`"

		if [[ -z $MNTPT ]] then
			# check with session path
			# E.g. /tmp/SUNWut/sessions/4/unit/dev/dsk/disk1
			BLKSESSPATH=$SUNWUTSESSIONS/$DISPLAY_ID/$SUNWUTSESSUNIT/dev/dsk/$DEVALIAS
			MNTPT="`getmountpoint $BLKSESSPATH`"
		fi
		if [[ -n $MNTPT ]] then
			# run umount command
			$UTDOMOUNTCMD -u -p $MNTPT -i $USER_ID
		fi
	fi

	return 0
}


# print usage message on stderr
# $n = error message (optional)
#
function showusage
{
	MESSAGE="$*"
	if [[ -n $MESSAGE ]] then
		print -u2 "ERROR: $MESSAGE"
	fi
	print -u2 "usage:"
	print -u2 "\t $PROGNAME -m -i uid -b block_device -d display_id [-s slice] [-F fstype] "
	print -u2 "\t $PROGNAME -u -i uid -b block_device -d display_id"

	exit 1
}


# main
#

# strip path prefix to get program name
PROGNAME=${0##*/}

# Set OS specific variables
OS=`uname -s`
ISA=`uname -p`

case "$OS" in
SunOS)
	IDCMD="/usr/xpg4/bin/id"
	AWKCMD="nawk"
	# list of filesystem types to try fstyp
	FST_LIST="ufs pcfs hsfs udfs"
	# list of filesystem types to try mount
	FSM_LIST="pcfs ufs hsfs udfs"
	PARTITION_COLUMN=3
	DIRECTORY_COLUMN=1
	;;
Linux)
	IDCMD="/usr/bin/id"
	AWKCMD="gawk"
	FST_LIST=""
	FSM_LIST="vfat ext2 iso9660 ntfs ext3 reiserfs"
	PARTITION_COLUMN=1
	DIRECTORY_COLUMN=3
	;;
*)	#undefined OS
	print -u2 "$PROGNAME: Unable to determine the OS running on this system."
	exit 1
esac


# need super user privileges (setuid not allowed)
if [[ "`$IDCMD -u -r`" != "0" ]] then
	print -u2 "$PROGNAME: permission denied"
	exit 1
fi

# setup Sun Ray paths
UTDOMOUNTCMD="/etc/opt/SUNWut/basedir/lib/utdomount"
SUNWUTPATH="/tmp/SUNWut"
SUNWUTSESSIONS=$SUNWUTPATH"/sessions"

# parse options
#
while getopts :b:d:i:ms:uF: vopts
do
	case $vopts in
		b) ARG_BLKDEV=$OPTARG
			;;
		d) ARG_XID=$OPTARG
			;;
		i) ARG_UID=$OPTARG
			;;
		m) ARG_MOUNT="1"
			;;
		s) ARG_SLICE=$OPTARG
			;;
		u) ARG_UMOUNT="1"
			;;
		F) ARG_FSTYPE=$OPTARG
			;;
		\?) showusage "Invalid option -$OPTARG"
			;;
		:) showusage "Required argument missing"
			;;
	esac
done

# check mutually exclusive operations
if [[ ( -n $ARG_MOUNT ) && ( -n $ARG_UMOUNT ) ]] then
	showusage "bad args: $*"
fi

# carry out operation
if [[ -n $ARG_MOUNT ]] then
	do_mount
else
	if [[ -n $ARG_UMOUNT ]] then
		do_umount
	else
		showusage "-m or -u option required"
	fi
fi

exit $?
