#! /bin/sh

# export DEBCONF_DEBUG=5
set -e
. /usr/share/debconf/confmodule
#set -x

if [ "$1" ]; then
	ROOT="$1"
	chroot=chroot
	shift
else
	ROOT=
	chroot=
fi

if [ "$1" ]; then
	ARCH="$1"
fi

. /usr/share/grub-installer/functions.sh
. /usr/share/grub-installer/otheros.sh

newline="
"

db_capb backup

log() {
	logger -t grub-installer "$@"
}

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

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

debug () {
	[ -z "${DEBCONF_DEBUG}" ] || log "debug: $@"
}

ARCH="${ARCH:-$(archdetect)}"
info "architecture: $ARCH"

umount_dirs=

cleanup () {
	for dir in $umount_dirs; do
		umount "$ROOT/${dir#/}" || true
	done
}

umount_on_exit () {
	if [ "$umount_dirs" ]; then
		umount_dirs="$umount_dirs $1"
	else
		umount_dirs="$1"
		trap cleanup EXIT HUP INT QUIT TERM
	fi
}

# XXX cjwatson 2019-03-25: This is all far too complicated and fragile, and
# should be replaced with in-target or similar.

# Ensure proc is mounted in all the $chroot calls;
# needed for RAID+LVM for example
initial_proc_contents="$(ls $ROOT/proc)"
if [ -z "$initial_proc_contents" ]; then
	info "Mounting /proc into $ROOT"
	if [ "$(udpkg --print-os)" = "kfreebsd" ]; then
		mount -t linprocfs proc $ROOT/proc && umount_on_exit /proc
	else
		mount -t proc proc $ROOT/proc && umount_on_exit /proc
	fi
fi

if [ "$(udpkg --print-os)" = linux ] && [ -z "$(ls $ROOT/sys)" ]; then
	mount -t sysfs sysfs $ROOT/sys && umount_on_exit /sys
fi

# On Linux, we need /run in the chroot to work around
# https://bugs.debian.org/918590.
if [ "$(udpkg --print-os)" = "linux" ] && [ ! -d "$ROOT/run/udev" ]; then
	mount --bind /run $ROOT/run
fi

get_serial_console() {
	# Get the last 'console=' entry (if none, the whole string is returned)
	local defconsole="$(sed -e 's/.*\(console=[^ ]*\).*/\1/' /proc/cmdline)"
	if echo "$defconsole" | grep -qe 'console=\(ttyS\|com\)'; then
		echo "$defconsole"
	fi
}

grub_serial_console() {
	#$1=output of get_serial_console
	local serconsole=${1##console=ttyS}
	serconsole=${serconsole##console=com}
	local unit=${serconsole%%,*}
	local options=""
	if echo $serconsole | grep -q ","; then
		options=${serconsole##*,}
	fi
	local speed=$(echo "$options" | sed -e 's/^\([0-9]*\).*$/\1/')
	# Take optional 1st (parity) and 2nd (word) characters after speed
	options=${options##${speed}}
	local parity=$(echo $options | sed 's/^\(.\?\).*$/\1/')
	local word=$(echo $options | sed 's/^.\?\(.\?\).*$/\1/')
	if [ -z "$speed" ]; then
		speed="9600"
	fi
	case "$parity" in 
		n) parity="--parity=no" ;;
		e) parity="--parity=even" ;;
		o) parity="--parity=odd" ;;
		*) parity="" ;;
	esac
	if [ "$word" ]; then
		word="--word=$word"
	fi

	echo serial --unit=$unit --speed=$speed $word $parity --stop=1
}

serial="$(get_serial_console)"

grub_probe () {
	if [ "$is_grub_common_installed" != true ]; then
		apt-install grub-common
		is_grub_common_installed=true
	fi
	$chroot $ROOT grub-probe $@
}

device_map=$ROOT/boot/grub/device.map

# Usage: convert os_device
# Convert an OS device to the corresponding GRUB drive
convert () {
	# Adjust the device map to add a SATA RAID array.
	if [ "$grub_version" = grub ] && [ "$frtype" = "sataraid" ] && type dmraid >/dev/null 2>&1; then
		temp_map=$ROOT/tmp/sataraid.map
		echo quit | $chroot $ROOT /usr/sbin/grub --batch --device-map=/tmp/sataraid.map >/dev/null 2>&1

		# Dmraid -r seems to list disks in reverse order to how they
		# are detected by the kernel.
		satadisk=$(dmraid -r | grep $(basename "$frdev") | cut -f 1 -d : | tail -1)
		sed -i "s@$satadisk@$frdev@" $temp_map

		# Remove member disks of the SATA RAID array from the device map.
		for sdisk in $(dmraid -r | grep $(basename "$frdev") | cut -f 1 -d : | grep -v "$satadisk"); do
			cat $temp_map | grep -v "$sdisk" > $temp_map.new
			mv $temp_map.new $temp_map
		done
		mv $temp_map $device_map
	fi

	tmp_drive="$(grub_probe -d -t drive "$1")" || exit $?
	if [ "$partition_offset" != 0 ]; then
		tmp_part="$(echo "$tmp_drive" | sed 's%.*,\([0-9]*\)).*%\1%')"
		if [ "$tmp_part" ] && [ "$tmp_part" != "$tmp_drive" ]; then
			tmp_drive="$(echo "$tmp_drive" | sed "s%\(.*,\)[0-9]*\().*\)%\1`expr $tmp_part - $partition_offset`\2%")"
		fi
	fi
	echo "$tmp_drive"
}

# Convert a linux non-devfs disk device name into the hurd's syntax
hurd_convert () {
	dr_type=$(expr "$1" : '.*\([hs]d\)[a-h][0-9]*')
	dr_letter=$(expr "$1" : '.*d\([a-h]\)[0-9]*')
	dr_part=$(expr "$1" : '.*d[a-h]\([0-9]*\)')
	case "$dr_letter" in
	a) dr_num=0 ;;
	b) dr_num=1 ;;
	c) dr_num=2 ;;
	d) dr_num=3 ;;
	e) dr_num=4 ;;
	f) dr_num=5 ;;
	g) dr_num=6 ;;
	h) dr_num=7 ;;
	esac
	echo "$dr_type${dr_num}s$dr_part"
}

# This should probably be rewritten using udevadm or similar.
device_to_disk () {
	echo "$1" | \
		sed 's:\(/dev/\(cciss\|ida\|rs\)/c[0-9]d[0-9][0-9]*\|/dev/mmcblk[0-9]\|/dev/nvme[0-9][0-9]*n[0-9][0-9]*\|/dev/\(ad\|ada\|da\|vtbd\|xbd\)[0-9]\+\|/dev/[hms]d[0-9]\+\|/dev/[a-z]\+\).*:\1:'
}

# Run update-grub in $ROOT
update_grub () {
	local in_target
	if [ "$ROOT" = /target ]; then
		in_target='in-target'
	else
		in_target="log-output -t grub-installer $chroot $ROOT"
	fi
	if ! $in_target $update_grub_cmd; then
		error "Running '$update_grub_cmd' failed." 1>&2
		db_input critical grub-installer/update-grub-failed || [ $? -eq 30 ]
		db_go || true
		db_progress STOP
		exit 1
	fi
}

findfs () {
	if ! grub_probe -t device $1; then
		mount | grep "on $ROOT${1%/} " | tail -n1 | cut -d' ' -f1
	fi
}

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

