096a0e1e18
* [mellanox]: Add SSD FW update tool. Signed-off-by: Nazarii Hnydyn <nazariig@mellanox.com> * [mellanox]: Update SSD tool. Signed-off-by: Nazarii Hnydyn <nazariig@mellanox.com>
728 lines
27 KiB
Bash
Executable File
728 lines
27 KiB
Bash
Executable File
#!/bin/bash
|
|
########################################################################
|
|
# Copyright (c) 2020 Mellanox Technologies. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
# 3. Neither the names of the copyright holders nor the names of its
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# Alternatively, this software may be distributed under the terms of the
|
|
# GNU General Public License ("GPL") version 2 as published by the Free
|
|
# Software Foundation.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
#==============================================================================#
|
|
#= Global variable #
|
|
#=
|
|
#=====
|
|
VERSION="1.3"
|
|
#=====
|
|
SWITCH_SSD_DEV="/dev/sda"
|
|
UTIL_TITLE="This is MLNX SSD firmware update utility to read and write SSD FW. Version ${VERSION}"
|
|
DEPENDECIES=("smartctl" "sha256sum" "tar" "/bin/bash" "gpg" "sed" "realpath" "dirname")
|
|
TRUE="0"
|
|
FALSE="1"
|
|
ERR_MSG="ERR_MSG"
|
|
INI_PREFIX="ini_section_"
|
|
PUBLIC_CERT_NAME="trusted.gpg"
|
|
CHECKSUM_NAME="checksum"
|
|
SCRIPT_MODE="RELESE" # RELESE -or- DEBUG
|
|
DEBUG_MSG="DEBUG" # remove all instance after script is ready.
|
|
#=====
|
|
PKG_EXTRACTED=$FALSE
|
|
LOGGER_UTIL=$FALSE
|
|
SSD_FW_VER=""
|
|
SSD_DEVICE_MODEL=""
|
|
SSD_SERIAL=""
|
|
SSD_SIZE=""
|
|
SECTIONS=()
|
|
#=====
|
|
ARG_IMAGE_FLAG=$FALSE
|
|
ARG_IMAGE_VAL=""
|
|
ARG_QUERY_FLAG=$FALSE
|
|
ARG_YES_FLAG=$FALSE
|
|
ARG_POWER_CYCLE_FLAG=$FALSE
|
|
ARG_HELP_FLAG=$FALSE
|
|
ARG_VERSION_FLAG=$FALSE
|
|
ARG_PACKAGE_INFO_FLAG=$FALSE
|
|
ARG_UPDATE_FLAG=$FALSE
|
|
|
|
|
|
|
|
#==============================================================================#
|
|
#= usage function. #
|
|
#=
|
|
function init_script() {
|
|
# check if logger utility supported
|
|
if [ -x "$(command -v logger)" ]; then
|
|
LOGGER_UTIL=$TRUE
|
|
else
|
|
LOGGER_UTIL=$FALSE
|
|
fi
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= usage function. #
|
|
#=
|
|
function usage() {
|
|
echo
|
|
echo -e "$UTIL_TITLE"
|
|
echo
|
|
echo -e "Usage:"
|
|
echo -e "\tmlnx_ssd_fw_update.sh [OPTION]"
|
|
echo -e "Commands:"
|
|
echo -e "\t-i, --image\t\t Path to SSD FW package"
|
|
echo -e "\t-q, --query\t\t Print SSD information (SSD model, serial number, version and size)"
|
|
echo -e "\t\t\t\t Combined with image, comparison is made if update is required"
|
|
echo -e "\t-p, --package-info\t Get package info"
|
|
echo -e "\t-u, --update\t\t Upgrade firmware"
|
|
echo -e "\t-y --yes\t\t Assume \"yes\" to all questions"
|
|
echo -e "\t-V, --version\t\t Print utility version"
|
|
echo -e "\t-h, --help\t\t Show this usage"
|
|
echo -e "\t --power-cycle\t Execute power cycle at completion, even if not required"
|
|
echo
|
|
echo -e "Example:"
|
|
echo -e "\tmlnx_ssd_fw_update.sh -q"
|
|
echo -e "\tmlnx_ssd_fw_update.sh -q -i mlnx_ssd_fw_package.pkg"
|
|
echo -e "\tmlnx_ssd_fw_update.sh -p -i mlnx_ssd_fw_package.pkg"
|
|
echo -e "\tmlnx_ssd_fw_update.sh -u -i mlnx_ssd_fw_package.pkg"
|
|
echo
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= Log function. #
|
|
#=
|
|
function LOG_MSG() {
|
|
if [ $# -gt 0 ]; then
|
|
LOG_STR=$1
|
|
if [[ $# -eq 1 ]]; then
|
|
[[ "$LOGGER_UTIL" == "$TRUE" && "$LOG_STR" != "" ]] && logger -t mlnx_ssd_fw_update.sh -p user.notice $(echo "$LOG_STR" | sed 's/\\t//g')
|
|
echo -e "$LOG_STR"
|
|
elif [[ $# -eq 2 && "$2" == "$ERR_MSG" ]]; then
|
|
[[ "$LOGGER_UTIL" == "$TRUE" && "$LOG_STR" != "" ]] && logger -t mlnx_ssd_fw_update.sh -p user.err $(echo "$LOG_STR" | sed 's/\\t//g')
|
|
echo -e "$LOG_STR"
|
|
elif [[ $# -eq 2 && "$2" == "$SCRIPT_MODE" ]]; then
|
|
echo -e "DBG: $LOG_STR"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= Log function. #
|
|
#=
|
|
function LOG_MSG_AND_EXIT() {
|
|
LOG_MSG "$@" "$ERR_MSG"
|
|
erase_extract_package "$extraction_path"
|
|
LOG_MSG "Exiting..."
|
|
exit 1
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function check if given argument is valid and return boolean result. #
|
|
#=
|
|
function check_usage() {
|
|
local argument_count=$#
|
|
|
|
LOG_MSG "Number of argument:$argument_count" ${DEBUG_MSG}
|
|
|
|
if [ $# -eq 0 ]; then
|
|
LOG_MSG "Error: false usage given."
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
while [[ $# -gt 0 ]]
|
|
do
|
|
key="$1"
|
|
|
|
case $key in
|
|
-i|--image)
|
|
ARG_IMAGE_FLAG=$TRUE
|
|
ARG_IMAGE_VAL="$2"
|
|
shift # past argument
|
|
shift # past value
|
|
;;
|
|
-q|--query)
|
|
ARG_QUERY_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
-y|--yes)
|
|
ARG_YES_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
-h|--help)
|
|
ARG_HELP_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
-V|--version)
|
|
ARG_VERSION_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
-u|--update)
|
|
ARG_UPDATE_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
-p|--package-info)
|
|
ARG_PACKAGE_INFO_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
--power-cycle)
|
|
ARG_POWER_CYCLE_FLAG=$TRUE
|
|
shift # past argument
|
|
;;
|
|
*)
|
|
LOG_MSG "Error: false usage given."
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ("$ARG_IMAGE_FLAG" == "$TRUE" && ( $argument_count -lt 3 )) ||
|
|
("$ARG_IMAGE_FLAG" == "$TRUE" && ( $argument_count -gt 5 )) ||
|
|
("$ARG_PACKAGE_INFO_FLAG" == "$TRUE" && ( $argument_count -ne 3 )) ||
|
|
("$ARG_QUERY_FLAG" == "$TRUE" && ( $argument_count -lt 1 )) ||
|
|
("$ARG_QUERY_FLAG" == "$TRUE" && ( $argument_count -gt 3 )) ||
|
|
("$ARG_HELP_FLAG" == "$TRUE" && ( $argument_count -gt 1 )) ||
|
|
("$ARG_VERSION_FLAG" == "$TRUE" && ( $argument_count -gt 1 )) ||
|
|
("$ARG_IMAGE_FLAG" == "$TRUE" && "$ARG_IMAGE_VAL" == "") ||
|
|
("$ARG_UPDATE_FLAG" == "$TRUE" && "$ARG_IMAGE_FLAG" == "$FALSE") ||
|
|
("$ARG_PACKAGE_INFO_FLAG" == "$TRUE" && "$ARG_IMAGE_FLAG" == "$FALSE") ||
|
|
("$ARG_POWER_CYCLE_FLAG" == "$TRUE" && "$ARG_UPDATE_FLAG" == "$FALSE") ||
|
|
("$ARG_UPDATE_FLAG" == "$TRUE" && "$ARG_PACKAGE_INFO_FLAG" == "$TRUE") ]]; then
|
|
|
|
LOG_MSG "Error: false usage given."
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
### Debug message remove when script is done.
|
|
LOG_MSG "ARG_IMAGE_FLAG = ${ARG_IMAGE_FLAG}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_IMAGE_VAL = ${ARG_IMAGE_VAL}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_QUERY_FLAG = ${ARG_QUERY_FLAG}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_YES_FLAG = ${ARG_YES_FLAG}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_HELP_FLAG = ${ARG_HELP_FLAG}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_VERSION_FLAG = ${ARG_VERSION_FLAG}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_PACKAGE_INFO_FLAG = ${ARG_PACKAGE_INFO_FLAG}" ${DEBUG_MSG}
|
|
LOG_MSG "ARG_POWER_CYCLE_FLAG = ${ARG_POWER_CYCLE_FLAG}" ${DEBUG_MSG}
|
|
|
|
}
|
|
|
|
#==============================================================================#
|
|
# This function return SSD fw version using hdparm utility #
|
|
#
|
|
function get_ssd_fw_version() {
|
|
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
|
|
|
local device_fw_version
|
|
device_fw_version=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Firmware Version: +\K[^,]+")
|
|
LOG_MSG "device_fw_version: $device_fw_version" ${DEBUG_MSG}
|
|
eval $1='$device_fw_version'
|
|
}
|
|
|
|
#==============================================================================#
|
|
# This function return SSD device model using hdparm utility #
|
|
#
|
|
function get_ssd_device_model() {
|
|
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
|
|
|
local device_model_name
|
|
device_model_name=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Device Model: +\K[^,]+")
|
|
LOG_MSG "device_model_name: $device_model_name" ${DEBUG_MSG}
|
|
eval $1='$device_model_name'
|
|
}
|
|
|
|
#==============================================================================#
|
|
# This function return SSD size using hdparm utility #
|
|
#
|
|
function get_ssd_size() {
|
|
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
|
|
|
local device_size
|
|
device_size=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "User Capacity:.+bytes \[\K[^ ]+")
|
|
LOG_MSG "device_size: $device_size" ${DEBUG_MSG}
|
|
eval $1='$device_size'
|
|
}
|
|
|
|
#==============================================================================#
|
|
# This function return SSD serial using hdparm utility #
|
|
#
|
|
function get_ssd_serial() {
|
|
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
|
|
|
local device_serial
|
|
device_serial=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Serial Number: +\K[^,]+")
|
|
LOG_MSG "device_serial: $device_serial" ${DEBUG_MSG}
|
|
eval $1='$device_serial'
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function check if given argument is valid and return boolean result. #
|
|
#=
|
|
function get_ssd_info() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
get_ssd_fw_version SSD_FW_VER
|
|
get_ssd_device_model SSD_DEVICE_MODEL
|
|
get_ssd_serial SSD_SERIAL
|
|
get_ssd_size SSD_SIZE
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function check if given argument is valid and return boolean result. #
|
|
#=
|
|
function check_tool_dependencies() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
for i in "${!DEPENDECIES[@]}"
|
|
do
|
|
if [ ! -x "$(command -v ${DEPENDECIES[$i]})" ]; then
|
|
LOG_MSG_AND_EXIT "Error: This tool require the following utils to be installed ${DEPENDECIES[$i]}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function parse package ini file and declare it attributes #
|
|
#=
|
|
function ini_parser {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
|
|
local filename="$1"
|
|
LOG_MSG "filename:$filename" ${DEBUG_MSG}
|
|
|
|
shopt -p extglob &> /dev/null
|
|
CHANGE_EXTGLOB=$?
|
|
if [ $CHANGE_EXTGLOB = 1 ]
|
|
then
|
|
shopt -s extglob
|
|
fi
|
|
ini="$(<$filename)" # read the file
|
|
ini=${ini//$'\r'/} # remove linefeed i.e dos2unix
|
|
ini="${ini//[/\\[}"
|
|
ini="${ini//]/\\]}"
|
|
IFS=$'\n' && ini=( ${ini} ) # convert to line-array
|
|
ini=( ${ini[*]//\)/\\\)} ) # append / before any parenthesis
|
|
ini=( ${ini[*]//\(/\\\(} ) # append / before any parenthesis
|
|
ini=( ${ini[*]/#*([[:space:]]);*/} )
|
|
ini=( ${ini[*]/#*([[:space:]])\#*/} )
|
|
ini=( ${ini[*]/#+([[:space:]])/} ) # remove init whitespace
|
|
ini=( ${ini[*]/%+([[:space:]])/} ) # remove ending whitespace
|
|
ini=( ${ini[*]/*([[:space:]])=*([[:space:]])/=} ) # remove whitespace around =
|
|
ini=( ${ini[*]/#\\[/\}$'\n'"$INI_PREFIX"} ) # set section prefix
|
|
ini=( ${ini[*]/%\\]/ \(} ) # convert text2function (1)
|
|
ini=( ${ini[*]/=/=\( } ) # convert item to array
|
|
ini=( ${ini[*]/%/ \)} ) # close array parenthesis
|
|
ini=( ${ini[*]/%\\ \)/ \\} ) # the multiline trick
|
|
ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2)
|
|
ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis
|
|
ini=( ${ini[*]/%\{/\{$'\n''ini_unset ${FUNCNAME/#'$INI_PREFIX'}'$'\n'} ) # clean previous definition of section
|
|
ini[0]="" # remove first element
|
|
ini[${#ini[*]} + 1]='}' # add the last brace
|
|
eval "$(echo "${ini[*]}")" # eval the result
|
|
[ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: failed to parse package content."
|
|
SECTIONS="$(echo ${ini[*]} | grep -Po "$INI_PREFIX+\K[\w]+")"
|
|
if [ $CHANGE_EXTGLOB = 1 ]
|
|
then
|
|
shopt -u extglob
|
|
fi
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function unset parse ini section and variables #
|
|
#=
|
|
function ini_unset {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
SECTION=$1
|
|
OLDIFS="$IFS"
|
|
IFS=' '$'\n'
|
|
if [ -z "$SECTION" ]
|
|
then
|
|
fun="$(declare -F)"
|
|
else
|
|
fun="$(declare -F $INI_PREFIX$SECTION)"
|
|
if [ -z "$fun" ]
|
|
then
|
|
echo "section $SECTION not found" 1>&2
|
|
return
|
|
fi
|
|
fi
|
|
fun="${fun//declare -f/}"
|
|
for f in $fun; do
|
|
[ "${f#$INI_PREFIX}" == "${f}" ] && continue
|
|
item="$(declare -f ${f})"
|
|
item="${item##*\{}" # remove function definition
|
|
item="${item##*FUNCNAME*$INI_PREFIX\};}" # remove clear section
|
|
item="${item/\}}" # remove function close
|
|
item="${item%)*}" # remove everything after parenthesis
|
|
item="${item});" # add close parenthesis
|
|
vars=""
|
|
while [ "$item" != "" ]
|
|
do
|
|
newvar="${item%%=*}" # get item name
|
|
vars="$vars $newvar" # add name to collection
|
|
item="${item#*;}" # remove readed line
|
|
done
|
|
for var in $vars; do
|
|
unset $var
|
|
done
|
|
done
|
|
IFS="$OLDIFS"
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function check package signing and returns back true or false #
|
|
#=
|
|
function check_package_signing() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
|
|
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
|
|
|
local package_path=$1
|
|
local checksum_unsigned_file="$package_path/$CHECKSUM_NAME"
|
|
local checksum_signed_file="$package_path/$CHECKSUM_NAME.sig"
|
|
local public_cert_file="$package_path/$PUBLIC_CERT_NAME"
|
|
|
|
### Check if unsigned checksum file exists
|
|
[ ! -f "$checksum_unsigned_file" ] && LOG_MSG_AND_EXIT "Error: fail to find unsigned checksum file to verify package signing."
|
|
|
|
### Check if signed checksum file exists
|
|
[ ! -f "$checksum_signed_file" ] && LOG_MSG_AND_EXIT "Error: fail to find sign checksum file to verify package signing."
|
|
|
|
### Check if public key exists
|
|
[ ! -f "$public_cert_file" ] && LOG_MSG_AND_EXIT "Error: fail to find public certificate to verify package signing."
|
|
|
|
|
|
LOG_MSG "public_cert_file: ${public_cert_file}" ${DEBUG_MSG}
|
|
LOG_MSG "checksum_signed_file: ${checksum_signed_file}" ${DEBUG_MSG}
|
|
LOG_MSG "checksum_unsigned_file: ${checksum_unsigned_file}" ${DEBUG_MSG}
|
|
|
|
gpg --keyring "$public_cert_file" --verify "$checksum_signed_file" "$checksum_unsigned_file" > /dev/null 2>&1
|
|
[ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fault package signing."
|
|
|
|
LOG_MSG "cd into: ${package_path}" ${DEBUG_MSG}
|
|
cd $package_path > /dev/null 2>&1
|
|
sha256sum -c $CHECKSUM_NAME > /dev/null 2>&1
|
|
[ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fault package SHA signing, file has been compromised"
|
|
LOG_MSG "backing back:" ${DEBUG_MSG}
|
|
cd - > /dev/null 2>&1
|
|
LOG_MSG "exiting:" ${DEBUG_MSG}
|
|
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function prints supported SSD from package ini #
|
|
#=
|
|
function string_supported_model() {
|
|
|
|
local section=$1
|
|
|
|
if [[ ! -z "${Vendor[*]}" ]] && [[ ! -z "${SSD_FW_Model[*]}" ]] && [[ ! -z "${SSD_FW_Version[*]}" ]] \
|
|
&& [[ ! -z "${SSD_Size[*]}" ]] && [[ ! -z ${Shutdown_Policy[*]} ]]; then
|
|
printf 'o %-10s | %-30s | %-12s | %-6sGB | %-7s |\n' \
|
|
"$( IFS=$'\n'; echo "${Vendor[@]}" )" "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" \
|
|
"${SSD_FW_Version[@]}" "${SSD_Size[@]}" "${Shutdown_Policy[@],,}"
|
|
fi
|
|
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function extract SSD FW package into /tmp #
|
|
#=
|
|
function extract_package() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
|
|
local filename=$1
|
|
LOG_MSG "filename:$filename" ${DEBUG_MSG}
|
|
### Check if file exists
|
|
[ ! -f $filename ] && LOG_MSG_AND_EXIT "Error: given file ($filename) not found."
|
|
### Check if tmp available
|
|
[ ! -d "/tmp" ] && LOG_MSG_AND_EXIT "Error: directory /tmp DOES NOT exists."
|
|
|
|
local base_filename="${filename##*/}"
|
|
local folder_name="/tmp/""${base_filename%%.*}"
|
|
|
|
### Check if full path available
|
|
if [ -d $folder_name ]; then
|
|
LOG_MSG "Path:$folder_name already exists, removing folder." ${DEBUG_MSG}
|
|
rm -rf ${folder_name}
|
|
[ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: folder:$folder_name is already in use and can't be overwrite, please remove it and retry."
|
|
fi
|
|
|
|
mkdir ${folder_name} && tar xf ${filename} -C ${folder_name} --strip-components 1 --warning=no-timestamp > /dev/null 2>&1
|
|
#tar -xf $filename --directory /tmp/ --warning=no-timestamp > /dev/null 2>&1
|
|
### Check if untar succeed.
|
|
[ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fail to extract given package ($filename)."
|
|
|
|
### return the path file extraction is
|
|
# local base_filename="${filename##*/}"
|
|
# local folder_name="/tmp/""${base_filename%%.*}"
|
|
eval $2="$folder_name"
|
|
|
|
PKG_EXTRACTED=$TRUE
|
|
|
|
check_package_signing $folder_name
|
|
|
|
LOG_MSG "successfully untar file." ${DEBUG_MSG}
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function extract SSD FW package into /tmp #
|
|
#=
|
|
function erase_extract_package() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
|
|
[[ "$PKG_EXTRACTED" == "$FALSE" ]] && return
|
|
|
|
local folder_name=$1
|
|
|
|
LOG_MSG "folder_name: $folder_name" ${DEBUG_MSG}
|
|
|
|
### Check if folder exists
|
|
if [ ! -d "$folder_name" ]; then
|
|
LOG_MSG "Error: directory $folder_name DOES NOT exists." "$ERR_MSG"
|
|
LOG_MSG "Exiting..."
|
|
exit 1
|
|
fi
|
|
rm -rf $folder_name
|
|
### Check if untar succeed.
|
|
if [ $? -ne 0 ]; then
|
|
LOG_MSG "Error: fail to delete $folder_name folder." "$ERR_MSG"
|
|
LOG_MSG "Exiting..."
|
|
exit 1
|
|
fi
|
|
|
|
PKG_EXTRACTED=$FALSE
|
|
LOG_MSG "successfully removed folder:$folder_name" ${DEBUG_MSG}
|
|
}
|
|
|
|
|
|
#==============================================================================#
|
|
#= This function returns back ini section array.
|
|
#=
|
|
function call_ini_section() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
|
|
local ini_section=$1
|
|
LOG_MSG "ini_section:$ini_section" ${DEBUG_MSG}
|
|
|
|
[[ -z "$ini_section" ]] && LOG_MSG_AND_EXIT "Error: given INI section is null."
|
|
[[ -z "$(declare -F "$INI_PREFIX$ini_section")" ]] && LOG_MSG_AND_EXIT "Error: $ini_section section is missing in INI file."
|
|
|
|
eval "$(echo "$INI_PREFIX$ini_section")" # call given section function.
|
|
}
|
|
|
|
#==============================================================================#
|
|
#= This function prints ssd info
|
|
#=
|
|
function print_ssd_info() {
|
|
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
|
|
|
local argument_count=$#
|
|
|
|
if [ $argument_count -eq 2 ]; then
|
|
local newer_fw_version=$1
|
|
local power_policy=$2
|
|
LOG_MSG "Device Model\t\t : $SSD_DEVICE_MODEL"
|
|
LOG_MSG "Serial Number\t\t : $SSD_SERIAL"
|
|
LOG_MSG "User Capacity\t\t : $SSD_SIZE GB"
|
|
LOG_MSG "Current Firmware Version : $SSD_FW_VER"
|
|
LOG_MSG "Available Firmware Version : $Newer_FW_Version"
|
|
LOG_MSG "Power Cycle Required\t : $power_policy"
|
|
LOG_MSG "Upgrade Required\t : yes"
|
|
elif [ $argument_count -eq 1 ]; then
|
|
local _upgrade_require=$1
|
|
LOG_MSG "Device Model\t : $SSD_DEVICE_MODEL"
|
|
LOG_MSG "Serial Number\t : $SSD_SERIAL"
|
|
LOG_MSG "User Capacity\t : $SSD_SIZE GB"
|
|
LOG_MSG "Firmware Version : $SSD_FW_VER"
|
|
LOG_MSG "Upgrade Required : $_upgrade_require"
|
|
else
|
|
LOG_MSG "Device Model\t : $SSD_DEVICE_MODEL"
|
|
LOG_MSG "Serial Number\t : $SSD_SERIAL"
|
|
LOG_MSG "User Capacity\t : $SSD_SIZE GB"
|
|
LOG_MSG "Firmware Version : $SSD_FW_VER"
|
|
fi
|
|
}
|
|
|
|
# Main
|
|
# ------------------------------------------------------------------------------
|
|
init_script
|
|
check_usage "$@"
|
|
|
|
# show help
|
|
if [ $ARG_HELP_FLAG == $TRUE ]; then
|
|
usage
|
|
exit 0
|
|
# show version
|
|
elif [ $ARG_VERSION_FLAG == $TRUE ]; then
|
|
echo $UTIL_TITLE
|
|
exit 0
|
|
# show SSD info
|
|
elif [ $ARG_QUERY_FLAG == $TRUE ]; then
|
|
match_found=$FALSE
|
|
check_tool_dependencies
|
|
get_ssd_info
|
|
|
|
if [ $ARG_IMAGE_FLAG == $TRUE ]; then
|
|
extract_package $ARG_IMAGE_VAL extraction_path
|
|
ini_parser "$extraction_path/list.ini"
|
|
|
|
for section in $SECTIONS; do
|
|
if [[ $section != "main" ]]; then
|
|
call_ini_section $section
|
|
if [[ "$SSD_DEVICE_MODEL" == "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" ]] && \
|
|
[[ "$SSD_FW_VER" == "${SSD_FW_Version[@]}" ]] && \
|
|
[[ "$SSD_SIZE" == "${SSD_Size[@]}" ]]; then
|
|
|
|
match_found=$TRUE
|
|
break
|
|
fi
|
|
ini_unset $section
|
|
fi
|
|
done
|
|
|
|
erase_extract_package "$extraction_path"
|
|
if [[ "$match_found" == "$FALSE" ]]; then
|
|
#LOG_MSG "SSD FW upgrade not require, based on given package latest version is in used."
|
|
print_ssd_info "no"
|
|
echo -e ""
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
if [[ "$match_found" == "$TRUE" ]]; then
|
|
print_ssd_info $Newer_FW_Version ${Shutdown_Policy[0],,}
|
|
erase_extract_package "$extraction_path"
|
|
else
|
|
print_ssd_info
|
|
fi
|
|
|
|
echo -e ""
|
|
|
|
exit 0
|
|
# show package version
|
|
elif [ $ARG_PACKAGE_INFO_FLAG == $TRUE ]; then
|
|
check_tool_dependencies
|
|
extract_package $ARG_IMAGE_VAL extraction_path
|
|
# 2. check signing
|
|
ini_parser "$extraction_path/list.ini"
|
|
|
|
call_ini_section "main"
|
|
LOG_MSG "Package Name: $ARG_IMAGE_VAL"
|
|
[[ ! -z ${description[@]} ]] && LOG_MSG "Description: ${description[@]}"
|
|
[[ ! -z ${version[@]} ]] && LOG_MSG "Version: ${version[@]}"
|
|
[[ ! -z ${release_date[@]} ]] && LOG_MSG "Release Date: ${release_date[@]}"
|
|
LOG_MSG "Supported SSDs:"
|
|
LOG_MSG " Vendor | Model | FW ver | Size | Pwr Cyc Req |"
|
|
LOG_MSG "=============|================================|==============|==========|=============|"
|
|
for section in $SECTIONS; do
|
|
if [[ "$section" != "main" ]]; then
|
|
call_ini_section $section
|
|
supported_model=$(string_supported_model $section)
|
|
LOG_MSG "$supported_model"
|
|
ini_unset $section
|
|
fi
|
|
done
|
|
echo -e ""
|
|
erase_extract_package "$extraction_path"
|
|
exit 0
|
|
# operate SSD fw update
|
|
elif [ $ARG_UPDATE_FLAG == $TRUE ]; then
|
|
check_tool_dependencies
|
|
get_ssd_info
|
|
extract_package $ARG_IMAGE_VAL extraction_path
|
|
# 2. check signing
|
|
UPDATE_DONE=$FALSE
|
|
ini_parser "$extraction_path/list.ini"
|
|
for section in $SECTIONS; do
|
|
if [[ $section != "main" ]]; then
|
|
call_ini_section $section
|
|
if [[ "$SSD_DEVICE_MODEL" == "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" ]] && \
|
|
[[ "$SSD_FW_VER" == "${SSD_FW_Version[@]}" ]] && \
|
|
[[ "$SSD_SIZE" == "${SSD_Size[@]}" ]]; then
|
|
UPDATE_DONE=$TRUE
|
|
|
|
power_policy=${Shutdown_Policy[0],,}
|
|
LOG_MSG "Power policy:$power_policy" ${DEBUG_MSG}
|
|
print_ssd_info $Newer_FW_Version ${Shutdown_Policy[0],,}
|
|
echo -e ""
|
|
#[[ "yes" == "$power_policy" ]] && LOG_MSG "PLEASE NOTE: System will power-cycle automatically once SSD FW Update complete!"
|
|
[[ "yes" == "$power_policy" || "$ARG_POWER_CYCLE_FLAG" == "$TRUE" ]] && LOG_MSG "Please note: Once SSD FW Update process ends, system will power-cycle automaticly and it will take up to 1 minute to access it back."
|
|
|
|
# Prompt approval for FW update if ignore in case "yes" flag is on.
|
|
if [[ "$ARG_YES_FLAG" == "$FALSE" ]]; then
|
|
read -p "Do you want to continue? [Y/N]" -n 1 -r
|
|
echo # (optional) move to a new line
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
LOG_MSG_AND_EXIT "Aborting..."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Check FWUpgrade scripts exists & if so call it.
|
|
ssd_script_name=$Update_Script
|
|
ssd_script_path="${extraction_path}/${section}/${ssd_script_name}"
|
|
LOG_MSG "ssd_script_path: $ssd_script_path" ${DEBUG_MSG}
|
|
if [ ! -f $ssd_script_path ]; then
|
|
LOG_MSG_AND_EXIT "Error: fail to call upgrade script ($ssd_script_path)!"
|
|
fi
|
|
(
|
|
cd "${extraction_path}/${section}" > /dev/null 2>&1 || exit
|
|
/bin/bash "$ssd_script_path" "${extraction_path}/${section}"
|
|
#cd - > /dev/null 2>&1 || exit
|
|
)
|
|
if [ $? -ne 0 ]; then
|
|
LOG_MSG_AND_EXIT "Error: SSD FW update failed."
|
|
else
|
|
LOG_MSG "SSD FW update completed successfully."
|
|
|
|
if [ $ARG_POWER_CYCLE_FLAG == $TRUE ]; then
|
|
LOG_MSG "Execute power cycle..."
|
|
sleep 1
|
|
sync
|
|
power_cycle_script="${extraction_path}/common/mlnx_shutdown.sh"
|
|
[ ! -f $power_cycle_script ]&& LOG_MSG_AND_EXIT "Error: failed to initiate power cycle."
|
|
($power_cycle_script "-s")
|
|
[ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: failed to power cycle the system automatically."
|
|
erase_extract_package "$extraction_path"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
break # Exit the for loop
|
|
fi
|
|
ini_unset $section
|
|
fi
|
|
done
|
|
if [ $UPDATE_DONE == $FALSE ]; then
|
|
LOG_MSG "SSD FW upgrade not require, based on given package latest version is in used."
|
|
print_ssd_info "no"
|
|
fi
|
|
|
|
echo -e ""
|
|
erase_extract_package "$extraction_path"
|
|
exit 0
|
|
fi
|
|
|
|
exit 0
|