#! /bin/sh

###############################################################################
# Copyright (c) 2005, all rights reserved
# License- GPL
#
# File:     vrsn
# Author:   Jeremy P. Thien
# Company:  Adtec Digital, Inc.
# Created:  Jan  7, 2006
# @date    Last Edit:     $Date$ by $Author$
#
# Provide access to version information
# by listing the available product versions or
# by updating the current product version selection
#
# NOTE: Much of this was modeled after Nimble Forest boot script.
# NOTE: Added SNMP Trap messages. 
#       Only added one for successfule version changes in perform_update() as
#       this is the last thing that happens for all paths to a version change.
#       Added traps for all error conditions. May be too much... TPM 04-23-2009
###############################################################################

SCRIPT_NAME=`/bin/basename $0`
LOG_TAG=$'\040\040\040[VRSN]'
DEBUG=N   #Y


export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
export LD_LIBRARY_PATH=/usr/local/lib

# Product table allowable change, see function qualify_update
MIN_MAX_soloist_4111_hw2=0,0
MIN_MAX_displayMate=0,0
MIN_MAX_edje_4111=0,0
MIN_MAX_dta=0,0
MIN_MAX_dpi=0,0
MIN_MAX_mediahub=0,0
MIN_MAX_mediahub_hd=0,0


# error codes
ERR=([128]="Insufficient Space" [129]="Gnu Missing" [130]="Invalid Version" \
[131]="Invalid Firmware" [132]="Extraction Failed" [133]="Extraction Busy" \
[134]="Remount failed" [135]="Kernel Update Failure" [136]="Delete Failed" \
[137]="Cannot determine GNU" [138]="Unable to select version" \
[139]="Netboot system.  Vrsn not available.")

# define minimum space prior to extraction in Megs
declare -i MIN_FREE_SPACE=30
declare -i MIN_FREE_SPACE_RW=3  # read/write partition

# Determine if TERSE
if [ "$SCRIPT_NAME" == "vn" ]; then
   TERSE="Y"
else
   TERSE="N"
fi

# Location of the optional packages.
# This is THE root for all Nimble Forest managed packages
readonly OPTPKG=/opt/pkg

# OEM symbolic link.
# This is a top level policy decision within the Nimble Forest CMS.
# "oem" should ALWAYS exist.
readonly OEMSYMLINK=${OPTPKG}/var/oem

# Currrent OEM Symbolic link
# This is the name for the link for the "current oem"
# Created each this script runs, and to be used later to copy configurations
# from.
readonly PREVOEMSYMLINK=${OPTPKG}/var/oem_prev

# Nimble Forest archive search pattern.
# This is a top level policy decision within the Nimble Forest CMS.
readonly NFCMS_NAME_PATTERN=*.nfcms.tgz
# windoze apps seem to rename when transferring
readonly NFCMS_ALT_PATTERN=*.nfcms.gz

# Temporary extracting directory
# This directory signals that an extraction is in progress and
# other extractions should not occur.
readonly TMP_EXTRACTING=/tmp/vrsn_extracting

# default gnu folder if not exists in config
readonly DFLT_GNU="2.4.21.01"


#/*****************************************************************************
# FUNCTION- usage
# Print the usage.
#*****************************************************************************/
usage()
{
  echo "Description:"
  echo "    ${SCRIPT_NAME} is a utility for interacting with the Nimble Forest"
  echo "    configuration managment system (CMS)."
  echo "Usage:"
  echo "  \"${SCRIPT_NAME} [-t | -u VERSION]\" where options include:"
  echo "    -t"
  echo "          List available product versions"
  echo "    -u VERSION"
  echo "          Update to VERSION (from ""-t"" version list) and reboot"
  echo "    -x FILE"
  echo "          Extract FILE to the Nimble Forest CMS"
  echo "    -s"
  echo "          Search for valid Nimble Forest CMS archive"
  echo "    -d VERSION"
  echo "          Delete VERSION (from ""-t"" version list)"
  echo "    -a FILE"
  echo "          Extract FILE to the Nimble Forest CMS, Update and reboot"
  echo "    -h Display this screen"
  exit 0
}

