#!/bin/bash
#-----------------------------------------------------
# Filename: curl.sh
# Revision: 6.0.1
# DesignDate：2022/12/13
# Author: H3C/APP
# Description: update firmware based on redfish HDM2
#-----------------------------------------------------
# ChangeLog
# Version 6.0.1
# add update function
#-----------------------------------------------------

FILENAME="curl.sh"
IP=""
PORT=""
USER=""
PSWD=""
FWTYPE=""
FWNAME=""
REBOOT="Default"
PRESRV="Retain"
MEMBER="Primary"
BACKUP=false
TOKEN=""
SUBTYPE=""
ACTMODE=""
MEMLIST=""
TRYTIMES=5
GETTIMES=60
SLEEPTIME=30
DELAYTIME=1
CNCTTIME=30
MAXTIME=1800 #30mins
RBTTIME=300
SESSIONID=""
RET_SUCCESS=0
RET_FAILURE=1
RET_TIMEOUT=2
RET_SESSION_FAIL=3
RET_PROGRESS_TIMEOUT=4
STA_NULL=0
STA_UPGRADING=3
PWR_STA=0
PWR_OFF=0
PWR_ON=3
UPD_RESULT=0
UPD_FAILED=1
UPD_NOT_FAILED=0
OEM_NAME="Public"
CURL_CMD="curl"
CMD_FLAG=0
SECURE=0

# Usage
function Usage()
{
    echo -e "Usage:"
    echo -e "$1\t\tUpdate HDM or BIOS or CPLD and so on"
    echo -e "Option:"
    echo -e "\t <-I>: HDM IP"
    echo -e "\t <-O>: HDM PORT"
    echo -e "\t <-U>: HDM UserName"
    echo -e "\t <-P>: HDM UserPassword"
    echo -e "\t <-F>: firmware path/name"
    echo -e "\t <-R>: reboot(HDM default 0, BIOS default 1), 0: Auto, 1: Manual"
    echo -e "\t <-K>: keep configuration(default 0), HDM(0: Retain, 1: Restore factory); BIOS(0: Retain, 1: Restore, 2: ForceRestore)"
    echo -e "\t <-B>: backup(default 0), 0: false, 1: true"
    echo -e "\t <-M>: update primary or standby flash(default 0), 0: Primary, 1: Standby, 2: Both"
    echo -e "\t <-S>: choose transfer protocol type, 0: http, 1: https"
}

# IN arg
while getopts "I:O:U:P:F:R:K:B:C:M:S:h" arg
do
    case $arg in
        I)
            IP="$OPTARG"
            ;;
        O)
            PORT="$OPTARG"
            ;;
        U)
            USER="$OPTARG"
            ;;
        P)
            PSWD="$OPTARG"
            ;;
        F)
            FWNAME="rom.ima=@$OPTARG"
            ;;
        R)
            if [[ "0" = "$OPTARG" ]]; then
                REBOOT="Auto"
            elif [[ "1" = "$OPTARG" ]]; then
                REBOOT="Manual"
            else
                REBOOT="Default"
            fi
            ;;
        K)
            if [[ "0" = "$OPTARG" ]]; then
                PRESRV="Retain"
            elif [[ "1" = "$OPTARG" ]]; then
                PRESRV="Restore"
            elif [[ "2" = "$OPTARG" ]]; then
                PRESRV="ForceRestore"
            else
                PRESRV="Retain"
            fi
            ;;
        B)
            if [[ "0" = "$OPTARG" ]]; then
                BACKUP=false
            elif [[ "1" = "$OPTARG" ]]; then
                BACKUP=true
            else
                BACKUP=false
            fi
            ;;
        C)
            if [[ "1" = "$OPTARG" ]]; then
                CMD_FLAG=1
            else
                CMD_FLAG=0
            fi
            ;;
        M)
            if [[ "0" = "$OPTARG" ]]; then
                MEMBER="Primary"
            elif [[ "1" = "$OPTARG" ]]; then
                MEMBER="GoldenImage"
            elif [[ "2" = "$OPTARG" ]]; then
                MEMBER="Both"
            else
                MEMBER="Primary"
            fi
            ;;
        S)
            SECURE="$OPTARG"
            ;;
        h)
            Usage $FILENAME
            exit 0
            ;;
        ?)
            echo "Unknown argment"
            Usage $FILENAME
            exit 1
            ;;
    esac
done

# log path
IP_OLD=`echo $IP`
IP_New=`echo ${IP//:/-}`
mkdir -p ./log/$IP_New
log_path=./log/$IP_New

log_status=$log_path/status.txt
cookies=$log_path/cookies
rsp_inf=$log_path/resp.info
cc_xml=$log_path/bmc_cc.xml

# Check Input parameter
if [[ -z "$IP" ]]; then
    echo "No IP is given!!!" >> $log_status
    Usage $FILENAME
    exit ${RET_FAILURE}
fi
if [[ -z "${PORT}" ]]; then
    if [ $SECURE -eq 1 ]; then # https
        PORT="443"
    else # http
        PORT="80"
    fi
fi
if [[ "$FWNAME" == "rom.ima=@" ]] || [[ -z "$FWNAME" ]]; then
    echo "No firmware file is given!!!" >> $log_status
    Usage $FILENAME
    exit ${RET_FAILURE}
fi

