HEX
Server: Apache/2.4.34 (Red Hat) OpenSSL/1.0.2k-fips
System: Linux WORDPRESS 3.10.0-1160.118.1.el7.x86_64 #1 SMP Thu Apr 4 03:33:23 EDT 2024 x86_64
User: digital (1020)
PHP: 7.2.24
Disabled: NONE
Upload Files
File: //run_smc_client.sh
#!/bin/bash


######################################################################
# Function    : Script Usage
# Params      : No
# Return      : None
# For example : script::usage
######################################################################
script::usage()
{
    echo "************************************************************************************************"
    echo "* Script                : ${BASH_SOURCE[0]}.                                                    "
    echo "* Usage                 : [OPTION...]                                                           "
    echo "* [-h,--help]           : Script Help Information.                                              "
    echo "* [-i,--install_path]   : The Client Tools Install Path.                                        "
    echo "* [--accesstokenid]     : AccessTokenId.                                                        "
    echo "* [--accesstokencode]   : AccessTokenCode.                                                      "
    echo "* [--ak]                : AccessId.                                                             "
    echo "* [--sk]                : SecretKey.                                                            "
    echo "* [--endpoint]          : SMC Endpoint.                                                         "
    echo "* [-f,--force_update]   : Force To Update Tools , Datas Will Be Overwritten , Default Force     "
    echo "* [--delete]            : Delete The Client Tools , Need To Assign Path[--install_path].        "
    echo "* [--download]          : Download The Client Tools , Need To Assign Path[--install_path].      "
    echo "* [--decompress]        : Decompress The Client Tools , Need To Assign Path[--install_path].    "
    echo "* [--auto_run]          : One-Click Operation.                                                  "
    echo "* [--no_update]         : Only Run Client Tools , Need To Assign Path[--install_path].          "
    echo "* [--log_path]          : Log File Path , Default /var/log.                                     "
    echo "* [--sourceid]          : Appoint source id.                                                    "
    echo "* [--sourcename]        : Appoint source name.                                                  "
    echo "* [-v,--version]        : Client Tools Version.                                                 "
    echo "* [--exclude]           : Default True And Save Config File.                                    "
    echo "* [Examples]            :                                                                       "
    echo "*         bash ${BASH_SOURCE[0]} --accesstokenid=xxx --accesstokencode=xxx                      "
    echo "*         bash ${BASH_SOURCE[0]} --install_path=./ --auto_run --froce_update --ak=xxx --sk=xxx  "
    echo "*         bash ${BASH_SOURCE[0]} --help                                                         "
    echo "************************************************************************************************"
    exit 0
}

######################################################################
# Function    : Script TmpFile CleanUp
# Params      : No
# Return      : None
# For example : script::cleanup
######################################################################
script::cleanup()
{
    # Before Script Exit To Do Anything
    # TODO
    log::info "Script Exit."
    kill $$
}

# Received Signal
trap script::cleanup EXIT 2

# Default Install Path
DEFAULT_INSTALL_PATH="/smc"

# Default OutPut Log File
DEFAULT_LOG_PATH="/var/log/smc_tools.log"

# Default Deps Pkgs Install
PKGS_DEFAULT_LIST=(
"tar"
"readlink"
"wget"
)

# Yum Pkgs
PKGS_YUM_LIST=(
)

# Zypper Pkgs
PKGS_ZYPPER_LIST=(
)

# Apt-get Pkgs
PKGS_APT_LIST=(
)

# Backup File List
BACKUP_LIST=(
"client_data"
"user_config.json"
"key_data"
"key_data.pub"
)

SMC_CLIENT_URL_ROOT="https://p2v-tools-sg1.oss-ap-southeast-1.aliyuncs.com/smc"
SMC_CLIENT_TOOL_URL="${SMC_CLIENT_URL_ROOT}/smc_client_tool"

######################################################################
# Function    : Log
# Params      : $@
# Return      : None
# For example : log::info "Hello word !"
######################################################################
log::info()
{
    DATE_N=`date "+%Y-%m-%d %H:%M:%S"`
    echo -e "[${DATE_N}] [Info]  $@" | tee -a ${log_file}
}

log::warn()
{
    DATE_N=`date "+%Y-%m-%d %H:%M:%S"`
    echo -e "[${DATE_N}] [Warn]  $@" | tee -a ${log_file}
}

