#!/bin/ksh
#
# Copyright (c) 2001 by Sun Microsystems, Inc.
# All rights reserved.
#ident	"@(#)san_recover.sh	1.4	01/10/12 SMI"
#

PATH=/usr/bin:/usr/sbin/:$PATH
SANOS=/opt/SUNWsan/etc/san_os
SANDRV=/opt/SUNWsan/etc/san_drivers
PatchIDList=""

update_os ()
{
  cp /dev/null $SANOS
  /sbin/uname -r >> $SANOS
  /usr/bin/head -1 /etc/release | 
    /usr/bin/sed -e 's/[ 	]*//' >> $SANOS
}

getpatchids ()
{
   PatchIDList=`nawk -F: -v list=" " \
        '/^[^#]/ && $6 ~ /[A-Z]?[0-9]+-[0-9]+/ \
	{if (list !~ $6) list=list $6 " " } \
	END{print list}' $SANDRV`
}

patch_cleanup ()
{

  for P in $PatchIDList ; do

    BaseId=${P%%-??}
    cd /var/sadm/patch

    for Current_P in `ls -dr ${BaseId}-?? 2> /dev/null` ; do
       # remove patch if not already removed
       echo "Removing $Current_P"
       patchrm $Current_P
       if [ $? -ne 0 ] ; then
	  echo
          echo "Problems removing patch $Current_P."
	  echo "Try removing manually and rerun san_recover."
	  echo
	  exit 1	
       fi
    done
  done

  for P in $PatchIDList ; do
    # remove entrys from san_drivers
    grep -v $P /opt/SUNWsan/etc/san_drivers > /tmp/san_drivers.$$
    mv /tmp/san_drivers.$$ /opt/SUNWsan/etc/san_drivers 

    # remove sav files
    BaseId=${P%%-??}
    rm -f /var/sadm/pkg/SUNWsan/${BaseId}-??.sav 
  done
}


remove_sfk_pkgs()
{
  S_OS=`uname -r`
  cd /var/sadm/pkg
  for pkg in `ls -d SUNW*` ; do
    P_OS=`pkgparam $pkg SFK_OS`
    if [ -n "$P_OS" ] ; then
      if [[ "$S_OS" != $P_OS ]] ; then
	# Wrong OS for this package. Remove it.
	pkgrm $pkg
      fi
    fi
  done
}

rmstored_patches ()
{
  for P in $PatchIDList ; do
    rm -f /opt/SUNWsan/patches/${P}.tar.Z
  done
}

is_installed ()
{
  PTCH=$1
  base=${PTCH%%-??}
  vers=${PTCH##*-}

  #check installed
  found=`patchadd -p | nawk '$2 ~ /'$base'/{if ( (substr($2,8) + 1) > '$vers') {print 1}}'`
  [ -n "$found" ] && return 0

  # check if obsoleted
  patchadd -p | grep 'Obsoletes:.*'$base'.*Requires:' > /dev/null
  [ $? -eq 0 ] && return 0

  return 1
}

is_in_list ()
{
  PTCH=$1
  base=${PTCH%%-??}
  vers=${PTCH##*-}

  shift

  match=1
  for item in $* ; do
    if [[ ${item%%-??} = ${base} ]] ; then
      if [[ ${item##*-} -ge $vers ]]; then
         match=0
         break
      fi
    fi
  done

  return $match
}

installpatches ()
{
  mkdir /tmp/revcover.$$
  cd /tmp/revcover.$$

  for P in $PatchIDList ; do

    if [ -f /opt/SUNWsan/patches/${P}.tar.Z ] ; then
      zcat /opt/SUNWsan/patches/${P}.tar.Z | tar xf -
    else
      echo "Unable to locate patch ${P}"
      echo "Your system will be downgraded until this patch is successfully installed."
      echo	
    fi

  done 

  # reorder for installation dependancies
  NewPatchList=""
  PatchList="$PatchIDList "

  while [ -n "$PatchList" ] ; do

    P=${PatchList%% *}
    PatchList=${PatchList##$P }

    met_req=1
    REQUIRES=`sed -n -e 's/^SUNW_REQUIRES=//p' ?(T)$P/SUNW*/pkginfo | head -1`
    for R in $REQUIRES; do
      Rbase=${R%%-??}
      Rvers=${R##*-}

      is_installed $R
        [ $? -eq 0 ] && continue

      is_in_list $R $NewPatchList
        [ $? -eq 0 ] && continue

      met_req=0

      is_in_list $R $PatchList
        [ $? -eq 0 ] && PatchList="$PatchList$P " && break

      echo "Unable to re-install patch $P due to the absense of patch $R"

    done

    [ $met_req -eq 1 ] && NewPatchList="$NewPatchList$P "

  done


  for P in $NewPatchList ; do

      echo "Reapplying patch ${P}"
      patchadd ?(T)${P}
      if [ $? -ne 0 ] ; then 
	 echo "Unable to install ${P}"
         echo "Your system will be downgraded until this patch is succesfully installed."
         echo	
      fi

  done

  cd /tmp
  rm -rf /tmp/revcover.$$
}

#Main

/etc/init.d/san_driverchk > /dev/null
case $? in
	# recover 0
 	# no problem
	0) echo "No problems detected" ;;

	# recover 1
	# OS changed (7 -> 8)
	1) 
	   getpatchids 
           [ -n "$PatchIDList" ] && patch_cleanup
	   remove_sfk_pkgs
           rmstored_patches
	   update_os
	   echo "Please install SFK patches from sunsolve" 
	  ;;


	# recover 2
	# release changed ( 8u1 -> 8u3 )
	2) 
	   getpatchids 
           if [ -n "$PatchIDList" ]; then
	     patch_cleanup
	     installpatches 
           fi
	   update_os
	  ;;

	# recover 3
	# Binaries changed
	3) echo "A SFK binary has been updated outside the normal method"
	  ;;

	*) echo "Unknown result from san_driverchk" ;;

esac