#/*****************************************************************************
# FUNCTION- output
# Send output based on terse or verbose, Logging also
#*****************************************************************************/
output ()
{
  if [ "$TERSE" != "Y" ]; then
    echo $1
  fi
  /usr/bin/logger -t $LOG_TAG "$1"
}

#/*****************************************************************************
# FUNCTION- error_handle
# handles error conditions, terse aware.
#*****************************************************************************/
error_handle ()
{
  /usr/bin/logger -t $LOG_TAG "${ERR[$1]}"
  if [ "$TERSE" == "Y" ]; then
    exit $1
  else
    echo "Error ${1}: ${ERR[$1]}"
    exit $1
  fi
}


#/*****************************************************************************
# FUNCTION- send_trap_msg
# sends trap messages for version change conditions.
#*****************************************************************************/
send_trap_msg ()
{
  /usr/bin/logger -p local0.error -t' [SYSD]' "   250252 $1"
}


#/*****************************************************************************
# FUNCTION- expose_gnu
# Since the gnu link is under the /opt/pkg/var mount, we need to expose it and put the 
# mount back.  The /tmp/* folder will be left in place for subsequent operations.
#*****************************************************************************/
expose_gnu ()
{
  if [ ! -e /tmp/gnu ]; then
    mkdir /tmp/gnu      
    
    TMP_DIR=/tmp/vrsn.$$   # lets create a unique temp app dir, avoid collisions 
    mkdir  $TMP_DIR
    mount /opt/pkg/var $TMP_DIR -o bind  &>/dev/null     # preserve the old var dir onto temp
	  
	 # The next set of lines are critical that they complete.  Exposing the gnu oem folder 
	 # is dangerous while running vrsn script since it can break oem link which always
	 # needs to point to a valid gnu folder, else the system will not boot.
	 umount /opt/pkg/var &>/dev/null
	 if [ $? -ne 0 ]; then   # was not able to remove top layer to expose gnu
	    umount $TMP_DIR    # cleanup
	    rmdir /tmp/gnu
	    rmdir $TMP_DIR
	    return 137   # umount failed and cannot see gnu link,  should we reboot?
	 fi
    mount /opt/pkg/var /tmp/gnu -o bind  &>/dev/null  # contains the info we want, save to tmp
    mount $TMP_DIR /opt/pkg/var -o bind  &>/dev/null  # restore old var 
  else     # /tmp/gnu exists from the previous call
	 # to get to the next line we expect there to be a file /tmp/gnu/oem that is a 
	 # symlink to ../gnu/gcc-3xxxxx or ../gnu/2.4.24.01   
	 GNU_VERSION=$(basename $(find /tmp/gnu/ -name oem -printf "%l\n"))
	 if [ ! $GNU_VERSION ]; then
	    return 137   # get gnu failed and cannot see gnu link    
	 else
	   output "Found GNU OEM Link: ${GNU_VERSION}"
	 fi    
  fi
  return 0	 
}

#/*****************************************************************************
# FUNCTION- deref_oemsymlink
# Dereference $OEMSYMLINK symbolic link to the directory to which it points.
# This is very useful for accessing files without depending on the symbolic
# link, especially since we may be changing the link. Since the symbolic link
# is so important, we will also try to restore it to some safe value if it is
# missing.
#*****************************************************************************/
deref_oemsymlink ()
{
  # Dereference the OEM symbolic link and save the pointed to directory.
  pushd ${OEMSYMLINK} &>/dev/null
  OEMDIR=`pwd -P`
  popd &>/dev/null
  #debug "OEMDIR=${OEMDIR}"

  # Make sure we can see any new libraries that the new OEM configuration brings.
  #LD_LIBRARY_PATH=${OEMDIR}/lib:${LD_LIBRARY_PATH}
  #debug "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
}


