#!/bin/sh

. /lib/partman/lib/base.sh

# ChromeOS firmware injects 'cros_secure' into the cmdline when the
# verified boot mechanism is used. Not having that means we have some
# other way to boot and do not exactly need a cros partition.
if ! grep -q 'cros_secure' /proc/cmdline >/dev/null; then
	exit 0
fi

have_cros=no
set --

# Get disk device from a partition device.
disk_from_partdev() {
	case "$1" in
		/dev/ide/host*/bus[01]/target[01]/lun0/disc)
			echo "$1";
			;;
		/dev/ide/host*/bus[01]/target[01]/lun0/part)
			echo "$1";
			;;
		/dev/ide/host*/bus[01]/target[01]/lun0/part*)
			local dir=$(dirname "$1")
			if [ -e "$dir/disc" ]; then
				echo "$dir/disc"
			elif [ -e "$dir/part" ]; then
				echo "$dir/part"
			else
				echo "$1"
			fi
			;;
		/dev/hd[a-z])
			echo "$1";
			;;
		/dev/hd[a-z][0-9]*)
			echo "${1%%[0-9]*}"
			;;
		/dev/scsi/host*/bus*/target*/lun*/disc)
			echo "$1";
			;;
		/dev/scsi/host*/bus*/target*/lun*/part*)
			local dir=$(dirname "$1")
			if [ -e "$dir/disc" ]; then
				echo "$dir/disc"
			else
				echo "$1"
			fi
			;;
		/dev/sd[a-z]|/dev/sd[a-z][a-z])
			echo "$1";
			;;
		/dev/sd[a-z][0-9]*|/dev/sd[a-z][a-z][0-9]*|/dev/wd[a-z][0-9]*|/dev/wd[a-z][a-z][0-9]*)
			echo "${1%%[0-9]*}"
			;;
		/dev/cciss/host*|/dev/cciss/disc*)
			echo "$1";
			;;
		/dev/cciss/c*d*)
			echo "$1";
			;;
		/dev/mmcblk[0-9])
			echo "$1";
			;;
		/dev/mmcblk[0-9]p[0-9]*)
			echo "${1%%p[0-9]*}"
			;;
		/dev/md*|/dev/md/*)
			echo "$1";
			;;
		/dev/mapper/*)
			local type=$(dm_table "$1")
			if [ "$type" = "crypt" ]; then
				echo "$1";
			elif [ "$type" = "multipath" ]; then
				echo "$1";
			elif is_multipath_part "$1"; then
				echo "${1%%-part[0-9]*}"
			else
				echo "$1";
			fi
			;;
		/dev/linux_lvm/*)
			echo "$1";
			;;
		/dev/loop/*|/dev/loop*)
			echo "$1";
			;;
		/dev/dasd*[0-9]*)
			echo "${1%%[0-9]*}"
			;;
		/dev/dasd*)
			echo "$1";
			;;
		/dev/*vd[a-z])
			echo "$1";
			;;
		/dev/*vd[a-z][0-9]*)
			echo "${1%%[0-9]*}"
			;;
		/dev/ad[0-9]*[sp][0-9]*)
			echo "$1" | sed 's,\(/dev/ad[0-9]\+\)[sp][0-9]\+.*,\1,'
			;;
		/dev/ad[0-9]*)
			echo "${1%%[0-9]*}"
			;;
		/dev/da[0-9]*[sp][0-9]*)
			echo "$1" | sed 's,\(/dev/da[0-9]\+\)[sp][0-9]\+.*,\1,'
			;;
		/dev/da[0-9]*)
			echo "${1%%[0-9]*}"
			;;
		/dev/zvol/*)
			echo "$1"
			;;
		/dev/nvme[0-9]*n[0-9]*p[0-9]*)
			echo "${1%%p[0-9]*}"
			;;
		*)
			echo "$1"
			;;
	esac
}

# This function takes some devices (e.g. /dev/sda, /dev/mapper/luks-*,
# /dev/dm-0, /dev/disk/by-partuuid/*), tries to find physical disks
# where they are on.
find_disks() {
	# Use real devices for all. Turns /dev/disk/** into /dev/*.
	for d in "$@"; do
		if [ -n "$d" ]; then
			set -- "$@" "$(readlink -f "$d")"
		fi
		shift
	done

	# We can have chains of VG-LV, dm-*, md*, *_crypt, so on. They can
	# resolve to multiple devices. So we keep a stack of devices to
	# search (in $@) and prepend new ones to run in the next cycle of
	# the loop. We also need to keep the results in a stack, so keep
	# them at the end divided with a separator.
	BREAK="{BREAK}"
	ITER=0
	set -- "$@" "$BREAK"
	while [ "$#" -gt 0 ]; do
		ITER=$((ITER + 1))

		if [ "$1" = "$BREAK" ]; then
			shift
			break
		elif [ "$ITER" -gt 100 ]; then
			shift
			continue
		else
			dev="$(basename "$1")"
			shift
		fi

		parent="$(readlink -f "/sys/class/block/${dev}/..")" || parent=''
		case "$parent" in
			# VG-LV, sda2_crypt e.g. doesn't exist in /sys/class/block,
			# so readlink fails. We check each dm device's name here to
			# find which dm-* device they actually are.
			'')
				for d in /sys/class/block/dm-*; do
					d="$(basename "$d")"
					if grep -qs "^$dev\$" "/sys/class/block/${d}/dm/name"; then
						set -- "$d" "$@"
					fi
				done
				;;
			# dm-* and md* reside on /sys/devices/virtual/block, and
			# have a "slaves" folder for partitions they are built on.
			*/virtual/block)
				for d in "/sys/class/block/${dev}/slaves"/*; do
					set -- "$(basename "$d")" "$@"
				done
				;;
			# Real partitions e.g. /sys/devices/**/block/sda/sda2
			# and /sys/devices/**/nvme/nvme0/nvme0n1/nvme0n1p2
			# but we need their parent, sda or nvme0n1.
			*/block/*|*/nvme[0-9]/*|*/nvme[0-9][0-9]/*)
				set -- "$(basename "$parent")" "$@"
				;;
			# These are real disks we can use. Keep them after the
			# separator, without duplicates.
			*/block|*/nvme[0-9]|*/nvme[0-9][0-9])
				case "$@" in
					*${BREAK}*${dev}*) continue ;;
				esac
				if [ -b "/dev/${dev}" ]; then
					set -- "$@" "/dev/${dev}"
				fi
				;;
			# I don't know what goes here, but let's try the parent.
			*)
				set -- "$(basename "$parent")" "$@"
				;;
		esac
	done

	echo "$@"
}

