#!/bin/bash
# Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. 
# Author: chengjike 
# 
# ultrapath-nvme upLinux_plus script for linux
#

if [ $(echo "$0" | grep -c "/") -ne 0 ] && [ "$0" != "" ]; then
    cd "${0%/*}"
fi

readonly LOCK_FILE="/var/lock/upLinux.shell.lock"
readonly UP_LINUX_CONF="/etc/upLinux.conf"
readonly OPER_TYPE=1396789576

BASIC_LIB_DIR="/UltraPath_NVMe/install/linuxTools/globalLib"
BASIC_LOG_DIR="/opt/UltraPath_NVMe/log"
BASIC_LOG_FILE="${BASIC_LOG_DIR}/ultrapathTool.log"

CHECK_LIBFILE="${BASIC_LIB_DIR}/check_lib.sh"
if [ -f "${CHECK_LIBFILE}" ]; then
    . "${CHECK_LIBFILE}"
else
    echo -e "ERROR: not found the lib[${CHECK_LIBFILE}]."
    exit 1
fi

readonly HBA_PARAM_RANGE="dev_loss_tmo 1 600 5
fast_io_fail_tmo 0 599 4
recovery_tmo 0 600 5
scsi_timeout 1 600 30"

function abnormal_exit()
{
    exit 1
}

function useage()
{
    echo -e "Parameters:
    set dev_loss_tmo=<num>: Change the value of dev_loss_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme). The value of dev_loss_tmo must be greater than that of fast_io_fail_tmo.
    show dev_loss_tmo: Check the value of dev_loss_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme).
    set fast_io_fail_tmo=<num>: Change the value of fast_io_fail_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme). The value of fast_io_fail_tmo must be smaller than that of dev_loss_tmo.
    show fast_io_fail_tmo: Check the value of fast_io_fail_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme).
    set recovery_tmo=<num>: Change the value of recovery_tmo for the iSCSI session (the SCSI device on the iSCSI session is taken over by ultrapath-nvme).
    show recovery_tmo: Check the value of recovery_tmo for the iSCSI session (the SCSI device on the iSCSI session is taken over by ultrapath-nvme).
    set scsi_timeout=<num>: Change the value of timeout for the SCSI device that is taken over by ultrapath-nvme.
    show scsi_timeout: Check the value of timeout for the SCSI device that is taken over by ultrapath-nvme.
    config blacklist: Add vendors and models of the devices that ultrapath-nvme can take over to the blacklist in the DM-Multipath configuration file (/etc/multipath.conf). In this way, DM-Multipath does not take over the devices.
    unconfig blacklist: Clear configuration items configured by running the config blacklist command from the DM-Multipath configuration file (/etc/multipath.conf)."
}

function useage_show()
{
    echo -e "Parameters:
    show dev_loss_tmo: Check the value of dev_loss_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme).
    show fast_io_fail_tmo: Check the value of fast_io_fail_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme).
    show recovery_tmo: Check the value of recovery_tmo for the iSCSI session (the SCSI device on the iSCSI session is taken over by ultrapath-nvme).
    show scsi_timeout: Check the value of timeout for the SCSI device that is taken over by ultrapath-nvme."
}

function useage_set()
{
    echo -e "Parameters:
    set dev_loss_tmo=<num>: Change the value of dev_loss_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme). The value of dev_loss_tmo must be greater than that of fast_io_fail_tmo.
    set fast_io_fail_tmo=<num>: Change the value of fast_io_fail_tmo for the FC remote port (the SCSI device on the FC remote port is taken over by ultrapath-nvme). The value of fast_io_fail_tmo must be smaller than that of dev_loss_tmo.
    set recovery_tmo=<num>: Change the value of recovery_tmo for the iSCSI session (the SCSI device on the iSCSI session is taken over by ultrapath-nvme).
    set scsi_timeout=<num>: Change the value of timeout for the SCSI device that is taken over by ultrapath-nvme."
}

function useage_config()
{
    echo -e "Parameters:
    config blacklist: Add vendors and models of the devices that ultrapath-nvme can take over to the blacklist in the DM-Multipath configuration file (/etc/multipath.conf). In this way, DM-Multipath does not take over the devices."
}

function useage_unconfig()
{
    echo -e "Parameters:
    unconfig blacklist: Clear configuration items configured by running the config blacklist command from the DM-Multipath configuration file (/etc/multipath.conf)."
}

