#!/bin/sh
set -e

# Program to search for disks with a correct yaboot setup, and then
# prompt the user for which one to install yaboot on.
#
# Copyright (C) 2004 Colin Watson <cjwatson@debian.org>
# Copyright (C) 2003 Gaudenz Steinlin <gaudenz@soziologie.ch>
# Copyright (C) 2003 Thorsten Sauter <tsauter@gmx.net>
# Copyright (C) 2002 Colin Walters <walters@gnu.org>

. /usr/share/debconf/confmodule

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

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

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

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

writefile () {
    cat >>"$1" || die yaboot-installer/conferr "Error writing $2"
}

findfs () {
    mount | grep "on /target${1%/} " | cut -d' ' -f1
}

db_capb backup

db_progress START 0 6 yaboot-installer/progress

die() {
    template="$1"
    shift

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

# Install yaboot in /target

db_progress INFO yaboot-installer/apt-install

if ! apt-install yaboot hfsutils powerpc-utils; then
    info "Calling 'apt-install yaboot hfsutils powerpc-utils' failed"
    # Hm, unable to install yaboot into /target/, what should we do?
    db_input critical yaboot-installer/apt-install-failed || [ $? -eq 30 ]
    if ! db_go; then
	db_progress STOP
	exit 10 # back up to menu
    fi
    db_get yaboot-installer/apt-install-failed
    if [ "$RET" != true ]; then
	db_progress STOP
	exit 1
    fi
fi

# Find the boot partition

db_progress STEP 1
db_progress INFO yaboot-installer/part

db_get debian-installer/kernel/subarchitecture
SUBARCH="$RET"
info "subarchitecture: $SUBARCH"

# Telling parted to create an Apple_Bootstrap partition doesn't work as well
# as we might like: parted's probe function isn't intelligent enough to know
# about this, and reports the partition as containing whatever filesystem
# was there beforehand.
#
# As a workaround, we only check for partitions with the boot flag set, and
# don't bother checking the filesystem. However, this means that we *must*
# ask the user to confirm the bootstrap partition, otherwise we might
# mistakenly overwrite some other partition that happened to be flagged as
# bootable.

PARTITIONS=
DEFAULT=
bootdev_priority=critical

if [ "$SUBARCH" = powermac_newworld ] && \
   db_get partman-newworld/boot_partitions && [ "$RET" ]; then
    OLDIFS="$IFS"
    IFS=,
    for part in $RET; do
	IFS="$OLDIFS"
	mappart="$(mapdevfs "$part")"
	if [ -z "$PARTITIONS" ]; then
	    DEFAULT="$mappart"
	    PARTITIONS="$mappart"
	else
	    PARTITIONS="$PARTITIONS,$mappart"
	fi
	IFS=,
    done
    IFS="$OLDIFS"
    info "partman-supplied bootstrap partitions: $PARTITIONS"
    info "partman-supplied default bootstrap partition: $DEFAULT"
    if [ "$PARTITIONS" ] && [ "$DEFAULT" = "$PARTITIONS" ]; then
	# We have explicit information from partman-newworld that only one
	# bootstrap partition is available, so it's safe to bypass this
	# question.
	bootdev_priority=medium
    fi
fi

if [ -z "$PARTITIONS" ]; then
    case $SUBARCH in
	powermac_newworld)
	    PARTED_MATCH='boot'
	    ;;
	chrp|chrp_rs6k)
	    PARTED_MATCH='prep.*'
	    ;;
	*)
	    error 'unknown subarchitecture; allowing any bootable partition'
	    PARTED_MATCH='boot'
	    ;;
    esac

    for i in /dev/discs/*/disc; do
	info "parted dump of partition table on $i:"
	parted -s "$i" print | logger -t yaboot-installer
	dev="`parted -s "$i" print | sed -n 's,^Disk geometry for \([^:]*\)/disc:.*$,\1,p'`"
	# Look for partitions with the boot flag set.
	for part in `parted -s "$i" print | sed -n 's,^\([0-9]\+\) .* '"$PARTED_MATCH"'$,'"$dev"'/part\1,p'`; do
	    mappart="$(mapdevfs "$part")"
	    if [ -z "$PARTITIONS" ]; then
		DEFAULT="$mappart"
		PARTITIONS="$mappart"
	    else
		PARTITIONS="$PARTITIONS,$mappart"
	    fi
	done
	info "guessed bootstrap partitions: $PARTITIONS"
	info "guessed default bootstrap partition: $DEFAULT"
    done
fi

if [ -z "$PARTITIONS" ]; then
    # error: no viable boot partitions found; fall over
    die yaboot-installer/nopart 'No bootstrap partitions found'
fi

db_subst yaboot-installer/bootdev DEVICES "$PARTITIONS"
db_set yaboot-installer/bootdev "$DEFAULT"
db_input "$bootdev_priority" yaboot-installer/bootdev || [ $? -eq 30 ]
if ! db_go; then
    db_progress STOP
    exit 10 # back up to menu
fi

db_get yaboot-installer/bootdev
if [ "$RET" = false ]; then
    die yaboot-installer/nopart 'No bootstrap partition selected (?)'
fi
# already devfs-mapped
boot="$RET"

# Find the root partition

db_progress STEP 1
db_progress INFO yaboot-installer/root

rootdev="$(findfs /)"
[ "$rootdev" ] || die yaboot-installer/noroot 'No root partition found'

slashbootdev="$(findfs /boot)"
[ "$slashbootdev" ] || slashbootdev="$rootdev"

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

# mkofboot needs proc in /target
mountvirtfs proc /target/proc
# ofpath needs sysfs in /target for 2.6
mountvirtfs sysfs /target/sys

# Probe for other OSes.

db_progress STEP 1
db_progress INFO yaboot-installer/os-probing

os-prober >/tmp/os-probed || true

extraglobals=/tmp/yaboot.conf.extraglobals
rm -f "$extraglobals"
extraimages=/tmp/yaboot.conf.extraimages
rm -f "$extraimages"

writeglobals() {
    writefile "$extraglobals" 'extra global settings'
}

writeimages() {
    writefile "$extraimages" 'extra image records'
}

# Get the Open Firmware path for a device. Requires non-devfs syntax.
map_of_path() {
    chroot /target ofpath "$1" || return 1
}

OLDIFS="$IFS"
IFS=:
# Note that this creates a subshell, so variables set inside this loop won't
# persist outside it.
cat /tmp/os-probed | while read partition title label loadertype; do
    IFS="$OLDIFS"
    info "probed: $partition:$title:$label:$loadertype"
    mappedpartition="$(mapdevfs "$partition")"
    debug "mapped: $mappedpartition"
    # You only get the first of each non-Linux OS here, as that's all
    # yaboot supports without painful hacking. Sorry.
    case $loadertype in
	linux)
	    IFS=:
	    linux-boot-prober "$partition" | while read \
		    rootpart bootpart label kernel initrd params; do
		IFS="$OLDIFS"
		info "linux-boot-probed:" \
		     "$rootpart:$bootpart:$label:$kernel:$initrd:$params"
		ofrootpart="$(map_of_path "$mappedpartition")" || continue
		debug "OF root partition: $ofrootpart"
		# bootpart may or may not be in devfs syntax.
		mappedbootpart="$(mapdevfs "$bootpart")" || \
		    mappedbootpart="$bootpart"
		debug "mapped boot partition: $mappedbootpart"
		ofbootpart="$(map_of_path "$mappedbootpart")" || continue
		debug "OF boot partition: $ofbootpart"
		if [ -z "$label" ]; then
		    label="$title"
		fi
		# Prepend the last part of the partition name to the label,
		# for uniqueness and (I hope) clarity, given that we don't
		# have a way to display a useful description in yaboot.
		label="${mappedbootpart##*/}-$label"
		if echo "$kernel" | grep -q '^/boot/' && \
		   [ "$mappedbootpart" != "$mappedpartition" ]; then
		    # separate /boot partition
		    kernel="${kernel#/boot}"
		    initrd="${initrd#/boot}"
		fi
		writeimages <<EOF

