#!/bin/bash
ASCEND_SECLOG="/var/log/ascend_seclog"
logFile="${ASCEND_SECLOG}/ascend_install.log"
installInfo="/etc/ascend_install.info"
sourcedir="$PWD"/firmware
SHELL_DIR=$(cd "$(dirname "$0")" || exit; pwd)
COMMON_SHELL="$SHELL_DIR/common.sh"
# load common.sh, get install.info
board_id=""

OPERATION_LOGDIR="${ASCEND_SECLOG}"
OPERATION_LOGPATH="${OPERATION_LOGDIR}/operation.log"
LOG_OPERATION_INSTALL="Install"
LOG_OPERATION_UPGRADE="Upgrade"
LOG_OPERATION_UNINSTALL="Uninstall"
LOG_LEVEL_SUGGESTION="SUGGESTION"
LOG_LEVEL_MINOR="MINOR"
LOG_LEVEL_MAJOR="MAJOR"
LOG_LEVEL_UNKNOWN="UNKNOWN"
LOG_RESULT_SUCCESS="success"
LOG_RESULT_FAILED="failed"

# 创建列表
_make_list() {
    local _outvar="$1"
    eval "${_outvar}=\"\""
}

# 列表添加元素
_append_list() {
    local _outvar="$1"
    local _item="$2"

    local _value
    eval "_value=\"\${${_outvar}}\""

    if [ "${_value}" = "" ]; then
        _value="${_item}"
    else
        _value="${_value} ${_item}"
    fi

    eval "${_outvar}=\"${_value}\""
}

