#!/bin/sh

set -e

. /usr/share/debconf/confmodule

log () {
	logger -t nobootloader "$@"
}

error () {
	log "error: $@"
}

findfs () {
	case "$(udpkg --print-os)" in
	    hurd)
		fsysopts "/target$1" | sed 's:^.* \([^ ]*\):\1:' ;;
	    *)
		mount | grep "on /target${1%/} " | tail -n1 | cut -d' ' -f1 ;;
	esac
}

die () {
	local template="$1"
	shift

	error "$@"
	db_input critical "$template" || [ $? -eq 30 ]
	db_go || true
	exit 1
}

mountvirtfs () {
	fstype="$1"
	path="$2"
	if grep -q "[[:space:]]$fstype\$" /proc/filesystems && \
	   ! grep -q "^[^ ]\+ \+$path " /proc/mounts; then
		mkdir -p "$path" || \
			die nobootloader/mounterr "Error creating $path"
		mount -t "$fstype" "$fstype" "$path" || \
			die nobootloader/mounterr "Error mounting $path"
		trap "umount $path" HUP INT QUIT KILL PIPE TERM EXIT
	fi
}

rootfs_devfs=$(findfs /)
bootfs_devfs=$(findfs /boot)

# partconf workaround (mounts /target as /target/)
if [ "$rootfs_devfs" = "" ]; then
	rootfs_devfs=$(findfs //)
fi

if [ "$bootfs_devfs" = "" ]; then
	bootfs_devfs=$rootfs_devfs
	boot="boot/"
else
	boot=""
fi

rootfs=$(mapdevfs $rootfs_devfs)
bootfs=$(mapdevfs $bootfs_devfs)

case "$(archdetect)" in
    powerpc/chrp_pegasos)
	kernel=$(ls /target/boot/vmlinuz-* | sed -e 's%/target/boot/%%')

	if [ -z "$kernel" ]; then
		kernelpath=$(ls /target/boot/vmlinux-* | sed -e 's%/target%%')
		version="${kernelpath#*vmlinux-}"
		if [ "$version" ]; then
			if apt-install mkvmlinuz; then
				# mkvmlinuz needs proc in /target
				mountvirtfs proc /target/proc
				chroot /target /usr/sbin/mkvmlinuz "$version" "$kernelpath"
			fi
		fi
		kernel=$(ls /target/boot/vmlinuz-* | sed -e 's%/target/boot/%%')
	fi

	partition_offset=1
	if [ -e /proc/device-tree/openprom/firmware-version ]; then
		firmware_version="$(cat /proc/device-tree/openprom/firmware-version)"
		fv1="${firmware_version%%.*}"
		rest="${firmware_version#*.}"
		fv2="${rest%%.*}"
		rest="${rest#*.}"
		fv3="${rest%%.*}"
		if [ "$fv1" -eq 1 ]; then
			if [ "$fv2" -eq 3 ] && [ "$fv3" -ge 99 ]; then
				partition_offset=0
			elif [ "$fv2" -ge 4 ]; then
				partition_offset=0
			fi
		elif [ "$fv1" -ge 2 ]; then
			partition_offset=0
		fi
	fi

	bootfs_disk_syspath=
	if [ -d /sys/block ]; then
		if type udevadm >/dev/null 2>&1; then
			bootfs_disk_syspath="$(dirname "$(udevadm info -q path -n "$bootfs_devfs")")"
		elif type udevinfo >/dev/null 2>&1; then
			bootfs_disk_syspath="$(dirname "$(udevinfo -q path -n "$bootfs_devfs")")"
		fi
	fi
	if [ "$bootfs_disk_syspath" ]; then
		# TODO: device symlinks are allegedly slated to go
		# away, but it's not entirely clear what their
		# replacement will be yet ...
		bootfs_disk="$(basename "$(readlink "/sys$bootfs_disk_syspath/device")")"
		kind="$(basename "$(readlink "/sys$bootfs_disk_syspath/device/bus")")"
		case $kind in
		    ide)
			host="$(basename "$(dirname "$(readlink "/sys$bootfs_disk_syspath/device")")" | sed 's/[^0-9]*//')"
			# TODO: devfs set bus to hwif->channel, which
			# doesn't appear to be exposed. Since we only
			# support the first controller anyway, I'm hoping
			# that the host (hwif->index) will be good enough.
			bus="$(echo "$bootfs_disk" | cut -d. -f1)"
			target="$(echo "$bootfs_disk" | cut -d. -f2)"
			lun=
			;;
		    scsi)
			host="$(echo "$bootfs_disk" | cut -d: -f1)"
			bus="$(echo "$bootfs_disk" | cut -d: -f2)"
			target="$(echo "$bootfs_disk" | cut -d: -f3)"
			lun="$(echo "$bootfs_disk" | cut -d: -f4)"
			;;
		esac
		part="$(($(echo "$bootfs_devfs" | sed 's/^.*[^0-9]//') - $partition_offset))"
	else
		kind=$(echo $bootfs_devfs | sed -e 's%/dev/%%' -e 's%/host.*$%%')
		host=$(echo $bootfs_devfs | sed -e 's%^.*host%%' -e 's%/bus.*$%%')
		bus=$(echo $bootfs_devfs | sed -e 's%^.*bus%%' -e 's%/target.*$%%')
		target=$(echo $bootfs_devfs | sed -e 's%^.*target%%' -e 's%/lun.*$%%')
		lun=$(echo $bootfs_devfs | sed -e 's%^.*lun%%' -e 's%/part.*$%%')
		part="$(($(echo "$bootfs_devfs" | sed -e 's%^.*part%%') - $partition_offset))"
	fi

	# We don't know how to map non ide or scsi disks
	# and we have trouble when there is more than one such controller.
	case "$kind","$host" in
	    ide,0)
		path="/pci/ide/disk@$bus,$target" ;;
	    scsi,0)
		path="/pci/scsi/disk@$bus,$target,$lun" ;;
	    *)
		path="hd" ;;
	esac

	# map theidevice to the OF aliases from /proc/device-tree/aliases.
	if [ -d /proc/device-tree/aliases ]; then
		for alias in $(ls /proc/device-tree/aliases/*); do
			device=$(grep disk $alias | sed -e 's%@[^/]*/%/%g')
			if [ "$path" = "$device" ]; then
				path="${alias#/proc/device-tree/aliases/}"
			fi
		done
	fi

	bootcmd="boot ${path}:${part} ${boot}vmlinuz root=${rootfs}"

	template=nobootloader/confirmation_powerpc_chrp_pegasos
	db_subst $template KERNEL_BOOT "${bootcmd}"
	db_subst $template OF_BOOT_DEVICE "${path}:${part}" 
	db_subst $template OF_BOOT_FILE "${boot}vmlinuz root=${rootfs}"
	db_input high $template || true
	;;
    powerpc/pasemi)
	# TODO: Need to figure out if we need to generate the ramdisk
	# TODO: Is this the right kernel path?
	# TODO: Need to generate the device name based on actual disk used
	kernel=vmlinuz
	initrd=initrd

	template=nobootloader/confirmation_powerpc_pasemi
	db_subst $template INITRD "sata0.0:/${boot}${initrd}"
	db_subst $template KERNFILE "sata0.0:/${boot}${kernel}"
	db_subst $template BOOTARGS "root=$rootfs"
	db_input high $template || true
	;;
    hurd-i386/*)
	kernel=gnumach.gz
	template=nobootloader/confirmation_common
	db_subst $template ROOT "root=device:${rootfs#/dev/}"
	db_subst $template BOOT "${bootfs}"
	db_subst $template KERNEL "${kernel}"
	db_input high $template || true
	;;
    *)
	db_get base-installer/kernel/linux/link_in_boot
	link_in_boot="$RET"
	if [ "$link_in_boot" = "true" ]; then
		boot_link="boot/"
	else
		boot_link=""
		boot=""
		bootfs=${rootfs}
	fi
	if [ -e /target/${boot_link}vmlinuz ]; then
		kernel="/${boot}vmlinuz"
	elif [ -e /target/${boot_link}vmlinux ]; then
		kernel="/${boot}vmlinux"
	fi

	uparams=$(user-params) || true
	template=nobootloader/confirmation_common
	db_subst $template ROOT "root=${rootfs} ${uparams}"
	db_subst $template BOOT "${bootfs}"
	db_subst $template KERNEL "${kernel}"
	db_input high $template || true
	;;
esac

db_go || true
