#!/usr/bin/env sh
# set -x

# Covert all upper case character to lower case characters.
upperToLower() {
  lowercase=$(echo $1 | awk 'BEGIN { getline; print $1=tolower($1) }')
}

_LOGFILE="/var/cpq/MR_Component.log"

# Return codes
SUCCESS_NO_REBOOT=0
SUCCESS_WITH_REBOOT=1
VERSION_MATCH=2
INSTALL_NOT_ATTEMPTED=3
INSTALL_FAILED=7

# Variables
SC_RESULT_FAIL=0
SC_RESULT_PASS=0
COUNT=0
discoveryFlag=0
forceFlag=0
silentFlag=0
downgradeFlag=0
rewriteFlag=0

ARGUS=$@
NARGS=$#
_VER=
_REV=
_COMP=
_DESCRIPT=
_FILENAME=
_COMPVERBOSE=

#parseCmdArgs() {
#echo "parseCmdArgs"
for arg in "$@"
do
    case $arg in
        -s|--silent)
            silentFlag=1
            #echo "silent flag enabled"
            shift
        ;;
        -f|--force)
            forceFlag=1
            #echo "force flag enabled"
            shift
        ;;
        -g|--downgrade)
            downgradeFlag=1
            echo "downgrade flag enabled"
            shift
        ;;
        -e|--rewrite)
            rewriteFlag=1
            echo "rewrite flag enabled"
            shift
        ;;
        -h|--help)
            shift
		;;
        --unpack)
            shift
		;;
        --version)            
            shift
		;;
        --interface)            
            shift
		;;
        --inventory)            
            shift				
		;;
        -d|--discovery)
            discoveryFlag=1
            xmlFile="$2"
            #echo "Discovery flag enabled"
            #echo "Discovery file Path: $xmlFile"
            shift
        ;;
        --default)
          echo "Invalid argument: $1"
        ;;
    esac
done

#}

# Write information to stdout and the log file.
output_CmpLog() {
  if [ 1 -eq $silentFlag ]; then
    echo "$1" >> $_LOGFILE
  else
    echo "$1" | tee -a $_LOGFILE
  fi
}

# Write information to discovery xml file.
printXML() {
  if [ ! -x $1 ]; then
    #echo -e $1 "$2" | tee -a $xmlFile
    echo -e $1 "$2" >> $xmlFile
  else
    #echo "$2" | tee -a $xmlFile
    echo "$2" >> $xmlFile
  fi
}

file="unknown"
# Search the specified directory (i.e. $1) for a specific file or file type (i.e. $2).
directory_listing() {
  local TMP=./tmpfile.txt
  local JUNK
  file=""
  file=$(find "$1" -type f -iname "$2" | sed -e 's/^\.\///' 2> /dev/null)  
  number_of_files=$(echo $file | awk ' { print split($0, ARRAY_OF_FILES, "[[:space:]]+") } ')
  # Verify that the file variable is not an empty string.
  if [ 0 -eq $number_of_files ]; then
    output_CmpLog "Error: Could not find any Smart Component XML file, please install at least one Smart Component package and re-run the script."
    output_CmpLog "Script Exiting."
    output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
    exit $INSTALL_NOT_ATTEMPTED
  fi
  #_VER=`grep \<version $file|awk -F = '{print $2}'|awk '{print $1}'|tr -d '"'`
  #echo `grep \<version $file|awk -F = '{print $2}'|awk '{print $1}'|tr -d '"'` > $TMP
  echo `grep \<version $file|awk -F = '{print $2}'|awk '{gsub(/"/, "", $1); print $1}'` > $TMP
  read _VER JUNK < $TMP
  #_COMP=`grep \<filename\> $file|awk -F '>' '{print $2}'|awk -F '<' '{print $1}'|tr -d '"'`
  _COMP=`grep \<filename\> $file|awk -F '>' '{print $2}'|awk -F '<' '{gsub(/"/, "", $1); print $1}'`
  _DESCRIPT=`grep \<alt_name_xlate\ lang\=\"en\" $file|awk -F '>' '{print $2}'|awk -F '<' '{print $1}'|sed -e 's/\"//g'|tail -n 1`
  _FILENAME="${_COMP%.*}"
  _SWKEY=`grep \<sw_key\ guid\=\"\" $file|awk -F '>' '{print $1}' |awk -F 'name=' '{print $2}'|sed -e 's/\"//g'|tail -n 1`
  output_CmpLog "SWKEY: $_SWKEY"
  
  output_CmpLog "Run with $NARGS Command Arguments(s): $ARGUS"
  output_CmpLog ""
  output_CmpLog "$_COMP - $_DESCRIPT"
  output_CmpLog "    Component Version: $_VER"
}