# 获取需求包列表。
_get_required_packages() {
    local _outvar="$1"
    local _version_info_path="$2"
    local _packages

    if [ ! -f "${_version_info_path}" ]; then
        eval "${_outvar}=\"\""
        return 1
    fi

    _packages=$(awk '
        function join(items, len, sep,  result, i) {
            if (len >= 1) {
                result = items[1]
                for (i = 2; i <= len; i++) {
                    result = sprintf("%s%s%s", result, sep, items[i])
                }
                return result
            }
            return ""
        }

        BEGIN {
            len_packages = 0
        }
        /^required_package_.+_version=/ {
            split($0, line_tokens, "=")
            len_require_tokens = split(line_tokens[1], require_tokens, "_")
            len_package_names = 0
            for (i = 3; i < len_require_tokens; i++) {
                len_package_names++
                package_names[len_package_names] = require_tokens[i]
            }
            package_name = join(package_names, len_package_names, "_")

            len_packages += 1
            packages[len_packages] = package_name
        }
        END {
            if (len_packages >= 1) {
                printf("%s", packages[1])
                for (i = 2; i <= len_packages; i++) {
                    printf(" %s", packages[i])
                }
            }
        }
    ' "${_version_info_path}")
    eval "${_outvar}=\"${_packages}\""
}

# 获取需求包信息。
_get_required_package_info() {
    local _outvar="$1"
    local _version_info_path="$2"
    local _pkg_name="$3"
    local _required_pkg_name
    local _required_value

    if [ ! -f "${_version_info_path}" ]; then
        eval "${_outvar}=\"\""
        return 1
    fi

    _required_pkg_name="required_package_${_pkg_name}_version"
    _required_value="$(grep "^${_required_pkg_name}=" "${_version_info_path}" | cut -d= -f2-)"
    # _required_value取得的值带有双引号，eval时不可以在外侧再添加双引号

    eval "${_outvar}=${_required_value}"
}

# 检查版本与需求版本兼容性。
_check_version_required() {
    local version="$1"
    local require="$2"
    local script_dir="$3"
    local result

    result=$(awk -f "${script_dir}/check_version_required.awk" -v version="${version}" -v all_required="${require}")
    if [ "${result}" = "T" ]; then
        return 0
    fi

    return 1
}

# 获取包版本。
get_package_version() {
    local _outvar="$1"
    local _version_info_path="$2"
    local _result

    if [ ! -f "${_version_info_path}" ]; then
        eval "${_outvar}=\"\""
        return 1
    fi

    _result="$(grep "^Version=" "${_version_info_path}" | cut -d= -f2-)"
    eval "${_outvar}=\"${_result}\""
}

# 检查包版本兼容性。
_check_package_version_compatiable() {
    local version_info_path="$1"
    local pkg_version_info_path="$2"
    local package="$3"
    local script_dir="$4"

    local pkg_version
    local required

    # get pkg_version
    get_package_version "pkg_version" "${pkg_version_info_path}"
    # get required
    _get_required_package_info "required" "${version_info_path}" "${package}"
    # check pkg_version and required
    _check_version_required "${pkg_version}" "${required}" "${script_dir}"
    if [ $? -eq 0 ]; then
        comm_log "INFO" "${package} is installed, current version: ${pkg_version}, version check successfully."
        return 0
    fi

    comm_log "ERROR" "${package} is installed, current version: ${pkg_version}, required version is ${required}, version check failed."
    return 1
}


# 检查版本兼容性。
_check_version_compatiable() {
    local version_info_path="$1"
    local install_path="$2"
    local script_dir="$3"

    local check_result=0
    local failed_list
    local required_packages
    local package
    local self_version
    local pkg_version_info_path
    local pkg_installed
    local driver_install_path

    _get_required_packages "required_packages" "${version_info_path}"
    get_package_version "self_version" "${version_info_path}"

    _make_list "failed_list"

    for package in ${required_packages}; do
        if [ "${package}" = "driver" ]; then
            get_driver_install_path "driver_install_path" "${install_path}"
            if [ "${driver_install_path}" != "" ]; then
                pkg_installed="true"
            else
                pkg_installed="false"
            fi
            pkg_version_info_path="${driver_install_path}/${package}/version.info"
        else
            does_pkg_installed "${install_path}" "${package}" "pkg_installed"
            pkg_version_info_path="${install_path}/${package}/version.info"
        fi
        if [ "${pkg_installed}" = "true" ] && [ -f "${pkg_version_info_path}" ]; then
            _check_package_version_compatiable "${version_info_path}" "${pkg_version_info_path}" "${package}" "${script_dir}"
            if [ $? -ne 0 ]; then
                check_result=1
                _append_list "failed_list" "${package}"
            fi
        else
            comm_log "INFO" "${package} is not installed, does not need to check."
        fi
    done

    if [ ${check_result} -ne 0 ]; then
        comm_log "ERROR" "version check failed, please uninstall incompatible packages or install compatible packages. [$(echo ${failed_list} | sed 's/ /, /g')]"
    fi

    return ${check_result}
}

_package_to_log_pkg_name() {
    local _outvar="$1"
    local _pkg_name="$2"

    local _result

    _result="$(awk -v pkg_name="${_pkg_name}" '
        BEGIN {print toupper(substr(pkg_name, 1, 1)) substr(pkg_name, 2)}
    ')"

    eval "${_outvar}=\"${_result}\""
}

preinstall_process() {
    local install_path=""
    local docker_root=""
    local script_dir=""
    local package=""
    local logfile=""
    local real_install_path
    local version_info_path
    local ret

    # 参数列表末尾添加--参数
    eval set -- "$@ --"

    while true
    do
        case "$1" in
        --install-path=*)
            install_path="$(echo "$1" | cut -d"=" -f2-)"
            shift
            ;;
        --docker-root=*)
            docker_root="$(echo "$1" | cut -d"=" -f2-)"
            shift
            ;;
        --script-dir=*)
            script_dir="$(echo "$1" | cut -d"=" -f2-)"
            shift
            ;;
        --package=*)
            package="$(echo "$1" | cut -d"=" -f2-)"
            shift
            ;;
        --logfile=*)
            logfile="$(echo "$1" | cut -d"=" -f2-)"
            shift
            ;;
        --logstyle=*)
            LOG_STYLE="$(echo "$1" | cut -d"=" -f2-)"
            shift
            ;;
        *)
            break
            ;;
        esac
    done

    if [ "${install_path}" = "" ]; then
        echo "error: install_path is needed!"
        return 1
    fi
    if [ "${script_dir}" = "" ]; then
        echo "error: script_dir is needed!"
        return 1
    fi

    if [ "${package}" = "" ]; then
        echo "error: package is needed!"
        return 1
    fi
    if [ "${logfile}" = "" ]; then
        echo "error: logfile is needed!"
        return 1
    fi

    LOG_FILE="${logfile}"
    _package_to_log_pkg_name "LOG_PKG_NAME" "${package}"

    if [ "${docker_root}" = "" ]; then
        real_install_path="${install_path}"
    else
        real_install_path="${docker_root}/${install_path}"
    fi

    version_info_path="$(pwd)/version.info"

    _check_version_compatiable "${version_info_path}" "${real_install_path}" "${script_dir}"
    ret=$?
    if [ $ret -ne 0 ]; then
        return 1
    fi

    return 0
}

preinstall_check() {
    preinstall_process "$@"
}

changeLogMode() {
    if [ ! -f $logFile ]; then
        touch $logFile
    fi
    chmod 640 $logFile
}

log() {
    cur_date=`date +"%Y-%m-%d %T"`
    echo "[Firmware] [$cur_date] $1" >> $logFile
}
fwEcho() {
    cur_date=`date +"%Y-%m-%d %T"`
    echo "[Firmware] [$cur_date] $1"
}
fwColorEcho() {
    cur_date=`date +"%Y-%m-%d %T"`
    echo -e "[Firmware] [$cur_date] $1"
}

export feature_nvcnt_check=n
export reset_passwd=n
export feature_ver_compatible_check=y
export feature_running_on_device_check=n