# ********
# 功能：记录日志信息
# 参数1：日志信息
# 参数2：日志文件名
# ********
LOG()
{
    local message=$1
    local log_record=$2
    local time_stamp=`date +%F" "%T`
    echo "$time_stamp $message" >> $log_record
}

# ********
# 功能：选用合适的curl命令
# 参数：无
# 返回值：无
# ********
func_get_curl_cmd()
{
    curl --version >/dev/null 2>&1 #所有信息都不打印
    if [[ $? -ne 0 ]] || [[ ${CMD_FLAG} -eq 1 ]]; then
        CURL_CMD="./curl"
        chmod a+x $CURL_CMD
        $CURL_CMD --version 2>&1>/dev/null #仅错误信息打印到屏幕
    else
        CURL_CMD="curl"
    fi
}

# ********
# 功能：解析ipv6地址
# 参数：无
# *********
func_parse_ipv6()
{
    num=`echo $IP | awk -F ':' '{print NF}'`
    if [ $num -gt 2 ]; then # ipv6
        if [ $SECURE -eq 1 ]; then
            IP=`echo "-k --tlsv1 -g https://[${IP}]"`
        else
            IP=`echo "-g [${IP}]"`
        fi
    else # ipv4
        if [ $SECURE -eq 1 ]; then
            IP=`echo "-k --tlsv1 https://$IP"`
        fi
    fi
}

