#!/bin/bash
#
# ovirt-config-boot - configure local boot/root disk partitions

# SYNOPSIS
# ovirt-config-boot livecd_path bootparams reboot
#
#       livecd_path - where livecd media is mounted,
#                     parent of LiveOS and isolinux folders
#                     default is /live
#
#       bootparams  - extra boot parameters like console=...
#                     default is $OVIRT_BOOTPARAMS
#
#       reboot      - reboot after install
#                     default is yes

# Source functions library
. /etc/init.d/functions
. /usr/libexec/ovirt-functions

trap '__st=$?; stop_log; exit $__st' 0
trap 'exit $?' 1 2 13 15

ovirt_boot_setup() {
    local live=$1
    local bootparams=$2
    local disk
    local disk2
    local partN=-1
    log "installing the image."

    if [ "$OVIRT_ROOT_INSTALL" = "n" ]; then
        log "done."
        return
    fi

    if [ -e "$live/syslinux" ]; then
      syslinux=syslinux
    elif [ -e "$live/isolinux" ]; then
      syslinux=isolinux
    else
      syslinux=
    fi

    if [ ! -e "$live/LiveOS/squashfs.img" \
      -o ! -e "$live/$syslinux/version" ]; then
      log "source image not valid."
      return 1
    fi
    . /etc/default/version
    local current_version=$VERSION
    local current_major=$(echo $VERSION|cut -d. -f1)
    # image version
    . $live/$syslinux/version
    local new_major=$(echo $VERSION|cut -d. -f1)
    # only N.x -> N.y upgrades are allowed
    if [ "$current_major" != "$new_major" ]; then
      log_error "cannot upgrade from $current_version to $VERSION."
      return 1
    fi

    grub_dev="$(findfs LABEL=Boot 2>&1)"
    if [ $? -eq 0 ]; then
        # minimal boot partition for iscsi root
        mount "$grub_dev" /boot
        mountpoint /boot > /dev/null
        if [ $? -ne 0 ] ; then
            log_error "Boot partition not available"
            return 1
        fi
        # Grab OVIRT_ISCSI VARIABLES from boot partition for upgrading
        # file created only if OVIRT_ISCSI_ENABLED=y
        if [ -f /boot/ovirt ]; then
            . /boot/ovirt
            iscsiadm -p $OVIRT_ISCSI_TARGET_IP:$OVIRT_ISCSI_TARGET_PORT -m discovery -t sendtargets
            log "Restarting iscsi service"
            service iscsi restart
        fi
    fi

    local oldtitle
    if [ "$OVIRT_ISCSI_ENABLED" != "y" ]; then
        # get title for the current Root
        /sbin/dmsetup mknodes
        if [ $? -ne 0 ] ; then
          log_error "Could not create DM links"
          return 1
        fi
        mount -r LABEL=Root /liveos
        mountpoint /liveos > /dev/null
        if [ $? -ne 0 ] ; then
          log_error "Root partition not available"
          return 1
        fi

        initrd_dest="/liveos"
        grub_dir="/liveos/grub"
        grub_prefix="/grub"

        if [ -e "$initrd_dest/vmlinuz0" -a -e "$initrd_dest/initrd0.img" ]; then
            oldtitle="BACKUP $(grep ^title ${grub_dir}/grub.conf|head -n1|cut -c7-)"
        fi
        umount /liveos

        # prepare Root partition update
        rc=1
        candidate_dev="$(findfs LABEL=RootBackup 2>/dev/null)"
        if [ $? -eq 0 ]; then
            e2label "$candidate_dev" RootNew
            rc=$?
        else
            candidate_dev="$(findfs LABEL=RootUpdate 2>/dev/null)"
            if [ $? -eq 0 ]; then
                e2label "$candidate_dev" RootNew
                rc=$?
            else
                candidate_dev="$(findfs LABEL=RootNew 2>/dev/null)"
                rc=$?
                umount /liveos ||:
            fi
        fi
        if [ $rc -ne 0 ]; then
            log_error "root partition not available."
            log_error "$(ls -al /dev/disk/by-label)"
            return $rc
        fi

        mount "$candidate_dev" /liveos

        rm -rf /liveos/LiveOS
        mkdir -p /liveos/LiveOS
        grub_dev="$candidate_dev"

    else
        initrd_dest="/boot"
        grub_dir="/boot/grub"
        grub_prefix="/grub"
        oldtitle=
    fi

    # find partition number for GRUB, $4 is to allow 0 as a partition number for grub
    get_part_info "$grub_dev" disk partN y
    rc=$?
    if [ $rc -ne 0 -o "$partN" -lt 0 ]; then
      log_error "unable to determine Root partition"
      return 1
    fi

    cp -p $live/$syslinux/version /liveos
    rc=$?
    if [ $rc -ne 0 ]; then
        log_error "version details copy failed."
        return $rc
    fi

    cp -p $live/$syslinux/vmlinuz0 $initrd_dest \
    && cp -p $live/$syslinux/initrd0.img $initrd_dest
    rc=$?
    if [ $rc -ne 0 ]; then
        log_error "kernel image copy failed."
        return $rc
    fi

    if [ "$OVIRT_ISCSI_ENABLED" != "y" ]; then
        cp -p $live/LiveOS/squashfs.img /liveos/LiveOS
        rc=$?
        if [ $rc -ne 0 ]; then
            log_error "squashfs image copy failed."
            return $rc
        fi
    fi

    if [ "$OVIRT_ISCSI_ENABLED" = "y" ]; then
        root_part="root=LABEL=ovirt-node-root"
        bootparams="ro rootfstype=ext2 rootflags=ro $bootparams \
                    netroot=iscsi:$OVIRT_ISCSI_TARGET_IP::$OVIRT_ISCSI_TARGET_PORT::$OVIRT_ISCSI_NODE_NAME ip=eth0:dhcp"
    else
        root_part="root=live:LABEL=Root"
        bootparams="ro rootfstype=ext2 rootflags=ro $bootparams"
    fi
    mkdir -p $grub_dir
    mkdir -p $grub_dir/efi
    mount LABEL=EFI $grub_dir/efi
    cp -ra /boot/efi/* $grub_dir/efi
    umount $grub_dir/efi
    cat > $grub_dir/grub.conf << EOF
default saved
timeout 5
hiddenmenu
title $PRODUCT (${VERSION}-${RELEASE})
    root (hd0,$partN)
    kernel /vmlinuz0 $root_part $bootparams
    initrd /initrd0.img
EOF
    local backup_entry=0
    if [ -n "$oldtitle" ]; then
        local partB
        partB=0
        if [ $partN = '0' ]; then
            partB='1'
        fi
        cat >> $grub_dir/grub.conf << EOF
title ${oldtitle}
    root (hd0,$partB)
    kernel /vmlinuz0 root=live:LABEL=RootBackup $bootparams
    initrd /initrd0.img
    savedefault
EOF
        backup_entry=1
    fi
    if echo "$disk" | grep -q " " ; then
        # workaround for grub setup failing with spaces in dev.name
        disk2=$(multipath -l "$disk" | awk '/ active / {print $3}')
        if [ -n "$disk2" ]; then
            disk="/dev/$disk2"
            # flush to sync DM and blockdev, workaround from rhbz#623846#c14
            echo 3 > /proc/sys/vm/drop_caches
            partprobe "$disk"
        fi
    fi
    echo "(hd0) $disk" > $grub_dir/device.map
    ( cd /usr/share/grub/*; cp -p stage? e2fs_stage1_5 $grub_dir )
    # grub setup will do direct changes
    sync
    grub --device-map=$grub_dir/device.map <<EOF
root (hd0,$partN)
setup --prefix=$grub_prefix (hd0)
EOF
    rc=$?
    if [ $rc -ne 0 ]; then
        log_error "boot loader install failed."
        return $rc
    fi

    if [ "$OVIRT_ISCSI_ENABLED" != "y" ]; then
        umount /liveos
        rc=$?
        if [ $rc -ne 0 ]; then
            log_error "umount /liveos failed."
            return $rc
        fi
        # mark new Root ready to go, reboot() in ovirt-function switches it to active
        e2label "$candidate_dev" RootUpdate
        mount "$candidate_dev" /liveos
        ln -snf /liveos/grub /boot/grub
        grub <<EOF_SAVEDEFAULT
savedefault --default=$backup_entry
savedefault --default=0 --once
EOF_SAVEDEFAULT
        umount /liveos
    fi

    if [ "$OVIRT_ISCSI_ENABLED" = "y" ]; then
        # copy defaults for when Root/HostVG is inaccessible(iscsi upgrade)
        cp $OVIRT_DEFAULTS /boot
    fi

    log "done."
}

live=$1
bootparams=$2
doreboot=$3
if [ -z "$live" -o "$live" = "-h" -o "$live" = "--help" ]; then
    cat <<EOF
Usage: $0 [livecd_path] [bootparams] [reboot(yes/no)]
       livecd_path - where livecd media is mounted,
                     parent of LiveOS and isolinux folders
                     default is /live

       bootparams  - extra boot parameters like console=...
                     default is "$OVIRT_BOOTPARAMS"

       reboot      - reboot after install
                     default is yes
EOF
    exit 1
fi

if ! is_local_storage_configured; then
    printf "\nLocal storage must be configured prior to installing \n"
    exit 99
fi

if [ -z "$bootparams" ]; then
    bootparams="$OVIRT_BOOTPARAMS"
fi
if [ -z "$doreboot" ]; then
    doreboot="yes"
fi

start_log
if [ "$OVIRT_ROOT_INSTALL" = "n" ]; then
    log "done."
    return
else
    ovirt_boot_setup "$live" "$bootparams"
fi
rc=$?
if [ $rc -eq 0 -a "$doreboot" = "yes" ]; then
    disable_firstboot
    if [ "$OVIRT_ISCSI_ENABLED" != "y" ]; then
        ovirt_store_firstboot_config
    fi
    stop_log

    reboot
fi
stop_log
exit $rc