export global_pci_num

errorUsage() {
    if [ $# -eq 1 ]; then
        fwEcho "[ERROR]ERR_NO:0x0004;ERR_DES: Unrecognized parameters: ${1}. Try './xxx.run --help' for more information."
        exitLog 1
    else
        fwEcho "[ERROR]ERR_NO:0x0004;ERR_DES: Unrecognized parameters. Try './xxx.run --help' for more information."
        exitLog 1
    fi
}

# LogFile polling and backup
rotateLog() {
    echo "${logFile} {
        su root root
        daily
        size=5M
        rotate 3
        missingok
        create 440 root root
    }" > /etc/logrotate.d/ascend-install
}

startLog() {
    cur_date=`date +"%Y-%m-%d %T"`
    fwEcho "[INFO]Start time: $cur_date"
    fwEcho "[INFO]Start time: $cur_date" >> $logFile
}

exitLog() {
    cur_date=`date +"%Y-%m-%d %T"`
    fwEcho "[INFO]End time: ${cur_date}"
    fwEcho "[INFO]End time: ${cur_date}" >> $logFile
    exit $1
}

# check if there are multiple run processes in execution
checkProcess(){
    name=`ps -ef | awk '$2=='$$'{print $10}'|rev|cut -d "/" -f1|rev`
    checkname=`echo "$name" | awk -F "-" '{print $1"-"$2}'`
    shellname=`echo $0 |rev |cut -d "/" -f1 |rev`
    process=`ps -ef | grep -v "grep" | grep -w "$shellname" |grep -w "${checkname}-.*.run"`
    pid=`echo "$process" | awk -F ' ' '{print $2}'`
    ret=`echo "$process" | awk -F ' ' '{print $3}' | grep -v "$pid" | wc -l`
    if [ $ret -gt 1 ]; then
        log "[ERROR]ERR_NO:0x0094;ERR_DES:There is already a process being executed,please do not execute multiple tasks at the same time"
        log "[INFO]$name;$shellname;$ret;$process"
        fwEcho "[ERROR]ERR_NO:0x0094;ERR_DES:There is already a process being executed,please do not execute multiple tasks at the same time"
        exitLog 1
    fi
}
# check the disk space of the installation directory before installation or upgrade，driver need 300M，firmware need 32M.
checkFreeSpace(){
    [ $uninstall = y ] && return 0
    # obtain occupy_space size defined in specific_func.inc
    freeSpace=`df -BM "$Install_Path_Param" |awk '/[0-9]%/{print $(NF-2)}'`
    log "[INFO]freeSpace:${freeSpace}"
    if [ $(echo $freeSpace | awk '{print int($1)}') -le $occupy_space ]; then
        log "[ERROR]free space only ${freeSpace}, cannot install firmware package (greater than ${occupy_space}M), please make sure enough space under the installation path"
        fwEcho "[ERROR]Free space only ${freeSpace}, cannot install firmware package (greater than ${occupy_space}M), please make sure enough space under the installation path"
        exitLog 1
    fi
}

# check if the user exists
checkUser(){
    ret=`cat /etc/passwd | cut -f1 -d':' | grep -w "$1" -c`
    if [ $ret -le 0 ]; then
        return 1
    else
        return 0
    fi
}

# check the association between users and user groups
checkGroup(){
    group_user_related=`groups "$2"|awk -F":" '{print $2}'|grep -w "$1"`
    if [ "${group_user_related}x" != "x" ];then
        return 0
    else
        return 1
    fi
}

# check if root permission
isRoot() {
    if [ $(id -u) -ne 0 ]; then
        fwEcho "[ERROR]ERR_NO:0x0093;ERR_DES:do not have root permission, install failed, please use root permission!"
        exitLog 1
    fi
}

# get the version number under the installation path (version2)
getVersionInstalled() {
    version2="none"
    if [ -f "$1"/version.info ]; then
        version2=`cat "$1"/version.info | awk -F '=' '$1=="Version" {print $2}'`
    fi
    echo $version2
}

# get the version number in the run package (version1)
getVersionInRunFile() {
    version1="none"
    if [ -f ./version.info ]; then
        version1=`cat version.info | awk -F '=' '$1=="Version" {print $2}'`
    fi
    echo $version1
}

updateVersionInfoVersion() {
        if [ -f "$1"/firmware/version.info ]; then
            rm -f "$1"/firmware/version.info
        fi
        if [ -d "$1"/firmware ]; then
            cp ./version.info "$1"/firmware
            chmod 440 "$1"/firmware/version.info
        fi
}

