#!/bin/sh  -e

# /* QB: G#86 2018/09/18 */
# auto-detect whether BIOS or UEFI
if [ -d "/sys/firmware/efi/efivars" ] ; then
   firmware="uefi"
else
   firmware="bios"
fi
# /* QE: G#86 */

# /* QB: G#907 2019/12/10 */
EXEC_PATH=/mnt/application
# /* QE: G#907 */
CONFIG_PATH=/mnt/fastpath
SERVICE_NAME=qnos
PKG_NAME=qnos-m4500
NAME=$SERVICE_NAME-mgmt
ONIE_VERSION=POST_2014_05
# /* QB: G#9 2018/07/31 */
# Switchdrvr writes to /tmp/issuWrPipe, so the script should read from it
# Switchdrvr reads from /tmp/issuRdPipe, so the script should write to it
ISSU_RD_PIPE="/tmp/issuWrPipe"
ISSU_WR_PIPE="/tmp/issuRdPipe"
ISSU_STAT_FILE="/mnt/fastpath/issu_stat"
# /* QE: G#9 */
# /* QB: G#1087 2020/04/24 */
LOGGER_PREFIX="[`who am i | awk '{print $2 \" \" $3 \" \" $4 \" \" $5 \" \" $6}'`]"
# /* QE: G#1087 */

# /* QB: G#1087 2020/04/24 */
firmwareupgrade_log()
{
  #/* QB: G#1083 2020/04/23 */
  logger -t '' -p local1.info "${LOGGER_PREFIX}" "$1"
  #/* QE: G#1083 */
}
# /* QE: G#1087 */

usage()
{
# /* QB: G#86 2018/09/04 */
# /* QB: E#254502  2018/10/18 */
cat << __START__

 Usage: $NAME < -c | -z | -i | -u | -r | -R | -h | -v | -o <image_path> | -s >  [-f]

 $SERVICE_NAME management utility to perform configuration and image management

 COMMAND LINE OPTIONS

 -c  Clear saved startup configuration of $SERVICE_NAME service

 -z  Erase all configuration files to restore $SERVICE_NAME to factory
     default configuration

 -i  Set default GRUB entry to boot ONIE in OS install mode

 -r  Set default GRUB entry to boot ONIE in rescue mode

 -u  Set default GRUB entry to boot ONIE in OS uninstall mode

 -o  copy NOS installer image to ONIE installer partition

 -R  Restore default GRUB entry to factory default

 -v  Display $SERVICE_NAME package information

 -s  Save application state for ISSU (In Service Software Upgrade)

 -f  Force mode to perform control command without prompting user 
     for confirmation

 -h
     Help. Prints this text.

 Note:
      $SERVICE_NAME service needs to be stopped to execute -z command.

__START__
# /* QE: E#254502  */
# /* QE: G#86 */
}

confirm () 
{
  if [ "$FORCE" = "1" ]; then
     true
  else
    read -r -p "${1:-Are you sure? [y/N]} " response
    case $response in
        [yY][eE][sS]|[yY]) 
            true
            ;;
         *)
            exit 0
            ;;
    esac
  fi
}

# /* QB: G#86 2018/09/18 */
grub_reboot()
{
  # Legacy bios will store grub config in /boot/grub
  # while UEFI platforms will use /grub/
  if [ "$firmware" = "bios" ] ; then
     grub-reboot "$1"
  else
     grub-reboot --boot-directory=/ "$1"
  fi
}

