#!/bin/sh

# Set color commands used with echo
# Refer to man console_codes for more info
NORMAL="\\033[0;39m"         # grey
SUCCESS="\\033[1;32m"        # green
WARNING="\\033[1;33m"        # yellow
FAILURE="\\033[1;31m"        # red
INFO="\\033[1;36m"           # light cyan

# Prints msg to TTY and kmsg, stripping color codes for kmsg
# This echos twice - once for tty0 and once on kmsg for all others
# $1 - Message string to print
# Explicitly send boot messages to tty0, /dev/console is ttyS0
echo_tty_kmsg() {
    echo -e "$1" > /dev/tty0
    echo -e "$1" | sed 's/\x1b\[[0-9;]*m//g' > /dev/kmsg
}

# This is the end point for fatal errors, repeats the fatal message every
# 30 seconds forever
# $1 - message to be printed out to user on failure
shell_trap() {
    local msg="$1"
    while true; do
        echo_tty_kmsg "Unable to boot Clear Linux*."
        echo_tty_kmsg "[${FAILURE} FAIL ${NORMAL}] FATAL: $msg"
        sleep 30
    done
}

# return details of the first CPU only
get_cpuinfo() {
    cat /proc/cpuinfo | awk 'BEGIN { RS = "" ; } { printf ("%s\n", $0); exit(0); }'
}

have_cpu_feature() {
    local feature="$1"
    get_cpuinfo | egrep -q "^flags.*\<$feature\>"
}

# Checks results, use only with missing CPU features
# $1 - Return code from previously run check
# $2 - Message to print to user - specific to CPU feature missing
check_result() {
    local ret="$1"
    local msg="$2"
    [ "$ret" -ne 0 ] && { echo_tty_kmsg "[${FAILURE} FAIL ${NORMAL}] $msg"; shell_trap "Detected Missing Required CPU Feature: $msg"; }
    echo_tty_kmsg "[${SUCCESS}  OK  ${NORMAL}] $msg"
}

have_vmx() {
    local feature="vmx"
    local desc="Virtualisation support"
    local need="$desc ($feature)"
    have_cpu_feature "$feature"
    check_result "$?" "$need"
}

have_ssse3_cpu_feature () {
    local feature="ssse3"
    local desc="Supplemental Streaming SIMD Extensions 3"
    local need="$desc ($feature)"
    have_cpu_feature "$feature"
    check_result "$?" "$need"
}

have_pclmul_cpu_feature () {
    local feature="pclmulqdq"
    local desc="Carry-less Multiplication extensions"
    local need="$desc ($feature)"
    have_cpu_feature "$feature"
    check_result "$?" "$need"
}

have_sse41_cpu_feature () {
    local feature="sse4_1"
    local desc="Streaming SIMD Extensions v4.1"
    local need="$desc ($feature)"
    have_cpu_feature "$feature"
    check_result "$?" "$need"
}

have_sse42_cpu_feature () {
    local feature="sse4_2"
    local desc="Streaming SIMD Extensions v4.2"
    local need="$desc ($feature)"
    have_cpu_feature "$feature"
    check_result "$?" "$need"
}

have_64bit_cpu() {
    local feature="lm" # "Long mode"
    local desc="64-bit CPU"
    local need="$desc ($feature)"
    have_cpu_feature "$feature"
    check_result "$?" "$need"
}

# Mounts the rootfs on a loopback device
# $1 - path to the media device the rootfs is stored on
mount_root() {
    local installer=${1}
    mkdir /mnt/media
    mount --read-only $installer /mnt/media
    local rootfsloop=$(losetup -fP --show /mnt/media/images/rootfs.img)
    if [ -n "${rootfsloop}" ]; then
        mkdir /mnt/rootfs
        mount --read-only ${rootfsloop} /mnt/rootfs
    else
        echo_tty_kmsg "[${FAILURE} FAIL ${NORMAL}] Failed to initialize loopback device for rootfs.img."
    fi
}

# Finds the installer media and calls mount_root if successful
find_and_mount_installer() {
    local retries=0

    while [ $retries -le 5 ]; do
        local installer=$(blkid -L CLR_ISO)
        if [ -n "${installer}" ]; then
            echo_tty_kmsg "[${SUCCESS}  OK  ${NORMAL}] Found installer media, continuing boot..."
            mount_root ${installer}
            break
        else
            echo_tty_kmsg "Searching for installer media, retrying..."
            sleep 1
            (( retries++ ))
        fi
    done

    if [ $retries -ge 5 ]; then
        shell_trap "[${FAILURE} FAIL ${NORMAL}] Failed to find installer media, retries exhausted, failed to boot Clear Linux*."
    fi
}

overlay_and_switch() {
    mkdir /mnt/ramfs
    mount -t tmpfs -o size=512M none /mnt/ramfs
    mkdir -p /mnt/ramfs/w_root /mnt/ramfs/workdir /mnt/ramfs/rw_root
    mount -t overlay -o lowerdir=/mnt/rootfs,upperdir=/mnt/ramfs/w_root,workdir=/mnt/ramfs/workdir none /mnt/ramfs/rw_root

    # Switch root
    exec switch_root /mnt/ramfs/rw_root /sbin/init
}

main() {
    # Mount temp filesystem
    mount -t proc none /proc
    mount -t sysfs none /sys
    mount -t devtmpfs none /dev
    mount -t tmpfs none /run


    # Verify CPU features needed to run Clear exist
    echo_tty_kmsg "Checking if system is capable of running Clear Linux*..."
    have_64bit_cpu
    have_ssse3_cpu_feature
    have_sse41_cpu_feature
    have_sse42_cpu_feature
    have_pclmul_cpu_feature
    echo_tty_kmsg "[${SUCCESS}  OK  ${NORMAL}] All checks passed."

    # insmod required modules
    {{range .Modules}}
    insmod {{.}}
    {{end}}

    find_and_mount_installer
    overlay_and_switch
}

main
