#!/bin/bash
#
# Filesystem services, based on available partition number (i.e. 1), as 
# opposed to absolute partition (i.e. /dev/sda3)
#
# Currently, options are not supported to the mkfs commands.  They will be added
# if the need arises
#
# optparam prefix "--partition" value M Set the partition number on which to operate"
# optparam prefix "--print-max" Print the maximum usable partition number"
# optparam prefix "--print" Print the devicename of the partition N
# optparam prefix "--mount" value N [-l LOC] [-o OPT]: Mount the Nth partition at $AUTODIR/var/mnt/N/ or LOC, with options OPT
# optparam prefix "--umount" value N: Unmount the Nth partition"
# optparam prefix "--mkext2fs" value N OPTS: Make an ext2 fs on the Nth partition"
# optparam prefix "--mkext3fs" value N OPTS: Make an ext3 fs on the Nth partition"
# optparam prefix "--mkjfs" value N OPTS: Make a jfs fs on the Nth partition"
# optparam prefix "--mkreiserfs" value N OPTS: Make a reiser fs on the Nth partition"
# optparam prefix "--mkxfs" value N OPTS: Make an xfs fs on the Nth partition"
# optparam prefix "-mount-ramfs" LOC: Mount a ramfs at $AUTODIR/var/mnt/ramfs or LOC
#
# If your test requires running on a machine with raw disks, you need to 
# specify that in the class parameter, just like ip_address, or number of cpus.  
# For instance:
# class machine_with_disks 	\
#	num_cpus>=8 		\
#	free_partitions>=1
#
# Would run your test on at least an 8-way with at least one free partition.  
# You could use that partition with the fs script like this:
#		fs -mkext3fs 1
#		fs -mount -text3 1 /test/mount/point
#		dbench 1 /test/mount/point
#		fs -unmount 1
#
# --partition format:
# 	N format:
#		get the Nth partition.  If there are DATS_FREE_PARTITIONS, then
#		use them first.  If there aren't, go looking through all of the
# 		DATS_FREE_DISKS, and find their partitions.  The Nth found
#		partition will be selected
#	M:N format:
#		Go to the Mth DATS_FREE_DISK, and then select the Nth partition
#		on that disk
#		
#		If M is 0, then partition N will be selected from the 
#		DATS_FREE_PARTITIONS, just like in the "N format" section

. /etc/autobench.conf || . functions

SCRIPT_NAME=$0

function print_usage() {
	echo "$0:"
	echo -e "\t --print-max"
	echo -e "\t	 Print the maximum usable partition number"
	echo -e "\t --partition=N"
	echo -e "\t	 Set the Nth partition as the target"
	echo -e "\t --print"
	echo -e "\t	 Print the devicename of partition"
	echo -e "\t --mount [-l LOC] [-o OPT]"
	echo -e "\t	 Mount the partition at $AUTODIR/var/mnt/N/ or LOC, with options OPT"
	echo -e "\t --umount"
	echo -e "\t	 Unmount the partition"
	echo -e "\t --mkext2fs [NO_OPTS]"
	echo -e "\t	 Make an ext2 fs on the partition"
	echo -e "\t --mkext3fs [NO_OPTS]"
	echo -e "\t	 Make an ext3 fs on the partition"
	echo -e "\t --mkjfs [NO_OPTS]"
	echo -e "\t	 Make a jfs fs on the partition"
	echo -e "\t --mkreiserfs [NO_OPTS]"
	echo -e "\t	 Make a reiser fs on the partition"
	echo -e "\t --mkxfs [NO_OPTS]"
	echo -e "\t	 Make an xfs fs on the partition"
	echo -e "\t --mount-ramfs [LOC]"
	echo -e "\t	 Mount a ramfs at $AUTODIR/var/mnt/tmp or LOC"
	exit 1
}

function field {
	local FORMAT=" ";
	for i in $*; do
		FORMAT="$FORMAT \$$i,";
	done < /dev/null;
	#strip off the trailing ','
	FORMAT=${FORMAT/%,/}
	awk "{print $FORMAT}" 
}

function check_mount_point {
	if [ -z "$LOC" ]; then 
		echo
		exit 2;
	fi;
	echo "$LOC"
}

function ls_disk_partitions {
	DISK=$1
	echo `sfdisk -l $DISK 		\
		| grep "^$DISK" 	\
		| grep -v "Empty" 	\
		| grep -v "Extended" 	\
		| field 1`
}