# Check to see if the package installed successfully.
didPackageInstall() {
   upperToLower "$1"
   if echo "$results" | grep -w -q 'error\|fail'; then
     output_CmpLog "Error: The $package failed to install!"
     output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
     exit $INSTALL_NOT_ATTEMPTED
   fi
}

getOSPlatform() {
#echo "getOSPlatform"
# Determine what type of OS platform the script is running on and Storcli packages installation.
if [[ -f "/etc/redhat-release" || -f "/etc/SuSE-release" || -f "/etc/SUSE-brand" ]]; then
  output_CmpLog "Info: You are running on an RPM based distribution!"
  RPMNAME=storcli-*.noarch.rpm
  #chmod +x ${RPMNAME}
  if ! rpm -qa | grep storclio; then	
    rpm_install=$(rpm -ivh --replacepkgs --replacefiles "$RPMNAME" 2> /dev/null)    
    didPackageInstall $rpm_install
    output_CmpLog "Storcli rpm installation completed."
  else    
    rpm_install=$(rpm -Uvh --replacepkgs --replacefiles "$RPMNAME" 2> /dev/null)  
    didPackageInstall $rpm_install
    output_CmpLog "${RPMNAME} installation done."
  fi
elif [ -f "/etc/debian_version" ]; then
  output_CmpLog "Info: You are running on an Debian based distribution!"
  DEBNAME=storcli_*.deb
  #chmod +x ${DEBNAME}  
  sudo dpkg -i --force-architecture ${DEBNAME}
else
  output_CmpLog "Info: You are running on a VMWare distribution!"
  #esxcli software vib list
  vibname=`find $PWD -type f -iname "vmware-esx-storcli*.vib"`  
  esxcli software vib install -v="$vibname" --no-sig-check    
fi
}

getCmpXML() {
  directory_listing "." "[cC][Pp]0*.xml"
}

# This function Check to see if the file is readable.
isFileReadable() {
  #echo "isFileReadable"
  if [ ! -r $1 ]; then
    output_CmpLog "Error: $1 file is not readable, please make the file readable and re-run the script."
    output_CmpLog "Script exiting."
    output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
    exit $INSTALL_NOT_ATTEMPTED
  fi
}

locateStorcli() {
#echo "locateStorcli"
# Locate where the storcli utility is installed.
# Once the installation directory is found, split the string containing the filenames into an array.
# Determine what type of OS platform the script is running on and Storcli packages installation.
if [[ -f "/etc/redhat-release" || -f "/etc/SuSE-release" || -f "/etc/SUSE-brand" || -f "/etc/debian_version" ]]; then
#storcli_array=$(find /opt/MegaRAID/ -type f \( -name "storcli64" -o -name "storclio64" -o -name "storcli" \) 2> /dev/null)
  storcli=""
  if [[ -f "/opt/MegaRAID/storcli/storcli64" ]]; then
    storcli="/opt/MegaRAID/storcli/storcli64"
  elif [[ -f "/opt/MegaRAID/storcli/storcli" ]]; then
    storcli="/opt/MegaRAID/storcli/storcli"
  elif [[ -f "/opt/MegaRAID/storclio/storclio64" ]]; then
    storcli="/opt/MegaRAID/storclio/storclio64"
  else
    storcli=""
  fi
else
#storcli_array=$(find /opt/lsi/ -type f \( -name "storcli64" -o -name "storclio64" -o -name "storcli" \) 2> /dev/null)
  storcli=""
  if [[ -f "/opt/lsi/storcli/storcli64" ]]; then
    storcli="/opt/lsi/storcli/storcli64"
  elif [[ -f "/opt/lsi/storcli/storcli" ]]; then
    storcli="/opt/lsi/storcli/storcli"
  elif [[ -f "/opt/lsi/storclio/storclio64" ]]; then
    storcli="/opt/lsi/storclio/storclio64"
  else
    storcli=""
  fi
fi

# Verify that the variable contains an executable file.
if [ ! -x "$storcli" ]; then
  output_CmpLog "Error: Cannot find the storcli utility, please install either the storcli or storcli64 utility."
  output_CmpLog "Script Exiting."
  output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
  exit $INSTALL_NOT_ATTEMPTED
fi
}