isValidPath() {
    if [ -f ${installInfo} ];then
        Driver_Install_Path_Param=$(getInstallParam "Driver_Install_Path_Param" "${installInfo}")
        Firmware_Install_Path_Param=$(getInstallParam "Firmware_Install_Path_Param" "${installInfo}")
        if [ ${uninstall} = n ]; then
            if [ -z "${Driver_Install_Path_Param}" ]; then
                fwEcho "[ERROR]ERR_NO:0x0080;ERR_DES:Driver package is not installed on this device,please install driver first!"
                log "[ERROR]ERR_NO:0x0080;ERR_DES:Driver package is not installed on this device,operation failed!"
                exitLog 1
            fi

            if [ ! -d "${Driver_Install_Path_Param}" ]; then
                fwEcho "[ERROR]ERR_NO:0x0080;ERR_DES:install path(${Driver_Install_Path_Param}) is wrong, install failed"
                log "[ERROR]ERR_NO:0x0080;ERR_DES:install path(${Driver_Install_Path_Param}) is wrong, install failed"
                exitLog 1
            fi

            # record original install path
            [ ! -z "${Firmware_Install_Path_Param}" ] && old_install_path="${Firmware_Install_Path_Param}"

            Install_Path_Param="${Driver_Install_Path_Param}"
        else
            old_install_path="${Firmware_Install_Path_Param}"
        fi
    else
        if [ ${uninstall} = y ]; then
            error "${LOG_OPERATION_UNINSTALL}" 1 "ERR_NO:0x0080;ERR_DES:Firmware package is not installed on this device, uninstall failed"
        fi
        fwEcho "[ERROR]ERR_NO:0x0080;ERR_DES:Driver package is not installed on this device, please install driver first!"
        log "[ERROR]ERR_NO:0x0080;ERR_DES:Driver package is not installed on this device, operation failed!"
        exitLog 1
    fi
}

install_info_key_array=("Driver_Install_Type" "UserName" "UserGroup" "Driver_Install_Path_Param" "Firmware_Install_Path_Param" "Firmware_Install_Type")
updateInstallParam() {
    local _key="$1"
    local _val="$2"
    local _file="$3"
    local _param

    if [ ! -f "${_file}" ]; then
        exit 1
    fi

    for key_param in "${install_info_key_array[@]}"; do
        if [ ${key_param} == ${_key} ]; then
            _param=`grep -r "${_key}=" "${_file}"`
            sed -i "/${_key}=/d" "${_file}"
            echo "${_key}=${_val}" >> "${_file}"
            break
        fi
    done
}

getInstallParam() {
    local _key="$1"
    local _file="$2"
    local _param

    if [ ! -f "${_file}" ];then
        exit 1
    fi

    for key_param in "${install_info_key_array[@]}"; do
        if [ ${key_param} == ${_key} ]; then
            _param=`grep -r "${_key}=" "${_file}" | cut -d"=" -f2-`
            break;
        fi
    done
    echo "${_param}"
}

updateInstallCfgFile() {
    if [ -z "${Firmware_Install_Type}" ]; then
        updateInstallParam "Firmware_Install_Type" "$installType" "$installInfo"
    else
        updateInstallParam "Firmware_Install_Type" "$installType" "$installInfo"
    fi

    if [ -z "${Firmware_Install_Path_Param}" ]; then
        updateInstallParam "Firmware_Install_Path_Param" "$Driver_Install_Path_Param" "$installInfo"
    else
        updateInstallParam "Firmware_Install_Path_Param" "${Driver_Install_Path_Param}" "$installInfo"
    fi

    return 0
}

logBaseVersion() {
    if [ -f ${installInfo} ];then
        Firmware_Install_Path_Param=$(getInstallParam "Firmware_Install_Path_Param" "${installInfo}")
        if [ ! -z "$Firmware_Install_Path_Param" ]; then
            installed_version=$(getVersionInstalled "$Firmware_Install_Path_Param"/firmware)
            if [ ! "${installed_version}"x = ""x ]; then
                fwEcho "[INFO]base version is ${installed_version}."
                log "[INFO]base version is ${installed_version}."
                return 0
            fi
        fi
    fi
    log "[INFO]base version was destroyed or not exist."
}

