#!/bin/ksh
#
# ident	"@(#)scadmin.ksh	1.75	03/05/19 SMI"
#
# 	Copyright 1993-2003 Sun Microsystems, Inc.  All rights reserved.
#	Use is subject to license terms.
#
# scadmin - Sun Cluster administration script.
#

PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/SUNWcluster/bin:$PATH
prog=`basename $0`

B=/opt/SUNWcluster/bin
E=/etc/opt/SUNWcluster
V=/var/opt/SUNWcluster

# Define message file name and location
TEXTDOMAIN=scadmin; export TEXTDOMAIN
TEXTDOMAINDIR=/opt/SUNWcluster/locale; export TEXTDOMAINDIR

yes=`gettext "yes"`
short_yes=`gettext "y"`
cap_yes=`gettext "YES"`
cap_short_yes=`gettext "Y"`
no=`gettext "no"`
short_no=`gettext "n"`
cap_no=`gettext "NO"`
cap_short_no=`gettext "N"`
wrong=`gettext "Please answer yes or no."`
 
USAGE="`gettext 'Usage:\n\
	%s [-a] [-f] startcluster localnodename clustname\n\
	%s [-a] [-f] startnode [clustname]\n\
	%s [-a] stopnode [clustname]\n\
	%s abortpartition localnodename clustname\n\
	%s continuepartition localnodename clustname\n\
	%s reldisks [clustname]\n\
	%s resdisks [clustname]\n\
	%s reserve cXtYdZ\n\
	%s switch   clustname [-m] logical-hosts ...\n\
	%s switch   clustname dest-host logical-hosts ...\n\
	%s switch   clustname -r\n'`"

# print usage and exit
usage_exit () {
	printf "${USAGE}\n" "$prog" "$prog" "$prog" "$prog" "$prog" "$prog" "$prog" "$prog" "$prog" "$prog" "$prog" >&2
	exit 2
}

# look up a value in the configuration file
enmatch () {
	${B}/cdbmatch $* ${cdbfile}
	if [ $? -ne 0 ]; then
		lmsg=`gettext "cdbmatch %s %s failed"`
		printf "${lmsg}\n" "$*" "${cdbfile}" 1>&2
		return 1
	fi
	return 0
}

# find the nodeid of the local node
get_nodeids () {

	# myuname is global
	myuname=$(uname -n)
	if [ $? -ne 0 ]; then
		lmsg=`gettext "Cannot obtain nodename of localhost"`
		printf "${lmsg}\n"
		exit 1
	fi
	if [ "`enmatch cluster.node.0.hostname`" = "${myuname}" ]
	then
		myid=0
	elif [ "`enmatch cluster.node.1.hostname`" = "${myuname}" ]
	then
		myid=1
	elif [ "`enmatch cluster.node.2.hostname`" = "${myuname}" ]
	then
		myid=2
	elif [ "`enmatch cluster.node.3.hostname`" = "${myuname}" ]
	then
		myid=3
	else
		lmsg=`gettext "Host %s is not a cluster member"`
		printf "${lmsg}\n" "${myuname}"
		exit 1
	fi
}
# check the nodename entered for a valid cluster member.
nodename_in_cluster () {
        typeset -i status
        typeset -i node
        typeset -i numofnodes

        nodename=$1
        let status=0
        let numofnodes=$(enmatch cluster.number.nodes)
	if [ $? -ne 0 ]; then
		exit 1
	fi

        let node=0
        while (( node < numofnodes )); do
                if [ "`enmatch cluster.node.${node}.hostname`" = "${nodename}" ]
                then
                        let status=1
                fi
                let node=node+1
        done
        if (( status == 0 )); then
		lmsg=`gettext \
		    "Error: Host %s is not a potential cluster member."`
		printf "${lmsg}\n" "${nodename}"
                exit 1
        fi
        return ${status}
}

function reconfigure_cluster
{
	${B}/scccd ${clustname} "" tryattach
	if [ "$?" -ne "0" ]; then
	        lmsg="`gettext \
		'The CCD is not ready for cluster reconfiguration.\n\
		 Attempt the reconfiguration later.'`"
		printf "${lmsg}\n"
		exit 1
	fi
	${B}/clustm reconfigure ${clustname}
}

