#/bin/sh
#
#	mount/umount SUSE Linux Product ISO images via loop back
#
#	Author: Christian.Lorenz@novell.com
#
#	Copyright (c) 2006 SUSE LINUX GmbH, Germany. All rights reserved.
# 	GNU Public License
#


################################################################################
#
#	do some setups
#
BASEPATH="/srv/inst/mediasets/"
ISOMNT="/tmp/isomnt/"
CDROMDEV="/dev/cdrom"
MOUNTOPTIONS="ro"


################################################################################
#
#	initialize some variables
#
declare -a ISOS
NUM_OF_ISOS=0
VERBOSE=0
CMD=""
BLOCKSIZE=2048
BLOCKBURST=64k

################################################################################
#
#	print a message as an info 
#
info()
{
	echo "INFORMATION: $*"
}


################################################################################
#
#	print a message as a warning
#
warn()
{
	echo "WARNING: $*"
}


################################################################################
#
#	print a message and exit
#
die()
{
	echo "ERROR: $*"
	exit 1
}


################################################################################
#
#	check if we run with root permissions
#
if [ $( id --user ) != 0 ]; then
	die "this script has to be run with root permissions"
fi


################################################################################
#
#	check for the number of possible loop devices
#
MAJOR=$( grep loop /proc/devices | cut -c1-3 | tr -d ' ' )
MAXLOOP=$( grep "$MAJOR.*loop" /proc/diskstats | wc -l )
MAXLOOPDEVS=$( ls /dev/loop* | wc -l )
#echo "MAXLOOP=$MAXLOOP"
#echo "MAXLOOPDEVS=$MAXLOOPDEVS"
if [ $MAXLOOPDEVS -lt $MAXLOOP ]; then
	info "creating missing loop devices ..."
	LOOP=0
	while [ $LOOP -lt $MAXLOOP ]; do
		LOOPNODE="/dev/loop$LOOP"
		if [ ! -e $LOOPNODE ]; then
			info "creating $LOOPNODE"
			mknod $LOOPNODE b $MAJOR $LOOP
		fi
		LOOP=$(( $LOOP + 1 ))
	done
fi


################################################################################
#
#	create the temporary ISO mount point
#
mkdir --parents $ISOMNT


################################################################################
#
#	inspect the given ISOFILE
#
getisoidentifier()
{
	ISOFILE="$1"
	ISOMNT="$2"
	PRODUCT="-"
	VERSION=""
	ARCH=""
	MEDIA=""
	LABEL=""
	MEDIASETPATH=""

	#
	#	in case of a file, we have to do a loopback
	#
	if [ -f "$ISOFILE" ]; then
		[ "$MOUNTOPTIONS" != "" ] && MOUNTOPTIONS=",$MOUNTOPTIONS"
		MOUNTOPTIONS="loop$MOUNTOPTIONS"
	fi

	#
	#	mount the ISO and have a look at it
	#
	mount -o $MOUNTOPTIONS "$ISOFILE" "$ISOMNT"

	if [ -r $ISOMNT/content ]; then
		#
		#	get some informations about the ISO image
		#
		PRODUCT="$( grep "^PRODUCT " $ISOMNT/content | cut -f2- -d ' ' | tr ' ' '-' )"
		VERSION="$( grep "^VERSION " $ISOMNT/content | cut -f2- -d ' ' | tr ' ' '-' )"
		ARCH="$( grep "^DEFAULTBASE " $ISOMNT/content | cut -f2- -d ' ' | tr ' ' '-' )"
		LABEL="$( grep "^LABEL " $ISOMNT/content | cut -f2- -d ' ' )"
		MEDIAFILE="$( echo $ISOMNT/media.* )"
		if [ -r $MEDIAFILE ]; then
			MEDIA="$( basename $MEDIAFILE | cut -f2- -d. )"
		else
			die "unknown media"
		fi
	fi

	#
	#	umount the ISO image again
	#
	umount $ISOMNT

	echo "$PRODUCT" "$VERSION" "$ARCH" "CD$MEDIA" "$LABEL"
}


