#!/bin/sh
##
## 2016 Darko Poljak (darko.poljak at ungleich.ch)
##
## This file is part of cdist.
##
## cdist is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## cdist is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with cdist. If not, see <http://www.gnu.org/licenses/>.

set -e

if [ "${debug}" ]
then
    set -x
    cdist_params="${cdist_params} -l 3"
fi

bootstrap_dir="${target_dir}"

case "${os}" in
    ubuntu|debian|devuan)
        # nothing, those are valid values
        ;;
    *)
        echo "ERROR: invalid os value: ${os}" >&2
        exit 1
        ;;
esac

check_bootstrap_dir() {
    if [ ! -e "$1" ]
    then
        echo "ERROR: bootstrap directory $1 does not exist" >&2
        exit 1
    fi
}

# bootstrap
if [ "${bootstrap}" ]
then
    if [ "${DEBOOTSTRAP_DIR}" ]
    then
        debootstrap_cmd="${DEBOOTSTRAP_DIR}/debootstrap"
    else
        command -v debootstrap 2>&1 > /dev/null || {
            echo "ERROR: debootstrap not found" >&2
            exit 1
        }
        debootstrap_cmd="debootstrap"
    fi

    # If PreOS on drive then do not check for directory emptiness.
    # Partition can at least contain 'lost+found' directory.
    if [ ! "${drive}" ]
    then
        if [ -e "${bootstrap_dir}" ]
        then
            dir_content=$(ls -A "${bootstrap_dir}" | wc -l)
        else
            dir_content=0
        fi
        if [ "${dir_content}" -ne 0 ]
        then
            echo "ERROR: "${bootstrap_dir}" not empty " >&2
            exit 1
        fi
    fi

    if [ "${verbose}" -o "${debug}" ]
    then
        echo "bootstrapping..."
    fi
    mkdir -p "${bootstrap_dir}"
    "${debootstrap_cmd}" --include=openssh-server --arch=${arch} ${suite} ${bootstrap_dir} \
        ${mirror} ${script}
    if [ "${verbose}" -o "${debug}" ]
    then
        echo "bootstrap finished"
    fi
fi

chroot_mount() {
    mount -t proc none "${bootstrap_dir}/proc" || true
    mount -t sysfs none "${bootstrap_dir}/sys" || true
    mount -o bind /dev "${bootstrap_dir}/dev" || true
    mount -t devpts none "${bootstrap_dir}/dev/pts" || true
}

chroot_umount() {
    umount "${bootstrap_dir}/dev/pts" || true
    umount "${bootstrap_dir}/dev" || true
    umount "${bootstrap_dir}/sys" || true
    umount "${bootstrap_dir}/proc" || true
}

TRAPFUNC="umount \"${bootstrap_dir}/dev/pts\" || true; \
umount \"${bootstrap_dir}/dev\" || true; \
umount \"${bootstrap_dir}/sys\" || true; \
umount \"${bootstrap_dir}/proc\" || true;"

