#  $Id: patch_list.sh 145555 2017-07-10 13:08:33Z steven.durrans@oracle.com $
#  Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
#  This software code contains proprietary information 
#  and should be treated as confidential

if [ -f ${TTAMSG}/common -a -f ${TTAMSG}/patch_list ]; then
  . ${TTAMSG}/common
  . ${TTAMSG}/patch_list
else
  echo "Unable to open message file: ${TTAMSG}/patch_list"
  exit 1
fi

PATCH_CFG=${TTAINSTDIR}/var/info/patch.cfg
PATCH_VERSION="PATCHED_VERSION"

GetSGDVersion() {
    TTAVERSION="${TTAINSTDIR}/etc/pkg/ttaversion"
    
    if [ ! -s "${TTAVERSION}" ]; then
	return
    fi
    
    SGD_VERSION=`tail -1 ${TTAVERSION}`
    echo "${SGD_VERSION}"
}


PATCH_LIST=${TTAINSTDIR}/var/info/patch.list
PATCH_LOG=${TTAINSTDIR}/var/log/patch.log
BACKUP_BIN_DIR=${TTAINSTDIR}/bin/bin/backups
BACKUP_JSERVER_DIR=${TTAINSTDIR}/bin/java/backups
BACKUP_WEBSERVER_DIR=${TTAINSTDIR}/webserver/backups
BACKUP_FILE_DIR=${TTAINSTDIR}/var/patchbackups
DELIM="|"
ACTIVE="active"
INACTIVE="inactive"

AddedPatch() {
   echo "$1 - Added patch : $2 $3" >> ${PATCH_LOG}
}

RemovedPatch() {
   echo "$1 - Removed patch : $2 $3" >> ${PATCH_LOG}
}

Check_sgd_running() {
    # ps output only gives limited characters in the command so truncate
    # the install directory if it's too long
    match=`echo $2 | cut -c1-25`

  # Count the number of lines in the file
  entries=`wc -l "$1" 2> /dev/null | awk '{print $1}'`
  if [ ! -s "$1" ]; then
      # Delete an empty file
      rm -f "$1" 2> /dev/null
      return 2;
  elif [ $entries -eq 1 ]; then
      ThePid=`tail -1 "$1" 2>/dev/null | sed 's/ //g'`
      if [ ! -n "${ThePid}" ]; then
          # No pid in the file
	  rm -f "$1" 2> /dev/null
	  return 1
      elif [ -n "`ps -fp${ThePid} 2>/dev/null | egrep \"$match\" | egrep -v egrep`" ] ; then
          # Single pid and the process is still running
	  return 0
      fi

      # The file exists but the process isn't one we expect
      rm -f "$1" 2> /dev/null
      return 1
  else
      # Multiple entries in the file - write all the pids for our processes
      # into a "running" file
      while read Pid ; do
         [ -n "`ps -fp${Pid} 2>/dev/null | egrep \"$match\" | egrep -v egrep`" ] && echo ${Pid} >> running
      done < $1

      if [ -s running ]; then
          # Move the "running" file back to the correct location
          mv -f running $1
          running_entries=`wc -l "$1" 2> /dev/null | awk '{print $1}'`
          ThePid=`tail -1 "$1" 2>/dev/null | sed 's/ //g'`
          if [ $running_entries -eq 1 ]; then
              # Single running process
	      return 0
          else
              # Multiple running processes
              return 3
          fi
      else
          rm -f "$1" 2> /dev/null
          return 1
      fi
  fi
}

ExitIfRunning() {
    DIR=$4

    Check_sgd_running $1 $2
    result=$?
    if [ ${result} -eq 0 -o ${result} -eq 3 ]; then
	echo "$3"
	cd ${TTAINSTDIR}/bin
	rm -rf ${DIR} 2> /dev/null
	exit 1
    fi
}

# Delete all the patches of the given type from the patch list
DeleteRedundantPatches () {
    [ -f "${PATCH_LIST}" ] || {
        return
    }

    TYPE=$1

    # Find and delete the redundant patches from the old version
    [ -x "/usr/bin/nawk" ] && AWK="nawk" || AWK="awk"
    LIST=`grep "${DELIM}${TYPE}${DELIM}" ${PATCH_LIST} |
    ${AWK} -F "${DELIM}" -v version=${FILE_VERSION} '{
        if ($6 == version)
          print $1
    }' | tr ' ' '|'`

    if [ -n "${LIST}" ]; then
	egrep -v "${LIST}" ${PATCH_LIST} > ${TTAINSTDIR}/var/info/patch.list.tmp
	mv -f ${TTAINSTDIR}/var/info/patch.list.tmp ${PATCH_LIST}
    fi
}