################################################################################
#
#	show the usage
#
show_usage()
{
	[ "$*" != "" ] && echo "$*"
cat <<-EOM
Usage: $0 <command> [options] <ISO file> ...
Options are:
    -h
    --help                     Show this message and exit.
    -V
    --version                  Show version and exit.
    -v
    --verbose                  Increase verbosity.
    -b <str>
    --basepath <str>           Set a mediaset basepath where all ISO images
                               will be mounted to
    -d <cdrom device>
    --device <cdrom device>    Specify the cdrom device (default: /dev/cdrom)

Available commands are: 

    info                       Get some information about an ISO image
    mount                      Mount all specified ISO images
    umount                     Umount the specified ISO images
    rename                     Rename the specified ISO images according to
                               information found in the ISO image
    readiso                    Read the ISO image from the specified device
                               and store it under the name according the
                               information found in the ISO image under the
                               base path
EOM
	[ "$*" != "" ] && exit 1
	exit 0
}


################################################################################
#
#	check the arguments
#
while [ "$1" != "" ]; do
	if [ "$( echo "#$1" | cut -c2 )" = '-' ]; then
		case "$1" in
			-h|--help)
				#
				#	show the usage
				#
				show_usage
				exit 0
				;;
			-V|--version)
				#
				#	show the version
				#
				echo '$Id: image2mpeg,v 1.34 2005/12/12 11:52:15 gromeck Exp $'
				exit 0
				;;
			-v|--verbose)
				#
				#	verbosity level
				#
				VERBOSE=1
				;;
			-b|--basepath)
				#
				#	set the mediaset basepath
				#
				shift
				BASEPATH="$1"
				;;
			-d|--device)
				#
				#	set the cdrom device
				#
				shift
				CDROMDEV="$1"
				;;
			*)
				#
				#	unknown option
				#
				echo "$0: unknown option '$1'"
				show_usage
				exit 1
				;;
		esac
	else
		if [ "$CMD" = "" ]; then
			case "$1" in
				help|HELP)
					#
					#	help!
					#
					CMD="help"
					show_usage
					exit 0
					;;
				info|INFO)
					#
					#	get some information about the ISO image
					#
					CMD="info"
					VERBOSE=1
					;;
				mount|MOUNT)
					#
					#	mount ISOs
					#
					CMD="mount"
					;;
				umount|UMOUNT)
					#
					#	umount ISOs
					#
					CMD="umount"
					;;
				rename|RENAME)
					#
					#	rename ISO images
					#
					CMD="rename"
					;;
				readiso|READISO)
					#
					#	read ISO image from the given device
					#
					CMD="readiso"
					;;
			esac
		else
			#
			#	add the given files to the list of ISOs
			#
			[ ! -r "$1" ] && warn "Couldn't access '$1' -- ignoring!"
			ISO[$NUM_OF_ISOS]="$1"
			NUM_OF_ISOS=$(( $NUM_OF_ISOS + 1 ))
		fi
	fi
	shift
done

################################################################################
#
#	check the number of ISO files & max loops
#
if [ "$CMD" = "mount" ] && [ $NUM_OF_ISOS -gt $MAXLOOP ]; then
	cat <<EOM
You only got $MAXLOOP loop devices configured in your system, which
is exceeded by the number of ISO images ($NUM_OF_ISOS) you are trying to mount.

You have to increase the number of loop devices by setting the kernel
parameter 'max_loop=<number of loop devices>'. You should add this
parameter to /boot/grub/menu.lst to make this change permanently.
EOM
	exit 1
fi


################################################################################
#
#	if we have to read an iso image we will reset the ISO array and
#	add the CDROM device as the only ISO file
#
if [ "$CMD" = "readiso" ]; then
	unset ISOS
	declare -a ISOS
	ISO[0]="$CDROMDEV"
	NUM_OF_ISOS=1
fi


case "$CMD" in
	info|mount|umount|rename|readiso)
		################################################################################
		#
		#	info
		#	mount
		#	umount
		#	rename
		#	readiso
		#
		#
		#	in case of a file, we have to do a loopback
		#
		[ "$MOUNTOPTIONS" != "" ] && MOUNTOPTIONS=",$MOUNTOPTIONS"
		MOUNTOPTIONS="loop$MOUNTOPTIONS"
		for ISOFILE in ${ISO[*]}; do
			#
			#	get the info about the ISO file
			#