is_removable () {
	removabledevice="$(mount | grep "on $ROOT${1%/} " | cut -d' ' -f1)"
	if [ -z "$removabledevice" ]; then
		return
	fi
	# check if the device we got is a symlink. That might happen in future
	# if we implement probe-for-root-fs
	if [ -L "$removabledevice" ]; then
		removabledevice="$(readlink -f $removabledevice)"
	fi
	# copy from convert(). We can't use the entire stuff yet. We can clean it later on.
	removabledevice="$(echo "$removabledevice" | sed -e 's%\([vsh]d[a-z]\)[0-9]*$%\1%' -e 's%\(fd[0-9]*\)$%\1%' -e 's%/part[0-9]*$%/disc%' -e 's%\(c[0-7]d[0-9]*\).*$%\1%' -e 's%^/dev/%%g')"
	if [ -e "/sys/block/$removabledevice/removable" ]; then
		if [ "$(cat /sys/block/$removabledevice/removable)" != "0" ]; then
			echo "/dev/$removabledevice"
			return
		fi
	fi
	if [ -z "$removabledevice" ]; then
		return
	fi
	if type udevadm >/dev/null 2>&1; then
		if [ "$bootfstype" = "zfs" ] || [ "$rootfstype" = "zfs" ]; then
			bus="$(udevadm info -q env -n $removabledevice || true)"
		else
			bus="$(udevadm info -q env -n $removabledevice)"
		fi
	else
		if [ "$bootfstype" = "zfs" ] || [ "$rootfstype" = "zfs" ]; then
			bus="$(udevinfo -q env -n $removabledevice || true)"
		else
			bus="$(udevinfo -q env -n $removabledevice)"
		fi
	fi
	bus="$(echo "$bus" | grep ^ID_BUS= | sed 's/^ID_BUS=//')"
	case $bus in
		usb|ieee1394)
			echo "/dev/$removabledevice"
			;;
	esac
}

# by-id mapping copied from grub-pc.postinst.

cached_available_ids=
available_ids()
{
	local id path

	if [ "$cached_available_ids" ]; then
		echo "$cached_available_ids"
		return
	fi

	[ -d /dev/disk/by-id ] || return
	cached_available_ids="$(
		for path in /dev/disk/by-id/*; do
			[ -e "$path" ] || continue
			printf '%s %s\n' "$path" "$(readlink -f "$path")"
		done | sort -k2 -s -u | cut -d' ' -f1
	)"
	echo "$cached_available_ids"
}

# Returns non-zero and no output if no mapping can be found.
device_to_id()
{
	local id
	for id in $(available_ids); do
		if [ "$(readlink -f "$id")" = "$(readlink -f "$1")" ]; then
			echo "$id"
			return 0
		fi
	done
	# Fall back to the plain device name if there's no by-id link for it.
	if [ -e "$1" ]; then
		echo "$1"
		return 0
	fi
	return 1
}

devices_to_ids()
{
	local device id ids
	ids=
	for device; do
		id="$(device_to_id "$device" || true)"
		if [ "$id" ]; then
			ids="${ids:+$ids, }$id"
		fi
	done
	echo "$ids"
}

# Split a device name into a disk device name and a partition number, if
# possible.
split_device () {
	disk=
	part=
	case $1 in
		/dev/[vhs]d[a-z]*|/dev/fio[a-z]*)
			disk="$(echo "$1" | sed 's,\(/dev/[a-z]\+\).*,\1,')"
			part="$(echo "$1" | sed 's,/dev/[a-z]\+\(.*\),\1,')"
			;;
		/dev/*/c*d*)
			disk="$(echo "$1" | sed 's,\(/dev/.*/c[0-9]\+d[0-9]\+\).*,\1,')"
			part="$(echo "$1" | sed 's,/dev/.*/c[0-9]\+d[0-9]\+p\([0-9]\+\),\1,')"
			[ "$part" != "$1" ] || part=
			;;
		/dev/mmcblk*)
			disk="$(echo "$1" | sed 's,\(/dev/mmcblk[0-9]\+\).*,\1,')"
			part="$(echo "$1" | sed 's,/dev/mmcblk[0-9]\+p\([0-9]\+\),\1,')"
			[ "$part" != "$1" ] || part=
			;;
		/dev/nvme*n*)
			disk="$(echo "$1" | sed 's,\(/dev/nvme[0-9]\+n[0-9]\+\).*,\1,')"
			part="$(echo "$1" | sed 's,/dev/nvme[0-9]\+n[0-9]\+p\([0-9]\+\),\1,')"
			[ "$part" != "$1" ] || part=
			;;
	esac
	echo "$disk $part"
}

rootfs=$(findfs /)
bootfs=$(findfs /boot)
[ -n "$bootfs" ] || bootfs="$rootfs"


bootfstype=$(findfstype /boot)
rootfstype="$(findfstype /)"
[ -n "$bootfstype" ] || bootfstype=$rootfstype