smc::report_source_status() {
    local msg=$1
    # remove '"' chars of msg
    msg=$(echo ${msg//\"/\\\"})
    local smc_client_tool=${client_file}
    if ! test -f $smc_client_tool; then
        mkdir -p /smc
        smc_client_tool=/smc/smc_client_tool
        if ! test -f $smc_client_tool; then
            if ! wget $SMC_CLIENT_TOOL_URL -O $smc_client_tool; then
                log::warn "Failed to download smc client tool."
                rm -rf $smc_client_tool
                exit 1
            fi
        fi
    fi

    chmod +x $smc_client_tool
    local source_status_path=./source_status.json
    local status_data="{\"source_id\":\"$source_id\", \"error_code\":\"I1\", \"error_msg\":\"${msg}\"}"
    echo -e "${status_data}" > $source_status_path
    $smc_client_tool --accesstokenid=$accesstokenid --accesstokencode=$accesstokencode --reportsource=$source_status_path --endpoint="https://smc-service.aliyuncs.com"
}

log::error()
{
    DATE_N=`date "+%Y-%m-%d %H:%M:%S"`
    local msg="[${DATE_N}] [Error]  $@"
    echo -e "${msg}" | tee -a ${log_file}
    if [[ "${reportstatus}" == "True" ]]; then
        smc::report_source_status "${msg}"
    fi
    exit 1
}

######################################################################
# Function    : Get system architure
# Params      : No
# Global      : architure
# Return      : None
# For example : get::system::architure
######################################################################
get::system::architure()
{
    local word_bit=$(getconf WORD_BIT)
    local long_bit=$(getconf LONG_BIT)
    if [[ -z "${word_bit}" || -z "${long_bit}" ]]; then
        log::error "Get Architure Failed." && exit 1
    fi

    architure=""
    if [[ "${word_bit}" == "32" && "${long_bit}" == "64" ]]; then
        local schema_type=$(arch|xargs -i echo {})
        if [[ "${schema_type}" == "aarch64" ]]; then
            architure=arm64
        else
            architure=x86_64
        fi
    else
        architure=i386
    fi
    
    log::info "System Architure Is ${architure}."
}

######################################################################
# Function    : Check install dependent package
# Param1      : Installation mode:yum/apt-get/zypper
# Param2      : Package array
# Return      : 0 or 1
# For example : install::deps::check "yum" "${PKGS_DEFAULT_LIST[@]}"
######################################################################
install::deps::check()
{
    local PKGS_DEPS_ORDER=$1
    local PKGS_DEPS_LIST=("$@")

    if [[ "${#PKGS_DEPS_LIST[@]}" == 1 ]]; then
        log::info "The ${PKGS_DEPS_ORDER} No Package To Install."
        return 0
    fi

    for i in ${!PKGS_DEPS_LIST[@]}
    do
        if [[ ${i} != 0 ]]; then
            local deps=($(echo ${PKGS_DEPS_LIST[i]} | tr -s "|" " "))
            if [[ ${#deps[@]} == 1 ]]; then
                local install_cmd=${PKGS_DEPS_ORDER}install ${PKGS_DEPS_LIST[i]}
                which ${PKGS_DEPS_LIST[i]} >/dev/null 2>&1 || log::error "The ${PKGS_DEPS_LIST[i]} Package Need Install , Please To Use [${install_cmd}] Install."
            else
                for j in ${!deps[@]}
                do
                    if [[ ${j} != 0 ]]; then
                        which ${deps[0]} >/dev/null 2>&1 || log::error "The ${deps[0]} Package Need Install , Please To Install."
                    fi
                done
            fi
        fi
    done

    return 0
}

######################################################################
# Function    : Call interfaces according to different platforms
# Params      : No
# Return      : None
# For example : install::deps::platforms
######################################################################
install::deps::platforms()
{
    if which yum >/dev/null 2>&1; then
        install::deps::check "yum -y " ${PKGS_YUM_LIST[@]}
        install::deps::check "yum -y " ${PKGS_DEFAULT_LIST[@]}
    fi
    if which apt-get >/dev/null 2>&1; then
        install::deps::check "apt-get -y " ${PKGS_APT_LIST[@]}
        install::deps::check "apt-get -y " ${PKGS_DEFAULT_LIST[@]}
    fi
    if which zypper >/dev/null 2>&1; then
        install::deps::check "zypper -n " ${PKGS_ZYPPER_LIST[@]}
        install::deps::check "zypper -n " ${PKGS_DEFAULT_LIST[@]}
    fi
}

######################################################################
# Function    : Choice client update mode
# Params      : update_mode
# Global      : update_mode
# Return      : None
# For example : choice::update::mode
######################################################################
choice::update::mode()
{
    if [[ "${force_update}" == "False" ]]; then
        echo "****************************************************************"
        echo "Whether To Forcibly Update The SMC Client Tools ? "
        read -t 30 -p "Please Enter yes Or no , Simplify [y/n]: " input_status
        if [[ -z "${input_status}" ]]; then
            echo -e "\nYou No Enter Information , Default Non-update."
            input_status="no"
        else
            input_status=${input_status}
            echo "Your Enter Is ${input_status}."
        fi
        echo "****************************************************************"
    else
        input_status="yes"
    fi 
}

######################################################################
# Function    : client update mode
# Params      : update_mode
# Global      : update_mode
# Return      : None
# For example : client::update::mode
######################################################################
client::update::mode()
{
    update_mode=$1
    
    case "${update_mode}" in
        "yes"|"Yes"|"YES"|"y"|"Y")
            update_mode="force"
            ;;
        "no"|"No"|"NO"|"n"|"N")
            update_mode="optional"
            ;;
        *)
            log::error "Your Enter Is Invalid Parameter , Please To Check."
            ;;
    esac
}

######################################################################
# Function    : Get SMC client running progress
# Params      : No
# Return      : pid_exe , pid_no_exe
# For example : get::client::progress
######################################################################
get::client::progress()
{
    local client_pids=($(ps -ef | grep -v "grep" | grep -E "${TOOL_FILE_NAME}" | awk '{print $2}'))
    if [[ "${#client_pids[@]}" -ne 0 ]]; then
        local index_exe=0
        local index_no_exe=0
        for pid in ${client_pids[@]}
        do
            local link_path=$(readlink /proc/${pid}/exe 2>/dev/null| awk '/go2aliyun_client/{print $1}')
            if [[ -n ${link_path} ]]; then
                pid_exe[index_exe]=${link_path}
                log::info "The Client Tools Progress Is Exist, Re-Running Path:${pid_exe[index_exe]}."
                ((index_exe++))
            fi
        done
    else
        log::info "The Client Tools Progress Inexistence."
    fi
}

######################################################################
# Function    : impermanent setting of SELinux status
# Params      : No
# Return      : None
# For example : impermanent::set::selinux::status
######################################################################
impermanent::set::selinux::status()
{
    if which sestatus >/dev/null 2>&1;then
        selinux_status=$(sestatus | grep "SELinux status" | awk -F ' ' '{print$3}')
        if [ "${selinux_status:=X}" = "enabled" ];then
            if which setenforce >/dev/null 2>&1;then
                setenforce 0 || log::warn "SELinux set Failed!"
            else
                log::warn "SELinux is enable!"
            fi
        fi
    else
        log::warn "Unknown SELinux status"
    fi
}


######################################################################
# Function    : Before Exit SMC client , To Delete client old tools
# Params      : pid_exe
# Return      : None
# For example : exit::client::progress
######################################################################
exit::client::progress()
{
    if [[ "${#pid_exe[@]}" -ne 0 ]]; then
        for pid_path in ${pid_exe[@]}
        do
            [[ -f ${pid_path} ]] && eval "${pid_path} --abort"
            [[ ! -e ${pid_path} ]] && killall go2aliyun_client
        done
    fi

    if [[ "${#pid_exe[@]}" -ne 0 ]]; then
        log::warn "The Client Tools Progress Had Exit."
    fi
}

######################################################################
# Function          : Backup File
# Params            : No
# Set Global Params : smc_backup_file_list , backup_path
# Return            : None
# For example       : file::backup
######################################################################
file::backup()
{
    if [[ "${exclude}" == "True" ]]; then
        log::info "The Backup Starting."
        if [[ -d "${client_path}" ]]; then
            log::info "The Backup Path Is [${client_path}]."
        else
            log::warn "The Backup Path Not Exist [${client_path}]."
            return 0
        fi
        
        mkdir -p ${backup_path}
        log::info "The Backup File Save Path Is [${backup_path}]."
        
        local index=0
        for need_backup_file in ${BACKUP_LIST[@]}
        do
            local backup_file=$(find ${client_path} -name "${need_backup_file}" 2>/dev/null)
            if [[ -z "${backup_file}" ]]; then
                log::warn "The Client Tools Config ${need_backup_file} Not Found , So Non-Backup."
            else
                if rsync -topg ${backup_file} ${backup_path} >/dev/null 2>&1; then
                    log::info "The ${backup_file} Backup Successfully."
                    smc_backup_file_list[index]=${backup_file}
                    ((index++))
                else
                    if [[ "${force_update}" == "False" ]]; then
                        log::warn "The ${backup_file} Backup Failed."
                    else
                        log::error "The ${backup_file} Backup Failed , Please To Check."
                    fi
                fi
            fi
        done
        log::info "The Backup Finished."
    else
        log::info "The Exclude Mode Is False , So Anything To Backup."
    fi
    
    return 0
}

######################################################################
# Function          : Copy File
# Params            : No
# Use Global Params : smc_backup_file_list , backup_path
# Return            : None
# For example       : file::copy
######################################################################
file::copy()
{
    if [[ "${exclude}" == "False" ]]; then
        if [[ -d "${client_path}" ]]; then
            log::info "The Reduction Backup Path Is [${client_path}]."
        else
            log::warn "The Reduction Backup Path Not Exist [${client_path}]."
            return 0
        fi
        log::info "The Reduction Starting..."
        for copy_file in ${smc_backup_file_list[@]}
        do
            local to_path=$(dirname "${copy_file}")
            local file_name=$(basename "${copy_file}")
            if rsync -topg ${backup_path}/${file_name} ${to_path} >/dev/null 2>&1; then
                log::info "The ${file_name} Move To ${to_path} Successfully."
                smc_backup_file_list[index]=${backup_file}
                ((index++))
            else
                if [[ "${force_update}" == "False" ]]; then
                    log::warn "The ${file_name} Move To ${to_path} Failed."
                else
                    log::error "The ${file_name} Move To ${to_path} Failed , Please To Check."
                fi
            fi
        done
        log::info "The Reduction Finished."
    else
        log::info "The Exclude Mode Is True , So Anything To Reduction."
    fi
    
    return 0
}

######################################################################
# Function    : Delete client old tools
# Params      : No
# Return      : None
# For example : delete::client::tools
######################################################################
delete::client::tools()
{
    if [[ "${TOOL_DIR_NAME:=X}" == "X" ]]; then
        log::error "The Client Tools Path Not Exist , Please To Check."
    fi
    
    if [[ "${force_update}" == "False" && "${update_mode}" == "optional" ]]; then
        echo "****************************************************************"
        echo "Whether To Forcibly Delete The SMC Client Tools ? "
        read -t 30 -p "Please Enter yes Or no , Simplify [y/n]: " input_status
        if [[ -z "${input_status}" ]]; then
            echo -e "\nYou No Enter Information , Default Non-update."
            local input_status="no"
        else
            local input_status=${input_status}
            echo "Your Enter Is ${input_status}."
        fi
        echo "****************************************************************"
        
        case ${input_status} in
            "yes"|"Yes"|"YES"|"y"|"Y")
                get::client::progress
                exit::client::progress
                file::backup
                if [[ -e ${install_path} ]]; then
                    local delete_path=$(find ${install_path}/ -name "${TOOL_DIR_NAME}.tar.gz" 2>/dev/null)
                    if [[ -n "${delete_path}" ]]; then
                        for delete_source in ${delete_path}
                        do
                            rm -rf ${delete_source}
                            log::info "Delete SMC Client Tools Package Successfully.[${delete_source}]"
                        done
                    else
                        log::warn "Non-Source SMC Client Tools Package To Delete."
                    fi
                fi
                ;;
            "no"|"No"|"NO"|"n"|"N")
                get::client::progress
                local no_delete_path=$(find ${install_path}/ -name "${TOOL_DIR_NAME}.tar.gz" 2>/dev/null)
                if [[ -n "${no_delete_path}" ]]; then
                    for no_delete_source in ${no_delete_path}
                    do
                        mv ${no_delete_source} ${no_delete_source}.$(date +%s)
                    done
                fi
                log::info "Non-Delete The Client Tools."
                ;;
            *)
                log::error "Your Enter Is Invalid Parameter , Please To Check."
                ;;
        esac
    else
        get::client::progress
        exit::client::progress
        if [[ -e ${install_path} ]]; then
            if [[ -d "${client_path}" ]]; then
                file::backup
            else
                log::info "The Client Tools Not Exist , No Anything To Backup."
            fi
            local delete_path=$(find ${install_path}/ -name "${TOOL_DIR_NAME}.tar.gz" 2>/dev/null)
            if [[ -n "${delete_path}" ]]; then
                for delete_source in ${delete_path}
                do
                    rm -rf ${delete_source}
                    log::info "Delete SMC Client Tools Package Successfully.[${delete_source}]"
                done
            else
                log::warn "Non-Source SMC Client Tools Package To Delete."
            fi
        fi
    fi 
}

