#! /bin/sh
#
#	Copyright 12/01/97 Sun Microsystems, Inc.  All Rights Reserved.
#
#ident "@(#)oracle_db_shutdown.sho   1.15     97/12/01 SMI"
#
# oracle_db_shutdown - shut down Oracle instances
# 
# This is an internal HA DBMS command, and should not be called directly
# from the command line. Currently, oracle_svc_stop and oracle_svc_abort
# call this script
#
# usage:
#    oracle_db_shutdown <mode> <instance1> ....
#  where mode should be "immediate" or "abort"
#
HA_BIN=/opt/SUNWhadf/bin
# Copyright 12/01/97 Sun Microsystems, Inc.  All Rights Reserved.
# @(#)oracle_boiler	1.8 97/12/01 SMI

# begin of common ha-dbms boilerplate

# remember our name
argv0=`basename $0`


LOGGER=/usr/bin/logger

# if HA_CLUSTER is not set, read the environment
# NOTE: haoracle_fmon_start unsets HA_CLUSTER to force re-building the env.
if [ "$HA_CLUSTER" = "" ] ; then
	if [ ! -r "$HA_ENV" ] ; then
		$LOGGER -p local7.err -t "$HA_CLUSTER" "$argv0: Cannot determine correct HA environment"
		exit 1
	fi
	. $HA_ENV
	if [ $? -ne 0 ] ; then
		$LOGGER -p local7.err -t "$HA_CLUSTER" "$argv0: cannot include ha_env file $HA_ENV"
		exit 1	
	fi
fi

# include HA utilities library
. utilities
if [ $? -ne 0 ]; then
	$LOGGER -p local7.err -t "$HA_SLOGTAG" "$argv0: Cannot find HA utilities library"
	exit 1
fi

# usage
#if [ "$USAGE_PARMS" != "" ] ; then
#  	if [ $# -ne $USAGE_PARMS ] ; then
#    		$LOGGER -p local7.err -t "$HA_SLOGTAG" "$argv0: Incorrect number of command line parameters"
#    		exit 2
#  	fi
#fi


# some default files and locations
# don't move this up - it depends on HA_FILES, which gets set above
HA_DATABASES=${HA_FILES}/haoracle_databases
HA_DB_SUPPORT=${HA_FILES}/haoracle_support


# verify that we have the haoracle_databases files
if [ ! -r $HA_DATABASES ] ; then
  logerr "file ${HA_DATABASES} does not exist or is not readable!"
  exit 2
fi

# verify that we have the haoracle_support file
if [ ! -r $HA_DB_SUPPORT ] ; then
  logerr "file ${HA_DB_SUPPORT} does not exist or is not readable!"
  exit 2
fi


# talk_start ... - echo the args, run them, and evaluate return value
talk_start() {
  	lognotice "$$: $*"
  	if $* ; then
    		return 0
  	else
    		logerr "$$: $* ... failed"
    		return 1
  	fi
}


# talk_start_bg ... - print the args, then run them in the background
talk_start_bg() {
  	lognotice "$$: $*"
  	$* &
  	}


# get_pid [ -u userid ] pattern - find the process id of a running program
# if called with "-u userid", only process for that user will be considered
get_pid() {
	if [ "$1" = "-u" ] ; then
		ps_args="-f -u $2"
		shift
		shift
	else
		ps_args="-ef"
	fi
	PID=`/usr/bin/ps $ps_args | grep "\<$*\>" | nawk -v pat="$*" '
 BEGIN { 
   search_pat = substr(pat, 0, 79)
   }
 { if ( match($0, search_pat) )
     if ( ! match($0, "nawk -v pat=") )
       print $2
  }
'`
}


# kill_proc pattern - find and terminate a process
kill_proc() {
  	lognotice "Killing $*..." 
  	get_pid $*
  	if [ "$PID" ] ; then
    		for p in ${PID} ; do
      			lognotice "Killing process id $p"
      			kill $p
    		done
    		echo
  	else
    		lognotice "process \"$*\" could not be located..." 
  	fi
}

# read_ha_databases instance - find an entry in the HA_DATABASES file,
# 	parse it apart, and return in variables. Assumes that oracle_home
#	is set!
read_ha_databases() {
	conf_line=`grep "^o[nf][f]*	$1	" $HA_DATABASES`
	if [ "$conf_line" = "" ] ; then
		logerr "$1 missing from $HA_DATABASES!"
		return 1
	fi
	logical_host=`echo "$conf_line" | cut -s -f 3`
	poll_cycle=`echo "$conf_line" | cut -s -f 4`
	connect_cycle=`echo "$conf_line" | cut -s -f 5`
	timeout=`echo "$conf_line" | cut -s -f 6`
	restart_delay=`echo "$conf_line" | cut -s -f 7`
	db_login=`echo "$conf_line" | cut -s -f 8`
	init_ora=`echo "$conf_line" | cut -s -f 9`
	listener_name=`echo "$conf_line" | cut -s -f 10`
	return 0
}

