#!/bin/sh

#
# Standard initramfs preamble
#
prereqs()
{
	# Make sure that cryptroot is run last in local-top
	for req in /scripts/local-top/*; do
		script=$(basename $req)
		[ $script != cryptroot ] && echo $script
	done
}

case $1 in
prereqs)
	prereqs
	exit 0
	;;
esac


#
# Helper functions
#
get_options()
{
	# Do we have any settings from the /conf/conf.d/cryptroot file?
	[ -r /conf/conf.d/cryptroot ] && . /conf/conf.d/cryptroot
	cryptopts="${CRYPTOPTS}"

	# Does the kernel boot command line override them?
	for x in $(cat /proc/cmdline); do
		case $x in
		cryptopts=*)
			cryptopts=${x#cryptopts=}
			;;
		esac
	done

	# Sanity check
	if [ -z "$cryptopts" ]; then
		# Apparently the root partition isn't encrypted
		echo "No cryptroot configured, skipping"
		exit 0
	fi

	# There are two possible scenarios here:
	#
	# 1) The fstype of the root device has been identified as "luks"
	# 2) The fstype is not "luks" but cryptopts has been set
	#
	# The former means that we use the luks functionality of cryptsetup, the
	# latter means that we do it the old-fashioned way.
	#
	# Start by parsing some options, all options are relevant to regular cryptsetup
	# but only crypttarget and cryptsource is relevant to luks which picks up the 
	# rest of the parameters by reading the partition header
	cryptcipher=aes-cbc-essiv:sha256
	cryptsize=256
	crypthash=sha256
	crypttarget=cryptroot
	cryptsource=$ROOT
	cryptlvm=""

	if [ -n "$cryptopts" ]; then
		local IFS=" ,"
		for x in $cryptopts; do
			case $x in
			hash=*)
				crypthash=${x#hash=}
				;;
			size=*)
				cryptsize=${x#size=}
				;;
			cipher=*)
				cryptcipher=${x#cipher=}
				;;
			target=*)
				crypttarget=${x#target=}
				;;
			source=*)
				cryptsource=${x#source=}
				;;
			lvm=*)
				cryptlvm=${x#lvm=}
				;;
			esac
		done
	fi
}

activate_vg()
{
	local vg
	vg=$1

	# Sanity checks
	if [ ! -x /sbin/vgchange ]; then
		return 1
	fi

	if [ -z "$vg" ]; then
		return 1
	fi

	# Make sure we're dealing with a lvm device
	vg=${vg#/dev/mapper/}
	if [ "$vg" = "$1" ]; then
		return 1
	fi

	# Make sure that the device contains at least one dash
	if [ "$(echo -n "$vg" | tr -d -)" = "$vg" ]; then
		return 1
	fi

	# Split volume group from logical volume.
	vg=$(echo ${vg} | sed -e 's#\(.*\)\([^-]\)-[^-].*#\1\2#')
	# Reduce padded --'s to -'s
	vg=$(echo ${vg} | sed -e 's#--#-#g')

	vgchange -ay ${vg}
	return $?
}

load_keymap()
{
	if [ -x /bin/loadkeys -a -r /etc/boottime.kmap.gz ]; then
		loadkeys -q /etc/boottime.kmap.gz
	fi
}

#
# Begin real processing
#

# define crypto variables
get_options

# make sure the cryptsource device is available
if [ ! -e $cryptsource ]; then
	activate_vg $cryptsource
fi
if [ ! -e $cryptsource ]; then
	panic "$0: source device $cryptsource not found"
fi

# If possible, load the keymap so that the user can input non-en characters
load_keymap

# prepare commands
if /sbin/cryptsetup isLuks $cryptsource > /dev/null 2>&1; then
	cryptcreate="/sbin/cryptsetup luksOpen $cryptsource $crypttarget"
else
	cryptcreate="/sbin/cryptsetup -c $cryptcipher -s $cryptsize -h $crypthash create $crypttarget $cryptsource"
fi
cryptremove="/sbin/cryptsetup remove $crypttarget"
NEWROOT="/dev/mapper/$crypttarget"

# Loop until we have a satisfactory password
while [ 1 ]; do
	if [ -x "/sbin/cryptgetpw" ]; then
		/sbin/cryptgetpw < /dev/console | $cryptcreate
	else
		$cryptcreate < /dev/console
	fi

	FSTYPE=''
	if [ $? -ne 0 ]; then
		echo "$0: cryptsetup failed, bad password or options?"
	elif ! fstype < "$NEWROOT" > /conf/param.conf; then
		echo "$0: fstype not recognized, bad password or options?"
	else
		. /conf/param.conf

		# See if we need to setup lvm on the crypto device
		if [ "$FSTYPE" = "lvm" ] || [ "$FSTYPE" = "lvm2" ]; then
			NEWROOT="/dev/mapper/$cryptlvm"
			activate_vg "$NEWROOT" || panic "failed to setup lvm device"
			if ! fstype < "$NEWROOT" > /conf/param.conf; then
				panic "failed to setup lvm device, fs not recognised"
			fi
			. /conf/param.conf
		fi
	fi

	if [ -n "$FSTYPE" ] && [ "$FSTYPE" != "unknown" ]; then
		break
	fi

	if [ -e "$NEWROOT" ]; then
		$cryptremove
	fi
	sleep 3
done

# init can now pick up new FSTYPE, FSSIZE and ROOT
echo "ROOT=\"$NEWROOT\"" >> /conf/param.conf
exit 0