######################################################################
# Function           : Get tools directory structure
# Clobal Params      : No
# Return             : None
# For example        : tools::directory::structure "${client_path}"
######################################################################
tools::directory::structure()
{
    local src_dir=$1
    local dst_dir=$2
    for var in $(ls ${src_dir})
    do
        if [[ -d "${src_dir}/${var}" ]]; then
            [[ ! -d ${dst_dir}/${var} ]] || mkdir -p ${dst_dir}/${var}
            tools::directory::structure "${src_dir}/${var}" "${dst_dir}/${var}"
        else
            if rsync -topgr ${src_dir}/${var} ${dst_dir} >/dev/null 2>&1; then
                log::info "Update ${dst_dir}/${var} * successfully."
            else
                log::error "Update ${dst_dir}/${var} * failed, pls to check."
            fi
        fi
    done
}

######################################################################
# Function           : Download client tools
# Clobal Params      : dload_dir_url,install_path
# Return             : None
# For example        : download::client::tools
######################################################################
download::client::tools()
{
    log::info "The Install Path Is ${install_path}"
    
    if ! wget -c -t3 -T30 "${dload_dir_url}" -O "${install_path}/${TOOL_DIR_NAME}.tar.gz" >/dev/null 2>&1; then
        log::error "Download SMC Client Tools ${TOOL_DIR_NAME}.tar.gz Failed."
    else
        log::info "Download SMC Client Tools ${TOOL_DIR_NAME}.tar.gz Successfully."
    fi
}