getCtrlCnt() {
#echo "getCtrlCnt"
# Find the number of supported controllers.
controller_count=$("$storcli" show ctrlcount)
# Verify that at least one supported controller is installed in the server.
num_controllers=$(echo $controller_count | grep -o -E '[0-9]+' | tail -1)
if [ 0 -eq $num_controllers ]; then

  if [ 1 -eq $discoveryFlag ]; then
    printXML "" "<hp_rom_discovery version=\"2.0.2.0\">"
    printXML '\t' "<type value=\"firmware:sd:sasexpander\" />"
    printXML '\t' "<alt_name value=\"$_DESCRIPT\" />"
    printXML '\t' "<version value=\"$xml_file_firmware_version\" />"
    printXML '\t' "<takes_effect value=\"deferred\" />"
    printXML '\t' "<devices>"
    printXML '\t' "</devices>"
    printXML "" "</hp_rom_discovery>"
    exit $INSTALL_NOT_ATTEMPTED
  fi

  output_CmpLog "Error: No supported controllers found."
  output_CmpLog "Script exiting."
  output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
  exit $INSTALL_NOT_ATTEMPTED
fi

# Total number of supported controllers found.
output_CmpLog "Number of controllers found: $num_controllers"
}

getEIDs() {
  attached_EIDS=$("$storcli" /c"$controller_id"/eall show | grep [0-9] | grep -v '=' | awk '{print $1}')
  # Verify that the variable is not empty.
  if [ -z "$attached_EIDS" ]; then
    output "Warning: No drives are connected to the controller in slot $controller_slot_number"
    no_drive_found=true
  fi
}

# Get the target controller's firmware version.
getControllerFirmwareVersion() {
   ctrl_firmware_version=$("$storcli" /c"$controller_id" show | grep 'FW Package Build =' | awk '{print $5;exit;}')   
   # Verify that the variable is not empty.
   if [ -z $ctrl_firmware_version ]; then
     output_CmpLog "Error: Could not obtain the current firmware version for $target"
	 exit $INSTALL_FAILED
   fi
}

# Get the target controller's firmware version.
getExpanderFirmwareVersion() {
   exp_info_all=$("$storcli" /c"$controller_id"/e"$EID" show all)
   exp_firmware_version=$(echo "$exp_info_all" | grep 'Firmware Version =' | awk '{print $4}')
   # Verify that the variable is not empty.
   if [ -z $exp_firmware_version ]; then
     output_CmpLog "Error: Could not obtain the current Expander firmware version for $target"
	 exit $INSTALL_FAILED
   fi
}

# Get the target controller's firmware version.
getExpanderProductName() {
   exp_info_all=$("$storcli" /c"$controller_id"/e"$EID" show all)
   #exp_product_name1=$(echo "$exp_info_all" | grep 'Name =' | awk '{print $3}')
   #exp_product_name2=$(echo "$exp_info_all" | grep 'Name =' | awk '{print $4}')
   exp_product_name=$(echo "$exp_info_all" | grep 'Name =' | sed 's/Name = //')
   #exp_product_name="$exp_product_name1 $exp_product_name2"
   output_CmpLog "Enclosure $EID: $exp_product_name"
   # Verify that the variable is not empty.
   if [ -z "$exp_product_name" ]; then
     output_CmpLog "Error: Could not obtain the current Expander product name for $target"
	 exit $INSTALL_FAILED
   fi
}