# ********
# 功能：解析接口返回的完成码并打印出来
# 参数：完成码
# *********
func_parse_cc_and_print()
{
    local code=$1
    if [[ $code =~ ^[0-9]+$ ]]; then #入参必须是整数
        $CURL_CMD -c $cookies -b $cookies -X GET $IP:$PORT/cc/bmc_cc.xml --connect-timeout $CNCTTIME -s > $cc_xml #下载bmc_cc.xml文件
        local bin=""
        while [ $code -gt 0 ] #十进制转二进制
        do
            rem=$((code & 1))
            bin="${rem}${bin}"
            code=$((code >> 1))
        done

        local len=${#bin}
        if [ $len -lt 32 ]; then #不足32位补足0
            local dif=$((32 - len))
            for ((i=0;i<$dif;i++))
            do
                bin=`echo "0${bin}"`
            done
        fi
        local mod_bin=`echo $bin | cut -b 2-8` #提取有效位
        local num_bin=`echo $bin | cut -b 24-32`
        local mod_id=`echo "$((2#$mod_bin))"` #二进制转十进制
        local cc_num=`echo "$((2#$num_bin))"`
        local cc_en=`cat $cc_xml | sed -n '/<module.*id="'${mod_id}'"/,/<\/module/p' | grep -A 2 '<cc define.*num="'${cc_num}'">' | grep "des_en"`
        local cc_tmp=`echo "${cc_en#*>}"`
        local cc_des=`echo "${cc_tmp%<*}"`
        if [ -n "${cc_des}" ]; then
            LOG "cc: ${cc_des}" $log_status
            echo "$IP_OLD: ${cc_des}"
        fi
    fi
}

# ********
# 功能：通过查询redfish版本接口来获取OEM信息
# 参数：无
# 返回值：0-查询成功；1-查询失败；2-查询超时
# ********
func_get_redfish_version()
{
    rd_inf=`$CURL_CMD -c $cookies -b $cookies -X GET $IP:$PORT/redfish --connect-timeout $CNCTTIME -s`
    rd_cc=`echo "$rd_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ -z "$rd_cc" ]]; then
        LOG "Get redfish version: timeout." $log_status
        LOG "$rd_inf" $rsp_inf
        return ${RET_TIMEOUT}
    elif [[ $rd_cc -eq 0 ]] && [[ `echo "$rd_inf" | grep "Oem"` ]]; then
        oem_nm=`echo "$rd_inf" | grep -A 1 "Oem" | sed -n 2p | awk -F '\"' '{print $2}'`
        if [[ -z "${oem_nm}" ]]; then
            OEM_NAME="Public"
        else
            OEM_NAME=`echo ${oem_nm}`
        fi
        LOG "OEM_NAME: ${OEM_NAME}" $log_status
        return ${RET_SUCCESS}
    else
        rd_desc=`echo "$rd_inf" | grep "Description" | sed -e 's/ //g' -e 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$rd_desc" $log_status
        LOG "$rd_inf" $rsp_inf
        func_parse_cc_and_print "${rd_cc}"
        return ${RET_FAILURE}
    fi
}

# ********
# 功能：创建会话
# 参数：无
# 返回值：0-创建会话成功；1-创建会话失败
# ********
func_establish_session()
{
    local try_time=1
    LOG "Establish session..." $log_status
    while(( $try_time <= $TRYTIMES ))
    do
        ses_inf=`$CURL_CMD -c $cookies -H 'Content-Type:application/json' -X POST -d '{"UserName":"'"$USER"'", "Password":"'"$PSWD"'"}' $IP:$PORT/redfish/v1/SessionService/Sessions --connect-timeout $CNCTTIME -s`
        ses_cc=`echo "$ses_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ -z "$ses_cc" ]]; then
            LOG "Create session: timeout." $log_status
            let try_time++
            sleep $SLEEPTIME
        elif [[ $ses_cc -eq 0 ]] && [[ `echo "$ses_inf" | grep "X-Auth-Token"` ]]; then
            TOKEN=`echo "$ses_inf" | grep "X-Auth-Token" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
            SESSIONID=`echo "$ses_inf" | grep "@odata.id" | sed -e 's/"//g' -e 's/,//g' | awk -F 'Sessions/' '{print $2}'`
            LOG "Establish session successful! token=$TOKEN, session_id=$SESSIONID." $log_status
            return ${RET_SUCCESS}
        else
            ses_desc=`echo "$ses_inf" | grep "Description" | sed -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
            LOG "$ses_desc" $log_status
            if [[ `echo $ses_desc | grep "Upgrade is in progress."` ]] || [[ `echo $ses_desc | grep "Invalid input parameters."` ]]; then
                echo "$IP_OLD: ${ses_desc}"
                return ${RET_FAILURE}
            fi
            let try_time++
            sleep $SLEEPTIME
        fi
    done
    LOG "$ses_inf" $rsp_inf
    return ${RET_FAILURE}
}

# *********
# 功能：删除指定会话
# 参数：无
# 返回值：0-删除会话成功；1-删除会话失败
# *********
func_delete_session()
{
    LOG "Delete session..." $log_status
    sess_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X DELETE $IP:$PORT/redfish/v1/SessionService/Sessions/$SESSIONID --connect-timeout $CNCTTIME -s`
    sess_cc=`echo "$sess_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $sess_cc -ne 0 ]]; then
        sess_desc=`echo "$sess_inf" | grep "Description" | sed -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        LOG "$sess_desc" $log_status
        LOG "$sess_inf" $rsp_inf
        return ${RET_FAILURE}
    elif [[ -z "$sess_cc" ]]; then
        LOG "Delete session: timeout." $log_status
        LOG "$sess_inf" $rsp_inf
        return ${RET_TIMEOUT}
    else
        LOG "Session deleted." $log_status
        return ${RET_SUCCESS}
    fi
}

# *********
# 功能：取消升级
# 参数：无
# 返回值：0-取消升级成功；1-取消升级失败
# *********
func_post_update_cancel()
{
    LOG "Ready to cancel update..." $log_status
    can_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Cancel --connect-timeout $CNCTTIME -s`
    can_cc=`echo "$can_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $can_cc -ne 0 ]]; then
        can_desc=`echo "$can_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$can_desc" $log_status
        LOG "$can_inf" $rsp_inf
        return ${RET_FAILURE}
    elif [[ -z "$can_cc" ]]; then
        LOG "Cancel: timeout." $log_status
        LOG "$can_inf" $rsp_inf
        return ${RET_TIMEOUT}
    else
        LOG "Update canceled." $log_status
        return ${RET_SUCCESS}
    fi
}

# *********
# 功能：升级回退
# 参数：无
# 返回值：0-升级回退成功；1-升级回退失败
# *********
func_post_update_rollback()
{
    LOG "Ready to rollback..." $log_status
    rol_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Rollback --connect-timeout $CNCTTIME -s`
    rol_cc=`echo "$rol_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $rol_cc -ne 0 ]]; then
        rol_desc=`echo "$rol_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$rol_desc" $log_status
        LOG "$rol_inf" $rsp_inf
        return ${RET_FAILURE}
    elif [[ -z "$rol_cc" ]]; then
        LOG "rollback: timeout." $log_status
        LOG "$rol_inf" $rsp_inf
        return ${RET_TIMEOUT}
    else
        LOG "Update rollback." $log_status
        return ${RET_SUCCESS}
    fi
}

# ********
# 功能：升级状态查询
# 参数：无
# 返回值：0-获取到的升级状态为null；1-获取升级状态失败；2-获取升级状态超时; 3-获取到的升级状态为Upgrading
# ********
func_get_upgrade_state()
{
    up_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService --connect-timeout $CNCTTIME -s`
    up_cc=`echo "$up_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ -z "$up_cc" ]]; then
        LOG "Get upgrade state: timeout." $log_status
        LOG "$up_inf" $rsp_inf
        return ${RET_TIMEOUT}
    elif [[ $up_cc -eq 0 ]] && [[ `echo "$up_inf" | grep "UpgradeState"` ]]; then
        up_st=`echo "$up_inf" | grep "UpgradeState" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ "$up_st" = "Upgrading" ]]; then
            return ${STA_UPGRADING}
        else
            return ${STA_NULL}
        fi
    else
        up_desc=`echo "$up_inf" | grep "Description" | sed -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        LOG "$up_desc" $log_status
        LOG "$up_inf" $rsp_inf
        func_parse_cc_and_print "${up_cc}"
        return ${RET_FAILURE}
    fi
}

# ********
# 功能：为升级准备足够的空间
# 参数：固件文件大小
# 返回值：0-升级准备成功；1-升级准备失败
# ********
func_post_prepare()
{
    LOG "Prepare for update..." $log_status
    local image_size=$1
    pre_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"Type":"multipart/form-data", "FileSizeByte":'$image_size'}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Prepare --connect-timeout $CNCTTIME -s`
    pre_cc=`echo "$pre_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $pre_cc -ne 0 ]]; then
        pre_desc=`echo "$pre_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$pre_desc" $log_status
        LOG "$pre_inf" $rsp_inf
        func_parse_cc_and_print "${pre_cc}"
        return ${RET_FAILURE}
    elif [[ -z "$pre_cc" ]]; then
        LOG "Prepare: timeout." $log_status
        LOG "$pre_inf" $rsp_inf
        return ${RET_TIMEOUT}
    else
        LOG "Update preparation completed." $log_status
        return ${RET_SUCCESS}
    fi
}

# ********
# 功能：上传固件
# 参数：固件文件大小
# 返回值：0-上传固件成功；0-上传固件失败
# ********
func_post_upload()
{
    LOG "Uploading the image..." $log_status
    local image_size=$1
    local cnt=0
    local MAXLOOP=3
    while true
    do
        ld_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:multipart/form-data" -H "ImageSize:$image_size" -X POST -F $FWNAME --http1.0 $IP:$PORT/redfish/v1/UpdateService/upload --connect-timeout $CNCTTIME --max-time $MAXTIME -s`
        ld_cc=`echo "$ld_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ $ld_cc -ne 0 ]]; then
            let cnt++
            if [[ $cnt -ge $MAXLOOP ]]; then
                ld_desc=`echo "$ld_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
                LOG "$ld_desc" $log_status
                LOG "$ld_inf" $rsp_inf
                func_parse_cc_and_print "${ld_cc}"
                func_post_update_cancel
                return ${RET_FAILURE}
            else
                ld_desc=`echo "$ld_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
                LOG "$ld_desc" $log_status
                LOG "$ld_inf" $rsp_inf
                sleep $SLEEPTIME
                continue
            fi
        elif [[ -z "$ld_cc" ]]; then
            let cnt++
            if [[ $cnt -ge $MAXLOOP ]]; then
                LOG "Uploading: timeout." $log_status
                LOG "$ld_inf" $rsp_inf
                func_post_update_cancel
                return ${RET_TIMEOUT}
            else
                LOG "Uploading: timeout, retry." $log_status
                LOG "$ld_inf" $rsp_inf
                sleep $SLEEPTIME
                continue
            fi
        else
            LOG "The image is uploaded." $log_status
            return ${RET_SUCCESS}
        fi
    done
}

# ********
# 功能：校验固件
# 参数：无
# 返回值：0-校验固件成功；1-校验固件失败
# ********
func_post_verify()
{
    LOG "Verifying the image..." $log_status
    ver_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"FirmwareName":""}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Verify --connect-timeout $CNCTTIME -s`
    ver_cc=`echo "$ver_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $ver_cc -ne 0 ]]; then
        ver_desc=`echo "$ver_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$ver_desc" $log_status
        LOG "$ver_inf" $rsp_inf
        func_parse_cc_and_print "${ver_cc}"
        func_post_update_cancel
        return ${RET_FAILURE}
    elif [[ -z "$ver_cc" ]]; then
        LOG "Verify: timeout." $log_status
        LOG "$ver_inf" $rsp_inf
        func_post_update_cancel
        return ${RET_TIMEOUT}
    else
        LOG "The image verify completed." $log_status
        return ${RET_SUCCESS}
    fi
}

