#!/bin/sh -u

### BEGIN INIT INFO
# Provides:          kesl-supervisor
# Required-Start:    $local_fs
# Required-Stop:     $remote_fs
# Should-Start:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Description:       See kesl(5) man page
### END INIT INFO

export LC_ALL=C

readonly KESL_INCLUDE_SH_STANDALONE=true
if [ -z "${__KESL_INCLUSE_SH_INCLUDE_GUARD__:-}" ]; then
readonly __KESL_INCLUSE_SH_INCLUDE_GUARD__=1

if [ -z "${KESL_INCLUDE_SH_STANDALONE:-}" ]; then
    : "${KESL_INCLUDE_SH_PATH:?The 'KESL_INCLUDE_SH_PATH' variable must be set and not null}"
fi

__GetKeslIncludedSpecs__()
{
    local _module="${1%.inc}"
    : "${_module:?Module name must be specified}"

    shift

    eval "${1#@}=\${_module}"
    
    local _hash=$(printf '%s' "${_module}" | md5sum | { IFS=' ' read -r hashValue fileName; printf '%s' "${hashValue}"; })
    eval "${2#@}=__KESL_INCLUDE_SH_MODULE_${_hash}__"
}

StandaloneSh()
{
    : "${KESL_INCLUDE_SH_STANDALONE:?KESL_INCLUDE_SH_STANDALONE variable must be set and not null}"

    local incModuleName=''
    local incGuardVarName=''
    __GetKeslIncludedSpecs__ "${1}" @incModuleName @incGuardVarName

    eval "${incGuardVarName}=1"
}

IncludeSh()
{
    local incModuleName=''
    local incGuardVarName=''
    __GetKeslIncludedSpecs__ "${1}" @incModuleName @incGuardVarName

    if ! eval "test -z \"\${${incGuardVarName}:-}\""; then
        return
    fi

    if [ ! -z "${KESL_INCLUDE_SH_STANDALONE:-}" ]; then
        eval : "\${${incGuardVarName}:?Module ${incModuleName} source code must be subtituted and marked as standalone by the StandaloneSh() function.}"
        return
    fi

    : "${KESL_INCLUDE_SH_PATH:?KESL_INCLUDE_SH_PATH variable must be set and not null}"

    local path="${KESL_INCLUDE_SH_PATH%%:*}"
    local rest="${KESL_INCLUDE_SH_PATH#:*}"

    while :; do
        if [ "${path#/}" = "${path}" ]; then
            echo "ERROR: sh-include path must be an absolute path: '${path}'" 1>&2
            exit 1
        fi

        local moduleFilePath="${path}/${incModuleName}.inc"
        if [ -f "${moduleFilePath}" ]; then
            eval "${incGuardVarName}=1"
            . "${moduleFilePath}" || return $?
            break
        fi

        path="${rest%%:*}"
        rest="${rest#:*}"
        if [ "${path}" = "${rest}" ]; then
            echo "ERROR: module '${incModuleName}' is not found" 1>&2
            exit 1
        fi
    done
}

fi


StandaloneSh 'utils'
DieRc()
{
    local res=1
    if [ "$1" -eq "$1" ] 2>/dev/null; then
        res=$1
        shift
    fi

    printf "\n%s: ERROR: %s\n\n" "$(basename "$0")" "$*" >&2

    exit ${res}
}

DieFmt()
{
    local fmt="$1"
    shift

    printf "\n%s: ERROR: ${fmt}\n\n" "$(basename "$0")" "$@" >&2

    exit 1
}

Die()
{
    DieRc 1 "$@"
}

Echo()
{
    printf "%b\n" "$*"
}

EchoBold()
{
    printf '\033[1m'
    Echo "$@"
    printf '\033[0m'
}

PrintfBold()
{
    printf '\033[1m'
    printf "$@"
    printf '\033[0m'
}

Repeat()
{
    local n="$1"
    local ch="$2"
    printf "%${n}s\n" | tr " " "${ch}"
}

AssignAtVar()
{
    eval "${1#@}=\"\${2}\""
}

RemoveLargestPrefix()
{
    eval "AssignAtVar \"\${3}\" \"\${${1}##\${2}}\""
}

RemoveLargestSuffix()
{
    eval "AssignAtVar \"\${3}\" \"\${${1}%%\${2}}\""
}

PsCommand()
{
    COLUMNS=4096 ps "$@"
}

Log()
{
    Echo "$(date -u "+%Y.%m.%d %H:%M:%S.%3N") $*"
}

CreateSymlink()
{
    ln -sfT "$1" "$2" || Die "'ln' failed CreateSymlink '$1' '$2' (exit code=$?)"
}

CopySymlink()
{
    cp -TP "$1" "$2" || Die "'cp' failed CopySymlink '$1' '$2' (exit code=$?)"
}

MoveSymlink()
{
    mv -fT "$1" "$2" || Die "'mv' failed MoveSymlink '$1' '$2' (exit code=$?)"
}

RemoveSymlink()
{
    rm -f "$1"
}