case $ARCH in
    powerpc/chrp|powerpc/chrp_rs6k|powerpc/chrp_ibm|powerpc/cell)
    ;;
    powerpc/*)
      offs=$(findfs /boot/grub)
      [ -n "$offs" ] || error "GRUB requires that the OF partition is mounted in /boot/grub" 1>&2
    ;;
esac

# This code to set disc_offered was taken from lilo-installer
rootfs_nodevfs=$(mapdevfs $rootfs)
bootfs_nodevfs=$(mapdevfs $bootfs)
prefix=$(device_to_disk "$bootfs")

case $prefix in
    /dev/md)
	disc_offered_devfs="$bootfs"
	;;
    /dev/mapper)
	disc_offered_devfs="$bootfs"
	;;
    /dev/loop)
	disc_offered_devfs="$bootfs"
	;;
    /dev/[hmsv]d[a-z0-9]*|/dev/xvd[a-z]|/dev/cciss/c[0-9]d[0-9]*|/dev/ida/c[0-9]d[0-9]*|/dev/rs/c[0-9]d[0-9]*|/dev/mmcblk[0-9]|/dev/nvme[0-9]*n[0-9]*|/dev/ad[0-9]*|/dev/da[0-9]*|/dev/fio[a-z])
	disc_offered_devfs="$prefix"
	;;
    *)
	disc_offered_devfs=$(echo "$bootfs_nodevfs" | sed "s:\(.*\)/.*:\1/disc:")
	;;
esac
disc_offered=$(mapdevfs "$disc_offered_devfs")

# Identify partition table of the disk containing our boot partition
bootfslabel=$(partmap $disc_offered || echo unknown)

found=0
# Check if the boot file system is on Serial ATA RAID
frdev=""
if [ "$found" = "0" ] && type dmraid >/dev/null 2>&1 && \
   dmraid -s -c >/dev/null 2>&1 && \
   db_get disk-detect/activate_dmraid && [ "$RET" = true ]; then
	for frdisk in $(dmraid -s -c); do
		if echo "$disc_offered" | grep -q "/$frdisk[0-9]\+"; then
			frdev=/dev/mapper/$frdisk
			frbootpart=${disc_offered#$frdev}
			frgrubroot=$frbootpart
			frtype=sataraid
			found=1
			break
		fi
	done
	[ "$found" = "1" ] || frdisk=
fi
# Check if the boot file system is on multipath
if [ "$found" = "0" ] && type multipath >/dev/null 2>&1; then
	for frdisk in $(multipath -l 2>/dev/null | \
			grep '^mpath[a-z]\+ ' | cut -d ' ' -f 1); do
		if echo "$disc_offered" | 	   \
			grep -q "^/dev/mapper/${frdisk}[0-9]\+"; then
			frdev=/dev/mapper/$frdisk
			frbootpart=${disc_offered#$frdev}
			frgrubroot=${frbootpart#p}
			frtype=multipath
			found=1
			break
		fi
	done
	if [ "$found" = "1" ]; then
		# Create the device nodes for grub:
		apt-install dmsetup
		$chroot $ROOT dmsetup mknodes
	else
		frdisk=
	fi
fi
if [ "$found" = "0" ] && type lvdisplay >/dev/null 2>&1 && \
     (lvdisplay "$disc_offered" | grep -q 'LV Name' 2>/dev/null || \
      [ -e "$(dirname "$disc_offered")/control" ]); then
	# Don't set frdev/frdisk here, otherwise you'll end up in different
	# code paths below ...
	frtype=lvm
fi
# Check if the boot file system is on an mdadm device
if [ "$found" = "0" ] && type mdadm >/dev/null 2>&1; then
	frdisk_list=
	for frdisk in $(mdadm --detail "$bootfs_nodevfs" 2>/dev/null | \
			grep " active sync " 2>/dev/null | \
			sed "s/^.* active sync\s*//" 2>/dev/null \
	); do
		case $frdisk in
		    /dev/*)	;;
		    *)		continue ;;
		esac
		# Build a list of devices in the mirror
		frdisk_list="$frdisk_list $(mapdevfs "$frdisk" || true)"
		frdev=
		frtype="mdadm"
		found=1
	done
fi
# Check if the boot file system is on a virtio device, /dev/vd*
if [ "$found" = "0" ] && echo "$bootfs" | grep -qs "^\/dev\/vd[a-z]"; then
	frdisk=
	found=1
fi
# Check if the boot file system is on a loopback device
if [ "$found" = "0" ] && echo "$bootfs" | grep -qs '^/dev/loop'; then
	frdev="$bootfs"
	frtype="loop"
	found=1
fi

info "Identified partition label for $bootfs: $bootfslabel"

experimental_arch () {
	db_subst grub-installer/grub_not_mature_on_this_platform ARCH $ARCH
	db_input low grub-installer/grub_not_mature_on_this_platform || [ $? -eq 30 ]
	db_go || exit 10
	db_get grub-installer/grub_not_mature_on_this_platform
	if [ "$RET" != true ]; then
		exit 10
	fi
}

case $ARCH in
    arm64/efi)
	grub_package="grub-efi-arm64"
	;;
    i386/mac|amd64/mac)
	# Note: depends on partman-efi to load the efivars module!
	if [ -d /sys/firmware/efi ]; then
		# This point can't be reached (yet).  See debian/isinstallable.
		grub_package="grub-efi"
	else
		grub_package="grub-pc"
	fi
	;;
    i386/efi|amd64/efi)
	if [ -f /var/lib/partman/ignore_uefi ]; then
		grub_package="grub-pc"
	else
		grub_package="grub-efi-amd64-signed"
		if [ ! -d /target/boot/efi ]; then
			# No EFI System Partition, so presumably the partitioner
			# believed this to be unnecessary, perhaps because we're
			# installing on a pre-existing MBR partition table or
			# perhaps because there's a BIOS Boot Partition.  In either
			# case, the right answer is to fall back to grub-pc.
			grub_package="grub-pc"
		fi
	fi
	;;
    i386/*|amd64/*)
	grub_package="grub-pc"
	;;
    powerpc/*)
	grub_package="grub-ieee1275"
	experimental_arch
	;;
    ppc64el/*)
	grub_package="grub-ieee1275"
	;;
    mipsel/loongson-2f)
	grub_package="grub-yeeloong"
	;;
    *)
	grub_package="grub-pc"
esac

case $ARCH:$grub_package in
    ppc64el/*:grub-ieee1275)
	# By default, use the first PReP partition found (prep-bootdev).
	# If available, prefer a PReP partition in the same device (disc_offered).
	# (the matching works on devices with/without disk-partition separator.)
	# On MD/mdadm devices, each component device may have a PReP partition.

	wipe_bootdevs=""
	wipe_bootdev="$(/usr/lib/grub-installer/prep-bootdev)"
	for prep_p in $(/usr/lib/grub-installer/prep-bootdev -l); do
		prep_dev=$(split_device $prep_p)
		offered=$(split_device $disc_offered)
		if [ "${prep_dev%% *}" = "${offered%% *}" ]; then
			wipe_bootdev=$prep_p
			break
		fi

		if echo $disc_offered | grep -q '/dev/md[0-9]\+'; then
			if mdadm --detail --verbose $disc_offered \
			     | sed -n 's:.*\(/dev/.*[^0-9]\)[0-9]\+$:\1:p' \
			     | grep "${prep_dev%% *}"; then
				wipe_bootdevs="$wipe_bootdevs $prep_p"
			fi
		fi
	done
	unset prep_p

	if [ -z "$wipe_bootdevs" ]; then
		wipe_bootdevs="$wipe_bootdev"
	fi

	for wipe_bootdev in $wipe_bootdevs; do
		if [ -n "$wipe_bootdev" ] && [ -e "$wipe_bootdev" ]; then
			info "Wiping PReP partition $wipe_bootdev"
			log-output -t grub-installer dd if=/dev/zero of="$wipe_bootdev" bs=512 count="$(blockdev --getsz "$wipe_bootdev")"
		else
			info "WARNING: PReP partition not found: $wipe_bootdev"
		fi
	done

	if [ -z "$wipe_bootdevs" ]; then
		info "WARNING: no PReP partition found"
	fi
	;;
esac

case $grub_package in
    grub)
	grub_version="grub"
	menu_file="menu.lst"
	update_grub_cmd="update-grub -y"
	partition_offset=1
	frgrubroot=$(($frgrubroot - 1))
	;;
    *)
	grub_version="grub2"
	menu_file="grub.cfg"
	update_grub_cmd="update-grub"
	partition_offset=0
	;;
esac

# determine if /boot or / are on a removable disk. We will do it for Linux only
# and see how bad it goes.

if [ "$(uname -s | tr '[A-Z]' '[a-z]')" = "linux" ]; then
	bootremovable="$(is_removable /boot)"
	[ -n "$bootremovable" ] || bootremovable="$(is_removable /)"
fi

user_params=$(user-params) || true
defopt_params=""
kopt_params=""
got_quiet=""
got_splash=""
for u_param in $user_params; do
	case "$u_param" in
	    quiet)
		got_quiet=1
		if ! db_get debian-installer/quiet || [ "$RET" = true ]; then
			defopt_params=${defopt_params:+$defopt_params }$u_param
		fi
		;;
	    splash)
		got_splash=1
		;;
	    *)
		kopt_params=${kopt_params:+$kopt_params }$u_param ;;
	esac
done
if [ "$got_splash" ] && \
   db_get debian-installer/framebuffer && [ "$RET" = true ] && \
   (! db_get debian-installer/splash || [ "$RET" = true ]); then
	defopt_params=${defopt_params:+$defopt_params }splash
fi
if [ "$grub_package" = grub-pc ]; then
	# Empty this for now to stop it being asked. We'll fix this up later.
	# (quoting to deconfuse vim)
	$chroot $ROOT 'debconf-set-selections' <<EOF
$grub_package grub-pc/install_devices multiselect
$grub_package grub-pc/install_devices_empty boolean true
EOF
fi

db_progress START 0 6 grub-installer/progress/title

db_subst grub-installer/progress/step_install GRUB "$grub_version"
db_progress INFO grub-installer/progress/step_install

# apt-install passes --no-remove to apt, but grub{,2} conflict each other, so
# we need to purge them first to support users who try grub2 and then switch
# to grub legacy, or vice-versa
case "$grub_package" in
    grub-pc)
	log-output -t grub-installer $chroot $ROOT dpkg -P grub-efi grub-efi-amd64 grub-efi-ia32-bin grub-efi-ia32
	;;
    grub-efi)
	log-output -t grub-installer $chroot $ROOT dpkg -P grub-efi-amd64-signed
	;;
esac

exit_code=0
inst_package=$grub_package
case "$grub_package" in
   *)
	# Will pull in os-prober based on global setting for Recommends
	apt-install $grub_package || exit_code=$? 
	case $grub_package in
	    *-signed)
		apt-install shim-signed || true
		apt-install grub-pc || true
		;;
	esac
	;;
esac

if [ $exit_code -ne 0 ] ; then
	db_progress STOP
	info "Calling 'apt-install $inst_package' failed"
	db_subst grub-installer/apt-install-failed GRUB "$inst_package"
	db_input critical grub-installer/apt-install-failed || true
	if ! db_go; then
		exit 10 # back up to menu
	fi
	exit 1
fi

grub_debian_version="$($chroot $ROOT dpkg-query -W -f '${Version}' $inst_package)"

db_progress STEP 1
db_progress INFO grub-installer/progress/step_os-probe
os-prober > /tmp/os-probed || true

db_settitle debian-installer/grub-installer/title

# Work out what probed OSes can be booted from grub
if [ -s /tmp/os-probed ]; then
	supported_os_list=""
	unsupported_os_list=""

	OLDIFS="$IFS"
	IFS="$newline"
	for os in $(cat /tmp/os-probed); do
		IFS="$OLDIFS"
		title=$(echo "$os" | cut -d: -f2)
		type=$(echo "$os" | cut -d: -f4)
		case "$type" in
		    chain)
			: ;;
		    linux)
			# Check for linux systems that we don't
			# know how to boot
			partition=$(echo "$os" | cut -d: -f1)
			if [ -z "$(linux-boot-prober $partition)" ]; then
				if [ -n "$unsupported_os_list" ]; then
					unsupported_os_list="$unsupported_os_list, $title"
				else
					unsupported_os_list="$title"
				fi
				continue
			fi
			;;
		    hurd)
			: ;;
		    *)
			if [ -n "$unsupported_os_list" ]; then
				unsupported_os_list="$unsupported_os_list, $title"
			else
				unsupported_os_list="$title"
			fi
			continue
			;;
		esac

		if [ -n "$supported_os_list" ]; then
			supported_os_list="$supported_os_list, $title"
		else
			supported_os_list="$title"
		fi
		
		IFS="$newline"
	done
	IFS="$OLDIFS"
	
	if [ -z "$OVERRIDE_UNSUPPORTED_OS" ] && [ -n "$unsupported_os_list" ]; then
		# Unsupported OS, jump straight to manual boot device question.
		state=2
	else
		q=grub-installer/with_other_os
		db_subst $q OS_LIST "$supported_os_list"
		state=1
	fi
else
	q=grub-installer/only_debian
	state=1
fi

if [ "$frdev" ] && [ "$frtype" != "sataraid" ] && [ "$frtype" != "loop" ]; then
	if [ -e $ROOT$frdev ] && [ -e $ROOT$frdev$frbootpart ] && \
	   [ $frgrubroot -ge $((1 - $partition_offset)) ]; then
		db_subst grub-installer/$frtype GRUBROOT $ROOT$frdev$frbootpart
		q=grub-installer/$frtype
	else
		db_input critical grub-installer/${frtype}-error
		db_go || true
		exit 1
	fi
fi

# Try to avoid using (hd0) as a boot device name.  Something which can be
# turned into a stable by-id name is better.
default_bootdev_os="$($chroot $ROOT grub-mkdevicemap --no-floppy -m - | head -n1 | cut -f2)"
if [ "$default_bootdev_os" ]; then
	default_bootdev="$($chroot $ROOT readlink -f "$default_bootdev_os")"
	if db_get grub-installer/bootdev && [ "$RET" = '(hd0)' ]; then
		db_set grub-installer/bootdev "$default_bootdev"
	fi
else
	default_bootdev="(hd0)"
fi

# Set a sensible default boot device, so that we aren't installing GRUB to
# installation media which may be removed later.  The disk containing /cdrom
# is very unlikely to be a sensible default.  If we had to fall back to
# (hd0), then we can't tell exactly which disk that is, but if /cdrom seems
# to be a USB stick then (hd0) may not be safe.  If we hit either of those
# checks, then try the disk containing /boot instead.
# The same goes for /hd-media, so avoid installing there as well.
cdsrc=$(mount | grep "on /cdrom " | cut -d' ' -f1)
cdfs=$(mount | grep "on /cdrom " | cut -d' ' -f5)
hdsrc=$(mount | grep "on /hd-media " | cut -d' ' -f1)
hybrid=false
if db_get cdrom-detect/hybrid; then
	hybrid="$RET"
fi
case $ARCH:$grub_package in
    *:grub|*:grub-pc|sparc:grub-ieee1275)
	if [ "$grub_version" = grub2 ] && \
	    ([ "$frtype" = mdadm ] || [ "$frtype" = multipath ]); then
		# Check whether any of the RAIDed devices is a partition, and if so
		# install to the corresponding disk instead, as GRUB 2 doesn't like
		# installing to a RAID device composed of partitions.
		# TODO: This duplicates some pretty horrible code from above. This
		# should at least be turned into a function or something ...
		disks=
		use_disks=
		for frdisk_one in $frdisk_list; do
			prefix=$(echo "$frdisk_one" | \
			  sed 's:\(/dev/\(cciss\|ida\|rs\)/c[0-9]d[0-9][0-9]*\|/dev/mmcblk[0-9]\|/dev/\(ad\|da\)[0-9]\+\|/dev/nvme[0-9]n[0-9]\|/dev/[a-z]\+\).*:\1:')
			disks="${disks:+$disks }$prefix"
			case $prefix in
			    /dev/[hmsv]d[a-z]|/dev/xvd[a-z]|/dev/cciss/c[0-9]d[0-9]*|/dev/ida/c[0-9]d[0-9]*|/dev/rs/c[0-9]d[0-9]*|/dev/mmcblk[0-9]|/dev/ad[0-9]*|/dev/da[0-9]*|/dev/fio[a-z]|/dev/nvme[0-9]n[0-9])
				if [ "$prefix" != "$frdisk_one" ]; then
					use_disks=1
				fi
				;;
			esac
		done
		if [ "$use_disks" ]; then
			default_bootdev="$disks"
		else
			default_bootdev="$bootfs_nodevfs"
		fi
		db_set grub-installer/bootdev "$default_bootdev"
		state=3
	elif [ "$(device_to_disk "$cdsrc")" = "$default_bootdev" ] || \
	   ([ -n "$hdsrc" ] && [ "$(device_to_disk "$hdsrc")" = "$default_bootdev" ]) || \
	   ([ "$default_bootdev" = '(hd0)' ] && \
	    (([ -n "$cdfs" ] && [ "$cdfs" != "iso9660" ]) || \
	     [ "$hybrid" = true ])) || \
	   ([ "$default_bootdev" != '(hd0)' ] && \
	    ! partmap "$default_bootdev" >/dev/null && \
	    ! grub_probe -t fs -d "$default_bootdev" >/dev/null); then
		db_fget grub-installer/bootdev seen
		if [ "$RET" != true ]; then
			bootfs=$(findfs /boot)
			[ "$bootfs" ] || bootfs="$(findfs /)"
			disk=$(device_to_disk "$bootfs")
			db_set grub-installer/bootdev "$disk"
			state=2
		fi
	fi
	;;
    ppc64el/*:grub-ieee1275)
	bootdev="$wipe_bootdev"
	state=3
	;;
    *)
	# No need for install device selection on other platforms.
	bootdev=dummy
	state=3
	;;
esac

db_progress STEP 1
db_progress INFO grub-installer/progress/step_bootdev

select_bootdev() {
	debug "select_bootdev: arg='$1'"

	local dev_list dev_descr grubdev devices disk_id dev descr
	local default_choice priority chosen result

	result=""
	default_choice="$1"

	# /dev/disk/by-id has multiple links for the same physical disk.
	# Let's trust grub-mkdevicemap to select the most suitable ones
	# and correctly handle systems with no /dev/disk/by-id.
	# Use disk id string as a shortcut way to describe it.
	# FIXME switch to grub-pc's far more elegant disk_descriptions()
	dev_list=
	dev_descr=
	devices="$($chroot $ROOT grub-mkdevicemap --no-floppy -m - | cut -f2)"
	for grubdev in $devices; do
		disk_id="$(device_to_id $grubdev)"
		dev="$(readlink -f "$disk_id")"
		dev_list="${dev_list:+$dev_list, }$dev"
		descr="$(echo $disk_id |sed -e 's+^.*/++' |sed -e 's+,+\\,+g')"
		if [ "$dev" = "$disk_id" ]; then
			dev_descr="${dev_descr:+$dev_descr, }$dev"
		else
			#/dev/sdX (id)
			dev_descr="${dev_descr:+$dev_descr, }$dev  ($descr)"
		fi
	done

	debug "Bootdev Choices: '$dev_list'"
	debug "Bootdev Descriptions: '$dev_descr'"

	db_subst grub-installer/choose_bootdev DEVICES_LIST "$dev_list"
	db_subst grub-installer/choose_bootdev DESCRIPTIONS "$dev_descr"
	priority=high
	# set initial selection
	if [ -n "$default_choice" ] ; then
		chosen="$(readlink -f "$default_choice")"
		if [ -n "$chosen" ] ;then
			db_set grub-installer/choose_bootdev "$chosen"
		fi
	elif [ "$(echo "$devices" | wc -l)" = 1 ]; then
		# only one likely choice
		db_set grub-installer/choose_bootdev "$dev_list"
		priority=low
	fi

	db_input "$priority" grub-installer/choose_bootdev || true
	if ! db_go; then
		log "Returning to menu"
		db_progress STOP
		exit 10
	fi

	db_get grub-installer/choose_bootdev || true
	# Choices-C (not shown to user) can be set to 'manual'
	if [ "$RET" = "manual" ] ; then
		result=""
	else
		result="$(echo "$RET" | cut -d' ' -f1)"
	fi

	debug "select_bootdev: result='$result'"
	echo "$result"
}