# ********
# 功能：查询当前处于升级的流程
# 参数：无
# 返回值：0-校验固件完成；1-获取任务状态失败
# ********
func_get_task_status()
{
    while true
    do
        tsk_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/${OEM_NAME}/UpdateTaskStatus --connect-timeout $CNCTTIME -s`
        tsk_cc=`echo "$tsk_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ -z "$tsk_cc" ]]; then
            LOG "Get task status: timeout." $log_status
            LOG "$tsk_inf" $rsp_inf
            func_post_update_rollback
            return ${RET_TIMEOUT}
        elif [[ $tsk_cc -eq 0 ]] && [[ `echo "$tsk_inf" | grep "UpgradeState"` ]] && [[ `echo "$tsk_inf" | grep "Ongoing"` ]]; then
            tsk_st=`echo "$tsk_inf" | grep "UpgradeState" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
            on_going=`echo "$tsk_inf" | grep "Ongoing" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
            if [[ "$tsk_st" != "Verify" ]]; then
                LOG "This should be the verify phase, but..." $log_status
                LOG "$tsk_inf" $rsp_inf
                func_post_update_cancel
                return ${RET_FAILURE}
            else
                if [[ "$on_going" = "true" ]]; then
                    sleep $DELAYTIME
                    continue
                else
                    return ${RET_SUCCESS}
                fi
            fi
        else
            tsk_desc=`echo "$tsk_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
            LOG "Verify:$tsk_desc" $log_status
            LOG "$tsk_inf" $rsp_inf
            func_parse_cc_and_print "${tsk_cc}"
            return ${RET_FAILURE}
        fi
    done
}

# ************
# 功能：固件上传后，解析固件可升级列表
# 参数：无
# 返回值：0-获取可升级列表成功；1-获取可升级列表失败
# ************
func_get_update_components()
{
    com_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/${OEM_NAME}/UpdateComponents --connect-timeout $CNCTTIME -s`
    com_cc=`echo "$com_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ -z "$com_cc" ]]; then
        LOG "Get component: timeout." $log_status
        LOG "$com_inf" $rsp_inf
        func_post_update_rollback
        return ${RET_TIMEOUT}
    elif [[ $com_cc -eq 0 ]] && [[ `echo "$com_inf" | grep "FirmwareType"` ]]; then
        FWTYPE=`echo "$com_inf" | grep "FirmwareType" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        ACTMODE=`echo "$com_inf" | grep -w "ActiveMode" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
        SUBTYPE=`echo "$com_inf" | grep "SubType" | sed -n 1p | sed 's/"//g' | awk -F ':' '{print $2}'`
        if [[ "PSU" = "$FWTYPE" ]]; then
            slt_num=`echo "$com_inf" | grep "\"Slot\":" | wc -l`
            for ((j=1;j<=${slt_num};j++))
            do
                slt_idx=`echo "$com_inf" | grep "\"Slot\":" | sed -n ${j}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                cur_ver=`echo "$com_inf" | grep "CurrentVersion" | sed -n ${j}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                new_ver=`echo "$com_inf" | grep "NewVersion" | sed -n ${j}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                LOG "PSU Slot${slt_idx}: ${cur_ver} -> ${new_ver}" $log_status
                echo "PSU Slot${slt_idx}: ${cur_ver} -> ${new_ver}"
            done
        else
            lct_num=`echo "$com_inf" | grep "\"Location\":" | wc -l`
            for ((i=1;i<=${lct_num};i++))
            do
                lct_nam=`echo "$com_inf" | grep "\"Location\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                cur_ver=`echo "$com_inf" | grep "CurrentVersion" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                new_ver=`echo "$com_inf" | grep "NewVersion" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                LOG "${lct_nam}: ${cur_ver} -> ${new_ver}" $log_status
                if [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]] && [[ "$lct_nam" = "$MEMBER" ]] || [[ "Both" = "$MEMBER" ]]; then
                    echo "${lct_nam}: ${cur_ver} -> ${new_ver}"
                elif [[ "HDM" != "$FWTYPE" && "BMC" != "$FWTYPE" ]]; then
                    echo "${lct_nam}: ${cur_ver} -> ${new_ver}"
                fi
            done
        fi
        echo "$IP_OLD: $FWTYPE active mode: $ACTMODE"
        LOG "$FWTYPE active mode: $ACTMODE" $log_status
        if [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]]; then
            mem_list1=`echo ${com_inf##*\"Member\":}` # 将"Member":及其前面的内容去掉
            mem_list2=`echo ${mem_list1#*\"}` # 将剩下的第一个"号及其前面的内容去掉
            mem_list3=`echo ${mem_list2%%]*}` # 将剩下的第一个]号及其后面的内容去掉
            MEMLIST=`echo ${mem_list3%\"*}` # 将剩下的最后一个"号及其后面的内容去掉
            if [[ "Primary" = "$MEMBER" ]]; then
                mem_list=`echo ${MEMLIST#*\{}` # 将剩下的第一个{号及其前面的内容去掉
                MEMLIST=`echo ${mem_list#*\"}` # 将剩下的第一个"号及其前面的内容去掉
            elif [[ "GoldenImage" = "$MEMBER" ]]; then
                mem_list=`echo ${MEMLIST%%\}*}` # 将剩下的第一个}号及其后面的内容去掉
                MEMLIST=`echo ${mem_list%\"*}` # 将剩下的最后一个"号及其后面的内容去掉
            fi
        elif [[ "BIOS" = "$FWTYPE" ]]; then
            if [[ "Primary" = "$MEMBER" ]]; then
                MEMBER="Flash1"
            elif [[ "GoldenImage" = "$MEMBER" ]]; then
                MEMBER="Flash2"
            fi
        fi
        return ${RET_SUCCESS}
    else
        com_desc=`echo "$com_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$com_desc" $log_status
        LOG "$com_inf" $rsp_inf
        func_parse_cc_and_print "${com_cc}"
        func_post_update_rollback
        return ${RET_FAILURE}
    fi
}

# ********
# 功能：升级
# 参数：无
# 返回值：0-执行升级任务成功；1-执行升级任务失败
# ********
func_post_update()
{
    LOG "Updating the image..." $log_status
    if [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]]; then 
        upd_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"FirmwareList":[{"FirmwareType":"'"$FWTYPE"'","Preserve":"'"$PRESRV"'","RebootMode":"'"$REBOOT"'","Backup":'$BACKUP',"Member":[{"'"$MEMLIST"'"}]}]}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Update --connect-timeout $CNCTTIME -s`
    elif [[ "BIOS" = "$FWTYPE" ]]; then
        upd_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"FirmwareList":[{"FirmwareType":"'"$FWTYPE"'","Preserve":"'"$PRESRV"'","RebootMode":"'"$REBOOT"'","Backup":'$BACKUP',"BiosFlash":"'"$MEMBER"'"}]}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Update --connect-timeout $CNCTTIME -s`
    else
        upd_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X POST -d '{"FirmwareList":[{"FirmwareType":"'"$FWTYPE"'","Preserve":"'"$PRESRV"'","RebootMode":"'"$REBOOT"'","Backup":'$BACKUP'}]}' $IP:$PORT/redfish/v1/UpdateService/Actions/Oem/${OEM_NAME}/UpdateService.Update --connect-timeout $CNCTTIME -s`
    fi
    upd_cc=`echo "$upd_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    if [[ $upd_cc -ne 0 ]]; then
        upd_desc=`echo "$upd_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        LOG "$upd_desc" $log_status
        LOG "$upd_inf" $rsp_inf
        func_parse_cc_and_print "${upd_cc}"
        func_post_update_rollback
        return ${RET_FAILURE}
    elif [[ -z "$upd_cc" ]]; then
        LOG "Update: timeout." $log_status
        LOG "$upd_inf" $rsp_inf
        func_post_update_rollback
        return ${RET_TIMEOUT}
    else
        return ${RET_SUCCESS}
    fi
}