# If the SGD server has been upgraded, delete any patches which have
# been superseded by the new version.
TidyUpAfterUpgrade() {
    # If patch config file doesn't exist there is nothing to do here.
    [ -f "${PATCH_CFG}" ] || {
        return;
    }
    
    FILE_VERSION=`grep "${PATCH_VERSION}" ${PATCH_CFG} 2> /dev/null | awk '{print $3}'`
    CURRENT_VERSION=`GetSGDVersion`

    case "${CURRENT_VERSION}" in
	${FILE_VERSION})
            return
	    ;;
	*)
	    DeleteRedundantPatches "binary" 
	    DeleteRedundantPatches "jserver"
	    DeleteRedundantPatches "webserver"
	    DeleteRedundantPatches "webcomp"
	    DeleteRedundantPatches "file"
	    ;;
    esac
}

# Modifies a entry in the patch list
# By default, it changes the status from active -> inactive.
# If a second parameter is supplied, it swaps entry for the new 
# entry without any other changes
UpdateEntry() {
    FROM_ENTRY=$1
    TO_ENTRY=$2

    if [ -z "${TO_ENTRY}" ]; then
	TO_ENTRY=`echo ${FROM_ENTRY} | sed -e 's/'${DELIM}${ACTIVE}${DELIM}'/'${DELIM}${INACTIVE}${DELIM}'/g'`
    fi

    grep -v "${FROM_ENTRY}" ${PATCH_LIST} > patch.list.tmp
    echo ${TO_ENTRY} >> patch.list.tmp
    mv -f patch.list.tmp ${PATCH_LIST}	
}

# Update the patch name for a patch command
UpdateRef() {
    COMMAND=$1
    NAME=$2
    PATCH_CFG=$3

    grep -v "^${COMMAND} :" ${PATCH_CFG} > patch.cfg.tmp
    mv -f patch.cfg.tmp ${PATCH_CFG}
    echo "${COMMAND} : ${NAME}" >> ${PATCH_CFG}
}


Usage_list() {
    echo "${info_long_usage}"
    exit 1
}

Version() {
    COMMAND=$1
    MSG=$2

    if [ -s "${PATCH_CFG}" ]; then
	DATA=`grep "^${COMMAND}" ${PATCH_CFG} |  awk '{print $3}'`	
    fi
    
    if [ -z "${DATA}" ]; then
	echo "  ${MSG} 2.0"
    else
	echo "  ${MSG} ${DATA}"
    fi
}

ReportVersions() {
    echo "${info_version}"

    Version "patch_add" "${info_add}"
    Version "patch_list" "${info_list}"
    Version "patch_remove" "${info_remove}"
    Version "patch_update" "${info_update}"

    echo ""
    echo "${info_errstrings}"

    Version "en-us/patch_add" "${info_add}"
    Version "en-us/patch_list" "${info_list}"
    Version "en-us/patch_remove" "${info_remove}"
}

TidyUpAfterUpgrade

NAME=""
ACTIVE=""
BRIEF=""

while [ ! -z "$1" ]; do
    case "$1" in
	--help)
	    Usage_list
	    ;;
	--name)
	    case "$2" in
		"" | --*) echo ${err_invalid_args}; Usage_list
	    esac
	    NAME=$2
	    shift; shift
	    ;;
	--active)
	    ACTIVE="active"
	    shift
	    ;;
	--verbose)
	    VERBOSE="verbose"
	    shift
	    ;;
	--version)
	    ReportVersions
	    exit
	    ;;
  --brief)
      BRIEF="brief"
      shift
      ;;
	*)
	    echo ${err_invalid_args} "$1"; Usage_list
	    ;;
    esac
done

if [ ! -s "${PATCH_LIST}" ]; then
    echo "${err_no_patch_list}"
    exit 1
fi

[ -x "/usr/bin/nawk" ] && AWK="nawk" || AWK="awk"
${AWK} -F "${DELIM}" -v name="$NAME" -v active="$ACTIVE" -v verbose="$VERBOSE" -v brief="$BRIEF" '
           BEGIN {
               pos = 1
           }

           function update(name, date, path, status, type) {
               colon = index(path, ":")
               if (colon > 0)
                  path = substr(path, colon+1, length(path))

               if (type == "delete")
                   path = "Deleted: "path

               for (i=1; i<pos; i++)
               {
                  if (patch[i,1] == name && patch[i,4] == status)
                  {
                      if (index(patch[i,3], path"\n") == 0)
                         patch[i,3] = (patch[i,3]"\n"path)
                      return
                  }
               }

               patch[pos,1] = name
               patch[pos,2] = date
               patch[pos,3] = path
               patch[pos,4] = status

               pos++
            }

            {
               if (length($0) > 0 &&
                   (length(name) == 0 || $1 == name) &&
                   (length(active) == 0 || $7 == active))
               {
                   update($1, $3, $4, $7, $2)
               }
           }
             
           END {
               for (i=1; i<pos; i++)
               { 
                  if (length(brief) > 0)
                  {
                      print patch[i,1]
                  }
                  else
                  {
                      print ""
                      print "Name : " patch[i,1]
                      print "Installation date : " patch[i,2]
                      if (length(verbose) > 0 )
                      {
                        if (index(patch[i,3], "\n") > 0)
                          print "Location :\n" patch[i,3]
                        else
                          print "Location : " patch[i,3]
                      }
                      print "Status : " patch[i,4]
                  }
               }
           }
        ' ${PATCH_LIST}