onie_boot_mode()
{
  # /* QB: G#1090 2020/04/24 */
  if [ -f /mnt/onie-boot/onie/tools/bin/onie-boot-mode ]; then
  # /* QE: G#1090 */
     set +e
     /mnt/onie-boot/onie/tools/bin/onie-boot-mode -o $1
     grub-editenv /mnt/onie-boot/grub/grubenv list | grep "onie_mode=$1" > /dev/null 2>&1
     if [ $? -ne 0 ]; then
       mv /mnt/onie-boot/grub/grubenv /tmp/grubenv
       grub-editenv /tmp/grubenv list | \
       while read LINE; do
         grub-editenv /mnt/onie-boot/grub/grubenv set "$LINE"
       done
       grub-editenv /mnt/onie-boot/grub/grubenv set "onie_mode=$1"
     fi
     # /* QB: G#140 2018/10/02 */
     grub-editenv /mnt/onie-boot/grub/grubenv unset "diag_mode"
     grub-editenv /mnt/onie-boot/grub/grubenv set "diag_mode=normal"
     # /* QE: G#140 */
     set -e
  # /* QB: G#1090 2020/04/24 */
  else
     echo "\n onie_boot_mode: Cannot find /mnt/onie-boot/onie/tools/bin/onie-boot-mode\n"
  fi
  # /* QE: G#1090 */
}
# /* QE: G#86 */

CMD=""
# /* QB: G#86 2018/09/04 */
while getopts "hcziruRvfos" opt;
# /* QE: G#86 */
do
    case "$opt" in
    h|\?)
        usage
        exit 0
        ;;
    c)  CMD=CLEAR_CFG
        ;;
    z)  CMD=ERASE
        ;;
    i)  CMD=ONIE_INSTALL
        ;;
    r)  CMD=ONIE_RESCUE
        ;;
    u)  CMD=ONIE_UNINSTALL
        ;;
# /* QB: G#86 2018/09/04 */
    o)  CMD=ONIE_RECOVERY
        ;;
# /* QE: G#86 */
    R)  CMD=ONIE_UNDO
        ;;
    v)  CMD=VERSION
        ;;
    f)  FORCE=1
        ;;
    s)  CMD=ISSU_START
        ;;
    esac
done

# /* QB: G#86 2018/09/04 */
if [ "$CMD" = "ONIE_RECOVERY" ]; then
   if [ "$2" = "" ]; then
      usage
      exit 1
   fi
fi
# /* QE: G#86 */

if [ -z $CMD ]; then
   usage
   exit 1
fi

if [ "$CMD" = "VERSION" ]; then
   if [ -e /etc/redhat-release ]; then
      rpm -qi ${PKG_NAME}
   else
   # /* QB: G#86 2018/09/04 */
      if [ ! -z ${SNAP_DATA} ]; then
         snap list | grep ${PKG_NAME}
      else
         apt-cache show ${PKG_NAME}
      fi
   fi

   if [ -e /dev/disk/by-label/RECOVERY ]; then
      echo "ONIE-in-band"
   # /* QE: G#86 */
   fi
   exit 0
fi

if test "`whoami`" != "root" ; then
  echo "Error! You must be root or sudoer to execute this command"
  exit 1
fi

if [ -e /bin/onie-boot-default ]; then
   ONIE_VERSION=PRE_2014_05
fi

if test "$CMD" = "ONIE_UNDO" ; then
   if [ "$ONIE_VERSION" != "PRE_2014_05" ]; then
      echo "Restoring default GRUB entry to boot $SERVICE_NAME"
      grub-reboot ICOS
      exit 0
   else
      onie-boot-default -o none
      onie-boot-update
      exit 0
   fi
fi

if test "$CMD" = "CLEAR_CFG" || test "$CMD" = "ERASE" ; then

   printf "\n!!!!!!!!!!!!!!!\n"
   echo "!    Alert    !"
   echo "!!!!!!!!!!!!!!!"
   echo "!  You are about to delete $SERVICE_NAME configuration information"
   echo "!  All configuration data will be lost and cannot be recovered. "
confirm "!  Are you sure? [y/N] "