# This entry automatically added by the Debian installer for an existing
# Linux installation on $mappedpartition.
image=$ofbootpart,$kernel
    label=$label
    root=$ofrootpart
    append="$params"
EOF
		if [ -n "$initrd" ]; then
		    writeimages <<EOF
    initrd=$ofbootpart,$initrd
EOF
		fi
		IFS=:
	    done
	    IFS="$OLDIFS"
	    ;;
	macosx)
	    if ! [ "$macosx" ]; then
		macosx=1
		echo "macosx=$mappedpartition" | writeglobals
	    fi
	    ;;
	macos)
	    if ! [ "$macos" ]; then
		macos=1
		echo "macos=$mappedpartition" | writeglobals
	    fi
	    ;;
	*)
	    info "unhandled: $partition:$title:$label:$loadertype"
	    ;;
    esac
    IFS=:
done
IFS="$OLDIFS"

# Generate yaboot.conf

db_progress STEP 1
db_progress INFO yaboot-installer/conf

root="`mapdevfs "$rootdev"`"
slashboot="`mapdevfs "$slashbootdev"`"

partnr="`printf %s "$slashboot" | sed 's/[^0-9]*\([0-9]\)/\1/'`"
disk="`printf %s "$slashboot" | sed 's/[0-9].*//'`"