# ********
# 功能：查询当前处于升级的流程和进度
# 参数：无
# 返回值：0-升级完成；1-查询升级进度失败
# ********
func_get_update_progress()
{
    local cnt=0
    local MAXLOOP=3
    while true
    do
        tsk_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/${OEM_NAME}/UpdateTaskStatus --connect-timeout $CNCTTIME -s`
        tsk_cc=`echo "$tsk_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
        if [[ -z "$tsk_cc" ]]; then
            let cnt++
            if [[ $cnt -ge $MAXLOOP ]]; then
                LOG "Get upgrade state: timeout." $log_status
                LOG "$tsk_inf" $rsp_inf
                return ${RET_TIMEOUT}
            else
                LOG "Get upgrade state: timeout, retry." $log_status
                LOG "$tsk_inf" $rsp_inf
                sleep $SLEEPTIME
                continue
            fi
        elif [[ $tsk_cc -eq 0 ]] && [[ `echo "$tsk_inf" | grep "UpgradeState"` ]] && [[ `echo "$tsk_inf" | grep "Ongoing"` ]]; then
            tsk_st=`echo "$tsk_inf" | grep "UpgradeState" | sed -e 's/ //g' -e 's/"//g' -e 's/,//g' | awk -F ':' '{print $2}'`
            on_going=`echo "$tsk_inf" | grep "Ongoing" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
            if [[ "$on_going" = "true" ]] && [[ "$tsk_st" != "Uping" ]]; then
                LOG "This should be the update phase, but..." $log_status
                LOG "$tsk_inf" $rsp_inf
                return ${RET_FAILURE}
            elif [[ "$on_going" != "true" ]] && [[ "$tsk_st" != "Uping" ]]; then
                LOG "$FWTYPE firmware upgrade completed." $log_status
                LOG "$FWTYPE active mode: $ACTMODE" $log_status
                return ${RET_SUCCESS}
            else
                prg_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/UpdateService/Oem/${OEM_NAME}/UpdateTaskProgress --connect-timeout $CNCTTIME -s`
                prg_cc=`echo "$prg_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                if [[ -z "$prg_cc" ]]; then
                    let cnt++
                    if [[ $cnt -ge $MAXLOOP ]]; then
                        LOG "Get task progress: timeout." $log_status
                        LOG "$prg_inf" $rsp_inf
                        return ${RET_TIMEOUT}
                    else
                        LOG "Get task progress: timeout, retry." $log_status
                        LOG "$prg_inf" $rsp_inf
                        sleep $SLEEPTIME
                        continue
                    fi
                elif [[ $prg_cc -eq 0 ]]; then
                    if [[ "PSU" = "$FWTYPE" ]] && [[ `echo "$prg_inf" | grep "\"Progress\":"` ]]; then
                        slt_num=`echo "$prg_inf" | grep "\"Slot\":" | wc -l`
                        for ((j=1;j<=${slt_num};j++))
                        do
                            slt_idx=`echo "$prg_inf" | grep "\"Slot\":" | sed -n ${j}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                            slt_prg=`echo "$prg_inf" | grep "\"Progress\":" | sed -n ${j}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                            slt_rst=`echo "$prg_inf" | grep "\"Result\":" | sed -n ${j}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                            if [[ $slt_rst -ne 0 ]]; then
                                UPD_RESULT=$UPD_FAILED
                                LOG "PSU Slot${slt_idx}: Update Failed! " $log_status
                                LOG "$prg_inf" $rsp_inf
                                echo -n "PSU Slot${slt_idx}: Update Failed!   "
                            else
                                UPD_RESULT=$UPD_NOT_FAILED
                                LOG "PSU Slot${slt_idx}: ${slt_prg}% " $log_status
                                echo -n "PSU Slot${slt_idx}: ${slt_prg}%   "
                            fi
                        done
                        printf "\r"
                    elif [[ "PSU" != "$FWTYPE" ]] && [[ `echo "$prg_inf" | grep "\"Location\":"` ]] && [[ `echo "$prg_inf" | grep "\"Progress\":"` ]]; then
                        loc_num=`echo "$prg_inf" | grep "\"Location\":" | wc -l`
                        for ((i=1;i<=${loc_num};i++))
                        do
                            loc_nam=`echo "$prg_inf" | grep "\"Location\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
                            loc_prg=`echo "$prg_inf" | grep "\"Progress\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                            loc_rst=`echo "$prg_inf" | grep "\"Result\":" | sed -n ${i}p | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
                            if [[ $loc_rst -ne 0 ]]; then
                                UPD_RESULT=$UPD_FAILED
                                LOG "${loc_nam}: Update Failed! " $log_status
                                LOG "$prg_inf" $rsp_inf
                                echo -n "${loc_nam}: Update Failed! "
                            else
                                UPD_RESULT=$UPD_NOT_FAILED
                                LOG "${loc_nam}: ${loc_prg}% " $log_status
                                echo -n "${loc_nam}: ${loc_prg}% "
                                if [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]] && [[ "Auto" = "$REBOOT" ]] && [[ ${loc_prg} -eq 100 ]]; then
                                    LOG "$FWTYPE firmware upgrade completed." $log_status
                                    LOG "$FWTYPE active mode: $ACTMODE" $log_status
                                    return ${RET_SUCCESS}
                                fi
                            fi
                        done
                        printf "\r"
                    fi
                fi
            fi
            sleep $DELAYTIME
        else
            let cnt++
            if [[ $cnt -ge $MAXLOOP ]]; then
                tsk_desc=`echo "$tsk_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
                LOG "Updating:$tsk_desc" $log_status
                LOG "$tsk_inf" $rsp_inf
                func_parse_cc_and_print "${tsk_cc}"
                return ${RET_FAILURE}
            else
                tsk_desc=`echo "$tsk_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
                LOG "Updating:$tsk_desc, retry" $log_status
                LOG "$tsk_inf" $rsp_inf
                sleep $SLEEPTIME
                continue
            fi
        fi
    done
}

