#!/bin/bash
# Make custom ISO image for partner.
# Arguments:
#   key of space to make ISO for
#
# © 2012, Multapplied Networks, Inc.

# Space key is a mandatory argument
if [ "$#" -ne 1 ] ; then
    echo "Space key is a required argument" 1>&2
    exit 1
fi

SPACE_KEY="$1"

if [ "$(whoami)" != "bondingadmin" ] ; then
    sudo -u bondingadmin /usr/sbin/make-debian-8-iso "$@"
    exit $?
fi

should_create_iso=$(ba should_create_iso "$SPACE_KEY" > /dev/null 2>&1)
if [ "$?" -ne 0 ] ; then
    echo "ISOs can't be created for this space."
    exit 1
fi

set -e


# Load arguments
ISO_INPUT_DIR="/var/lib/bondingadmin/base-isos/"
ISO_OUTPUT_DIR="/var/lib/bondingadmin/isos/$SPACE_KEY"
ISO_APPEND="_$SPACE_KEY"
ISO_DEFAULT_FILES_DIR="/usr/share/bondingadmin/default/iso.d"
ISO_LOCAL_FILES_DIR="/etc/bondingadmin/iso.d"
PRESEED_SCRIPTS="/usr/share/bondingadmin/installer-scripts/*.sh"
BONDINGADMIN_CONF="/etc/bondingadmin/bondingadmin.conf"

# These values cannot be preseeded; they must be in the kernel parameters.
DI_LOCALE="en_CA.UTF-8"
DI_LANG="English"
DI_KEYMAP="us"
DI_CONSOLE_V="tty0" # Virtual terminal 0 (Ctrl-Alt-F1)
DI_CONSOLE_S="ttyS0,115200n8" # Serial: COM1, 115200 baud, no parity, 8 data bits, 1 stop bit, no flow control.
DI_CONSOLE_S_ALT="ttyS1,115200n8" # Serial: COM2, 115200 baud, no parity, 8 data bits, 1 stop bit, no flow control. (for things like the netgate devices with usb serial)

# Get the management server setting from BONDINGADMIN_CONF
MGMT_URL=$(grep 'mgmt_server_url' "$BONDINGADMIN_CONF" | gawk '{ print $3 }')
CREATION_DATE=$(date +%F)
MGMT_SERVER="$MGMT_URL (${CREATION_DATE})"

test -f /etc/default/bondingadmin/make-iso && . /etc/default/bondingadmin/make-iso