function obtain_switchover_lock
{
    let wait=1
    while (( wait != 0 )); do
        ${B}/scccd ${clustname} LOCKNODE add lnode ${clustname} > /dev/null
        let rstatus=$?
        if (( rstatus == 17 )); then
            print "ccd file does not exsist, can not obtain switchover lock."
            return 1
        fi
        if (( rstatus != 0 )); then
	    let wait=wait+1
	    p=$(LC_ALL=C ${B}/get_node_status | grep sc: | awk '{print $2}')
	    if [[ ${p} == "aborted"  || ${p} != "included" ]]; then
			return 1
	    fi
	    sleep 5
        else
	    let wait=0 
        fi
    done
    return 0
}

function release_switchover_lock
{
	let wait=1
	while (( wait != 0 )); do
	   ${B}/scccd ${clustname} LOCKNODE remove lnode ${clustname}
           let rstatus=$?
           if (( rstatus == 17 )); then
               print "ccd file does not exsist, can not release switchover lock."
               return 1
           fi
	   if (( rstatus == 0 )); then
		let wait=0
	   fi
	   p=$(LC_ALL=C ${B}/get_node_status | grep sc: | awk '{print $2}')
	   if [[ ${p} != "included" ]]; then
		print "Unable to release switchover lock."
		print "Exiting switch attempt without abort."
		exit 1
	   fi
	done
	return 0
}

function check_for_reconfiguration
{
	typeset node_status cmm_state pdb_state

	node_status=$(LC_ALL=C ${B}/get_node_status)
	node_status=$(print ${node_status})

	cmm_state=${node_status##sc: }
	cmm_state=${cmm_state%% node id:*}
	pdb_status=${cmm_state% \(*\)}
 
	if [[ "${pdb_status}" = "in_transition reconfiguration" ]]; then
	        lmsg="`gettext \
		 'The cluster undergoing a reconfiguration.\n\
		 The switchover cannot be performed at this time.'`"
		printf "${lmsg}\n"
		release_switchover_lock
		exit 1
	fi

}

function check_mstate_format
{
    typeset node fmt_present
    typeset mstatefile

    mstatefile=/var/opt/SUNWcluster/run/$$mstate

#
# make sure only one node tries to add the format
#
    for node in ${currnodes}; do
        if [ "${node}" != "${localnodeid}" ]; then
                return 0
        else
                break
        fi
    done

#
# check if format already exists in the CCD. If it does
# not then we will:
#
# 1. store any existing rows from the current format
# 2. remove the current format
# 3. add the new format
# 4. restore the rows
#
    ccdfile=$(${B}/ccdadm ${clustname} -w)
    fmt_present=$(/bin/egrep 'LOGHOST_MSTATE_sync:.*ccd_nofreeze' ${ccdfile})
    if [[ -n ${fmt_present} ]]; then
# But first, make a backup copy just in case.
        ${B}/ccdadm -p ${ccdfile} >/dev/null 2>&1
        ${B}/scccd ${clustname} LOGHOST_MSTATE query lname '' \
                > ${mstatefile} 2>/dev/null
        while read row; do
                lname=$(print ${row} | sed 's/^.*:\(.*\):.*$/\1/')
                ${B}/scccd ${clustname} LOGHOST_MSTATE remove \
                         lname "${lname}"
        done <${mstatefile}
        ${B}/scccd ${clustname} LOGHOST_MSTATE remove_format
        ${B}/scccd ${clustname} LOGHOST_MSTATE add_format \
                'lname:mmode'  ${B}/mstate_sync
        while read row; do
                row=$(print ${row} |  sed 's/^.*:\(.*:.*\)/\1/')
                ${B}/scccd ${clustname} LOGHOST_MSTATE add \
                        'lname:mmode' "${row}"
        done < ${mstatefile}
    fi

    /bin/rm -rf ${mstatefile}

    return 0
}

function switchover_cmd
{
typeset dest_host	# destination host
typeset l lhlist	# logical host list and iterator
typeset row		# row retrieved from the CCD
typeset n curr_members	# current cluster membership and iterator
typeset nodename curr_nodes curr_nodeid dest_nodeid
typeset nodenames
integer found
typeset node
typeset something_went_wrong
typeset -i m_mode=0
typeset -i r_mode=0

curr_nodes=""
# run get_node_status in C locale because we parse output
curr_members=$(LC_ALL=C ${B}/get_node_status | /bin/grep membership \
		| sed -e 's/membership: //')
if [[ "${curr_members}" = "unknown" ]]; then
  lmsg="`gettext \
'This node does not appear to be in the cluster membership.\n\
This command cannot be run from this node.'`"
  printf "${lmsg}\n"
  exit 1
else
  for n in ${curr_members}; do
    nodename=$(${B}/cdbmatch cluster.node.${n}.hostname ${cdbfile})
    curr_nodes="${curr_nodes} ${nodename}"
  done
fi

while getopts mr c
do
 case $c in
    m) let m_mode=1
       ;;
    r) let r_mode=1
       ;;
    \?) lmsg=`gettext "%s: %s is not a valid option."`
        printf "${lmsg}\n" "$Myname" "$OPTARG"
        exit 2
        ;;
    esac