if [ "$bootdev" != "dummy" ] && [ ! "$frdev" ]; then
	# check for a preseeded value
	db_get grub-installer/bootdev || true
	if [ -n "$RET" ] ; then
		bootdev="$RET"
	fi
fi

while : ; do

	debug "q='$q' state='$state' defbd='$default_bootdev' bd='$bootdev'"
	db_fget grub-installer/bootdev seen
	if [ "$RET" = true ] && db_get grub-installer/bootdev && [ "$RET" ] ; then
		if [ "$RET" = "default" ]; then
			bootdev=$default_bootdev
		else
			bootdev=$RET
		fi
		break
	elif [ "$state" = 1 ]; then
		if [ "$frdev" ]; then
			# If /boot is on SATA RAID/multipath, then there's
			# only one possible answer; we don't support device
			# selection yet. This is pretty nasty.
			db_set $q true || true
			db_fset $q seen true || true
		fi
		db_input high $q || true
		if ! db_go; then
			# back up to menu
			db_progress STOP
			exit 10
		fi
		db_get $q
		if [ "$RET" = true ]; then
			if [ -n "$bootremovable" ]; then
				bootdev="$bootremovable"
				if [ "$grub_version" = grub ] && \
				   [ ! -e "$device_map" ]; then
					mkdir -p "$(dirname "$device_map")"
					echo "(hd0) $bootremovable" > "$device_map"
				fi
			fi

			# default_bootdev can be guessed incorrectly.
			# If the user supplied a value for bootdev,
			# ask them to resolve any conflict.
			if [ "$bootdev" != "$default_bootdev" ] ; then
				bootdev="$(select_bootdev "$bootdev")"
				previous_state=1
			fi
			if [ -e "$bootdev" ] ; then
			    break
			else
			    state=2
			fi
		else
			# Exit to menu if /boot is on SATA RAID/multipath; we
			# don't support device selection in that case
			if [ "$frdev" ]; then
				db_progress STOP
				exit 10
			fi
			state=2
		fi
	elif [ "$state" = 2 ]; then

		if [ "$previous_state" != "1" ]; then
			bootdev="$(select_bootdev "$bootdev")"
			unset previous_state
		fi

		if [ ! -e "$bootdev" ]; then
		    db_input critical grub-installer/bootdev || true
		fi
		if ! db_go; then
			if [ "$q" ]; then
				state=1
			else
				# back up to menu
				db_progress STOP
				exit 10
			fi
		else
			db_get grub-installer/bootdev
			bootdev=$RET
			if echo "$bootdev" | grep -qv '('; then
				mappedbootdev=$(mapdevfs "$bootdev") || true
				if [ -n "$mappedbootdev" ]; then
					bootdev="$mappedbootdev"
				fi
			fi
			break
		fi
	else
		break
	fi