######################################################################
# Function           : Decompress client tools
# Params             : No
# Return             : None
# For example        : decompress::client::tools
######################################################################
decompress::client::tools()
{
    if [[ "${install_path:=X}" == "X" ]]; then
        log::error "Decompress Error , The Install Path Is NULL , Please To Check."
    fi
    
    local client_tar=${install_path}/${TOOL_DIR_NAME}.tar.gz
    
    if [[ -d "${client_path}" ]]; then
        local decompress_path=${install_path}/${tmp_dir}
        mkdir -p ${install_path}/${tmp_dir}
    else
        local decompress_path=${install_path}
    fi
    
    if ! tar xf ${client_tar} -C ${decompress_path}; then
        log::error "Decompress ${TOOL_DIR_NAME}.tar.gz Tools Failed."
    else
        log::info "Decompress ${TOOL_DIR_NAME}.tar.gz Tools Successfully."
    fi
    
    if [[ -d ${install_path}/${tmp_dir} ]]; then
        log::info "The Update File Starting..."
        tools::directory::structure "${install_path}/${tmp_dir}/${LATEST_TOOL_FILE_NAME}" "${install_path}/${LATEST_TOOL_FILE_NAME}"
        log::info "The Update File Finished."
        rm -rf ${install_path}/${tmp_dir}
    fi
    
    if test -f ${client_file}; then
        if chmod +x ${client_file}; then
            log::info "Add Client Tools Executable Permission Successfully."
        else
            log::error "Add Client Tools Executable Permission Failed."
        fi
    else
        log::error "The SMC Client Tools Not Exist. Add Executable Permission Failed."
    fi
}