# Discover the devices
deviceDiscovery() {
  if [ 1 -eq $discoveryFlag ]; then  
    output_CmpLog "Generating discovery file at $xmlFile"
    printXML "" "<hp_rom_discovery version=\"2.0.2.0\">"
    printXML '\t' "<type value=\"firmware:sd:sasexpander\" />"
    printXML '\t' "<alt_name value=\"$_DESCRIPT\" />"
    printXML '\t' "<version value=\"$xml_file_firmware_version\" />"
    printXML '\t' "<takes_effect value=\"deferred\" />"
    printXML '\t' "<devices>"
  fi
  # The following while loop iterates over each supported attached controller.
  controller_id=0
  while [ "$controller_id" -le $(($num_controllers-1)) ]
  do
    output_CmpLog "The controller ID is: $controller_id"    
    ctrl_model_name=$("$storcli" /c"$controller_id" show | grep 'Product Name =' | awk '{print $4, $5, $6, $7, $8, $9}')
    output_CmpLog "Controller model: $ctrl_model_name"
    target="$ctrl_model_name"
	# Get the Sub Vendor id and Device id information that is currently on the controller.
	SubVendor_Id=$("$storcli" /c"$controller_id" show | grep 'SubVendor Id =' | awk '{print $4}')
	SubDevice_Id=$("$storcli" /c"$controller_id" show | grep 'SubDevice Id =' | awk '{print $4}')
	if [[ "$SubVendor_Id" == "0x1590" && "$SubDevice_Id" == "0x22C" ]]; then
	  getEIDs
	  for EID in $attached_EIDS
	  do
            # Get the version of firmware that is currently on the controller.
            #getControllerFirmwareVersion
	    getExpanderFirmwareVersion
            getExpanderProductName
            `echo "$_SWKEY" | grep -q "$getExpanderProductName"`
            KEYOUT=$?
            #echo $CMDOUT
            if  [ $KEYOUT -eq 0 ]; then
	      if [ "$exp_firmware_version" \< "$xml_file_firmware_version" ]; then
                perform_action="upgrade"     
              elif [ "$exp_firmware_version" \> "$xml_file_firmware_version" ]; then     
                perform_action="downgrade"     
              else     
                perform_action="rewrite"	  
              fi
   
              if [ $discoveryFlag -eq 1 ]; then
	        output_CmpLog "Discovered SubVendorId: $SubVendor_Id, SubDeviceId: $SubDevice_Id"   
                #printXML '\t\t' "<device id=\"AC:$controller_id,S:$EID\">"		  
                printXML '\t\t' "<device>"		  
                printXML '\t\t\t' "<device_id value=\"AC:$controller_id,S:$EID\" />"
                printXML '\t\t\t' "<controller_id value=\"AC:$controller_id\" />"
                printXML '\t\t\t' "<product_id value=\"$exp_product_name\" />" # Change it to correct product id value eg: Apollo 4510
                printXML '\t\t\t' "<fw_item>"
                printXML '\t\t\t\t' "<type value=\"sasexpander\" />"
                printXML '\t\t\t\t' "<firmware_id value=\"\" />"
                printXML '\t\t\t\t' "<takes_effect value=\"deferred\" />"
                printXML '\t\t\t\t' "<version value=\"$xml_file_firmware_version\" />"
                printXML '\t\t\t\t' "<active_version value=\"$exp_firmware_version\" />"
                printXML '\t\t\t\t' "<action value=\"$perform_action\" />"
                printXML '\t\t\t\t' "<duration value=\"6\" />"
                printXML '\t\t\t\t' "<shared value=\"no\" />"
                printXML '\t\t\t' "</fw_item>"     
                printXML '\t\t' "</device>"
             fi
           fi
          done
	fi
    
    controller_id=$(($controller_id + 1))
  done

  if [ $discoveryFlag -eq 1 ]; then
    printXML '\t' "</devices>"
    printXML "</hp_rom_discovery>"
    output_CmpLog "============ Summary ============"    
    output_CmpLog "Smart Component Finished"
    output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
    output_CmpLog "Device discovery complete"
    output_CmpLog "Update not attempted."
    exit $INSTALL_NOT_ATTEMPTED
  fi

}

flashDevices() {
  # The following while loop iterates over each supported attached controller.
  controller_id=0
  while [ "$controller_id" -le $(($num_controllers-1)) ]
  do
    # Get the Sub Vendor id and Device id information that is currently on the controller.
	SubVendor_Id=$("$storcli" /c"$controller_id" show | grep 'SubVendor Id =' | awk '{print $4}')
	SubDevice_Id=$("$storcli" /c"$controller_id" show | grep 'SubDevice Id =' | awk '{print $4}')
	if [[ "$SubVendor_Id" == "0x1590" && "$SubDevice_Id" == "0x22C" ]]; then
	getEIDs
	for EID in $attached_EIDS
	do
          output_CmpLog "The controller ID is: $controller_id" 
          output_CmpLog "Discovered SubVendorId: $SubVendor_Id, SubDeviceId: $SubDevice_Id"	  
          ctrl_model_name=$("$storcli" /c"$controller_id" show | grep 'Product Name =' | awk '{print $4,   $5, $6, $7, $8, $9}')    
          output_CmpLog "Controller model: $ctrl_model_name"
          # Get the version of firmware that is currently on the controller.
          getControllerFirmwareVersion    
	      getExpanderFirmwareVersion
          getExpanderProductName
          `echo "$_SWKEY" | grep -q "$getExpanderProductName"`
          KEYOUT1=$?
          if  [ $KEYOUT1 -eq 0 ]; then
            output_CmpLog "Firmware binary: $PWD/$firmware_binary"
            flash "$exp_product_name" "$PWD/$firmware_binary"
          fi
	 done
	fi
    
    controller_id=$(($controller_id + 1))
  done
}