# Delete startup configuration
  if test "$CMD" = "CLEAR_CFG" ; then
    printf "\nErasing startup configuration files\n"
    rm -f ${CONFIG_PATH}/*.cfg
    rm -f ${CONFIG_PATH}/startup-config
    exit 0
  fi

# Erase config partition
  if test "$CMD" = "ERASE" ; then
    #/* QB: B#1550 2018/01/04 */
    if [ -e /usr/bin/snap ]; then
      if systemctl is-active snap.${SNAP_NAME}.icos ; then
         printf "\nError! snap.${SNAP_NAME}.icos service should be stopped to proceed with the command.\n"
         exit 1
      fi
    elif [ -e /bin/systemctl ]; then
      if systemctl -q is-active ${SERVICE_NAME} ; then
        printf "\nError! ${SERVICE_NAME} service should be stopped to proceed with the command.\n"
        exit 1
      fi
    else
      if [ "$(status ${SERVICE_NAME} | grep -i running)" != "" ]; then
        printf "\nError! ${SERVICE_NAME} service should be stopped to proceed with the command.\n"
        exit 1
      fi
    fi
    #/* QE: B#1550 */
    printf "\nRestoring $SERVICE_NAME to factory default configuration\n"
    if [ -e ${CONFIG_PATH}/image1 ]; then
       # Backup and restore image1 which contains version information
       cp -f ${CONFIG_PATH}/image1 /tmp
       rm -rf ${CONFIG_PATH}/*
       cp -f /tmp/image1 ${CONFIG_PATH}/image1
    else
       rm -rf ${CONFIG_PATH}/*
    fi
    exit 0
  fi
fi

if test "$CMD" = "ONIE_INSTALL" || test "$CMD" = "ONIE_RESCUE" || test "$CMD" = "ONIE_UNINSTALL" ; then

 printf "\n!!!!!!!!!!!!!!!\n"
   echo "!   WARNING   !"
   echo "!!!!!!!!!!!!!!!"
if test "$CMD" = "ONIE_RESCUE"; then
   echo "!  You are about to make changes to switch boot sequence"
else
# /* QB: E#254483  2018/10/22 */
   echo "!  You are about going back to ONIE in order to reinstall operating system. "
   echo "!  After you reinstall os, all system data except startup-config will be lost and     "
   echo "!  cannot be recovered. "
# /* QE: E#254483  */
fi
confirm "!  Are you sure? [y/N] "

if  [ ! -d /mnt/onie-boot ] ; then
  if [ "$ONIE_VERSION" != "PRE_2014_05" ]; then
    mkdir -p /mnt/onie-boot
    mount LABEL=ONIE-BOOT /mnt/onie-boot
  fi
fi

# Boot to install os mode
  if test "$CMD" = "ONIE_INSTALL" ; then
    printf "\nUpdating ONIE GRUB configuration to reinstall $SERVICE_NAME OS\n"
    if [ "$ONIE_VERSION" = "PRE_2014_05" ]; then
      onie-boot-default -o install
      onie-boot-update
    else
      # /* QB: G#1090 2020/04/24 */
      if [ -f /mnt/onie-boot/onie/tools/bin/onie-boot-mode ]; then
      # /* QE: G#1090 */
         # /* QB: G#86 2018/09/18 */
         onie_boot_mode install
         grub_reboot ONIE
         # /* QE: G#86 */
         umount /mnt/onie-boot
      # /* QB: G#1090 2020/04/24 */
      else
         printf "\nONIE GRUB configuration has been modified in last operation, and ONIE directory was unmount.\n"
      fi
      # /* QE: G#1090 */
    fi
  fi

# Boot to rescue mode
  if test "$CMD" = "ONIE_RESCUE" ; then
    printf "\nUpdating ONIE GRUB configuration to perform rescue operations\n"
    if [ "$ONIE_VERSION" = "PRE_2014_05" ]; then
      onie-boot-default -o rescue
      onie-boot-update
    else
      # /* QB: G#1090 2020/04/24 */
      if [ -f /mnt/onie-boot/onie/tools/bin/onie-boot-mode ]; then
      # /* QE: G#1090 */
         # /* QB: G#86 2018/09/18 */
         onie_boot_mode rescue
         grub_reboot ONIE
         # /* QE: G#86 */
         umount /mnt/onie-boot
      # /* QB: G#1090 2020/04/24 */
      else
         printf "\nONIE GRUB configuration has been modified in last operation, and ONIE directory was unmount.\n"
      fi
      # /* QE: G#1090 */
    fi
  fi