#/*****************************************************************************
# FUNCTION- interactive_oem_selection
# Allow the user to interact with the OEM selection.
#*****************************************************************************/
#interactive_oem_selection ()
oem_selection ()
{
  # Local variables.
  local readonly PATH=${OPTPKG}/usr
  local readonly NAME=config
  local readonly MAXDEPTH=4
  local SELECTED_OEMDIR=${OEMDIR}
  local FILE
  local ANY_VALID_SELECTION=

  declare -a local POSSIBLE_OEMDIR
  declare -a local PRETTYPRINT
  declare -i local I=1

  # Detect and display all possible OEM configurations..
  for FILE in `/usr/bin/find ${PATH} -maxdepth ${MAXDEPTH} -name ${NAME} -type f -print`; do 
    POSSIBLE_OEMDIR[I]=${FILE%/${NAME}}
    PRETTYPRINT[I]=${POSSIBLE_OEMDIR[I]#${PATH}/}
    I=I+1
  done
  
  I=1
  while [ -n "${POSSIBLE_OEMDIR[I]}" ]; do
    if [ "${POSSIBLE_OEMDIR[I]}" == "${OEMDIR}" ]; then
      if [ "$TERSE" == "N" ]; then
        echo "${PRETTYPRINT[I]} (*** current selection ***)"
      else
        echo "${PRETTYPRINT[I]}"
      fi
      ANY_VALID_SELECTION="YES"
    else
      if [ "$TERSE" == "N" ]; then
        echo -e "${PRETTYPRINT[I]}"
      fi
    fi

    I=I+1
  done
}


#/*****************************************************************************
# FUNCTION- update_oem_selection
# Allow the user to change the OEM selection.
#*****************************************************************************/
update_oem_selection()
{ 
    local readonly OPTPKGUSR=${OPTPKG}/usr
    local readonly OPTPKGGNU=${OPTPKG}/gnu
    local readonly CFG_FILE=${OPTPKGUSR}/${SELECTED_OEMDIR}/config
    #local readonly MAXDEPTH=3
    if [ ! -e ${CFG_FILE} ]; then
       error_handle 130
       send_trap_msg "${ERR[130]}"
    fi
    # We detect possible OEM configuration directories as those having a "config"
    # file with the first or second line starting with "#!OEM"
    local readonly OEM_LINE=`grep -n "#\!OEM" ${CFG_FILE} | cut -d: -f1 | head -n 1`
    if [ "$OEM_LINE" == "1" -o "$OEM_LINE" == "2" ]; then
      get_req_gnu      # populate REQ_GNU to match gnu for this app
      if [ ! -d ${OPTPKGGNU}/$REQ_GNU ]; then
         error_handle 129   # required gnu does not exist for this application
         send_trap_msg "${ERR[129]}"
      fi
      expose_gnu       #uncover and get current GNU_VERSION
      if [ $? -eq 0 ]; then
        pushd ${OPTPKG}/var &>/dev/null
        if [ -d "../usr/${SELECTED_OEMDIR}" ]; then
          mount -o rw,remount / &>/dev/null
          output "Updating OEM version to $SELECTED_OEMDIR."
          /bin/rm -f ${OEMSYMLINK} &>/dev/null
          /bin/ln -sf ../usr/${SELECTED_OEMDIR#${OPTPKG}} ${OEMSYMLINK} &>/dev/null
          #update GNU
          if [ "$REQ_GNU" != "$GNU_VERSION" ]; then
	         output "Updating GNU to ${REQ_GNU}"
	         rm -f /tmp/gnu/prev_oem                  # remove it, avoid error from next line
            mv /tmp/gnu/oem /tmp/gnu/prev_oem   # preserve it in case need to rollback
            ln -fs ../gnu/${REQ_GNU} /tmp/gnu/oem
	         output "Updated GNU to ${REQ_GNU}"
          fi
	      # create a link to the current boot as PREV
	      /bin/rm -f ${PREVOEMSYMLINK} &>/dev/null
	      /bin/ln -sf ${OEMDIR} ${PREVOEMSYMLINK} &>/dev/null
	      mount -o ro,remount / &>/dev/null

        else
          error_handle 130    # selected OEM dir did not exist
          send_trap_msg "${ERR[130]}"
        fi
        popd &>/dev/null
      else   # failed to exposed current gnu version, unable to update?  
        error_handle 137
        send_trap_msg "${ERR[137]}"
      fi 
    else
      error_handle 130   # version folder existed but did not have valid config file.
      send_trap_msg "${ERR[130]}"
    fi
}

#############################################################################
# FUNCTION get_req_gnu
# retrieved the required gnu version for the release and populates REQ_GNU
# if not exist then sets default.
#############################################################################
get_req_gnu ()
{
    if [ -e ${OPTPKG}/usr/${SELECTED_OEMDIR}/config ]; then
      local readonly OPTPKGUSR=${OPTPKG}/usr
      local readonly CFG_FILE=${OPTPKGUSR}/${SELECTED_OEMDIR}/config
      REQ_GNU=$(grep "^#ver:" ${CFG_FILE} | cut -d: -f2)
      if [ ! $REQ_GNU ]; then 
        REQ_GNU=$DFLT_GNU
      fi    # set the default if not found
      output "Found Required GNU for ${SELECTED_OEMDIR}: ${REQ_GNU}"
    else
      REQ_GNU=""
    fi        
}


#/*****************************************************************************
# FUNCTION rollback_oemselection
# provide a method to rollback the previously made oem selections for app and gnu
#*****************************************************************************/
rollback_oemselection()
{
  if [ -e ${OPTPKG}/var/oem_prev ]; then  
    rm ${OPTPKG}/var/oem
    mv ${OPTPKG}/var/oem_prev ${OPTPKG}/var/oem
  fi     
  if [ -e /tmp/gnu/prev_oem ]; then
    rm /tmp/gnu/oem
    mv /tmp/gnu/prev_oem /tmp/gnu/oem
  fi
}

#/*****************************************************************************
# FUNCTION- toggle_boot_flag
# Determine if this unit gets it's boot flag flipped
# Some units (DPI's) may have their 2nd partition (hde2) at a location that micromonitor 
# will not find.  We check the unit type and find the right offset (2930) before changing
# bootable flag for the partition.
#*****************************************************************************/
toggle_boot_flag () 
{
  # get hde2 offset
  declare -i HDE2=$(sfdisk -luB  /dev/hde | grep hde2 | cut -c 15-22)
  # get product
  . /etc/env.global
  if [ "$PRODUCT" == "dpi" ] && [ $HDE2 -ne 2930 ]; then
     BOOT_FLAG=FALSE  # do not change boot flag
  else
     BOOT_FLAG=TRUE
  fi
}


#/*****************************************************************************
# FUNCTION- determine_nonbootable
# finds the currently non-bootable flag for system, either /dev/hde1 or /dev/hde2
#*****************************************************************************/
determine_nonbootable ()
{
  # find the line with the bootable flag
  determine_bootable
  if [ "$BOOT_PART" == "1" ]; then
     NONBOOT_PART="2"
  elif [ "$BOOT_PART" == "2" ]; then
     NONBOOT_PART="1"
  else   #uhoh, not able to determine bootable partition
     NONBOOT_PART="2"  # try 2
  fi
}

#/*****************************************************************************
# FUNCTION- determine_bootable
# finds the currently bootable flag for system, either /dev/hde1 or /dev/hde2
#*****************************************************************************/
determine_bootable ()
{
  local DEVHD="/dev/hde"
  # find the line with the bootable flag
  #if [ -e /sbin/sfdisk ]; then  # could be 2.6 system
#    local BOOTABLE=$(sfdisk -d ${DEVHD} : grep bootable | cut -d" " -f1) 
#  else  # have to use fdisk     # or a 2.4 system
    local BOOTABLE=$(fdisk -l ${DEVHD} | grep "\/dev.*\*" | cut -f1 -d" ")
 # fi
  if [ $BOOTABLE ]; then
    BOOT_PART=${BOOTABLE:(-1)}   # get the last character, 1 or 2
  else 
    BOOT_PART=1  # guess one?
  fi
  output "Current autoboot partition: $BOOT_PART"
}


#/*****************************************************************************
# FUNCTION- update_kernel
# Run molo for kernel, needs which partition to do this as arg. Also changes bootable
#*****************************************************************************/
update_kernel()
{
  DEVHD="/dev/hde"
  if [ $# -ne 1 ]; then 
    return 1   # wrong args 
  fi      
  if [ "$DEBUG" == "Y" ]; then
    local readonly MOLO="./molo -atc"
  else
    local readonly MOLO="./molo -ac"
  fi    
  if [ "$1" == "1" ]; then
    local PART="primary"
    #local UNPART="2"
  elif [ "$1" == "2" ]; then
    local PART="secondary"
    #local UNPART=1
  else 
    return 1  # wrong arg
  fi              
  
  pushd "${OPTPKG}/usr/${SELECTED_OEMDIR}/boot"  &>/dev/null
  if [ -e ${PART}/kernel ]; then 
    output "Updating the ${PART} kernel."
    $MOLO $PART
    if [ $? -ne 0 ]; then
      return 135
    fi
  else
    return 0  # kernel did not exist, so no update needed.
  fi  
  popd &>/dev/null
}


#/*****************************************************************************
# FUNCTION- search_oem_archive
# Search for Nimble Forest CMS archive files.
# NOTE:
# Re-ordered find command to suppress warning message for "maxdepth" usage.
# Changed find's prune value from "/proc/*" to /proc/.  There appears to be a slight variation in 2.4 vs 2.6 usage of the glob.   
#
#*****************************************************************************/
search_oem_archive()
{
  PROD_NAME=$(basename $OEMDIR)  # this for finding only nfcms files that match the existing system.
  #/usr/bin/find / -maxdepth 6 -path '/proc' -prune -o -path '/dev' -prune -o -name "$PROD_NAME.*$NFCMS_NAME_PATTERN" -print
  /usr/bin/find / -maxdepth 6 -path '/proc' -prune -o -path '/dev' -prune -o \( -name $NFCMS_NAME_PATTERN -o -name $NFCMS_ALT_PATTERN \) -print 2> /dev/null
}


#/*****************************************************************************
# FUNCTION- extract_oem_archive
# Extract Nimble Forest CMS archive file.
#*****************************************************************************/
extract_oem_archive()
{
  OPTTMP=/opt/tmp
  PROD=${OEMDIR}		# pattern should be /opt/pkg/usr/adtec/{product}/{version}
  for i in 1 2 3 4 5; do
    PROD=${PROD:$(expr index $PROD /)}
  done
  PROD=${PROD:0:$(expr index $PROD /)-1}	# finally, strip of version portion
  
  output "Validating Firmware: $(basename $NFCMS_ARCHIVE)" 
  if [ ! -e $NFCMS_ARCHIVE ]; then
     error_handle 138
     send_trap_msg "${ERR[138]}"
  fi
  # get the first two byts of the file
  local MAGIC=$(/bin/dd if=${NFCMS_ARCHIVE} bs=2 count=1 2>/dev/null | /usr/bin/od -t x2 -An)
  if [[ ${MAGIC} = " 1f8b" ]]; then  # gzip archive
    gunzip -t $NFCMS_ARCHIVE &>/dev/null   # test the NFCMS Archive
    if [ $? -ne 0 ]; then                  # bad archive
      rm -f $NFCMS_ARCHIVE                 # delete it
      error_handle 131  # corrupt archive
      send_trap_msg "${ERR[131]}"
    else                                   # valid file, but right product?
      tar -tzf $NFCMS_ARCHIVE | grep $PROD &>/dev/null   # test the NFCMS Archive 
                                                        # for correct product
      if [ $? -ne 0 ]; then                  # not found?
        rm -f $NFCMS_ARCHIVE                 # delete it
        error_handle 130  # was not the correct product type
        send_trap_msg "${ERR[130]}"
      else
        output "Firmware file validated."
      fi
    fi
  else 
    /usr/local/bin/gpg  --homedir /root/.gnupg/ --verify $NFCMS_ARCHIVE
    if [ $? -ne 0 ]; then                  # bad archive
      rm -f $NFCMS_ARCHIVE                 # delete it
      output "Invalid signature found in $NFCMS_ARCHIVE"
      error_handle 131  # corrupt archive
      send_trap_msg "${ERR[131]}"
    else
      output "Firmware file validated."
    fi
  fi
  # NOTE: Do not allow update of network file systems.
  if [ -e /boot/bootnet-to-disc.sh ]; then
    echo "Will not extract to network file system."
    exit 1   # hard exit, will never happen in field.    
  elif [ -d $TMP_EXTRACTING ]; then
    error_handle 133  #already extracting
    send_trap_msg "${ERR[133]}"
  else
    output "Extracting firmware: $(basename $NFCMS_ARCHIVE)."
    mkdir $TMP_EXTRACTING
    /bin/mount rootfs / -t rootfs -o remount,rw  &>/dev/null 
    if [ $? -ne 0 ] ; then 
      /bin/rmdir $TMP_EXTRACTING
      error_handle 134
      send_trap_msg "${ERR[134]}"
    fi 
    rm -rf ${OPTTMP} &>/dev/null              # clean
    mkdir ${OPTTMP}  &>/dev/null
    if [[ ${MAGIC} = " 1f8b" ]]; then  # gzip archive
      /bin/tar -xvzkf $NFCMS_ARCHIVE -C $OPTTMP
	    if [ $? -ne 0 ] ; then 
	      /bin/rmdir $TMP_EXTRACTING
	      rm -f $OPTTMP 
	      #/bin/rm -f $NFCMS_ARCHIVE &>/dev/null  # delete it?
	      error_handle 132                               # extraction failed
	      send_trap_msg "${ERR[132]}"
	    fi
    else
      pushd $OPTTMP >/dev/null
      /usr/local/bin/gpg --decrypt "$NFCMS_ARCHIVE" | tar -xvzkf -
      popd >/dev/null
	  fi
    output "Extraction complete."

    #now that it extracted, move the files
    for (( N=1; N<6; N++ )) ; do
      # step down through the directories and attempt to move.  
      # fails until non-matched directories
      for DIR in $(find ${OPTTMP} -mindepth ${N} -maxdepth ${N} -type d -printf "%P\n"); do
         #echo "${OPTTMP}/${DIR}/* ${OPTPKG}/${DIR}/"
         mv ${OPTTMP}/${DIR}/* ${OPTPKG}/${DIR}/ &>/dev/null
	     if [ $? -eq 0 ]; then    # ignore errors, OK
	        output "Moved ${DIR} to ${OPTPKG}"
	     fi    
      done 	 
    done      
        
    # delete the archive and tmp folder now that we are done
    if [ "$DEBUG" != "Y" ]; then
      /bin/rm -f $NFCMS_ARCHIVE &>/dev/null
    fi  
    /bin/rm -rf ${OPTTMP} &>/dev/null    
    sync     #allow things to sync and settle.
    sleep 1  # 
    
    /bin/mount rootfs / -t rootfs -o remount,ro  &>/dev/null 
    if [ $? -ne 0 ] ; then     
        output "Failed to re-mount rootfs as RO, continuing."
	     # no exit, this should be non-fatal?
    fi 
    
    # cleanup busy flag
    /bin/rmdir $TMP_EXTRACTING
  fi
  return 0
}

#/*****************************************************************************
# FUNCTION-delete_oem_selection 
# Removes previous oem dirs.
#*****************************************************************************/
del_oem_selection()					
{
  local ret=0
  if [ -e /boot/bootnet-to-disc ]; then
    echo "Will not delete network file system."
    exit 1
  elif [[ $OEMDIR = *$SELECTED_OEMDIR ]] ; then 
    output "Will not delete current booted system."
    error_handle 136
    send_trap_msg "${ERR[136]}"
  fi  
  if [ ! -d "${OPTPKG}/usr/${SELECTED_OEMDIR}" ]; then
    error_handle 136
    send_trap_msg "${ERR[136]}"
  fi
  # the following parses the supplied directory and verifies that the 
  # path is achored at adtec and has at least 3 components to prevent
  # deleting a parent directory
  RES=$( echo ${SELECTED_OEMDIR} | ( IFS=/ ; while read BASE PROD VER ; do echo $BASE $PROD $VER; done ) )
  set -- $RES
  if [ "${1}" != "adtec" ]; then   
     error_handle 136
     send_trap_msg "${ERR[136]}"
  fi
  if [ -z $3 ]; then
     error_handle 136
     send_trap_msg "${ERR[136]}"
  fi
  get_req_gnu   # populate REQ_GNU  to see if it is last  
  if [ ! "$REQ_GNU" ]; then
    error_handle 137
    send_trap_msg "${ERR[137]}"
  fi    
  /bin/mount rootfs / -t rootfs -o remount,rw &>/dev/null 
  if [ -d "${OPTPKG}/usr/${SELECTED_OEMDIR}" ]; then
    output "Deleting ${OPTPKG}/usr/${SELECTED_OEMDIR}"
    /bin/rm -rf "${OPTPKG}/usr/${SELECTED_OEMDIR}" &>/dev/null
    if [ $? -ne 0 ]; then 
      error_handle 136
      send_trap_msg "${ERR[136]}"
    fi
  fi
  if [ -d "${OPTPKG}/var/${SELECTED_OEMDIR}" ]; then
    output "Deleting ${OPTPKG}/var/$SELECTED_OEMDIR"
    /bin/rm -rf "${OPTPKG}/var/${SELECTED_OEMDIR}" &>/dev/null
  fi
  # now lets test to see if that was the last GNU, we have $REQ_GNU
  # find config and send to grep to find any matches
  local FOUND_GNU=$(find ${OPTPKG}/usr -mindepth 4 -maxdepth 4 -name config -exec grep -l "^\#ver:${REQ_GNU}" {} \;)
  if [ ! "$FOUND_GNU" ]; then
    if [ "$REQ_GNU" != "2.4.21.01" ] ; then   # no more versions required this GNU, exclude 2.4
      output "Removing $REQ_GNU"
      rm -rf ${OPTPKG}/gnu/${REQ_GNU}
    fi
  fi
  
  mount rootfs / -t rootfs -o remount,ro &>/dev/null
}

#/*****************************************************************************
# FUNCTION-test_drive_space
# Checks for available drive space 
#*****************************************************************************/
test_drive_space()
{
   #  Use blocks to avoid complications with M and B human displays.
   let "MIN_FREE_BLOCKS=MIN_FREE_SPACE*1024"
   local DRV_FREE=`df -P /opt/pkg/usr | grep -v "Filesystem"`
   local FREE_SPACE=`echo $DRV_FREE | cut -d" " -f 4`
   if [ $FREE_SPACE -lt $MIN_FREE_BLOCKS ] ; then 
      error_handle 128
      send_trap_msg "${ERR[128]}"
   fi
   # now check RW
   let "MIN_FREE_BLOCKS=MIN_FREE_SPACE_RW*1024"
   DRV_FREE=`df -P /opt/pkg/var | grep -v "Filesystem"`
   FREE_SPACE=`echo $DRV_FREE | cut -d" " -f 4`
   if [ $FREE_SPACE -lt $MIN_FREE_BLOCKS ] ; then 
      error_handle 128
      send_trap_msg "${ERR[128]}"
   fi
   
}

#/*****************************************************************************
# FUNCTION- qualify update
# Test to ensure that we cannot jump major versions.
# PRODUCT     ALLOWABLE_SELECTION
# shd              0,0
# dpi             -1,0
# dta             -2,+1
# default         -1,+1
#
# Allowable selection is the values to add to the CURRENT version to get MIN/MAX
# In this example the shd could not jump a major, the dta could go back one major
# only, the dta could go down up to two and up one.  The default would be if we 
# missed updating the table for a product.
#/*****************************************************************************
qualify_update()
{
   local MIN_MAX_VAR=MIN_MAX_${PRODUCT}
   local eval MIN_MAX=\$$MIN_MAX_VAR
   local MIN=${MIN_MAX%%,*}
   local MAX={MIN_MAX#*,}
   #first we need to parse the major out of SELECTED_OEMDIR
   local BASE=$(basename ${SELECTED_OEMDIR})
   MAJOR=${BASE%%.*}
   if [ $MAJOR -lt $MIN -o $MAJOR -gt MAX ]; then
		error_handle 138
		send_trap_msg "${ERR[138]}"
	fi
	# return OK
}


#/*****************************************************************************
# FUNCTION- perform update
# We wrap a bunch of checks to ensure each step operates correctly
#/*****************************************************************************
perform_update()
{
  #qualify_update
  toggle_boot_flag
  update_oem_selection
  if [ $? -eq 0 ]; then
    determine_nonbootable   #get nonboot part
    if [ "$BOOT_FLAG" == "TRUE" ]; then
      update_kernel $NONBOOT_PART    # update the non-bootable one.
    else
      update_kernel $BOOT_PART    # update the bootable one for special cases
    fi
    if [ $? -ne 0 ]; then
      rollback_oemselection
      error_handle 135   # kernel update failed.
      send_trap_msg "${ERR[135]}"
    else
      # success
      echo "Version Select Successful."
      if [ "$DEBUG" != "Y" ]; then
        send_trap_msg "Updating OEM version to $SELECTED_OEMDIR."
        /sbin/shutdown -r now >& /dev/null
      fi
      exit 0
    fi     
  else
    rollback_oemselection
    error_handle 138
    send_trap_msg "${ERR[138]}"
  fi
}

# here we are simply going to decipher what the final extracted path
# from the nfcms archive and select it.  This allows us to extract
# and select in one step
select_by_name()
{
 # NFCMS_ARCHIVE is populated with /media/hd0/soloist-4111_hw2-v2.01.01.nfcms.tgz
 # parse it
 local BASE=$(basename $NFCMS_ARCHIVE)
 local PROD=${BASE%-*}
 local VER_EXT=${BASE##*-v}
 VER=${VER_EXT%.nfcms.tgz*}
 SELECTED_OEMDIR=adtec/${PROD}/${VER}
 output "Found $SELECTED_OEMDIR. Selecting now."
 perform_update
 return 0
}

# test if net booted system
netboot()
{
  if [ -e /tmp/kernel ]; then
    echo "TRUE"
  else
    echo "FALSE"
  fi
}


#--Program start here--
deref_oemsymlink

# really wanted to stub this into all but search.
# temp fix for now to prevent trying to use on 
# net booted system.  Eventually I hope to allow 
# for version selection on netbooted systemn, 
# but will require a bit more work.
#if [ "$(netboot)"=="TRUE" ]; then
#   error_handle 139
#fi   
# MPG removed for now, had a problem


while getopts "tu:x:d:sha:b:z" OPTION; do
  case $OPTION in
    u) SELECTED_OEMDIR=$OPTARG; perform_update;;
    t) oem_selection; break ;;
    x) NFCMS_ARCHIVE=$OPTARG; test_drive_space && extract_oem_archive;;
    s) search_oem_archive;;
    d) SELECTED_OEMDIR=$OPTARG; del_oem_selection;;
    a) NFCMS_ARCHIVE=$OPTARG; test_drive_space && extract_oem_archive && select_by_name;;
    b) NFCMS_ARCHIVE=$(search_oem_archive | head -1)
	   if [ ! -z $NFCMS_ARCHIVE ]; then
	      test_drive_space && extract_oem_archive && select_by_name
	   fi  
	   ;;
    z) send_trap_msg "Test send_trap_message."; break ;;
    h|*) usage;;
  esac
done