######################################################################
# Function           : No force update mode Check client tools
# Params             : No
# Return             : 0 or 1
# For example        : check::client::tools
######################################################################
check::client::tools()
{
    if [[ "${install_path:=X}" == "X" ]]; then
        log::error "Check Client Tools Error , The Install Path Is NULL , Please To Check."
    fi

    if ! test -f ${client_file}; then
        log::error "The SMC Client Tools Not Exist , Please To Check."
    fi
}

######################################################################
# Function           : Update client tools entrance
# Params             : update_mode force or non-force
# Return             : None
# For example        : client::update
######################################################################
client::update()
{
    case "${update_mode}" in
        force)
            log::info "Update The Client Tools And Will Delete Old Client Tools."
            delete::client::tools
            download::client::tools
            decompress::client::tools
            ;;
        optional)
            log::info "Update Mode Is Optional And Will Use Old The Client Tools."
            # Check Client Toools
            check::client::tools
    esac
}

######################################################################
# Function           : Only Run client 
# Params             : accesstokenid, accesstokencode or ak, sk
# Return             : None
# For example        : client::only::run
######################################################################
client::only::run()
{
    # check client tools exist or non-exist
    check::client::tools
    
    # exit if client runing
    get::client::progress

    # set SELinux status
    impermanent::set::selinux::status

    log::info "The Client Tools Will Be Running."
    local run_cmd="${client_file} --nocheckversion --noenterkey=yes --rerun"
    if [[ "${accesstokenid:-X}" != "X" && "${accesstokencode:-X}" != "X" ]]; then
        run_cmd="${run_cmd} --accesstokenid=${accesstokenid} --accesstokencode=${accesstokencode}"
    elif [[ "${ak:-X}" != "X" && "${sk:-X}" != "X" ]]; then
        run_cmd="${run_cmd} --accessid=${ak} --secretkey=${sk}"
    fi

    if [[ "${source_id:-X}" != "X" ]];then
        run_cmd="${run_cmd} --sourceid=${source_id}"
    fi
    if [[ "${source_name:-X}" != "X" ]];then
        run_cmd="${run_cmd} --sourcename=${source_name}"
    fi
    if [[ "${background}" == "True" ]]; then
        run_cmd="${run_cmd} --background=always"
    fi
    if [[ "${endpoint:-X}" != "X" ]];then
        run_cmd="${run_cmd} --endpoint=${endpoint}"
    fi

    $run_cmd

    if [[ "${background}" == "True" ]]; then
        # try get source id, max try count 10
        local a=0
        for ((; a<10; a++)) do
            sleep 5s
            if ls ${client_log} >/dev/null; then
                if tail -10 "${client_log}" | grep "Not Finished!"; then
                    local error_msg=""
                    error_msg=$(tail -10 ${client_log} | grep "Error")
                    if [ -z "$error_msg" ]; then
                        error_msg="Goto Aliyun Not Finished!"
                    fi
                    log::error "SMC Client Run Error: ${error_msg}"
                fi

                if grep -qE "Import Source Server \[s-" ${client_log}; then
                    source_id=$(grep -E "Import Source Server \[s-" ${client_log} | tail -1 | grep -oE "s-[a-z0-9]+")
                    echo -e "$source_id"
                    exit 0
                fi
            fi
        done
    fi
}

