#! /bin/ksh
#
#	Copyright 11/04/99 Sun Microsystems, Inc.  All Rights Reserved.
#
#ident "@(#)oracle_db_shutdown.sho   1.39     99/11/04 SMI"
#
# oracle_db_shutdown - shut down Oracle instances & listeners
# 
# 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.  This assumes that the calling process only passes
# Oracle instances that are not (eventually) mastered by this node.
#
# usage:
#    oracle_db_shutdown <mode> <not_mastered> <instance1> ....
#  where mode should be "immediate" or "abort"
#
# External Dependencies:
#	get_pid ===> PID
#	find_oracle
# 	
# Input arguments:
#	stop_mode
#	remote_mastered
#	ORACLE_SID
#

# Copyright 06/09/99 Sun Microsystems, Inc.  All Rights Reserved.
# @(#)oracle_boiler	1.35 99/06/09 SMI

# begin of common ha-dbms boilerplate

# remember our name
argv0=`basename $0`

# Get the BASEDIR and PRODUCTDIR settings from the installed pkgs
_basedir=`pkgparam SUNWscor BASEDIR 2>/dev/null`
_productdir=`pkgparam SUNWscor PRODUCTDIR 2>/dev/null`
_basedir=${_basedir:=""}
_productdir=${_productdir:="SUNWcluster"}

LOGGER=/usr/bin/logger
PATH=${_basedir}/opt/${_productdir}/bin:/opt/SUNWcluster/bin:${_basedir}/opt/${_productdir}/ha/oracle:${PATH}
export PATH
HA_FILES=/etc/opt/SUNWscor; export HA_FILES
HA_VAR=/var/opt/SUNWscor; export HA_VAR

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

HA_CLUSTER=$CLUSTNAME; export HA_CLUSTER

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

PREFIX="SUNWcluster.ha.${ds}"
HA_FM_NAME="fault_mon"

# verify that we have the haoracle_support file
if [ ! -r $HA_DB_SUPPORT ] ; then
  logerr "4000" \
	"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() {
  	logprint "$$: $*"
  	if $* ; then
    		return 0
  	else
    		logprint "$$: $* ... failed"
    		return 1
  	fi
}


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