# Boot to uninstall os mode
  if test "$CMD" = "ONIE_UNINSTALL" ; then
    printf "\nUpdating ONIE GRUB configuration to uninstall $SERVICE_NAME OS\n"
    if [ "$ONIE_VERSION" = "PRE_2014_05" ]; then
      onie-boot-default -o uninstall
      onie-boot-update
    else
      # /* QB: G#1090 2020/04/24 */
      if [ -f /mnt/onie-boot/onie/tools/bin/onie-boot-mode ]; then
      # /* QE: G#1090 */
         # /* QB: G#86 2018/09/18 */
         onie_boot_mode uninstall
         grub_reboot ONIE
         # /* QE: G#86 */
         umount /mnt/onie-boot
      # /* QB: G#1090 2020/04/24 */
      else
         printf "\nONIE GRUB configuration has been modified in last operation, and ONIE directory was unmount.\n"
      fi
      # /* QE: G#1090 */
    fi
  fi
  echo "Reboot for changes to take effect"
  exit 0
fi

# /* QB: G#86 2018/09/04 */
# Copy ONIE image to recovery partition
if test "$CMD" = "ONIE_RECOVERY" ; then
   # /* QB: G#1087 2020/04/24 */
   if [ -n "${3}" ]; then
      LOGGER_PREFIX="${3}"
   fi
   # /* QE: G#1087 */
   # /* QB: G#907 2019/12/10 */
   # Turn on "run script continuously despite error", else script will exit without any warning message, when it runs into an error.
   set +e
   # /* QB: G#1087 2020/04/23 */
   # /* QB: G#907 2020/03/23 */
   if [ ! -f ${2} ]; then
      output_msg="Error! Image file ${2} cannot be found"
      echo "\n${output_msg}\n"
      firmwareupgrade_log "${output_msg}"
      exit 1
   fi
   # /* QB: G#907 */
   # /* QE: G#1087 */
   # /* QB: G#1041 2020/04/09 */
   payload_sha1=$(head -n 50 "$2" | grep "payload_sha1=" --text | awk '{split($0,arr,"="); print arr[2]}')
   sha1=$(sed -e '1,/^exit_marker$/d' "$2" | sha1sum | awk '{ print $1 }')
   echo ""
   echo "Verifying firmware checksum ..."
   if [ "$sha1" != "$payload_sha1" ] ; then
       echo "Found    : $payload_sha1"
       echo "Calculate: $sha1"
       # /* QB: G#1087 2020/04/23 */
       output_msg="Firmware checksum verification status: failed"
       echo "${output_msg}"
       firmwareupgrade_log "${output_msg}"
       # /* QE: G#1087 */
       exit 1
   else
       echo "Firmware checksum verification status: passed"
   fi
   # /* QB: G#1087 2020/04/23 */
   # /* QE: G#1087 */
   # /* QE: G#1041 */
   PRODUCT_NAME_VPD=`grep "PRODUCT_NAME=" ${EXEC_PATH}/fastpath.vpd`
   if [ -z "$PRODUCT_NAME_VPD" ]; then
       # /* QB: G#1087 2020/04/23 */
       output_msg="Error! Cannot find Product Name."
       echo "\n${output_msg}\n"
       firmwareupgrade_log "${output_msg}"
       # /* QE: G#1087 */
       exit 1
   fi
   PRODUCT_NAME=`echo $PRODUCT_NAME_VPD | awk '{split($0,a,"=" ); print a[2]}'`
   grep -q ${PRODUCT_NAME}_ ${2}
   # /* QB: G#2100, 2022/12/05 */
   rc1=$?
   PRODUCT_NAME_S=`cat $EXEC_PATH/platform_id`
   grep -q qnos-${PRODUCT_NAME_S}_ ${2}
   rc2=$?
   if [ $rc1 -ne 0 -a $rc2 -ne 0 ]; then
   # /* QE: G#2100 */
       # /* QB: G#1087 2020/04/23 */
       output_msg="Error! ONIE image doesn't fit to this device."
       echo "\n${output_msg}\n"
       firmwareupgrade_log "${output_msg}"
       # /* QE: G#1087 */
       exit 1
   fi
   set -e
   # /* QE: G#907 */

   if [ ! -e /dev/disk/by-label/RECOVERY ]; then
      # /* QB: E#254502  2018/10/18 */
      # /* QB: G#1087 2020/04/23 */
      output_msg="Error! ONIE installer partition not found"
      echo "\n${output_msg}\n"
      firmwareupgrade_log "${output_msg}"
      # /* QE: G#1087 */
      # /* QE: E#254502  */
      exit 1
   fi

   mkdir -p /mnt/recovery

   printf "\ncopying ONIE image to ONIE installer partition\n"
   #check if the path provided is correct and file exists
   # /* QB: G#907 2020/03/23 */
   # /* QB: G#907 */
   mount LABEL=RECOVERY /mnt/recovery
   #delete existing image
   rm -f /mnt/recovery/onie-*
   #copy new image
   cp -f ${2} /mnt/recovery/onie-installer
   # /* QB: G#907 2020/03/23 */
   # /* QB: G#907 */
   sync
   umount /mnt/recovery
   exit 0
