#!/bin/bash
#
# description: NorCal system init script

# This script is written as a bash script, calling /usr/bin/NorCalInit
# to do all of the real work, so that we can use the existing code to
# print 'OK'/'FAIL' at bootup time.

# The NorCal is started fairly early in the boot process, between the
# two stages of Eos initialization.

. /etc/rc.d/init.d/functions

REDUNDANCY_FILE="/var/run/redundancy-protocol"
INTERVAL=0.5
NOR_CAL_LOG=/var/log/NorCalInit
TTY_TXT=""

DEBUG_LOG=""
declare -A DEBUG_MAP
debug_timeout() {
    echo "======================================================================"
    echo "NorCal script was forced to exit"
    echo "Debug state variables:"
    for key in "${!DEBUG_MAP[@]}"
    do
        echo "${key}=${DEBUG_MAP[$key]}"
    done
    
    if [ "$DEBUG_LOG" != "" ]; then
        echo "Log:"
        echo -n "$DEBUG_LOG"
    fi
}

debug_timeout_wrapper() {
    debug_timeout >> $NOR_CAL_LOG

    # Make sure to exit the trap with a non-zero exit code
    exit 1
}

debug_log() {
    timestamp=$(date "+%F %T")
    DEBUG_LOG+="$timestamp: $1"$'\n'
}

tty_path() {
    # find a tty associated with fd 0, 1 or 2.
    for i in 0 1 2
    do
        if [ -t $i ]; then
            echo "/proc/self/fd/$i"
            break
        fi
    done
}

start() {
    # read from TTY associated with stdin/stdout/stderr
    # in default systemd we have this:
    #
    # lr-x------ 1 root root 64 Oct 15 14:12 0 -> /dev/null
    # l-wx------ 1 root root 64 Oct 15 14:12 1 -> pipe:[10872]
    # l-wx------ 1 root root 64 Oct 15 14:12 2 -> /dev/console
    #
    # Somehow setting StandardInput to tty messes up output on console,
    # so we just directly read from TTY.
    TTY="$(tty_path)"
    if [ "$TTY" != "" ]; then
        # Use bash's automatic fd allocation
        exec {TTY_FD}<$TTY
    fi

    # Open log file so that we can spy on it in debug mode
    touch $NOR_CAL_LOG
    exec {NOR_CAL_LOG_FD}<$NOR_CAL_LOG
    DEBUG_TOGGLE=0

    echo -n $"Starting NorCal initialization: "
    /usr/bin/NorCalInit </dev/null >>$NOR_CAL_LOG 2>&1 &
    PID=$!

    while [ 1 ]; do
        if [ "$TTY" != "" ]; then
            DEBUG_MAP["CURRENT_STATE"]="READ_TTY"
            read -s -r -d "" -N 1 -t $INTERVAL -u ${TTY_FD} CHAR || true
            if [ "$CHAR" = 'v' ]; then
                debug_log "Verbose Mode Triggered"
                DEBUG_TOGGLE=$((1-DEBUG_TOGGLE)) 
            else
                TTY_TXT+=$CHAR
            fi
        else
            sleep $INTERVAL
        fi
        # Check if TTY_TXT ends with the NorCalInit interupt sequence
        if [[ $TTY_TXT == *$'\x1B123' ]]; then
            # Later echo will add [failed]\n
            echo -n "User Interrupted, Initialization "
            echo "<ESC>123" >> $NOR_CAL_LOG
            kill -9 $PID >> $NOR_CAL_LOG 2>&1
            debug_log "NorCal escape sequence triggered"
            # fall through to wait for process to exit
        fi

        if [ $DEBUG_TOGGLE == 1 ]; then
            # Read from NorCal log file without blocking
            while [ 1 ]; do
                DEBUG_MAP["CURRENT_STATE"]="PRINT_VERBOSE_LOG"
                read -r -s -u ${NOR_CAL_LOG_FD} LINE; RETVAL=$?
                # ok? echo && continue
                [ $RETVAL -eq 0 ] && echo -E "$LINE" && continue
                break
            done
        fi
    
        DEBUG_MAP["CURRENT_STATE"]="ACQUIRE_PID_STATE"
        STATE="`ps -p $PID -o state=`"
        DEBUG_MAP["LAST_PID_STATE"]=$STATE
        if [ "$STATE" = "" ]; then
            # has exited
            DEBUG_MAP["CURRENT_STATE"]="EXIT"
            debug_log "Waiting on NorCalInit process to return exited"
            wait $PID >> $NOR_CAL_LOG 2>&1
            norCalRet=$?
            if [ $norCalRet -eq 0 ]; then
                if [ -f $REDUNDANCY_FILE ]; then
                    PROTOCOL="`cat $REDUNDANCY_FILE | grep ^REDUNDANCY_PROTOCOL | cut -d '=' -f 2`"
                    echo -n "Redundancy protocol is $PROTOCOL. "
                fi
                success
                echo
                exit 0
            else
                # If NorCalInit fails, the system is pretty much hosed
                failure
                # Sometimes box resets again post NorCalInit failure, resulting in contents
                # of /var/log/NorCalInit to be lost. We copy /var/log/NorCalInit to
                # /mnt/flash/debug in the systemd unit (see NorCal.service/OnFailure).
                echo
                echo $"   (errors in /var/log/NorCalInit and /mnt/flash/debug/NorCalInit; log in as 'root' to troubleshoot)"
                exit 1
            fi
        fi
    done
}

# When systemd times out a service it sends a SIGTERM to it. On a rare case like in
# BUG956611 we would like to have some debug information on what was happening in this script. 
trap debug_timeout_wrapper SIGTERM

# Once we figure out what it means to "stop" NorCal, add support to do
# that here.
case "$1" in
start)
    start
    ;;
stop)
    ;;
*)
    echo $"Usage: $0 {start}"
    exit 1
esac