# determine whether the command returns a failure, and report an error if it fails.
# $1:Operation type, $2:ret code,   $3:(Optional)print messages
error() {
    local operation="$1"
    local retcode="$2"
    local msg="$3"
    if [ ${retcode} -ne 0 ]; then
        logOperation "${operation}" "${start_time}" "${runfilename}" "${LOG_RESULT_FAILED}" "${installType}" "${all_parma}"
    fi

    if [ $# -eq 3 ]; then
        if [ ${retcode} -ne 0 ]; then
            fwEcho "[ERROR]${msg}"
            log "[ERROR]${msg}"
            exitLog 1
        fi
    elif [ $# -eq 2 ]; then
        if [ ${retcode} -ne 0 ]; then
            exitLog 1
        fi
    fi
}

check_Device() {
    . "$sourcedir"/script/feature.conf
    version_control=`cat "$sourcedir"/script/feature.conf | grep FEATURE_FIRMWIRE_INTERCEPT`
    temp=${version_control#*=}
    if [ "$temp" = "y" ]; then
        return 1;
    else
        return 0;
    fi
}

get_board_feature() {
    local board_config

    . "$sourcedir"/script/feature.conf
    board_config=`cat "$sourcedir"/script/feature.conf | grep FEATURE_BOARDID`

    temp=${board_config#*=}
    board_id=(${temp//,/ })
}

installRun() {
    local run_install_type="$1"
    # Convert it to lowercase.
    run_install_type="${run_install_type,,}"
    # delete 'e' from install type.
    run_install_type="${run_install_type/e/}ed"

    INSTALL_ADDRESS="Driver_Install_Path_Param"
    INSTALL_ADDRESS_DRIVER="/driver/version.info"
    ATLAS_DRIVER_VERSION_NAME="Interversion"
    ASCENDHAL_VERSION="ascendhal_version"

    get_board_feature
    check_Device
    if [ $? -eq 1 ]; then
        if [ ! -f "/etc/ascend_install.info" ]; then
            fwColorEcho "[ERROR]firmware failed,Please make sure that the Run package is installed properly"
            exitLog 1
        fi

        while read line
        do
            temp=${line%%=*}
            if [ "$temp" = "$INSTALL_ADDRESS" ]; then
                    temp=${line#*=}
                    INSTALL_ADDRESS_DRIVER="$temp$INSTALL_ADDRESS_DRIVER"
                    while read driver_name
                    do
                        temp=${driver_name%%=*}
                        if [ "$temp" = "$ATLAS_DRIVER_VERSION_NAME" -o "$temp" = "$ASCENDHAL_VERSION" ]; then
                            rm -rf /etc/version.cfg
                            for board_info in ${board_id[@]};
                            do
                                echo  $board_info >> /etc/version.cfg
                                chmod 640 /etc/version.cfg
                            done
                        fi
                    done < $INSTALL_ADDRESS_DRIVER

            fi
        done < /etc/ascend_install.info


        if [ ! -f "/etc/version.cfg" ]; then
            if [ ! -d "/usr/local/" ]; then
                mkdir /usr/local --mode 755
            fi
            if [ ! -d "/usr/local/Ascend/" ]; then
                mkdir /usr/local/Ascend  --mode 755
            fi
            rm -rf /usr/local/Ascend/version.cfg

            for board_info in ${board_id[@]};
            do
                echo  $board_info >> /usr/local/Ascend/version.cfg
                chmod 640 /usr/local/Ascend/version.cfg
            done
        fi
    fi
    ./firmware/script/run_firmware_install.sh "$Install_Path_Param" $reset_passwd_flag "$installType"
    firmware_install_status=$?
    if [ ${firmware_install_status} -eq 0 ]; then
        updateVersionInfoVersion "$Install_Path_Param"
        if [ ${feature_running_on_device_check} = y ];then
            fwColorEcho "[INFO]\033[32mFirmware package ${run_install_type} successfully! \033[0m\033[31mReboot now to take effect.\033[0m"
        else
            fwColorEcho "firmware_preinst"
            fwColorEcho "[INFO]\033[32mFirmware package ${run_install_type} successfully! \033[0m\033[31mReboot now or after driver installation for the installation/upgrade to take effect.\033[0m"
        fi
    else
        fwColorEcho "[INFO]Failed to ${1,,} firmware package, please retry after uninstall and reboot!"
    fi
}

uninstallRun() {
    operation="${LOG_OPERATION_UNINSTALL}"
    Firmware_Install_Path_Param=$(getInstallParam "Firmware_Install_Path_Param" "${installInfo}")
    Firmware_Install_Type=$(getInstallParam "Firmware_Install_Type" "${installInfo}")

    # remove version.info
    if [ -f "$old_install_path"/firmware/version.info ];then
       rm -rf "$old_install_path"/firmware/version.info
       log "[INFO]rm -rf version.info success"
    fi
    uninstall_result=n
    if [ -f "$old_install_path"/firmware/script/run_firmware_uninstall.sh ]; then
        "$old_install_path"/firmware/script/run_firmware_uninstall.sh "$old_install_path"
        if [ $? -eq 0 ];then
            uninstall_result=y
        fi
    fi
    if [ $uninstall_result = n ]; then
        ./firmware/script/run_firmware_uninstall.sh "$old_install_path"
        if [ $? -eq 0 ]; then
            uninstall_result=y
        else
            log "[WARNING]uninstall firmware failed"
        fi
    fi

    if [ $uninstall = y ] && [ $uninstall_result = n ]; then
        fwEcho "[ERROR]ERR_NO:0x0090;ERR_DES:uninstall firmware failed;Detail message in ${ASCEND_SECLOG}/ascend_install.log"
        logOperation "${operation}" "${start_time}" "${runfilename}" "${LOG_RESULT_FAILED}" "${installType}" "${all_parma}"
        log "[ERROR]ERR_NO:0x0090;ERR_DES:uninstall firmware failed"
        exitLog 1
    fi

    if [ $uninstall_result = y ]; then
        log "[INFO]uninstall firmware success"
        if [ $uninstall = y ]; then
            if [ -d "${Firmware_Install_Path_Param}" ] && [ `ls "${Firmware_Install_Path_Param}" | wc -l` -eq 0 ];then
               rm -rf "${Firmware_Install_Path_Param}"
            fi
            sed -i '/Firmware_Install_Path_Param=/d' $installInfo
            sed -i '/Firmware_Install_Type=/d' $installInfo
            if [ ` grep -c -i "Install_Path_Param" $installInfo ` -eq 0 ]; then
                rm -f $installInfo
            fi
            fwColorEcho "[INFO]\033[32mFirmware package uninstalled successfully! Uninstallation takes effect immediately. \033[0m"
            logOperation "${operation}" "${start_time}" "${runfilename}" "${LOG_RESULT_SUCCESS}" "${installType}" "${all_parma}"
            exitLog 0
        fi
    fi
}


logOperation() {
    local operation="$1"
    local start_time="$2"
    local runfilename="$3"
    local result="$4"
    local install_type="$5"
    local cmdlist="$6"
    local level

    if [ "${operation}" = "${LOG_OPERATION_INSTALL}" ]; then
        level="${LOG_LEVEL_SUGGESTION}"
    elif [ "${operation}" = "${LOG_OPERATION_UPGRADE}" ]; then
        level="${LOG_LEVEL_MINOR}"
    elif [ "${operation}" = "${LOG_OPERATION_UNINSTALL}" ]; then
        level="${LOG_LEVEL_MAJOR}"
    else
        level="${LOG_LEVEL_UNKNOWN}"
    fi

    if [ ! -d "${OPERATION_LOGDIR}" ]; then
        mkdir -p ${OPERATION_LOGDIR}
        chmod 750 ${OPERATION_LOGDIR}
    fi

    if [ ! -f "${OPERATION_LOGPATH}" ]; then
        touch ${OPERATION_LOGPATH}
        chmod 640 ${OPERATION_LOGPATH}
    fi

    if [ $upgrade = y ] || [ $uninstall = y ]; then
        echo "${operation} ${level} root ${start_time} 127.0.0.1 ${runfilename} ${result}"\
            "cmdlist=${cmdlist}." >> ${OPERATION_LOGPATH}
    else
        echo "${operation} ${level} root ${start_time} 127.0.0.1 ${runfilename} ${result}"\
            "install_type=${install_type}; cmdlist=${cmdlist}." >> ${OPERATION_LOGPATH}
    fi
}

uniqueMode() {
    if [ ! -z "$installType" ]; then
        fwEcho "[ERROR]ERR_NO:0x0004;ERR_DES:only support one type : run/full/upgrade,operation failed!"
        log "[ERROR]ERR_NO:0x0004;ERR_DES:only support one type : run/full/upgrade,operation failed!"
        exitLog 1
    fi
}

unsupportParam() {
    # version/uninstall/check only support single use
    if [ $version = y ] || [ $uninstall = y ] || [ $check = y ]; then
        if [ $i -gt 1 ]; then
            log "[ERROR]ERR_NO:0x0004;ERR_DES:version/uninstall/check can't use with other parameters."
            fwEcho "[ERROR]ERR_NO:0x0004;ERR_DES:version/uninstall/check can't use with other parameters."
            exitLog 1
        fi
    fi
    if [ $quiet = y ] && [ $full_install = n ] && [ $run = n ] && [ $upgrade = n ]; then
        log "[ERROR]ERR_NO:0x0004;ERR_DES:quiet param need used with full/run/upgrade."
        fwEcho "[ERROR]ERR_NO:0x0004;ERR_DES:quiet param need used with full/run/upgrade."
        exitLog 1
    fi
    if [ $reset_passwd_flag = y ] && [ $full_install = n ] && [ $upgrade = n ]; then
        log "[ERROR]ERR_NO:0x0004;ERR_DES:reset param need used with full/upgrade."
        fwEcho "[ERROR]ERR_NO:0x0004;ERR_DES:reset param need used with full/upgrade."
        exitLog 1
    fi
    if [ $reset_passwd_flag = y ] && [ $reset_passwd = n ];then
        log "[ERROR]don't support reset passwd command"
        fwEcho "[ERROR]don't support reset passwd command"
        exitLog 1
    fi
}

# upgrade-tool exist check.
toolsExistCheck() {
    if [ ! -f "${Install_Path_Param}"/driver/tools/upgrade-tool ]; then
        log "[ERROR][upgrade-tool] doesn't exist."
        fwColorEcho "[ERROR]\033[31mFirmware upgrade tool doesn't exist.\033[0m"
        return 1
    fi

    return 0
}

# get top-up-devid for vm checking.
firmwareDeviceReady() {
    local i=0 ret=0 uped_num=0 tmp_uped_num=""
    local wait_mini_ready=$1
    global_top_up_chip=64

    export LD_LIBRARY_PATH=\
"${Install_Path_Param}"/driver/lib64:\
"${Install_Path_Param}"/driver/lib64/common:\
"${Install_Path_Param}"/driver/lib64/driver:\
${LD_LIBRARY_PATH}

    if [ ${feature_running_on_device_check} = y ];then
        return 0
    fi
    for i in `seq 1 ${wait_mini_ready}`
    do
        timeout 10s "${Install_Path_Param}"/driver/tools/upgrade-tool --device_index -1 --system_version \
                    > ascend_get_mini_devices.log 2>&1 && ret=$? || ret=$?
        # tmp_uped_num's value is like "0 1 2 4 7".
        tmp_uped_num=$(echo $(cat ascend_get_mini_devices.log | awk '{print $1}' | awk -F [:,] '{print $2}' | grep -v '^$'))
        uped_num=`echo ${tmp_uped_num} | awk '{print NF}'`
        log "[INFO]chips [${tmp_uped_num}] are up."

        if [ ${ret} -eq 0 ];then
            # to check whether there is a chip up at least.
            if [ ${uped_num} -ge 1 ];then
                global_top_up_chip=`echo ${tmp_uped_num} | awk 'NR==1{print $1}'`
                log "[INFO]the minimum devid is [${global_top_up_chip}]."
                rm -f ascend_get_mini_devices.log
                break
            fi
        fi

        # If the command times out, and --preserve-status is not set, then exit with
        # status 124.  Otherwise, exit with the status of COMMAND.
        if [ ${ret} -eq 124 ];then
            log "[WARNING] '${Install_Path_Param}/driver/tools/upgrade-tool --device_index -1 --system_version' command time(10 seconds) out"
        fi

        log "[INFO]wait for mini os, ${i}/${wait_mini_ready}"
        sleep 20
    done

    if [ ${global_top_up_chip} -eq 64 ]; then
        log "[ERROR]none of the chips are up."
        fwColorEcho "[ERROR]\033[31mNone of the chips are up.\033[0m"
        return 1
    fi

    return 0
}

vmCheck() {
    local ret=0

    toolsExistCheck && ret=$? || ret=$?
    if [ ${ret} -ne 0 ];then
        log "[ERROR]toolsExistCheck failed."
        return 1
    fi

    firmwareDeviceReady 8 && ret=$? || ret=$?
    if [ ${ret} -ne 0 ];then
        log "[ERROR]firmwareDeviceReady failed."
        return 1
    fi

    "${Install_Path_Param}"/driver/tools/upgrade-tool --device_index ${global_top_up_chip} --phymachflag >& /dev/null && ret=$? || ret=$?
    if [ ${ret} -eq 2 ]; then
        log "[ERROR]not a physical-machine, firmware upgrade does not support."
        fwColorEcho "[ERROR]\033[31mNot a physical-machine, firmware upgrade does not support.\033[0m"
        return 1
    fi

    log "[INFO]vmCheck success."
    return 0
}

if [ ! -d "${ASCEND_SECLOG}" ]; then
    mkdir -p ${ASCEND_SECLOG}
    chmod 750 ${ASCEND_SECLOG}
fi

runfilename="${1##*/}"
full_install=n
uninstall=n
upgrade=n
old_install_path=""
Install_Path_Param=""
operation="Install"
quiet=n
reset_passwd_flag=n
run=n
version=n
check=n
installType=""
firmware_install_status=0
occupy_space=32
# cut first two params from *.run
# $1: run package name，$2: run package path，$3: parameter list
#shift 2

if [ ! -d /usr/local/Ascend/driver ]; then
    echo "Please Setup Driver RPM First "
    exitLog 1
fi

if [ -d /usr/local/Ascend/firmware ] && [ `ls /usr/local/Ascend/firmware | wc -l` -ne 0 ]; then
    find /usr/local/Ascend/firmware -type f -exec chattr -i {} \;
fi

if [ -f /etc/uvp_version ];then
    if [ -d /usr/local/Ascend/firmware ]; then
        rm -rf /usr/local/Ascend/firmware
    fi
    mkdir -p -m 0755 /usr/local/Ascend/firmware
    mkdir -p -m 0755 /usr/local/Ascend/firmware/state_machine/
    exit 0
fi

start_time=$(date +"%Y-%m-%d %T")

startLog
fwEcho "[INFO]LogFile: ${ASCEND_SECLOG}/ascend_install.log"
fwEcho "[INFO]OperationLogFile: ${ASCEND_SECLOG}/operation.log"
changeLogMode
isRoot
checkProcess
logBaseVersion

i=0
while true
do
    case "$1" in
    --uninstall)
    i=$(( $i + 1 ))
    operation=${LOG_OPERATION_UNINSTALL}
    uninstall=y
    shift
    ;;
    --upgrade)
    i=$(( $i + 1 ))
    uniqueMode
    operation=${LOG_OPERATION_UPGRADE}
    upgrade=y
    shift
    ;;
    --full)
    i=$(( $i + 1 ))
    operation=${LOG_OPERATION_INSTALL}
    uniqueMode
    installType="full"
    full_install=y
    shift
    ;;
    --version)
    i=$(( $i + 1 ))
    version=y
    shift
    ;;
    --quiet)
    i=$(( $i + 1 ))
    quiet=y
    shift
    ;;
    --run)
    i=$(( $i + 1 ))
    uniqueMode
    installType="run"
    run=y
    shift
    ;;
    --reset)
    i=$(( $i + 1 ))
    reset_passwd_flag=y
    shift
    ;;
    --check)
    i=$(( $i + 1 ))
    check=y
    shift
    ;;
    -*)
    errorUsage $2
    ;;
    *)
    break
    ;;
    esac