done

db_progress STEP 1
db_subst grub-installer/progress/step_install_loader BOOTDEV "$bootdev"
db_progress INFO grub-installer/progress/step_install_loader

info "Installing grub on '$bootdev'"

update_mtab

mkdir -p $ROOT/boot/grub

write_grub() {
	info "Installing GRUB to $frdev; grub root is $disc_offered"
	# TODO: Check for errors during this process!
	TERM=linux $chroot $ROOT \
        grub --device-map=/dev/null >/var/log/grub-${frtype}.log 2>&1 </dev/null <<EOF
device (hd0,$frgrubroot) $disc_offered
device (hd0) $frdev
root (hd0,$frgrubroot)
setup (hd0)
quit
EOF
}

if [ -z "$frdisk" ] || [ "$grub_version" = grub2 ]; then

	# Install grub on each space separated disk in the list
	bootdevs="$bootdev"

	case $ARCH:$grub_package in
	    ppc64el/*:grub-ieee1275)
		# On MD/mdadm devices, each component device may have a PReP partition.
		bootdevs="$wipe_bootdevs"
		;;
	esac

	for bootdev in $bootdevs; do
		grub_install_params=
		if ! is_floppy "$bootdev"; then
			if $chroot $ROOT grub-install -h 2>&1 | grep -q no-floppy; then
				info "grub-install supports --no-floppy"
				grub_install_params="$grub_install_params --no-floppy"
			else
				info "grub-install does not support --no-floppy"
			fi
			if [ -e $ROOT/boot/grub/device.map ] && grep '^(fd' $ROOT/boot/grub/device.map; then
				recheck="--recheck"
			fi
		else
			if [ -e $ROOT/boot/grub/device.map ] && ! grep '^(fd' $ROOT/boot/grub/device.map; then
				recheck="--recheck"
			fi
		fi

		# Should we force a copy of grub-efi to be installed
		# to the removable media path too? Ask at low
		# priority, or can also be pre-seeded of course
		db_input low grub-installer/force-efi-extra-removable || [ $? -eq 30 ]
		db_go || exit 10
		db_get grub-installer/force-efi-extra-removable
		if [ "$RET" = true ]; then
			grub_install_params="$grub_install_params --force-extra-removable"
			# Make sure this happens on upgrades too
			$chroot $ROOT 'debconf-set-selections' <<EOF
$grub_package grub2/force_efi_extra_removable boolean true
EOF
		fi

		if [ "$ARCH" = "powerpc/chrp_pegasos" ] ; then
			# nvram is broken here
			grub_install_params="$grub_install_params --no-nvram"
		fi

		if [ "$grub_version" = "grub" ] ; then
			grub_install_params="$grub_install_params $recheck"
		else
			# install even if it requires blocklists
			grub_install_params="$grub_install_params --force"
		fi

		if [ "$ARCH" = "amd64/efi" ] ; then
		        grub_install_params="$grub_install_params --target x86_64-efi"
                fi

		CODE=0
		case $ARCH:$grub_package in
		    *:grub|*:grub-pc|*:grub-efi*|sparc:grub-ieee1275|ppc64el/*:grub-ieee1275)
			info "Running $chroot $ROOT grub-install $grub_install_params \"$bootdev\""
			log-output -t grub-installer $chroot $ROOT grub-install $grub_install_params "$bootdev" || CODE=$?
			;;
		    *)
			info "Running $chroot $ROOT grub-install $grub_install_params"
			log-output -t grub-installer $chroot $ROOT grub-install $grub_install_params || CODE=$?
			;;
		esac
		if [ "$CODE" = 0 ]; then
			info "grub-install ran successfully"
		else
			case $ARCH:$grub_package in
			    *:grub|*:grub-pc|*:grub-efi*|sparc:grub-ieee1275|ppc64el/*:grub-ieee1275)
				error "Running 'grub-install $grub_install_params \"$bootdev\"' failed."
				;;
			    *)
				error "Running 'grub-install $grub_install_params failed."
				;;
			esac
			db_subst grub-installer/grub-install-failed BOOTDEV "$bootdev"
			db_input critical grub-installer/grub-install-failed || [ $? -eq 30 ]
			db_go || true
			db_progress STOP
			exit 1
		fi
	done

else

	# Semi-manual grub setup for Serial ATA RAID/multipath
	info "Boot partition is on a Serial ATA RAID disk, multipath, or mdadm device"
	case $(archdetect) in
	    i386/*)
		stagedir=i386-pc ;;
	    amd64/*)
		stagedir=x86_64-pc ;;
	    *)
		error "Unsupported architecture for SATA RAID/multipath/mdadm installation"
		exit 1
		;;
	esac
	if [ ! -d $ROOT/usr/lib/grub/$stagedir/ ]; then
		error "Grub stage files not available"
		exit 1
	fi
	mkdir -p $ROOT/boot/grub
	cp $ROOT/usr/lib/grub/$stagedir/* $ROOT/boot/grub

	if [ "$frtype" = "mdadm" ]; then
		for frdisk in $frdisk_list; do
			frdev=$(echo "$frdisk" | sed "s/[0-9]\+$//")
			disc_offered=$frdev
			frbootpart=${frdisk#$frdev}
			frgrubroot=$(($frbootpart-1))
			write_grub
		done
	else
		write_grub
	fi

fi

make_device_map () {
	# If you're preseeding (hd0) et al, stop - preseed OS device names
	# instead.  However, for backward compatibility we ensure that a
	# device.map exists if you do this.
	[ "$grub_version" = grub2 ] || return 0
	[ ! -e "$device_map" ] || return 0
	local no_floppy
	case $1 in
		\(fd*|fd*)
			no_floppy=
			;;
		*)
			no_floppy=--no-floppy
			;;
	esac
	$chroot $ROOT grub-mkdevicemap $no_floppy
}

make_active_partition () {
	if [ "$grub_package" != "grub-pc" ]; then
	# only do this for grub-pc since on EFI $bootdev is a dummy argument
	# and looking for a partition table on the wrong or non existing disk
	# crashes the installer LP:#1303790
		return
	fi
	bootdisk=
	bootpart=
	case $bootdev in
		/dev/*)
			bootdev_split="$(split_device "$bootdev")"
			bootdisk="${bootdev_split%% *}"
			bootpart="${bootdev_split#* }"
			;;
		\([hf]d[0-9]*\))
			make_device_map "$bootdev"
			bootdev_nopart="$(echo "$bootdev" | sed 's/,[^)]*//')"
			bootdisk="$(grep -v '^#' $device_map | grep "^ *$bootdev_nopart" \
				| sed 's/^ *(.*)[[:space:]]*\(.*\)/\1/')"
			bootpart="$(echo "$bootdev" | sed 's/.*,\([^)]*\).*/\1/')"
			[ "$bootpart" != "$bootdev" ] || bootpart=
			if [ "$bootpart" ]; then
				bootpart="$(($bootpart + $partition_offset))"
			fi
			;;
		[hf]d[0-9]*)
			# The GRUB format with no parenthesis.
			make_device_map "$bootdev"
			bootdisk="$(grep -v '^#' $device_map | grep "^ *(${bootdev%%,*})" \
				| sed 's/^ *(.*)[[:space:]]*\(.*\)/\1/')"
			bootpart="${bootdev#*,}"
			[ "$bootpart" != "$bootdev" ] || bootpart=
			if [ "$bootpart" ]; then
				bootpart="$(($bootpart + $partition_offset))"
			fi
			;;
	esac

	# Make sure that there's *some* active partition; some BIOSes
	# reportedly don't like it otherwise.  Leave well alone on GPT since
	# libparted does this for us.
	if [ "$bootdisk" ]; then
		if [ -z "$bootpart" ]; then
			# If /boot is on the same disk and is primary,
			# that's probably a reasonable default.
			bootfs="$(findfs /boot)"
			[ "$bootfs" ] || bootfs="$(findfs /)"
			bootfs="$(mapdevfs "$bootfs")"
			bootfs_split="$(split_device "$bootfs")"
			bootfs_disk="${bootfs_split%% *}"
			bootfs_part="${bootfs_split#* }"
			if [ "$bootfs_disk" = "$bootdisk" ] && \
			   ([ "$bootfs_part" -ge 1 ] && [ "$bootfs_part" -le 4 ]); then
				bootpart="$bootfs_part"
			fi
		fi

		# Don't quote $bootpart here; that argument should vanish if
		# there is no obviously appropriate partition to select.
		/usr/lib/grub-installer/ensure-active "$bootdisk" $bootpart
	fi
}