done

((positions_occupied_by_switches = OPTIND - 1))
shift $positions_occupied_by_switches

if (( r_mode == 1 )); then
	if (( $# >= 1 )) || (( m_mode == 1 )); then
		lmsg=`gettext "No arguments are required with the '-r' option."`
		printf "${lmsg}\n"
		usage_exit
	else
		reconfigure_cluster
		exit $? 
	fi
fi

if ( (( m_mode == 0 )) && (( $# < 2 )) ) || 
	( (( m_mode == 1 )) && (( $# < 1 )) ); then
	lmsg=`gettext "%s: Required parameters missing."`
	printf "${lmsg}\n" "$prog"
	usage_exit
fi

dest_host=""
if (( m_mode == 0 )); then
  dest_host=$1
  shift
  # check whether destination host is a cluster member
  let found=0
  for n in ${curr_nodes}; do
    if [[ "${n}" = "${dest_host}" ]]; then
      let found=1
      break
    fi
  done
  
  if (( found == 0 )); then
    lmsg=`gettext "Destination host %s is not a cluster member."`
    printf "${lmsg}\n" "${dest_host}"
    exit 1
  fi
fi

lhlist=$*

#
# Obtain switchover lock to serialize switchover attempts
#
obtain_switchover_lock

if (( $? != 0 )); then
	print "Unable to obtain switchover lock."
	print "Exiting switchover attempt."
	exit 1
fi

# If this flag gets set in the loop below, the function will return 1.
# It gets set any time something unexpected happens -- either pilot
# error or system error.
# (Any time we feel it's important enough to print a message.)
something_went_wrong=0

for l in ${lhlist}; do

  # check for the validity of the logical host
  # using a static query to the CCD.
  ccdfile=$(${B}/ccdadm ${clustname} -w)
  row=$(${B}/scccd -f ${ccdfile} ${clustname} LOGHOST query lname ${l})
  if [[ -z "${row}" ]]; then
    something_went_wrong=1
    lmsg="`gettext \
'The logical host %s is not defined in the Cluster Configuration Database.\n\
Ignoring %s.'`"
    printf "${lmsg}\n" "${l}" "${l}"
    continue
  fi

  # Get nnodelist and check if the destination node exists
  # only if we are not in maintenance mode.
  if (( m_mode == 0 )); then
        nodenames=`echo ${row} | /usr/bin/awk -F: '{ print $3}' | \
                          /usr/bin/tr ',' ' ' `
        found=0
        for node in ${nodenames}
        do   
                if [ "${node}"  = "${dest_host}" ]; then
                        found=1
                        break; 
                fi
        done   
        if (( found == 0 )); then
	   something_went_wrong=1
	   lmsg="`gettext \
'The specified destination host - %s - is not configured to master\n\
this logical host %s.'`"
	   printf "${lmsg}\n" "${dest_host}" "${l}"
           continue
        fi
  fi 

  # query for the current master of the logical host
  row=$(${B}/scccd ${clustname} LOGHOST_CM query lname ${l})
  curr_master=${row#*:*:}

  if [[ -n "${curr_master}" ]]; then
    
    if [[ -n "${dest_host}" && "${curr_master}" = "${dest_host}" ]]; then
      something_went_wrong=1
lmsg="`gettext \
'The specified destination host - %s - is the current\n\
master of logical host %s. Ignoring %s.'`"
      printf "${lmsg}\n" "${dest_host}" "${l}" "${l}"
      continue
    fi

    # Set to maintenance mode.
    if (( m_mode == 1 )); then
	# If DiskSuite is the volume manager and this logical host is
	# mastered by a remote node, skip it.
	# Operator must run command on current master host.
	if [[ "$vm" = "sds" ]]; then
		# myuname was set by get_nodeids()
		if [[ "${curr_master}" != "${myuname}" ]]; then
			something_went_wrong=1
			lmsg="`gettext \
'Ignoring %s because it is not mastered here.\n\
Please re-run this command on node %s,\n\
which currently masters %s.\n'`"
			printf "${lmsg}\n" "${l}" "${curr_master}" "${l}"
			continue
		fi
	fi
    fi

    # find the node id of the current master

    for n in ${curr_members}; do
      nodename=$(${B}/cdbmatch cluster.node.${n}.hostname ${cdbfile})
      if [[ "${nodename}" = "${curr_master}" ]]; then
	curr_nodeid=${n}
      fi
      if [[ "${nodename}" = "${dest_host}" ]]; then
	dest_nodeid=${n}
      fi
    done

    check_for_reconfiguration

    # Note: this logic is duplicated in loghostreconfig.sh.
    ${B}/scccd ${clustname} LOGHOST_CM remove lname ${l}
    
    if (( $? != 0 )); then

      something_went_wrong=1

      lmsg="`gettext \
'Unable to bring down logical host %s on %s.\n\
Check system console logs on %s for detailed\n\
error messages. Trying to re-master it on the original node.'`"
      printf "${lmsg}\n" "${l}" "${curr_master}" "${curr_master}"

      # Un-do maintenance mode if appropriate.
      if (( m_mode == 1 )); then
         set_loghost_mstate ${l} 1
      fi

      # Query to verify that row was indeed removed.
      row=$(${B}/scccd ${clustname} LOGHOST_CM query lname ${l})
      cm=${row#*:*:}
      if [ -z "$cm" ]; then
	# Row was successfully removed.
	# Add it back so that the logical host
	# is brought to sane state again.

	${B}/scccd ${clustname} LOGHOST_CM add "lname:curr_master" \
	    "${l}:${curr_master}"

	if (( $? != 0 )); then
	  lmsg="`gettext \
'Unable to re-master the logical host %s on %s.\n\
Aborting node to prevent data service inconsistencies.'`"
	  printf "${lmsg}\n" "${l}" "${curr_master}"
	  release_switchover_lock
	  ${B}/clustm abort ${clustname} ${curr_nodeid}
	  cleanup_and_exit
	else
	  lmsg=`gettext \
	      "Logical host %s has been re-mastered on %s."`
	  printf "${lmsg}\n" "${l}" "${curr_master}"
	fi
      fi

      # we got the logical host re-mastered and hence continue
      continue
    else
      # scccd remove returned success, but
      # handle special case where release of SDS diskset fails
      # when going into maintenance mode.  We'll proceed as if
      # the operation succeeded, but print a warning message.
      if [[ ${m_mode} -eq 1 ]]; then
	if [ -f ${V}/release_failed ]; then
	  something_went_wrong=1
	  lmsg="`gettext \
'Release of some diskset(s) failed while putting %s \n\
into maintenance mode.'`"
	  printf "${lmsg}\n" "${l}"
	  rm -f ${V}/release_failed
	fi
      fi
    fi
    if (( m_mode == 1 )); then
	set_loghost_mstate ${l} 0
    fi
  fi

  if [[ -n "${dest_host}" ]]; then

    if (( m_mode == 0 )); then
        set_loghost_mstate ${l} 1
    fi


    check_for_reconfiguration

    ${B}/scccd ${clustname} LOGHOST_CM add "lname:curr_master" \
		"${l}:${dest_host}"

    if (( $? != 0 )); then

      something_went_wrong=1
      #
      # clean up the stuff if required, so that logical host is
      # not mastered anywhere.
      #

      lmsg="`gettext \
'Unable to bring up logical host %s on %s.\n\
Check system console logs on %s for detailed error messages.'`"
      printf "${lmsg}\n" "${l}" "${dest_host}" "${dest_host}"


      ${B}/scccd ${clustname} LOGHOST_CM remove lname ${l}
      
      if (( $? != 0 )); then

	 lmsg="`gettext \
'Unable to clean up logical host %s on %s.\n\
Aborting node to prevent data service inconsistencies.'`"
	 printf "${lmsg}\n" "${l}" "${dest_host}"

	 release_switchover_lock
         ${B}/clustm abort ${clustname} ${dest_nodeid}
	 cleanup_and_exit

      else

	#
	# we try to re-master the logical host back to its
	# original node where it was being mastered before.
	# If this fails, clean up and exit.
	#

	if [[ ${m_mode} -eq 0  && -n "${curr_master}" ]]; then

     	    ${B}/scccd ${clustname} LOGHOST_CM add "lname:curr_master" \
		"${l}:${curr_master}"

       	    if [[ $? -ne 0 ]]; then
		lmsg="`gettext \
'Unable to re-master the logical host %s on %s\n\
Logical host %s will not be mastered anywhere'`"
		printf "${lmsg}\n" "${l}" "${curr_master}" "${l}"

      		${B}/scccd ${clustname} LOGHOST_CM remove lname ${l}

		if [[ $? -ne 0 ]]; then
		  release_switchover_lock
		  ${B}/clustm abort ${clustname} ${curr_nodeid}
		  cleanup_and_exit
		fi
	    else
		lmsg=`gettext \
		    "Logical host %s has been re-mastered on ${curr_master}."`
		printf "${lmsg}\n" "${l}"
	    fi
	fi
      fi
    fi
  fi
done

#
# Release lock so other switchover attempts can proceed.
#
release_switchover_lock

if [[ ${something_went_wrong} -eq 1 ]]; then
	return 1
fi

return 0
}


set_loghost_mstate()
{
    typeset logname value

    logname=$1
    value=$2

    check_mstate_format

    mstate=$(${B}/scccd ${clustname} LOGHOST_MSTATE query lname ${logname})
    if (( $? == 0 )); then
    	mode=${mstate#*:*:}
    	if [[ -n ${mode} && ${mode} != ${value} ]]; then

        	${B}/scccd ${clustname} LOGHOST_MSTATE remove lname ${logname}

        	${B}/scccd ${clustname} LOGHOST_MSTATE add "lname:mmode" "${logname}:${value}"

        	if [[ $? -ne 0 ]]; then
		  lmsg="`gettext \
'Unable to set the state of logical host to %s\n\
Check system console logs for detailed error messages.'`"
		  printf "${lmsg}\n" "${value}"
        	fi
    	fi
    else
	lmsg="`gettext \
'Unable to get the current state for logical host %s.\n\
Check system logs for detailed error messages.'`"
	printf "${lmsg}\n" "${logname}"
    fi
}


rm_SDS_temp_files ()
{
	# Remove files created by loghostreconfig/loghost_sync that
	# indicate release of DiskSuite diskset failed.

	/bin/rm -f ${V}/release_failed*
	/bin/rm -f ${V}/readonly*
}


cleanup_and_exit ()
{
	rm_SDS_temp_files
	exit 1
}


#
# Print message that errors were encountered and exit 1.
# The only argument to this function is the name of the program.
#
errors_encountered_exit ()
{
	lmsg=`gettext "%s: errors encountered."`
	printf "${lmsg}\n" "$1"
	rm_SDS_temp_files
	exit 1
}


#
# Internationalized ckyorn 
# It returns the valid answer received, either "yes" or "no".
# Default is "no" - exit if user hits <CR>
#
function yorn 
{
	typeset question="$*"
	typeset reply=""

	while true; do
		printf "${question}" 1>&2
		read reply
		case $reply in
			"")
			     reply=$no
			     break
			     ;;
 
			$yes)
			     break
			     ;;
 
			$short_yes)
			     break
			     ;;
 
			$cap_yes)
			     break
			     ;;
 
			$cap_short_yes)
			     break
			     ;;
 
			$no)
			     break
			     ;;
 
			$short_no)
			     break
			     ;;
 
			$cap_no)
			     break
			     ;;
 
			$cap_short_no)
			     break
			     ;;

			*)
			     printf "${wrong}\n" 1>&2
			     ;;
		esac
	done

	print "${reply}"
}

