#!/bin/sh
# Copyright (c) Oracle Corporation 2009-2010. All Rights Reserved.
#
# $Id: mpkill,v 5.1 2010-03-30 15:56:17 jschmidt checked $

#
# mpkill - Abort a Running MOPatch Process.
#
# Call mpkill -h for a short command-line overview.  See
# readme.txt under $ORACLE_HOME/MOPatch or SAP note 1027012 for
# complete documentation.
#

###############################
#
# included blocks and functions
#
###############################

IFS=" 	
"
SPC=" "
TAB="	"
NL="
"

( unset CDPATH ) 1>/dev/null 2>&1 && unset CDPATH
PS1='$ '
PS2='> '
PS4='+ '

logopen=0
logfile=""
logerrhdl=2
rlogopen=0
verbosep=0

internalerror=0
cmdlineerror=0
conflicterror=0
opatcherror=0
linkerror=0

usage()
{
  echo "$1" 1>&2
  echo "$USAGE" 1>&2
  exit 2
}

error()
{
  p_4_0_class=""
  if test "X$1" = "X-c"; then
    p_4_0_class=$2
    shift
    shift
  else
    p_4_0_class="internalerror"
  fi

  if test $logopen = 1; then
    echo 1>&2
    echo "$1" 1>&2

    # keep noise low in recursive calls
    if test $rlogopen = 0; then
      echo "Refer to log file${NL}  $logfile${NL}for more information." 1>&2
    fi
    echo 1>&3
    echo "$1  Exiting." 1>&3
  else
    echo "$1" 1>&2
  fi

  case $p_4_0_class in
    internalerror) exit  1 ;;
    cmdlineerror)  exit  2 ;;
    conflicterror) exit  4 ;;
    opatcherror)   exit  8 ;;
    linkerror)     exit 16 ;;
    ""|*[!0-9]*)   exit  1 ;;
    *)             exit $p_4_0_class ;;
  esac
}

logerr()
{
  p_4_1_quiet=""
  if test "X$1" = "X-q"; then
    p_4_1_quiet=1
    shift
  else
    p_4_1_quiet=0
  fi

  p_4_1_class=""
  if test "X$1" = "X-c"; then
    p_4_1_class=$2
    shift 2
  else
    p_4_1_class="internalerror"
  fi

  if test $p_4_1_quiet = 1; then
    if test $logopen = 1; then
      echo "$1" 1>&3
    fi
  else
    echo "$1  Continuing." 1>&2
    if test $logopen = 1; then
      echo "$1  Continuing." 1>&3
    fi
  fi

  eval "$p_4_1_class"='1'

  return 0
}

out()
{
  if test $# = 1; then
    echo "$1" 1>&1
    echo "$1" 1>&3
  else
    echo 1>&1
    echo 1>&3
  fi

  return 0
}

log()
{
  if test $# = 1; then
    echo "$1" 1>&3
  else
    echo 1>&3
  fi

  return 0
}

verbose()
{
  if test $# = 1; then
    if test $verbosep = 1; then
      echo "$1" 1>&1
    fi
    echo "$1" 1>&3
  else
    if test $verbosep = 1; then
      echo 1>&1
    fi
    echo 1>&3
  fi

  return 0
}

rawout()
{
  if test $# = 1; then
    echo "$1" 1>&1
  else
    echo 1>&1
  fi

  return 0
}

numberp()
{
  case $1 in
    ""|*[!0-9]*) return 1 ;;
    *)           return 0 ;;
  esac
}

quotemeta()
{
  l_4_9_scqre=""                                    # special char quoting regexp
  if test "X${1-}" = "X-x"; then
    l_4_9_scqre='\.\*\[\\\^\$(){}?+|'
    shift
  else
    l_4_9_scqre='\.\*\[\\\^\$'
  fi

  if test "X${1-}" = "X-s"; then
    l_4_9_scqre="$l_4_9_scqre\\$2"
    shift
    shift
  fi

  if sed 's/\(['"$l_4_9_scqre"']\)/\\\1/g'; then
    return 0
  else
    return 1
  fi
}