done

operation=${LOG_OPERATION_INSTALL}
installType="full"
full_install=y

if [ $1 -eq 2 ]; then
    operation=${LOG_OPERATION_UPGRADE}
    full_install=n
    upgrade=y
else
    name=$(rpm -qa | grep "Ascend.*firmware" | sed 's/Ascend\(.*\)firmware.*/\1/')
    if [[ $name =~ ^[0-9]{3} ]]; then
        full_install=n
        upgrade=y
        operation=${LOG_OPERATION_UPGRADE}
    fi
fi


if [ $upgrade = y ] || [ $full_install = y ] || [ $run = y ]; then
    fwColorEcho  "[WARNING]\033[33mDo not power off or restart the system during the installation/upgrade\033[0m"
fi

unsupportParam

# --check
if [ "${check}" = "y" ] && [ "${feature_ver_compatible_check}" = "y" ]; then
    source ${SHELL_DIR}/common_func.inc
    source ${SHELL_DIR}/version_compatiable.inc

    if [ -f "${installInfo}" ]; then
        Firmware_Install_Path_Param=$(getInstallParam "Firmware_Install_Path_Param" "${installInfo}")
        if [ -z "${Firmware_Install_Path_Param}" ]; then
            Firmware_Install_Path_Param=$(getInstallParam "Driver_Install_Path_Param" "${installInfo}")
            [ -z "${Firmware_Install_Path_Param}" ] && Firmware_Install_Path_Param="/usr/local/Ascend"
        fi
    else
        Firmware_Install_Path_Param="/usr/local/Ascend"
    fi

    preinstall_check --install-path="${Firmware_Install_Path_Param}" --script-dir="${SHELL_DIR}" --package="firmware" --logfile="${logFile}" --logstyle="no-colon" || exitLog $?
    log "[INFO]preinstall_check success"
    fwColorEcho "[INFO]\033[32mFirmware package preinstall_check success.\033[0m"
    exitLog 0