function useage_set_range()
{
    local attribute=${1}
    local value=${2}
    
    if [ $(echo "${HBA_PARAM_RANGE}" | grep -E -c "^${attribute}") -ne 1 ]; then
        useage_set
        return 1
    fi
    local min_val=$(echo "${HBA_PARAM_RANGE}" | grep -E "^${attribute}" | awk '{print $2}')
    local max_val=$(echo "${HBA_PARAM_RANGE}" | grep -E "^${attribute}" | awk '{print $3}')
    local default_val=$(echo "${HBA_PARAM_RANGE}" | grep -E "^${attribute}" | awk '{print $4}')
    
    echo -e "Usage:
    ${0} set ${attribute}=<num>
        --num is in the range ${min_val}-${max_val}, default is ${default_val}."
    return 0
}

function check_environment()
{
    check_only_run "${LOCK_FILE}"
    if [ $? -eq 1 ]; then
        basic_trace_msg "ERROR" "This shell is already running, exit." "verbose"
        abnormal_exit
    fi
}

function show_param_value()
{
    local file="$1"
    local param="$2"

    if [ ! -f "${file}" ]; then
        basic_trace_msg "ERROR" "input file[${file}] is invalid."
        return 1
    fi
    
    local param_cnt=$(cat "${file}" | grep -c "^[[:blank:]]*${param}[[:blank:]]*=")
    if [ ${param_cnt} -ne 1 ]; then
        basic_trace_msg "WARN" "get param[${param}] cnt is not 1 in file[${file}]."
        return 1
    fi
    
    local value=$(cat "${file}" | grep "^[[:blank:]]*${param}[[:blank:]]*=" | awk -F "=" '{print $2}')
    echo "${value}"
    return 0
}

function set_param_value()
{
    local file="$1"
    local param="$2"
    local value="$3"

    if [ ! -f "${file}" ]; then
        basic_trace_msg "ERROR" "input file[${file}] is invalid."
        return 1
    fi
    
    local param_cnt=$(cat "${file}" | grep -c "^[[:blank:]]*${param}[[:blank:]]*=")
    if [ ${param_cnt} -gt 0 ]; then
        sed -i -e "/^[[:blank:]]*${param}[[:blank:]]*=/d" "${file}"
    fi

    value=$(echo ${value} | sed 's/^0*//')
    if [ -z "${value}" ]; then
        value="0"
    fi
    echo "${param}=${value}" >> "${file}"
    return $?
}

function handle_show()
{
    local ret=1
    local value=""
    local param_cnt=$#
    if [ ${param_cnt} -ne 2 ]; then
        basic_trace_msg "WARN" "The parameter is invalid." "verbose"
        useage_show
        abnormal_exit
    fi
    
    local attribute="${2}"
    case "${attribute}" in
        "dev_loss_tmo")
            value=$(show_param_value "${UP_LINUX_CONF}" "dev_loss_tmo")
            ret=$?
            ;;
        "fast_io_fail_tmo")
            value=$(show_param_value "${UP_LINUX_CONF}" "fast_io_fail_tmo")
            ret=$?
            ;;
        "recovery_tmo")
            value=$(show_param_value "${UP_LINUX_CONF}" "recovery_tmo")
            ret=$?
            ;;
        "scsi_timeout")
            value=$(show_param_value "${UP_LINUX_CONF}" "scsi_timeout")
            ret=$?
            ;;
        *)
            basic_trace_msg "WARN" "The parameter is invalid." "verbose"
            useage_show
            abnormal_exit
            ;;
    esac
    
    if [ ${ret} -ne 0 ]; then
        basic_trace_msg "WARN" "The value of the ${attribute} configuration item fails to be obtained." "verbose"
        abnormal_exit
    fi
    basic_trace_msg "INFO" "get ultrapath-nvme ${attribute} config value is ${value}."
    echo -e "${attribute}: ${value}"
}