readonly PRODUCT_NAME='kesl'
readonly LAUNCHER='/opt/kaspersky/kesl/libexec/launcher'
readonly LAUNCHER_LOG='/var/log/kaspersky/kesl/kesl_launcher.log'
readonly SUBSYS_LOCK_DIRECTORY='/var/lock/subsys/'
readonly SUBSYS_LOCK_FILE="${SUBSYS_LOCK_DIRECTORY}kesl-supervisor"
readonly SYSTEMD_SERVICE_FILENAME='kesl-supervisor.service'
readonly PRODUCT_RUNNING_STATUS='0'
readonly PRODUCT_STOPPED_STATUS='3'
readonly PRODUCT_STOPPED='0'
readonly PRODUCT_ALREADY_STOPPED='2'
readonly PRODUCT_STARTED='0'
readonly PRODUCT_ALREADY_STARTED='2'
readonly MSG_APP_IS_RUNNING="${PRODUCT_NAME} is running"
readonly MSG_APP_IS_STOPPED="${PRODUCT_NAME} is stopped"
readonly MSG_APP_STARTED="${PRODUCT_NAME} started"
readonly MSG_APP_ALREADY_STARTED="${PRODUCT_NAME} already started"
readonly MSG_APP_STOPPED="${PRODUCT_NAME} stopped"
readonly MSG_APP_ALREADY_STOPPED="${PRODUCT_NAME} already stopped"
readonly MSG_APP_STOP_ERROR="${PRODUCT_NAME} stop failed. See ${LAUNCHER_LOG}"
readonly MSG_APP_STATUS_ERROR="${PRODUCT_NAME} status failed. See ${LAUNCHER_LOG}"
readonly MSG_APP_START_ERROR="${PRODUCT_NAME} start failed. See ${LAUNCHER_LOG}"

IsSystemd()
{
    if [ ! -d '/etc/systemd/system' ]; then
        return 1
    fi

    PsCommand -p 1 -o comm= | grep -F 'systemd' >/dev/null 2>&1 || return $?
}

CreateSubsysLockFile()
{
    if [ -d "${SUBSYS_LOCK_DIRECTORY}" ]; then
        touch "${SUBSYS_LOCK_FILE}" 2>/dev/null
    fi
}

RemoveSubsysLockFile()
{
    if [ -d "${SUBSYS_LOCK_DIRECTORY}" ]; then
        rm -f "${SUBSYS_LOCK_FILE}" 2>/dev/null
    fi
}

status()
{
    local res=0
    "${LAUNCHER}" "--status" 1>/dev/null 2>&1
    res=$?
    if [ "${res}" -eq "${PRODUCT_RUNNING_STATUS}" ]; then
        Echo "${MSG_APP_IS_RUNNING}"
    elif [ "${res}" -eq "${PRODUCT_STOPPED_STATUS}" ]; then
        Echo "${MSG_APP_IS_STOPPED}"
    else
        Echo "${MSG_APP_STATUS_ERROR}"
    fi
    return ${res}
}

start()
{
    if [ ${PPID} -ne 1 ] && IsSystemd; then
        systemctl start "${SYSTEMD_SERVICE_FILENAME}"
        local out=''
        out="$(systemctl is-active "${SYSTEMD_SERVICE_FILENAME}")"
        if [ "${out}" = 'active' ]; then
            Echo "${MSG_APP_STARTED}"
            return 0
        else
            Echo "${MSG_APP_START_ERROR}"
            return 255
        fi
    else
        local res=0
        "${LAUNCHER}" 1>/dev/null 2>&1
        res=$?
        if [ "${res}" -eq "${PRODUCT_STARTED}" ]; then
            CreateSubsysLockFile
            Echo "${MSG_APP_STARTED}"
        elif [ "${res}" -eq "${PRODUCT_ALREADY_STARTED}" ]; then
            Echo "${MSG_APP_ALREADY_STARTED}"
        else
            Echo "${MSG_APP_START_ERROR}"
            return 255
        fi
        return 0
    fi
}

DoStop()
{
    local res=0
    "${LAUNCHER}" "--stop" 1>/dev/null 2>&1
    res=$?
    RemoveSubsysLockFile
    if [ "${res}" -eq "${PRODUCT_STOPPED}" ]; then
        Echo "${MSG_APP_STOPPED}"
    elif [ "${res}" -eq "${PRODUCT_ALREADY_STOPPED}" ]; then
        Echo "${MSG_APP_ALREADY_STOPPED}"
        return 0
    else
        Echo "${MSG_APP_STOP_ERROR}"
    fi
    return ${res}
}

stop()
{
    if [ ${PPID} -ne 1 ] && IsSystemd; then
        systemctl stop "${SYSTEMD_SERVICE_FILENAME}"
        local out=''
        out="$(systemctl is-active "${SYSTEMD_SERVICE_FILENAME}")"
        if [ "${out}" != 'active' ]; then
            Echo "${MSG_APP_STOPPED}"
        else
            Echo "${MSG_APP_STOP_ERROR}"
        fi
    else
        DoStop || return $?
    fi
}

restart()
{
    stop
    start
}

Main()
{
    case "${1:-}" in
        start|stop|status|restart)
            "${1}" || return $?
            ;;
        *)
            Echo "Usage: $(basename "$0") {start|stop|status|restart}" >&2
            return 1
            ;;
    esac
}

Main "$@"