fi
# /* QE: G#86 */

# /* QB: G#9 2018/07/31 */
# Send message to switchdrvr for preparing ISSU
if  [ "$CMD" = "ISSU_START" ] ; then
  if [ -p "$ISSU_RD_PIPE" ] && [ -p "$ISSU_WR_PIPE" ] ; then
    echo -n "ISSU Save" > $ISSU_WR_PIPE
    echo "ISSU save request sent to switchdrvr."
    saving=0

    while [ true ] ;
    do
      reply=""
      if (read reply < $ISSU_RD_PIPE) 2> /dev/null ; then

        if [ "$reply" = "ISSU state/data saved" ] ; then
          echo "$reply."
          break
        elif [ "$reply:" != ":" ] &&  [ "$reply:" != "ISSU saving application state/data:" ] ; then
          echo "$reply."
        fi

        #Check if write pipe exists and send Ack to ISSU component
        if  [ -p "$ISSU_WR_PIPE" ] ; then
          echo "Ack" > $ISSU_WR_PIPE
        fi

        # Check for ISSU saving status in /mnt/fastpath/issu_stat file
        attempt=0
        while [ "$saving:" = "0:" ] && [ $attempt -le 10 ] ;
        do
          if [ -f  $ISSU_STAT_FILE ] ; then
            grep ":ISSU_STATE_CNF_SAVING:" $ISSU_STAT_FILE >/dev/null 2>&1
            if [ "$?:" = "0:" ] ; then
              saving=1
              echo "ISSU saving application state/data."
              break
            fi
          fi
          attempt=$((attempt + 1))
          sleep 1
        done

      else

        # Pipe communication error check stat file to find if ISSU is finished
        grep ":ISSU_STATE_CNF_SAVED:" $ISSU_STAT_FILE >/dev/null 2>&1
        if [ "$?:" = "0:" ] ; then
          echo "ISSU state/data saved."
        else
          echo "Error! ISSU save failed."
        fi
        #Break the loop to return to console
        break

      fi
    done
  else
    echo "Error ! pipe(s) not found for communicating with switchdrvr."
  fi
fi
# /* QE: G#9 */