function check_hba_attr_value()
{
    local attribute=${1}
    local value=${2}
    local dev_loss_tmo_value=0
    local fast_io_fail_tmo_value=0  
    
    if [ $(echo "${HBA_PARAM_RANGE}" | grep -E -c "^${attribute}") -ne 1 ]; then
        basic_trace_msg "WARN" "check ${attribute} paramter value[${value}] fail."
        return 1
    fi
    local min_val=$(echo "${HBA_PARAM_RANGE}" | grep -E "^${attribute}" | awk '{print $2}')
    local max_val=$(echo "${HBA_PARAM_RANGE}" | grep -E "^${attribute}" | awk '{print $3}')
    
    if [ $(echo "${value}" | grep -E -c "^[0-9]+$") -ne 1 ]; then
        basic_trace_msg "WARN" "check ${attribute} paramter value[${value}] fail."
        return 1
    fi
    
    if [ ${min_val} -gt ${value} ] || [ ${value} -gt ${max_val} ]; then
        basic_trace_msg "WARN" "check ${attribute} paramter value[${value}] fail."
        return 1
    fi
    
    if [ $(echo "${attribute}" | grep -c "dev_loss_tmo") -ne 0 ]; then
        fast_io_fail_tmo_value=$(show_param_value "${UP_LINUX_CONF}" "fast_io_fail_tmo")
        if [ ${value} -le ${fast_io_fail_tmo_value} ]; then
            basic_trace_msg "WARN" "The value of dev_loss_tmo must be greater than the value of fast_io_fail_tmo. The current value of fast_io_fail_tmo is ${fast_io_fail_tmo_value}." "verbose"
            return 1
        fi
    fi

    if [ $(echo "${attribute}" | grep -c "fast_io_fail_tmo") -ne 0 ]; then
        dev_loss_tmo_value=$(show_param_value "${UP_LINUX_CONF}" "dev_loss_tmo")
        if [ ${dev_loss_tmo_value} -le ${value} ]; then
            basic_trace_msg "WARN" "The value of dev_loss_tmo must be greater than the value of fast_io_fail_tmo. The current value of dev_loss_tmo is ${dev_loss_tmo_value}." "verbose"
            return 1
        fi
    fi
    return 0
}

function set_hba_attribute()
{
    local attribute=${1}
    local value=${2}
    
    check_hba_attr_value "${attribute}" ${value}
    if [ $? -ne 0 ]; then
        basic_trace_msg "WARN" "The parameter is invalid." "verbose"
        useage_set_range "${attribute}" ${value}
        return 1
    fi
    
    set_param_value "${UP_LINUX_CONF}" "${attribute}" "${value}"
    if [ $? -ne 0 ]; then
        basic_trace_msg "WARN" "The value of the ${attribute} configuration item fails to be set." "verbose"
        basic_trace_operate "FAIL" "${OPER_TYPE}" "$0 set ${attribute}" "execute $0 set ${attribute} to ${value} fail" "$0${attribute}Ϊ${value}ʧ"
        return 1
    fi
    
    basic_trace_msg "INFO" "the value of the ${attribute} configuration item is set successfully."
    basic_trace_operate "SUCCESS" "${OPER_TYPE}" "$0 set ${attribute}" "execute $0 set ${attribute} to ${value} success" "$0${attribute}Ϊ${value}ɹ"
    
    systemctl restart upudev.service > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        basic_trace_msg "ERROR" "The value of ${attribute} is successfully set but the setting does not take effect. The setting will take effect after the host is restarted." "verbose"
        return 1
    fi
    basic_trace_msg "INFO" "The value of ${attribute} is successfully set and the setting has taken effect." "verbose"
    return 0
}

function handle_set()
{
    local ret=1
    local param_cnt=$#
    if [ ${param_cnt} -ne 2 ]; then
        basic_trace_msg "WARN" "The parameter is invalid." "verbose"
        useage_set
        abnormal_exit
    fi
    
    local attribute=$(echo ${2} |awk -F = '{print $1}')
    local value=$(echo ${2} |awk -F = '{print $2}')
    case "${attribute}" in
        "dev_loss_tmo")
            set_hba_attribute "dev_loss_tmo" "${value}"
            ret=$?
            ;;
        "fast_io_fail_tmo")
            set_hba_attribute "fast_io_fail_tmo" "${value}"
            ret=$?
            ;;
        "recovery_tmo")
            set_hba_attribute "recovery_tmo" "${value}"
            ret=$?
            ;;
        "scsi_timeout")
            set_hba_attribute "scsi_timeout" "${value}"
            ret=$?
            ;;
        *)
            basic_trace_msg "WARN" "The parameter is invalid." "verbose"
            useage_set
            abnormal_exit
            ;;
    esac
    
    return ${ret}
}

