#!/bin/bash
######################################################################
#=====================================================================
#
#  applypatch - HF/Patch EDITION 1051
#
#  This script applies an ESRI Hot Fix/Patch/Service Pack to an existing 
#  product installation.
#
#  The following constants are required for this script.
#
#	AIVersion	:: identifies the version of ArcSDE being patched.
#	QFEVersion 	:: identifies the version of the QFE patch;
#			   should change with each QFE patch.
#	NameOfTOCFile   :: the TOC of files distributed on CD with 
#		     	   each patch (should never change)
#	NameOfTARFile   :: the compressed TAR patch file distributed on CD
#		     	   with each patch (should never change)
#
#=====================================================================
######################################################################

			###################
			#                 #
			# A Few Constants #
			#                 #
			###################

TOC_VERSION="TOC2"
#ArcIMSFileTest="bin/aimsserver.exe"
ArcIMSFileTest="tools/uninstallArcIMS"
ArcInfoFileTest="bin/arc"
ArcSDEFileTest="bin/giomgr"
ArcSDEClientFolderTest="tools/client"
ArcSDKName="client"
ArcSDEServer="Server"
ArcSDEClient="Client"
Tru64Platform="tru64"
ApplyPatchTOC="applypatch.toc"
ApplyPatchTAR="patch_tar.z"
QFETestFile=""
#ArcServerFileTest=".Setup/uninstallArcGISServer" (pre10.1)
ArcServerFileTest=".Setup/Uninstall_ArcGISServer/Uninstall_ArcGISServer"
ArcEngineRTFileTest="uninstallArcGISEngineRT"
ArcReaderFileTest="uninstallArcReader"
ArcEngCPPFileTest="uninstallArcGISEngineDevKitCPP"
ArcEngJavaFileTest="uninstallArcGISEngineDevKitJava"
ArcObjCPPFileTest="uninstallArcObjectsSDKCPP"
ArcObjJavaFileTest="uninstallArcObjectsSDKJava"
ArcSrvrJavaFileTest="uninstallArcGISServerJavaADF"
ArcIMSJavaFileTest="uninstallArcIMSJavaADF"
ArcMapSrvrFileTest="bin/mapserver.dll"
ArcGISJavaHelpFileTest="uninstallArcGISJavaDoc"
ArcGISWebAdaptorFileTest="uninstall_WebAdaptor"
ArcGISSDSFileTest="uninstall_ArcGISSpatialDataServer"
ArcGISPortalFileTest="uninstall_ArcGISPortal"
ArcGISDataStoreFileTest="uninstall_ArcGISDataStore"
ArcGISGeoEnrichmentFileTest="uninstall_ArcGISGeoEnrichmentServer"
ArcGISNotebookSvrFileTest="uninstall_ArcGISNotebookServer"
ArcGISMissionSvrFileTest="uninstall_ArcGISMissionServer"
ArcGISInsightsPortalFileTest="uninstall_Insights.sh"
ArcGISInsightsServerFileTest="uninstall_Insights.sh"
ArcGISUrbanFileTest="uninstall_ArcGISUrban.sh"
ArcGISVideoServerFileTest="uninstall_ArcGISVideoServer"
ArcGISDataPipelinesServerFileTest="uninstall_ArcGISDataPipelinesServer"
IsBaselinePatch="false"
BaselinePatchName=""
BaselinePatchQfeId=""
BaselinePatchUrl=""
MOLEFileTest92="uninstallMole"
MOLEFileTest="uninstallMOLE"
MAFileTest="uninstallMilitaryAnalyst"
LMFileTest="uninstallLicenseManager"
IsSystemDService=false
SystemDServiceName=""
OriginalPatchFilename=""
TempFile1=""
TOC_IFS=":"
ValidationErrorList="/tmp/applypatch.$$.errors.lst"
SPNumber=0
DF="/bin/df"
TAR="/bin/tar"
LS="/bin/ls"
PGREP_OPT="-fla"
ThePosition=0
APPLY_PATCH_VERSION="2.0.3"
VER=""


######################################################################
#=====================================================================
#
#  Function Synopsis:
#
#     Set_System_Commands()	      Set up location of system commands
#                                 based on platform this is being run
#     Get_Patch_Info()            Get information from about the patch 
#                                 from the patch TOC file
#     MyDf()                      Determine available disk space in KB
#                                 (platform independant df)
#     MyDu()                      Determine size of a file in KB
#                                 (platform independant du)
#     LenChr()                    Determine length of string -  
#                                 including trailing CR/LF
#     ToLower/ToUpper()           Convert a given string to lower or 
#                                 upper case and return thr result
#     Prompt()                    Display a prompt to the user
#     Error_Exit()                The installation of the patch failed. 
#                                 This routine is called when none of 
#                                 the patch files have been installed 
#                                 yet and the product HOME is still in
#                                 its original state
#=====================================================================
#     Size_Of_Patch()             Determine disk space required by patch
#                                 files
#     Size_Of_Originals()         Determine the total size of the files 
#                                 contained within the Updated TOC using
#                                 the size of the files already existing 
#                                 in the user's product install
#     Validate_Patch_Home()       Validate PatchHome for location of 
#                                 patch files
#     Validate_Product_Path()     Make sure that Product Home specified 
#                                 by the user is valid for installation
#     Validate_Save_Path()        Make sure save path exists and is 
#                                 writeable
#     Update_TOC_File()           Create an updated TOC file based on
#                                 what the user has installed in their
#                                 product HOME
#     Apply_The_Patch()           Copies in the new files from compressed 
#                                 tar file
#     Validate_The_Patch()        Validates that the patch files were installed.
#     Cut_String()                Cuts the blanks from the end of the 
#                                 given string
#     Clean_Up()                  Delete any temporary files we might  
#                                 have created
#     List_Valid_Selections()     Lists all valid/available options for 
#                                 ESRI Patch installation
#     Reiterate_Choice()          Reiterates the choice the user made 
#                                 from valid selectable ESRI Patch 
#                                 installation options
#     Choose_Available_Install()  Prompt user to select one of the 
#                                 available installations
#     Copy_Rollback_Scripts()     Create the $installDir/.Setup/qfe folder 
#                                 if not already present, then copy the 
#                                 rollback scripts from ./resources to 
#                                 that location. 
#     Copy_Backup_Script()        Helper for Copy_Rollback_Scripts 
#     Copy_Remove_Script()        Helper for Copy_Rollback_Scripts
#     Check_For_Previous_Backup() Check if the backup system is in place 
#                                 and if this patch is already installed.
#     Is_Patch_Backed_Up()        Check the manifest.txt to see if this 
#                                 patch is already installed.  
#     IsPatchInstalled()          Check the ESRI_PATCH_LOG to see if this
#                                 patch (or any patch) is installed.
#     CheckForBaselinePatch()     Fail if a required baseline patch is
#                                 not already installed.
#     SourceEsriPropertiesFile()  Source $HOME/.ESRI.properties.xxx to
#                                 get installed products/versions.
#=====================================================================
######################################################################