basenamef()
{
  case $1 in
    *$NL*)
      echo "Internal error: Invalid newline characters in file name." 1>&2
      return 1 ;;
  esac

  if test "X$1" = "X"; then
    echo ""
    return 0
  elif expr "//$1" : '.*/\(.*\)$'; then
    return 0
  else
    return 1
  fi
}

exitvalf()
{
  l_4_10_exitval=0

  if test $internalerror != 0; then
    l_4_10_exitval=`expr $l_4_10_exitval + 1`
  fi
  if test $cmdlineerror != 0; then
    l_4_10_exitval=`expr $l_4_10_exitval + 2`
  fi
  if test $conflicterror != 0; then
    l_4_10_exitval=`expr $l_4_10_exitval + 4`
  fi
  if test $opatcherror != 0; then
    l_4_10_exitval=`expr $l_4_10_exitval + 8`
  fi
  if test $linkerror != 0; then
    l_4_10_exitval=`expr $l_4_10_exitval + 16`
  fi

  case $l_4_10_exitval in
    [0-9]|[0-9][0-9])
      echo "$l_4_10_exitval"
      return 0 ;;
    *)
      echo "Internal error: Invalid exit value \"$l_4_10_exitval\"." 1>&2
      echo "1"
      return 1 ;;
  esac
}


################################
#
# constants and global variables
#
################################

REVISION='$Revision: 5.1 $'
COPYRIGHT="Copyright (c) Oracle Corporation 2009-2010. All Rights Reserved."
HEADER="mpkill - Abort a Running MOPatch Process - 2.1.11."
USAGE="Usage: mpkill [-hv] [-s sigspec]"

LTIMESTAMP=`date "+%Y_%m_%d-%H-%M-%S"`

# parameter variables
xlogfile=""
sigspec="USR1"

if self=`basenamef "$0"`; then
  :
else
  error "Cannot determine basename of \"$0\"."
fi


#########################################
#
# parse and verify options and parameters
#
#########################################

# keep for later
oargv=""
if test $# = 0; then
  oargv=$0
else
  oargv="$0 $*"
fi

while getopts :vs:L: c; do
  case $c in
    v) verbosep=1 ;;
    s) sigspec=$OPTARG ;;
    L) xlogfile=$OPTARG ;;
    *) cat << EOF 1>&2
Invalid or incomplete option specified.
$USAGE

Options:
  -h    show a short command-line overview.  See readme.txt under
        \$ORACLE_HOME/MOPatch or SAP note 1027012 for complete
        documentation.
  -v    be verbose; produce more diagnostic output

  -s sigspec
        send the MOPatch process the specified signal.  Defaults to
        "USR1", which is the recommended way to abort a running MOPatch
        process.

        Must be one of the signal numbers "1", "2", "3", "9", "15" or one
        of the symbolic signals "INT", "QUIT", "KILL", "TERM", "USR1".

This utility requires environment variable ORACLE_HOME to be set.

$HEADER
$COPYRIGHT
EOF
       exit 2 ;;
  esac
done

# PD (osf1_alpha): check for non-Posix shell
if test "X${OPTIND-}" = "X"; then
  error "Cannot run on non-Posix shell. On Tru64, use /usr/bin/posix/sh."
fi

# shift <n> may not be portable
i=$OPTIND
while test $i -gt 1; do
  i=`expr $i - 1`
  shift
done

# verify signal specifier
case $sigspec in
  1|2|3|9|15) : ;;
  HUP|INT|QUIT|KILL|TERM|USR1) : ;;
  *)
    usage "Invalid signal specifier \"$sigspec\" specified." ;;
esac

# verify Oracle Home.  Assume that MOPatch already checked the
# rest and keep the tests minimal.
if test "X${ORACLE_HOME-}" = "X"; then
  usage "No Oracle Home specified."
fi


###############
#
# open log file
#
###############