db_get grub-installer/make_active
if [ "$RET" = true ]; then
	make_active_partition
fi

if [ "$grub_package" = "grub-pc" ]; then
	# Do the same thing on upgrades.
	$chroot $ROOT 'debconf-set-selections' <<EOF
$grub_package grub-pc/install_devices multiselect $(devices_to_ids $bootdevs)
$grub_package grub-pc/install_devices_empty boolean false
$grub_package grub-pc/install_devices_empty seen false
EOF
fi

db_progress STEP 1
db_progress INFO grub-installer/progress/step_config_loader

if [ "$bootfstype" = "zfs" ] || [ "$rootfstype" = "zfs" ]  && [ -f "/boot/zfs/zpool.cache" ]; then
	# Required by update-grub on ZFS
	mkdir -p $ROOT/boot/zfs
	cp /boot/zfs/zpool.cache $ROOT/boot/zfs/
fi

# Delete for idempotency
rm -f $ROOT/boot/grub/$menu_file
update_grub

# For SATA RAID/multipath the grub root may need fixing up
# For dmraid we can end up with e.g. '(sil_aiahbgbgaaaj1)', or we can end up
# with '(hd0,0)' when it should be a higher partition
# TODO: This should really be better supported in update-grub
if [ "$grub_version" = grub ] && [ "$frdev" ] && \
   ! grep -q "^# groot=(hd0,$frgrubroot)" $ROOT/boot/grub/$menu_file; then
	info "Fixing up the grub root to '(hd0,$frgrubroot)'"
	sed -i "/^# groot/s/(.*)/(hd0,$frgrubroot)/" $ROOT/boot/grub/$menu_file
	update_grub
