#!/bin/bash

# constants
VERSION='@VERSION@'     # updated at install time
DEBUG=0
DD="dd status=none"
DBSTCK_DIR="/usr/share/debootstick"

# get cmdline parsing and os-detection functions
. $DBSTCK_DIR/scripts/create-image/cmdline
. $DBSTCK_DIR/scripts/create-image/os-detect

# check options
root_password_request="NO_REQUEST"
root_password_on_first_boot=0
config_grub_on_serial_line=0
system_type="live"
layout_file="default"
kernel_bootargs=""
config_hostname=""
chroot_in=""
image_out=""

parse_args()
{
    while [ $# != 0 ]
    do
        case "$1" in
            -h|--help)
                usage_and_exit 0
            ;;
            --help-os-support)
                describe_os_support
                exit 0
            ;;
            -v|--version)
                echo "debootstick $VERSION"
                exit 0
            ;;
            --kernel-package)
                kernel_package="$2"
                shift 2
            ;;
            --config-kernel-bootargs)
                kernel_bootargs="$2"
                shift 2
            ;;
            --config-root-password-ask)
                root_password_request="ASK"
                shift
            ;;
            --config-root-password-none)
                root_password_request="NO_PASSWORD"
                shift
            ;;
            --config-root-password-first-boot)
                root_password_on_first_boot=1
                shift
            ;;
            --config-hostname)
                config_hostname="$2"
                shift 2
            ;;
            --config-grub-on-serial-line)
                config_grub_on_serial_line=1
                shift
            ;;
            --system-type)
                system_type="$2"
                shift 2
            ;;
            --disk-layout)
                layout_file="$2"
                shift 2
            ;;
            -*)
                echo "Unknown option '$1'. Exiting." >&2
                exit 1
            ;;
            *)
                break
            ;;
        esac
    done

    # we need 2 more args
    if [ -z "$2" ]
    then
        usage_and_exit 1
    fi

    chroot_in="$1"
    image_out="$2"
}

parse_args "$@"

# let's verify system_type variable
case "$system_type" in
    'live'|'installer')
        ;;  # ok
    *)
        echo "--system-type option value must be either 'live' or 'installer'." >&2
        exit 1
esac

# let's verify layout_file variable
if [ "$layout_file" != "default" ]
then
    if [ ! -r "$layout_file" ]
    then
        echo "disk layout file '$layout_file' not found or not readable." >&2
        exit 1
    fi
fi

# ensure we are root
if [ $(id -u) -ne 0 ]; then
    echo "debootstick should be run as root. Trying sudo..."
    exec sudo "$0" "$@"
fi

# check that $image_out is a writable file path
if [ ! -w $(dirname "$image_out") ]
then
    usage_and_exit
fi

# $chroot_in should be a directory
if [ ! -d "$chroot_in" ]
then
    usage_and_exit
fi

# this directory should contain a system
# file hierarchy (1st level of checks)
check_fs_hierarchy "$chroot_in" 1 || exit 1

# detect target type
target_type="$(detect_target_type "$chroot_in")"
[ -z "$target_type" ] && exit 1