# ********
# 功能：获取电源状态
# 参数：无
# 返回值：0-关机状态；1-获取电源状态失败；2-获取电源状态超时；3-开机状态
# ********
func_get_power_state()
{
    chs_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/Chassis --connect-timeout $CNCTTIME -s`
    chs_cc=`echo "$chs_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
    chs_id=`echo "$chs_inf" | grep "@odata.id" | sed -n 2p | sed -e 's/"//g' -e 's/,//g' | awk -F 'Chassis/' '{print $2}'`
    if [[ -z "$chs_cc" ]] && [[ -z "$chs_id" ]]; then
        LOG "Get chassis info: timeout." $log_status
        LOG "$chs_inf" $rsp_inf
        return ${RET_TIMEOUT}
    elif [[ $chs_cc -eq 0 ]]; then
        for ((a=1;a<=$TRYTIMES;a++))
        do
            # 用于查询电源状态
            chs_id_inf=`$CURL_CMD -c $cookies -b $cookies -H "X-Auth-Token:$TOKEN" -H "Content-Type:application/json" -X GET $IP:$PORT/redfish/v1/Chassis/${chs_id}/Power --connect-timeout $CNCTTIME -s`
            chs_id_cc=`echo "$chs_id_inf" | grep "CompletionCode" | sed -e 's/ //g' -e 's/,//g' | awk -F ':' '{print $2}'`
            pwr_sta=`echo "$chs_id_inf" | grep "HostPowerStatus" | sed -e 's/ //g' -e 's/,//g' -e 's/"//g' | awk -F ':' '{print $2}'`
            if [[ "x$chs_id_cc" = "x" ]] && [[ "x$pwr_sta" = "x" ]]; then
                LOG "Get chassis id info: timeout." $log_status
                LOG "$chs_id_inf" $rsp_inf
                continue
            elif [[ $chs_id_cc -eq 0 ]] && [[ "On" = "$pwr_sta" ]]; then # 处于开机状态
                return ${PWR_ON}
            elif [[ $chs_id_cc -eq 0 ]] && [[ "Off" = "$pwr_sta" ]]; then # 处于关机状态
                return ${PWR_OFF}
            else
                chs_id_desc=`echo "$chs_id_inf" | grep -w "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
                LOG "$chs_id_desc" $log_status
                LOG "$chs_id_inf" $rsp_inf
                continue
            fi
        done
    else
        chs_desc=`echo "$chs_inf" | grep "Description" | sed 's/"//g' | awk -F ':' '{print $2}'`
        func_parse_cc_and_print "${tsk_cc}"
        LOG "$chs_desc" $log_status
    fi
    LOG "Get power state failed!" $log_status
    LOG "$chs_inf" $rsp_inf
    return ${RET_FAILURE}
}

# ********
# 功能：升级主流程
# 参数：无
# 返回值：0-升级成功；1-升级不成功；2-获取升级进度超时；3-创建会话失败
# ********
update_main()
{
    func_get_curl_cmd
    func_parse_ipv6
    func_establish_session
    [[ $? -ne ${RET_SUCCESS} ]] && return ${RET_SESSION_FAIL}
    func_get_upgrade_state
    ren=$?
    if [[ $ren -ne ${STA_NULL} ]]; then
        if [[ $ren -eq ${RET_TIMEOUT} ]]; then
            return ${RET_TIMEOUT}
        elif [[ $ren -eq ${STA_UPGRADING} ]]; then
            LOG "Other users are updating firmware, please wait..." $log_status
        fi
        return ${RET_FAILURE}
    fi
    func_get_redfish_version
    ret1=$?
    [[ $ret1 -ne ${RET_SUCCESS} ]] && return $ret1
    image_file=`echo $FWNAME | awk -F '@' '{print $2}'`
    image_size=`ls -l $image_file | awk '{print $5}' | sed 's/ //g'`
    LOG "image_size: $image_size" $log_status
    func_post_prepare $image_size
    ret2=$?
    [[ $ret2 -ne ${RET_SUCCESS} ]] && return $ret2
    func_post_upload $image_size
    ret3=$?
    [[ $ret3 -ne ${RET_SUCCESS} ]] && return $ret3
    func_post_verify
    ret4=$?
    [[ $ret4 -ne ${RET_SUCCESS} ]] && return $ret4
    func_get_task_status
    ret5=$?
    [[ $ret5 -ne ${RET_SUCCESS} ]] && return $ret5
    func_get_update_components
    ret6=$?
    [[ $ret6 -ne ${RET_SUCCESS} ]] && return $ret6
    func_get_power_state
    PWR_STA=$?
    if [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]]; then 
        [[ "ForceRestore" = "$PRESRV" ]] && PRESRV="Retain" # HDM应该为恢复出厂配置
        [[ -z "$REBOOT" || "Default" = "$REBOOT" ]] && REBOOT="Auto" # HDM默认自动重启
    elif [[ "BIOS" = "$FWTYPE" ]]; then
        [[ -z "$REBOOT" || "Default" = "$REBOOT" ]] && REBOOT="Manual" # BIOS默认手动重启
    else
        [[ -z "$REBOOT" || "Default" = "$REBOOT" ]] && REBOOT="Auto" # 其他固件REBOOT值为Auto或Manual任意
    fi
    func_post_update
    ret7=$?
    [[ $ret7 -ne ${RET_SUCCESS} ]] && return $ret7
    if [[ "BIOS" = "$FWTYPE" ]] && [[ "ForceRestore" = "$PRESRV" ]] && [[ ${PWR_STA} -eq ${PWR_ON} ]]; then # BIOS强制覆盖升级需要主机下电
        func_delete_session
        printf "\n$IP_OLD: Forced overwrite upgrade can only be done when the host is powered off.\n"
        printf "$IP_OLD: $FWTYPE Update Fail.\n"
        LOG "The host need power off." $log_status
        sleep 5 # 升级接口返回需要等待，因为升级状态仍在升级中，若不等待，则无法进行下个固件更新
        exit 3
    fi
    func_get_update_progress
    res=$?
    if [[ $res -eq ${RET_FAILURE} ]]; then
        return ${RET_FAILURE}
    elif [[ $res -eq ${RET_TIMEOUT} ]] && [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]] && [[ "Auto" = "$REBOOT" ]] && [[ "Retain" = "$PRESRV" ]]; then
        LOG "Get $FWTYPE updating progress timeout." $log_status
    elif [[ $res -eq ${RET_TIMEOUT} ]]; then
        return ${RET_PROGRESS_TIMEOUT}
    fi
    if [[ ${UPD_RESULT} -eq ${UPD_FAILED} ]]; then
        return ${RET_FAILURE}
    elif [[ "HDM" = "$FWTYPE" || "BMC" = "$FWTYPE" ]] && [[ "Auto" = "$REBOOT" ]] && [[ "Retain" = "$PRESRV" ]]; then # HDM升级完成后重启
        func_delete_session # 同版本HDM升级时可能不会重启
        printf "\n$IP_OLD: After upgrading $FWTYPE firmware, reset BMC, please wait a moment...\n"
        sleep $RBTTIME
        for ((i=1;i<=$TRYTIMES;i++))
        do
            func_establish_session
            if [[ $? -ne ${RET_SUCCESS} ]]; then
                continue
            else
                let i=$TRYTIMES+1
                for ((j=1;j<=$TRYTIMES;j++))
                do
                    sleep $SLEEPTIME
                    func_get_upgrade_state # 查询升级状态，确保能进行下一次升级
                    [[ $? -eq ${STA_NULL} ]] && break # 升级状态为null
                done
            fi
        done
    elif [[ "BIOS" = "$FWTYPE" ]] && [[ "Auto" = "$REBOOT" ]] && [[ ${PWR_STA} -eq ${PWR_ON} ]]; then # 开机状态下BIOS升级完成后重启,在刷新完成前都处于升级状态,所以要等待.
        printf "\n$IP_OLD: After upgrading $FWTYPE firmware, restart BIOS, please wait a moment...\n"
        local upg_flag=0
        for ((n=0;n<$GETTIMES;n++)) # 轮询等待状态从null->Upgrading最长30mins
        do
            func_get_upgrade_state
            if [[ $? -eq ${STA_UPGRADING} ]]; then # 升级状态为Upgrading
                upg_flag=1
                break
            fi
            sleep $SLEEPTIME
        done
        if [[ $upg_flag -eq 1 ]]; then
            while true; do # 超时后状态会自动置为null
                func_get_upgrade_state
                [[ $? -eq ${STA_NULL} ]] && break # 升级状态为null
                sleep $SLEEPTIME
            done
        fi
    fi
    return ${RET_SUCCESS}
}

LOG "===REBOOT: ${REBOOT}, PRESRV: ${PRESRV}, BACKUP: ${BACKUP}===" $log_status
update_main
ret=$?
if [[ $ret -eq ${RET_FAILURE} ]]; then
    func_delete_session
    printf "\n$IP_OLD: $FWTYPE Update Fail.\n"
    LOG "$FWTYPE Update Fail." $log_status
    exit 1
elif [[ $ret -eq ${RET_SESSION_FAIL} ]]; then
    printf "\n$IP_OLD: Created session failed.\n"
    printf "$IP_OLD: $FWTYPE Update Fail.\n"
    LOG "Created session failed." $log_status
    exit 1
elif [[ $ret -eq ${RET_TIMEOUT} ]]; then
    printf "\n$IP_OLD: $FWTYPE Update Timeout.\n"
    LOG "$FWTYPE Update Timeout." $log_status
    exit 1
elif [[ $ret -eq ${RET_PROGRESS_TIMEOUT} ]]; then
    printf "\n$IP_OLD: $FWTYPE Update Timeout.\n"
    printf "$IP_OLD: Customers need to ensure whether the $FWTYPE firmware upgrade successful or not.\n"
    LOG "Customers need to ensure whether the $FWTYPE firmware upgrade successful or not." $log_status
    exit 2
else
    func_delete_session
    printf "\n$IP_OLD: $FWTYPE Update Pass.\n"
    exit 0
fi