# find_oracle instance - finds and sets various Oracle related variables:
#	ORACLE_HOME SQLDBA PFILE
# in case of a problem, it returns with an empty ORACLE_HOME variable
find_oracle() {
  	ORATAB=/var/opt/oracle/oratab

  	ORACLE_HOME=""
	SQLDBA=""
	if oratab_line=`grep "^$1:" $ORATAB` ; then
		oracle_home=`echo $oratab_line | awk -F: '{print $2}' -`
		if [ -d $oracle_home ] ; then
			if [ ! -f $oracle_home/orainst/RELVER ] ; then
				logerr "cannot find Oracle release number; RELVER file is missing"
				exit 1
			fi

			ora_version=`grep RELEASE_VERSION $oracle_home/orainst/RELVER | cut -d= -f2`
			if [ "$ora_version" = "" ] ; then
				logerr "RELEASE_VERSION missing from RELVER file"
				exit 1
			fi

			ora_subversion=`echo $ora_version | cut -d. -f2`
			ora_rel=`echo $ora_version | cut -d. -f3`
			if [ "$ora_rel" = "" ] ; then
				ora_rel=0
			fi

			# check if the oracle version is supported
			# The versions we will support are:  7.3.[>=2] ,
			# 7.2.[>=3] , and 7.1.[>=6].
			if [ $ora_subversion -eq 3 -a $ora_rel -lt 2 -o \
			     $ora_subversion -eq 2 -a $ora_rel -lt 3 -o \
			     $ora_subversion -eq 1 -a $ora_rel -lt 6 ] ; then
				logerr "Oracle $ora_version not supported!"
				exit 1;
			fi

			# release 7.3 use svrmgrl to connect to the instance
			if [ $ora_subversion -ge 3 ] ; then
				SQLDBA="${oracle_home}/bin/svrmgrl"
			else
				SQLDBA="${oracle_home}/bin/sqldba"
			fi

			if [ -x ${SQLDBA} ] ; then
				read_ha_databases $1
				ORACLE_HOME="$oracle_home"
				PFILE="$init_ora"
			else
				logerr "${SQLDBA} does not exist or is not executable!"
			fi
		else
			logerr "Invalid value for ORACLE_HOME: ${oracle_home}"
		fi
	else
		logerr "Database '$1' not found in ${ORATAB}"
	fi
    	export ORACLE_HOME SQLDBA PFILE
}


make_rpc_call() {
  	lognotice "Calling $3 for instance $2 on host $1..."
  	ha_dbms_call $1 $2 $3 
  	}

#end of common ha-dbms boiler plate
#include_boiler

if [ $# -lt 1 ] ; then
  	logerr "usage: $argv0 mode [ instance1 ... ]"
  	exit 2
fi

stop_mode=$1
shift

# ha_dbms_db_shutdown_oracle ( stop | abort ) instance
ha_dbms_db_shutdown_oracle() {
	stop_mode=$1
	ORACLE_SID=$2 ; export ORACLE_SID
	find_oracle $ORACLE_SID

	if [ "$ORACLE_HOME" != "" ] ; then
    		oracle_owner=`ls -ld ${ORACLE_HOME} | nawk '{print $3}'`
		# find out if database is indeed up
   		if [ -f ${ORACLE_HOME}/dbs/sgadef${ORACLE_SID}.dbf -o \
	  	     -f ${ORACLE_HOME}/dbs/sgadef${ORACLE_SID}.ora ] ; then
			db_up="yes"
		else
      			get_pid -u $oracle_owner ora_smon_${ORACLE_SID}
      			if [ "$PID" ] ; then
				db_up="yes"
			else
				db_up="no"
			fi
      		fi
		if [ "$db_up" = "yes" ] ; then
      			lognotice "starting shutdown $stop_mode for oracle instance $ORACLE_SID"
      			echo "connect internal
shutdown $stop_mode" | su $oracle_owner -c $SQLDBA


			# Look for hung listener processes.  These
			# will cause switchover to fail if their databases
			# are on raw devices.
      			get_pid oracle${ORACLE_SID}
			for hung_listener in $PID
			    do
			    kill -KILL $hung_listener
			done

		else
			lognotice "Oracle database \"${ORACLE_SID}\" already shut down"
		fi
	else
  		logerr "Oracle database \"${ORACLE_SID}\" NOT shut down"
	fi
}

# main loop - call shutdown for the various instances
for instance in $* ; do
    	ha_dbms_db_shutdown_oracle $stop_mode $instance 
done

# stop listeners after instance shutdown; since multiple instance
# may share same listener
if [ "$stop_mode" = "abort" ] ; then
	p="`getpids2 orasrv`"
	if [ ! -z "$p" ] ; then
		kill_proc orasrv
	fi
        p="`getpids2 tnslsnr`"
        if [ ! -z "$p" ] ; then
                kill_proc tnslsnr
        fi
else
        # selectively stop listener for those logical hosts not mastered 
        $HA_BIN/haget -f not_mastered | \
        while read lh ; do
#                t_pid=`/usr/bin/ps -ef|grep -w tnslsnr|grep -w "$lh"| nawk '{print $2}'`
#		if [ "$t_pid" ]; then
#			kill -KILL $t_pid
#		fi

		active_listener=`grep "^on	.*	$lh" \
			${HA_DATABASES} | cut -s -f 10 | sort | uniq`

		for al in $active_listener
		do
			t_pid=`/usr/bin/ps -ef|grep -w tnslsnr | grep -w "$al"| nawk '{print $2}'`
			if [ "$t_pid" ]; then
				kill -KILL $t_pid
			fi
		done

		# Shutdown unnamed (default) LISTENER, if any
		#t_pid=`/usr/bin/ps -ef|grep -w tnslsnr | grep ' LISTENER '| nawk '{print $2}'`
		#if [ "$t_pid" ]; then
		#	kill -KILL $t_pid
		#fi

        done

fi

wait