######################################################################
# Function           : Auto Run client 
# Params             : accesstokenid, accesstokencode or ak, sk
# Return             : None
# For example        : client::auto::run
######################################################################
client::auto::run()
{
    # check system enviroment
    install::deps::platforms
    
    # choice client update mode
    choice::update::mode
    
    # update client tools
    client::update::mode "${input_status}"
    client::update

    # set SELinux status
    impermanent::set::selinux::status

    LATEST_TOOL_FILE_NAME=$(echo ${install_path}/go2aliyun_client*_linux_${architure}|awk -F/ '{print $NF}')
    client_file=${install_path}/${LATEST_TOOL_FILE_NAME}/${TOOL_FILE_NAME}
    client_path=${install_path}/${LATEST_TOOL_FILE_NAME}
    run_date=`date "+%Y%m%d"`
    client_log=${install_path}/${LATEST_TOOL_FILE_NAME}/Logs/${TOOL_FILE_NAME}_${run_date}.log

    # use backup file
    file::copy

    # runing client
    log::info "The Client Tools Will Be Running."
    local run_cmd="${client_file} --nocheckversion --noenterkey=yes --rerun"
    if [[ "${accesstokenid:-X}" != "X" && "${accesstokencode:-X}" != "X" ]]; then
        run_cmd="${run_cmd} --accesstokenid=${accesstokenid} --accesstokencode=${accesstokencode}"
    elif [[ "${ak:-X}" != "X" && "${sk:-X}" != "X" ]]; then
        run_cmd="${run_cmd} --accessid=${ak} --secretkey=${sk}"
    fi

    if [[ "${source_id:-X}" != "X" ]];then
        run_cmd="${run_cmd} --sourceid=${source_id}"
    fi
    if [[ "${source_name:-X}" != "X" ]];then
        run_cmd="${run_cmd} --sourcename=${source_name}"
    fi
    if [[ "${background}" == "True" ]]; then
        run_cmd="${run_cmd} --background=always"
    fi
    if [[ "${endpoint:-X}" != "X" ]];then
        run_cmd="${run_cmd} --endpoint=${endpoint}"
    fi

    $run_cmd

    if [[ "${background}" == "True" ]]; then
        # try get source id, max try count 10
        local a=0
        for ((; a<10; a++)) do
            sleep 5s
            if ls ${client_log} >/dev/null; then
                if tail -10 "${client_log}" | grep "Not Finished!"; then
                    local error_msg=""
                    error_msg=$(tail -10 ${client_log} | grep "Error")
                    if [ -z "$error_msg" ]; then
                        error_msg="Goto Aliyun Not Finished!"
                    fi
                    log::error "SMC Client Run Error: ${error_msg}"
                fi

                if grep -qE "Import Source Server \[s-" ${client_log}; then
                    source_id=$(grep -E "Import Source Server \[s-" ${client_log} | tail -1 | grep -oE "s-[a-z0-9]+")
                    echo -e "$source_id"
                    exit 0
                fi
            fi
        done
    fi
}