elif [ "${check}" = "y" ] && [ "${feature_ver_compatible_check}" = "n" ]; then
    exitLog 0
fi

# --version
if [ $version = y ]; then
    fwEcho "[INFO]firmware version :"$(getVersionInRunFile)
    exitLog 0
fi

trap "logOperation \"${operation}\" \"${start_time}\" \"${runfilename}\" \"${LOG_RESULT_FAILED}\" \"${installType}\" \"${all_parma}\";exit 1" \
INT QUIT TERM HUP
if [ $upgrade = y ]; then
    if [ -f ${installInfo} ];then
        Firmware_Install_Type=$(getInstallParam "Firmware_Install_Type" "${installInfo}")
        if [ -z "$Firmware_Install_Type" ]; then
            installType="full"
        else
            installType="$Firmware_Install_Type"
        fi
    else
        installType="full"
    fi
fi

isValidPath
rotateLog
checkFreeSpace

if [ "${feature_ver_compatible_check}" = "y" ] && [ "${uninstall}" = "n" ]; then
    preinstall_check --install-path="${Install_Path_Param}" --script-dir="${SHELL_DIR}" --package="firmware" --logfile="${logFile}" --logstyle="no-colon" || exitLog $?
    log "[INFO]preinstall_check success"
fi

# 1.if current scene is virtual-machine, you will get a abnormal exit.
# 2.update new configuration to the ${installInfo}.
if [ "${uninstall}" == "n" ]; then
    vmCheck
    if [ $? -ne 0 ]; then
        logOperation "${operation}" "${start_time}" "${runfilename}" "${LOG_RESULT_FAILED}" "${installType}" "${all_parma}"
        log "[ERROR]vmCheck failed."
        exitLog 1
    fi
    updateInstallCfgFile
fi