SDS_err_cleanup()
{
  if [[ -f ${V}/readonly ]]; then
    # SDS case
    lmsg="`gettext \
'Switchover of some logical host(s) failed because \n\
some diskset(s) were taken read-only.'`"
    printf "\n${lmsg}\n"
  fi
  if [[ -f ${V}/release_failed ]]; then
    # SDS case
    lmsg="`gettext \
'Switchover of some logical host(s) failed because \n\
release of some diskset(s) failed.'`"
    printf "\n${lmsg}\n"
  fi
  cleanup_and_exit
}


#
# Creating secured directory for cluster temporary files, if
# it is not already created.  If the directory already exists,
# checks for owner and permissions of that directory.
# Change ccd.database file(s) permissions to 0600, if they are
# not already changed
#
function check_security_permissions
{
	if [ ! -d ${V}/run ]; then
		/bin/mkdir -p -m 700 ${V}/run
	else
		/bin/chown -f root ${V}/run
		/bin/chmod -f 0700 ${V}/run
	fi

	[ -f ${E}/conf/ccd.database.init ] && \
	    /bin/chmod -f 0600 ${E}/conf/ccd.database.init

	[ -f ${E}/conf/ccd.database ] && \
	    /bin/chmod -f 0600 ${E}/conf/ccd.database

	[ -f ${E}/conf/ccd.database.shared ] && \
	    /bin/chmod -f 0600 ${E}/conf/ccd.database.shared

	[ -f ${E}/conf/ccd.database.shadow ] && \
	    /bin/chmod -f 0600 ${E}/conf/ccd.database.shadow

	[ -f ${E}/conf/ccd.database.orig ] && \
	    /bin/chmod -f 0600 ${E}/conf/ccd.database.orig
}