# Flash the Controller.
flash() {
   target=$1
   getControllerFirmwareVersion
   getExpanderFirmwareVersion
   NoVerChk=""
   if [ "$exp_firmware_version" \< "$xml_file_firmware_version" ]; then
     perform_action="upgrade"
   elif [ "$exp_firmware_version" \> "$xml_file_firmware_version" ]; then
     NoVerChk="noverchk"
     perform_action="downgrade"
   else
     NoVerChk="noverchk"
     perform_action="rewrite"
   fi

   upgrade_or_downgrade="firmware from $exp_firmware_version to $xml_file_firmware_version on $target"
   rewrite="firmware from $xml_file_firmware_version to $exp_firmware_version on $target"
   if [ "$perform_action" == "rewrite" ]; then
     if [ $forceFlag -eq 0 ]; then
       if [ $rewriteFlag -eq 0 ]; then      
         output_CmpLog "Firmware versions are matching.Installation not attempted for enclosure ID : $EID of controller ID : $controller_id" 
         return
        fi 
     fi
     output_CmpLog "Attempting to $perform_action $rewrite"
   elif [ "$perform_action" == "downgrade" ]; then
     if [ $forceFlag -eq 0 ]; then
       if [ $downgradeFlag -eq 0 ]; then
         output_CmpLog "Firmware is at latest version. Installation not attempted for enclosure ID : $EID of controller ID : $controller_id"
         return
        fi
     fi
     output_CmpLog "Attempting to $perform_action $upgrade_or_downgrade"
   else
     output_CmpLog "Attempting to $perform_action $upgrade_or_downgrade"
   fi

   output_CmpLog "This could take several minutes..."
   flash_flag="failed"
   #"$storcli" /c"$controller_id" set ocr = on
   flash_status=$("$storcli" /c"$controller_id" /e"$EID" download src=$2 mode=E) 
   #"$storcli" /c"$controller_id" restart
   
   for status in $flash_status
   do
     if [ "$status" == "Success" ]; then
       flash_flag="succeeded"
     fi
   done

   sleep 70
   if echo "$flash_flag" | grep -q 'succeeded'; then
     flash_status_flag="reboot required."
     if echo "$perform_action" | grep -q 'upgrade'; then
       performed_action="upgraded"
       output_CmpLog "Successfully $performed_action $upgrade_or_downgrade, $flash_status_flag"
     elif echo "$perform_action" | grep -q 'downgrade'; then
       performed_action="downgraded"
       output_CmpLog "Successfully $performed_action $upgrade_or_downgrade, $flash_status_flag"
     else
       performed_action="rewrite"
       output_CmpLog "Successfully $performed_action $rewrite, $flash_status_flag"
     fi
     output_CmpLog "========================================================================================================================================"
     SC_RESULT_PASS=1
   else
     output_CmpLog "Error: Failed to flash $target"
     output_CmpLog "========================================================================================================================================"
     SC_RESULT_FAIL=1 
   fi

}


parseXML() {
  xml_file=$file
  #echo $xml_file
  isFileReadable $PWD/$xml_file
  # Extract the name of the firmware binary file from the XML file.
  firmware_binary=$(grep -o -E "<FileName>(T.*)</FileName>" "$PWD/$xml_file" | sed 's/FileName//g' | sed 's/<//g' | sed 's/>//g' | sed 's/\///g' | head -1)
  if [ -z $firmware_binary ]; then
    output_CmpLog "No firmware binary file was found for $package"
    continue
  fi
  isFileReadable $PWD/$firmware_binary
  
  # Read from the smart component's xml file and obtain the firmware version.
  xml_file_firmware_version=$(grep 'version value=' "$xml_file" | head -1 | awk '{print $2}' | sed -e 's/value="\(.*\)"/\1/')    
}

main() {
  #parseCmdArgs  
  #cat /dev/null > _LOGFILE
  getCmpXML  
  parseXML
  getOSPlatform
  locateStorcli
  getCtrlCnt  
  if [ $discoveryFlag -eq 1 ]; then
    deviceDiscovery
  else
    flashDevices
    output_CmpLog "============ Summary ============"
    output_CmpLog "Smart Component Finished"

    if [ 1 -eq $SC_RESULT_FAIL ]; then
      output_CmpLog "Exit Status: $INSTALL_FAILED"
      exit $INSTALL_FAILED
    elif [ 1 -eq $SC_RESULT_PASS ]; then
      output_CmpLog "Exit Status: $SUCCESS_WITH_REBOOT"
      exit $SUCCESS_WITH_REBOOT
    else
      output_CmpLog "Update not attempted (or interrupted). All selected devices are either up-to-date or have newer versions installed or Hardware not detected"
      output_CmpLog "Exit Status: $INSTALL_NOT_ATTEMPTED"
      exit $INSTALL_NOT_ATTEMPTED
    fi
  fi

}

main