fi

# Set a password if asked
if [ "$grub_version" = "grub" ] ; then
	# Set up a password if asked or preseeded.
	password=
	db_get grub-installer/password-crypted
	if [ "$RET" = false ] || [ "$RET" = true ]; then
		# password-crypted used to be a boolean template
		error "Preseeding of encrypted passwords changed! Check installation guide."
		exit 1
	elif [ "$RET" ]; then
		password="$RET"
	else
		PW_PRIO=low
		while :; do
			password=""
			db_input $PW_PRIO grub-installer/password || true
			if ! db_go; then
				# back up to menu
				db_progress STOP
				exit 10
			fi

			db_get grub-installer/password
			if [ "$RET" ]; then
				password="$RET"
				db_input $PW_PRIO grub-installer/password-again || true
				if ! db_go; then
					db_progress STOP
					exit 10
				fi
				
				db_get grub-installer/password-again
				if [ "$password" = "$RET" ]; then
					break
				else
					db_input critical grub-installer/password-mismatch || true
					if ! db_go; then
						db_progress STOP
						exit 10
					fi
				fi
			else
				# The user doesn't want a password
				break
			fi
			# We only get here if passwords don't match
			PW_PRIO=critical
			db_set grub-installer/password ""
			db_set grub-installer/password-again ""
			db_fset grub-installer/password seen false
			db_fset grub-installer/password-again seen false
		done
		if [ "$password" ]; then
			password=$(echo -e "md5crypt\n$password" | \
				   $chroot $ROOT \
				   grub --batch --device-map=/dev/null 2>&1 | \
				   grep "^Encrypted:" | cut -d' ' -f2)
		fi
	fi

	if [ "$password" ]; then
		echo "password --md5 $password" >/tmp/menu.lst.password
		# Add a line to menu.lst to use the given password
		# The line is appended after the commented example
		sed -i '/^# password/r /tmp/menu.lst.password' $ROOT/boot/grub/$menu_file
		# By default, menu.lst is world-readable, which is not so good if it
		# contains a password.
		chmod o-r $ROOT/boot/grub/$menu_file
		rm -f /tmp/menu.lst.password
	fi 
fi

# Add user parameters to menu.lst; some options are only added to the
# default entry for a kernel instead of all entries.
if [ "$grub_version" = grub ]; then
	if db_get debian-installer/splash && [ "$RET" = false ]; then
		sed -i 's!^\(# defoptions=.*\) splash\( \|$\)!\1\2!' $ROOT/boot/grub/$menu_file
	fi
	if [ "$defopt_params" ]; then
		sed -i "s!^\(# defoptions=.*\)!\1 $defopt_params!" $ROOT/boot/grub/$menu_file
	fi
	if [ "$kopt_params" ]; then
		sed -i "s!^\(# kopt=.*\)!\1 $kopt_params!" $ROOT/boot/grub/$menu_file
	fi
else
	# It's simplest to duplicate grub2's default for
	# GRUB_CMDLINE_LINUX_DEFAULT here, as well as its handling of
	# quoting.
	set_config_item () {
		local key value
		key="$1"
		value="$(echo "$2" | sed -e 's,[$`"\],\\&,g')"
		if grep -q "^$key=" "$ROOT/etc/default/grub"; then
			value="$(echo "$value" | sed -e 's,[\@],\\&,g')"
			sed -i -re "s@^($key=).*@\1\"$value\"@" "$ROOT/etc/default/grub"
		else
			echo >> "$ROOT/etc/default/grub"
			echo "$key=\"$value\"" >> "$ROOT/etc/default/grub"
		fi
	}

	if [ -z "$got_splash" ] && \
	   db_get debian-installer/framebuffer && [ "$RET" = true ] && \
	   (! db_get debian-installer/splash || [ "$RET" = true ]); then
		defopt_params="splash${defopt_params:+ $defopt_params}"
	fi
	if [ -z "$got_quiet" ] && \
	   (! db_get debian-installer/quiet || [ "$RET" = true ]); then
		defopt_params="quiet${defopt_params:+ $defopt_params}"
	fi
	set_config_item GRUB_CMDLINE_LINUX_DEFAULT "$defopt_params"
	set_config_item GRUB_CMDLINE_LINUX "$kopt_params"
fi
# In either case, update the Debian kernel entries
if [ "$user_params" ]; then
	update_grub
fi

if db_get grub-installer/timeout
then
	# Check whether it's a number
	if [ "$RET" -eq "$RET" ] 2> /dev/null
	then
		timeout="$RET"
	fi
fi

if [ -s /tmp/os-probed ]; then
	# Other operating systems are installed, so show the menu by default
	# and raise the timeout.
	if [ "$grub_version" = grub ]; then
		sed -i 's/^hiddenmenu[[:space:]]*$/#hiddenmenu/;
			s/^\(timeout[[:space:]][[:space:]]*\).*/\110/' \
			$ROOT/boot/grub/menu.lst
	else
		sed -i 's/^GRUB_HIDDEN_TIMEOUT=.*/#&/;
			s/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=10/' \
			$ROOT/etc/default/grub
		update_grub # propagate to grub.cfg
	fi
