#!/bin/bash
set +x
LOG_FILE="/var/log/inspect.log"
OLD_VER="V100R001C01SPC100 V100R001C01SPC200 V100R001C01SPC210 V100R001C01SPC290 V100R001C20SPC100 V100R001C20SPC001 V100R001C20 V100R001C30 V100R001C30SPC100 V100R001C30SPC110 V100R001C30 V100R001C30SPC200 V300R005C00SPC100 V300R005C00SPC110 V300R005C00SPC160 V300R005C00SPC170 V300R005C00"
NEW_VER="Exclude ${OLD_VER}"
OLD_PATH="/opt/huawei/patch"
NEW_PATH="/var/huawei/patch"
G_MML_FILE_PATH="/opt/huawei/snas/script/inspect_mml"
source $G_MML_FILE_PATH/CheckItems
CurInspectNum="282"
CurInspectFun="$(GetInspectType $CurInspectNum)"
RESULTFILE="/tmp/tmpResult${CurInspectFun}"
>${RESULTFILE}

function LOG
{
    local time=$(date)
    echo [${time}][$$][$CurInspectFun]$@ >> $LOG_FILE
}

function getModuleViaPatchName()
{
    local patchName=$1
    echo "${patchName}" | awk -F'SPH[0-9]+|.patch' '{print $2}'
}

#特殊处理环境上原本没有的补丁模块，但是补丁包里面又包含补丁模块，则不需要处理，需要过滤掉
#返回值 0:表示需要处理   1:不需要处理 2:lsmod命令异常
function special_operate()
{
    local patchName=$1
    local moduleName=$(getModuleViaPatchName ${patchName})
    local is_c72=0
    local ofed_ver="3.2"
    dmidecode -t 4 | grep -q "Family: Atom" >/dev/null 2>&1
    if [ $? -eq 0 ];then
        is_c72=1
    else
        echo ${moduleName} | grep -q "ko2iblnd" >/dev/null 2>&1
        if [ $? -eq 0 ];then
            ofed_ver=$(ofed_info -s | grep -Po '(?<=-)[0-9.]+-' | tr -d '-')
            if [ "X$ofed_ver" == "X" ];then
                LOG "[$LINENO]no need to active ${patchName}!"
                return 1
            fi
            echo ${moduleName} | grep -q "$ofed_ver" >/dev/null 2>&1
            ret=$?
            if [ "$ofed_ver" == "3.2" ] && [ $ret -ne 0 ] ;then
                echo "${moduleName}"
                return 0
            elif [ $ret -eq 0 ];then
                echo "${moduleName%_$ofed_ver}"
                return 0
            fi
            LOG "[$LINENO]no need to active ${patchName}!"
            return 1
        fi
    fi

    lsmod | grep -w snas_base >/dev/null 2>&1
    if [ $? -ne 0 ];then
        LOG "[$LINENO]lsmod maybe abnormal!"
        return 2
    fi
    lsmod | grep -qw ${moduleName} >/dev/null 2>&1
    if [ $? -ne 0 ];then
        echo ${moduleName} | grep -q "module_ipmi" >/dev/null 2>&1
        if [ $? -eq 0 ] && [ ${is_c72} -eq 1 ];then
            return 0
        fi

        echo ${moduleName} | grep -q "cm_sysctrl_c72" >/dev/null 2>&1
        if [ $? -eq 0 ] && [ ${is_c72} -eq 1 ];then
            echo "${moduleName%_c72}"
            return 0
        fi
        echo ${moduleName} | grep -q "cm_sysctrl_t3000" >/dev/null 2>&1
        if [ $? -eq 0 ] && [ ${is_c72} -eq 0 ];then
            #cm_sysctrl_t3000.ko不仅适用T3000还适用RH
            echo "${moduleName%_t3000}"
            return 0
        fi
        echo ${moduleName} | grep -q "pangea_sal" >/dev/null 2>&1
        if [ $? -eq 0 ];then
            #pangea_sal 名字转换
            echo "sal"
            return 0
        fi

        LOG "[$LINENO]no need to active ${patchName}!"
        return 1
    fi

    return 0
}