# Find disks for root and /boot
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
		[ "$fs" != free ] || continue
		partitions="$partitions $id,$path"
	done
	close_dialog

	for part in $partitions; do
		id=${part%,*}
		path=${part#*,}
		disk="$(disk_from_partdev "$path")"

		if [ -f $id/mountpoint ]; then
			mnt="$(cat $id/mountpoint)"
			if [ "$mnt" = "/" ] || [ "$mnt" = "/boot" ]; then
				# To-be-created parts don't have devices, check the disk.
				if [ ! -b "$path" ] && [ -b "$disk" ]; then
					set -- "$@" "$disk"
				else
					set -- "$@" "$path"
				fi
			fi
		fi
	done
done

# Result of this is /dev/sda /dev/mmcblk0 /dev/nvme0n1 or so.
set -- $(find_disks "$@")

# Is there at least one cros-partition in root/boot disks?
for disk in "$@"; do
	dev="$DEVICES/=dev=${disk#/dev/}"
	[ -d "$dev" ] || continue
	cd $dev
	partitions=
	open_dialog PARTITIONS
	while { read_line num id size type fs path name; [ "$id" ]; }; do
		[ "$fs" != free ] || continue
		partitions="$partitions $id,$path"
	done
	close_dialog

	for part in $partitions; do
		id=${part%,*}
		path=${part#*,}
		[ -f $id/method ] || continue
		method=$(cat $id/method)
		if [ "$method" = cros ]; then
			have_cros=yes
		fi
	done
done

if [ "$have_cros" = "no" ]; then
	db_fset partman-cros/no_cros seen false
	db_input critical partman-cros/no_cros || true
	db_go || exit 1
	db_get partman-cros/no_cros
	if [ "$RET" = true ]; then
		exit 1
	fi
fi

exit 0