if [ -d "$ISO_OUTPUT_DIR" ] ; then
    echo -n "Cleaning output directory: "
    rm -rf $ISO_OUTPUT_DIR/*
else
    echo -n "Creating output directory: "
    mkdir -p $ISO_OUTPUT_DIR
fi
echo "done."

TMPDIR=$(mktemp -d)
trap 'rm -rf $TMPDIR' EXIT

if [[ ! -z `ls $ISO_INPUT_DIR` ]]; then
    iso_amd64="$ISO_INPUT_DIR/debian-bonding-amd64.iso"
    iso_i386="$ISO_INPUT_DIR/debian-bonding-i386.iso"
else
    echo "Unable to sync base ISOs." 1>&2
    exit 1
fi

function prep_base_iso_dir() {
    base_iso=$1; shift

    base_iso_name=$(basename $base_iso)
    base_iso_filename=${base_iso_name%.*}
    base_iso_unpack_dir="$TMPDIR/$base_iso_filename"

    # Clear and re-create ISO directory
    mkdir -p $base_iso_unpack_dir
    /usr/bin/bsdtar -C $base_iso_unpack_dir -xf $base_iso
    chmod -R u+rw $base_iso_unpack_dir

    echo $base_iso_unpack_dir
}

function unpack_base_iso() {
    base_iso_unpack_dir=$1; shift

    # Prepare custom filesystem
    # Remove vesamenu.c32, and use menu.c32 instead
    cp /usr/lib/syslinux/modules/bios/menu.c32 $base_iso_unpack_dir/isolinux/menu.c32
    rm -f $base_iso_unpack_dir/isolinux/vesamenu.c32

    for preseed in auto std net ; do
        wget http://localhost/preseed-${preseed}.cfg?space=$SPACE_KEY -q -O $base_iso_unpack_dir/preseed-${preseed}.cfg
    done

    cp $PRESEED_SCRIPTS $base_iso_unpack_dir
    cp -r $ISO_DEFAULT_FILES_DIR/* $base_iso_unpack_dir
    cp -r $ISO_LOCAL_FILES_DIR/* $base_iso_unpack_dir 2> /dev/null || true # This might be empty

    installdir=$(echo $base_iso_unpack_dir/install.* | cut -d ' ' -f 1)
    ARCH=${installdir:(-3)}

    sed -i -e "s/%DI_LOCALE%/$DI_LOCALE/g"\
        -e "s/%DI_LANG%/$DI_LANG/g"\
        -e "s/%DI_KEYMAP%/$DI_KEYMAP/g"\
        -e "s/%DI_CONSOLE_V%/$DI_CONSOLE_V/g"\
        -e "s/%DI_CONSOLE_S%/$DI_CONSOLE_S/g"\
        -e "s/%DI_CONSOLE_S_ALT%/$DI_CONSOLE_S_ALT/g"\
        -e "s/%ARCH%/$ARCH/g"\
        -e "s/%MGMT_SERVER%/$MGMT_SERVER/g"\
        $base_iso_unpack_dir/isolinux/txt.cfg $base_iso_unpack_dir/boot/grub/grub.cfg $base_iso_unpack_dir/isolinux/stdmenu.cfg

    md5sum $(find $base_iso_unpack_dir -type f ! -name "md5sum.txt" ! -path "$base_iso_unpack_dir/isolinux/*" ! -name "debian") > $base_iso_unpack_dir/md5sum.txt

    # Let's save some space...
    rm -rf $base_iso_unpack_dir/install.386/gtk
    rm -rf $base_iso_unpack_dir/install.amd/gtk
    test -e $base_iso_unpack_dir/doc && rm -r $base_iso_unpack_dir/doc
}

function make_uefi() {
    # Modern, with UEFI and BIOS support
    directory=$1; shift
    iso_name=$1; shift

    target_iso_path="$TMPDIR/$iso_name.iso"
    /usr/bin/xorriso \
        -as mkisofs \
        -r \
        -V $iso_name \
        -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin \
        -b isolinux/isolinux.bin \
        -c isolinux/boot.cat \
        -no-emul-boot \
        -boot-load-size 4 \
        -boot-info-table \
        -eltorito-alt-boot \
        -e boot/grub/efi.img \
        -no-emul-boot \
        -isohybrid-gpt-basdat \
        -isohybrid-apm-hfsplus \
        -o $target_iso_path \
        $directory &> /dev/null

    cp -f $target_iso_path $ISO_OUTPUT_DIR
}

function make_bios() {
    # BIOS-only
    # Unfortunately there are some UEFI implementations that boot from MBR
    # and fail to boot if GPT is present. We generate a ISO containing only
    # BIOS support for this.
    # For some extra details see these links
    # http://www.syslinux.org/wiki/index.php?title=Isohybrid
    # http://wiki.osdev.org/Broken_UEFI_implementations#GIGABYTE_Hybrid_EFI
    directory=$1; shift
    iso_name=$1; shift

    target_iso_path="$TMPDIR/$iso_name.iso"
    /usr/bin/xorriso \
        -as mkisofs \
        -r \
        -V $iso_name \
        -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin \
        -b isolinux/isolinux.bin \
        -c isolinux/boot.cat \
        -no-emul-boot \
        -boot-load-size 4 \
        -boot-info-table \
        -o $target_iso_path \
        $directory &> /dev/null

    cp -f $target_iso_path $ISO_OUTPUT_DIR

}

echo -n "Making amd64 ISOs: prepare"
base_amd64_iso=$(prep_base_iso_dir $iso_amd64)
echo -n " unpack"
unpack_base_iso $base_amd64_iso
echo -n " create"
make_uefi $base_amd64_iso "debian-bonding-amd64-uefi$ISO_APPEND"
make_bios $base_amd64_iso "debian-bonding-amd64-bios$ISO_APPEND"
echo "."

echo -n "Making i386 ISO: prepare"
base_i386_iso=$(prep_base_iso_dir $iso_i386)
echo -n " unpack"
unpack_base_iso $base_i386_iso
echo -n " create"
make_bios $base_i386_iso "debian-bonding-i386-bios$ISO_APPEND"
echo "."