# Return 1, need filter this patch
function patchSdFilter()
{
    local patchName=$1
    local moduleName=$(getModuleViaPatchName ${patchName})
    local isnotT3000Serial=0
    if [ "${moduleName}" = "sd_t3000" -o "${moduleName}" = "sd" ]; then
        patchName=${patchName};
    else
        return 0
    fi
    dmidecode -t 1 | grep -Poq '(?<=Product Name:) +T3[0-9]00' >/dev/null 2>&1
    isnotT3000Serial=$?
    if [ ${isnotT3000Serial} -ne 0 ]; then
        if [ "${moduleName}" = "sd_t3000" ]; then
            LOG "[$LINENO]: Filter ${patchName} on RH."
            return 1
        fi
    else # is T3000 Serials
        if [ "${moduleName}" = "sd" ]; then
            LOG "[$LINENO]: Filter ${patchName} on T3000."
            return 1
        fi
    fi
    return 0
}
function get_livepatch_moudle()
{
    local ppath=$(find $1 -name "$2" -exec dirname {} \;)
    local pname="$2"
    local tmpDir="/tmp/tmp_HotPatch$$"
    if [ ! -d "${tmpDir}" ]; then
        mkdir -p "${tmpDir}"
    else
        rm -rf "${tmpDir}/*"
    fi
    local tmpfile="${tmpDir}/tmp.tar.gz"
    cp ${ppath}/${pname} ${tmpDir}
    DATA_POS="`grep -a -n "^##\[\[DATA\]\]##" ${tmpDir}/${pname} | awk -F":" '{print $1}'`"
    DATA_POS=`expr $DATA_POS + 1`
    tail -n +${DATA_POS} "${tmpDir}/${pname}" >$tmpfile 2>/dev/null
    tar zxf $tmpfile -C ${tmpDir} > /dev/null 2>&1
    module=$(ls ${tmpDir} | grep ".tar.gz" | grep -v tmp.tar.gz |awk -F"." '{print $1}' | awk -F'SPH[0-9]+|.patch' '{print $2}')
    ls ${tmpDir} |grep "${module}.ko_flag" >/dev/null 2>&1 
    if [ $? -ne 0 ];then
        echo "NO"
    else
        echo "$module"
    fi
    rm -rf ${tmpDir}
}
#获取补丁列表存入临时文件中。调用者保证目录和临时文件有效
function get_patch_list()
{
    local tmppath="$1"
    local tmpfile="$2"
    local patchList=""
    local errFlag=0
    local iret=0
    local moduleName=""

    # 从7.0开始livepatch查询的补丁名字和补丁文件名字已经无明确对应关系了，只有模块名能对应上
    # 从补丁文件中获取模块名，模块可能有多个补丁，从livepatch -q结果中按顺序对应
    tmppath=$(find ${tmppath} -name "hotpatch.conf" -exec dirname {} \;)
    if [ -f ${tmppath}/hotpatch.conf ]; then
        patchList=$(cat ${tmppath}/hotpatch.conf | awk '{print $1}')
    fi
    >${tmpfile}
    for item in ${patchList}; do
        moduleName=$(patchSdFilter ${item})
        iret=$?
        if [ ${iret} -ne 0 ]; then
            continue
        fi
        if [ -n "${moduleName}" ]; then
            echo "${item} ${moduleName}" >>${tmpfile}
            continue
        fi

        moduleName=$(special_operate ${item})
        iret=$?
        if [ ${iret} -ne 0 ];then
            continue
        fi
        if [ -n "${moduleName}" ]; then
            echo "${item} ${moduleName}" >>${tmpfile}
            continue
        fi

        moduleName=$(getModuleViaPatchName ${item})
        if [ -n "${moduleName}" ]; then
            echo "${item} ${moduleName}" >>${tmpfile}
        fi
    done

    return ${errFlag}
}

#获取补丁列表存入临时文件中。调用者保证目录和临时文件有效
function get_patch_list_new()
{
    local tmppath="$1"
    local tmpfile="$2"
    local patchList=""
    local errFlag=0
    local iret=0
    local moduleName=""

    # 从7.0开始livepatch查询的补丁名字和补丁文件名字已经无明确对应关系了，只有模块名能对应上
    # 从补丁文件中获取模块名，模块可能有多个补丁，从livepatch -q结果中按顺序对应
    tmppath=$(find ${tmppath} -name "hotpatch.conf" -exec dirname {} \;)
    if [ -f ${tmppath}/hotpatch.conf ]; then
        patchList=$(cat ${tmppath}/hotpatch.conf | awk '{print $1}')
    fi
    >${tmpfile}
    for item in ${patchList}; do
        #进到此处,hotpatch_list存在且不为空,
        #如果item在hotpatch_list中没有patchName,不检查
        patchName=$(cat $tmppath/hotpatch_list | grep $item | awk '{print $1}')
        if [ "X${patchName}" == "X" ]; then
            continue
        fi

        moduleName=$(patchSdFilter ${item})
        iret=$?
        if [ ${iret} -ne 0 ]; then
            continue
        fi
        if [ "X${moduleName}" != "X" ]; then
            echo "${item} ${patchName}" >>${tmpfile}
            continue
        fi

        moduleName=$(special_operate ${item})
        iret=$?
        if [ ${iret} -ne 0 ];then
            continue
        fi
        if [ "X${moduleName}" != "X" ]; then
            echo "${item} ${patchName}" >>${tmpfile}
            continue
        fi

        echo "${item} ${patchName}" >>${tmpfile}

    done

    return ${errFlag}
}