elif [ -n "$timeout" ]; then
	# Leave a slight delay
	if [ "$grub_version" = grub ]; then
		sed -i 's/^hiddenmenu[[:space:]]*$/#hiddenmenu/;
			s/^\(timeout[[:space:]][[:space:]]*\).*/\1'$timeout'/' \
			$ROOT/boot/grub/menu.lst
	else
		sed -i 's/^GRUB_HIDDEN_TIMEOUT=.*/#&/;
			s/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT='$timeout'/' \
			$ROOT/etc/default/grub
		update_grub # propagate to grub.cfg
	fi
fi

if [ "$serial" ] ; then
	# Modify menu.lst so _grub_ uses serial console.
	case $grub_package in
	    grub)
		(
			grub_serial_console $serial
			echo "terminal serial"
			cat $ROOT/boot/grub/$menu_file
		) >$ROOT/boot/grub/$menu_file.new
		mv $ROOT/boot/grub/$menu_file.new $ROOT/boot/grub/$menu_file
		;;
	    grub-pc|grub-efi*)
		if grep -q "^GRUB_TERMINAL=" $ROOT/etc/default/grub; then
			sed -i $ROOT/etc/default/grub -e "s/^\(GRUB_TERMINAL\)=.*/\1=serial/g"
		else
			echo "GRUB_TERMINAL=serial" >> $ROOT/etc/default/grub
		fi
		if grep -q "^GRUB_SERIAL_COMMAND=" $ROOT/etc/default/grub ; then
			sed -i $ROOT/etc/default/grub -e "s/^\(GRUB_SERIAL_COMMAND\)=.*/\1=\"`grub_serial_console $serial`\"/g"
		else
			echo "GRUB_SERIAL_COMMAND=\"`grub_serial_console $serial`\"" >> $ROOT/etc/default/grub
		fi
		update_grub # propagate to grub.cfg
		;;
	esac
fi 

# Generate menu.lst additions for other OSes
tmpfile=/tmp/menu.lst.extras
OLDIFS="$IFS"
IFS="$newline"

no_floppy=""
if $chroot $ROOT dpkg --compare-versions $grub_debian_version ge 1.96+20090609-1 ; then
	no_floppy="--no-floppy"
fi

if [ "$grub_version" != grub2 ] || \
   ! $chroot $ROOT which os-prober >/dev/null 2>&1; then
	for os in $(cat /tmp/os-probed); do
		IFS="$OLDIFS"
		title=$(echo "$os" | cut -d: -f2)
		shortname=$(echo "$os" | cut -d: -f3)
		type=$(echo "$os" | cut -d: -f4)
		case "$type" in
		    chain)
			partition=$(mapdevfs $(echo "$os" | cut -d: -f1))
			grubdrive=$(convert "$partition") || true
			if [ -n "$grubdrive" ]; then
				case $grub_version in
				    grub)	grub_write_chain ;;
				    grub2)	grub2_write_chain ;;
				esac
			fi
			;;
		    linux)
			partition=$(echo "$os" | cut -d: -f1)
			mappedpartition=$(mapdevfs "$partition")
			IFS="$newline"
			for entry in $(linux-boot-prober "$partition"); do
				IFS="$OLDIFS"
				bootpart=$(echo "$entry" | cut -d: -f2)
				mappedbootpart=$(mapdevfs "$bootpart") || true
				if [ -z "$mappedbootpart" ]; then
					mappedbootpart="$bootpart"
				fi
				label=$(echo "$entry" | cut -d : -f3)
				if [ -z "$label" ]; then
					label="$title"
				fi
				kernel=$(echo "$entry" | cut -d : -f4)
				initrd=$(echo "$entry" | cut -d : -f5)
				if echo "$kernel" | grep -q '^/boot/' && \
				   [ "$mappedbootpart" != "$mappedpartition" ]; then
					# separate /boot partition
					kernel=$(echo "$kernel" | sed 's!^/boot!!')
					initrd=$(echo "$initrd" | sed 's!^/boot!!')
					grubdrive=$(convert "$mappedbootpart") || true
				else
					grubdrive=$(convert "$mappedpartition") || true
				fi
				params="$(echo "$entry" | cut -d : -f6-) $serial"
				case $grub_version in
				    grub)	grub_write_linux ;;
				    grub2)	grub2_write_linux ;;
				esac
				IFS="$newline"
			done
			IFS="$OLDIFS"
			;;
		    hurd)
			partition=$(mapdevfs $(echo "$os" | cut -d: -f1))
			grubdrive=$(convert "$partition") || true
			hurddrive=$(hurd_convert "$partition") || true
			# Use the standard hurd boilerplate to boot it.
			case $grub_version in
			    grub)	grub_write_hurd ;;
			    grub2)	grub2_write_hurd ;;
			esac
			;;
		    *)
			info "unhandled: $os"
			;;
		esac
		IFS="$newline"
	done
	IFS="$OLDIFS"
fi
rm -f /tmp/os-probed

if [ -s $tmpfile ] ; then
	case $grub_version in
	    grub)
		grub_write_divider
		cat $tmpfile >> $ROOT/boot/grub/$menu_file
		;;
	    grub2)
		if ! $chroot $ROOT which os-prober >/dev/null 2>&1; then
			cat > $ROOT/etc/grub.d/30_otheros << EOF
#!/bin/sh
exec tail -n +3 \$0
EOF
			cat $tmpfile >> $ROOT/etc/grub.d/30_otheros
			chmod +x $ROOT/etc/grub.d/30_otheros
			update_grub # propagate 30_otheros to grub.cfg
		fi
		;;
	esac
	rm -f $tmpfile
fi

case $ARCH in
    mipsel/loongson-2f)
	# Configure PMON to load GRUB by default.
	if [ ! -e $ROOT/boot.cfg ] && [ ! -e $ROOT/boot/boot.cfg ]; then
		pmon_partition="$(grub_probe -d -t drive "$bootfs" | \
				  sed 's/.*,//; s/[^0-9]//g')"
		if [ "$pmon_partition" ]; then
			pmon_partition=$(($pmon_partition - 1))
		else
			pmon_partition=0 # fallback guess
		fi
		if [ "$rootfs" = "$bootfs" ]; then
			pmon_grub_path=/boot/grub.elf
			pmon_boot_cfg_path=$ROOT/boot.cfg
		else
			pmon_grub_path=/grub.elf
			pmon_boot_cfg_path=$ROOT/boot/boot.cfg
		fi
		cat > $pmon_boot_cfg_path <<EOF
default 0
timeout 0
showmenu 0

title Boot with GRUB
	kernel (wd0,$pmon_partition)$pmon_grub_path
	args nil
EOF
	fi
	;;
esac

db_progress STEP 1
db_progress INFO grub-installer/progress/step_update_etc

if [ -e $ROOT/etc/kernel-img.conf ] ; then
	sed -i 's/do_bootloader = yes/do_bootloader = no/' $ROOT/etc/kernel-img.conf
fi
if [ ! -e $ROOT/etc/kernel/postinst.d/zz-update-grub ] && \
   [ -z "$(grep update-grub $ROOT/etc/kernel-img.conf)" ]; then
	(
		echo "postinst_hook = update-grub"
		echo "postrm_hook   = update-grub"
	) >> $ROOT/etc/kernel-img.conf
fi

db_progress STEP 1
db_progress STOP

if [ "$(udpkg --print-os)" = "linux" ] && ! umount $ROOT/run; then
	info "Failed to unmount /run in $ROOT"
fi
if ! umount $ROOT/proc; then
	info "Failed to unmount /proc in $ROOT"
fi