#=====================================================================
# SourceEsriPropertiesFile()
#
# Source $HOME/.ESRI.properties.xxx to get installed products/versions.
#
# Use the #PV# value in applypatch.toc to choose the correct properties
# file in case there are multiple versions (which is the case with
# WebAdapter or LicenseManager).
#=====================================================================
SourceEsriPropertiesFile()
{
  local toc=""
  local ver=""
  local properties_file=""

  # Locate applypatch.toc
  toc=$(stat -f -c %n ${ScriptDir}/*/applypatch.toc)
  if [ ! -f "$toc" ]; then
    Error_Exit "Could not find applypatch.toc"
  fi

  # Get the patch product version
  ver=$(grep "#PV#" "$toc" | awk -F' ' '{print $2}')
  if [ -z "$ver" ]; then
    Error_Exit "No #PV# value in applypatch.toc.  Could not determine patch product version."
  fi

  # Loop through each $HOME/.ESRI.properties file and choose one
  # That matches the patch's version string. Fail if not found.
  local files=""
  local found=false
  local res=1
  local properties_file=""

  files=$(ls -1 ${HOME}/.ESRI.properties.$(uname -n).* 2> /dev/null)

  [ -z "$files" ] && fail "No \$HOME/.ESRI.properties files found."

  for f in $files
  do
    #echo "Checking ${f}..."
    check_properties_file_versions "$f" "$ver"
    res=$?
    if [ "$res" -eq 0 ]; then
      properties_file="$f"
      break
    fi
  done

  if [ "$res" -ne 0 ]; then
    fail "ERROR: No installed products have the version $ver."
  fi

  # Values will propagate globally
  . "${properties_file}" 2> /dev/null
}

#---------------------------------------------------------------------
# Helper for SourceEsriPropertiesFile
#
# Check all the *_VERSION tags in case different products use different
# version tags (e.g. Insights)
#---------------------------------------------------------------------
check_properties_file_versions()
{
  local file="$1"
  local version="$2"
  local found=false

  versions=$(grep _VERSION "$file" | cut -d= -f2)

  for v in $versions
  do
    if [ "$v" = "$version" ]; then
      found=true
      break
    fi
  done

  [ "$found" = true ]
}

######################################################################
#=====================================================================
#  Set_System_Commands()
#
#  Most commands that we use in this script are in /bin for most
#  platforms.  We assume that users will have /bin in their $path.
#
#  For commands that are NOT in /bin for some platforms, we specify 
#  the location over here because we cannot assume that the $path
#  variable will be able to find them.
#=====================================================================
######################################################################
Set_System_Commands() 
{
   #XXXXX========================================================
   #  Set special case values (based upon platform).
   #=============================================================
   case $(uname) in
      AIX)
         CurrentPlatform="ibm"
         CurrentPlatformUC="IBM"
         ;;
      HP-UX)
         CurrentPlatform="hp"
         CurrentPlatformUC="HP"
         ;;
      Linux)
         CurrentPlatform="linux"
         CurrentPlatformUC="Linux"
         ;;
      OSF1)
         CurrentPlatform="tru64"
         CurrentPlatformUC="Tru64"
         ;;
      SunOS)
         CurrentPlatform="solaris"
         CurrentPlatformUC="Solaris"
         DF="/usr/sbin/df"
         LS="/usr/bin/ls"
         TAR="/usr/sbin/tar"
         ;;
      IRIX*)
         CurrentPlatform="sgi"
         CurrentPlatformUC="SGI"
         DF="/usr/sbin/df"
         LS="/usr/bin/ls"
         TAR="/usr/bin/tar"
         ;;
      Darwin)
         CurrentPlatform="macos"
         CurrentPlatformUC="MacOS"
         TAR="/usr/bin/tar"
         COMPRESS="/usr/bin/compress"
         ;;
   esac

   # Check for valid pgrep option (-fa vs -fl) for long listing
   if [ $(uname) = "SunOS" ]; then
     res=$(pgrep ${PGREP_OPT} sh 2>&1 | grep 'illegal option')
   else
     res=$(pgrep ${PGREP_OPT} sh 2>&1 | grep 'invalid option')
   fi

   # The pgrep -fa option failed so use -fl
   if [ -n "$res" ]; then
     PGREP_OPT="-fl"
   fi
   
}


######################################################################
#=====================================================================
#  Print_Applypatch_Intro()
#
#  
#=====================================================================
######################################################################
Print_Applypatch_Intro()
{
   echo ""
   echo "  ==================================================================="
   echo ""
   echo "                 ArcGIS Enterprise Update Tool ${APPLY_PATCH_VERSION}"
   #echo "                     ArcGIS Enterprise Update Tool"
   echo ""
   echo "  ==================================================================="
   echo ""
   echo "  At any prompt, press the Return key to take the default option"
   echo "  shown in parenthesis or press 'q' to quit the installation process."
   #echo ""
   #echo "  Since you are currently running this installation on $CurrentPlatformUC, you"
   #echo "  will only be able to install $CurrentPlatformUC setups."
   echo ""
}


######################################################################
#=====================================================================
#  List_Valid_Selections()
#
#  
#=====================================================================
######################################################################
List_Valid_Selections()
{
   ThePosition=0

   # global
   TempFile1=/tmp/applypatch.tmp1.$$
   
   cat /dev/null > $TempFile1
  
   cd $ScriptDir

   #=============================================================
   #  Print valid Product-Platform selection header.
   #=============================================================
   #echo ""
   #echo "  The Current Valid Product-Platform Installation(s)"
   #echo "  Valid patches / hotfixes found:"
   echo "  The following patches / hotfixes will be applied:"
   echo ""
   #echo "  ==================================================================="

   
   #=============================================================
   #  Walk through the list of all files and directories in the
   #  current directory.
   #=============================================================
   #=============================================================
   # Find all SDE Clients first.
   #=============================================================
   for Item in $($LS -1d $CurrentPlatform.*)
   do
      
      #==========================================================
      #  Proceed to list availabe items (if applicable) if the
      #  current item is a directory.
      #==========================================================
      if [ -d "$Item" ]; then 
         
         #=======================================================
         #  Set the CurrentTOC variable to the current
         #  directories $ApplyPatchTOC file.
         #=======================================================
         CurrentTOC=$Item/$ApplyPatchTOC
         
         #=======================================================
         #  If the CurrentTOC exists, then we will use it to get
         #  the basic information for the current ESRI Patch 
         #  installation.
         #=======================================================
         if [ -f "$CurrentTOC" ]; then
        
            #====================================================
            #  Get the current TOC file's QFE patch product.
            #====================================================
            TheProduct=$(Get_Patch_Info Product $CurrentTOC)
	                
            #XXXXX===============================================
            #  Determine if the current TOC file's patch product
            #  is ArcSDE.
            #====================================================
            IsArcSDE=0
            case $(ToLower "$TheProduct") in 
               arcsde)
                  IsArcSDE=1
                  ;;
               *)
            esac
            
            if [ $IsArcSDE = 1 ]
            then
               #====================================================
               #  If the CurrentPlatform corresponds to the platform
               #  given in the current directory...we proceed to 
               #  get information from the Current TOC file that
               #  we need to display to the user so they can make a
               #  selection.
               #====================================================
               Result1=$(echo $Item | grep $CurrentPlatform)
               if [ "X$Result1" != "X" ]
               then
               
                  #=================================================
                  #  Get the product version, the product platform,
                  #  the QFE version and the QFE date.
                  #  Cut excess characters off the end of the 
                  #  information obtained.
                  #=================================================
                  TheVersion=$(Get_Patch_Info Version $CurrentTOC)
                  TheServPack=$(Get_Patch_Info ServicePack $CurrentTOC)
                  ThePlatform=$(Get_Patch_Info Platform $CurrentTOC)
                  TheQFEVersion=$(Get_Patch_Info QFEVersion $CurrentTOC)
                  TheQFEAbbreviated=$(Get_Patch_Info QFEGeneral $CurrentTOC)
                  TheQFEDate=$(Get_Patch_Info QFEDate $CurrentTOC)
                  TheBitSet=$(Get_Patch_Info BitSet $CurrentTOC)
                  TheDataBase=$(Get_Patch_Info DataBase $CurrentTOC)
                  TheDataDB=$(Get_Patch_Info DBInternal $CurrentTOC)
      	       
      	          if [ "$TheDataDB" = "$ArcSDKName" ]; then
               
                     #=================================================
                     #  Increment the position index.
                     #=================================================
                     ThePosition=$(expr $ThePosition + 1)
               
                     #XXXXX============================================
                     #  Echo out the current SDE-SDK product information for
                     #  user selection.  What is displayed to the user
                     #  depends upon the product.
                     #=================================================
                     #XXXXX=========================================
                     #  If the current platform is Tru64, then do 
                     #  not print out the bitset - it's redundent.
                     #==============================================
                     if [ "$CurrentPlatform" = "$Tru64Platform" ]; then
                        #echo "  ($ThePosition)  $TheProduct $TheVersion $ArcSDEClient $TheQFEAbbreviated ($TheQFEVersion) on $ThePlatform ($TheQFEDate)"
                        echo "  ($ThePosition)  $TheQFEVersion $TheQFEAbbreviated for ($TheProduct $TheVersion $ArcSDEClient) on $ThePlatform ($TheQFEDate)"
                     else
                        #echo "  ($ThePosition)  $TheProduct $TheVersion $ArcSDEClient $TheQFEAbbreviated ($TheQFEVersion) on $ThePlatform($TheBitSet-bit) ($TheQFEDate)"
                        #echo "  ($ThePosition)  $TheQFEVersion $TheQFEAbbreviated for ($TheProduct $TheVersion $ArcSDEClient) on $ThePlatform($TheBitSet-bit) ($TheQFEDate)"
                        echo "    * $TheQFEVersion $TheQFEAbbreviated for ($TheProduct $TheVersion $ArcSDEClient) on $ThePlatform($TheBitSet-bit) ($TheQFEDate)"
                     fi

                     #=================================================
                     #  Echo out the current position and the Current
                     #  TOC file to a temporary file.  This will be 
                     #  used later when the user makes a selection.
                     #=================================================
                     echo "($ThePosition) $CurrentTOC" >> $TempFile1
         	  fi
               fi
            fi            
         fi
      fi
   done
   
   if [ $ThePosition -ne 0 ]; then
      echo ""
   fi
   
   #=============================================================
   # Find all product info except ArcSDE Clients.
   #=============================================================
   for Item in $($LS -1d $CurrentPlatform.*)
   do
      
      #==========================================================
      #  Proceed to list available items (if applicable) if the
      #  current item is a directory.
      #==========================================================
      if [ -d "$Item" ]; then 
         
         #=======================================================
         #  Set the CurrentTOC variable to the current
         #  directories $ApplyPatchTOC file.
         #=======================================================
         CurrentTOC=$Item/$ApplyPatchTOC
         
         #=======================================================
         #  If the CurrentTOC exists, then we will use it to get
         #  the basic information for the current ESRI Patch 
         #  installation.
         #=======================================================
         if [ -f "$CurrentTOC" ]; then
         
            #====================================================
            #  Get the current TOC file's QFE patch product.
            #====================================================
            TheProduct=$(Get_Patch_Info Product $CurrentTOC)

            #====================================================
            #  Get the TOC Version and make sure it matches
            #  our TOC_VERSION.
            #====================================================
            TheTocVersion=$(Get_Patch_Info TOCVersion $CurrentTOC)

            CheckTOCVersion "$TheProduct" "$TheTocVersion"
            if [ $? -ne 0 ]; then
              echo "*** ERROR: The version of applypatch.toc does not match this applypatch version."
              echo ""
              echo "    $CurrentTOC"
              echo ""
              Clean_Up
              exit 1
            fi

            #XXXXX===============================================
            #  Determine if the current TOC file's patch product
            #  is ArcSDE.
            #====================================================
            IsArcSDE=0
            case $(ToLower "$TheProduct") in 
                arcsde)
                  IsArcSDE=1
                  ;;
                arcinfo)
                  TheProduct="${TheProduct} Workstation"
                  ;;
                arcserver)
                  TheProduct="ArcGIS Server"
                  ;;
                arcengine)
                  TheProduct="ArcGIS Engine ${VER}"
                  ;;
                arcreader)
                  TheProduct="ArcGIS ArcReader ${VER}"
                  ;;
                arcengcpp)
                  TheProduct="ArcGIS Engine Developer Kit for C++"
                  ;;
                arcengjava)
                  TheProduct="ArcGIS Engine Developer Kit for the Java Platform"
                  ;;
                arcobjcpp)
                  TheProduct="ArcObjects SDK for C++"
                  ;;
                arcobjjava)
                  TheProduct="ArcObjects SDK for the Java Platform"
                  ;;
                arcserverjava)
                  TheProduct="ArcGIS Server ADF for the Java Platform"
                  ;;
                arcimsjava)
                  TheProduct="ArcIMS Web ADF for the Java Platform"
                  ;;
                arcmapserver)
                  TheProduct="ArcIMS ArcMap Server"
                  ;;
                arcgisjavahelp)
                  TheProduct="ArcGIS Help System for the Java Platform"
                  ;;
                mole)
                  TheProduct="ArcGIS Military Overlay Editor"
                  ;;
                ma)
                  TheProduct="ArcGIS Military Analyst"
                  ;;
                arcwebadaptor)
                  TheProduct="ArcGIS Web Adaptor ${VER} for the Java Platform"
                  ;;
                arcgisportal)
                  TheProduct="Portal for ArcGIS"
                  ;;				  
                arcsds)
                  TheProduct="ArcGIS Spatial Data Server ${VER} for the Java Platform"
                  ;;
                datastore)
                  TheProduct="ArcGIS Data Store"
                  ;;
                notebookserver)
                  TheProduct="ArcGIS Notebook Server"
                  ;;
                missionserver)
                  TheProduct="ArcGIS Mission Server"
                  ;;
                licensemanager)
                  TheProduct="ArcGIS License Manager ${VER}"
                  ;;
                insightsportal)
                  TheProduct="ArcGIS Insights (Portal) ${VER}"
                  ;;
                insightsserver)
                  TheProduct="ArcGIS Insights (Server) ${VER}"
                  ;;
                urban)
                  TheProduct="ArcGIS Urban ${VER}"
                  ;;
                videoserver)
                  TheProduct="ArcGIS Video Server"
                  ;;
                datapipelinesserver)
                  TheProduct="ArcGIS Data Pipelines Server"
                  ;;
               *)
            esac

            #====================================================
            #  If the CurrentPlatform corresponds to the platform
            #  given in the current directory...we proceed to 
            #  get information from the Current TOC file that
            #  we need to display to the user so they can make a
            #  selection.
            #====================================================
            Result1=$(echo $Item | grep $CurrentPlatform)
            if [ "X$Result1" != "X" ]; then
               
               #=================================================
               #  Get the product version, the product platform,
               #  the QFE version and the QFE date.
               #  Cut excess characters off the end of the 
               #  information obtained.
               #=================================================
               TheVersion=$(Get_Patch_Info Version $CurrentTOC)
               TheServPack=$(Get_Patch_Info ServicePack $CurrentTOC)
               ThePreHotFix=$(Get_Patch_Info PreHotFix $CurrentTOC)
               ThePHFTitle=$(Get_Patch_Info PHFTitle $CurrentTOC)
               ThePlatform=$(Get_Patch_Info Platform $CurrentTOC)
               TheQFENumber=$(Get_Patch_Info QFEID $CurrentTOC)
               TheQFEVersion=$(Get_Patch_Info QFEVersion $CurrentTOC)
               TheQFEAbbreviated=$(Get_Patch_Info QFEGeneral $CurrentTOC)
               TheQFEDate=$(Get_Patch_Info QFEDate $CurrentTOC)
               
               #XXXXX============================================
               #  If the current product is ArcSDE, get the
               #  product bitset and the product database.
               #=================================================
               if [ $IsArcSDE = 1 ]; then
                  TheBitSet=$(Get_Patch_Info BitSet $CurrentTOC)
                  TheDataBase=$(Get_Patch_Info DataBase $CurrentTOC)
                  TheDataDB=$(Get_Patch_Info DBInternal $CurrentTOC)
               fi

               #XXXXX============================================
               #  Echo out the current product information for
               #  user selection.  What is displayed to the user
               #  depends upon the product.
               #=================================================
               if [ $IsArcSDE = 1 ]; then
               
                  #==============================================
                  # List ArcSDE Server Product info.
                  #==============================================
                  if [ $TheDataDB != $ArcSDKName ]; then
                  
                     #=================================================
                     #  Increment the position index.
                     #=================================================
                     ThePosition=$(expr $ThePosition + 1)
                     
                     #XXXXX=========================================
                     #  If the current platform is Tru64, then do 
                     #  not print out the bitset - it's redundent.
                     #==============================================
                     if [ $CurrentPlatform = $Tru64Platform ]; then
                        #echo "  ($ThePosition)  $TheProduct $TheVersion $ArcSDEServer $TheQFEAbbreviated ($TheQFEVersion) for $TheDataBase on $ThePlatform ($TheQFEDate)"
                        echo "  ($ThePosition)  $TheQFEVersion $TheQFEAbbreviated for ($TheProduct $TheVersion $ArcSDEServer for $TheDataBase) on $ThePlatform ($TheQFEDate)"
                     else
                        #echo "  ($ThePosition)  $TheProduct $TheVersion $ArcSDEServer $TheQFEAbbreviated ($TheQFEVersion) for $TheDataBase on $ThePlatform($TheBitSet-bit) ($TheQFEDate)"
                        #echo "  ($ThePosition)  $TheQFEVersion $TheQFEAbbreviated for ($TheProduct $TheVersion $ArcSDEServer for $TheDataBase) on $ThePlatform($TheBitSet-bit) ($TheQFEDate)"
                        echo "    * $TheQFEVersion $TheQFEAbbreviated for ($TheProduct $TheVersion $ArcSDEServer for $TheDataBase) on $ThePlatform($TheBitSet-bit) ($TheQFEDate)"
                     fi
                  
                     #=================================================
                     #  Echo out the current position and the Current
                     #  TOC file to a temporary file.  This will be 
                     #  used later when the user makes a selection.
                     #=================================================
                     echo "($ThePosition) $CurrentTOC" >> $TempFile1
                  fi
               else
               
                  #=================================================
                  #  Set the Platform for IMSADF
                  #=================================================
                  if [ "$TheProduct" = "ArcIMS Web ADF for the Java Platform" -o "$TheProduct" = "ArcGIS Help System for the Java Platform" ]
                  then
                     if [ $(uname) = "Linux" ]
                     then
                        ThePlatform=Linux
                     elif [ $(uname) = "HP-UX" ]
                     then
                        ThePlatform=HP
                     elif [ $(uname) = "AIX" ]
                     then
                        ThePlatform=IBM
                     else
                        ThePlatform=Solaris
                     fi
                  fi
                  
                  #=================================================
                  #  Increment the position index.
                  #=================================================
                  ThePosition=$(expr $ThePosition + 1)
                  #echo "  ($ThePosition)  $TheProduct $TheVersion $TheQFEAbbreviated ($TheQFEVersion) on $ThePlatform ($TheQFEDate)"
                  #echo "  ($ThePosition)  $TheQFEVersion for ($TheProduct) on $ThePlatform ($TheQFEDate)"
                  echo "    * $TheQFEVersion for ($TheProduct) on $ThePlatform ($TheQFEDate)"
                  
                  #=================================================
                  #  Echo out the current position and the Current
                  #  TOC file to a temporary file.  This will be 
                  #  used later when the user makes a selection.
                  #=================================================
                  echo "($ThePosition) $CurrentTOC" >> $TempFile1
               fi
            fi            
         fi
      fi
   done
   
   #=============================================================
   #  If ThePosition counter is 0, we didn't find any valid
   #  installable QFE setups.  Print a message to the user,
   #  clean up and exit.
   #=============================================================
   if [ $ThePosition -eq 0 ]; then
      echo ""
      echo "***ERROR:"
      echo "  There are no valid ESRI setups available."
      echo "  Please verify:"
      echo ""
      echo "  1.  You are running on the same platform/OS for the QFE"
      echo "      setup being installed."
      echo "  2.  You have downloaded the appropriate ESRI setup."
      echo "  3.  The applypatch installation script exists in the"
      echo "      same directory that the downloaded ESRI setup"
      echo "      directory exists."
      echo ""
      echo "  Cleaning up and exiting..."
      echo ""
      Clean_Up
      exit 1
   fi

   #echo ""
}


######################################################################
#=====================================================================
#  Clean_Up() 
#
#  Delete any temporary files we might have created.
#=====================================================================
######################################################################
Clean_Up() 
{
   rm -f $TmpPatchFile
   rm -f $UpdatedTOCFile
   rm -f $TempFile1
   rm -f $ValidationErrorList
   cd $CurrentWorkingDir > /dev/null 2>&1
}


######################################################################
#=====================================================================
#  Get_Patch_Info()
#
#  Get information from about the patch from the patch TOC file.
#=====================================================================
######################################################################
Get_Patch_Info()
{
  local res=""
  #XXXXX========================================================
  #  Get appropriate information about the selected patch from 
  #  its corresponding TOC file.
  #=============================================================
  case $1 in
    Product)
      res=$(cat $2 | awk '/^#PN#/{print $2}')
      ;;
    Version)
      res=$(cat $2 | awk '/^#PV#/{print $2}')
      ;;
    ProductFlag)
      res=$(cat $2 | awk '/^#PF#/{print $2}')
      ;;
    ServicePack)
      res=$(cat $2 | awk '/^#PS#/{print $2, $3}')
      ;;
    PreHotFix)
      res=$(cat $2 | awk '/^#PH#/{print $2, $3}')
      ;;
    PHFTitle)
      res=$(cat $2 | awk '/^#HT#/{print $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16}')
      ;;
    QFEID)
      res=$(cat $2 | awk '/^#QI#/{print $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16}')
      ;;
    Platform)
      res=$(cat $2 | awk '/^#PL#/{print $2, $3, $4}')
      ;;
    QFEVersion)
      res=$(cat $2 | awk '/^#QV#/{print $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16}')
      ;;
    QFEGeneral)
      res=$(cat $2 | awk '/^#QG#/{print $2, $3, $4, $5}')
      ;;
    QFEDate)
      res=$(cat $2 | awk '/^#QD#/{print $2, $3, $4, $5}')
      ;;
    BitSet)
      res=$(cat $2 | awk '/^#BS#/{print $2}')
      ;;
    DataBase)
      res=$(cat $2 | awk '/^#DB#/{print $2, $3, $4}')
      ;;
    DBInternal)
      res=$(cat $2 | awk '/^#DI#/{print $2, $3}')
      ;;
    AllDataBases)
      res=$(cat $2 | awk '/^#AD#/{print $2, $3, $4, $5, $6, $7, $8, $9}')
      ;;
    PlatInternal)
      res=$(cat $2 | awk '/^#PI#/{print $2, $3}')
      ;;
    TOCVersion)
      res=$(cat $2 | awk '/^#TV#/{print $2}')
      ;;
    FileName)
      res=$(cat $2 | awk '/^#FN#/{print $2}')
      ;;
    IsBaselinePatch)
      res=$(cat $2 | grep "^#BP#" | cut -d' ' -f2-)
      ;;
    BaselinePatchName)
      res=$(cat $2 | grep "^#BN#" | cut -d' ' -f2-)
      ;;
    BaselinePatchQfeId)
      res=$(cat $2 | grep "^#BQ#" | cut -d' ' -f2-)
      ;;
    BaselinePatchUrl)
      res=$(cat $2 | grep "^#BU#" | cut -d' ' -f2-)
      ;;
   esac
  
   echo $(Cut_String "$res")
}


######################################################################
#=====================================================================
#  Cut_String()
#
#  Cuts the blanks from the end of the given string.
#=====================================================================
######################################################################
Cut_String()
{
   length=$(LenChr "$1")
   echo "$1" | cut -c1-$length
}


######################################################################
#=====================================================================
#  LenChr() 
#
#  Determine length of string - including trailing CR/LF.
#=====================================================================
######################################################################
LenChr() 
{
   echo "$1" | wc -c | awk '{print $1}'
}


######################################################################
#=====================================================================
# ToLower/ToUpper()
#
# Convert a string to lower or upper case
#=====================================================================
######################################################################
ToLower()
{
  echo "$1" | tr '[A-Z]' '[a-z]'
}
ToUpper()
{
  echo "$1" | tr '[a-z]' '[A-Z]'
}

######################################################################
#=====================================================================
# Prompt()
#
# Show a prompt and get a response on the same line.
#=====================================================================
######################################################################
Prompt()
{
  local prompt="$1"

  printf "\n%s" "${prompt}"
  #echo ""

  # If -n is not supported use \c to get a one-line
  #echo -n "" > /dev/null 2>&1
  #if [ $? -ne 0 ]; then
  #  echo "${prompt} \c"
  #else
  #  echo -n "${prompt}"
  #fi
}


######################################################################
#=====================================================================
#  User_Selection_Process()
#
#=====================================================================
######################################################################
User_Selection_Process()
{

   #=============================================================
   #  Initialize valid choice indicator.
   #=============================================================
   local -i ValidChoice=0

   # FORCE THE FIRST CHOICE FOR SERVER PRODUCTS
   local product=$(Get_Patch_Info Product $CurrentTOC)
   if $(IsServerProduct $product) ; then
     ValidChoice=1
     Choice=1
     Reiterate_Choice
   fi
   
   #=============================================================
   #  While no valid choice has been selected, print out
   #  available QFE patch installation selections.
   #=============================================================
   while [ $ValidChoice -eq  0 ]
   do

      #XXXXX=====================================================
      #  Prompt the user to make a selection from those listed
      #  read user's selection.
      #==========================================================

      Prompt "  Please make a selection from the list above [q] (1): "

      read Choice

      #==========================================================
      #  Perform actions based upon user's choice.
      #==========================================================

      case "X${Choice}" in
         X)   
            ValidChoice=1
            Choice=1
            Reiterate_Choice
            ;;
         X[1-9]|X[1-9][0-9])
            if [ $Choice -le $ThePosition ] && [ $Choice -gt 0 ]; then
               ValidChoice=1
               Reiterate_Choice
            fi
            ;;
         Xq|XQ)
            Voluntary_Quit
            ;;
      esac


# DELETEME: This re-prompting for the selection they just made is unnecessary.
#
      #==========================================================
      #  If a valid choice was made, the choice will be 
      #  reiterated.  Prompt the user to verify that the 
      #  reiterated choice was the one intended.  If yes, then
      #  continue to set ValidChoice to 1 so we can exit the 
      #  loop.  Otherwise, set ValidChoice to 0 to repeat the
      #  loop.
      #==========================================================
#      if [ $ValidChoice -eq 1 ]
#      then
#      
#         #XXXXX==================================================
#         #  Verify (with the user) that the selection they made
#         #  (and just reiterated) is correct.
#         #=======================================================
#         echo ""
#
#         Prompt "Is this the correct selection? [y,n,q] (y): "
#
#         read NewChoice
#
#         #=======================================================
#         #  Perform actions based upon users choice.
#         #=======================================================
#         case $(ToLower "${NewChoice}") in
#            ""|y*)   
#               ValidChoice=1
#               ;;
#            n*)
#               ValidChoice=0
#               ;;
#            q*)
#               Voluntary_Quit
#               ;;
#         esac
#      fi

   done
   
   
   #=============================================================
   #  Remove the temporary file containing all valid selections.
   #=============================================================
   rm -f $TempFile1

}


######################################################################
#=====================================================================
#  Reiterate_Choice()
#
#=====================================================================
######################################################################
Reiterate_Choice()
{

   cd $ScriptDir

   if [ $SilentInstall -eq 1 ]; then

      if [ -z "$SilentProd" ]; then
        SilentProd=$(ls -1d ${CurrentPlatform}.* | cut -d. -f2)
      fi

      SelectedTOC="${CurrentPlatform}.${SilentProd}/${ApplyPatchTOC}"
   else
      
   #=============================================================
   #  Based upon the user's choice, determine the selected QFE
   #  patch TOC file.
   #=============================================================
      SelectedTOC=$(cat $TempFile1 | grep "^($Choice)" | awk '{print $2}')
   fi

   #=============================================================
   #  Verify that the SelectedTOC file exists.  If it doesn't,
   #  print an error message to the user, clean up and exit.
   #=============================================================
   if [ ! -f "$ScriptDir/$SelectedTOC" ]; then
      echo ""
      echo "*** ERROR:"
      echo "  Unable to validate the selected option's TOC file existence."
      echo ""
      echo "  TOC file path:  $ScriptDir/$SelectedTOC"
      echo ""
      echo "  Cleaning up and exiting..."
      echo ""
      Clean_Up
      exit 1
   fi
   
   #=============================================================
   #  Get the Selected TOC file's QFE patch product.
   #=============================================================
   ProductName=$(Get_Patch_Info Product $SelectedTOC)
   ProductVersion=$(Get_Patch_Info Version $SelectedTOC)
   ProductFlag=$(Get_Patch_Info ProductFlag $SelectedTOC)

   # TODO: Remove setting ProductFolderName for each product and
   # instead just set it to $ProductFlag
   # ProductFolderName="$ProductFlag"

   #XXXXX========================================================
   #  Set flag to determine product.  If unable to determine
   #  product, print error message, clean up and exit.
   #=============================================================
   case $(ToLower "$ProductName") in 
      arcims)
         ArcIMS=1
         ProdHomeName="AIMSHOME"
         ProductHome=$AIMSHOME
         ProductDispName=$ProductName
         QFETestFile=".ESRI_IMS_PATCH_LOG"
         ;;
      arcinfo)
         ArcInfo=1
         ProdHomeName="ARCHOME"
         ProductHome=$ARCHOME
         ProductDispName="${ProductName} Workstation"
         QFETestFile=".ESRI_WS_PATCH_LOG"
         ;;
      arcsde)
         ArcSDE=1
         ProdHomeName="SDEHOME"
         ProductHome=$SDEHOME
         ProductDispName=$ProductName
         QFETestFile=".ESRI_SDE_PATCH_LOG"
         ;;
      arcserver)
         ArcGIS=1
         ProdHomeName=""
         ProductHome=""
         DevkitHome=""

         if [ $ProductVersion = "9.2" ] || [ $ProductVersion = "9.3" ] || [ $ProductVersion = "9.3.1" ]; then
           if [ -f "/etc/mainwin.conf" ]; then
             agstmp=$(grep "^CORE_USERMAP=" /etc/mainwin.conf | cut -f 2 -d '=')
             if [ "x$agstmp" != "x" ]; then
               agsdir=$(dirname $agstmp)
               if [ -f "$agsdir/init_server.sh" ]; then
                 . $agsdir/init_server.sh
                 ProdHomeName="ARCGISHOME"
                 ProductHome="$ARCGISHOME"
               fi
             fi
           fi
         else
           ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
           ProductHome="$Z_ArcGISServer_INSTALL_DIR"
           DevkitHome="$Z_DEVKIT_HOME"
         fi

         ProductDispName="ArcGIS Server"
         QFETestFile=".ESRI_S_PATCH_LOG"
         ProductFolderName="server"
         ;;
      arcengine)
         ArcGIS=1
         ProdHomeName="Z_ArcGISEngineRT_INSTALL_DIR"
         ProductHome="$Z_ArcGISEngineRT_INSTALL_DIR"
         ProductDispName="ArcGIS Engine ${VER}"
         QFETestFile=".ESRI_E_PATCH_LOG"
         ProductFolderName="engine"
         ;;
      arcreader)
         ArcGIS=1
         ProdHomeName="Z_ArcReader_INSTALL_DIR"
         ProductHome="$Z_ArcReader_INSTALL_DIR"
         ProductDispName="ArcGIS ArcReader ${VER}"
         QFETestFile=".ESRI_R_PATCH_LOG"
         ProductFolderName="arcreader"
         ;;
      arcengcpp)
         ArcGIS=1
         ProdHomeName="Z_ArcGISEngineDevKitCPP_INSTALL_DIR"
         ProductHome="$Z_ArcGISEngineDevKitCPP_INSTALL_DIR"
         ProductDispName="ArcGIS Engine Developer Kit for C++"
         QFETestFile=".ESRI_ENGCPP_PATCH_LOG"
         ProductFolderName="engcpp"
         ;;
      arcengjava)
         ArcGIS=1
         ProdHomeName="Z_ArcGISEngineDevKitJava_INSTALL_DIR"
         ProductHome="$Z_ArcGISEngineDevKitJava_INSTALL_DIR"
         ProductDispName="ArcGIS Engine Developer Kit for the Java Platform"
         QFETestFile=".ESRI_ENGJAVA_PATCH_LOG"
         ProductFolderName="engjava"
         ;;
      arcobjcpp)
         ArcGIS=1
         ProdHomeName="Z_ArcObjectsSDKCPP_INSTALL_DIR"
         ProductHome="$Z_ArcObjectsSDKCPP_INSTALL_DIR"
         ProductDispName="ArcObjects SDK for C++"
         QFETestFile=".ESRI_ARCOBJCPP_PATCH_LOG"
         ProductFolderName="arcobjcpp"
         ;;
      arcobjjava)
         ArcGIS=1
         ProdHomeName="Z_ArcObjectsSDKJava_INSTALL_DIR"
         ProductHome="$Z_ArcObjectsSDKJava_INSTALL_DIR"
         ProductDispName="ArcObjects SDK for the Java Platform"
         QFETestFile=".ESRI_ARCOBJJAVA_PATCH_LOG"
         ProductFolderName="arcobjjava"
         ;;
      arcserverjava)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServerJavaADF_INSTALL_DIR"
         ProductHome="$Z_ArcGISServerJavaADF_INSTALL_DIR"
         ProductDispName="ArcGIS Server ADF for the Java Platform"
         QFETestFile=".ESRI_SRVRJAVA_PATCH_LOG"
         ProductFolderName="srvrjava"
         ;;
      arcimsjava)
         ArcGIS=1
         ProdHomeName="Z_ArcIMSJavaADF_INSTALL_DIR"
         ProductHome="$Z_ArcIMSJavaADF_INSTALL_DIR"
         DevkitHome="$Z_DEVKIT_HOME"
         ProductDispName="ArcIMS Web ADF for the Java Platform"
         QFETestFile=".ESRI_IMSJAVA_PATCH_LOG"
         ProductFolderName="imsjava"
         ;;
      arcmapserver)
         ArcGIS=1
         ProdHomeName="Z_ENGINE_HOME"
         ProductHome="$Z_ENGINE_HOME"
         ProductDispName="ArcIMS ArcMap Server"
         QFETestFile=".ESRI_MAPSRVR_PATCH_LOG"
         ProductFolderName="mapsrvr"
         ;;
      arcgisjavahelp)
         ArcGIS=1
         ProdHomeName="Z_ArcGISJavaDoc_INSTALL_DIR"
         ProductHome="$Z_ArcGISJavaDoc_INSTALL_DIR"
         ProductDispName="ArcGIS Help System for the Java Platform"
         QFETestFile=".ESRI_JAVAHELP_PATCH_LOG"
         ProductFolderName="javahelp"
         ;;
      arcwebadaptor)
         ArcGIS=1
         ProdHomeName="Z_WebAdaptor_INSTALL_DIR"
         ProductHome="$Z_WebAdaptor_INSTALL_DIR"
         ProductDispName="ArcGIS Web Adaptor for the Java Platform"
         QFETestFile=".ESRI_WA_PATCH_LOG"
         ProductFolderName="webadaptor"
         ;;
      arcgisportal)
         ArcGIS=1
         ProdHomeName="Z_ArcGISPortal_INSTALL_DIR"
         ProductHome="$Z_ArcGISPortal_INSTALL_DIR"
         ProductDispName="Portal for ArcGIS"
         QFETestFile=".ESRI_P_PATCH_LOG"
         ProductFolderName="portal"
         ;;
      arcsds)
         ArcGIS=1
         ProdHomeName="Z_ArcGISSpatialDataServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISSpatialDataServer_INSTALL_DIR"
         ProductDispName="ArcGIS Spatial Data Server ${VER} for the Java Platform"
         QFETestFile=".ESRI_SDS_PATCH_LOG"
         ProductFolderName="sds"
         ;;
      datastore)
         ArcGIS=1
         ProdHomeName="Z_ArcGISDataStore_INSTALL_DIR"
         ProductHome="$Z_ArcGISDataStore_INSTALL_DIR"
         ProductDispName="ArcGIS Data Store"
         QFETestFile=".ESRI_DS_PATCH_LOG"
         ProductFolderName="datastore"
         ;;
      geoenrichmentserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISGeoEnrichmentServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISGeoEnrichmentServer_INSTALL_DIR"
         ProductDispName="ArcGIS GeoEnrichment Server"
         QFETestFile=".ESRI_DE_PATCH_LOG"
         ProductFolderName="geoenrichmentserver"
         ;;
      notebookserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISNotebookServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISNotebookServer_INSTALL_DIR"
         ProductDispName="ArcGIS Notebook Server"
         QFETestFile=".ESRI_NBS_PATCH_LOG"
         ProductFolderName="notebookserver"
         ;;
      missionserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISMissionServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISMissionServer_INSTALL_DIR"
         ProductDispName="ArcGIS Mission Server"
         QFETestFile=".ESRI_MS_PATCH_LOG"
         ProductFolderName="missionserver"
         ;;
      insightsportal)
         ArcGIS=1
         ProdHomeName="Z_ArcGISPortal_Insights_INSTALL_DIR"
         ProductHome="$Z_ArcGISPortal_Insights_INSTALL_DIR"
         ProductDispName="ArcGIS Insights (Portal)"
         QFETestFile=".ESRI_INSIGHTS_PATCH_LOG"
         ProductFolderName="$ProductFlag"
         ;;
      insightsserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_Insights_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_Insights_INSTALL_DIR"
         ProductDispName="ArcGIS Insights (Server)"
         QFETestFile=".ESRI_INSIGHTS_PATCH_LOG"
         ProductFolderName="$ProductFlag"
         ;;
      mole)
         ArcGIS=1
         if [ "$ProductVersion" = "9.2" ]; then
            ProdHomeName="Z_Mole_INSTALL_DIR"
            ProductHome="$Z_Mole_INSTALL_DIR"
         else
            ProdHomeName="Z_MOLE_INSTALL_DIR"
            ProductHome="$Z_MOLE_INSTALL_DIR"
         fi
         ProductDispName="ArcGIS Military Overlay Editor"
         QFETestFile=".ESRI_MOLE_PATCH_LOG"
         ProductFolderName="mole"
         ;;
      moleengine)
         ArcGIS=1
         ProdHomeName="Z_ArcGISEngineRT_INSTALL_DIR"
         ProductHome="$Z_ArcGISEngineRT_INSTALL_DIR"
         ProductDispName="ArcGIS Military Overlay Editor for Engine"
         QFETestFile=".ESRI_MOLEE_PATCH_LOG"
         ProductFolderName="moleengine"
         ;;
      molereader)
         ArcGIS=1
         ProdHomeName="Z_ArcReader_INSTALL_DIR"
         ProductHome="$Z_ArcReader_INSTALL_DIR"
         ProductDispName="ArcGIS Military Overlay Editor for ArcReader"
         QFETestFile=".ESRI_MOLER_PATCH_LOG"
         ProductFolderName="molearcreader"
         ;;
      moleserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Military Overlay Editor for Server"
         QFETestFile=".ESRI_MOLES_PATCH_LOG"
         ProductFolderName="moleserver"
         ;;
      ma)
         ArcGIS=1
         ProdHomeName="Z_MilitaryAnalyst_INSTALL_DIR"
         ProductHome="$Z_MilitaryAnalyst_INSTALL_DIR"
         ProductDispName="ArcGIS Military Analyst"
         QFETestFile=".ESRI_MA_PATCH_LOG"
         ProductFolderName="ma"
         ;;
      maengine)
         ArcGIS=1
         ProdHomeName="Z_ArcGISEngineRT_INSTALL_DIR"
         ProductHome="$Z_ArcGISEngineRT_INSTALL_DIR"
         ProductDispName="ArcGIS Military Analyst for Engine"
         QFETestFile=".ESRI_MAE_PATCH_LOG"
         ProductFolderName="maengine"
         ;;
      mareader)
         ArcGIS=1
         ProdHomeName="Z_ArcReader_INSTALL_DIR"
         ProductHome="$Z_ArcReader_INSTALL_DIR"
         ProductDispName="ArcGIS Military Analyst for ArcReader"
         QFETestFile=".ESRI_MAR_PATCH_LOG"
         ProductFolderName="maarcreader"
         ;;
      maserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Military Analyst for Server"
         QFETestFile=".ESRI_MAS_PATCH_LOG"
         ProductFolderName="maserver"
         ;;
      licensemanager)
         ArcGIS=1
         if [ "$ProductVersion" = "$LM_VERSION" ]; then
            ProdHomeName="Z_LicenseManager_INSTALL_DIR"
            ProductHome="$LM_INSTALL_DIR"
         else
            ProdHomeName=""
            ProductHome=""
         fi
         ProductDispName="ArcGIS License Manager ${VER}"
         QFETestFile=".ESRI_LM_PATCH_LOG"
         ProductFolderName="lm"
         ;;
      serverlpes)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Server for the Java Platform Spanish Supplement"
         QFETestFile=".ESRI_SLPES_PATCH_LOG"
         ProductFolderName="serverlpes"
         ;;
      serverlpfr)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Server for the Java Platform French Supplement"
         QFETestFile=".ESRI_SLPFR_PATCH_LOG"
         ProductFolderName="serverlpfr"
         ;;
      serverlpja)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Server for the Java Platform Japanese Supplement"
         QFETestFile=".ESRI_SLPJA_PATCH_LOG"
         ProductFolderName="serverlpja"
         ;;
      serverlpde)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Server for the Java Platform German Supplement"
         QFETestFile=".ESRI_SLPDE_PATCH_LOG"
         ProductFolderName="serverlpde"
         ;;
      serverlpzhcn)
         ArcGIS=1
         ProdHomeName="Z_ArcGISServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISServer_INSTALL_DIR"
         ProductDispName="ArcGIS Server for the Java Platform Simplified Chinese Supplement"
         QFETestFile=".ESRI_SLPZHCN_PATCH_LOG"
         ProductFolderName="serverlpzhcn"
         ;;
      urban)
         ArcGIS=1
         ProdHomeName="Z_ArcGISPortal_ArcGISUrban_INSTALL_DIR"
         ProductHome="$Z_ArcGISPortal_ArcGISUrban_INSTALL_DIR"
         ProductDispName="ArcGIS Urban"
         QFETestFile=".ESRI_P_U_PATCH_LOG"
         ProductFolderName="urban"
        ;;
      videoserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISVideoServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISVideoServer_INSTALL_DIR"
         ProductDispName="ArcGIS Video Server"
         QFETestFile=".ESRI_VIDEO_SERVER_PATCH_LOG"
         ProductFolderName="videoserver"
         ;;
      datapipelinesserver)
         ArcGIS=1
         ProdHomeName="Z_ArcGISDataPipelinesServer_INSTALL_DIR"
         ProductHome="$Z_ArcGISDataPipelinesServer_INSTALL_DIR"
         ProductDispName="ArcGIS Data Pipelines Server"
         QFETestFile=".ESRI_DPS_PATCH_LOG"
         ProductFolderName="datapipelinesserver"
         ;;
      *)
         echo ""
         echo ""
         echo "*** ERROR:"
         echo "  Unable to determine product from supplied TOC file."
         echo "  The ESRI Patch installation has failed."
         echo ""
         echo "  Cleaning up and Exiting..."
         echo ""
         Clean_Up
         exit 1
   esac

   #=============================================================
   #  Get appropriate QFE patch information from the Selected
   #  TOC.  Cut excess characters off of the end of the info
   #  obtained.
   #=============================================================
   ProductVersion=$(Get_Patch_Info Version $SelectedTOC)
   
   ProductSerPack=$(Get_Patch_Info ServicePack $SelectedTOC)
   
   ProductPreHotFix=$(Get_Patch_Info PreHotFix $SelectedTOC)
   ProductPHFTitle=$(Get_Patch_Info PHFTitle $SelectedTOC)
   
   ProductPlatform=$(Get_Patch_Info Platform $SelectedTOC)
   QFENumber=$(Get_Patch_Info QFEID $SelectedTOC)
   QFEVersion=$(Get_Patch_Info QFEVersion $SelectedTOC)
   QFEDate=$(Get_Patch_Info QFEDate $SelectedTOC)
   QFEAbbreviated=$(Get_Patch_Info QFEGeneral $SelectedTOC)

   OriginalPatchFilename=$(Get_Patch_Info FileName $SelectedTOC)

   #=================================================
   # Get baseline patch info from TOC
   #=================================================
   IsBaselinePatch=$(Get_Patch_Info IsBaselinePatch $SelectedTOC)
   BaselinePatchName=$(Get_Patch_Info BaselinePatchName $SelectedTOC)
   BaselinePatchQfeId=$(Get_Patch_Info BaselinePatchQfeId $SelectedTOC)
   BaselinePatchUrl=$(Get_Patch_Info BaselinePatchUrl $SelectedTOC)

   #=================================================
   #  Set the Platform for IMSADF and JavaHelp
   #=================================================
   if [ "$ProductDispName" = "ArcIMS Web ADF for the Java Platform" ] ||
      [ "$ProductDispName" = "ArcGIS Help System for the Java Platform" ]
   then
      if [ $(uname) = "Linux" ]; then
         ProductPlatform=Linux
      elif [ $(uname) = "HP-UX" ]; then
         ProductPlatform=HP
      elif [ $(uname) = "AIX" ]; then
         ProductPlatform=IBM
      else
         ProductPlatform=Solaris
      fi
   fi

   ArcSDESet=""
   
   #XXXXX=======================================================
   #  If the current product is ArcSDE, get appropriate QFE patch
   #  information related to ArcSDE.  Cut excess characters off
   #  of the end of the info obtained.
   #=============================================================
   if [ $ArcSDE = 1 ]; then
      ProductBitSet=$(Get_Patch_Info BitSet $SelectedTOC)
      CurrentDBFormal=$(Get_Patch_Info DataBase $SelectedTOC)
      CurrentDB=$(Get_Patch_Info DBInternal $SelectedTOC)
      if [ "$CurrentDB" = "$ArcSDKName" ]; then 
         ArcSDESet=$ArcSDEClient
      else
         ArcSDESet=$ArcSDEServer
      fi
   fi

   #XXXXX=======================================================
   #  Reiterate the choice to the user for their verification.
   #=============================================================
   #echo ""
#   if [ $ArcSDE = 1 ]; then
#      if [ "$CurrentPlatform" = "$Tru64Platform" ]; then
#         if [ "$CurrentDB" = "$ArcSDKName" ]; then
#            echo "    $QFEVersion $QFEAbbreviated for ($ProductDispName $ProductVersion $ArcSDEClient) on $ProductPlatform ($QFEDate)"
#         else
#            echo "    $QFEVersion $QFEAbbreviated for ($ProductDispName $ProductVersion $ArcSDEServer for $CurrentDBFormal) on $ProductPlatform ($QFEDate)"
#         fi
#      else
#         if [ "$CurrentDB" = "$ArcSDKName" ]; then
#            echo "    $QFEVersion $QFEAbbreviated for ($ProductDispName $ProductVersion $ArcSDEClient) on $ProductPlatform($ProductBitSet-bit) ($QFEDate)"
#         else
#            echo "    $QFEVersion $QFEAbbreviated for ($ProductDispName $ProductVersion $ArcSDEServer for $CurrentDBFormal) on $ProductPlatform($ProductBitSet-bit) ($QFEDate)"
#         fi
#      fi
#   else
#      echo "    $QFEVersion for ($ProductDispName) on $ProductPlatform ($QFEDate)"
#   fi
#   echo ""
}


######################################################################
#=====================================================================
#  Voluntary_Quit()
#
#  If the user selects to quit, print out a message, clean up and 
#  exit.
#=====================================================================
######################################################################
Voluntary_Quit()
{
   echo ""
   echo "  *** Exiting.  Run $PROG again to install this update."
   echo ""
   Clean_Up
   exit 0
}


######################################################################
#=====================================================================
#  Validate_Patch_Home()
#
#  Validating PatchHome amounts to making sure we can find the patch
#  directory for $CurrentPlatform, and subsequently the TOC and TAR 
#  files.
#=====================================================================
######################################################################
Validate_Patch_Home() 
{

   #=============================================================
   #  First, make sure we have an absolute path-name to this 
   #  directory.  Some possible variations on the command line:
   #     .  applypatch
   #     .  ./applypatch
   #     .  dirname/applypatch
   #     .  /drive/dirname/applypatch
   #     .  ../dirname/applypatch
   #=============================================================
   
   PatchHome=$ScriptDir
   #=============================================================
   	
   #XXXXX========================================================
   #  Second, test for patch directory.
   #=============================================================
   DirNotFound="no"   
   if [ $ArcSDE = 1 ]; then
      if [ "$ProductBitSet" = "64" ] && [ "$CurrentPlatform" != "$Tru64Platform" ]; then
         TempPath="$PatchHome/$CurrentPlatform$ProductBitSet.$CurrentDB"
      else
         TempPath="$PatchHome/$CurrentPlatform.$CurrentDB"
      fi
   else 
      if [ $ArcGIS = 1 ]; then
         TempPath="$PatchHome/$CurrentPlatform.$ProductFolderName"
         if [ "$ProductDispName" = "ArcGIS Server ADF for the Java Platform" ]; then
            TempPath="$PatchHome/hp_ibm.$ProductFolderName"
        # elif [ "$ProductDispName" = "ArcIMS Web ADF for the Java Platform" ]
        # then
        #    TempPath="$PatchHome/linux_solaris.$ProductFolderName"
         elif [ "$ProductDispName" = "ArcGIS Help System for the Java Platform" ]; then
            TempPath="$PatchHome/linux_solaris.$ProductFolderName"
         fi
      else
         TempPath="$PatchHome/$CurrentPlatform"
      fi
   fi
   
   if [ ! -d "$TempPath" ]; then
      DirNotFound="yes"      
   fi
      
   #=============================================================
   #  Now, look for files.
   #=============================================================
   FilesNotFound="no"
   if [ ! -r "$TempPath/$ApplyPatchTOC" ] || [ ! -r "$TempPath/$ApplyPatchTAR" ]; then
      FilesNotFound="yes"
   fi

   #=============================================================
   #  If the patch directory is not found OR the TOC and TAR
   #  files are not found, print an error message and set a
   #  return flag to indicate we need to exit processing.
   #=============================================================
   return_status=0
   if [ "$DirNotFound" = "yes" ] || [ "$FilesNotFound" = "yes" ]; then
      echo ""
      echo ""
      echo "*** ERROR:"
      echo "  Unable to locate setup files:"
      echo ""
      echo "  $TempPath/$ApplyPatchTOC"
      echo "  $TempPath/$ApplyPatchTAR"
      echo ""
      return_status=1
   fi

   return $return_status
   
}


######################################################################
#=====================================================================
#  Error_Exit() 
#
#  The installation of the patch failed. This routine is called when 
#  none of the patch files have been installed yet and SDEHOME is 
#  still in its original state.
#
#  TODO: Make this take a message argument.
#=====================================================================
######################################################################
Error_Exit() 
{
  local msg="$1"  # optional error message

  echo ""
  echo "*** ERROR:"
  echo ""
  if [ -n "$msg" ]; then
    echo "$msg"
    echo ""
  fi
  echo "  The ESRI patch installation has failed."
  echo ""
  Clean_Up
  exit 1
}

fail()
{
  Error_Exit "$@"
}

######################################################################
#=====================================================================
#  Strip_Product_Version()
#
#  Strips the "."'s from the product version number.
#=====================================================================
######################################################################
Strip_Product_Version()
{
  ProductVersionStripped=$(echo $ProductVersion | sed 's/\.//g')

  #  Why???
  if [ "$ProductVersionStripped" = "931" ]; then
   ProductVersionStripped="93"
  fi
}


######################################################################
#=====================================================================
#  Pre_Install_Info()
#
#=====================================================================
######################################################################
Pre_Install_Info()
{
   
   #XXXXX=======================================================
   #  Generate header string containing selected product info.
   #=============================================================
   if [ $ArcSDE = 1 ]; then
      if [ "$CurrentPlatform" = "$Tru64Platform" ]; then
         #TheHeader1="$ProductDispName $ProductVersion $ArcSDESet $QFEAbbreviated ($QFEVersion) for $CurrentDBFormal on $ProductPlatform Install"
         TheHeader1="$QFEVersion $QFEAbbreviated for ($ProductDispName $ProductVersion $ArcSDESet for $CurrentDBFormal) on $ProductPlatform Install"
      else
         #TheHeader1="$ProductDispName $ProductVersion $ArcSDESet $QFEAbbreviated ($QFEVersion) for $CurrentDBFormal on $ProductPlatform($ProductBitSet-bit) Install"
         TheHeader1="$QFEVersion $QFEAbbreviated for ($ProductDispName $ProductVersion $ArcSDESet for $CurrentDBFormal) on $ProductPlatform($ProductBitSet-bit) Install"
      fi
   else
      #TheHeader1="$ProductDispName $ProductVersion $QFEAbbreviated ($QFEVersion) on $ProductPlatform Install"
      TheHeader1="$QFEVersion for ($ProductDispName) on $ProductPlatform Install"
   fi
   
   TheHeader2="($QFEDate)"
   
   
   echo ""
   #echo "  ###################################################################"
   #echo "  ==================================================================="
   echo "  -------------------------------------------------------------------" 
   #echo ""
   #echo "  $TheHeader1 $TheHeader2"
   #echo ""
   echo "  Before installing this update..."
   echo ""
   #echo "  ==================================================================="
   #echo "  ###################################################################"
   #echo ""
   if [ "$ProductDispName" = "ArcGIS Server" ] ||
      [ "$ProductDispName" = "ArcGIS Server for the Java Platform Spanish Supplement" ]  ||
      [ "$ProductDispName" = "ArcGIS Server for the Java Platform French Supplement" ]   ||
      [ "$ProductDispName" = "ArcGIS Server for the Java Platform Japanese Supplement" ] ||
      [ "$ProductDispName" = "ArcGIS Server for the Java Platform German Supplement" ]   ||
      [ "$ProductDispName" = "ArcGIS Server for the Java Platform Simplified Chinese Supplement" ]
   then
      echo "  - Make sure you install this $QFEAbbreviated as the ArcGIS Server account (do not install as ROOT)."
      #echo ""
   fi
   if [ $ArcSDE = 1 ]; then
      if [ $(LenChr "$ProductPreHotFix") != 1 ]; then
         echo "  - You must have $ProductDispName $ProductVersion $ArcSDESet with $ProductPHFTitle installed before you can apply this $QFEAbbreviated."
      elif [ $(LenChr "$ProductSerPack") != 1 ] && [ "$QFEAbbreviated" != "Service Pack" ] && [ "$QFEAbbreviated" != "Update" ]; then
         echo "  - You must have $ProductDispName $ProductVersion $ArcSDESet Service Pack $ProductSerPack installed before you can apply this $QFEAbbreviated."
       else
         echo "  - You must have $ProductDispName $ProductVersion $ArcSDESet installed before you can apply this $QFEAbbreviated."
      fi
   else
      if [ $(LenChr "$ProductPreHotFix") != 1 ]; then
         echo "  - You must have $ProductDispName with $ProductPHFTitle installed before you can apply this $QFEAbbreviated."
      elif [ $(LenChr "$ProductSerPack") != 1 ] && [ "$QFEAbbreviated" != "Service Pack" ] && [ "$QFEAbbreviated" != "Update" ]; then
         echo "  - You must have $ProductDispName Service Pack $ProductSerPack installed before you can apply this $QFEAbbreviated."
      else
         echo "  - You must have $ProductDispName installed before you can apply this $QFEAbbreviated."
      fi
   fi
   #echo ""
   if [ $ArcSDE = 1 ]; then
      echo "  - You should install this $QFEAbbreviated when no one is using $ProductDispName $ProductVersion $ArcSDESet."
   else
      echo "  - You should install this $QFEAbbreviated when no one is using $ProductDispName."
   fi

   if [ "$ProductDispName" = "ArcGIS Server" ] ||
      [ "$ProductDispName" = "Portal for ArcGIS" ] ||
      [ "$ProductDispName" = "ArcGIS Notebook Server" ] ||
      [ "$ProductDispName" = "ArcGIS Mission Server" ] ||
      [ "$ProductDispName" = "ArcGIS Data Store" ]; then
      #echo "  - Your $ProductDispName may be restarted during the installation process."
      echo "  - If your $ProductDispName was already started, it will be restarted after the installation."
   fi
#   echo ""
#   echo "  This $QFEAbbreviated is not compatible with other versions of $ProductDispName."
#   echo ""
   #echo "  ==================================================================="
   echo "  -------------------------------------------------------------------" 
   echo ""
}


######################################################################
#=====================================================================
#  Set_Product_Home()
#
#  Determine the user's product HOME (or install location).  Will 
#  default to the current product HOME (if set) or let the user
#  override or define an install location.
#=====================================================================
######################################################################
Set_Product_Home()
{
   # Don't prompt for InstallPath in Server products.  Just use the
   # detected path.
   local product=$(Get_Patch_Info Product $CurrentTOC)
   if $(IsServerProduct $product) ; then
     #echo ""
     echo "  Your product installation directory is currently set to:"
     echo ""
     echo "     $ProductHome"
     echo ""
     InstallPath=$ProductHome
     Validate_Product_Path
     if [ $? -ne 0 ]; then
       echo "***Error:"
       echo ""
       echo "  Could not find an install that matches this patch's product ($product)."
       Error_Exit
     fi
     return
   fi

   #=============================================================
   #  Add special check for ArcIMS ArcMap Server
   #=============================================================
   if [ "$ProductDispName" = "ArcIMS ArcMap Server" ]; then
      if [ -f "$ArcIMSSetupFile" ]; then
         FindArcMap=$(grep -i "Z_COMPONENTS_INSTALLED" $ArcIMSSetupFile | grep -i "ArcMap")
         if [ -z "$FindArcMap" ]; then
            echo ""
            echo "*** ERROR:"
            echo "  ArcIMS ArcMap Server is not detected." 
            echo ""
            Error_Exit
         fi
      else
         echo ""
         echo "  ArcIMS ArcMap Server is not detected." 
         echo ""
         Error_Exit
      fi
   fi

   #=============================================================
   #  Add special check for Server Language Packs
   #=============================================================
   if [ "$ProductDispName" = "ArcGIS Server for the Java Platform Spanish Supplement" ]; then
      if [ ! -f $ProductHome/Uninstall_ServerLanguagePack-[0-9\.]*-es.sh ]; then
         echo ""
         echo "*** ERROR:"
         echo "  $ProductDispName is not detected." 
         echo ""
         Error_Exit
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Server for the Java Platform French Supplement" ]; then
      if [ ! -f $ProductHome/Uninstall_ServerLanguagePack-[0-9\.]*-fr.sh ]; then
         echo ""
         echo "*** ERROR:"
         echo "  $ProductDispName is not detected." 
         echo ""
         Error_Exit
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Server for the Java Platform Japanese Supplement" ]; then
      if [ ! -f $ProductHome/Uninstall_ServerLanguagePack-[0-9\.]*-ja.sh ]; then
         echo ""
         echo "*** ERROR:"
         echo "  $ProductDispName is not detected." 
         echo ""
         Error_Exit
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Server for the Java Platform German Supplement" ]; then
      if [ ! -f $ProductHome/Uninstall_ServerLanguagePack-[0-9\.]*-de.sh ]; then
         echo ""
         echo "*** ERROR:"
         echo "  $ProductDispName is not detected." 
         echo ""
         Error_Exit
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Server for the Java Platform Simplified Chinese Supplement" ]; then
      if [ ! -f $ProductHome/Uninstall_ServerLanguagePack-[0-9\.]*-zh_CN.sh ]; then
         echo ""
         echo "*** ERROR:"
         echo "  $ProductDispName is not detected." 
         echo ""
         Error_Exit
      fi
   fi

   #=============================================================
   #  Determine ProductHome...
   #=============================================================

   #=============================================================
   #  If $ProductHome is set, ask user if they want to use it as 
   #  the installation location for the QFE patch.  Otherwise,
   #  prompt for pathname to the Product installation location.
   #=============================================================
   if [ -n "$ProductHome" ] && [ "$IsFirstTimeHomeSet" = "yes" ]; then

      echo ""
      echo "  Your product installation directory is currently set to:"
      echo ""
      echo "     $ProductHome"
      echo ""
      echo "  If you would like to apply the $(ToLower "$QFEAbbreviated") to this installation,"
      echo "  press <Enter> to continue or press 'q' to quit."
      #echo "  press <Enter> to continue and 'q' to quit.  Otherwise, specify the path to"
      #echo "  the installation you would like to update."
      echo ""

      #XXXXX=====================================================
      #  Prompt the user to enter an Installation path.
      #==========================================================
      Prompt "  Enter path [q] ($ProductHome): "

      read InstallPath
      
      
      #==========================================================
      #  Clean up and exit if the user selected to quit.
      #==========================================================
      if [ "$(ToLower "$InstallPath")" = "q" ]; then
         Voluntary_Quit
      fi

      #==========================================================
      #  If user hits return (accepts default), assign the 
      #  ProductHome as the InstallPath.
      #==========================================================
      if [ -z "$InstallPath" ]; then
         InstallPath=$ProductHome
      fi
   
   #=============================================================
   #  If $ProductHome is not set, prompt user to enter a path for
   #  the product installation location for the QFE patch. 
   #=============================================================
   else
      
      echo ""

      #XXXXX=====================================================
      #  Prompt the user to enter an Installation path.
      #==========================================================
      if [ $ArcSDE = 1 ]; then
        Prompt "  Enter path to your $ProductDispName $ProductVersion $ArcSDESet installation [q]: "
      else
        Prompt "  Enter path to your $ProductDispName installation [q]: "
      fi

      read InstallPath

      #==========================================================
      #  Clean up and exit if the user selected to quit.
      #==========================================================
      if [ "$(ToLower "$InstallPath")" = "q" ]; then
         Voluntary_Quit
      fi

      #==========================================================
      #  Keep prompting user for an Installation path for as long
      #  as they do not enter one.
      #==========================================================
      while [ -z "$InstallPath" ]
      do

         #XXXXX==================================================
         #  Prompt user for an Installation path.
         #=======================================================
         Prompt "  Enter path [q]: "

         read InstallPath

         #=======================================================
         #  Clean up and exit if the user selected to quit.
         #=======================================================
         if [ "$(ToLower "$InstallPath")" = "q" ]; then
            Voluntary_Quit
         fi

      done
   fi


   #=============================================================
   #  Validate the product installation path chosen by the user.
   #  If the path is invalid, keep asking until they enter a 
   #  valid path. 
   #=============================================================
   Validate_Product_Path
   while [ $? -ne 0 ]
   do
      echo ""

      #XXXXX=====================================================
      #  Prompt user for a valid Installation path.
      #==========================================================
      Prompt "  Enter path to your $ProductVersion installation [q]: "

      read InstallPath

      #==========================================================
      #  Clean up and exit if the user selected to quit.
      #==========================================================
      if [ "$(ToLower "$InstallPath")" = "q" ]; then
         Voluntary_Quit
      fi

      #==========================================================
      #  Keep prompting user for an Installation path for as long
      #  as they do not enter one.
      #==========================================================
      while [ -z "$InstallPath" ]
      do

         #XXXXX==================================================
         #  Prompt user for a valid Installation path.
         #=======================================================
         Prompt "  Enter path [q]: "

         read InstallPath
         
         #=======================================================
         #  Clean up and exit if the user selected to quit.
         #=======================================================
         if [ "$(ToLower "$InstallPath")" = "q" ]; then
            Voluntary_Quit
         fi
         
      done
      
      #==========================================================
      #  Validate the Installation path chosen by the user.
      #==========================================================
      Validate_Product_Path
      
   done
 
   echo ""

}


######################################################################
#=====================================================================
#  Validate_Product_Path()
#
#  Based upon the product and the product installation path given by
#  the user, verify this is a valid installation location.
#=====================================================================
######################################################################
Validate_Product_Path() 
{
   #XXXXX========================================================
   #  Test for valid ArcIMS installation location.
   #=============================================================
   if [ $ArcIMS = 1 ]; then
      if [ -f "$InstallPath/$ArcIMSFileTest" ]; then
         Validate_PreServicePack
         if [ $? -eq 1 ]; then
            return 1
         else
            return 0
         fi
      else
         echo ""
         #echo "***WARNING:  $InstallPath/$ArcIMSFileTest does not exist."
         echo "*** WARNING: "
         echo "  $InstallPath is not a valid $ProdHomeName location."
         echo "  Please try again."
         return 1
      fi
   fi
   
   #XXXXX========================================================
   #  Test for valid ArcInfo installation location.
   #=============================================================
   if [ $ArcInfo = 1 ]; then
      if [ -f "$InstallPath/$ArcInfoFileTest" ]; then
         return 0
      else
         echo ""
         #echo "***WARNING:  $InstallPath/$ArcInfoFileTest does not exist."
         echo "*** WARNING: "
         echo "  $InstallPath is not a valid $ProdHomeName location."
         echo "  Please try again."
         return 1
      fi
   fi
   
   #XXXXX========================================================
   #  Test for valid ArcSDE installation location.
   #=============================================================
   if [ $ArcSDE = 1 ]; then
      #===========================================================
      # Reset ArcSDEClientFolderTest to a file lib/jsde<92>_sdk.jar
      #===========================================================
      ArcSDEClientFileTest="lib/jsde${ProductVersionStripped}_sdk.jar"
      if [ -f "$InstallPath/$ArcSDEFileTest" ] && [ "$CurrentDB" != "$ArcSDKName" ]; then
         Validate_PreServicePack
         if [ $? -eq 1 ]; then
            return 1
         else
            return 0
         fi
#      elif [ -d $InstallPath/$ArcSDEClientFolderTest -a $CurrentDB = $ArcSDKName ]
      elif [ -f "$InstallPath/$ArcSDEClientFileTest" ] && [ "$CurrentDB" = "$ArcSDKName" ]; then
         Validate_PreServicePack
         if [ $? -eq 1 ]; then
            return 1
         else
            return 0
         fi
      else
         echo ""
         #echo "***WARNING:  $InstallPath/$ArcSDEFileTest does not exist."
         echo "*** WARNING:"
         echo "  $InstallPath is not a valid $ProdHomeName location."
         echo "  Please try again."
         return 1
      fi
   fi

   #XXXXX========================================================
   #  Test for valid ArcGIS installation location.
   #=============================================================
   if [ $ArcGIS = 1 ]; then
    
      #set -x
      #XXXXX==========================================================
      # Check that the current user is also the install owner
      #===============================================================
      if [ -d "${InstallPath}" ]; then
        if [ "$ProductDispName" = "ArcGIS Server" ] ||
          [ "$ProductDispName" = "Portal for ArcGIS" ] ||
          [ "$ProductDispName" = "ArcGIS Data Store" ] ||
          [ "$ProductDispName" = "ArcGIS GeoEnrichment Server" ] ||
          [ "$ProductDispName" = "ArcGIS Notebook Server" ] ||
          [ "$ProductDispName" = "ArcGIS Mission Server" ] ||
          [ "$ProductDispName" = "ArcGIS Insights (Portal)" ] ||
          [ "$ProductDispName" = "ArcGIS Insights (Server)" ] ||
          [ "$ProductDispName" = "ArcGIS Urban" ] ||
          [ "$ProductDispName" = "ArcGIS Video Server" ] ||
          [ "$ProductDispName" = "ArcGIS Data Pipelines Server" ] ||
          [ "$ProductDispName" = "ArcGIS Server for the Java Platform Spanish Supplement" ]  ||
          [ "$ProductDispName" = "ArcGIS Server for the Java Platform French Supplement" ]   ||
          [ "$ProductDispName" = "ArcGIS Server for the Java Platform Japanese Supplement" ] ||
          [ "$ProductDispName" = "ArcGIS Server for the Java Platform German Supplement" ]   ||
          [ "$ProductDispName" = "ArcGIS Server for the Java Platform Simplified Chinese Supplement" ]
        then
          local install_owner=$(stat -c %U $InstallPath | xargs)
          local current_user=$CurrentUserName
          if [ "$install_owner" != "$current_user" ]; then
            echo "*** ERROR:"
            echo " The ArcGIS Server install owner is '${install_owner}' but your username is '${current_user}'."
            echo " You must install this $QFEAbbreviated as '${install_owner}'."
            echo ""
            Error_Exit
          fi
        fi
      fi

      if [ "$ProductDispName" = "ArcGIS Server" ]; then
         TestFile=$InstallPath/$ArcServerFileTest
      elif [ "$ProductDispName" = "ArcGIS Engine ${VER}" ]; then
         TestFile=$InstallPath/$ArcEngineRTFileTest
      elif [ "$ProductDispName" = "ArcGIS ArcReader ${VER}" ]; then
         TestFile=$InstallPath/$ArcReaderFileTest
      elif [ "$ProductDispName" = "ArcGIS Engine Developer Kit for C++" ]; then
         TestFile=$InstallPath/$ArcEngCPPFileTest
      elif [ "$ProductDispName" = "ArcGIS Engine Developer Kit for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcEngJavaFileTest
      elif [ "$ProductDispName" = "ArcObjects SDK for C++" ]; then
         TestFile=$InstallPath/$ArcObjCPPFileTest
      elif [ "$ProductDispName" = "ArcObjects SDK for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcObjJavaFileTest
      elif [ "$ProductDispName" = "ArcGIS Server ADF for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcSrvrJavaFileTest
      elif [ "$ProductDispName" = "ArcIMS Web ADF for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcIMSJavaFileTest
      elif [ "$ProductDispName" = "ArcIMS ArcMap Server" ]; then
         TestFile=$InstallPath/$ArcMapSrvrFileTest
      elif [ "$ProductDispName" = "ArcGIS Help System for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcGISJavaHelpFileTest
      elif [ "$ProductDispName" = "ArcGIS Web Adaptor ${VER} for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcGISWebAdaptorFileTest
      elif [ "$ProductDispName" = "Portal for ArcGIS" ]; then
         TestFile=$InstallPath/$ArcGISPortalFileTest
      elif [ "$ProductDispName" = "ArcGIS Data Store" ]; then
         TestFile=$InstallPath/$ArcGISDataStoreFileTest
      elif [ "$ProductDispName" = "ArcGIS GeoEnrichment Server" ]; then
         TestFile=$InstallPath/$ArcGISGeoEnrichmentFileTest
      elif [ "$ProductDispName" = "ArcGIS Notebook Server" ]; then
         TestFile=$InstallPath/$ArcGISNotebookSvrFileTest
      elif [ "$ProductDispName" = "ArcGIS Mission Server" ]; then
         TestFile=$InstallPath/$ArcGISMissionSvrFileTest
      elif [ "$ProductDispName" = "ArcGIS Insights (Portal)" ]; then
         TestFile=$InstallPath/$ArcGISInsightsPortalFileTest
      elif [ "$ProductDispName" = "ArcGIS Insights (Server)" ]; then
         TestFile=$InstallPath/$ArcGISInsightsServerFileTest
      elif [ "$ProductDispName" = "ArcGIS Spatial Data Server ${VER} for the Java Platform" ]; then
         TestFile=$InstallPath/$ArcGISSDSFileTest
      elif [ "$ProductDispName" = "ArcGIS Military Overlay Editor" ]               ||
           [ "$ProductDispName" = "ArcGIS Military Overlay Editor for Engine" ]    ||
           [ "$ProductDispName" = "ArcGIS Military Overlay Editor for ArcReader" ] ||
           [ "$ProductDispName" = "ArcGIS Military Overlay Editor for Server" ]
      then
         if [ "$ProductVersion" = "9.2" ]; then
            TestFile=$InstallPath/$MOLEFileTest92
         else
            TestFile=$InstallPath/$MOLEFileTest
         fi
      elif [ "$ProductDispName" = "ArcGIS Military Analyst" ]               ||
           [ "$ProductDispName" = "ArcGIS Military Analyst for Engine" ]    ||
           [ "$ProductDispName" = "ArcGIS Military Analyst for ArcReader" ] ||
           [ "$ProductDispName" = "ArcGIS Military Analyst for Server" ]
      then
         TestFile=$InstallPath/$MAFileTest
      elif [ "$ProductDispName" = "ArcGIS License Manager ${VER}" ]; then
         TestFile=$InstallPath/$LMFileTest
      elif [ "$ProductDispName" = "ArcGIS Server for the Java Platform Spanish Supplement" ]; then
         TestFile=${InstallPath}/Uninstall_ServerLanguagePack-[0-9\.]*-es.sh
      elif [ "$ProductDispName" = "ArcGIS Server for the Java Platform French Supplement" ]; then
         TestFile=${InstallPath}/Uninstall_ServerLanguagePack-[0-9\.]*-fr.sh
      elif [ "$ProductDispName" = "ArcGIS Server for the Java Platform Japanese Supplement" ]; then
         TestFile=${InstallPath}/Uninstall_ServerLanguagePack-[0-9\.]*-ja.sh
      elif [ "$ProductDispName" = "ArcGIS Server for the Java Platform German Supplement" ]; then
         TestFile=${InstallPath}/Uninstall_ServerLanguagePack-[0-9\.]*-de.sh
      elif [ "$ProductDispName" = "ArcGIS Server for the Java Platform Simplified Chinese Supplement" ]; then
         TestFile=${InstallPath}/Uninstall_ServerLanguagePack-[0-9\.]*-zh_CN.sh
      elif [ "$ProductDispName" = "ArcGIS Web Adaptor for the Java Platform" ]; then
         TestFile="${InstallPath}/${ArcGISWebAdaptorFileTest}"
      elif [ "$ProductDispName" = "ArcGIS Urban" ]; then
         TestFile="${InstallPath}/${ArcGISUrbanFileTest}"
      elif [ "$ProductDispName" = "ArcGIS Video Server" ]; then
         TestFile="${InstallPath}/${ArcGISVideoServerFileTest}"
      elif [ "$ProductDispName" = "ArcGIS Data Pipelines Server" ]; then
         TestFile=$InstallPath/$ArcGISDataPipelinesServerFileTest
      else
         echo ""
         echo "*** WARNING:"
         echo "  Unknown Product: $ProductDispName"
         return 1
      fi

      if [ -f "$TestFile" ]; then
         Validate_PreServicePack
         if [ $? -eq 1 ]; then
            return 1
         else
            return 0
         fi
      else
         echo ""
         echo "*** WARNING: "
         echo "  $InstallPath is not a valid $ProductDispName location."
         echo "  Please try again."
         return 1
      fi
      
   fi
   
}


######################################################################
#=====================================================================
#  Validate_PreServicePack()
#
#  Based upon the product and the product installation path given by
#  the user, verify whether the required previous service pack or 
#  hot fix has been installed.
#=====================================================================
######################################################################
Validate_PreServicePack()
{
   if [ "$ProductVersion" = "9.3.1" ]; then
      TestFile="$InstallPath/$QFETestFile"
      if [ ! -f "$TestFile" ]; then
         echo ""
         echo "*** WARNING:"
         echo "  $ProductDispName was not detected in this location."
         echo "  You can either select another location to install"
         echo "  or quit to install $ProductDispName first,"
         echo "  then come back to install this $QFEAbbreviated again."
         echo ""
         return 1
      else
         UpdateVersion=$(Get_Update_Info)
         if [ $UpdateVersion != $ProductVersion ]
         then
            echo ""
            echo "*** WARNING:"
            echo "  $ProductDispName was not detected in this location."
            echo "  You can either select another location to install"
            echo "  or quit to install $ProductDispName first,"
            echo "  then come back to install this $QFEAbbreviated again."
            echo ""
            return 1
         fi
      fi
   fi
   
   if [ $(LenChr "$ProductPreHotFix") != 1 ]; then
      TestFile="$InstallPath/$QFETestFile"
      if [ ! -f "$TestFile" ]; then
         echo ""
         echo "*** WARNING:"
         echo "  $ProductPHFTitle was not detected in this location."
         echo "  You can either select another location to install"
         echo "  or quit to install $ProductPHFTitle first,"
         echo "  then come back to install this $QFEAbbreviated again."
         echo ""
         return 1
      else
         TestOut=$(grep -i "$ProductPreHotFix $TestFile")
         if [ -z "$TestOut" ]; then
            echo ""
            echo "*** WARNING:"
            echo "  $ProductPHFTitle was not detected in this location."
            echo "  You can either select another location to install"
            echo "  or quit to install $ProductPHFTitle first,"
            echo "  then come back to install this $QFEAbbreviated again."
            echo ""
            return 1
         fi
      fi
   elif [ $(LenChr "$ProductSerPack") != 1 ] && [ "$QFEAbbreviated" != "Update" ]; then
      SPNumber=$(Get_SP_Info)
      if [ $SPNumber -gt 0 ]; then
         if [ $ProductSerPack -gt $SPNumber ] && [ "$QFEAbbreviated" != "Service Pack" ]; then
            echo ""
            echo "*** WARNING:"
            echo "  $ProductDispName Service Pack $ProductSerPack was not detected in this location."
            echo "  You can either select another location to install"
            echo "  or quit to install the Service Pack $ProductSerPack first,"
            echo "  then come back to install this $QFEAbbreviated again."
            echo ""
            return 1
         elif [ $ProductSerPack -lt $SPNumber ]; then
            echo ""
            echo "*** WARNING:"
            echo "  A newer Service Pack, $ProductDispName Service Pack $SPNumber was detected in this location."
            echo "  You can either select another location to install or quit the install."
            echo ""
            return 1
         fi
      elif [ "$QFEAbbreviated" != "Service Pack" ] && [ $ProductSerPack -gt 0 ]; then
         echo ""
         echo "*** WARNING:"
         echo "  $ProductDispName Service Pack $ProductSerPack was not detected in this location."
         echo "  You can either select another location to install"
         echo "  or quit to install the Service pack $ProductSerPack first,"
         echo "  then come back to install this $QFEAbbreviated again."
         echo ""
         return 1
      fi      
   fi
   return 0
}

######################################################################
#=====================================================================
#  Existing_Product_Bitset()
#
#  Based upon the product and the platform, determine the user's
#  installation bitset.
#=====================================================================
######################################################################
Existing_Product_Bitset()
{

   #XXXXX========================================================
   #  Determine file to check based upon product.
   #=============================================================
   if [ $ArcIMS = 1 ]; then
      TestFile=$InstallPath/$ArcIMSFileTest
   elif [ $ArcInfo = 1 ]; then
      TestFile=$InstallPath/$ArcInfoFileTest
   elif [ $ArcSDE = 1 ]; then
      if [ "$CurrentDB" != "$ArcSDKName" ]; then
         TestFile=$InstallPath/$ArcSDEFileTest
      else
         if [ "$(uname)" = "HP-UX" ]; then
            TestFile="${InstallPath}/lib/libsde${ProductVersionStripped}.sl"
            if [ ! -f "$TestFile" ]; then
               TestFile="${InstallPath}/lib/libsde.sl"
            fi
         else
            if [ -f "${InstallPath}/lib/libsde${ProductVersionStripped}.so" ]; then
               TestFile="${InstallPath}/lib/libsde${ProductVersionStripped}.so"
            elif [ -f "${InstallPath}/lib/libsde_64.so" ]; then
               TestFile="${InstallPath}/lib/libsde_64.so"
            elif [ -f "${InstallPath}/lib/libsde${ProductVersionStripped}_64.so" ]; then
               TestFile="${InstallPath}/lib/libsde${ProductVersionStripped}_64.so"
            else
               TestFile="${InstallPath}/lib/libsde.so"
            fi
         fi
      fi
   elif [ $ArcGIS = 1 ]; then
      case $(uname) in
         OSF1)
            echo 64
         ;;
         *)
            echo 32
         ;;
      esac
      return
   fi  
   
   #XXXXX========================================================
   #  Based upon platform, perform a "file" test to determine
   #  whether the user's existing product install is 32 bit or
   #  64 bit.  Currently, Linux is always 32 bit and Tru64 is
   #  always 64 bit.
   #=============================================================
   #=============================================================
   # When file command can not get bit set information, set 
   # bit set value = 0.
   #=============================================================
   case $(uname) in
      AIX)
         Value=$(file $TestFile | awk '{print $2}' | cut -c1-2)
         if [ "$Value" = "64" ]; then
            echo 64
         else
            if [ "$Value" = "32" ]; then
               echo 32
            else
               echo 0
            fi
         fi
         ;;
      HP-UX)
         Value=$(file $TestFile | awk '{print $2}' | cut -c5-6)
         if [ "$Value" = "64" ]; then
            echo 64
         else 
            echo 32
         fi
         ;;
      Linux)
         echo 32
         ;;
      OSF1)
         echo 64
         ;;
      Darwin)
         echo 64
         ;;
      SunOS)
         Value=$(file $TestFile | awk '{print $3}' | cut -c1-2)
         if [ "$Value" = "64" ]; then
            echo 64
         else
            if [ "$Value" = "32" ]; then
               echo 32
            else
               echo 0
            fi
         fi
         ;;
   esac
   #============================================================
}


######################################################################
#=====================================================================
#  Validate_Selection()
#
#=====================================================================
######################################################################
Validate_Selection()
{
      
   #=============================================================
   #  Verify the the bitset of the QFE patch intended to be 
   #  installed matches the bitset of the user's existing 
   #  product.   
   #=============================================================
   #=============================================================
   # This Check only used for ArcSDE.
   # If ExistingProdBits = 0, which means we can not detect the 
   # bit set of existing product, prompt message to let users 
   # confirm the installation by themselves.
   #=============================================================
   IsBitCheckOK="yes"
   if [ "$ExistingProdBits" = "0" ]; then

      while [ true ]; do
         echo " ==========Confirm installed $ProductDispName $ProductVersion $ArcSDESet bit set==========="
         echo " You are trying to install a $ProductBitSet bit $QFEAbbreviated of $ProductDispName $ProductVersion"
         echo " $ArcSDESet onto $InstallPath. "
         echo ""   
         echo "    \`y' to make sure the installed bit set matches the setup product bit"
         echo "    \`n' to reselect the installation path"
         echo ""

         Prompt " Enter choice [y,n,q] (y): "

         read choice
   
         #==========================================================
         #  Perform actions based upon user's choice.
         #==========================================================
         case $(ToLower "${choice}") in
            ""|y*)
               HomeSetToInstall="yes"
               break
               ;;
            n*)
               IsBitCheckOK="no"
               break
               ;;
            q*)
               HomeSetToInstall="yes"
               Voluntary_Quit
               ;;
         esac
      done
   else
      HomeSetToInstall="yes"
      if [ $ProductBitSet != $ExistingProdBits ]; then
         echo "*** WARNING: "
         echo "  You are trying to install a $ProductBitSet bit $QFEAbbreviated of $ProductDispName $ProductVersion $ArcSDESet"
         echo "  onto an existing $ExistingProdBits bit version of $ProductDispName $ProductVersion $ArcSDESet."
         echo "  Please try again."
         echo ""
         HomeSetToInstall="no"
         IsBitCheckOK="no"
      fi
   fi
   #XXXXX========================================================
   #  For ArcSDE, verify that the selected QFE patch database is
   #  being installed upon the same user's database.   
   #=============================================================
   if [ $ArcSDE = 1 ] && [ "$IsBitCheckOK" = "yes" ] && [ $CurrentDB != $ArcSDKName ]; then
      if [ "$ProductBitSet" = "64" ] && [ $(uname) = "AIX" ]; then
         TheFile=libsde${CurrentDB}srvr${ProductVersionStripped}_64.so
      elif [ $(uname) = "HP-UX" ]; then
         TheFile=libsde${CurrentDB}srvr${ProductVersionStripped}.sl
      else
         TheFile=libsde${CurrentDB}srvr${ProductVersionStripped}.so
      fi
      
      if [ ! -f "$InstallPath/lib/$TheFile" ]; then
         TheExistDB="a different database"
         if [ -f "$InstallPath/lib/libsdeinfsrvr${ProductVersionStripped}.sl" ] ||
            [ -f "$InstallPath/lib/libsdeinfsrvr${ProductVersionStripped}.so" ] ||
            [ -f "$InstallPath/lib/libsdeinfsrvr${ProductVersionStripped}_64.so" ]
         then
            TheExistDB="an Informix"
         fi
         if [ -f "$InstallPath/lib/libsdedb2srvr${ProductVersionStripped}.sl" ] ||
            [ -f "$InstallPath/lib/libsdedb2srvr${ProductVersionStripped}.so" ] ||
            [ -f "$InstallPath/lib/libsdedb2srvr${ProductVersionStripped}_64.so" ] 
         then
            TheExistDB="a DB2"
         fi
         if [ -f "$InstallPath/lib/libsdeora8isrvr${ProductVersionStripped}.sl" ] ||
            [ -f "$InstallPath/lib/libsdeora8isrvr${ProductVersionStripped}.so" ] ||
            [ -f "$InstallPath/lib/libsdeora8isrvr${ProductVersionStripped}_64.so" ]
         then
            TheExistDB="an Oracle_8i"
         fi
         if [ -f "$InstallPath/lib/libsdeora9isrvr${ProductVersionStripped}.sl" ] ||
            [ -f "$InstallPath/lib/libsdeora9isrvr${ProductVersionStripped}.so" ] ||
            [ -f "$InstallPath/lib/libsdeora9isrvr${ProductVersionStripped}_64.so" ]
         then
            TheExistDB="an Oracle_9i"
         fi
         if [ -f "$InstallPath/lib/libsdeora10gsrvr${ProductVersionStripped}.sl" ] ||
            [ -f "$InstallPath/lib/libsdeora10gsrvr${ProductVersionStripped}.so" ] ||
            [ -f "$InstallPath/lib/libsdeora10gsrvr${ProductVersionStripped}_64.so" ]
         then
            TheExistDB="Oracle_10g"
         fi
         echo "*** WARNING:"
         echo "  You are trying to install the $CurrentDBFormal version of the $ProductDispName $ProductVersion"
         echo "  $ArcSDESet $QFEAbbreviated onto $TheExistDB version."
         echo ""
         echo "  Please try again."
         echo ""
         HomeSetToInstall="no"
      fi
   fi

}


######################################################################
#=====================================================================
#  Update_TOC_File()
#
#  Create an updated TOC file based on what the user has installed in
#  their product HOME.
#=====================================================================
######################################################################
Update_TOC_File() 
{

   #=============================================================
   #  A QFE patch could contain files that are not currently in 
   #  the user's product installation.  This could be because of 
   #  one (or both) of two reasons:
   #
   #     1.  The patch contains brand-new files
   #     2.  The patch contains files for an optional package 
   #         (core), that the user hasn't installed.
   #
   #  In Case 1, we just give the user the new files.  In Case 2, 
   #  we only give them a "patched" version of the files they 
   #  have in their current product installation.
   #
   #  Here, we create an updated TOC file that only contains the 
   #  files that are to be applied to the user-specified product
   #  installation.  The "package" field in the updated TOC file 
   #  is set to either "new" if the file to be installed did not
   #  exist on the user's system before or "old" if an existing 
   #  file is being replaced.
   #=============================================================

   echo "  Updating TOC..."

   UpdatedTOCFile="/tmp/applypatch.toc.$$"

   cat /dev/null > $UpdatedTOCFile

   #=============================================================
   #  Read through the user selected QFE patch TOC file.
   #=============================================================
   while IFS="$TOC_IFS" read file size package bytes month day
   do
      # Skip comment lines
      if [ "${file:0:1}" = "#" ]; then
        continue
      fi

      #==========================================================
      #  If the current file exists in the user's install 
      #  location, or the file in the TOC is labelled as "new",
      #  then the file is considered valid for installation.
      #  It will be labelled as "old".
      #==========================================================
      if [ ! -f "$InstallPath/$file" ] || [ "$package" = "new" ] || [ "$package" = "NEW" ]; then
          package="new"
      elif [ -f "$InstallPath/$file" ] && [ "$package" != "delete" ]; then
          package="old"
      fi
         
      #==========================================================
      #  Write out the appropriate information to the Updated
      #  TOC file.
      #==========================================================
      printf "%s%s" "$file"    "$TOC_IFS" >> $UpdatedTOCFile
      printf "%s%s" "$size"    "$TOC_IFS" >> $UpdatedTOCFile
      printf "%s%s" "$package" "$TOC_IFS" >> $UpdatedTOCFile
      printf "%s%s" "$bytes"   "$TOC_IFS" >> $UpdatedTOCFile
      printf "%s%s" "$month"   "$TOC_IFS" >> $UpdatedTOCFile
      printf "%s\n" "$day"                >> $UpdatedTOCFile

   done < $PatchHome/$SelectedTOC
}
 

######################################################################
#=====================================================================
#  Check_Access_Rights()
#
#  Check to see if the directories containing the files to be
#  installed (from UpdatedTOCFile) exist and have write access.
#=====================================================================
######################################################################
Check_Access_Rights()
{
   echo "  Checking install directory permissions..."
   #=============================================================
   #  Read through all the lines of the UpdatedTOCFile. 
   #=============================================================
   while IFS="$TOC_IFS" read file size package bytes month day
   do
      #==========================================================
      #  If the directory to the current file does not exist,
      #  write out an error message and then exit. 
      #==========================================================
      if [ ! -d "$(dirname "$InstallPath/$file")" ]; then
         if [ "$package" != "new" ] && [ "$package" != "NEW" ]; then
            echo ""
            echo "*** ERROR: "
            echo "  $(dirname "$InstallPath/$file") does not exist."
            Error_Exit
         else
            TmpInstallDir=$(dirname "$InstallPath/$file")
      
            # Walk the path backwards to check each parent dir
            while [ ! -d "$TmpInstallDir" ]
            do
               TmpInstallDir=$(dirname "$TmpInstallDir")
            done

            if [ ! -w  "$TmpInstallDir" ]; then
               echo ""
               echo "*** ERROR: "
               echo "  No write access to the folder $TmpInstallDir"
               echo "  for the new file: $InstallPath/$file."
               Error_Exit
            fi
         fi
      fi

      #==========================================================
      #  If the directory to the current file does not have
      #  write access, write out an error message and then exit. 
      #==========================================================
      if [ ! -w "$(dirname "$InstallPath/$file")" ]; then
         if [ "$package" != "new" ] && [ "$package" != "NEW" ]; then
            echo ""
            echo "*** ERROR: "
            echo "  No write access to $(dirname "$InstallPath/$file")."
            Error_Exit
         fi
      fi
            
   done < $UpdatedTOCFile

}


######################################################################
#=====================================================================
#  Check_Disk_Space()
#
#  Make sure that the minimum disk space needed to install the QFE
#  Patch is available.
#=====================================================================
######################################################################
Check_Disk_Space()
{
   echo "  Checking disk space..."

   #=============================================================
   #  No mater what is being done with the original files, the
   #  ProductHome must have sufficient space for the difference 
   #  between the original files and the new ESRI Patch files.  
   #  That is:
   #
   #     DF(ProductHome) > DU(patch_files) - DU(original_files) 
   #=============================================================
   local FreeSpaceInDest=$(expr $(MyDf $InstallPath) / 1000)
   local BytesReqd4Patch=$(Size_Of_Patch)
   local BytesReqd4Originals=$(Size_Of_Originals)
   local SpaceRequired=$(expr $BytesReqd4Patch - $BytesReqd4Originals)
   local SpaceRequired=$(expr $SpaceRequired / 1000)
     
   #=============================================================
   #  If there is not enough space available, print out an error
   #  message, clean up and exit. 
   #=============================================================
   if [ $FreeSpaceInDest -lt $SpaceRequired ]; then
      echo ""
      echo "*** ERROR: "
      echo "  There is not enough disk space to install this $QFEAbbreviated"
      echo "  in $InstallPath."
      echo ""
      echo "  Space Required :  $SpaceRequired MBytes."
      echo "  Space Available:  $FreeSpaceInDest MBytes."

      Error_Exit
   fi

}


######################################################################
#=====================================================================
#  MyDf() 
#
#  Determine available disk space (in KBytes).
#  Platform independant df.
#=====================================================================
######################################################################
MyDf() 
{
   #XXXXX========================================================
   #  Determine the available disk space - platform based.
   #=============================================================
   case $(uname) in
      AIX)
         $DF -k "$1" | tail -1 | awk '{print $3}'
         ;;
      HP-UX)
         $DF "$1" | tail -1 | awk '{print $4}'
         ;;
      IRIX*)
         $DF -k "$1" | tail -1 | awk '{print $5}'
         ;;
      Linux)
         CheckField=$($DF -k "$1" | tail -1 | awk '{print NF}')
         if [ $CheckField -lt 6 ]; then
            $DF -k "$1" | tail -1 | awk '{print $3}'
         else
            $DF -k "$1" | tail -1 | awk '{print $4}'
         fi
         ;;
      OSF1)
         $DF -k "$1" | tail -1 | awk '{print $4}'
         ;;
      SunOS)
         $DF -k "$1" | tail -1 | awk '{print $4}'
         ;;
      Darwin)
         $DF -k "$1" | tail -1 | awk '{print $4}'
         ;;
   esac
}


######################################################################
#=====================================================================
#  Size_Of_Patch() 
#
#  Add 2% to the total patch size to account for variations in the
#  du -sk output.
#=====================================================================
######################################################################
Size_Of_Patch() 
{

   #=============================================================
   #  Determine the total size of the patch based upon the 
   #  accumulation of sizes in the Updated TOC file.
   #=============================================================
   Total_Size=$(Unadjusted_Size_Of_Patch)
   
   #=============================================================
   #  Increase by 2% to cover variations in the "du -sk" output.
   #=============================================================
   Total_Size=$(expr $Total_Size + \( 2 \* $Total_Size / 100 \))
   echo $Total_Size
   
}


######################################################################
#=====================================================================
#  Size_Of_Originals() 
#
#  Determine the total size of the files contained within the Updated
#  TOC using the size of the files already existing in the user's
#  product install.
#=====================================================================
######################################################################
Size_Of_Originals() 
{
  local -i Total_Size=0
   
  #=============================================================
  #  Read through the Updated TOC file and add up the sizes of
  #  the files contained within it - using the size of the files
  #  already existing in the user's product install.
  #=============================================================
  while IFS="$TOC_IFS" read file size package bytes month day
  do
    if [ -f "$InstallPath/$file" ]; then
      File_Size=$(MyDu "$InstallPath/$file")
      Total_Size=$(($Total_Size + $File_Size))
    fi
  done < $UpdatedTOCFile

  echo $Total_Size 
}


######################################################################
#=====================================================================
#  Unadjusted_Size_Of_Patch() 
#
#  Add up the size of the files in the Updated TOC file to get a 
#  total patch size.
#=====================================================================
######################################################################
Unadjusted_Size_Of_Patch() 
{
  local -i Total_Size=0
   
  #=============================================================
  #  Read through the Updated TOC file and add up the sizes of
  #  the files contained within it - to determine a Total_Size.
  #=============================================================
  while IFS="$TOC_IFS" read file file_size package bytes month day
  do
    Total_Size=$(($Total_Size + $file_size))
  done < $UpdatedTOCFile
  echo $Total_Size 
}


######################################################################
#=====================================================================
#  MyDu() 
#
#  Determine the size (in KBytes) of the given file. 
#  Platform independent du.
#=====================================================================
######################################################################
MyDu() 
{
  [ -f "$1" ] && du -sk "$1" | awk '{print $1}' || echo 0
}


######################################################################
#=====================================================================
#  Prompt_User_For_Backup()
#
#  Prompt the user to see if they would like to backup the original
#  files that will be replaced.
#=====================================================================
######################################################################
Prompt_User_For_Backup()
{

   #=============================================================
   #  Determine bytes required for the patch. 
   #=============================================================
   BytesReqd4Patch=$(Size_Of_Patch)
   BytesReqd4Patch=$(expr $BytesReqd4Patch / 1000)

   #=============================================================
   #  Describe backup process to user. 
   #=============================================================
   echo ""
   echo "  This $QFEAbbreviated will replace several files in your $ProductDispName $ProductVersion"
   echo "  $ArcSDESet installation directory.  We highly recommend to backup"
   echo "  the original files in case you decide you would like to "
   echo "  revert to them."
   echo ""
   echo "  You need $BytesReqd4Patch MBytes to install the $QFEAbbreviated with the backup."
   echo ""
   
   
   #XXXXX========================================================
   #  Continually prompt user and accept their input for 
   #  backup option until a valid option is selected.
   #=============================================================
   while [ true ]
   do
      echo ""
      echo "    \`y' to backup original files"
      echo "    \`n' to overwrite original files"
      echo ""

      Prompt "  Enter choice [y,n,q] (y): "

      read choice
   
      #==========================================================
      #  Perform actions based upon user's choice.
      #==========================================================
      case $(ToLower "${choice}") in
         ""|y*)
            SaveFiles="yes"
            break
            ;;
         n*)
            SaveFiles="no"
            break
            ;;
         q*)
            Voluntary_Quit
            ;;
      esac
   done

}


######################################################################
#=====================================================================
#  Validate_Save_Location()
#
#  If the user selected to backup the original files, then get a
#  backup location from the user and verify that it is a valid
#  location.
#=====================================================================
######################################################################
Validate_Save_Location()
{

   #=============================================================
   #  If the user selected to save backup the original files that
   #  will be replaced, print some details to the user and 
   #  prompt them for a backup location.  
   #=============================================================
   if [ "$SaveFiles" = "yes" ]; then
      echo ""
      echo ""
      echo "  By default the original files will be backed up in the $ProductDispName"
      echo "  installation location.  The suffix '.orig' will be appended to"
      echo "  each file.  To save these files in a different location, please"
      echo "  enter the path below:"
      echo ""

      #XXXXX=====================================================
      #  Prompt the user for a SavePath (backup location). 
      #  Default to the ProductHome.
      #==========================================================
      Prompt "Enter location to backup original files [q] ($InstallPath): "
      read SavePath
   
      #==========================================================
      #  Clean up and exit if the user selected to quit.
      #==========================================================
      if [ "$(ToLower "$SavePath")" = "q" ]; then
         Voluntary_Quit
      fi

      #==========================================================
      #  If user hit <Return> at the prompt, set the SavePath
      #  (backup path) to the default - the InstallPath.
      #==========================================================
      if [ -z "$SavePath" ]; then
         SavePath=$InstallPath
      fi

      #==========================================================
      #  Validate the SavePath (backup location) chosen by the
      #  user.  If the path is invalid, keep asking until they
      #  enter a valid path.
      #==========================================================
      Validate_Save_Path
      while [ $? -ne 0 ]
      do
         echo ""

         #XXXXX==================================================
         #  Prompt the user for a valid SavePath (backup
         #  location).
         #=======================================================
         Prompt "Enter another location [q]: "

         read SavePath
         
         #=======================================================
         #  Clean up and exit if the user selected to quit.
         #=======================================================
         if [ "$(ToLower "$SavePath")" = "q" ]; then
            Voluntary_Quit
         fi
         
         #=======================================================
         #  Keep prompting user for a valid SavePath (backup
         #  location) path for as long as they do not enter one.
         #=======================================================
         while [ -z "$SavePath" ]
         do

            #XXXXX===============================================
            #  Promp the user for a valid SavePath (backup
            #  location).
            #====================================================
            Prompt "Enter another location [q]: "

            read SavePath
            
            #====================================================
            #  Clean up and exit if the user selected to quit.
            #====================================================
            if [ "$(ToLower "$SavePath")" = "q" ]; then
               Voluntary_Quit
            fi
            
         done
         
         #=======================================================
         #  Validate the SavePath (backup location) chosen by
         #  the user.
         #=======================================================
         Validate_Save_Path
         
      done

   fi

}


######################################################################
#=====================================================================
#  Validate_Save_Path()
#
#  Validate that the save path exists and is writeable.
#=====================================================================
######################################################################
Validate_Save_Path() 
{

   return_status=0

   #=============================================================
   #  Make sure the backup location exists.
   #=============================================================
   if [ ! -d "$SavePath" ]; then
      echo ""
      echo "*** WARNING: "
      echo "  $SavePath does not exist."
      return 1
   fi

   #=============================================================
   #  Make sure the backup location is writeable.
   #=============================================================
   if [ ! -w "$SavePath" ]; then
      echo ""
      echo "*** WARNING: "
      echo "  You do not have write access to $SavePath."
      return 1
   fi


   #=============================================================
   #  Make sure there is sufficient disk space to store the
   #  original files.
   #
   #  There are 2 cases:
   #
   #     1.  Storing originals in the ProductHome itself or on 
   #         the same disk drive as the ProductHome.
   #	     In this case, we need to make sure that the 
   #         ProductHome drive has sufficient space for the patch 
   #         files + existing originals.  That is:
   #
   #		DF(ProductHome) > DU(patch_files)
   #
   #     2.  Storing originals on a different disk drive than 
   #         the ProductHome.
   #         In this case, we need to make sure this other drive
   #         has sufficient space for the originals:
   #
   #		DF($SavePath) > DU(original_files)
   #
   #     Note:  We verified earlier that the ProductHome has 
   #            room for any extra space needed to install the 
   #            patch files.
   #
   #=============================================================
   FreeSpaceInDest=$(expr $(MyDf $InstallPath) / 1000)
   BytesReqd4Patch=$(expr $(Size_Of_Patch) / 1000)
   BytesReqd4Originals=$(expr $(Size_Of_Originals) / 1000)
   FreeSpaceInSavePath=$(expr $(MyDf $SavePath) / 1000)
	
   #=============================================================
   #  Case 1 - save originals in the ProductHome.
   #=============================================================
   if [ $(Drive_Name $InstallPath) = $(Drive_Name $SavePath) ]; then
      if [ $FreeSpaceInDest -lt $BytesReqd4Patch ]; then
         echo ""
         echo "*** WARNING: "
         echo "  Not enough space to store originals on /$(Drive_Name $SavePath)"
         echo ""
         echo "  Space Required : $BytesReqd4Patch MBytes."
         echo "  Space Available: $FreeSpaceInDest MBytes."

         return_status=1
      fi


   #=============================================================
   #  Case 2 - original somewhere other than in the ProductHome.
   #=============================================================
   else

      if [ $FreeSpaceInSavePath -lt $BytesReqd4Originals ]; then
         echo ""
         echo "*** WARNING:"
         echo "  Not enough space to store originals on /`Drive_Name $SavePath`"
         echo ""
         echo "  Space Required : $BytesReqd4Originals MBytes."

         return_status=1
      fi
   fi

   return $return_status
   
}


######################################################################
#=====================================================================
#  Drive_Name() 
#
#  Determine the total size of the files contained within the Updated
#  TOC using the size of the files already existing in the user's
#  product install.
#=====================================================================
######################################################################
Drive_Name()
{
   current_dir=$(pwd)
   cd $1
   pwd | cut -d/ -f2
   cd $current_dir
}


######################################################################
#=====================================================================
#  Confirm_Settings()
#
#  Display the current selections made by the user and have the user
#  choose to confirm or change the settings.
#=====================================================================
######################################################################
Confirm_Settings()
{
   #XXXXX========================================================
   #  Display the current selections made by the user.  
   #=============================================================
   echo ""
   echo "  Confirm Settings"
   echo "  -------------------------------------------------------------------"
   if [ $ArcSDE = 1 ] ; then
      echo "  Product to update:        $ProductDispName $ProductVersion $ArcSDESet"
      echo "  Platform to update:       $ProductPlatform $ProductBitSet-bit"
      if [ "$CurrentDB" != "$ArcSDKName" ]; then
         echo "  Database to update:       $CurrentDBFormal"
      fi
   else
      echo "  Product to update:        $ProductDispName"
      echo "  Product version:          $VER"
      echo "  Platform to update:       $ProductPlatform"
   fi

   echo "  Location to update:       $InstallPath"
   if [ "$SaveFiles" = "yes" ]; then
      if [ "$InstallPath" = "$SavePath" ]; then
         echo "  Backup originals in:     $InstallPath"
      else
         echo "  Backup original files to:  $SavePath/${ProductName}_${ProductVersion}.orig"
      fi
   fi
   
   #if [ "$ProductDispName" = "ArcGIS Server" ] && [ "$RestartServer" = true ]; then
   #    echo ""
   #    echo "  Warning: Your ArcGIS Server will be restarted during the installation process." 
   #fi
   
   #if [ "$ProductDispName" = "Portal for ArcGIS" ] && [ "$RestartPortal" = true ]; then
   #    echo ""
   #    echo "  Warning: Your Portal for ArcGIS will be restarted during the installation process."
	 #    echo "  Your Portal for ArcGIS content will not be accessible during the installation process."
   #fi   
  
   #if [ "$ProductDispName" = "ArcGIS Data Store" ] && [ "$RestartDataStore" = true ]; then
   #    echo ""
   #    echo "  Warning: Your ArcGIS Data Store will be restarted during the installation process." 
   #fi

   #XXXXX========================================================
   #  Continually loop through the prompting of the user about
   #  the selections displayed until they make a valid choice.  
   #=============================================================
   while [ true ]
   do
      echo ""
      echo "     Press 'y' to continue with these settings"
      #echo "     \`c' to change settings"
      echo "     Press 'q' to exit without applying this $QFEAbbreviated"
      #echo ""

      Prompt "  Enter choice [y,q] (y): "
      #Prompt "  Enter choice [y,c,q] (y): "

      read choice
    
      #==========================================================
      #  Perform actions based upon user's choice.
      #==========================================================
      case $(ToLower "${choice}") in
         ""|y*)
            AllSetToInstall="yes"
            break
            ;;
         c*)
            echo ""
            break
            ;;
	       q*)
	          Voluntary_Quit
	          ;;
      esac
   done

}


######################################################################
#=====================================================================
#  Perform_Backup()
#
#  Backup the original files to the user specified location.  If there
#  is a failure during backup, restore the originals and exit on 
#  error.
#=====================================================================
######################################################################
Perform_Backup()
{
   local num_files=""
   local tmp_log="/tmp/backup_out.$$.log"

   num_files=$(cat "${ScriptDir}/${SelectedTOC}" | grep -Ev "^#|^$" | wc -l)

   echo "  Backing up ${num_files} original files ..."

   if [ -f "$RollbackBackupScript" ]; then
     # Run the backup script if present
     "$RollbackBackupScript" -t "${ScriptDir}/${SelectedTOC}" -q "$RollbackScriptPath" > "$tmp_log" 2>&1

     if [ $? -ne 0 ]; then
        echo "*** Error backing up original files."
        echo ""
        cat "$tmp_log"
     fi
     rm -f "$tmp_log"
     return
   fi

   #=============================================================
   #  If the user selected to backup the original files...proceed
   #  to back them up.  
   #=============================================================
   if [ "$SaveFiles" = "yes" ]; then

      #==========================================================
      #  If the product install path is the same as the user
      #  selected backup path...proceed to backup original files.
      #==========================================================
      if [ "$InstallPath" = "$SavePath" ]; then

         #=======================================================
         #  Rename the original files in the ProductHome.
         #=======================================================
         
         #=======================================================
         #  Indicate to the user that the original files are
         #  being renamed (for backup).
         #=======================================================
         echo ""
         echo "  Renaming original files ..."

         #=======================================================
         #  Walk through the Updated TOC file and rename the
         #  files in the ProductHome area.
         #=======================================================
         while IFS="$TOC_IFS" read file size package bytes month day
         do
         
            #====================================================
            #  If the current file indicator is "old"...proceed 
            #  to back it up.
            #====================================================
            if [ "$package" = "old" ]; then

               #=================================================
               #  If an old backup copy exists, remove it before
               #  the rename.  This will work even if it's 
               #  read-only or root owned.
               #=================================================
               if [ -f "$InstallPath/$file.orig" ]; then
                  rm -f "$InstallPath/$file.orig"
               fi
            
               #=================================================
               #  Save the original file (via mv).
               #=================================================
               mv "$InstallPath/$file" "$InstallPath/$file.orig"
               
               #=================================================
               #  If the backup of the original file failed, we
               #  need to restore the original files that have
               #  already been backed up.
               #=================================================
               if [ $? -ne 0 ]; then
                  echo "*** ERROR: "
                  echo "  Renaming $InstallPath/$file to $InstallPath/$file.orig."
                  echo "  Restoring original files ..."
                  
                  #==============================================
                  #  Set CurrentFile to the current file.
                  #==============================================
                  CurrentFile="$file"
                  
                  #==============================================
                  #  Walk through the Updated TOC file to
                  #  restore.
                  #==============================================
                  while IFS="$TOC_IFS" read file size package bytes month day
                  do
                  
                     #===========================================
                     #  If the current file matches the
                     #  CurrentFile saved off earlier (problem
                     #  file), indicate that the original files
                     #  have been restored and exit processing.
                     #===========================================
                     if [ "$CurrentFile" = "$file" ]; then
                        echo "            Original files restored."
                        Error_Exit
                     
                     #===========================================
                     #  Otherwise, if the current file does not
                     #  match the CurrentFile saved off earlier 
                     #  (problem file), we need to restore it.
                     #===========================================
                     elif [ "$package" = "old" ]; then
                     
                        #========================================
                        #  Restore the current file with the 
                        #  original that was previously saved
                        #  off (via mv).
                        #========================================
                        mv "$InstallPath/$file.orig" "$InstallPath/$file"
                        
                        #========================================
                        #  If the restore of the current file
                        #  failed, print an error message to the
                        #  user and exit processing.
                        #========================================
                        if [ $? -ne 0 ]; then
                           echo "*** ERROR:"
                           echo "  Renaming $InstallPath/$file.orig to $InstallPath/$file"
                           echo "  Original files could not be restored."
                           Error_Exit
                        fi
                     fi
                  done < $UpdatedTOCFile
                  
                  #==============================================
                  #  If we made it here, something went wrong.
                  #  We should have taken one of the exits above.
                  #  Print an error message to the user and 
                  #  exit processing.
                  #==============================================
                  echo "*** ERROR:"
                  echo "  An error occured while trying to restore the original files."
                  Error_Exit
               fi
            fi
         done < $UpdatedTOCFile
   
   
      #==========================================================
      #  Otherwise, the user specified a backup path other than 
      #  the product install path...proceed to backup original 
      #  files.
      #==========================================================
      else
   
         #=======================================================
         #  Save the original files at the location specified by
         #  the user.
         #=======================================================
         
         #=======================================================
         #  Indicate to the user that the original files are 
         #  being saved to the location they specified.
         #=======================================================
         echo ""
         echo "  Saving original files to $SavePath ..."
      
         #=======================================================
         #  Set the SavePath (backup location).
         #=======================================================
         SavePath="$SavePath/${ProductName}_${ProductVersion}.orig"
         
         #=======================================================
         #  Walk through the Updated TOC file and save the files
         #  in the user specified backup location.
         #=======================================================
         while IFS="$TOC_IFS" read file size package bytes month day
         do
            
            #====================================================
            #  If the current file indicator is "old"...proceed 
            #  to back it up.
            #====================================================
            if [ "$package" = "old" ]; then
            
               #=================================================
               #  If the current file's backup location directory
               #  doesn't exit, create it.
               #=================================================
               if [ ! -d $(dirname "$SavePath/$file") ]; then
                  mkdir -p "$(dirname "$SavePath/$file")"
                  
                  #==============================================
                  #  If failed to create the directory, print an
                  #  error message to the user and exit 
                  #  processing.
                  #==============================================
                  if [ $? -ne 0 ]; then
                     echo "*** ERROR:"
                     echo "  Creating directory $(dirname "$SavePath/$file")."
                     Error_Exit
                  fi
               fi
               
               #=================================================
               #  If an old backup copy exists, remove it before 
               #  the copy.  This will work even if it's 
               #  read-only or root owned.
               #=================================================
               if [ -f "$SavePath/$file" ]; then
                  rm -f "$SavePath/$file"
               fi
            
               #=================================================
               #  Save (backup) the original file.
               #=================================================
               cp -p "$InstallPath/$file" "$SavePath/$file"
               
               #=================================================
               #  If the file copy failed, print an error message
               #  to the user and exit processing.
               #=================================================
               if [ $? -ne 0 ]; then
                  echo "*** ERROR:"
                  echo "  Copying $InstallPath/$file to $SavePath/$file."
                  Error_Exit
               fi
            fi
         done < $UpdatedTOCFile
      fi

   fi

}


######################################################################
#=====================================================================
#  Remove_NonWritable_Files()
#
#  Walk through the Updated TOC file and remove non-writable original
#  files.
#
#  We know we have full access rights to the directories but some of 
#  the original files to be replaced may be "read only" or root-owned
#  with the "set-user-id" bit set.  These cannot be updated by the 
#  tar command unless the old version is first removed, so remove 
#  them now.
#=====================================================================
######################################################################
Remove_NonWritable_Files()
{

   #=============================================================
   #  Walk through the Updated TOC file.  If the current file
   #  is not writable, force remove it.  
   #=============================================================
   while IFS="$TOC_IFS" read file size package bytes month day
   do
      if [ -f "$InstallPath/$file" ] && [ ! -w "$InstallPath/$file" ]; then
         rm -f "$InstallPath/$file"
         # no error check here; wait and see if the tar works
         #echo "Test: file not writable: $file"
      fi
   done < $UpdatedTOCFile

}


######################################################################
#=====================================================================
#  Apply_The_Patch()
#
#  Uncompresses, untars and installs the ESRI Patch files in the 
#  appropriate location.
#=====================================================================
######################################################################
Apply_The_Patch()
{

   #=============================================================
   #  Indicate to the user that the ESRI Patch is being applied.  
   #=============================================================
   echo "  Applying the $(ToLower "$QFEAbbreviated") ..."

   #XXXXX========================================================
   #  This is hoaky, but necessary!   zcat will not uncompress a 
   #  file without a .Z (upper-Case) extension.  And, we cannot 
   #  create a CD-ROM with mixed case filenames.  So, we create 
   #  the ESRI Patch file on the CD with a lower-case .z 
   #  extension, and then this:
   #=============================================================
   TmpPatchFile=/tmp/applypatch.tar.Z
   rm -f $TmpPatchFile
   
   #XXXXX========================================================
   #  Create a link with upper-case .Z pointing to compressed
   #  tar file with lower-case .z:
   #    /tmp/applypatch.tar.Z -> $PatchHome/..../$ApplyPatchTAR
   #=============================================================
   if [ $ArcSDE = 1 ]; then
      if [ "$ProductBitSet" = "64" ] && [ "$CurrentPlatform" != "$Tru64Platform" ]; then
         ln -s $PatchHome/$CurrentPlatform$ProductBitSet.$CurrentDB/$ApplyPatchTAR $TmpPatchFile
      else
         ln -s $PatchHome/$CurrentPlatform.$CurrentDB/$ApplyPatchTAR $TmpPatchFile
      fi
   else
      if [ $ArcGIS = 1 ]; then
         if [ "$ProductDispName" = "ArcGIS Server ADF for the Java Platform" ]; then
            ln -s $PatchHome/hp_ibm.$ProductFolderName/$ApplyPatchTAR $TmpPatchFile
        # elif [ "$ProductDispName" = "ArcIMS Web ADF for the Java Platform" ]
        # then
        #    ln -s $PatchHome/linux_solaris.$ProductFolderName/$ApplyPatchTAR $TmpPatchFile
         elif [ "$ProductDispName" = "ArcGIS Help System for the Java Platform" ]; then
            ln -s $PatchHome/linux_solaris.$ProductFolderName/$ApplyPatchTAR $TmpPatchFile
         else
            ln -s $PatchHome/$CurrentPlatform.$ProductFolderName/$ApplyPatchTAR $TmpPatchFile
         fi
      else
         ln -s $PatchHome/$CurrentPlatform/$ApplyPatchTAR $TmpPatchFile
      fi
   fi

   #=============================================================
   #  If failure to create the link, print an error message,
   #  restore and exit.
   #=============================================================
   if [ $? -ne 0 ]; then
      echo ""
      echo "*** ERROR:"
      echo "  Creating scratch link $TmpPatchFile."
      echo "  Make sure that at least 10K bytes are free in /tmp."
      Restore_And_Exit
   fi

   #=============================================================
   #  cd to the InstallPath.
   #=============================================================
   cd $InstallPath > /dev/null 2>&1
   
   #=============================================================
   #  Call the function to uncompress, untar and install the QFE
   #  Patch files in the Install location.
   #=============================================================
   Extract_The_Patch
   
   if [ $? -ne 0 ]; then
      echo "*** ERROR:"
      echo "  The tar command being used to install the $QFEAbbreviated files failed"
      Restore_And_Exit
   fi
 
   #=============================================================
   # Delete and files that are flagged for deletion
   #=============================================================
   Delete_Files

   if [ $? -ne 0 ]; then
      echo "*** ERROR:"
      echo "  Deleting files flagged for deletion failed."
      Restore_And_Exit
   fi

   #=============================================================
   #  Return to the original working directory.
   #=============================================================
   cd $CurrentWorkingDir > /dev/null 2>&1

}

######################################################################
# SetRollbackScriptDestinationPath()
#
# Embedded products like Insights and Urban require they're own
# .Setup/qfe folder so removepatch doesn't uninstall the parent
# product's patches.
######################################################################
SetRollbackScriptDestinationPath()
{
  local product="$ProductFlag"
  local qfe_dir="${InstallPath}/.Setup/qfe"

  case "$product" in
    insights*|urban)
      qfe_dir="${qfe_dir}/${product}"
      ;;
  esac

  RollbackScriptPath="$qfe_dir"
  RollbackBackupScript="${RollbackScriptPath}/.resources/backuppatch.sh"
  RollbackRemoveScript="${RollbackScriptPath}/removepatch.sh"
}

######################################################################
# IsPatchInstalled()
#
# Read the ESRI_PATCH_LOG and search for the QFE_ID.  Return true
# if the patch is installed.
######################################################################
IsPatchInstalled()
{
  local qfe_id="$1"
  local res=1
  if [ -f "$InstallPath/$QFETestFile" ]; then
    grep -q "$qfe_id" "$InstallPath/$QFETestFile"
    res=$?
  fi
  [ $res -eq 0 ]
}


######################################################################
# CheckForBaselinePatch()
#
# Check if a baseline patch is installed or not.  If none is required
# or if it's installed return.  If it's required and not installed
# display an error and exit.
######################################################################
CheckForBaselinePatch()
{
  local res=0

  if [ -n "$BaselinePatchQfeId" ]; then
    IsPatchInstalled "$BaselinePatchQfeId"
    res=$?
  fi
  if [ $res -ne 0 ]; then
    echo ""
    echo "*** ERROR: The following baseline patch is not installed.  The below patch"
    echo "  needs to be installed before installing the current one:"
    echo ""
    echo "  Name:   $BaselinePatchName"
    echo "  QFE_ID: $BaselinePatchQfeId"
    echo "  URL:    $BaselinePatchUrl"
    echo ""
    Clean_Up
    exit 1
  fi
}

######################################################################
# Is_Patch_Backed_Up()
#
# Return true if this patch is already installed and backed up.
#
# Check the manifest.txt to see if this patch is already installed.
# If the patch_backup and patch_remove scripts aren't there then just
# return false since there's no way to uninstall without these.
######################################################################
Is_Patch_Backed_Up()
{
  local result=1
  local manifest="${RollbackScriptPath}/.resources/manifest.txt"

  if [ -f "$manifest" ]; then
    found=$(grep "$QFENumber" $manifest) 

    if [ -n "$found" ]; then
      # Patch is already backed up
      result=0
    fi
  fi

  echo $result
}


######################################################################
# Check_For_Previous_Backup()
#
# Check if the backup system is in place and if this patch is already
# installed.  If so, notify the user and exit.
######################################################################
Check_For_Previous_Backup()
{
  if [ $(Is_Patch_Backed_Up) -eq 0 ]; then
    echo ""
    echo "*** ERROR:"
    echo "  This patch is already installed.  You will need to uninstall this patch"
    echo "  before reinstalling it.  To uninstall this patch run the following command:"
    echo ""
    echo "      % $RollbackRemoveScript -q $QFENumber" 
    echo ""
    echo "-------------------------------------------------------------------------------"
    Clean_Up
    exit 1
  fi
}

######################################################################
# Copy_Backup_Script() / Copy_Remove_Script()
#
# Called from Copy_Rollback_Scripts().
######################################################################
Copy_Backup_Script()
{
  local resource_dir="$1"
  local backup_script="${resource_dir}/backuppatch.sh"
  local rollback_resources_dir="${RollbackScriptPath}/.resources"
  
  if [ ! -e "${backup_script}" ]; then
    echo "*** Error.  Patch backup script not found: ${backup_script}"
    return 1
  fi

  if [ ! -d "$rollback_resources_dir" ]; then
    mkdir -p "$rollback_resources_dir"
  fi

  # Don't replace existing newer versions
  if [ -f "${rollback_resources_dir}/backuppatch.sh" ]; then
    if [ "${rollback_resources_dir}/backuppatch.sh" -nt "${backup_script}" ]; then
      return 0
    fi
  fi

  echo "  Copying rollback scripts ..."

  cp -p "${backup_script}" "${rollback_resources_dir}"/

  if [ $? -ne 0 ]; then
    echo "*** Error.  Failed to copy $(basename ${backup_script}) to ${rollback_resources_dir}."
    return 1
  fi

  chmod +x "${rollback_resources_dir}/backuppatch.sh"
  return 0
}

Copy_Remove_Script()
{
  local resource_dir="$1"
  local remove_script="${resource_dir}/removepatch.sh"

  if [ ! -e "${remove_script}" ]; then
    echo "*** Error.  Patch backup script not found: ${remove_script}"
    return 1
  fi

  # Don't replace existing newer versions
  if [ -f "${RollbackScriptPath}/removepatch.sh" ]; then
    if [ "${RollbackScriptPath}/removepatch.sh" -nt "${remove_script}" ]; then
      return 0
    fi
  fi

  cp -p "${remove_script}" "${RollbackScriptPath}"/

  if [ $? -ne 0 ]; then
    echo "*** Error.  Failed to copy $(basename ${remove_script}) to ${resource_dir}."
    return 1
  fi

  chmod +x "${RollbackScriptPath}/removepatch.sh"
  return 0
}


######################################################################
#=====================================================================
# Copy_Rollback_Scripts()
#
# Create the $installDir/.Setup/qfe folder if not already present, then
# Copy the rollback scripts from ./resources to that location.
#
# Always update the rollback scripts to replace them with the newest 
# versions in this patch.
#=====================================================================
######################################################################
Copy_Rollback_Scripts()
{
  if [ ! -d "$RollbackScriptPath" ]; then
    mkdir -p "${RollbackScriptPath}"

    if [ $? -ne 0 ]; then
      echo "*** Error creating backup script folder ${RollbackScriptPath}."
      Clean_Up
      exit 1
    fi
  fi

  local resource_dir="$ScriptDir/resources"
  local temp_dir="/tmp/rollback_tmp.$$.tmp"
  local res_tar=${resource_dir}/res.tar

  if [ ! -d "$temp_dir" ]; then
    mkdir -p $temp_dir
  fi

  cd ${resource_dir}
  tar xf ${res_tar} -C ${temp_dir} > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    echo "*** Error extracting rollback resource scripts."
    rm -rf "$temp_dir"
    Clean_Up
    exit 1
  fi

  Copy_Backup_Script "${temp_dir}"
  if [ $? -ne 0 ]; then
    rm -rf "$temp_dir"
    Clean_Up
    exit 1
  fi

  Copy_Remove_Script "${temp_dir}"
  if [ $? -ne 0 ]; then
    rm -rf "$temp_dir"
    Clean_Up
    exit 1
  fi

  rm -rf "$temp_dir"
}


######################################################################
#=====================================================================
#  CheckProductVersionMatch()
#
#  Compare the installed product version (VER) with the patch version 
#  in the TOC (ProductVersion) to prevent installing the patch on an 
#  incompatible product installation.
#=====================================================================
######################################################################
CheckProductVersionMatch()
{
  echo "  Checking product/patch version match..."

  local ver="$VER"

  # Handle Insights
  if [ "$ProductFolderName" = "insightsportal" ] || [ "$ProductFolderName" = "insightsserver" ]; then
    ver="$Z_Insights_VERSION"
  fi

  # Handle Urban
  if [ "$ProductDispName" = "ArcGIS Urban" ]; then
    ver="$Z_ArcGISUrban_VERSION"
  fi

  if [ "$ver" != "$ProductVersion" ]; then
    echo ""
    echo "  *** ERROR: The patch version does not match the installed product version:"
    echo ""
    echo "        Patch version: $ProductVersion"
    echo "      Product version: $ver"
    echo ""
    echo "  Check that you have downloaded the correct version of this patch."
    echo ""
    Clean_Up
    exit 1
  fi
}

######################################################################
#=====================================================================
#  CheckForRootServerInstaller() 
#
#  Complain if root attempts to install Server, Portal or Datastore.
#=====================================================================
######################################################################
CheckForRootServerInstaller()
{
  cd $ScriptDir
  for dir in $(ls -1)
  do
    if [ -d "$dir" ]; then
      local toc=$ScriptDir/${dir}/applypatch.toc
      if [ -f "$toc" ]; then
        local product=$(Get_Patch_Info Product $toc)
        if $(IsServerProduct $product) ; then
          if [ $CurrentUserID -eq 0 ]; then
            echo ""
            echo "*** ERROR: This update can only be applied by the install owner. Run"
            echo "applypatch again to install this update as the install owner."
            echo ""
            Clean_Up
            exit 1
          fi
        fi
      fi
    fi
  done
}


######################################################################
#=====================================================================
#  Restore_And_Exit() 
#
#  The installation of the patch failed.  This routine is only called 
#  when some of the patch files may have already been installed, 
#  leaving the ProductHome in a ragged state.  If the user specified 
#  backing up the original files, give them the option of putting 
#  things back the way they were.
#=====================================================================
######################################################################
Restore_And_Exit() 
{

   #=============================================================
   #  Indicate to the user that the ESRI Patch has failed and it
   #  will need to be re-run.
   #=============================================================
   echo ""
   echo "             The $QFEAbbreviated ($QFEVersion) installation has failed."
   echo "             You will have to re-run applypatch to install $QFEVersion."
   echo ""


   # Run the external restore script if present
   if [ -f "$RollbackRemoveScript" ]; then
     "$RollbackRemoveScript" -u
     Clean_Up
     exit 1
   fi

   #=============================================================
   #  If the user specified to backup the original files...
   #  proceed to restore.
   #=============================================================
   if [ "$SaveFiles" = "yes" ]; then

      #XXXXX=====================================================
      #  Prompt the user to either restore or quit.
      #==========================================================
      echo "             Press 'y' to restore the original files or 'q' to quit."
      echo ""

      Prompt "Restore original files? [y,q] (y): "

      read choice

      #==========================================================
      #  Perform actions based upon users choice.
      #==========================================================
      case $(ToLower "${choice}") in
         n*)
            Clean_Up
            exit 1
            ;;
         q*)
            Voluntary_Quit
            ;;
      esac

      #==========================================================
      #  Indicate to the user the files are being restored.
      #==========================================================
      echo "  Restoring original files ..."
      
      #==========================================================
      #  If the product install path is the same as the user
      #  selected backup path...proceed to restore the original
      #  files.
      #==========================================================
      if [ "$InstallPath" = "$SavePath" ]; then
      
         #=======================================================
         #  Walk through the Updated TOC file and restore files
         #  as necessary.
         #=======================================================
         while IFS="$TOC_IFS" read file size package bytes month day
         do

            #====================================================
            #  If the current file indicator is "old"...proceed 
            #  to restore it.
            #====================================================
            if [ "$package" = "old" ]; then
	    
	             #=================================================
               #  If a target file exists, remove it before the
               #  restore.  This will work even if it's read-only
               #  or root owned.
               #=================================================
               if [ -f "$InstallPath/$file" ]; then
                  rm -f "$InstallPath/$file"
               fi

               #=================================================
               #  Restore the current file (via mv).
               #=================================================
               mv "$InstallPath/$file.orig" "$InstallPath/$file"
               
               #=================================================
               #  If unable to restore the current file, print an
               #  error message to the user and exit processing.
               #=================================================
               if [ $? -ne 0 ]; then
                  echo "*** ERROR:"
                  echo "  Renaming $InstallPath/$file.orig to $InstallPath/$file"
                  echo "  Could not restore original files."
                  echo ""
                  Clean_Up
                  exit 1
               fi
	          fi
         done < $UpdatedTOCFile
         
         #=======================================================
         #  Successful restore.  Indicate to the user that the
         #  original files were restored.
         #=======================================================
         echo "  Original files restored."


      #==========================================================
      #  Otherwise, the user specified a backup path other than 
      #  the product install path...proceed to restore the
      #  original files.
      #==========================================================
      else

         #=======================================================
         #  Walk through the Updated TOC file and restore files
         #  as necessary.
         #=======================================================
         while IFS="$TOC_IFS" read file size package bytes month day
         do
            #====================================================
            #  If the current file indicator is "old"...proceed 
            #  to restore it.
            #====================================================
            if [ "$package" = "old" ]; then

               #=================================================
               #  If a target file exists, remove it before the 
               #  restore.  This will work even if it's read-only 
               #  or root owned.
               #=================================================
               if [ -f "$InstallPath/$file" ]; then
                  rm -f "$InstallPath/$file"
               fi
            
               #=================================================
               #  Restore the original file.
               #=================================================
               cp -p "$SavePath/$file" "$InstallPath/$file"
               
               #=================================================
               #  If unable to restore the current file, print an
               #  error message to the user and exit processing.
               #=================================================
               if [ $? -ne 0 ]; then
                  echo "*** ERROR:"
                  echo "  Copying $SavePath/$file to $InstallPath/$file"
                  echo "  Could not restore original files."
                  echo " "
                  Clean_Up
                  exit 1
               fi
	          fi
         done < $UpdatedTOCFile
         
         #=======================================================
         #  Successful restore.  Indicate to the user that the
         #  original files were restored.
         #=======================================================
         echo "  Original files restored."

      fi
   fi
  
   #=============================================================
   #  Clean up and exit processing.
   #=============================================================
   Clean_Up
   exit 1
   
}


######################################################################
#=====================================================================
#  Extract_The_Patch() 
#
#  Extracts files from compressed tar file.
#=====================================================================
######################################################################
Extract_The_Patch() 
{
  tmp_list=/tmp/applypatch_files.$$.lst

  # Create a list of files to pass to tar.  Skip over blank lines and comments
  #
  cat $UpdatedTOCFile | grep -v "^#" | grep -v "^$" | grep -w -v ":delete" | cut -d${TOC_IFS} -f1 > $tmp_list

  if [ $(uname) = "SunOS" ]; then
    uncompress < $TmpPatchFile | $TAR xf - -I $tmp_list > /dev/null 2>&1
  else
    $TAR zxf $TmpPatchFile -T $tmp_list > /dev/null 2>&1
  fi

  res=$?

  rm -f $tmp_list

  # Return true (0) if tar succeeds, false (1) otherwise 
  return $res
}


######################################################################
#=====================================================================
#  Delete_Files()
#
#  If "delete" is passed as a package name then the file is flagged
#  for deletion like this.  
#
#  framework/runtime/xvfb/init_Xvfb.sh:8:old:4395:Nov:29
#  framework/etc/scripts/agsserver.sh:16:old:15145:Nov:29
#  framework/etc/scripts/actions.sh:4:old:2303:Nov:29
#  usr/init_user_param.sh:4:delete:6156:Nov:29    <-- delete this file
#
#  Delete them here.
#=====================================================================
######################################################################
Delete_Files()
{
  local -a file_list=()
  local res=0
 
  while IFS= read line
  do
    file_list+=( "$line" )
  done < <(cat $UpdatedTOCFile | grep -v "^#" | grep -v "^$" | grep ":delete" | cut -d${TOC_IFS} -f1)

  if [ ${#file_list[@]} -gt 0 ]; then
    for file in "${file_list[@]}"
    do
      if [ -f "$file" ]; then
        rm -f "$file"
        res=$?

        [ "$res" -ne 0 ] && break
      fi
    done
  fi
  return $res
}

######################################################################
#=====================================================================
#  Verify_The_Install()
#
#  Uncompresses, untars and installs the ESRI Patch files in the 
#  appropriate location.
#=====================================================================
######################################################################
Verify_The_Install()
{
   #=============================================================
   #  Print a message to the user indicating that the ESRI Patch
   #  has been installed.
   #=============================================================
   #echo ""
   #echo "  $QFEVersion has been installed."
   #echo ""

   #XXXXX========================================================
   #  Prompt the user to verify the ESRI Patch installation.
   #=============================================================
   #if test `uname` = "Linux"
   #then
   #  echo -n "Press the enter key to verify the installation [q]: "
   #else
   #  echo "Press the enter key to verify the installation [q]: \c"
   #fi
   #read choice
   
   
   #=============================================================
   #  Restore, clean up and exit if the user selected to quit.
   #=============================================================
   #if [ "X$choice" = "Xq" -o "X$choice" = "XQ" ];
   #then
   #   Restore_And_Exit
   #fi
   
   #=============================================================
   #  Print a message to the user indicating that the ESRI Patch
   #  is being verified.
   #=============================================================
   echo "  Verifying $QFEAbbreviated installation ..."

   #=============================================================
   #  Call function to validate the ESRI Patch files were 
   #  properly installed.  Get an account of any errors.
   #=============================================================
   error_count=$(Validate_The_Patch)
   
   #=============================================================
   #  If there were errors in the validation:  list the errors,
   #  restore and exit.
   #=============================================================
   if [ $error_count -ne 0 ]; then
      List_Validation_Errors
      Restore_And_Exit
      
   #=============================================================
   #  Otherwise, no errors.  Print a message to the user 
   #  indicating the ESRI Patch was successfully installed.
   #=============================================================
   else
#      if [ "$QFEAbbreviated" = "Service Pack" ]
#      then
#         Update_ServicePack_Info
#         if test $? -ne 0
#         then
#            Restore_And_Exit
#         fi
#      fi
      
      Update_QFE_Info
      if [ $? -ne 0 ]; then
         Restore_And_Exit
      fi

      if [ "$ProductDispName" = "ArcGIS Server" ] || 
         [ "$ProductDispName" = "Portal for ArcGIS" ]    || 
         [ "$ProductDispName" = "ArcGIS Data Store" ]    || 
         [ "$ProductDispName" = "ArcGIS Notebook Server" ]    || 
         [ "$ProductDispName" = "ArcGIS Mission Server" ]    || 
         [ "$ProductDispName" = "ArcGIS GeoEnrichment Server" ] ||
         [ "$ProductDispName" = "ArcGIS Insights (Portal)" ] ||
         [ "$ProductDispName" = "ArcGIS Insights (Server)" ] ||
         [ "$ProductDispName" = "ArcGIS Engine ${VER}" ] ||
         [ "$ProductDispName" = "ArcGIS Urban" ] ||
         [ "$ProductDispName" = "ArcGIS Video Server" ] ||
         [ "$ProductDispName" = "ArcGIS Data Pipelines Server" ] 
      then
        #Update_SP_Keys
        Run_SP_Config
        RunWineBoot
      fi
    
      # Display a helpful post install message for WebAdaptor only 
      if [ "$ProductDispName" = "ArcGIS Web Adaptor for the Java Platform" ]; then
        Display_WebAdaptor_PostInstall_Message
      fi

      # Display a helpful post install message for VideoServer only
      if [ "$ProductDispName" = "ArcGIS Video Server" ]; then
        Display_VideoServer_PostInstall_Message
      fi

      echo ""
      #echo "  The $QFEAbbreviated ($QFEVersion) has been successfully applied to $ProductDispName $ProductVersion $ArcSDESet $ProductSerPack."
      if [ $ArcSDE -eq 1 ]; then
        #echo "  The $(ToLower $QFEAbbreviated) ($QFEVersion) has been successfully applied to $ProductDispName $ProductVersion $ArcSDESet."
        echo "The following $(ToLower "$QFEAbbreviated") has been applied successfully to $ProductDispName $ProductVersion $ArcSDESet!"
      else
        #echo "  The $(ToLower $QFEAbbreviated) ($QFEVersion) files have been successfully applied to $ProductDispName."
        echo "The following $(ToLower "$QFEAbbreviated") has been applied successfully to ${ProductDispName}!"
      fi

      echo ""
      echo "      $QFEVersion"
      echo ""
   fi

}


######################################################################
#=====================================================================
#  Validate_The_Patch() 
#
#  Check that the patch was installed correctly by inspecting the 
#  ESRI Patch files installed.  Write any error messages to the
#  $ValidationErrorList.
#=====================================================================
######################################################################
Validate_The_Patch() 
{
  error_count=0
   
  while IFS="$TOC_IFS" read file size package bytes month day
  do
  
    # Validate deleted files (if any)
    if [ "$package" = "delete" ]; then
      if [ -f "$InstallPath/$file" ]; then
        error_count=$(( error_count + 1 ))
        echo ""
        echo "  *** File flagged for deletion is still present:" >> $ValidationErrorList
        echo "          $InstallPath/$file"                      >> $ValidationErrorList
      fi
      continue
    fi

    if [ -f "$InstallPath/$file" ]; then
     
      # Check the file sizes against what's in the TOC.  If they
      # differ bump the error count and log the error.
      f5=$(Get_File_Bytes "$InstallPath/$file")
	   
      if [ $bytes -ne $f5 ]; then
        error_count=$(( error_count + 1 ))
        echo ""                                              >> $ValidationErrorList
        echo "  *** Incorrect file size: $InstallPath/$file" >> $ValidationErrorList
        echo "                 Expected: $bytes"             >> $ValidationErrorList
        echo "                   Actual: $f5"                >> $ValidationErrorList
      fi
    else
      # If the file is not there and it's not a directory it's an error
      if [ ! -d "$InstallPath/$file" ]; then
        error_count=$(( error_count + 1 ))
        echo ""                                              >> $ValidationErrorList
        echo "  *** File missing:  $InstallPath/$file"       >> $ValidationErrorList
      fi
    fi
   
   done < $UpdatedTOCFile
  
  echo $error_count
}


######################################################################
#=====================================================================
#  List_Validation_Errors() 
#
#  List the files that were not installed correctly by showing the
#  error log created in Validate_The_Patch().
#=====================================================================
######################################################################
List_Validation_Errors() 
{
  if [ -f "$ValidationErrorList" ]; then
    cat "$ValidationErrorList"
  fi
}


######################################################################
#=====================================================================
#  Get_File_Bytes() 
#
#  Get the size in bytes of the specified file.
#=====================================================================
######################################################################
Get_File_Bytes() 
{
  if [ -f "$1" ]; then
    stat -c %s "$1" > /dev/null 2>&1
    if [ $? -ne 0 ]; then
      ls -l $1 | ( read f1 f2 f3 f4 f5 f6 f7 f8; echo $f5 )
    else
      stat -c %s "$1" 
    fi
  fi
}


######################################################################
#=====================================================================
#  Get_File_Month() 
#
#  Get the abbreviated month portion of the date of the specified 
#  file (e.g. Jan...Dec).
#=====================================================================
######################################################################
Get_File_Month() 
{
  if [ -f "$1" ]; then
    date -r "$1" "+%b" > /dev/null 2>&1
    if [ $? -ne 0 ]; then
      ls -l $1 | ( read f1 f2 f3 f4 f5 f6 f7 f8; echo $f6 )
    else
      date -r "$1" "+%b"
    fi
  fi
}


######################################################################
#=====================================================================
#  Get_File_Day() 
#
#  Get the day portion of the date of the specified file (1...31).
#=====================================================================
######################################################################
Get_File_Day() 
{
  if [ -f "$1" ]; then
    date -r "$1" "+%-d" > /dev/null 2>&1
    if [ $? -ne 0 ]; then
      ls -l $1 | ( read f1 f2 f3 f4 f5 f6 f7 f8; echo $f7 )
    else
      date -r "$1" "+%-d"
    fi
  fi
}

######################################################################
#=====================================================================
#  Update_QFE_Info() 
#
#  Update the .ESRI_<Product>_PATCH_LOG with the current QFE information.
#=====================================================================
######################################################################
Update_QFE_Info() 
{
   local ProcessID=$$
   local date_now=$(date '+%m/%d/%y %H:%M:%S')
   local TmpQFEFile=/tmp/applypatch.$ProductName.qfe.$ProcessID
   local QFEExist=0

   rm -f $TmpQFEFile
   touch $TmpQFEFile

   #==========================================================
   # Insert the current QFE info to the head of the info file:
   # .ESRI_<Product>_PATCH_LOG.
   #==========================================================
   echo "#START"               		                 >> $TmpQFEFile
   echo "QFE_ID: $QFENumber"   		                 >> $TmpQFEFile
   echo "QFE_TYPE: $QFEAbbreviated"		             >> $TmpQFEFile

   if [ "$QFEAbbreviated" = "Service Pack" ] || 
      [ "$QFEAbbreviated" = "Update" ]; then
      echo "QFE_TITLE: $ProductSerPack" 	         >> $TmpQFEFile
   else
      echo "QFE_TITLE: $QFEVersion"        	       >> $TmpQFEFile
   fi

   echo "QFE_FILE: $OriginalPatchFilename"         >> $TmpQFEFile
   echo "INSTALL_TIME: $date_now" 	               >> $TmpQFEFile
   echo "#END"				                             >> $TmpQFEFile
   echo ""			       		                         >> $TmpQFEFile
     
   #==========================================================
   # Move the existing .ESRI_XXX_PATCH_LOG file to a tmp file
   # and append it's contents to $TmpQFEFile so the new entry
   # appears on top.
   #==========================================================
   if [ -f "$InstallPath/$QFETestFile" ]; then
      QFEExist=1
      cat $InstallPath/$QFETestFile	               >> $TmpQFEFile 
      rm -f $InstallPath/$QFETestFile.tmp
      mv $InstallPath/$QFETestFile $InstallPath/$QFETestFile.tmp

      if [ $? -ne 0 ]; then
         echo "*** ERROR:"
         echo " Can not backup QFE infomation to $QFETestFile.tmp."
         echo ""
         return 1
      fi
   fi

   #==========================================================
   # Copy the updated QFE info back to .ESRI_<Product>_QFE.
   #==========================================================
   cp -p $TmpQFEFile $InstallPath/$QFETestFile

   if [ $? -ne 0 ]; then
      echo "*** ERROR:"
      echo " Writing QFE information has failed."
      echo ""
      if [ $QFEExist -eq 1 ]; then
         mv $InstallPath/$QFETestFile.tmp $InstallPath/$QFETestFile
         if [ $? -ne 0 ]; then
            echo " Recover $QFETestFile failed."
            echo ""
         fi
      fi
      rm -f $InstallPath/$QFETestFile.tmp
      return 1
   fi

   rm -f $InstallPath/$QFETestFile.tmp
   chmod 444 $InstallPath/$QFETestFile
   if [ $? -ne 0 ]; then
      echo "*** WARNING:"
      echo " Change the $QFETestFile permission to read only failed."
      echo ""
   fi

   rm -f $TmpQFEFile
   return 0
}

######################################################################
#=====================================================================
# Get_SP_Info()
#
# Get the installed service pack info from .ESRE_<Prod>_PATCH_LOG.
#=====================================================================
######################################################################
Get_SP_Info()
{
   local QFEType=""
   local QFETitle=0
   local start=0
   local FirstTime=0
   local FoundSP="0"
   
   local PatchLog="$InstallPath/$QFETestFile"
   if [ -f $PatchLog ]; then
      FindSP=$(grep "QFE_TYPE: Service Pack" $PatchLog)
      if [ -z "$FindSP" ]; then
         echo 0
      else
      
         while read file token2
         do
   
            #==========================================================
            #  If current line is blank or a comment line - skip it.
            #==========================================================
            if [ -z "$file" ] || [ "$file" = "#" ]; then
               continue
         
            elif [ "$file" = "#START" ]; then
               if [ $start != 0 ]; then
                  echo "*** WARNING:"
                  echo "  #START and #END mismatch in the file $PatchLog"
               fi
               start=1
            elif [ "$file" = "#END" ]; then
               if [ $start = 1 ]; then
                  start=2
               else
                  echo "*** WARNING:"
                  echo "  #START and #END mismatch in the file $PatchLog"
                  echo ""
               fi
            else
               if [ $start = 1 ]; then
                  if [ "$file" = "QFE_TYPE:" ]; then
                     QFEType=$token2
                  elif [ "$file" = "QFE_TITLE:" ]; then
                     QFETitle=$token2
                  else
                     continue
                  fi
               fi
            fi
    
            if [ $start = 2 ]; then
               if [ "$QFEType" = "Update" ]; then
                  echo 0
                  break
               fi
               if [ "$QFEType" = "Service Pack" ] && [ $FirstTime -eq 0 ]; then
                  FirstTime=1
                  echo $QFETitle
                  break
               fi
               start=0
            fi
         done < "$PatchLog"
         
         fi
   else
      echo 0
   fi
}


######################################################################
#=====================================================================
# Get_Update_Info()
#
# Get the installed Update info from .ESRE_<Prod>_PATCH_LOG.
#=====================================================================
######################################################################
Get_Update_Info()
{
   local QFEType=""
   local QFETitle=0
   local start=0
   local FirstTime=0
   local FoundSP="0"
   
   local PatchLog="$InstallPath/$QFETestFile"

   if [ -f "$PatchLog" ]; then

      FindSP=$(grep "QFE_TYPE: Update" $PatchLog)
      if [ -n "$FindSP" ]; then
      
         while read file token2
         do
   
            # If current line is blank or a comment line - skip it.
            if [ -z "$file" ] || [ "$file" = "#" ]; then
               continue
         
            elif [ "$file" = "#START" ]; then
               if [ $start != 0 ]; then
                  echo "*** WARNING:"
                  echo "  #START and #END mismatch in the file $PatchLog"
               fi
               start=1
            elif [ "$file" = "#END" ]; then
               if [ $start = 1 ]; then
                  start=2
               else
                  echo "*** WARNING:"
                  echo "  #START and #END mismatch in the file $PatchLog"
                  echo ""
               fi
            else
               if [ $start = 1 ]; then
                  if [ "$file" = "QFE_TYPE:" ]; then
                     QFEType=$token2
                  elif [ "$file" = "QFE_TITLE:" ]; then
                     QFETitle=$token2
                  else
                     continue
                  fi
               fi
            fi
    
            if [ $start = 2 ]; then
               if [ "$QFEType" = "Update" ] && [ $FirstTime -eq 0 ]; then
                  FirstTime=1
                  echo $QFETitle
                  break
               fi
               start=0
            fi
         done < "$PatchLog"
         return 
      fi
      echo 0
   fi
   echo 0
}



#=====================================================================
#  Parse_Command_Line()
#
#  Parses the command line to support silent install.
#=====================================================================
Parse_Command_Line()
{
  declare -A prods=( [-arcobjcpp]=arcobjcpp
                     [-arcobjjava]=arcobjjava
                     [-arcreader]=arcreader
                     [-datastore]=datastore
                     [-engcpp]=engcpp
                     [-engine]=engine
                     [-engjava]=engjava
                     [-ims]=ims
                     [-imsjava]=imsjava
                     [-javahelp]=javahelp
                     [-lm]=lm
                     [-ma]=ma
                     [-mapsvr]=mapsvr
                     [-mole]=mole
                     [-portal]=portal
                     [-server]=server
                     [-notebookserver]=notebookserver
                     [-missionserver]=missionserver
                     [-insightsportal]=insightsportal
                     [-insightsserver]=insightsserver
                     [-urban]=urban
                     [-videoserver]=videoserver
                     [-datapipelinesserver]=datapipelinesserver
                     [-slpde]=serverlpde
                     [-slpes]=serverlpes
                     [-slpfr]=serverlpfr
                     [-slpja]=serverlpja
                     [-slpzhcn]=serverlpzhcn
                     [-srvrjava]=srvrjava
                   )

  if [ $NumArgs -eq 1 ]; then
    [ "$AllArgs" = "-h" ] || [ "$AllArgs" = "-s" ] && Usage || Usage "Unrecognized option ($AllArgs)."
    return
  fi

  if [ $NumArgs -gt 1 ]; then

    local -i TheIndex=0

    for Arg in $AllArgs
    do
      TheIndex=$(( $TheIndex + 1 ))

      if [ $TheIndex -eq 1 ]; then

        if [ "$Arg" = "-s" ]; then
          SilentInstall=1
        else
          Usage "Invalid option ($Arg)."
        fi

      elif [ $TheIndex -eq 2 ]; then
        SilentProd=${prods[$Arg]}
      elif [ $TheIndex -eq 3 ]; then
        SilentPath=$Arg
      fi
    done

    if [ -z "$SilentProd" ]; then
      echo "WARNING: You need to specify a valid product argument with the -s (silent mode) option."
    fi
  fi
}


#=====================================================================
#  Usage()
#
#  Display the command line usage with an optional error.
#=====================================================================
######################################################################
Usage()
{
  local msg="$1"
  echo ""
  if [ -n "$msg" ]; then
    echo "*** $msg"
    echo ""
  fi
  echo ""
  echo " $PROG <-h> <-s> <-product> [product_path]"
  echo ""
  echo "    -h        - Usage help"
  echo "    -s        - Silent mode option"
  echo ""
  echo "    NOTE: If -s is specified you MUST provide a product name"
  echo "    and (optionally) a product install directory."
  echo ""
  echo "    Valid silent mode product name options:"
  echo "       -server"
  echo "       -portal"
  echo "       -datastore"
  echo "       -notebookserver"
  echo "       -missionserver"
  echo "       -insightsportal"
  echo "       -insightsserver"
  echo "       -urban"
  echo "       -videoserver"
  echo "       -datapipelinesserver"
  echo ""
  echo " Examples:"
  echo ""
  echo "    Run interactively:"
  echo "      % ./$PROG"
  echo ""
  echo "    Update ArcGIS Server silently:"
  echo "      % ./$PROG -s -server"
  echo ""
  echo "    Update ArcGIS Datastore silently using a specific install folder:"
  echo "      % ./$PROG -s -datastore /home/arcgis/datastore"
  #echo " $PROG -s -<arcreader|engcpp|engine|engjava|objcpp|objjava|ims"
  #echo "               |server|portal|datastore|srvrjava|mole|ma> <ProductPath|-default>"
  echo ""
  exit 1
}


#=====================================================================
# IsServerRunning()/IsPortalRunning()
#
# Check if Server or Portal is running
#=====================================================================
IsServerRunning()
{
  local server_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       egrep -i 'tomcat|geronimo|nodeagent') 
  [ -n "$server_procs" ]
}

IsPortalRunning()
{
  local portal_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       grep 'ARCGIS_PORTAL_NODEAGENT' 2>&1)
  [ -n "$portal_procs" ]
}

IsDataStoreRunning()
{
  local datastore_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       egrep -i 'tomcat|nodeagent')
  [ -n "$datastore_procs" ]
}
IsNotebookServerRunning()
{
  local notebookserver_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       egrep -i 'tomcat|nodeagent|rmid')
  [ -n "$notebookserver_procs" ]
}
IsMissionServerRunning()
{
  local missionserver_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       egrep -i 'tomcat|nodeagent|rmid')
  [ -n "$missionserver_procs" ]
}
IsVideoServerRunning()
{
  local videoserver_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       egrep -i 'tomcat|nodeagent')
  [ -n "$videoserver_procs" ]
}

IsDataPipelinesServerRunning()
{
  local datapipelines_procs=$(pgrep -u $LOGNAME ${PGREP_OPT} $InstallPath | 
                       egrep -i 'tomcat|nodeagent')
  [ -n "$datapipelines_procs" ]
}

#=====================================================================
# CheckServerProcs()
#
# Set restart flags for Server and Portal.  Only restart them if they 
# were already started.
#=====================================================================
CheckServerProcs()
{
  echo "  Checking running processes..."
  IsServerRunning
  [ $? -eq 0 ] && RestartServer=true

  IsPortalRunning
  [ $? -eq 0 ] && RestartPortal=true

  IsDataStoreRunning
  [ $? -eq 0 ] && RestartDataStore=true

  IsNotebookServerRunning
  [ $? -eq 0 ] && RestartNotebookServer=true

  IsMissionServerRunning
  [ $? -eq 0 ] && RestartMissionServer=true

  IsVideoServerRunning
  [ $? -eq 0 ] && RestartVideoServer=true

  IsDataPipelinesServerRunning
  [ $? -eq 0 ] && RestartDataPipelinesServer=true
}

IsServerProduct()
{
  local product="$1"
  case "$(ToLower "$product")" in
    arcserver|arcgisportal|datastore|geoenrichmentserver|notebookserver|missionserver|insightsportal|insightsserver|arcwebadaptor|urban|videoserver|datapipelinesserver)
      return 0
      ;;
  esac
  return 1
}

CheckTOCVersion()
{
  local product="$1"
  local ver="$2"

  if $(IsServerProduct $product) ; then
    [ "$ver" = "$TOC_VERSION" ] && return 0
  fi

  return 1
}

#=====================================================================
# CheckServerProcs()
#
# Look for the platform folder (e.g. linux.server) in the applypatch
# dir. Complain if it's not there.
#=====================================================================
CheckApplypatchDir()
{
  cd $ScriptDir
  ls -1 $CurrentPlatform.* > /dev/null 2>&1

  if [ $? -ne 0 ]; then
    echo ""
    echo "*** ERROR: This doesn't seem to be a standard patch package.  Exiting."
    echo ""
    Clean_Up
    exit 1
  fi
}

######################################################################
#=====================================================================
#  Functions to check for systemd services
#=====================================================================
######################################################################
Check_Systemd_Service()
{
  local service="$1"

  systemctl --version > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    return
  fi

  if $(does_service_exist $service) ; then
    if $(is_service_enabled $service) ; then
      if $(is_service_active $service) ; then
        IsSystemDService=true 
        SystemDServiceName="$service"
      fi
    fi
  fi
}

Show_Systemd_Startup_Warning()
{
  local product_name="$1"
  local service="$SystemDServiceName"

  if [ "$IsSystemDService" = true ]; then
    echo ""
    #echo "  NOTE: applypatch detected the systemd service \"${service}\" was enabled prior to"
    #echo "  applying this patch.  You will need to restart it as administrator using systemctl:"
    echo "  NOTE: Since $product_name is configured to start with the operating system using"
    echo "  systemd, you will need to restart it as administrator using systemctl:"
    echo ""
    echo "      # systemctl start ${service}"
    echo ""
  fi
}

does_service_exist()
{
  local service="$1"
  found=$(systemctl list-unit-files | grep $service)
  [ -n "$found" ] && return 0 || return 1
}

is_service_enabled()
{
  local service="$1"
  systemctl -q is-enabled $service > /dev/null 2>&1
  return $?
}

is_service_active()
{
  local service="$1"
  systemctl -q is-active $service > /dev/null 2>&1
  return $?
}


#=====================================================================
#  SP_Stop_Service()
#
#  Stop Service for Server Java and MapServer for Service Pack install.
#=====================================================================
######################################################################
SP_Stop_Service()
{
   if [ "$ProductDispName" = "ArcGIS Server" ] || [ "$ProductDispName" = "ArcGIS Insights (Server)" ]; then
      Check_Systemd_Service "arcgisserver.service"
      if [ -f "$InstallPath/stopserver.sh" ] && [ "$RestartServer" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping ArcGIS Server ..."
         cd $InstallPath
         ./stopserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "Portal for ArcGIS" ] || [ "$ProductDispName" = "ArcGIS Insights (Portal)" ] || [ "$ProductDispName" = "ArcGIS Urban" ]; then
      Check_Systemd_Service "arcgisportal.service"
      if [ -f "$InstallPath/stopportal.sh" ] && [ "$RestartPortal" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping Portal for ArcGIS ..."
         cd $InstallPath
         ./stopportal.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Data Store" ] || [ "$ProductDispName" = "ArcGIS GeoEnrichment Server" ]; then
      Check_Systemd_Service "arcgisdatastore.service"
      if [ -f "$InstallPath/stopdatastore.sh" ] && [ "$RestartDataStore" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping ArcGIS Data Store ..."
         cd $InstallPath
         ./stopdatastore.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Notebook Server" ]; then
      Check_Systemd_Service "agsnotebook.service"
      if [ -f "$InstallPath/stopnotebookserver.sh" ] && [ "$RestartNotebookServer" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping ArcGIS Notebook Server ..."
         cd $InstallPath
         ./stopnotebookserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Mission Server" ]; then
      Check_Systemd_Service "agsmission.service"
      if [ -f "$InstallPath/stopmissionserver.sh" ] && [ "$RestartMissionServer" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping ArcGIS Mission Server ..."
         cd $InstallPath
         ./stopmissionserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcIMS ArcMap Server" ] || [ $ArcIMS = 1 ]; then
      if [ -f "$AIMSHOME/qs_scripts/stop_arcims" ]; then
         echo " Stopping ArcIMS Server ..."
         . $AIMSHOME/qs_scripts/stop_arcims
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Video Server" ]; then
      Check_Systemd_Service "agsvideo.service"
      if [ -f "$InstallPath/stopvideoserver.sh" ] && [ "$RestartVideoServer" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping ArcGIS Video Server ..."
         cd $InstallPath
         # Stopping Video Server would kill patchnotification in version < 11.5
         if IsVersionGreaterThan "11.4" ; then
            ./stopvideoserver.sh > /dev/null 2>&1
         else
            if ! IsPatchNotificationRunning ; then
               ./stopvideoserver.sh > /dev/null 2>&1
            fi
         fi
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Data Pipelines Server" ]; then
      Check_Systemd_Service "agsdatapipelines.service"
      if [ -f "$InstallPath/stopdatapipelinesserver.sh" ] && [ "$RestartDataPipelinesServer" = true ]; then
         . $InstallPath/framework/etc/arcenv
         sleep 10
         echo "  Stopping Data Pipelines Server ..."
         cd $InstallPath
         ./stopdatapipelinesserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

}

IsVersionLessThan()
{
  local ver_to_test=$(echo "$1" | sed 's/\.//g')
  local product_ver=$(echo "$ProductVersion" | sed 's/\.//g')

  [ $ver_to_test -lt $product_ver ]
}

IsVersionGreaterThan()
{
  local ver_to_test=$(echo "$1" | sed 's/\.//g')
  local product_ver=$(echo "$ProductVersion" | sed 's/\.//g')

  [ $ver_to_test -gt $product_ver ]
}

# If patchnotification is running don't restart the server if it will kill PN.
IsPatchNotificationRunning()
{
  local proc=""

  proc=$(ps -aef | grep "$InstallPath" | grep "patchnotification")
  [ -n "$proc" ]
}

RunWineBoot()
{
  [ "$ProductDispName" != "ArcGIS Server" ] && return

  local arcenv="${InstallPath}/framework/etc/arcenv"
  local init_xvfb="${InstallPath}/framework/runtime/xvfb/init_Xvfb.sh"
  local init_display="${InstallPath}/framework/runtime/xvfb/init_display.sh"

  [ ! -f "$arcenv" ] && fail "The arcenv script was not found."

  if [ -f "$init_display" ]; then
    . "$init_display"

    echo "Restarting Display..."
    StartDisplay
  elif [ -f "$init_xvfb" ]; then
    . "$arcenv"

    # init_Xvfb.sh expects $installDir to be defined for some reason
    export installDir="${InstallPath}"

    . "$init_xvfb"

    # NOTE: If StartXvfb fails it could abort applypatch in installs < 11.5
    if IsVersionGreaterThan "11.4" ; then
      echo "Restarting Xvfb..."
      StartXvfb
    fi
  else
    fail "The init_Xvfb.sh script was not found."
  fi

  echo "Restarting Wine..."
  wineboot -u > /dev/null 2>&1
}

#=====================================================================
#  Run_SP_Config()
#
#  Run SP#config.sh for Service Pack.
#=====================================================================
######################################################################
Run_SP_Config()
{
   #================================================================
   # Run linux.<product>/post.install/post_install_script.sh if
   # present.
   # NOTE: This needs to be done after Verify_The_Install otherwise
   # any modifications made to patched files will cause the
   # Validate_The_Patch check to fail.
   #================================================================
   Run_Post_Install_Script "${InstallPath}"

   # Some products need to run a post-instal zip extraction so run those here
   Run_Post_Install_Zip_Extractions

   # Don't restart systemd services
   if [ "$IsSystemDService" = true ]; then
      Show_Systemd_Startup_Warning "$ProductDispName"
      return
   fi

   # Start standalone servers
   if [ "$ProductDispName" = "ArcGIS Server" ] || [ "$ProductDispName" = "ArcGIS Insights (Server)" ]; then
      if [ -f "$InstallPath/startserver.sh" ] && [ "$RestartServer" = true ]; then
         echo "  Starting ArcGIS Server ..."
         cd $InstallPath
         ./startserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "Portal for ArcGIS" ] || [ "$ProductDispName" = "ArcGIS Insights (Portal)" ] || [ "$ProductDispName" = "ArcGIS Urban" ]; then
      if [ -f "$InstallPath/startportal.sh" ] && [ "$RestartPortal" = true ]; then
         echo "  Starting Portal for ArcGIS ..."
         cd $InstallPath
         ./startportal.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Data Store" ] || [ "$ProductDispName" = "ArcGIS GeoEnrichment Server" ]; then
      if [ -f "$InstallPath/startdatastore.sh" ] && [ "$RestartDataStore" = true ]; then
         echo "  Starting ArcGIS Data Store ..."
         cd $InstallPath
         ./startdatastore.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Notebook Server" ]; then
      if [ -f "$InstallPath/startnotebookserver.sh" ] && [ "$RestartNotebookServer" = true ]; then
         echo "  Starting ArcGIS Notebook Server ..."
         cd $InstallPath
         ./startnotebookserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Mission Server" ]; then
      if [ -f "$InstallPath/startmissionserver.sh" ] && [ "$RestartMissionServer" = true ]; then
         echo "  Starting ArcGIS Mission Server ..."
         cd $InstallPath
         ./startmissionserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Video Server" ]; then
      if [ -f "$InstallPath/startvideoserver.sh" ] && [ "$RestartVideoServer" = true ]; then
         echo "  Starting ArcGIS Video Server ..."
         cd $InstallPath
         ./startvideoserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi

   if [ "$ProductDispName" = "ArcGIS Data Pipelines Server" ]; then
      if [ -f "$InstallPath/startdatapipelinesserver.sh" ] && [ "$RestartDataPipelinesServer" = true ]; then
         echo "  Starting Data Pipelines Server ..."
         cd $InstallPath
         ./startdatapipelinesserver.sh > /dev/null 2>&1
         cd $CurrentWorkingDir
      fi
   fi
}

#=====================================================================
#  Update_SP_Keys()
#
#  Update SP registry keys for Service Pack.
#=====================================================================
######################################################################
Update_SP_Keys()
{
   ProcessID=$$
   tmpspreg=/tmp/spreg.$ProcessID.reg

   if [ "$ProductDispName" = "ArcGIS Engine ${VER}" ]; then
      . $InstallPath/init_engine.sh

      echo 'REGEDIT4

[HKEY_LOCAL_MACHINE\Software\ESRI\Engine${VER}]
"SPBuild"="10.4.3393"
"SPDisplayName"="ArcGIS ${VER} Engine"
"SPNumber"="1"' > $tmpspreg
   elif [ "$ProductDispName" = "ArcGIS 10.4 for Server" ]; then
      . $InstallPath/servercore/.Server/init_server.sh
      mwadm start > /dev/null 2>&1
      echo 'REGEDIT4

[HKEY_LOCAL_MACHINE\Software\ESRI\Server${VER}]
"SPBuild"="10.5.3393"
"SPDisplayName"="ArcGIS Server ${VER}"
"SPNumber"="1"' > $tmpspreg
   elif [ "$ProductDispName" = "ArcGIS ArcReader ${VER}" ]; then
      . $InstallPath/init_engine.sh
      echo 'REGEDIT4

[HKEY_LOCAL_MACHINE\Software\ESRI\ArcReader${VER}]
"SPBuild"="10.4.3393"
"SPDisplayName"="ArcReader ${VER}"
"SPNumber"="1"' > $tmpspreg
   else
      return
   fi
      
   if [ "x`which regedit | grep \"no regedit in\"`" = "x" ]; then
      echo " Write SP registry keys."
      regedit -c $tmpspreg >/dev/null 2>&1
   fi
  
   rm -f $tmpspreg

}

######################################################################
#=====================================================================
#  Check_DISPLAY()
#
#  Make sure that the DISPLAY has been set
#  
#=====================================================================
######################################################################
Check_DISPLAY()
{

   if [ "$ProductDispName" = "ArcGIS Engine ${VER}" ]; then
      if [ -z "$DISPLAY" ]; then
         echo ""
         echo "*** ERROR: "
         echo "  Invalid DISPLAY.  Please set DISPLAY variable."
         echo "    e.g. DISPLAY=machine1:0; export DISPLAY "
         echo ""
         Error_Exit
      fi
   fi
   
}


find_LM_version()
{
	# get version number from sentinel file name in CommonFiles location
	local UNAME_N=$(uname -n)
	local INSTALL_FILE=""

	if [ -f ${HOME}/.esriprogramfiles/${UNAME_N}/CommonFiles/.LicenseManager_[0-9\.]*.install ]; then
		INSTALL_FILE=$(ls -1 ${HOME}/.esriprogramfiles/${UNAME_N}/CommonFiles/.LicenseManager_[0-9\.]*.install | head -n 1)
	fi
	if [ "x${INSTALL_FILE}X" != "xX" ]; then
		LM_VERSION=$(echo ${INSTALL_FILE} | sed -e 's;^.*LicenseManager_;;' -e 's;\.install$;;')
	fi

	# get version number from entry in .com.zerog.registry.xml 
	if [ -z "$LM_VERSION" ]; then
		if [ -f "$HOME/.com.zerog.registry.xml" ]; then
			LM_VERSION=$(grep "product name=\"LicenseManager\" " $HOME/.com.zerog.registry.xml | grep arcgis\/license | sed -e 's;^.*version=\";;' -e 's;\.0\.0\" copyright.*$;;')
		fi
	fi
	
	# get version number from install path stored in USER_INSTALL_DIR variable in LicenseManager_InstallLog.log
	if [ -z "$LM_VERSION" ]; then
		if [ -f "$HOME/LicenseManager_InstallLog.log" ]; then
			LM_VERSION=$(grep USER_INSTALL_DIR $HOME/LicenseManager_InstallLog.log | sed 's;^.*arcgis\/license;;')
		fi
	fi
	
	# get version number from path of running LM process
	if [ -z "$LM_VERSION" ]; then
		LM_VERSION=$(ps -ef | grep arcgis\/license | grep bin\/service.txt | grep -v grep | head -n 1 | sed -e 's;^.*arcgis\/license;;' -e 's;\/bin\/service\.txt.*$;;')
	fi
	
	# get version number from path of MainWin dir
	if [ -z "$LM_VERSION" ]; then
		LM_VERSION=$(ls -1A ${HOME}/ | grep \.arcgis[0-9\.]* | head -n 1 | sed 's;^.*\.arcgis;;')
	fi
	
	# get version number from path of running MainWin process
	if [ -z "$LM_VERSION" ]; then
		LM_VERSION=$(ps -ef | grep \/\.arcgis[0-9\.]* | grep watchdog | grep -v grep | head -n 1 | sed 's;^.*\.arcgis;;' | sed 's;\/\..*$;;')
	fi

#echo $LM_VERSION
}

find_LM_install_dir()
{
	local TEMP_LM_INSTALL_DIR=""
	# get install dir from USER_INSTALL_DIR variable in LicenseManager_InstallLog.log
	if [ -f "$HOME/LicenseManager_InstallLog.log" ]; then
		TEMP_LM_INSTALL_DIR=$(grep USER_INSTALL_DIR $HOME/LicenseManager_InstallLog.log | sed 's;^.*=;;')
		if [ -d "$TEMP_LM_INSTALL_DIR" ]; then
			LM_INSTALL_DIR=$TEMP_LM_INSTALL_DIR
		fi
	fi

	# get install dir from entry in .com.zerog.registry.xml 
	if [ -z "$LM_INSTALL_DIR" ]; then
		if [ -f "$HOME/.com.zerog.registry.xml" ]; then
			TEMP_LM_INSTALL_DIR=$(grep "product name=\"LicenseManager\" " $HOME/.com.zerog.registry.xml | grep arcgis\/license | sed -e 's;^.*location=\";;' -e 's;\" last_modified.*$;;')
			if [ -d "$TEMP_LM_INSTALL_DIR" ]; then
				LM_INSTALL_DIR=$TEMP_LM_INSTALL_DIR
			fi
		fi
	fi
	
	# get install dir from path of running lmgrd process
	if [ -z "$LM_INSTALL_DIR" ]; then
		TEMP_LM_INSTALL_DIR=$(ps -ef | grep arcgis\/license[0-9.]* | grep \/bin\/service.txt | grep "./lmgrd -c" | grep -v grep | head -n 1 | sed -e 's;^.*\.\/lmgrd -c ;;' -e 's;\/bin\/service\.txt.*$;;')
		if [ -d "$TEMP_LM_INSTALL_DIR" ]; then
			LM_INSTALL_DIR=$TEMP_LM_INSTALL_DIR
		fi
	fi

	# get install dir from path of running ARCGIS process
	if [ -z "$LM_INSTALL_DIR" ]; then
		TEMP_LM_INSTALL_DIR=$(ps -ef | grep arcgis\/license[0-9\.]*\/bin\/service.txt | grep ARCGIS | grep -v grep | head -n 1 | sed -e 's;^.*ARCGIS -T .* -c \/;\/;' -e 's;\/bin\/service\.txt.*$;;')
		if [ -d "$TEMP_LM_INSTALL_DIR" ]; then
			LM_INSTALL_DIR=$TEMP_LM_INSTALL_DIR
		fi
	fi

	# last resort, brute force search for LM file
#	if [ -z "$LM_INSTALL_DIR" ]
#	then
#		FIND_RESULT=` find / -name lsadmin.exe 2>/dev/null | grep arcgis\/license `
#		if [ -n $FIND_RESULT ]
#		then
#			TEMP_LM_INSTALL_DIR=` echo $FIND_RESULT | sed 's;\/bin\/lsadmin\.exe$;;' `
#			if [ -d "$TEMP_LM_INSTALL_DIR" ]
#			then
#				LM_INSTALL_DIR=$TEMP_LM_INSTALL_DIR
#			fi
#		fi
#	fi

#echo $LM_INSTALL_DIR
}


#================================================================
# Run_Post_Install_Script()
#
# If a script called post_install_script.sh is present in a folder
# called post.install in the linux.<product> folder of this patch,
# run it and pass it the $InstallPath for this patch.
#================================================================
Run_Post_Install_Script()
{
  cd $ScriptDir

  for dir in $(ls -1)
  do
    if [ -d "$dir" ]; then
      local script="$ScriptDir/${dir}/post.install/post_install_script.sh"
      if [ -f "$script" ]; then
	      echo "Running post install script to apply file changes"
        $script $InstallPath
        break
      fi
    fi
  done
}


#================================================================
# Run post-install zip extractions
#================================================================
Run_Post_Install_Zip_Extractions()
{
  case "$ProductDispName" in
    "ArcGIS Server")
      ExtractZips "${ProductHome}/framework/etc/scripts/agsserver.sh" "extractSetupZips"
      ExtractZips "${ProductHome}/framework/etc/scripts/agsserver.sh" "extractRuntimeZips"
      ;;
    "Portal for ArcGIS")
      ExtractZips "${ProductHome}/framework/etc/agsportal.sh" "extractPatchZips"
      ExtractZips "${ProductHome}/framework/etc/agsportal.sh" "extractRuntimeZips" "${ProductHome}/framework/etc/thirdparty_zips_manifest.txt"      
      ;;
    "ArcGIS Data Store")
      ExtractZips "${ProductHome}/framework/etc/scripts/arcgisdatastore.sh" "extractRuntimeZips"
      ;;
    "ArcGIS Notebook Server")
      ExtractZips "${ProductHome}/framework/etc/scripts/agsnotebook.sh" "extractSetupZips"
      ;;
    "ArcGIS Mission Server")
      ExtractZips "${ProductHome}/framework/etc/scripts/agsmissionserver.sh" "extractSetupZips"
      ;;
    "ArcGIS GeoEnrichment Server")
      ExtractZips "${ProductHome}/framework/etc/scripts/arcgisdatastore.sh" "extractRuntimeZips"
      ;;
    "ArcGIS Urban")
      ExtractZips "${ProductHome}/framework/etc/agsportal.sh" "patchadditionalsetup" "urban"
      ;;
    "ArcGIS Video Server")
      ExtractZips "${ProductHome}/framework/etc/scripts/agsvideoserver.sh" "extractSetupZips"
      ;;
  esac
}


#=====================================================================
# Helper for Run_Post_Install_Zip_Extractions
#=====================================================================
ExtractZips()
{
  local init_script="$1"
  local flag="$2"
  local arg="$3"
  local count=0

  # Return if there are no zip files in the install
  count=$(find ${ProductHome}/framework/zips -type f -iname "*.zip" 2> /dev/null | wc -l)
  ocount=$(find ${ProductHome}/zips -type f -iname "*.zip" 2> /dev/null | wc -l)
  [ $count -eq 0 ]  && [ $ocount -eq 0 ]  && return

  # Return if the extract flag is not present in the init script
  grep -q "$flag" "$init_script"
  [ $? -ne 0 ] && return

  CMD="${init_script} ${flag} ${arg}"

  echo "Running ${CMD}..."
  eval ${CMD}
}

#=====================================================================
# Display a helpful post install message for WebAdaptor only
#=====================================================================
Display_WebAdaptor_PostInstall_Message()
{
  echo ""
  echo "------------------------------------------------------------------------------"
  echo "NOTE: You may need to redeploy the updated arcgis.war file from your ArcGIS"
  echo "Web Adaptor installation folder to any Java application servers to which they"
  echo "were previously deployed. For instructions on how to deploy a .war file, refer"
  echo "to the documentation for your Java application server."
  echo "------------------------------------------------------------------------------"
  echo ""
}

#=====================================================================
# Display a helpful post install message for VideoServer only
#=====================================================================
Display_VideoServer_PostInstall_Message()
{
  ! IsPatchNotificationRunning && return

  IsVersionGreaterThan "11.4" && return

  echo ""
  echo "------------------------------------------------------------------------------"
  echo "NOTE: To complete the installation you need to manually restart Video Server"
  echo "after closing the patchnotification tool."
  echo "------------------------------------------------------------------------------"
  echo ""
}


# Helpers for CheckDataStoreDBFolders
patch_has_folder()
{
  local folder="$1"

  grep -q "$folder" "$UpdatedTOCFile"
}

check_valid_datastore_folder()
{
  local folder="$1"
  local product="$2"

  if ! patch_has_folder "$folder" ; then
    return
  fi

  echo "  Checking db folder $folder..."

  if [ ! -d "${InstallPath}/${folder}" ]; then
    fail "${TheProduct} ${product} is required to proceed with this installation. Exiting."
  fi
}

#=====================================================================
# Fail if the Datastore patch contains files in a specified
# database folder but the folder does not exist in the install.
#=====================================================================
CheckDataStoreDBFolders()
{
  [ "$ProductDispName" != "ArcGIS Data Store" ] && return

  check_valid_datastore_folder "framework/runtime/arangodb" "Graph store"
}

#=====================================================================
# This is a hack for the Datastore Highly Available 11.1 patch. Fail
# if the DS 11.1 Knowledge Graph patch is installed.
#=====================================================================
CheckDataStoreKnowledgeGraphPatchHack()
{
  [ "$ProductDispName" != "ArcGIS Data Store" ] && return

  # Return of this patch is not the "Highly Available" 11.1 DS patch
  [ "$QFENumber" != "DS-111-P-1081" ] && return

  local patch_log="${InstallPath}/${QFETestFile}"

  # No .ESRI_DS_PATCH_LOG file so return
  [ ! -f "$patch_log" ] && return

  grep -q "DS-111-P-914*" "$patch_log"
  [ $? -ne 0 ] && return

  echo ""
  echo "This patch is not needed. The updates in this patch were already applied with the ArcGIS Data Sore 11.1 Knowledge Graph Patch C."
  echo ""
  exit 1
}

#=====================================================================
#=====================================================================
#
#                  MAIN PORTION OF PROGRAM
#
#=====================================================================
#=====================================================================


#================================================================
#  Initialize some variables.
#================================================================
AllArgs=$*
NumArgs=$#
PROG=$(basename $0)
ArcIMS=0
ArcInfo=0
ArcSDE=0
ArcGIS=0
SelectedTOC=""
ProductName=""
ProductDispName=""
ProductSerPack=""
ProductVersion=""
ProductVersionStripped=""
QFEVersion=""
QFEDate=""
QFEAbbreviated=""
ExistingProdBits=""
InstallPath=""
PatchHome=$(dirname $0)
CurrentWorkingDir=$(pwd)
ScriptDir=$(cd $(dirname $0) && pwd)
ArcSDESet=""
ArcIMSSetupFile="$HOME/SetupArcIMS.properties"
SPNumber=0

SilentInstall=0
SilentProd=""
SilentPath=""

RollbackScriptPath=""
RollbackBackupScript=""
RollbackRemoveScript=""

RestartServer=false
RestartPortal=false
RestartDataStore=false
RestartNotebookServer=false
RestartMissionServer=false
RestartVideoServer=false
RestartDataPipelinesServer=false

CurrentUserID=$(id -u)
CurrentUserName="$LOGNAME"
if [ -z "$CurrentUserName" ]; then
  CurrentUserName=$(id | cut -f 2 -d '(' | cut -f 1 -d ')')
  if [ -z "$CurrentUserName" ]; then
    CurrentUserName=$(whoami)
  fi
fi


LM_VERSION=""
LM_INSTALL_DIR=""
find_LM_install_dir
find_LM_version


#================================================================
#  Remove the validation errors log if present
#================================================================
rm -f $ValidationErrorList

#================================================================
#  Set platform specific system commands.
#================================================================
Set_System_Commands

#================================================================
#  Parse the command line.
#================================================================
Parse_Command_Line

#================================================================
# Bail if root tries to install Server patches
#================================================================
CheckForRootServerInstaller

#================================================================
# Check if this script is run from a patch dir
#================================================================
CheckApplypatchDir

#================================================================
#  Print applypatch intro.
#================================================================
Print_Applypatch_Intro

#================================================================
#  Get ArcGIS product setup properties.
#================================================================
SourceEsriPropertiesFile

#================================================================
# Set initial version to match installed product(s) version
#================================================================
VER="$Z_REAL_VERSION"

#================================================================
#  Outter while loop to collect and verify selections made by the
#  user.
#================================================================
AllSetToInstall="no"
while [ $AllSetToInstall = "no" ]
do

   if [ $SilentInstall -eq 1 ]; then
      AllSetToInstall="yes"
      Reiterate_Choice
   
   else
      List_Valid_Selections

      User_Selection_Process
   fi
  
   # Handle Insights
   if [ "$ProductFolderName" = "insightsportal" ] || [ "$ProductFolderName" = "insightsserver" ]; then
     VER="$Z_Insights_VERSION"
   fi

   # Handle Urban
   if [ "$ProductDispName" = "ArcGIS Urban" ]; then
     VER="$Z_ArcGISUrban_VERSION"
   fi

   #=============================================================
   #  Validate the selected QFE patch directory and contents.
   #=============================================================
   Validate_Patch_Home
   if [ $? -ne 0 ]; then
      Error_Exit
   fi

   #=============================================================
   #  Strip the decimal points from the ProductVersion.
   #=============================================================
   Strip_Product_Version
   

   if [ $SilentInstall -eq 1 ]; then
      if [ -z "$SilentPath" ] || [ "$SilentPath" = "-default" ]; then
         InstallPath=$ProductHome
      else
         InstallPath=$SilentPath
      fi

      Validate_Product_Path
      if [ $? -ne 0 ]; then
         Error_Exit
      fi
      
      Pre_Install_Info
   else
#--------------------- For Normal Install----------------------------------   
   Pre_Install_Info


   #==============================================================
   # Add while loop for install home path setting. If we can't auto
   # detect the current installed product bit set, prompt info to 
   # let user make sure or reset the install home path.
   #==============================================================
   HomeSetToInstall="no"
   IsFirstTimeHomeSet="yes"
   while [ "$HomeSetToInstall" = "no" ]
   do
      #=============================================================
      #  Determine the user's product HOME (or install location).
      #=============================================================
      Set_Product_Home

      #================================================================
      # Require root passward to fix an incorrect permission for LP
      #================================================================
      if [ "$ProductDispName" = "ArcGIS Server for the Java Platform Spanish Supplement" ]  ||
         [ "$ProductDispName" = "ArcGIS Server for the Java Platform French Supplement" ]   || 
         [ "$ProductDispName" = "ArcGIS Server for the Java Platform Japanese Supplement" ] ||
         [ "$ProductDispName" = "ArcGIS Server for the Java Platform German Supplement" ]   ||
         [ "$ProductDispName" = "ArcGIS Server for the Java Platform Simplified Chinese Supplement" ]
      then
         echo "  Please enter your root password. This is required to fix an incorrect permission:"
         current_user=$(id | sed 's/uid=[0-9][0-9]*(\([^)]*\)).*/\1/')
         su root -c "chown -R $current_user $ProductHome/java/manager >/dev/null 2>&1"
      fi

      IsFirstTimeHomeSet="no"
      
      #=============================================================
      #  Determine bitset of the user's product.
      #=============================================================
      ExistingProdBits=`Existing_Product_Bitset`

      #if [ $ArcSDE = 1 ] 
      #then
      #   AllDataBases=`Get_Patch_Info AllDataBases $CurrentTOC`
      #fi

      if [ $ArcSDE = 1 ]; then
         Validate_Selection
         if [ $? != 0 ]; then
            exit 1
         fi
      else
         HomeSetToInstall="yes"
      fi
   done
   if [ $? -ne 0 ]; then
      exit 1
   fi
#------------------------------------------------------------------------   
   fi
   
   #=============================================================
   #  Check for DISPLAY variable for Engine RT and ArcReader
   #=============================================================
   Check_DISPLAY
   if [ $? -ne 0 ]; then
      exit 1
   fi

   #=============================================================
   #  Create an update TOC file based on what the user has 
   #  installed in their product HOME.
   #  Check the final status this function containing an exit 
   #  within a loop.  For certain platforms, a call to "exit 1" 
   #  will only exit the loop and not the entire script.  This 
   #  test will catch that condition.
   #=============================================================
   Update_TOC_File
   if [ $? -ne 0 ]; then
      exit 1
   fi

   #================================================================
   # Check the patch version against the product version to prevent
   # installing the wrong version of the patch.
   #================================================================
   CheckProductVersionMatch


   #=============================================================
   #  Check to see if the directories containing the files to be
   #  installed (from UpdatedTOCFile) exist and have write 
   #  access.
   #  Check the final status this function containing an exit 
   #  within a loop.  For certain platforms, a call to "exit 1" 
   #  will only exit the loop and not the entire script.  This 
   #  test will catch that condition.
   #=============================================================
   Check_Access_Rights
   if [ $? -ne 0 ]; then
      exit 1
   fi

   #=============================================================
   #  Make sure that the minimum disk space needed to install the 
   #  ESRI Patch is available.
   #=============================================================
   Check_Disk_Space

   #=============================================================
   #  Prompt the user to see if they would like to backup the 
   #  original files that will be replaced.
   #=============================================================
   #SP SPecial: No backup files.
   #Prompt_User_For_Backup
   SaveFiles="no"

   #=============================================================
   #  Prompt the user for a backup location and verify that is 
   #  valid if the user opted to backup the original files.
   #=============================================================
   #SP SPecial: No backup files.
   #Validate_Save_Location

   #================================================================
   # Check if Server or Portal is already running.  If so we'll
   # shut it down and restart it.
   #================================================================
   CheckServerProcs

   CheckDataStoreDBFolders

   CheckDataStoreKnowledgeGraphPatchHack

   #=============================================================
   #  Display the current selections made by the user and have 
   #  the user choose to confirm or change the settings.
   #  Check the final status this function containing an exit 
   #  within a loop.  For certain platforms, a call to "exit 1" 
   #  will only exit the loop and not the entire script.  This 
   #  test will catch that condition.
   #=============================================================
   if [ $SilentInstall -eq 0 ]; then
      Confirm_Settings
      if [ $? -ne 0 ]; then
         exit 1
      fi
   fi
done


#================================================================
#  Check the final status of the call to Confirm_Settings after 
#  the outter while loop.  For certain platforms, a call to 
#  "exit 1" will only exit the loop and notthe entire script.  
#  This test will catch that condition.
#================================================================
if [ $? -ne 0 ]; then
   exit 1
fi

#================================================================
# Define the backup and restore scripts
#================================================================
SetRollbackScriptDestinationPath

#================================================================
# If a baseline cumulative patch is required, check that it is
# installed or not.
#================================================================
CheckForBaselinePatch

#================================================================
# Create the $installDir/.Setup/qfe folder if not present, then
# Copy the rollback scripts there.
#================================================================
Copy_Rollback_Scripts

#================================================================
# Check if this patch is already installed.  If so, notify the 
# user and exit.
#================================================================
Check_For_Previous_Backup

#================================================================
# Run acgis/scripts/stopserver for ArcGIS Server 9.2 SP6
# Run $AIMSHOME/qs_scripts/stop_arcims for ArcIMS and MapServer 
#================================================================
SP_Stop_Service

#================================================================
#  Backup the original files to the user specified location.  If 
#  there is a failure during backup, restore the originals and 
#  exit on error.
#================================================================
Perform_Backup

#================================================================
#  Walk through the Updated TOC file and remove non-writable 
#  original files.
#
#  We know we have full access rights to the directories but some 
#  of the original files to be replaced may be "read only" or 
#  root-owned with the "set-user-id" bit set.  These cannot be 
#  updated by the tar command unless the old version is first
#  removed, so remove them now.
#================================================================
Remove_NonWritable_Files

Apply_The_Patch

Verify_The_Install

#================================================================
# Run SPconfig.sh for Server, Engine and Reader
# This has been removed inside Verify_The_Install
#=================================================================
#Run_SP_Config

Clean_Up
exit 0
