#!/bin/bash

error() { echo "$@" 1>&1; }
debug() { [ ${VERBOSITY:-0} -lt "$1" ] || error "$@"; }

partition() {
    local target="" out="" ptype="L"
    while : ; do
        case "$1" in
            --ptype=*) ptype="${1#--ptype=}";;
            *) break;;
        esac
        shift;
    done
    target="$1"

    local size="" name="${target##*/}"

    size=$(awk '$4 == name { print $3 }' name="$name" /proc/partitions)
    [ $? -eq 0 -a -n "$size" ] ||
        { error "failed to get size of $name"; return 1; }

    # wipe the front and end (gpt is at end also)
    dd if=/dev/zero of="$target" bs=$((1024*1024)) count=1 >/dev/null 2>&1
    out=$(dd if=/dev/zero of="$target" bs=1024 \
          seek=$(($size-1024)) count=1024 2>&1)
    [ $? -eq 0 ] ||
        { error "failed to wipe end of $target [$size]: $out"; return 1; }

    local sfdisk_out="" sfdisk_in="$((1024*1024/512)),,$ptype,*" sfdisk_cmd=""
    sfdisk_cmd=( sfdisk --no-reread --force --Linux --unit S "$target" )
    debug 1 "sfdisking with: echo '$sfdisk_in' | ${sfdisk_cmd[*]}"
    sfdisk_out=$(echo "$sfdisk_in" | "${sfdisk_cmd[@]}" 2>&1)
    ret=$?
    [ $ret -eq 0 ] || {
        error "failed to partition $target [${sfdisk_out}]";
        return 1;
    }
    blockdev --rereadpt "$target"
    udevadm settle
    [ -b "${target}1" ] ||
        { error "no partition found ${target}1"; return 1; }
    wipefs --all "${target}1"
}

is_md() {
    case "${1##*/}" in
        md[0-9]) return 0;;
    esac
    return 1
}

install_grub() {
    local mp="$1"
    local cmdline tmp r=""
    shift
    local grubdevs
    grubdevs=( "$@" )
    
    tmp=$(chroot "$mp" dpkg-query --show \
        --showformat='${Status}\n' grub-pc)
    r=$?
    if [ $r -ne 0 -a $r -ne 1 ]; then
        error "failed to check if grub-pc installed";
        return 1;
    fi
    case "$tmp" in
        install\ ok\ installed) :;;
        *) debug 1 "grub-pc not installed, not doing anything";
            return 0;;
    esac

    # copy anything after '--' on cmdline to install'd cmdline
    read cmdline < /proc/cmdline
    local reconf="" newargs=""

    tmp="${cmdline##* -- }"
    if [ "$tmp" != "$cmdline" ]; then
        # there was an explicit '--', so copy stuff after it
        newargs="$tmp"
    elif [ "${cmdline#* console=}" != "${cmdline}" ]; then
        # there are 'console=' params, copy those.
        newargs=$(set -f; c=""; for p in $cmdline; do
            [ "${p#console}" = "$p" ] || c="$c $p"; done; echo "${c# }")
    fi

    if [ -n "$newargs" ]; then
        local n="GRUB_CMDLINE_LINUX_DEFAULT"
        local sede="s|$n=.*|$n=\"$newargs\"|"
        sed -i "$sede" "$mp/etc/default/grub" ||
            { error "failed to update /etc/default/grub"; return 1; }
        grep "$n" "$mp/etc/default/grub"
        reconf="dpkg-reconfigure grub-pc"
        debug 1 "updating cmdline to '${newargs}'"

        # LP: #1179940 . this fix was applied to raring, which
        # made changes above not stick.  This might not be the best
        # way to handle this, but we'll do it for now.
        local cicfg="etc/default/grub.d/50-cloudimg-settings.cfg"
        if [ -f "$mp/$cicfg" ]; then
            debug 1 "moved $cicfg out of the way"
            mv "$mp/$cicfg" "$mp/$cicfg.disabled"
        fi
    fi

    local short="" bd="" grubdev grubdevs_new=""
    grubdevs_new=()
    for grubdev in "${grubdevs[@]}"; do
        if is_md "$grubdev"; then
            short=${grubdev##*/}
            for bd in "/sys/block/$short/slaves/"/*; do
                [ -d "$bd" ] || continue
                bd=${bd##*/}
                bd="/dev/${bd%[0-9]}" # hack: part2bd
                grubdevs_new[${#grubdevs_new[@]}]="$bd"
            done
        else
            grubdevs_new[${#grubdevs_new[@]}]="$grubdev"
        fi
    done
    grubdevs=( "${grubdevs_new[@]}" )

    debug 1 "installing grub to: ${grubdevs[*]}"
    chroot "$mp" env DEBIAN_FRONTEND=noninteractive sh -ec '
        reconf=$1; shift;
        prober="/etc/grub.d/30_os-prober"
        [ -x $prober ] && chmod -x /etc/grub.d/30_os-prober
        if [ -z "$reconf" ]; then
            $reconf
        else
            update-grub
        fi
        [ -f $prober ] && chmod +x $prober
        for d in "$@"; do grub-install "$d" || exit; done' \
        -- "$reconf" "${grubdevs[@]}" </dev/null ||
        { error "failed to install grub!"; return 1; }
}

# vi: ts=4 expandtab syntax=shell
