#!/bin/sh

PREREQ=""

prereqs()
{
	echo "$PREREQ"
}

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

. /usr/share/initramfs-tools/hook-functions

get_root_device() {
	[ -r /etc/fstab ] || return

	grep '^[^#]' /etc/fstab | ( \
	while read device mount type options dump pass; do
		if [ "$mount" = "/" ]; then
			echo "$device"
			return
		fi
	done )
}

node_is_in_crypttab() {
	local node
	node=$1
	
	grep -q ^$node /etc/crypttab
	return $?
}

get_lvm_device() {
	local node majorminor
	node=$1

	[ -z $node ] && return

	majorminor=$( dmsetup deps $node | \
		      sed 's/[^:]*: *(\([0-9]*\), *\([0-9]\).*/\1 \2/') || return
	major=$( echo $majorminor | cut -d " " -f1 )
	minor=$( echo $majorminor | cut -d " " -f2 )
	depnode=$( dmsetup info -c --noheadings -j $major -m $minor | cut -d ":" -f 1 )
	echo "$depnode"
}

get_root_opts() {
	local target source extraopts rootopts opt
	target=$1
	extraopts=$2

	[ ! -z $target ] || return
	[ -r /etc/crypttab ] || return

	opt=$( grep ^$target /etc/crypttab | head -1 | sed 's/[[:space:]]\+/ /g' )
	source=$( echo $opt | cut -d " " -f2 )
	rootopts=$( echo $opt | cut -d " " -f4- )

	[ ! -z "$opt" -a ! -z "$source" -a ! -z "$rootopts" ] || return 1
	[ ! -z "$extraopts" ] && rootopts="${extraopts},${rootopts}"

	# We have all the basic options, let's go trough them
	echo -n "target=$target,source=$source"
	local IFS=", "
	for opt in $rootopts; do
		case $opt in
			cipher=*)
				echo -n ",$opt"
				;;
			hash=*)
				echo -n ",$opt"
				;;
			size=*)
				echo -n ",$opt"
				;;
			lvm=*)
				echo -n ",$opt"
				;;
			*)
				# Presumably a non-supported option
				;;
		esac
	done
}

get_root_modules() {
	local rootnode value cipher ivhash
	rootnode=$1

	# Check the ciphers used by the active root mapping
	value=$( dmsetup table $rootnode | cut -d " " -f4 )

	cipher=$( echo $value | cut -d ":" -f1 | cut -d "-" -f1 )
	[ -z "$cipher" ] && return
	echo $cipher

	ivhash=$( echo $value | cut -d ":" -s -f2 )
	[ ! -z "$ivhash" ] && echo "$ivhash"
}

# Find out which device root is on
rootdev=$(get_root_device)
[ -z "$rootdev" ] && exit 0

# Check that it is a node under /dev/mapper/
node=${rootdev#/dev/mapper/}
[ "$node" != $rootdev ] || exit 0

# Can we find this node in crypttab
opts=""
if ! node_is_in_crypttab $node; then
	# It is a /dev/mapper node but not in crypttab, is it lvm?
	lvmtest=$(get_lvm_device $node)

	if [ -z "$lvmtest" ]; then
		# Neither in crypttab, nor a lvm device, our work is done
		exit 0
	else
		# It is a lvm device!
		opts="lvm=$node"
		node="$lvmtest"
	fi
fi

# Get crypttab root options
rootopts=$(get_root_opts $node $opts)
if [ -z "$rootopts" ]; then
	echo "$0: failed to determine cipher options to use"
	exit 1
fi

# Calculate needed modules
force_load dm_mod
force_load dm_crypt
modules=$(get_root_modules $node | sort | uniq)
if [ -z "$modules" ]; then
	echo "$0: failed to determine cipher modules to load"
	exit 1
fi
for mod in $modules; do
	manual_add_modules $mod
done

# Prepare the initramfs
echo "CRYPTOPTS=\"$rootopts\"" > ${DESTDIR}/conf/conf.d/cryptroot
copy_exec /sbin/cryptsetup /sbin
copy_exec /sbin/dmsetup /sbin
[ -x "/sbin/cryptgetpw" ] && copy_exec /sbin/cryptgetpw /sbin

# Allow the correct keymap to be loaded if possible
if [ -e /bin/loadkeys -a -r /etc/console/boottime.kmap.gz ]; then
	copy_exec /bin/loadkeys /bin/
	cp /etc/console/boottime.kmap.gz $DESTDIR/etc/
fi

# Done
exit 0
