#!/bin/sh

# Apply LVM partitioning on top of a RAID preseed

if ! [ -f /var/lib/partman/initial_auto_raid_crypto_pvs ] ||
   ! [ -e /lib/partman/lib/auto-lvm.sh ]; then
	exit 0
fi

. /lib/partman/lib/auto-lvm.sh
. /lib/partman/lib/crypto-base.sh

# pv_devices is used by auto_lvm_perform()
pv_devices="$(cat /var/lib/partman/initial_auto_raid_crypto_pvs)"
rm -f /var/lib/partman/initial_auto_raid_crypto_pvs

db_get partman-auto/expert_recipe_file
recipe="$RET"

# Clone-and-hack from initial_auto_raid_lvm (adding cryptsetup to the mix),
# which is itself another clone-and-hack described below.
#
# Since we're having LVM on top of LUKS and RAID, and RAID has been handled
# already, let's set up LUKS, before letting the rest of the script handle LVM.
#
# Comparison against partman-auto-crypto's autopartition-crypto:
#  - clean_method:
#      Skipped for now, doesn't seem needed.
#  - auto_lvm_prepare:
#      Re-use initial_auto_raid_lvm's re-implementation instead.
#  - first loop (find and prepare the first device marked for crypto):
#      Copied.
#  - crypto_check_setup:
#      Copied.
#  - crypto_setup:
#      Copied.
#  - second loop (fix method on PVs):
#      Copied, but with pv_devices adjusted to account for the LUKS layer.
#  - auto_lvm_perform:
#      Copied/already present in initial_auto_raid_lvm's re-implementation.
#  - forcing DISK_UNCHANGED:
#      Skipped for now, doesn't seem needed.
#
# OPEN QUESTION: Should auto_lvm_create_vg_map be adjusted for the PV-on-LUKS?

# Clone-and-hack from partman-auto-lvm, which can't cope with the idea of
# not needing to create partitions for itself yet.

size=0
devs=
for pv_device in $pv_devices; do
	dev="$(dev_to_partman $pv_device)"
	devs="${devs:+$devs }$dev"
	[ -f $dev/size ] || exit 1
	size=$(($size + $(cat $dev/size)))
done

set -- $devs
main_device=$1
shift
extra_devices="$*"

# Be sure the modules are loaded
modprobe dm-mod >/dev/null 2>&1 || true
modprobe lvm-mod >/dev/null 2>&1 || true

if type update-dev >/dev/null 2>&1; then
	log-output -t update-dev update-dev --settle
fi

if [ "$extra_devices" ]; then
	for dev in $devs; do
		physdev="$(cat "$dev/device")"
		target="${target:+$target }${physdev#/dev/}"
	done
	db_metaget partman-auto-lvm/text/multiple_disks description
	target=$(printf "$RET" "$target")
else
	target="$(humandev $(cat $main_device/device)) - $(cat $main_device/model)"
fi
target="$target: $(longint2human $size)"
free_size=$(convert_to_megabytes $size)

choose_recipe lvm "$target" "$free_size" || return $?

# Copied from partman-auto-crypto's autopartition-crypto:
found=no
for dev in $DEVICES/*; do
        [ -d "$dev" ] || continue
	cd $dev
	partitions=
	open_dialog PARTITIONS
	while { read_line num id size type fs path name; [ "$id" ]; }; do
		if [ "$fs" != free ]; then
			partitions="$partitions $id"
		fi
	done
	close_dialog

	for id in $partitions; do
		[ -f $id/method ] || continue
		method=$(cat $id/method)
		[ $method = crypto ] || continue

		echo dm-crypt > $id/crypto_type
		crypto_prepare_method "$dev/$id" dm-crypt || exit 1
		if [ "$(debconf-get partman-auto-crypto/erase_disks)" = "false" ]; then
			touch $id/skip_erase
		fi
		found=yes
		break
	done
	[ $found = yes ] && break
done
crypto_check_setup || exit 1
crypto_setup no || exit 1

# Rewrite pv_devices, that auto_lvm_perform would have set properly in the
# partman-auto-crypto case, but since initial_auto_raid_*lvm have their own
# tweaked implementation, build the mapper path like auto-shared.sh does:
for pv in $pv_devices; do
	mapped_pv=/dev/mapper/${pv##*/}_crypt
	new_pv_devices=${new_pv_devices:+$new_pv_devices }$mapped_pv
done
pv_devices="$new_pv_devices"

# Copied from partman-auto-crypto's autopartition-crypto:
for pv in $pv_devices; do
	dev="$(dev_to_partman $pv)"
	[ -d "$dev" ] || continue
	[ -f "$dev/crypt_realdev" ] || continue
	[ -f "$dev/device" ] || continue

	# We should have only one partition, but lets be thorough
	cd $dev
	partitions=
	open_dialog PARTITIONS
	while { read_line num id size type fs path name; [ "$id" ]; }; do
		[ "$fs" != free ] || continue
		partitions="$partitions $id"
	done
	close_dialog

	for id in $partitions; do
		for file in acting_filesystem filesystem format formatable use_filesystem; do
			rm -f $id/$file
		done
		echo lvm > $id/method
	done
done

# Make sure the recipe contains lvmok tags
if ! echo "$scheme" | grep -q lvmok; then
	bail_out unusable_recipe
fi

# Make sure a boot partition isn't marked as lvmok, unless the user
# has told us it is ok for /boot to reside on a logical volume
if echo "$scheme" | grep lvmok | grep -q "[[:space:]]/boot[[:space:]]"; then
	db_input critical partman-auto-lvm/no_boot || true
	db_go || return 255
	db_get partman-auto-lvm/no_boot || true
	[ "$RET" = true ] || bail_out unusable_recipe
fi

expand_scheme

# Extract the mapping of which VG goes onto which PV
auto_lvm_create_vg_map

auto_lvm_perform