ofpath="`chroot /target ofpath "$disk"`"

if [ -e /target/boot/vmlinux ]; then
    kernel=/boot/vmlinux
else
    kernel=/vmlinux
fi

if [ -e /target/boot/initrd.img ]; then
    initrd=/boot/initrd.img
elif [ -e /target/initrd.img ]; then
    initrd=/initrd.img
else
    initrd=
fi

# Is /boot on a separate partition?
if [ "$slashboot" != "$root" ]; then
    kernel="${kernel#/boot}"
    initrd="${initrd#/boot}"
fi

# Work out user parameters.
user_params="$(echo $(user-params))" || true

# we generate our own yaboot.conf kernel (yabootconfig is horribly broken)
# cjwatson: a little more justification of that would have been nice ...
# but it does seem clear that yabootconfig isn't flexible enough for our
# needs, e.g. OS probing.

rm -f /target/etc/yaboot.conf

writeyabootconf() {
    writefile /target/etc/yaboot.conf yaboot.conf
}

writeyabootconf <<EOF
## yaboot.conf generated by debian-installer
##
## run: "man yaboot.conf" for details. Do not make changes until you have!!
## see also: /usr/share/doc/yaboot/examples for example configurations.
##
## For a dual-boot menu, add one or more of:
## bsd=/dev/hdaX, macos=/dev/hdaY, macosx=/dev/hdaZ

boot=$boot
device=$ofpath
partition=$partnr
root=$root
timeout=100
install=/usr/lib/yaboot/yaboot
magicboot=/usr/lib/yaboot/ofboot
enablecdboot
EOF

if [ -s "$extraglobals" ]; then
    cat "$extraglobals" | writeyabootconf
    rm -f "$extraglobals"
fi

writeyabootconf <<EOF

image=$kernel
	label=Linux
	read-only
EOF
if [ "$initrd" ]; then
    writeyabootconf <<EOF
	initrd=$initrd
EOF
fi
if [ "$user_params" ]; then
    writeyabootconf <<EOF
	append="$user_params"
EOF
fi
writeyabootconf <<EOF

image=$kernel.old
	label=old
	read-only
EOF
if [ "$initrd" ]; then
    writeyabootconf <<EOF
	initrd=$initrd.old
EOF
fi
if [ "$user_params" ]; then
    writeyabootconf <<EOF
	append="$user_params"
EOF
fi

if [ -s "$extraimages" ]; then
    cat "$extraimages" | writeyabootconf
    rm -f "$extraimages"
fi

# Install into bootstrap partition

db_progress STEP 1
db_progress INFO yaboot-installer/ybin

chroot /target mkofboot -v -f || \
    die yaboot-installer/ybinerr "mkofboot failed with exit status $?"

# Done!

db_progress STEP 1
db_progress STOP

db_input medium yaboot-installer/success || [ $? -eq 30 ]
db_go || true