logdir="$ORACLE_HOME/cfgtoollogs/mopatch"
if test -d "$logdir"; then
  :
else
  error "Cannot find log directory \"$logdir\"."
fi

if test "X$xlogfile" = "X"; then
  logfile="$logdir/mpkill-$LTIMESTAMP.log"
  if ( exec 3>"$logfile" && exec 3>&- ) && exec 3>"$logfile"; then
    :
  else
    error "Cannot open log file \"$logfile\" for writing."
  fi
else
  logfile=$xlogfile
fi
logopen=1
logerrhdl=3

# carefully brush up log file name (which from here is used in
# messages only)
if ohre=`printf '%s\n' "$ORACLE_HOME" | quotemeta -s '/' 2>&3` &&
   lfn=`printf '%s\n' "$logfile" |
        sed 's/^'"$ohre"'\//$ORACLE_HOME\//' 2>&3`; then
  logfile=$lfn
fi

# write our header before doing anything else
out "$HEADER"
out "$COPYRIGHT"


#############################################
#
# miscellaneous validation and initialization
#
#############################################

# determine and verify MOPatch PID file
mppid=""
pidfile="$ORACLE_HOME/.mopatchpid"
if test -f "$pidfile"; then
  if mppid=`cat "$pidfile" 2>&3`; then
    :
  else
    error "Cannot read PID file \"$pidfile\"."
  fi
  if numberp "$mppid"; then
    :
  else
    error "Cannot determine PID from \"$mppid\" in PID file \"$pidfile\"."
  fi
elif test "X$self" != "Xfmpkill.sh"; then
  error "Cannot find PID file \"$pidfile\" (probably no MOPatch running)."
fi

# determine and verify FAMOPatch PID file
fmppids=""
pidfile="$ORACLE_HOME/.famopatchpid"
if test "X$self" = "Xfmpkill.sh"; then
  if test -f "$pidfile"; then
    if fmppids=`cat "$pidfile" 2>&3`; then
      :
    else
      error "Cannot read PID file \"$pidfile\"."
    fi
    for fmppid in $fmppids
    do
      if numberp "$fmppid"; then
        :
      else
        error "Cannot determine PID from \"$fmppid\" in PID file \"$pidfile\"."
      fi
    done
  else
    error "Cannot find PID file \"$pidfile\" (probably no FAMOPatch running)."
  fi
fi


################################################
#
# write some initial information to the log file
#
################################################

# brush up revision
revision=`printf '%s\n' "$REVISION" | sed 's/^\$Revisio[n]: //;s/ \$$//' 2>&3`

# write some diagnostic information
verbose
verbose "Version:       2.1.11"
verbose "Revision:      $revision"
verbose "Command-line:  $oargv"

verbose
verbose "Oracle Home:   $ORACLE_HOME"
verbose "Log file:      $logfile"
if test $verbosep = 0; then
rawout
rawout  "Log file: $logfile"
fi


##############
#
# main program
#
##############

for fmppid in $fmppids
do
  log "executing: kill \"-$sigspec\" \"$fmppid\""
  if kill "-$sigspec" "$fmppid" 1>&3 2>&3; then
    :
  else
    logerr "Cannot kill FAMOPatch process $fmppid with signal \"$sigspec\"."
  fi
done

if test "X$mppid" != "X"; then
  log "executing: kill \"-$sigspec\" \"$mppid\""
  # do not re-direct IO here, since it should be immediately
  # visible to the user
  if kill "-$sigspec" "$mppid"; then
    out
    out "Killed MOPatch process $mppid with signal \"$sigspec\"."
    out "Please wait for the MOPatch process and its child processes to"
    out "complete."
  else
    error "Cannot kill MOPatch process $mppid with signal \"$sigspec\"."
  fi
fi


########################
#
# miscellaneous clean-up
#
########################

# close log file
logerrhdl=2
logopen=0
if test "X$xlogfile" = "X"; then
  exec 3>&-
fi

exit `exitvalf`