# 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() {
  	logprint "Killing $*..." 
  	get_pid $*
  	if [ "$PID" ] ; then
    		for p in ${PID} ; do
      			logprint "Killing process id $p"
      			kill $p
    		done
    		echo
  	else
    		logprint "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=$(get_instance "${ds}" "$1")
        set_inst_name $1

	if [ "$conf_line" = "" ] ; then
		logerr "4010" "$1 missing from HA ORACLE CCD!"
		return 1
	fi
        on_off_mode=`echo "$conf_line" | cut -s -f 1`
	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`

        set_logical_host $logical_host
	return 0
}

# find_oracle instance - finds and sets various Oracle related variables:
#	ORACLE_HOME SQLDBA PFILE LD_LIBRARY_PATH
# in case of a problem, it returns with an empty ORACLE_HOME variable
find_oracle() {

	typeset my_node
	typeset physical_hosts

  	ORATAB=/var/opt/oracle/oratab

  	ORACLE_HOME=""
	SQLDBA=""
        read_ha_databases $1
        if [ $? -ne 0 ]; then
                return 1
        fi
        my_node=`uname -n`
        physical_hosts=$(haget -f physical_hosts -h $logical_host | tr '\012' ' ')
        is_member "$my_node" "$physical_hosts"
        if [ $? -ne 0 ] ; then
                return 1
        fi


	if oratab_line=`grep "^[	 ]*$1:" $ORATAB` ; then
		oracle_home=`echo $oratab_line | awk -F: '{print $2}' -`
		if [ -d $oracle_home ]; then
ora_version=$(get_dbms_version ${logical_host} ${ORACLE_SID} oracle)
rc=$?
if [ $rc -ne 0 ]; then
ora_version=$(get_dbms_version -p ${logical_host} ${ORACLE_SID} oracle)
rc=$?
fi
if [ $rc -ne 0  -o  "${ora_version}" = ""  ]; then
logerr "${prog}.4074" \
        "Could not find version for ${ORACLE_SID}, ($rc)"
	 exit 1
fi

			SQLDBA="${oracle_home}/bin/svrmgrl"

			if [ -x ${SQLDBA} ] ; then
				ORACLE_HOME="$oracle_home"
				PFILE="$init_ora"
			else
				logerr "4060" \
				"${SQLDBA} does not exist or is not executable!"
				return 1
			fi
		fi
	else
		logerr "4070" "Database '$1' not found in ${ORATAB}"
		return 1
	fi
	LD_LIBRARY_PATH=${ORACLE_HOME}/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
    	export ORACLE_HOME SQLDBA PFILE LD_LIBRARY_PATH

	return 0

}


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


get_remote_host(){
	get_diskgroups $1 $2
        RSHHOST=""
        for X in `haget  -f private_links -h $HA_REMOTEHOST` ; do
          net_pinghost $X > /dev/null 2>&1
          if [ $? -eq 0 ] ; then
                RSHHOST=$X
                export RSHHOST
                return 0
          fi
        done
        return 1
        }
#end of common ha-dbms boiler plate
#include_boiler
prog=${prog:="${HA_FM_NAME}"}

if [ $# -lt 1 ] ; then
  	logerr "${prog}.4100" \
		"usage: $argv0 mode remote_mastered [ instance1 ... ]"
  	exit 2
fi

stop_mode=$1; shift
remote_mastered=`echo $1 | tr ',' ' '`; shift

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

        read_ha_databases $ORACLE_SID || return
        if [ -z "`disk_lh_mounted $logical_host`" ] ; then
                return;
        fi
	
 	find_oracle $ORACLE_SID || return 

	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 "${prog}.2001" \
				"starting shutdown $stop_mode for oracle instance $ORACLE_SID"

			# time the shutdown, allow 30 secs for abort & other processing
			timeout=`expr $method_timeout - 30`
      			hatimerun -t $timeout su $oracle_owner -c "${_basedir}/opt/${_productdir}/ha/oracle/oracle_shutdown $stop_mode"

			if [ $? -ne 0 ] ; then
				# shutdown gracefully failed, force an abort
      				lognotice "${prog}.2002" \
					"Graceful shutdown failed for oracle instance $ORACLE_SID, starting abort..."
      				su $oracle_owner -c "${_basedir}/opt/${_productdir}/ha/oracle/oracle_shutdown abort"
			fi	

			# 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
                        lognotice "${prog}.2005" \
                                "Shutdown $stop_mode for oracle instance $ORACLE_SID completed"
		else
			#
			# Do a shutdown abort anyway to make sure that
			# the oracle enviroment is clean
			#
			su $oracle_owner -c "${_basedir}/opt/${_productdir}/ha/oracle/oracle_shutdown abort"
			lognotice "${prog}.2011" \
				"Oracle database \"${ORACLE_SID}\" already shut down"
		fi
update_status $logical_host ${ORACLE_SID} update OFFLINE 0
	export LISTENER_NAME=${listener_name:="LISTENER"}
/usr/bin/ps -e -u $oracle_owner -o args | grep -w "tnslsnr $LISTENER_NAME " | grep -v "grep" > /dev/null
                if [ $? -eq 0 ]; then
                        hatimerun -t $listener_timeout $ORACLE_HOME/bin/lsnrctl stop $LISTENER_NAME > /dev/null 
                fi

	fi
}

# main loop - call shutdown for the various instances

method_timeout=`hareg -q oracle -T stop_net`

for instance in $* ; do
    	ha_dbms_db_shutdown_oracle $stop_mode $instance &
done


#wait

# wait for completion of all the background jobs or  completion of allowed
# execution time

wait_time=`expr $method_timeout - 3`
 

while (( $SECONDS < $wait_time ))
do
        bg_jobs=$(jobs -l)

        if [ -z "$bg_jobs" ]; then
               return 0 
        fi
        sleep 1
done

return 1