TEMP=`getopt -o l:o: --long partition:,print-max,print,mount,umount,mkext2fs,mkext3fs,mkjfs,mkreiserfs,mkxfs -n "fs" -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
eval set -- "$TEMP"

# Figure out the name of the partition they asked for.
function partition_name {
	ARG=$1;
	# What format did they specify the partition in?
	if echo $ARG | grep -q ":"; then
		# X:Y format
		DISK_NUM=`echo $ARG | cut -f1 -d:`
		PART_NUM=`echo $ARG | cut -f2 -d:`
		# partition numbering is zero-based, fields are 1-based
		if [ $DISK_NUM -eq 0 ]; then
			# They want from the free partition list
			PARTITION=`echo $DATS_FREE_PARTITIONS \
					| field $PART_NUM 2> /dev/null`
			if [ -n "$PARTITION" ]; then
				FOUND=yes
			fi
		else 
			DISK=`echo $DATS_FREE_DISKS" " | field $DISK_NUM`
			if [ -n "$DISK" ]; then
				if [ $PART_NUM -eq 0 ]; then
					PARTITION=$DISK
					FOUND=yes
				else
					PARTITIONS=`ls_disk_partitions $DISK`
					PARTITION=`echo $PARTITIONS" " \
							| field $PART_NUM`
					if [ -n "$PARTITION" ]; then
						FOUND=yes
					fi
				fi
			else
				echo error: disk $DISK_NUM not found
				exit 4;
			fi
		fi
	else
		# N format
		# Figure out what the name of the Nth partition is.
		echo n format >&2
		PARTITION_FIELD=$ARG
		PARTITION=`echo $DATS_FREE_PARTITIONS | field $PARTITION_FIELD`
		echo PARTITION=\'$PARTITION\' >&2
		if [ "$PARTITION_FIELD" -lt "1" ]; then
			echo error: partition numbering starts at 1 >&2
			exit 5;
		fi
		if [ -z "$PARTITION" ]; then
			# N is > the number of partitions listed, use the free disks now
			COUNT=`echo $DATS_FREE_PARTITIONS | wc -w`
			PARTNUM=$ARG
			OFFSET=$((PARTNUM-COUNT))

			for DISK in $DATS_FREE_DISKS; do
				PARTITIONS=`ls_disk_partitions $DISK`
				PART_COUNT=`echo $PARTITIONS | wc -w`
				if [ $OFFSET -le $PART_COUNT ]; then
					PARTITION=`echo $PARTITIONS | field $OFFSET`
					FOUND=yes
					break
				fi
				OFFSET=$(($OFFSET-$PART_COUNT))
			done
		else
			FOUND=yes
		fi
		if [ "$ARG" -eq 0 ]; then
			unset FOUND
		fi
	fi
	if [ -z "$FOUND" ]; then
		echo "There are not a $ARG(th) partition" >&2
		exit 2
	fi
	echo $PARTITION
}

function check_partition {
	if [ -z "$PARTITION" ] ; then
		echo $SCRIPT_NAME: $1 must be given a partition
		exit 2;
	fi;
}

while true; do
case $1 in
	-l)
		MOUNT_POINT=$2
		shift 2;
		;;
	-o)
		MOUNT_OPTS=$2
		shift 2;
		;;
	--partition)
		PARTITION=`partition_name $2`
		if [ -z "$PARTITION" ] ; then
			echo invalid partition: $2
			exit 3;
		fi
		shift 2;
		;;
	--print-max)
		#Count the partitions
		COUNT=`echo $DATS_FREE_PARTITIONS | wc -w`
		for DISK in $DATS_FREE_DISKS; do
			PARTITIONS=`ls_disk_partitions $DISK`
			PART_COUNT=`echo $PARTITIONS | wc -w`
			COUNT=$(($COUNT+$PART_COUNT))
		done
		echo $COUNT
		shift;
		;;
	--print)
		check_partition
		echo $PARTITION
		shift;
		;;

	--mount*)
		if [ "$1" == "--mount-ramfs" ]; then
			PARTITION="-t ramfs";
		else
			check_partition $1;
			umount -f $PARTITION 2> /dev/null
		fi;
		if [ "$2" == "-l" ]; then
			MOUNT_POINT=$3;
			shift 2;
		fi
		if [ -z "$MOUNT_POINT" ]; then
			MOUNT_POINT=$AUTODIR/var/mnt/$2
		fi;
		if [ -n "$MOUNT_OPTS" ]; then
			MOUNT_OPTS="-o $MOUNT_OPTS"
		fi
		mkdir -p $MOUNT_POINT
		mount $PARTITION $MOUNT_POINT $MOUNT_OPTS
		shift;
		;;

	--umount)
		check_partition $2;
		umount -f $PARTITION 2> /dev/null
		shift;
		;;

	--mkext2fs)
		check_partition $2;
		umount -f $PARTITION 2> /dev/null
		echo y | mkfs -t ext2 $PARTITION
		shift;
		;;

	--mkext3fs)
		check_partition $1;
		umount -f $PARTITION 2> /dev/null
		echo y | mkfs -t ext2 -j $PARTITION
		shift;
		;;

	--mkjfs)
		check_partition $1;
		umount -f $PARTITION 2> /dev/null
		if [ $# -ge 3 ]; then
			OPTIONS="-j $3"
		fi
		mkfs -t jfs -q $PARTITION
		shift;
		;;

	--mkreiserfs)
		check_partition $1;
		umount -f $PARTITION 2> /dev/null
		echo y | mkfs -t reiserfs -f $PARTITION
		shift;
		;;

	--mkxfs)
		check_partition $1;
		umount -f $PARTITION 2> /dev/null
		mkfs -t xfs -f $PARTITION
		shift;
		;;

	--) shift ; break ;;
	*)
		print_usage
		exit 1;
		;;
esac
done