function get_patch_path()
{
    local nr=0
    local patch_base="${NEW_PATH}"
    local work_path=""
    local found=0
    local dir=""
    local sub_dirs="cur tmp"
    local tmpver=""
    local ver=""
    local ret=0

    tmpver=$(grep ProductVersion /opt/huawei/deploy/package/version)
    ret=$?
    ver=$(echo "${tmpver}" | awk -F "=" '{print $2}')
    if [ ${ret} -ne 0 -o "$ver" == "" ];then
        LOG "[$LINENO]get version fail"
        echo "Get patch version failed" >>${RESULTFILE} 2>&1
        return 1
    fi
    echo ${OLD_VER} | grep -w ${ver} > /dev/null 2>&1
    if [ $? -eq 0 ];then
        patch_base="${OLD_PATH}"
    else
        patch_base="${NEW_PATH}"
    fi

    for dir in ${sub_dirs}
    do
        if [ -d ${patch_base}/${dir} ];then
            nr=$(find ${patch_base}/${dir} -type d -name "*SPH*" | wc -l 2>/dev/null )
            if [ ! -z ${nr} -a ${nr} -ne 0 ];then
                work_path=${patch_base}/${dir}
                found=1
                break
            fi
        fi
    done

    if [ ${found} -eq 1 ];then
        echo ${work_path}
        LOG "[$LINENO]Get work path of hot patch ok, ${work_path}"
        return 0
    fi
    LOG "[$LINENO]Get work path of hot patch fail, maybe there is no patch"
    return 0
}

function check_patch()
{
    local ret=0
    local hpath=$1
    local module=""
    local moduleList=""
    local patchCount=0
    local activeCount=0
    local livepatchInfo=""
    local tmppath=""
    local patchfile=""
    local PATCH_FILE_LIST="/tmp/tmp_HotPatchlist$$.txt"

    tmppath=$(find ${hpath} -name "hotpatch.conf" -exec dirname {} \;) 
    local hotpatch_list=$([ -f $tmppath/hotpatch_list ] && cat $tmppath/hotpatch_list 2>&1)
    if [ "X${hotpatch_list}" != "X" ];then
        get_patch_list_new "${hpath}" "${PATCH_FILE_LIST}"
        if [ $? -eq 1 ];then
            LOG "[$LINENO]Get patch infomation failed.path:${hpath}"
            echo "Get patch infomation failed" >>${RESULTFILE} 2>&1
            return 1
        fi

        moduleList=$(cat "${PATCH_FILE_LIST}" | awk '{print $2}' | sort -u)
        for module in ${moduleList}; do
            livepatch -q${module} | grep "^Patch State" | grep -q "Active" >/dev/null 2>&1
            if [  $? -ne 0 ];then
                LOG "[$LINENO]Check hot patch of ${module} fail"
                patchfile=$(cat "${PATCH_FILE_LIST}" | grep "${module}" | awk '{print $1}')
                echo "${patchfile}: Hot patch active fail" >>${RESULTFILE} 2>&1
            fi
        done
    else
        get_patch_list "${hpath}" "${PATCH_FILE_LIST}"
        if [ $? -eq 1 ];then
            LOG "[$LINENO]Get patch infomation failed.path:${hpath}"
            echo "Get patch infomation failed" >>${RESULTFILE} 2>&1
            return 1
        fi

        # 从7.0开始livepatch查询的补丁名字和补丁文件名字已经无明确对应关系了，只有模块名能对应上
        # 从补丁文件中获取模块名，模块可能有多个补丁，从livepatch -q结果中按顺序对应
        livepatchInfo=$(livepatch -q)
        moduleList=$(cat "${PATCH_FILE_LIST}" | awk '{print $2}' | sort -u)
        for module in ${moduleList}; do
            patchCount=$(cat "${PATCH_FILE_LIST}" | awk -v module=${module} '{if($2==module){print $0}}' | grep -wc "${module}")
            local patchName=$(cat "${PATCH_FILE_LIST}" | grep ${module} | awk '{print $1}')
            patch_module=$(get_livepatch_moudle "${hpath}" "${patchName}")
            if [ "X${patch_module}" = "XNO" ];then
                continue
            fi
            activeCount=$(echo "${livepatchInfo}" | sed -n '/Patch Name:[ VRCSPH0-9]\+'"${patch_module}"'$/{N;N;s/\n/ /g;p}' | grep -c "Patch State: Active")
            if [ ${patchCount} -gt ${activeCount} ]; then
                LOG "[$LINENO]Check hot patch of ${module} fail(${patch_module})"
                echo "${module}: Hot patch active fail(${patch_module})" >>${RESULTFILE} 2>&1
            fi
        done
    fi

    if [ -f "${PATCH_FILE_LIST}" ];then
        rm -rf "${PATCH_FILE_LIST}"
    fi
    return 0
}

hppath=$(get_patch_path)
if [ -d "${hppath}" ];then
    check_patch ${hppath}
fi