#
# main program
#
# get program options
set -- `getopt af $*`
if [ $? != 0 ]
then
        usage_exit
fi
for i in  $*
do
        case $i in
        -a) async="-a"; shift ;;
        -f) forcestart="-f"; shift ;;
        --) shift; break;;
        esac
done

if [ $# -lt 1 ]; then
 lmsg=`gettext "Missing required parameter"`
 printf "${lmsg}\n"
 usage_exit
fi

cmd=$1
if [  ${cmd} != "startnode" -a ${cmd} != "stopnode" -a ${cmd} != "reldisks" -a\
      ${cmd} != "startcluster" -a ${cmd} != "continuepartition" -a \
      ${cmd} != "abortpartition" -a ${cmd} != "resdisks" -a\
      ${cmd} != "reserve" -a\
      ${cmd} != "switch" ]
then
	lmsg=`gettext "invalid command: %s"`
	printf "${lmsg}\n" "${cmd}"
	usage_exit
fi

nodename=""
if [ ${cmd} = "continuepartition" -o ${cmd} = "abortpartition" -o\
		${cmd} = "startcluster" ]; then
	nodename="$2"
	clustname="$3"
	if [ -z "${nodename}" -o -z "${clustname}" ]; then
		usage_exit
	else
		lmsg=`gettext "Node specified is %s"`
		printf "${lmsg}\n" "${nodename}"
		lmsg=`gettext "Cluster specified is %s"`
		printf "${lmsg}\n" "${clustname}"
	fi
else
	if [[ ${cmd} != "reserve" ]]; then
		clustname=$2
	else
		device=$2
	fi
fi

if [ -z "${clustname}" ]; then
	if [ -f ${E}/conf/default_clustername ]; then
		clustname=`cat ${E}/conf/default_clustername`
		lmsg=`gettext "Assuming a default cluster name of %s"`
		printf "${lmsg}\n" "${clustname}"
	else
		usage_exit
	fi
fi

cdbfile=${E}/conf/${clustname}.cdb

if [ ! -f $cdbfile ]; then
	lmsg=`gettext "Error: Invalid cluster name: %s"`
	printf "${lmsg}\n" "$clustname"
	lmsg=`gettext "       The file \"%s\" was not found"`
	printf "${lmsg}\n" "$cdbfile"
	usage_exit
fi

if [ ${cmd} = "startcluster" -o ${cmd} = "startnode" ]; then
	check_security_permissions
fi

# set variables related to node ids
get_nodeids
mynode=`eval enmatch cluster.node.${myid}.hostname`

# check if nodename is the name of my node
if [ -n "${nodename}" ]; then
# return status from nodename_in_cluster really does not
# have to be checked since if nodename is not defined to be
# a cluster member we will not return.
        nodename_in_cluster $nodename
 	if [ "${nodename}" != "${mynode}" ]; then
		lmsg="`gettext \
'Error: Attempted to start node %s.\n\
       This is node %s.\n\
       Cannot start a cluster from a remote node.'`"
		printf "${lmsg}\n" "${nodename}" "${mynode}"
		exit 2
	fi
fi


# -f option is legal only with the 'startnode' command
if [ "${forcestart}" = -f -a ${cmd} != "startnode" -a ${cmd} != "startcluster" ] ; then
	lmsg="`gettext \
'Error: The -f option is only legal when used with the 'startcluster'\n\
or 'startnode' subcommand'`"
	printf "${lmsg}\n"
	usage_exit
fi

quest=`gettext "Do you want to continue?  [yes or no] "`

# warn operator about the consequences of the -f option
if [ "${forcestart}" = -f ] ; then

	lmsg="`gettext \
'=========================== WARNING =================================\n\
=      Multiple failures have been detected in this cluster         =\n\
=====================================================================\n\n\
You are attempting to start up the cluster node %s using\n\
the -f option.  The -f option allows %s to come online when\n\
other node(s) and the quorum devices shared with them are not reachable.\n\
This action could corrupt the database and/or otherwise compromise\n\
cluster integrity if used incorrectly.  Please read the following\n\
instructions carefully.\n\n\
Before you proceed, you must verify that:\n\
	(1) the other node(s) are offline (i.e. halted)\n\
	(2) the quorum device(s) is offline (i.e. power is off)\n\n\
Note that you *must* bring the node %s offline before\n\
restarting the quorum device(s) or any of the other nodes.\n\
This can be done by executing the command\n\n\
	/opt/SUNWcluster/bin/scadmin stopnode %s\n\n\
Please enter \"yes\" only after you have verified (1) and (2).'`"
	printf \
	    "${lmsg}\n\n" "${mynode}" "${mynode}" "${mynode}" "${clustname}"

	# exits if response is 'no'
	resp=$(yorn "$quest")
	if [[ "$resp" = "$no" ]] || [[ "$resp" = "$short_no" ]] ||
	[[ "$resp" = "$cap_no" ]] || [[ "$resp" = "$cap_short_no" ]]; then
		lmsg=`gettext "exiting ..."`
		printf "${lmsg}\n" >&2
		exit 0
	fi
fi

# warn operator about the consequences of the startcluster command  
if [ "${cmd}" = "startcluster" ] ; then

	lmsg="`gettext \
'=========================== WARNING =================================\n\
=                     Creating a new cluster                        =\n\
=====================================================================\n\
You are attempting to start up the cluster node %s as the\n\
only node in a new cluster.  It is important that no other cluster\n\
nodes be active at this time.  If this node hears from other cluster\n\
nodes, this node will abort.  Other nodes may join only after this\n\
command has completed successfully.  Data corruption may occur if\n\
more than one cluster is active.'`"
	printf "${lmsg}\n\n" "${mynode}"

	# exits if response is 'no'
	resp=$(yorn "$quest")
	if [[ "$resp" = "$no" ]] || [[ "$resp" = "$short_no" ]] ||
	[[ "$resp" = "$cap_no" ]] || [[ "$resp" = "$cap_short_no" ]]; then
		lmsg=`gettext "exiting ..."`
		printf "${lmsg}\n" >&2
		exit 0
	fi
fi

# change current working directory to /opt/SUNWcluster/bin to avoid
# all kinds of problems with the 'rm(1)' command when filesystems
# disappear from underneath it or root does not have privileges to
# open the current working directory.

cd /opt/SUNWcluster/bin

# Cluster Application Bit Assignment for cluster.pdbapps vector in cdb file.
CVM=3 
VxVM=4 
SDS=5

# Bit 5 in pdbapps vector designates DiskSuite as configured volume manager
pdbapps=$(enmatch cluster.pdbapps)
if [ $? -ne 0 ]; then
	exit 1
fi
vm=$(${B}/appmatch ${pdbapps} ${SDS})
if [[ "${vm}" = "1" ]]; then
	not_meaningful=`gettext \
	    "The %s command is not meaningful in DiskSuite configurations."`
	vm=sds
	# Before starting, remove old temp files
	rm_SDS_temp_files
else
	# don't care
	vm=xxx
fi

# dispatch into reconf_ener

case ${cmd} in
	startnode)
		/bin/rm -f ${V}/${clustname}/startcluster

		${B}/reconf_ener ${forcestart} ${async} ${cmd} ${clustname}
		if [[ $? -ne 0 ]]; then
			if [[ -f ${V}/readonly ]]; then
				# SDS case
				lmsg=`gettext \
				    "Some diskset(s) were taken read-only."`
				printf "${lmsg}\n"
			fi
			errors_encountered_exit $prog
		fi
		;;
	startcluster)
		${B}/reconf_ener ${forcestart} ${async} -n startnode \
		    ${clustname}
		if [[ $? -ne 0 ]]; then
			if [[ -f ${V}/readonly ]]; then
				# SDS case
				lmsg=`gettext \
				    "Some diskset(s) were taken read-only."`
				printf "${lmsg}\n"
			fi
			errors_encountered_exit $prog
		fi
		;;
	stopnode)
		/bin/rm -f ${V}/${clustname}/startcluster
		${B}/reconf_ener ${forcestart} ${async} ${cmd} ${clustname}
		if [[ $? -ne 0 ]]; then
			if [[ -f ${V}/release_failed ]]; then
				# SDS case
				lmsg=`gettext \
		"Aborting node because diskset release failed during stopnode."`
				printf "${lmsg}\n"
				rm_SDS_temp_files
				# wait for clustd to finish
				while true; do
					clustm getstate ${clustname} \
					    > /dev/null 2>&1
					if [ $? -ne 0 ]; then
						break
					fi
					# Sleep because the abort
					# transition takes a while to complete.
					sleep 10
				done
				/sbin/uadmin 1 1
			else
				rm_SDS_temp_files
				errors_encountered_exit $prog
			fi
		fi
		rm_SDS_temp_files
		;;
	continuepartition)
		lmsg=`gettext \
		    "*** Node %s will continue participating in cluster %s"`
		printf "${lmsg}\n" "${mynode}" "${clustname}"
		${B}/clustm continuepartition ${clustname}
		if [ $? -ne 0 ]; then
			errors_encountered_exit $prog
		fi
		;;
	abortpartition)
		lmsg=`gettext \
		    "*** Node %s will abort from cluster %s"`
		printf "${lmsg}\n" "${mynode}" "${clustname}"
		${B}/clustm abortpartition ${clustname}
		if [ $? -ne 0 ]; then
			errors_encountered_exit $prog
		fi
		;;
	resdisks | reldisks)
		if [[ "$vm" = "sds" ]]; then
			printf "${not_meaningful}\n" "${cmd}"
			exit 0
		fi
		${B}/reconf_ener ${cmd} ${clustname}
		if [ $? -ne 0 ]; then
			errors_encountered_exit $prog
		fi
		;;
	reserve)
		if [[ "$vm" != "sds" ]]; then
			printf "${not_meaningful}\n" "${cmd}"
			exit 0
		fi
		if [[ -z "${device}" ]]; then
			lmsg=`gettext \
			    "%s: reserve command requires device name (cXtYdZ)"`
			printf "${lmsg}\n" "$prog"
			usage_exit
		fi
		${B}/scssa reserve ${device}s7
		if [[ $? -ne 0 ]]; then
			lmsg=`gettext "reserve of ${device} failed"`
			printf "${lmsg}\n" "${device}"
			exit 1
		fi
		${B}/scssa enfailfast ${device}s7
		if [[ $? -ne 0 ]]; then
			lmsg=`gettext "enfailfast of %s failed"`
			printf "${lmsg}\n" "${device}"
			exit 1
		fi
		;;
	switch)
		if (( $# < 2 )); then
			lmsg=`gettext "%s: Required parameters missing."`
			printf "${lmsg}\n" "$prog"
			usage_exit
		else
			shift 2
			set -m
			( switchover_cmd $* || \
			  (SDS_err_cleanup;) || exit 1)&
		fi
		;;
	*)
		usage_exit
		;;
esac

# Before exiting, remove temp files
rm_SDS_temp_files

exit 0