echo "ISOFILE:$ISOFILE"
			read PRODUCT VERSION ARCH MEDIA LABEL <<-EOM
				$( getisoidentifier "$ISOFILE" "$ISOMNT" )
			EOM
			if [ "$PRODUCT" = "-" ]; then
				warn "$ISOFILE is not a SUSE/Novell product ISO image"
				continue;
			fi
			MEDIASETPATH="$BASEPATH/$PRODUCT/$VERSION/$ARCH/$MEDIA"

			#
			#	check if the ISOFILE is mounted
			#
			MOUNTED="no"
			[ $( mount | grep "^$ISOFILE on $MEDIAPATH" | wc -l ) -gt 0 ] && MOUNTED="yes"

			#
			#	depending on the mode, we will do ...
			#
			if [ $VERBOSE != 0 ]; then
				echo "$ISOFILE: Product: $PRODUCT"
				echo "$ISOFILE: Verstion: $VERSION"
				echo "$ISOFILE: Architecture: $ARCH"
				echo "$ISOFILE: Media: $MEDIA"
				echo "$ISOFILE: Mediaset Path: $MEDIASETPATH"
				echo "$ISOFILE: Mounted: $MOUNTED"
			fi
			if [ $CMD = "info" ]; then
				printf "%-40s %-20s %-10s %-5s %-20s\n" "$PRODUCT" "$VESION" "$ARCH" "CD$MEDIA" "$LABEL"
				printf "\t$ISOFILE => $MEDIASETPATH\n"
			fi
			if [ $CMD = "rename" ]; then
				#
				#	rename the ISO image file
				#
				NEWISOFILE="$( dirname "$ISOFILE" )/$PRODUCT-$VERSION-$ARCH-$MEDIA.iso"
				[ $VERBOSE != 0 ] && echo "renaming ISO file '$ISOFILE' to '$NEWISOFILE'"
				mv "$ISOFILE" "$NEWISOFILE"
				ISOFILE="$NEWISOFILE"
			fi
			if [ $CMD = "mount" ]; then
				#
				#	mount the ISO image file
				#
				[ $VERBOSE != 0 ] && echo "mounting ISO file '$ISOFILE' to '$MEDIASETPATH'"
				if [ $MOUNTED == yes ]; then
					warn "$ISOFILE already mounted"
				else
					mkdir --parents "$MEDIASETPATH"
					mount -o $MOUNTOPTIONS "$ISOFILE" "$MEDIASETPATH"
				fi
			fi
			if [ $CMD = "umount" ]; then
				#
				#	umount the ISO image file
				#
				[ $VERBOSE != 0 ] && echo "umounting '$MEDIASETPATH'"
				if [ -e "$MEDIASETPATH" ]; then
					umount "$MEDIASETPATH"
					rmdir --parents --ignore-fail-on-non-empty "$MEDIASETPATH"
				else
					warn "$MEDIASETPATH not mounted"
				fi
			fi
			if [ $CMD = "readiso" ]; then
				[ ! -r "$CDROMDEV" ] && die "Couldn't access $ISOIMAGE"
				NEWISOFILE="$( dirname "$ISOFILE" )/$PRODUCT-$VERSION-$ARCH-$MEDIA.iso"
				touch "$NEWISOFILE" >/dev/null 2>&1
				[ ! -e "$NWWISOFILE" ] && die "Couldn't write $NEWISOFILE"

				#
				#	get the number of blocks
				#
				BLOCKS=$( isosize -d $BLOCKSIZE $ISOIMAGE )

				#
				#	copy the image
				#
				echo "Copying $BLOCKS blocks from $CDROMDEV to $ISOFILE ..."
				dd if=$CDROMDEV bs=$BLOCKBURST |
					dd bs=$BLOCKSIZE count=$BLOCKS |
					dd of=$ISOFILE bs=$BLOCKBURST
			fi
		done
		;;
	*)
		################################################################################
		#
		#	unknown command
		#
		show_usage
		exit 1
		;;
esac


################################################################################
#
#	remote the temporary ISO mount point
#
rmdir --parents --ignore-fail-on-non-empty $ISOMNT


#
#	EOF
#