######################################################################
# Function    : Check Script Parameter
# Params      : No
# Return      : None
# For example : check::script::parameter
######################################################################
check::script::parameter()
{   
    echo "***********************************************************************"
    echo "* Script Parameter Information                                         "
    echo "* install_path = ${install_path}                                       "

    if [[ "${accesstokenid:-X}" != "X" ]]; then
        echo "* accesstokenid = ${accesstokenid:+"*********************"}        "
    else
        echo "* accesstokenid = ${accesstokenid:-NULL}                           "
    fi
    
    if [[ "${accesstokencode:-X}" != "X" ]]; then
        echo "* accesstokencode = ${accesstokencode:+"*********************"}    "
    else
        echo "* accesstokencode = ${accesstokencode:-NULL}                       "
    fi

    if [[ "${ak:-X}" != "X" ]]; then
        echo "* ak = ${ak:+"*********************"}                              "
    else
        echo "* ak = ${ak:-NULL}                                                 "
    fi
    
    if [[ "${sk:-X}" != "X" ]]; then
        echo "* sk = ${sk:+"*********************"}                              "
    else
        echo "* sk = ${sk:-NULL}                                                 "
    fi
 
    echo "* force_update = ${force_update}                                       "
    echo "* exclude = ${exclude}                                                 "
    echo "* log = ${log_file}                                                    "
    # echo "* version = ${VERSION}                                               "
    echo "***********************************************************************"
}

######################################################################
# Function           : Auto Run client 
# Params             : NO
# Return             : None
# For example        : auto::run
######################################################################
auto::run()
{
    check::script::parameter
    client::auto::run
}

######################################################################
# Function           : check kernel version
# Params             : NO
# Return             : None
# For example        : check::kernel::version
######################################################################
check::kernel::version()
{
    kernel_v=$(uname -r | awk -F . '{print $1}')
    if [ "$architure"X = "x86_64"X ];then
        for i in issue os-release issue.net centos-release redhat-release;do
            if [ -f /etc/$i ];then
                if grep -q "Ubuntu" /etc/$i; then
                    if [ "$kernel_v" -ge 5 ];then
                        TOOL_DIR_NAME=go2aliyun_client_new_linux_${architure}
                    else
                        TOOL_DIR_NAME=go2aliyun_client_linux_${architure}
                    fi
                    return 0
                else
                    if [ "$kernel_v" -ge 4 ];then
                        TOOL_DIR_NAME=go2aliyun_client_new_linux_${architure}
                    else
                        TOOL_DIR_NAME=go2aliyun_client_linux_${architure}
                    fi
                    return 0
                fi
            fi
        done
    else
        TOOL_DIR_NAME=go2aliyun_client_linux_${architure}
    fi
}