function handle_config()
{
    local ret=1
    local value=""
    local param_cnt=$#
    if [ ${param_cnt} -ne 2 ]; then
        basic_trace_msg "WARN" "The parameter is invalid." "verbose"
        useage_config
        abnormal_exit
    fi
    
    local paramter="${2}"
    case "${paramter}" in
        "blacklist")
            bash /UltraPath_NVMe/install/linuxTools/toolLib/shielddevice.sh > /dev/null 2>&1
            ret=$?
            ;;
        *)
            basic_trace_msg "WARN" "The parameter is invalid." "verbose"
            useage_config
            abnormal_exit
            ;;
    esac
    
    if [ ${ret} -ne 0 ]; then
        basic_trace_msg "WARN" "Config ${paramter} fail." "verbose"
        basic_trace_operate "FAIL" "${OPER_TYPE}" "$0 config ${paramter}" "$0 config ${paramter} success" "$0${paramter}ʧ"
        abnormal_exit
    fi
    basic_trace_msg "INFO" "Config ${paramter} success." "verbose"
    basic_trace_operate "SUCCESS" "${OPER_TYPE}" "$0 config ${paramter}" "$0 config ${paramter} success" "$0${paramter}ɹ"
}

function handle_unconfig()
{
    local ret=1
    local value=""
    local param_cnt=$#
    if [ ${param_cnt} -ne 2 ]; then
        basic_trace_msg "WARN" "The parameter is invalid." "verbose"
        useage_unconfig
        abnormal_exit
    fi
    
    local paramter="${2}"
    case "${paramter}" in
        "blacklist")
            bash /UltraPath_NVMe/install/linuxTools/toolLib/shielddevice.sh "clear" > /dev/null 2>&1
            ret=$?
            ;;
        *)
            basic_trace_msg "WARN" "The parameter is invalid." "verbose"
            useage_unconfig
            abnormal_exit
            ;;
    esac
    
    if [ ${ret} -ne 0 ]; then
        basic_trace_msg "WARN" "Unconfig ${paramter} fail." "verbose"
        basic_trace_operate "FAIL" "${OPER_TYPE}" "$0 unconfig ${paramter}" "$0 unconfig ${paramter} success" "$0${paramter}ʧ"
        abnormal_exit
    fi
    basic_trace_msg "INFO" "Unconfig ${paramter} success." "verbose"
    basic_trace_operate "SUCCESS" "${OPER_TYPE}" "$0 unconfig ${paramter}" "$0 unconfig ${paramter} success" "$0${paramter}óɹ"
}

function handle_updateImage()
{
    local bash_script="/UltraPath_NVMe/install/linuxTools/toolLib/updateimage.sh"
    local methord=""
    if [ ! -f "${bash_script}" ]; then
        basic_trace_msg "ERROR" "the [${bash_script}] is not exist."
        basic_trace_operate "FAIL" "${OPER_TYPE}" "$0 updateImage" "$0 updateImage success" "$0ϵͳʧ"
        abnormal_exit
    fi

    methord=$(cat "/etc/UltraPath.packages.info" | grep "t140s_solutionType" | awk -F "=" '{print $2}')
    if [ -z "${methord}" ] || [ "${methord}" != "mkinitrd" ]; then
        basic_trace_msg "ERROR" "updateImage command is not support current installed methord[${methord}]."
        basic_trace_operate "FAIL" "${OPER_TYPE}" "$0 updateImage" "$0 updateImage success" "$0ϵͳʧ"
        abnormal_exit
    fi

    basic_choose_yes_no "You will update the system mirrors. Do you want to continue?"
    if [ $? -ne 0 ]
    then
        return 0
    fi

    bash "${bash_script}"
    if [ $? -ne 0 ]; then
        basic_trace_msg "ERROR" "The system image fails to be updated." "verbose"
        basic_trace_operate "FAIL" "${OPER_TYPE}" "$0 updateImage" "$0 updateImage success" "$0ϵͳʧ"
        abnormal_exit
    fi
    basic_trace_msg "INFO" "The system image is updated successfully.." "verbose"
    basic_trace_operate "SUCCESS" "${OPER_TYPE}" "$0 updateImage" "$0 updateImage success" "$0ϵͳɹ"
}

function handle_uplinux()
{
    local param_cnt=$#
    if [ ${param_cnt} -lt 1 ]; then
        basic_trace_msg "WARN" "The parameter is invalid." "verbose"
        useage
        abnormal_exit
    fi
    
    local action="${1}"
    case "${action}" in
        show)
            handle_show $@
            ;;
        set)
            handle_set $@
            ;;
        config)
            handle_config $@
            ;;
        unconfig)
            handle_unconfig $@
            ;;
        *)
            basic_trace_msg "WARN" "The parameter is invalid." "verbose"
            useage
            abnormal_exit
            ;;
    esac
}

# main start
if [ $(id -u) -ne 0 ]; then
    echo -e "\033[31m[ERROR]\033[0m must login as root."
    exit 1
fi

basic_create_log_file
check_environment
handle_uplinux $@