# get common and target-specific functions
functions="$(
    cat "$DBSTCK_DIR"/scripts/create-image/common/*
    cat $(find "$DBSTCK_DIR"/scripts/create-image/target/$target_type/ \
                    -type f ! -name detect.sh)
)"

# have them available here and in chrooted scripts
eval "$functions"
export chrooted_functions="$functions"
probe_target_optional_functions

if $target_get_bootloader_install_command_exists
then
    bootloader_install_command=$(target_get_bootloader_install_command)
fi

if [ "$system_type" = "installer" ]
then
    if [ -z "$bootloader_install_command" ] || ! $(target_use_lvm)
    then
        # cannot use installer mode if target does not use LVM or does not
        # specify a bootloader installation procedure.
        echo "Sorry, this target does not support installer system type." >&2
        exit 1
    fi
fi

# if we are here, command line is ok :)
if [ "$root_password_request" = "ASK" ]
then
    while true
    do
        read -s -p "Enter embedded-os root password: " passwd1
        echo
        read -s -p "Enter embedded-os root password again: " passwd2
        echo
        if [ "$passwd1" = "$passwd2" ]
        then
            echo 'OK'
            root_password_request="root:$passwd1"
            break
        else
            echo 'Sorry, passwords do not match, please retry.'
        fi
    done
fi

ORIG_TREE="$(cd "$chroot_in"; pwd)"
STICK_OS_ID=$(uuidgen | tr -d '-' | head -c 8)
DBSTCK_TMPDIR=$(mktemp -du --tmpdir tmp.dbstck.XXXXX.d)
final_image_path="$image_out"
final_image_abspath="$(abspath "$image_out")"
if [ "$DEBUG" = "1" ]
then
    CHROOTED_DEBUG="--debug"
fi

final_cleanup()
{
    return_code=$1
    if [ "$1" -gt 0 ]   # if error
    then
        rm -f $final_image_abspath
    fi
}

echo "I: detected target system: $(target_get_name)"

start_failsafe_mode --toplevel final_cleanup

failsafe mkdir -p $DBSTCK_TMPDIR

# step: parse and verify the layout file
default_layout_file="$DBSTCK_DIR/disk-layouts/target/$target_type/disk-layout"
if [ "$layout_file" = "default" ]
then
    layout_file="$default_layout_file"
    echo "I: using default disk layout: $default_layout_file"
else
    layout_file=$(abspath "$layout_file")
    echo -n "I: verifying disk layout file... "
fi
layout_dir="$DBSTCK_TMPDIR/.layout"
parse_layout "$layout_dir" < "$layout_file"
check_layout "$layout_dir"
if [ "$layout_file" != "$default_layout_file" ]
then
    def_layout_dir="$DBSTCK_TMPDIR/.def-layout"
    parse_layout "$def_layout_dir" < "$default_layout_file"
    check_layout_updates "$def_layout_dir" "$layout_dir"
    echo done
fi

need_fatresize=$(check_need_fatresize "$layout_dir")

cd $DBSTCK_TMPDIR
# execute target-specific preliminary steps, if any
optional_target_preliminary_steps

# step: create draft image structure
echo -n "I: draft image - partitioning and formatting... "
create_formatted_image \
        draft \
        "$ORIG_TREE" \
        $STICK_OS_ID
draft_rootfs_mountpoint="$DBSTCK_TMPDIR/draft/fs"
echo done

# step: copy original tree to work image and modify it
echo -n "I: draft image - copying filesystem tree... "
cd $draft_rootfs_mountpoint
cp -au "$ORIG_TREE"/* .
echo done

# execute target-specific preparation steps, if any
optional_target_prepare_rootfs draft outside

# 2nd level of checks of input file hierarchy
check_fs_hierarchy "$PWD" 2 || exit 1

echo -n "I: draft image - generating fstab... "
generate_fstab "$layout_dir"
echo done

mkdir -p opt/debootstick
cp -a $DBSTCK_DIR/scripts/live opt/debootstick/live
cp -a $DBSTCK_DIR/scripts/create-image/chrooted-customization-draft.sh .
draft_device="$(readlink $DBSTCK_TMPDIR/draft/device)"
with mount -o bind /run $PWD/run; do
    # let's start the customization
    chroot . ./chrooted-customization-draft.sh $CHROOTED_DEBUG    \
            "$draft_device" "$root_password_request"        \
            stick_os_id=$STICK_OS_ID   \
            config_grub_on_serial_line=$config_grub_on_serial_line  \
            kernel_package="\"$kernel_package\""    \
            kernel_bootargs="\"$kernel_bootargs\"" \
            config_hostname="\"$config_hostname\"" \
            need_fatresize=$need_fatresize
done
rm ./chrooted-customization-draft.sh

# execute target-specific cleanup steps, if any
optional_target_cleanup_rootfs draft outside

# step: finalyse filesystem setup
finalize_fs $draft_rootfs_mountpoint

# step: prepare a final image with minimal size
echo -n "I: final image - partitioning and formatting... "
create_formatted_image \
        final \
        $draft_rootfs_mountpoint \
        ${STICK_OS_ID} \
        $final_image_abspath
final_rootfs_mountpoint="$DBSTCK_TMPDIR/final/fs"
echo done
echo -n "I: final image - copying content from draft image... "
cp -au $draft_rootfs_mountpoint/* $final_rootfs_mountpoint/
echo done
release_image draft     # not needed anymore

# complete the dbstck.conf file
cat >> $final_rootfs_mountpoint/dbstck.conf << EOF
STICK_OS_ID=$STICK_OS_ID
USE_LVM=$(target_use_lvm)
SYSTEM_TYPE=$system_type
ASK_ROOT_PASSWORD_ON_FIRST_BOOT=$root_password_on_first_boot
BOOTLOADER_INSTALL=$bootloader_install_command
PARTITIONS="$(dump_partition_volumes_info "$layout_dir")"
LVM_VOLUMES="$(dump_lvm_volumes_info "$layout_dir")"
IMAGE_SIZE_MB="$(cat $layout_dir/needed_size_mb)"
EOF

if [ -f "$layout_dir"/final_vg_name ]
then
    cat >> $final_rootfs_mountpoint/dbstck.conf << EOF
FINAL_VG_NAME="$(cat "$layout_dir"/final_vg_name)"
VG_RENAME="$(target_get_vg_rename_command)"
EOF
fi

# step: customize final OS
cd $final_rootfs_mountpoint
final_device="$(readlink $DBSTCK_TMPDIR/final/device)"

echo -n "I: final image - generating fstab... "
generate_fstab "$layout_dir"
echo done

# execute target-specific preparation steps, if any
optional_target_prepare_rootfs final outside

# since the size of the filesystem mounted there is minimized,
# creating new files may cause problems.
# so we will use the directory /tmp that we mount in memory.
with mount -t tmpfs none $final_rootfs_mountpoint/tmp; do
    with mount -o bind /run $PWD/run; do
        cp -a $DBSTCK_DIR/scripts/create-image/chrooted-customization-final.sh tmp
        chroot . tmp/chrooted-customization-final.sh "$final_device"
    done
done

# execute target-specific cleanup steps, if any
optional_target_cleanup_rootfs final outside

cd ..

# execute target-specific final steps, if any
optional_target_final_customization_steps ${STICK_OS_ID}

# step: clean up
echo -n "I: cleaning up... "
undo_all
echo done

chmod u+rw $final_image_abspath
stick_size=$(real_size_human_readable $final_image_abspath)
echo "I: $final_image_path ready (size: ${stick_size}). "