# config
if [ "${configure}" ]
then
    if [ ! -f "${manifest}" ]
    then
        echo "ERROR: ${manifest} does not exist" >&2
        exit 1
    fi
    if [ ! -f "${remote_exec}" ]
    then
        echo "ERROR: ${remote_exec} does not exist" >&2
        exit 1
    fi
    if [ ! -f "${remote_copy}" ]
    then
        echo "ERROR: ${remote_copy} does not exist" >&2
        exit 1
    fi

    if [ "${keyfile_cnt}" -a "${keyfile_cnt}" -gt 0 ]
    then
        i="$((keyfile_cnt - 1))"
        keyfiles=""
        while [ "${i}" -ge 0 ]
        do
            kf_var="keyfile_${i}"
            eval kf='$'"${kf_var}"
            if [ ! -f "${kf}" ]
            then
                echo "ERROR: ${kf} does not exist" >&2
                exit 1
            fi
            key=$(cat "${kf}")
            keyfiles="${keyfiles} --key '${key}'"
            i=$((i - 1))
        done
        ssh_auth_keys_line="__ssh_authorized_keys root ${keyfiles}\n"
    else
        ssh_auth_keys_line=""
    fi

    check_bootstrap_dir "${bootstrap_dir}"

    if [ "${verbose}" -o "${debug}" ]
    then
        echo "configuring..."
    fi

    trap "${TRAPFUNC}" 0 1 2 3 15

    chroot_mount

    chroot "${bootstrap_dir}" /usr/bin/apt-get update

    if [ "${drive}" ]
    then
        grub_manifest_line="__package grub-pc --state present\n"
        grub_kern_params_line="__line linux_kernel_params \
--file /etc/default/grub \
--line 'GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash net.ifnames=0\"'\n"
    else
        grub_manifest_line=""
        grub_kern_params_line=""
    fi
    grub_lines="${grub_manifest_line}${grub_kern_params_line}"

    printf "${ssh_auth_keys_line}${grub_lines}" \
        | cat "${manifest}" - |\
        cdist config \
            ${cdist_params} -i - \
            --remote-exec "${remote_exec}" \
            --remote-copy "${remote_copy}" \
            "${bootstrap_dir}"

    # __hostname with systmed uses hostnamectl which needs dbus running
    # set hostname explicitly here instead
    printf "preos\n" > "${bootstrap_dir}/etc/hostname"

    chroot "${bootstrap_dir}" /usr/bin/apt-get autoclean
    chroot "${bootstrap_dir}" /usr/bin/apt-get clean
    chroot "${bootstrap_dir}" /usr/bin/apt-get autoremove

    chroot_umount

    trap - 0 1 2 3 15

    if [ "${verbose}" -o "${debug}" ]
    then
        echo "configuring finished"
    fi
fi

if [ "${pxe_boot_dir}" ]
then
    check_bootstrap_dir "${bootstrap_dir}"

    if [ "${verbose}" -o "${debug}" ]
    then
        echo "creating pxe..."
    fi

    mkdir -p "${pxe_boot_dir}"
    cp "${bootstrap_dir}"/boot/vmlinuz-* "${pxe_boot_dir}/kernel"
    cd "${bootstrap_dir}"
    find . -print0 | cpio --null -o --format=newc | gzip -9 > "${pxe_boot_dir}/initramfs"

    mkdir -p "${pxe_boot_dir}/pxelinux.cfg"
    cat <<EOPXEF > "${pxe_boot_dir}/pxelinux.cfg/default"
    DEFAULT preos
    LABEL preos
    KERNEL kernel
    APPEND utf8 load_ramdisk=1 root=/dev/ram nofb initrd=initramfs console=ttyS1,115200 net.ifnames=0
EOPXEF

    cp "${bootstrap_dir}/usr/lib/PXELINUX/pxelinux.0" "${pxe_boot_dir}/pxelinux.0"
    cp "${bootstrap_dir}/usr/lib/syslinux/modules/bios/ldlinux.c32" \
        "${pxe_boot_dir}/ldlinux.c32"
    # network boot need all files world readable
    chmod -R 644 "${pxe_boot_dir}"/*

    if [ "${verbose}" -o "${debug}" ]
    then
        echo "pxe creation finished"
    fi
fi

if [ "${drive}" ]
then
    trap "${TRAPFUNC}" 0 1 2 3 15
    chroot_mount
    chroot "${bootstrap_dir}" grub-install ${drive}
    chroot "${bootstrap_dir}" /bin/sh -c "GRUB_DISABLE_OS_PROBER=true update-grub"
    # set root password
    if [ ! "${root_password}" ]
    then
        if ! which strings >/dev/null 2>&1
        then
            printf "strings is missing\n" >&2
            exit 1
        fi
        root_password="$(head -n 1000 /dev/urandom | strings | \
            grep -o '[[:alnum:]]' | head -n 30 | tr -d '\n')"
        printf "Generated root password (without quotes):'${root_password}'\n"
    fi
    chroot "${bootstrap_dir}" /bin/sh -c "echo \"root:${root_password}\" | \
        chpasswd"
    # /etc/securetty must not be world writeable.
    chmod 644 "${bootstrap_dir}"/etc/securetty
    chroot_umount
    trap - 0 1 2 3 15
fi

if [ "${rm_bootstrap_dir}" ]
then
    if [ "${verbose}" -o "${debug}" ]
    then
        echo "removing bootstrap dir..."
    fi
    rm -r -f "${bootstrap_dir}"
    if [ "${verbose}" -o "${debug}" ]
    then
        echo "removing bootstrap dir finished"
    fi
fi