######################################################################
# Function    : Set global parameter
# Params      : $@
# Return      : None
# For example : set::global::parameter "$@"
######################################################################
set::global::parameter()
{
    # get system architure
    get::system::architure
    
    while [[ -n "$1" ]]
    do
        local key=${1%=*}
        local value=${1#*=}
        case "${key}" in
            -i|--install_path)
                local length=${#value}
                ((length--))
                if [[ "${value:${length}}" == "/" ]]; then
                    install_path=${value:0:${length}}
                else
                    install_path=${value}
                fi
                ;;
            --accesstokenid)
                accesstokenid=${value}
                ;;
            --accesstokencode)
                accesstokencode=${value}
                ;;
            --ak)
                ak=${value}
                ;;
            --sk)
                sk=${value}
                ;;
            --endpoint)
                endpoint=${value}
                ;;
            --background)
                case ${value} in
                    "True"|"true")
                        background=True
                        ;;
                    "False"|"false")
                        background=False
                        ;;
                    *)
                        log::error "The background Value Is Error ,  Your Entry ${value} , Please To Entry True Or False."
                        ;;
                esac
                ;;
            --reportstatus)
                case ${value} in
                    "True"|"true")
                        reportstatus=True
                        ;;
                    "False"|"false")
                        reportstatus=False
                        ;;
                    *)
                        log::error "The reportstatus Value Is Error ,  Your Entry ${value} , Please To Entry True Or False."
                        ;;
                esac
                ;;
            -f|--force_update)
                case ${value} in
                    "True"|"true")
                        force_update=True
                        ;;
                    "False"|"false")
                        force_update=False
                        ;;
                    *)
                        log::error "The force_update Value Is Error ,  Your Entry ${value} , Please To Entry True Or False."
                        ;;
                esac
                ;;
            --exclude)
                case ${value} in
                    "True"|"true")
                        exclude=True
                        ;;
                    "False"|"false")
                        exclude=False
                        ;;
                    *)
                        log::error "The exclude Value Is Error ,  Your Entry ${value} , Please To Entry True Or False."
                        ;;
                esac
                ;;
            -v|--version)
                VERSION=${value}
                ;;
            --log_path)
                local length=${#value}
                ((length--))
                if [[ "${value:${length}}" == "/" ]]; then
                    local log_path=${value:0:${length}}
                else
                    local log_path=${value}
                fi
                test -d "${log_path}" || mkdir -p "${log_path}"
                log_file=${log_path}/smc_tools.log
                ;;
            --sourceid)
                source_id=${value}
                ;;
            --sourcename)
                source_name=${value}
                ;;
        esac
        shift
    done
    log_file=${log_file:=${DEFAULT_LOG_PATH}}
    test -d $(dirname "${log_path}") || mkdir -p $(dirname "${log_path}")
    install_path=${install_path:=${DEFAULT_INSTALL_PATH}}
    test -d "${install_path}" || mkdir -p "${install_path}"
    force_update=${force_update:=True}
    exclude=${exclude:=True}
    check::kernel::version
    LATEST_TOOL_FILE_NAME=$(echo ${install_path}/go2aliyun_client*_linux_${architure}|awk -F/ '{print $NF}')
    TOOL_FILE_NAME=go2aliyun_client
    client_file=${install_path}/${LATEST_TOOL_FILE_NAME}/${TOOL_FILE_NAME}
    client_path=${install_path}/${LATEST_TOOL_FILE_NAME}
    run_date=`date "+%Y%m%d"`
    client_log=${install_path}/${LATEST_TOOL_FILE_NAME}/Logs/${TOOL_FILE_NAME}_${run_date}.log
    tmp_dir=$(date +%s%N)
    # VERSION=$(echo ${LATEST_TOOL_FILE_NAME} | awk '{match($0,"([0-9]+.[0-9]+.[0-9]+)",version);print version[1]}')
    backup_path="${install_path}/smc_tools_backup_$(date +%Y%m%d)" 
    # Client url
    dload_dir_url="${SMC_CLIENT_URL_ROOT}/${TOOL_DIR_NAME}.tar.gz"
}

######################################################################
# Function    : Entrance interface
# Params      : Interface type,value=[--install_path|--ak|...]
# Return      : None
# For example : main "$@"
######################################################################
main()
{
    set::global::parameter "$@"
    
    if [[ "${BASH_SOURCE[0]}" =~ "/dev" ]]; then
        log::info "The Script[Remote] Parameter No Information."
    else
        log::info "The Script[Local] Parameter No Information."
    fi

    if [[ "${@:-X}" == "X" ]]; then
        if test -f ${client_file}; then
            log::info "The SMC Client Tools Exist, Will Runing With No Update..."
            set -- "--no_update"
        else
            set -- "--auto_run"
        fi
    fi
    
    local index=0
    
    while [[ -n "$1" ]]
    do
        local key=${1%%=*}
        local value=${1#*=}
        case "${key}" in
            -i|--install_path)
                ;;
            --accesstokenid)
                ;;
            --accesstokencode)
                ;;
            --ak)
                ;;
            --sk)
                ;;
            --endpoint)
                ;;
            --background)
                ;;
            --reportstatus)
                ;;
            -f|--force_update)
                ;;
            --log_path)
                ;;
            -v|--version)
                ;;
            --exclude)
                ;;
            --sourceid)
                ;;
            --sourcename)
                ;;
            --delete)
                executes[index]=delete::client::tools
                ((index++))
                ;;
            --download)
                executes[index]=download::client::tools
                ((index++))
                ;;
            --decompress)
                executes[index]=decompress::client::tools
                ((index++))
                ;;
            --auto_run)
                executes[index]=auto::run
                ((index++))
                ;;
            --no_update)
                executes[index]=client::only::run
                ((index++))
                ;;
            -h|--help)
                executes[index]=script::usage
                ((index++))
                ;;
             *)
                log::warn "The $1 Is Not An Option."
                script::usage
                ;;
        esac
        shift
    done
    
    if [[ ${#executes[@]} -ne 0 ]];then
        for execute in ${executes[@]}
        do
            ${execute}
        done
    else
        if test -f ${client_file}; then
            log::info "The SMC Client Tools Exist, Will Only Runing..."
            client::only::run
        else
            log::warn "No Available Executes , Running Default Auto Run."
            auto::run
        fi
    fi
}

# script entrance
main "$@"