#!/bin/ksh
# DO NOT EDIT THIS FILE
#pragma ident       "@(#)init.ksh 1.36     01/05/24 SMI"

#
# Copyright (c) 1994,1999 by Sun Microsystems, Inc.
# All rights reserved.
#

# Create secure dir to write temporary files
mktmpdirs() {
	SCTMPDIR=/tmp/.scinstall.$$
	SCSAVEDIR=/var/tmp/.scinstall.$$
	trap 'rm -rf ${SCTMPDIR} ${SCSAVEDIR}' 0 1 2 3 15
	/usr/bin/rm -rf ${SCTMPDIR} ${SCSAVEDIR}
	/usr/bin/mkdir -m 700 ${SCTMPDIR} ${SCSAVEDIR}
	if [ $? -ne 0 ]; then
		echo "${0}: couldn't create temp. file directories"
		exit 1
	fi
}
mktmpdirs

############################################################################
# Global Variables
#

# Set the PATH
# jhc - 4/22/98
typeset CWD=`/usr/bin/pwd`
typeset SCBINDIR="/opt/SUNWcluster/bin"
typeset PNMBINDIR="/opt/SUNWpnm/bin"
PATH=${SCBINDIR}:${PNMBINDIR}:${CWD}:/bin:/usr/bin:/sbin:/usr/sbin:${PATH}

# Global internationalized constant strings
typeset YES=$(gettext 'yes')		# I18N "yes"		jhc - 4/22/98
typeset NO=$(gettext 'no')		# I18N "no"		jhc - 4/22/98

# Global constants used by logical hosts subroutines
typeset PKG_SCCF="SUNWsccf"		# sccf package		jhc - 4/22/98
typeset SCCONF="scconf"			# scconf command	jhc - 4/22/98
typeset CDBMATCH="cdbmatch"		# cdbmatch command	jhc - 4/22/98
typeset SCCCD="scccd"			# scccd command		jhc - 4/22/98
typeset PNMSET="pnmset"			# pnmset command	jhc - 4/22/98
typeset PNMCONFIG="/etc/pnmconfig"	# pnm config file	jhc - 4/22/98
typeset HACCDFILE="ccd.database"	# ccd database file	jhc - 4/22/98
typeset HACCDLOGHOST="LOGHOST"		# ccd key		jhc - 4/22/98
typeset HACCDLOGHOST_MSTATE="LOGHOST_MSTATE" # ccd key		jhc - 4/22/98
typeset HACCDLOGIP="LOGIP"		# ccd key		jhc - 4/22/98
typeset HACCDDS="DS_INFO"		# ccd key		jhc - 4/22/98
typeset HACCDPNM="PNM"			# ccd key		jhc - 4/22/98

# Global variables used by logical hosts subroutintes
typeset SUBNETS				# global subnets list	jhc - 4/22/98
set -A SUBNETS ""				
integer LOGIFNUM=1			# current logical "if"	jhc - 4/22/98

# Global constants used by upgrade subroutines
typeset BASEDIR=$(pkgparam SUNWsci BASEDIR 2>/dev/null)
typeset PRODUCTDIR=$(pkgparam SUNWsci PRODUCTDIR 2>/dev/null)
if [[ -z ${BASEDIR} ]]; then
	BASEDIR="/"
fi
if [[ -z ${PRODUCTDIR} ]]; then
	PRODUCTDIR="SUNWsci"
fi
typeset SCIDIR="/opt/${PRODUCTDIR}"
typeset SAVEDIR="${SCSAVEDIR}/sc2.x_config"
typeset TC_SSP_DATA="${SCSAVEDIR}/tc_ssp_data"
typeset SCIADM="${SCIDIR}/bin/sciadm"
typeset UPGRD_CCDINITFILE="ccd.database.init"	# used for querying
integer VERBOSE=0				# for debugging: 1-on, 0-off
typeset serverUpgradeList
set -A serverUpgradeList "SUNWmond SUNWff SUNWcmm SUNWscman SUNWsc SUNWpnm"
set -A HAOracleList "SUNWscor"
set -A HAInformixList "SUNWscinf"
set -A HASybaseList "SUNWscsyb"
set -A InternetProList \
	    "SUNWscpro SUNWschtt SUNWscnew SUNWscnsm SUNWscdns"
typeset HADFCONFIGDIR="/etc/opt/SUNWhadf"
typeset HADFCONFIGFILE="hadf/hadfconfig"

# Global variables used by upgrade subroutines
typeset LOADEDPKGS=""
set -A TC_SSP_IP ""
set -A TC_SSP_AK ""
set -A TC_SSP_ARCH ""
set -A TC_SSP_PORT ""
set -A TC_PORT_NUM ""
set -A TC_PORT_IP ""T
typeset TC_Counter="None"
typeset SSP_Counter="None"
integer TC_SSP_Counter=0

typeset echoNOption	#formerly N
typeset echoCOption	#formerly C

typeset ANSWER		#The return value of the last call of MyRead
typeset ARG=""		#argument list
typeset CDIMAGEPATH=${CDIMAGEPATH:="/cdrom/cdrom0"}	#path to the CD image
integer CDPATHSET=${CDPATHSET:=0}	#1 if path set in scbootstrap,
					#otherwise 0
typeset MEDIA=${MEDIA:=""}		#full path to software packages
typeset OSVERSION="$(uname -r)"
typeset CDOSNAME
if [[ "${OSVERSION}" == "5.6" ]]; then
	CDOSNAME="Sol_2.6"
elif [[ "${OSVERSION}" == "5.7" ]]; then
	CDOSNAME="Sol_2.7"
elif [[ "${OSVERSION}" == "5.8" ]]; then
	CDOSNAME="Sol_2.8"
fi
typeset CDPRODUCTNAME="Sun_Cluster_2_2"
typeset INTERACTIVE="yes"	#Interactive mode?
integer MYUID=`id|sed -e "s/uid=\([0-9][0-9]*\)..*/\1/"`
if pkginfo -q SUNWscins > /dev/null 2>&1
then
	typeset VERSION=$(pkgparam SUNWscins VERSION | cut -d, -f1)
else
	typeset VERSION="2.2"
fi

integer PDBAPPS=0
typeset CLUSTERNAME=""
typeset RUNNING="no"	#Is the cluster currently running?
integer NUMOFNODES=0
integer NUMNODEACTIVE=0
integer ACTIVECOUNT=0
integer NACTIVENODES=0
typeset CCDDEVICE="none"
typeset NETIFTYPE=""
typeset DIFN="scid0"
typeset DIFM="scid1"
typeset POUND="#"
set -A  PHYS ""
integer PHYSCNTR=1
integer LOOPCNTR=0
set -A  INFACE ""
typeset FOO
integer MINQUORUM
set -A  NODENAMES ""
integer DIRECTC=0
integer TC_SSP_Counter
set -A TC_SSP_IP ""
set -A TC_SSP_AK ""
set -A TC_SSP_ARCH ""
set -A TC_SSP_PORT ""
set -A TC_PORT_NUM ""
set -A TC_PORT_IP ""
set -A TC_SSP_Name ""
set -A TC_SSP_Type ""
typeset TC_SSP_NODELOCK
typeset TC_Counter
typeset SSP_Counter
integer SBOPT=0

typeset RHOSTS="/.rhosts"
typeset RHOSTS_TMP="${RHOSTS}.scinstall"
integer CREATERHOSTS=0
typeset LOCALHOSTNAME=`uname -n`
typeset LOCALNODEID=""
typeset PKGINFO="/usr/bin/pkginfo"
typeset BINDIR="/opt/SUNWcluster/bin"
typeset ETCDIR="/etc/opt/SUNWcluster"
typeset VARDIR="/var/opt/SUNWcluster"
typeset FINDDEVICES="/opt/SUNWcluster/bin/finddevices"
typeset PLUTOPATH="/var/tmp/_pluto_path.$$"
typeset CCDTMP="/var/tmp/_ccd.$$"
typeset CCDINSTALL="/opt/SUNWcluster/bin/ccdinstall"
typeset CCDCTL="/opt/SUNWcluster/bin/ccdctl"
typeset CCDADM="/opt/SUNWcluster/bin/ccdadm"
typeset SSAADM="/usr/sbin/ssaadm"
typeset ECSSSA="/opt/SUNWcluster/bin/scssa"

typeset CDG0=""
typeset CDG1=""
typeset CDG2=""
typeset CDG3=""
typeset VM=""
typeset UDLM=""
typeset CDBTEMPLATE="TEMPLATE.cdb"
typeset CDBFILE=""
typeset CCDINITTEMPLATE="ccd.TEMPLATE.init"
typeset CCDINITFILE="ccd.database.init"
typeset CONFIGDIR="/etc/opt/SUNWcluster/conf"
typeset LOGFILE="/var/opt/SUNWcluster/scadmin.log"

typeset RUNDIR=/var/opt/SUNWcluster/${CLUSTERNAME}
typeset SYSSCRIPTDIR=/var/opt/SUNWcluster/system.scripts

typeset ADMINFILE=""
typeset assaRespFileArg=""
# Temp response file for SUNWassa
typeset assaRespFile="${SCTMPDIR}/scinstall.assa.$$"
# Temp admin file for this installation
typeset tmpadmin="${SCTMPDIR}/scinstall.admin.$$"


#Global variables that will contain the packages that belong to a package set
set -A installList ""
set -A serverList ""
set -A clientList ""
set -A SDSshortList ""
set -A OPSList ""
set -A SCIList ""
set -A SMAList ""
set -A SCDSList ""
set -A OBSOLETE ""

set -A server27List ""
set -A SDSshort27List ""
set -A OPS27List ""
set -A SCI27List ""
set -A SMA27List ""

set -A installListI ""
set -A installListU ""
set -A serverListI ""
set -A serverListU ""
set -A clientListI ""
set -A clientListU ""
set -A SDSshortListI ""
set -A SDSshortListU ""
set -A OPSListI ""
set -A OPSListU ""
set -A SCIListI ""
set -A SCIListU ""
set -A SMAListI ""
set -A SMAListU ""
set -A SCDSListI ""
set -A SCDSListU ""
set -A OBSOLETEI ""
set -A OBSOLETEU ""

typeset DSFILE="${CONFIGDIR}/dataservices"
set -A DSNAMES ""
set -A DSPACKAGES ""
set -A DSINSTALLED ""
set -A DSUNINSTALLED ""
integer DSCOUNTER=0
integer DSINSTCOUNT=0
integer DSUNINSTCOUNT=0
integer NEEDCVM=0

set -A selectApps ""

# dup stdin/stdout - see comments for prompt_yesno()		jhc - 4/22/98
exec 3<&0
exec 4>&1

#################################################
# Initialization Routines

#Get the data services available
#    Reads in the list of supported data services from DSFILE
SetDataServices() {

	set -A DSLines ""
	typeset tmpFile="${SCTMPDIR}/DStmpfile.$$"
	integer tmpCounter

	let DSCOUNTER=1
	if [ ! -r ${DSFILE} ]; then
		return
	fi
	grep -v "^#" ${DSFILE} > ${tmpFile}
	while read DSLines[${DSCOUNTER}]; do
		if [ -n "${DSLines[${DSCOUNTER}]}" ]; then
			((DSCOUNTER += 1))
		fi
	done < ${tmpFile}
	let tmpCounter=1
	while [ ${tmpCounter} -lt ${DSCOUNTER} ]; do
		DSNAMES[${tmpCounter}]=`echo "${DSLines[${tmpCounter}]}" | \
			sed -e "s/:.*//"`
		DSPACKAGES[${tmpCounter}]=`echo "${DSLines[${tmpCounter}]}" | \
			sed -e "s/.*://"`
		((tmpCounter += 1))
	done
	/usr/bin/rm ${tmpFile}
#let tmpCounter=1
#while [ ${tmpCounter} -lt ${DSCOUNTER} ]; do
#	echo "${DSNAMES[${tmpCounter}]}  ${DSPACKAGES[${tmpCounter}]}"
#	((tmpCounter += 1))
#done
#Pause
}

#Initialize
Initialize() {

	GetClusterName
	GetPDBAPPS
	if [ -n "${ADMINFILE}" ]; then
		ARG="-n -a ${ADMINFILE}"
	else
		ADMINFILE=${tmpadmin}
		cat <<!EOF >${tmpadmin}
mail=
instance=overwrite
partial=nocheck
runlevel=nocheck
idepend=quit
rdepend=nocheck
space=nocheck
setuid=nocheck
conflict=nocheck
action=nocheck
basedir=default
!EOF
	fi

	cat <<!EOF >${assaRespFile}
CLASSES=none
ABHOME=/opt/SUNWasevm
ABTOP=/opt
INSTALL_CASE=nil
!EOF

}
#######################################################
####    dialogs      ##################################
#######################################################

#pragma ident "@(#)dialogs.ksh	1.17 99/01/27 SMI"

helpUSAGE="Usage: \
scinstall [-[a|c|s] -[i|u]] [-d pkg_directory] [-o] [-l] [-V]
	[-A Admin file] [-h]

-a Client and Server packages
-c Client packages
-s Server packages

-i Install client or server packages from -acs option
-u Remove client or server packages from -acs option

-d Location of Sun Cluster package sets

-o Remove obsolete Sun Cluster packages

-l List the installed Client and Server packages

-V Verify the installation

-A The admin file to use during installation

-h This usage message
"
verifyHeader="

==== Verify Package Installation ==========================

"

badUserID="
You must be logged on as root to modify the packages on this system.  
Install/Remove actions are disabled for non-root users.
"

helpInstallFramework="
==== Install/Upgrade Software Selection Menu =======================
Upgrade to the latest Sun Cluster Server packages or select package
sets for installation. The list of package sets depends on the Sun
Cluster packages that are currently installed.
"

helpRemoveFramework="
==== Remove Software Selection Menu ==========================
The Sun Cluster packages can be selected in sets, depending on
the current state of installation.
"

removeModeHelp="
            >>>> Warning <<<<
  The removal process will run several scripts as root.  
  If you choose automatic mode, the removal of the chosen packages 
  will proceed without any user interaction.  If you wish to manually 
  control the remove process you must choose the manual removal option.

Choices:
   manual     Interactively remove each package
   automatic  Remove the selected packages with no user interaction.

In addition, the following commands are supported:
   list       Show a list of the packages to be removed
   help       Show this command summary
   close      Return to previous menu
   quit       Quit the program
"

installModeHelp="
            >>>> Warning <<<<
  The installation process will run several scripts as root.  In
  addition, it may install setUID programs.  If you choose automatic
  mode, the installation of the chosen packages will proceed without
  any user interaction.  If you wish to manually control the install
  process you must choose the manual installation option.

Choices:
   manual     Interactively install each package
   automatic  Install the selected packages with no user interaction.

In addition, the following commands are supported:
   list       Show a list of the packages to be installed
   help       Show this command summary
   close      Return to previous menu
   quit       Quit the program
"

installHelp="
Answer Yes   to install the package.
Answer No    to skip to the next package.
Answer List  to see a description of the package.
Answer Help  to see this table.
Answer Close to return to the Main Menu.
Answer Quit  to exit the program."

removeHelp="
Answer Yes   to remove the package.
Answer No    to skip to the next package.
Answer List  to see a description of the package.
Answer Help  to see this table.
Answer Close to return to the Main Menu.
Answer Quit  to exit the program."

needFrameworkError="
Installation Error:
The Installation cannot continue until either the Client or Server package
set has been chosen for installation.
"

frameworkInstallError="
Installation Error:
There was an error while installing the Framework packages.  The Installation 
cannot continue until either the Client or Server package set has been 
installed.
Please correct the problem and begin installation again.
"

volumeManagerInstallError="
An error has occurred during the installation of the Volume Manager.
If a Volume Manager is not installed, the cluster may not perform 
as expected."

selectAppHeader="

==== Select Data Services Menu ==========================
"

dataServiceRemoveError="
An error has occurred during the removal of Data Service packages.
You will have to resolve the problem before the Data Service can
be removed."

dataServiceInstallError="
An error has occurred during the installation of Data Service packages.
You will have to resolve the installation problem and reinstall the Data
Service before it will be available."

mainMenuBanner="
============ Main Menu =================
"

changeMenuBanner="
=========== Changes Menu ================

Choices from this menu:
"


changeMenuHelp="
=========== Change Menu Help ============

This menu appears only after the Server packages have been successfully 
installed on the system.

The possible change choices are:

Node Information - Change the information about the nodes in this cluster.
Data Services    - Install or remove Data Service packages from the system.
Volume Manager   - Change which volume manager will be used on this system.
Quorum Device    - Select a device for quorum.
Logical Host     - Change the logical host.
NAFO             - Change the NAFO information.

Close   - Close this menu to return to the Main Menu.
Quit    - Exit this program.
Help    - This screen.
"

mainMenuHelp="
This menu appears only after either the Client or Server packages have been 
successfully installed on the system.

The choices presented will depend upon what has been installed on the system.
Your menu choices will change depending upon what package sets are installed.

The possible choices are:

Upgrade - Upgrade existing software to the latest version.
Install - Either the Server or Client have not been installed.
Remove  - The user may remove the Client, Server or Obsolete package sets 
          if any are installed.
Change  - Data Services can be added or removed if the Server packages
          have been installed.
Verify  - View the status of installed package sets.
List    - List the packages of a package set and their installation state.
Help    - This screen.
Quit    - Exit this program.
"

warningSDS="
     ---------WARNING---------
Solstice DiskSuite (SDS) will need to be installed before the
cluster can be started.
"

warningSEVM="
     ---------WARNING---------
The Sun StorEdge Volume Manager (SSVM) will need to be
installed before the cluster can be started.
"

warningCVM="
     ---------WARNING---------
The Cluster Volume Manager (CVM) will need to be installed
before Oracle Parallel Database (OPS) can be started.
"

warningOPS="
     ---------WARNING---------
You will be installing Oracle Parallel Database (OPS) on a
cluster that does not have the Cluster Volume Manager (CVM)
installed. CVM has to be installed for correct operation
of OPS.
"
#pragma ident "@(#)editfiles.ksh 1.17   01/03/28 SMI"

#######################################################
####    file editing functions      ###################
#######################################################

############################################################################
# File Writing
#


#Save the PDBAPPS variable in the CDBfile
SavePDBAPPS() {

	#
	# When this is first executed during initial configuration,
	# CDBFILE doesn't exist. Subsequent executions of this function
	# will work all right
	#
	if [ -n "${CDBFILE}" -a -s ${CONFIGDIR}/${CDBFILE} ]; then
		mv ${CONFIGDIR}/${CDBFILE} ${SCTMPDIR}/${CDBFILE}.o
		sed -e "/^cluster.pdbapps/s|:.*|: ${PDBAPPS}|" \
		    -e "/^cmm.minquorum/s|:.*|: ${MINQUORUM}|" \
		    ${SCTMPDIR}/${CDBFILE}.o >> ${CONFIGDIR}/${CDBFILE}
		rm -f ${SCTMPDIR}/${CDBFILE}.o
	fi
}

# Save the Clustername and create a CDB file for it, if needed
SaveClusterName() {

	typeset oldName

	RUNDIR="/var/opt/SUNWcluster/${CLUSTERNAME}"
	echo "${CLUSTERNAME}" > ${CONFIGDIR}/default_clustername
	CDBFILE="${CLUSTERNAME}.cdb"
	if [ ! -f ${CONFIGDIR}/${CDBFILE} ]; then
		#Create new CDBFILE with PDBAPPS vector
		cat ${CONFIGDIR}/${CDBTEMPLATE} \
		    | sed -e "/^cluster.pdbapps/s|:.*|: ${PDBAPPS}|" \
		    > ${CONFIGDIR}/${CDBFILE}
	fi

	oldName=`grep "^cluster.cluster_name" ${CONFIGDIR}/${CDBFILE} | sed -e "s/.*: //"`
	mv ${CONFIGDIR}/${CDBFILE} ${SCTMPDIR}/${CLUSTERNAME}.o
	sed -e "s|${oldName}|${CLUSTERNAME}|" \
		${SCTMPDIR}/${CLUSTERNAME}.o > ${CONFIGDIR}/${CDBFILE} 
	rm -f ${SCTMPDIR}/${CLUSTERNAME}.o

	# If the CCD init template has not yet been appended, do it now
	ccdmatch ccd.clustname ${CONFIGDIR}/${CCDINITFILE} >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		${CCDINSTALL} -i add ${CONFIGDIR}/${CCDINITTEMPLATE}
		if [ $? != 0 ]; then
			echo "Error: ${CCDINITFILE} could not be updated."
			exit 1
		fi
	fi

	# Add the new clustername to the CCD init database
	${CCDADM} -p ${CONFIGDIR}/${CCDINITFILE} >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "${CONFIGDIR}/${CCDINITFILE} is corrupted"
		exit 1;
	fi
	sed -e "/^ccd.clustname:/s|:.*|:${CLUSTERNAME}|" \
	    /${CONFIGDIR}/${CCDINITFILE}.pure > ${SCTMPDIR}/${CCDINITFILE}.o 
	${CCDADM} -x ${SCTMPDIR}/${CCDINITFILE}.o
	mv ${SCTMPDIR}/${CCDINITFILE}.o /${CONFIGDIR}/${CCDINITFILE}
	rm /${CONFIGDIR}/${CCDINITFILE}.pure
}

# Save the node info
SaveNodeInfo() {

	typeset tmpFile="${SCTMPDIR}/${CLUSTERNAME}.$$"
	typeset tmpDir
	integer tmpCount
	typeset tcmonCheck=""
	typeset check=""

	tmpDir=`pwd`

	mv ${CONFIGDIR}/${CDBFILE} ${tmpFile}
	/usr/bin/sed \
	-e "/^cluster.number.nodes/s|:.*|: ${NUMOFNODES}|" \
	-e "/^cluster.node.0.hostname/s|:.*|: ${NODENAMES[1]}|" \
	-e "/^cluster.node.1.hostname/s|:.*|: ${NODENAMES[2]}|" \
	-e "/^cluster.node.2.hostname/s|:.*|: ${NODENAMES[3]}|" \
	-e "/^cluster.node.3.hostname/s|:.*|: ${NODENAMES[4]}|" \
	-e "/^cluster.node.0.physaddr/s|:.*|: ${PHYS[1]}|" \
	-e "/^cluster.node.1.physaddr/s|:.*|: ${PHYS[2]}|" \
	-e "/^cluster.node.2.physaddr/s|:.*|: ${PHYS[3]}|" \
	-e "/^cluster.node.3.physaddr/s|:.*|: ${PHYS[4]}|" \
	-e "/^cluster.net_if_type/s|:.*|: ${NETIFTYPE}|" \
	-e "/^cluster.node.0.if.0/s|:.*|: ${INFACE[1]}|" \
	-e "/^cluster.node.0.if.1/s|:.*|: ${INFACE[2]}|" \
	-e "/^cluster.node.1.if.0/s|:.*|: ${INFACE[3]}|" \
	-e "/^cluster.node.1.if.1/s|:.*|: ${INFACE[4]}|" \
	-e "/^cluster.node.2.if.0/s|:.*|: ${INFACE[5]}|" \
	-e "/^cluster.node.2.if.1/s|:.*|: ${INFACE[6]}|" \
	-e "/^cluster.node.3.if.0/s|:.*|: ${INFACE[7]}|" \
	-e "/^cluster.node.3.if.1/s|:.*|: ${INFACE[8]}|" \
	-e "/^cluster.node.0.haiface.0/s|:.*|: ${INFACE[1]}:1|" \
	-e "/^cluster.node.0.haiface.1/s|:.*|: ${INFACE[2]}:1|" \
	-e "/^cluster.node.1.haiface.0/s|:.*|: ${INFACE[3]}:1|" \
	-e "/^cluster.node.1.haiface.1/s|:.*|: ${INFACE[4]}:1|" \
	-e "/^cluster.node.2.haiface.0/s|:.*|: ${INFACE[5]}:1|" \
	-e "/^cluster.node.2.haiface.1/s|:.*|: ${INFACE[6]}:1|" \
	-e "/^cluster.node.3.haiface.0/s|:.*|: ${INFACE[7]}:1|" \
	-e "/^cluster.node.3.haiface.1/s|:.*|: ${INFACE[8]}:1|" \
	-e "/^cluster.node.0.ifpath.0/s|:.*|: /dev/${INFACE[1]}|" \
	-e "/^cluster.node.0.ifpath.1/s|:.*|: /dev/${INFACE[2]}|" \
	-e "/^cluster.node.1.ifpath.0/s|:.*|: /dev/${INFACE[3]}|" \
	-e "/^cluster.node.1.ifpath.1/s|:.*|: /dev/${INFACE[4]}|" \
	-e "/^cluster.node.2.ifpath.0/s|:.*|: /dev/${INFACE[5]}|" \
	-e "/^cluster.node.2.ifpath.1/s|:.*|: /dev/${INFACE[6]}|" \
	-e "/^cluster.node.3.ifpath.0/s|:.*|: /dev/${INFACE[7]}|" \
	-e "/^cluster.node.3.ifpath.1/s|:.*|: /dev/${INFACE[8]}|" \
	-e "s%^\(ccm.net.[01].*\)%${POUND}\1%" \
	-e "s%^\(cluster.ccm.net.[01]\)%${POUND}\1%" \
	-e "/^cmm.sboptimization/s|:.*|: ${SBOPT}|" \
	-e "/^cluster.node.0.arch/s|:.*|: ${TC_SSP_ARCH[0]}|" \
	-e "/^cluster.node.1.arch/s|:.*|: ${TC_SSP_ARCH[1]}|" \
	-e "/^cluster.node.2.arch/s|:.*|: ${TC_SSP_ARCH[2]}|" \
	-e "/^cluster.node.3.arch/s|:.*|: ${TC_SSP_ARCH[3]}|" \
	-e "/^cluster.node.0.tc_ssp.port/s|:.*|: ${TC_SSP_PORT[0]}|" \
	-e "/^cluster.node.1.tc_ssp.port/s|:.*|: ${TC_SSP_PORT[1]}|" \
	-e "/^cluster.node.2.tc_ssp.port/s|:.*|: ${TC_SSP_PORT[2]}|" \
	-e "/^cluster.node.3.tc_ssp.port/s|:.*|: ${TC_SSP_PORT[3]}|" \
	-e "/^cluster.tc_ssp.0.ip/s|:.*|: ${TC_SSP_IP[0]}|" \
	-e "/^cluster.tc_ssp.1.ip/s|:.*|: ${TC_SSP_IP[1]}|" \
	-e "/^cluster.tc_ssp.2.ip/s|:.*|: ${TC_SSP_IP[2]}|" \
	-e "/^cluster.tc_ssp.3.ip/s|:.*|: ${TC_SSP_IP[3]}|" \
	-e "/^cluster.tc_ssp.lock/s|:.*|: ${TC_SSP_NODELOCK}|" \
	-e "/^cmm.directattacheddevice/s|:.*|: ${DIRECTC}|" \
	-e "/^cluster.tc_ssp.0.ak/s|:.*|: ${TC_SSP_AK[0]}|" \
	-e "/^cluster.tc_ssp.1.ak/s|:.*|: ${TC_SSP_AK[1]}|" \
	-e "/^cluster.tc_ssp.2.ak/s|:.*|: ${TC_SSP_AK[2]}|" \
	-e "/^cluster.tc_ssp.3.ak/s|:.*|: ${TC_SSP_AK[3]}|" \
	< ${tmpFile} > ${CONFIGDIR}/${CDBFILE}
	rm -f ${tmpFile}

	#Store Node info in the CCD
	set -A tmpName ""
	let tmpCount=1
	while [ ${tmpCount} -lt 5 ]; do
		if [ -n "${NODENAMES[${tmpCount}]}" ]; then
			tmpName[${tmpCount}]="${NODENAMES[${tmpCount}]}"
		else
			tmpName[${tmpCount}]="nohost"
		fi
		((tmpCount += 1))
	done

	# If the the CCD init template has not yet been appended, do it now
	ccdmatch ccd.clustname ${CONFIGDIR}/${CCDINITFILE} >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		${CCDINSTALL} -i add ${CONFIGDIR}/${CCDINITTEMPLATE}
		if [ $? -ne 0 ]; then
			echo "Error: ${CCDINITFILE} could not be updated."
			exit 1
		fi
	fi

	# Remove the checksum from the CCD init database
	${CCDADM} -p ${CONFIGDIR}/${CCDINITFILE} >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "${CONFIGDIR}/${CCDINITFILE} is corrupted"
		exit 1;
	fi

	# Removed from sed list :
	#-e "/^ccd.ccdfilename:/s|:.*|:${CONFIGDIR}|" \
	/usr/bin/sed \
	-e "/^ccd.ccddevice.ssa:/s|:.*|:${CCDDEVICE}|" \
	-e "/^ccd.nservers:/s|:.*|:${NUMNODEACTIVE}|" \
	-e "/^ccd.server.0.hname:/s|:.*|:${tmpName[1]}|" \
	-e "/^ccd.server.1.hname:/s|:.*|:${tmpName[2]}|" \
	-e "/^ccd.server.2.hname:/s|:.*|:${tmpName[3]}|" \
	-e "/^ccd.server.3.hname:/s|:.*|:${tmpName[4]}|" \
	-e "s|_configdir|${CONFIGDIR}|" \
	${CONFIGDIR}/${CCDINITFILE}.pure > ${SCTMPDIR}/${CCDINITFILE}.$$
	${CCDADM} -x ${SCTMPDIR}/${CCDINITFILE}.$$
	mv ${SCTMPDIR}/${CCDINITFILE}.$$ ${CONFIGDIR}/${CCDINITFILE}
	rm ${CONFIGDIR}/${CCDINITFILE}.pure

	#add HA info to ccd.database file
	if [ -f ${CONFIGDIR}/ha.ccd ]; then
		cd ${CONFIGDIR}
		${CCDINSTALL} add ha.ccd
		/bin/rm -f ha.ccd
		cd ${CWD}
	fi

	# add TC/SSP monitoring format to the ccd.database file
	tcmonCheck=$(grep "TCMON" ${CONFIGDIR}/${HACCDFILE})
	if [ -z "${tcmonCheck}" ]; then
		cat >> ${tmpFile} << EOF

#
# TC/SSP monitoring - Status information
#

TCMON_fmt:tc_ssp_ip:status
TCMON_idx:0
TCMON_sync:ccd_nofreeze

EOF
		${CCDINSTALL} add ${tmpFile}
		rm -f ${tmpFile}
	fi

	/usr/bin/sync
	cd ${tmpDir}
}


############################################################################
# Read from files
#

#Get the default cluster name
GetClusterName() {

	if [ -f ${CONFIGDIR}/default_clustername ]; then
		CLUSTERNAME=`cat ${CONFIGDIR}/default_clustername`
		CDBFILE="${CLUSTERNAME}.cdb"
		print "    Assuming a default cluster name of ${CLUSTERNAME}"
		# check if clustd is really running
		/opt/SUNWcluster/bin/timed_run -q 3 \
			${BINDIR}/clustm getstate ${CLUSTERNAME} >/dev/null 2>&1
		if [ $? -eq 0 ]; then
			echo "Note: Cluster ${CLUSTERNAME} is currently running."
			echo "      Install/Uninstall actions are disabled during"
			echo "      cluster operation."
			echo " "
			RUNNING="yes"
			Pause
		fi
	fi
}

#Read the value of PDBAPPS from out of the CDB file
GetPDBAPPS() {
	
	typeset tmpPDBAPPS
	typeset tmpMINQUORUM

	if [ -f ${CONFIGDIR}/${CLUSTERNAME}.cdb ]; then
		tmpPDBAPPS=`grep "^cluster.pdbapps" \
			${CONFIGDIR}/${CLUSTERNAME}.cdb | sed -e "s|.*: ||"`
		let PDBAPPS=${tmpPDBAPPS}
		tmpMINQUORUM=`grep "^cmm.minquorum" \
			${CONFIGDIR}/${CLUSTERNAME}.cdb | sed -e "s|.*: ||"`

		#
		# 4187380: cmm.minquorum does not exist in SC2.0/SC2.1 so don't
		#	   set MINQUORUM to what will be an empty string when
		#	   it should be an integer. The default value, 0, is
		#	   set in init.ksh.
		#
		if [[ -n "${tmpMINQUORUM}" ]] && \
		    [[ "${tmpMINQUORUM}" == [01] ]]; then
			let MINQUORUM=${tmpMINQUORUM}
		fi
	else
		let PDBAPPS=0
	fi
}
#######################################################
####    subroutines    ################################
#######################################################

#pragma ident   "@(#)subroutines.ksh 1.72   01/03/28 SMI"

############################################################################
# Functions
#

# Print the Usage in the case of incorrect options.
Usage() {

	echo "${helpUSAGE}"
	exit 0
}

# Check which version of echo is being used, and set correct echo options.
CheckEcho() {
	
	typeset result

	result=`echo -n`
	if [ "x-n" = "x${result}" ] ; then
		echoNOption=
		echoCOption=\\c
	else
		echoNOption=-n
		echoCOption=
	fi
}

# echo a line, leaving cursor at EOLN
Echo() {
	echo ${echoNOption} "$*" ${echoCOption}
}

# Press any key to continue ...
Pause() {
	echo " "
	Echo "	<<Press return to continue>>"
	line
}

# Toggle the Nth bit of a variable
# varName = Name of variable to be changed
# shiftDist = which bit is to be toggled
#
set_Bits() {
	typeset varName=$1
	integer shiftDist=$2

	if (( ${varName} & (1 << ${shiftDist}))); then
		eval let ${varName}=$((${varName}-(1 << ${shiftDist})))
	else
		eval let ${varName}=$((${varName}+(1 << ${shiftDist})))
	fi
}


#######
# List Manipulation Commands
#

# A list can have up to 512 entries (uses ksh arrays)
# Lists can be added to, searched, erased, and copied

# Add an entries to a list if it is not already a member of the list.
AddToList() {
	typeset listname=$1
	typeset newpackage=$2

	typeset ppackage
	typeset found=no
	integer positionInList=0                # Where are we in the list?

	for ppackage in `eval echo \\$\{$listname[*]\}`; do
		if [ "${newpackage}" == "${ppackage}" ]; then
			found=yes
			break
		fi
		((positionInList += 1))
	done
	if [ "${found}" = "no" ]; then
		eval ${listname}[${positionInList}]=${newpackage}
	fi
}

# Output a list in Reverse Order.
# This is really only needed when doing a remove
# so that we do not get a bunch of unrequired
# warning messages.
ReverseList() {
	Rlistname=$1

	integer i=0
	integer n=`eval echo \\$\{#${Rlistname}[*]\}`
	integer N=n-1
	typeset newlist

	while (( i < n )); do
		newlist[$i]=`eval echo \\$\{${Rlistname}[$N]\}`
		((i = i + 1))
		((N = N - 1))
	done
	print "${newlist[*]}"
}

# Remove all entries from a list (index 0..(n-1) )
UnSetList() {
	typeset list=$1

	integer i=0
	integer elements=`eval echo \\$\{#${list}[*]\}`

	while (( i < elements )) ; do
		eval unset ${list}[${i}]
		((i = i + 1))
	done
}

# Remove all entries from a list (index 1..n)
UnSetList2() {
	typeset list=$1

	integer i=0
	integer elements=`eval echo \\$\{#${list}[*]\}`

	while (( i <= elements )) ; do
		eval unset ${list}[${i}]
		((i = i + 1))
	done
}

# Append a list to the end of a list
AppendListToList() {
	typeset tolist=$1
	typeset fromlist=$2

	typeset package

	for package in `eval echo \\$\{${fromlist}[*]\}`; do
		AddToList ${tolist} ${package}
	done
}

# Print the list of packages with information from pkginfo
# $1 the list that contains the packages to check
# $2 either "yes" or "no" answers the question: has the package been installed?
PrintList() {
	typeset listname=$1
	typeset installed=$2

	typeset dir
	typeset name
	typeset package
	integer positionInList=0	# Where are we in the list?

	if [ ${installed} == "no" ]; then
		dir="-d ${MEDIA}"
	else
		dir=
	fi
	for package in `eval echo \\$\{${listname}[*]\}`; do
		name=`pkgparam ${dir} ${package} NAME 2>/dev/null`
		if [ -z "${name}" ]; 
			then name="<unknown>"
		fi
		printf "        %-10s %s\n" "${package}" "${name}"
		((positionInList += 1))
	done
	if [ ${positionInList} -eq 0 ]; then
		printf "        <no packages>\n"
	fi
}


#####################################################################
# Work functions
#

# Prompt a user for a response && read result.  Handle help, shell escapes ...
# The response is stored in the Global Variable ANSWER.
MyRead() {
	answer='!'
	typeset c
	typeset my_default=""
	integer expect_int=0
	typeset my_prompt=""
	typeset my_answers=""
	typeset display_my_answers=""
	typeset my_help="<no help is available>\n"
	typeset answer

	while getopts ifc:d:p:h: c "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
	do
		# echo getopts=$c \"${OPTARG}\" ${OPTIND}
		case ${c} in
		i)	expect_int=1
			;;
		f)      answer=''
			echo " "
			;;
		p)      my_prompt="${OPTARG}"
			;;
		d)      my_default="${OPTARG}"
			;;
		c)      my_answers="${OPTARG}"
			;;
		h)      my_help="${OPTARG}"
			;;
		\?)     echo "error in MyRead - bad options"
			answer="quit"
			return
			;;
		esac
	done
	shift `expr ${OPTIND} - 1`

	if [ -n "${my_answers}" ]; then
		display_my_answers=" [${my_answers}]"
	fi
	while : ; do
		echo " "
		Echo "${my_prompt}${display_my_answers} [${my_default}]: "
		read answer
		case "${answer}" in
		!)	echo "[invoking shell]"
			PS1="(subshell) ${PS1}" ksh
			;;
		!*)	set `expr "X${answer}" : "X!\(.*\)$"`
			echo invoking command: "$*"
			sh -c "$*"
			;;
		h | he | hel | help)
			printf "\n${my_help}\n"
			printf "Also accepted: !<command> and ! for shell escapes\n"
			;;
		*)	
			if [ ${expect_int} -eq 0 ]; then
				break
			fi
			case ${answer} in
			[1234567890]*)
				break
				;;
			'')
				break
				;;
			*) 
				echo "Please enter an integer value."
				;;
			esac
			;;
		esac
	done
	case "${answer}" in
	'') 	ANSWER="${my_default}"
		;;
	*) 	ANSWER="${answer}"
		;;
	esac
}


#Perform some command line options.
ReadOptions() {

	typeset opts=""
	typeset cOption="no"
	typeset iOption="no"
	typeset lOption="no"
	typeset oOption="no"
	typeset uOption="no"
	typeset sOption="no"

	while getopts acd:hilousVA: opts $@; do
		case ${opts} in
		#Both Client and Server
		a)
			cOption="yes"
			sOption="yes"
			;;
		#Client only
		c)
			cOption="yes"
			;;
		#Directory where media is located
		d)
			MEDIA="${OPTARG}"
			;;
		#help - show usage
		h)
			Usage
			;;
		#install a package set
		i)
			iOption="yes"
			;;
		#list function
		l)
			lOption="yes"
			;;
		#remove a package set
		o)
			oOption="yes"
			;;
		u)
			uOption="yes"
			;;
		#Server only
		s)
			sOption="yes"
			;;
		#Verify the installation
		V)
			INTERACTIVE="no"
			ReInit
			ShowVerify
			exit 0
			;;
		# A given adminfile
		A)
			ADMINFILE="${OPTARG}"
			;;
		*)
			Usage
			;;
		esac
	done

	if [ "${cOption}" == "yes" ] || [ "${sOption}" == "yes" ]; then
		if [ "${iOption}" == "no" ] && [ "${uOption}" == "no" ]; then
			Usage
		fi
	fi

	if [ "${iOption}" == "yes" ] && [ "${uOption}" == "yes" ]; then 
		Usage
	fi
	ReInit
	if [ "${lOption}" == "yes" ]; then
		INTERACTIVE="no"
		ShowList
		exit 0
	fi
	if [ "${oOption}" == "yes" ]; then
		if [ -n "${OBSOLETEI[*]}" ]; then
			INTERACTIVE="no"
			RemoveList OBSOLETEI
		else
			echo ""
			echo "There are no obsolete packages installed."
			echo ""
		fi
		exit 0
	fi
	if [ "${iOption}" == "yes" ]; then
		INTERACTIVE="no"
		if [ "${sOption}" == "yes" ]; then
			InstallList serverListU
		fi
		if [ "${cOption}" == "yes" ]; then
			InstallList clientListU
		fi
		exit 0
	fi
	if [ "${uOption}" == "yes" ]; then
		INTERACTIVE="no"
		if [ "${sOption}" == "yes" ]; then
			RemoveList serverListI
		fi
		if [ "${cOption}" == "yes" ]; then
			RemoveList clientListI
		fi
		exit 0
	fi
	INTERACTIVE="yes"
}

#Make the lists of installed and uninstalled Data Service packages
CheckDataServices() {
	typeset listname=$1
	typeset ilist=$2
	typeset ulist=$3

	typeset package
	integer count=1

	let DSINSTCOUNT=0
	let DSUNINSTCOUNT=0
	# Check each package for each Data Service
	while [ ${count} -lt ${DSCOUNTER} ]; do
		printf "."
		DSINSTALLED[${count}]=""
		DSUNINSTALLED[${count}]=""
		for package in ${DSPACKAGES[${count}]}; do
			# If package is installed
			if pkginfo -q ${package} >/dev/null 2>&1; then
				# Add package to installed package list
				# printf "${package} Is Installed\n"
				DSINSTALLED[${count}]="${DSINSTALLED[${count}]} ${package}"
			else
				# Add package to un-installed package list
				# printf "${package} Not Installed\n"
				DSUNINSTALLED[${count}]="${DSUNINSTALLED[${count}]} ${package}"
			fi
		done
		if [ -n "${DSINSTALLED[${count}]}" ]; then
			((DSINSTCOUNT += 1))
		elif [ -n "DSUNINSTALLED[${count}]}" ]; then
			((DSUNINSTCOUNT += 1))
		fi
		((count += 1))
	done
}

## Make the lists of installed and uninstalled packages
# Expected input:
#       $1 = List of packages that make up the package set
#       $2 = variable that holds the list of installed packages
#       $3 = variable that holds the list of un-installed packages
#
MakePackageList() {
	typeset listname=$1
	typeset ilist=$2
	typeset ulist=$3

	typeset package

	# Check each package in package set
	for package in `eval echo \\$\{${listname}[*]\}`; do
		# If package is installed
		if pkginfo -q ${package} >/dev/null 2>&1; then
			# Add package to installed package list
			# printf "${package} Is Installed\n"
			AddToList ${ilist} ${package}
		else
			# Add package to un-installed package list
			# printf "${package} Not Installed\n"
			AddToList ${ulist} ${package}
		fi
	done
}

# given a list, ckeck to see if the pkgs on it have been installed
# creates 2 lists - which end up containing the installed
# and uninstalled packages from the main list (which is unmodified)
CheckPackages() {
	typeset listname=$1
	typeset ilist=$2
	typeset ulist=$3

	typeset package

	# perform normal package check
	MakePackageList ${listname} ${ilist} ${ulist} ""
}

#initialize the package working list depending on the choices made
ReInit() {
	set -A installListI ""
	set -A installListU ""
	set -A serverListI ""
	set -A serverListU ""
	set -A clientListI ""
	set -A clientListU ""
	set -A SDSshortListI ""
	set -A SDSshortListU ""
	set -A SDSshort27ListI ""
	set -A SDSshort27ListU ""
	set -A OPSListI ""
	set -A OPSListU ""
	set -A SCIListI ""
	set -A SCIListU ""
	set -A SMAListI ""
	set -A SMAListU ""
	set -A SCDSListI ""
	set -A SCDSListU ""
	set -A OBSOLETEI ""
	set -A OBSOLETEU ""

	printf "\n	Checking on installed package state\n"
	CheckPackages installList installListI	installListU
	printf "."
	CheckPackages serverList serverListI	serverListU
	printf "."
	CheckPackages clientList clientListI	clientListU
	printf "."
	CheckPackages SDSshortList SDSshortListI	SDSshortListU
	printf "."
	CheckPackages OPSList	 OPSListI	OPSListU
	printf "."
	CheckPackages SCIList	 SCIListI	SCIListU
	printf "."
	CheckPackages SMAList	 SMAListI	SMAListU
	printf "."
	if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ] ; then
		CheckPackages server27List serverListI	serverListU
		printf "."
		CheckPackages client27List clientListI	clientListU
		printf "."
		CheckPackages SDSshort27List SDSshort27ListI	SDSshort27ListU
		printf "."
		CheckPackages OPS27List	 OPSListI	OPSListU
		printf "."
		CheckPackages SCI27List	 SCIListI	SCIListU
		printf "."
		CheckPackages SMA27List	 SMAListI	SMAListU
		printf "."
	fi
	CheckPackages SCDSList	 SCDSListI	SCDSListU
	printf "."
	CheckPackages OBSOLETE	 OBSOLETEI	OBSOLETEU
	printf "."
	CheckDataServices
	printf "."
	printf "\n"
}


#Initialize the package Lists
#
# The order of the each list's contents is important and cannot be changed
# without greatly impacting installation and removal of packages, and upgrade.
# The reason is that some of the packages have dependencies on others being
# installed on the system and so the order of their installation and removal is
# important.
#
SetLists() {

	# sc install packages
	AddToList installList	SUNWscins

	# sc framework
	AddToList serverList	SUNWsclb
	AddToList serverList	SUNWsc
	AddToList serverList	SUNWccd
	AddToList serverList	SUNWcmm
	AddToList serverList	SUNWff 
	AddToList serverList	SUNWmond
	AddToList serverList	SUNWpnm
	AddToList serverList	SUNWscman
	AddToList serverList	SUNWsccf
	AddToList serverList	SUNWscmgr

	# sc framework for 2.7
	AddToList server27List	SUNWffx
	AddToList server27List	SUNWsclbx
	AddToList server27List	SUNWmondx

	# client side packages
	AddToList clientList	SUNWscch
	AddToList clientList	SUNWccon
	AddToList clientList	SUNWccp
	AddToList clientList	SUNWcsnmp
	AddToList clientList	SUNWscsdb

	# SDS packages installable by scinstall
	AddToList SDSshortList	SUNWdid
	AddToList SDSshortList	SUNWmdm

	# SDS packages 2.7 support packages
	AddToList SDSshort27List SUNWdidx

	# OPS packages
	AddToList OPSList       SUNWudlm

	# OPS packages for 2.7
	AddToList OPS27List	SUNWudlmx

	# SCI packages
	AddToList SCIList       SUNWsci
	AddToList SCIList       SUNWscid
	AddToList SCIList       SUNWsma

	# SCI packages for 2.7
	AddToList SCI27List	SUNWsmax
	AddToList SCI27List	SUNWscidx

	# SMA packages
	AddToList SMAList	SUNWsma

	# SMA packages
	AddToList SMA27List	SUNWsmax

	# SUNWscds and its dependency
	AddToList SCDSList	SUNWscpro
	AddToList SCDSList	SUNWscds

	# Obsoleted packages from PDB
	AddToList OBSOLETE	SUNWdlm
	AddToList OBSOLETE	SUNWdlmd
	AddToList OBSOLETE	SUNWoudlm
	AddToList OBSOLETE	SUNWsccfg
	AddToList OBSOLETE	SUNWdmond
	AddToList OBSOLETE	SUNWpdb
	AddToList OBSOLETE	SUNWpdbcf
	AddToList OBSOLETE	SUNWpdbch
	AddToList OBSOLETE	SUNWpdbdb
	AddToList OBSOLETE	SUNWccm

	# Obsolete packages from Beta2
	AddToList OBSOLETE	 SUNWecs
	AddToList OBSOLETE	 SUNWecscf
	AddToList OBSOLETE	 SUNWecdns
	AddToList OBSOLETE	 SUNWechtt
	AddToList OBSOLETE	 SUNWecinf
	AddToList OBSOLETE	 SUNWecnew
	AddToList OBSOLETE	 SUNWecnsm
	AddToList OBSOLETE	 SUNWecor
	AddToList OBSOLETE	 SUNWecsch
	AddToList OBSOLETE	 SUNWecsdb
	AddToList OBSOLETE	 SUNWecsyb

	# ND packages - obsolete packages as of SC 2.1
	AddToList OBSOLETE	SUNWclmon
	AddToList OBSOLETE	SUNWcti
	AddToList OBSOLETE	SUNWnd
	AddToList OBSOLETE	SUNWndfs

	SetDataServices
}

#list whether none, some, or all of a package set is installed
ShowStateOf() {
	typeset listname=$1

	typeset qty

	if [ -z "`eval echo \\$\{${listname}ListU[*]\}`" ]; then
		qty="All"
	elif [ -z "`eval echo \\$\{${listname}ListI[*]\}`" ]; then
		qty="None"
	else
		qty="Some"
	fi
	printf "    %-4s of the %-12s packages have been installed\n" "${qty}" "${listname}"
}

#list whether none, some, or all of the data services are installed
ShowDSState() {

	typeset qty
	integer count=1
	
	if [ ${DSCOUNTER} -eq 0 ]; then
		echo "    No known Data Services"
		return
	fi
	while [ ${count} -lt ${DSCOUNTER} ]; do
		if [ -z "${DSUNINSTALLED[${count}]}" ]; then
			qty="All"
		elif [ -z "${DSINSTALLED[${count}]}" ]; then
			qty="None"
		else
			qty="Some"
		fi
		printf "    %-4s of the %s packages have been installed\n" \
			"${qty}" "${DSNAMES[${count}]}"
		((count += 1))
	done
}

# Perform the Verify command
ShowVerify() {
	
	print ${verifyHeader}

	print "Installation"
	ShowStateOf install
	print "Framework"
	ShowStateOf client
	ShowStateOf server
	print "Communications"
	if [[ -x /usr/kernel/drv/sci ]]; then
		ShowStateOf SCI
	else
		ShowStateOf SMA
	fi
	print "Data Services"
	ShowDSState 
}

#Determine install mode
#     The installation mode can either be "automatic" or "manual". Other
#     options are to "list" packages, "close" or stop the installation
#     process, and "quit" the program
GetInstallMode() {
	typeset pkgList=$1
	typeset mode=$2
	typeset modeHelpName=$3

	typeset modeList
	typeset modeHelp=""
	
	eval modeHelp=\$\{${modeHelpName}\}
	eval modeList=\$\{${pkgList}[*]\}
	while : ; do
		echo "${modeHelp}"
		MyRead -p "${mode} mode" -d "automatic" -c "manual automatic" -h "${modeHelp}"
		case ${ANSWER} in
		[aA]|[aA]u|[aA]ut|[aA]uto|[aA]utom|[aA]utoma|[aA]utomat|[aA]utomati|[aA]utomatic)
			assaRespFileArg="-r ${assaRespFile}"
			ARG="-n -a ${ADMINFILE}"; 
			break;;
		[mM]|[mM]a|[mM]an|[mM]anu|[mM]anua|[mM]anual)
			ARG="";
			break;;
		[lL]|[lL]i|[lL]is|[lL]ist)
			echo ""
			echo "    Packages to ${mode}: ${modeList[*]}"
			;;
		[cC]|[cC]l|[cC]lo|[cC]los|[cC]lose)
			ARG="Close"
			break;;
		[qQ]|[qQ]u|[qQ]ui|[qQ]uit)
			exit 0
			break;;
		*)  
			printf "Error: unrecognized response."
			printf "Please retry.\n";;
			esac
	done
}

#
# Remove a given patch
#
# $1 is the Patch ID that you want removed
#
# Returns:
#  1 on failure to remove patch
#  0 on successfull removal of patch
#
RemovePatch(){
	typeset patchid=$1

	typeset patchdb="/var/sadm/patch"

	printf "\n      Removing patch %s\n" "${patchid}"

	if [ -d ${patchdb}/${patchid} ]; then
		if [ -x ${patchdb}/${patchid}/backoutpatch ]; then
			set +e
			${patchdb}/${patchid}/backoutpatch ${patchid}
			if [ $? -ne 0 ]; then
				return 1
			fi

		# backoutpatch no longer exists for Solaris 2.7 patches
		# (and I assume the same holds for Solaris 2.8 as well)
		elif [[ "`uname -r`" == "5.7" ]] || [[ "`uname -r`" == "5.8" ]]; then
			set +e
			patchrm ${patchid}
			if [ $? -ne 0 ]; then
				return 1
			fi
		else
			printf "$(gettext \
			    'Unable to remove patch') \"%s\".\n" "${patchid}"
			return 1
		fi
	else
		printf "Cannot remove patch %s: Patch not found in %s.\n" \
			"${patchid}" "${patchdb}"
		return 1
	fi
	return 0
}

#
# Make sure that a given package is not currently patched.
#
# $1 is the package name that needs to be checked.
#
CheckForPatchID(){
	typeset package=$1

	typeset revpatchlist=""
	typeset patchlist=""
	typeset patchid=""

	# obtain the list of patches that have been put on this package.
	revpatchlist=`pkgparam ${package} PATCHLIST 2> /dev/null`
	# remove patches from newest to oldest
	for patchid in ${revpatchlist}; do
		patchlist="${patchid} ${patchlist}"
	done
	for patchid in ${patchlist}; do
		RemovePatch $patchid
		if [ $? -eq 1 ]; then
			return 1
		fi
	done
	return 0
}

#Perform the pre-remove routines when removing the SUNWsc package.
PreRemoveSC () {

	integer tmpCount
	typeset preRemoveList=""
	typeset tmpInteractive=""

	#Remove the list of packages
	if [ "${RFCHOICE}" == "Server" ] || [ "${RFCHOICE}" == "Both" ]; then
		#Remove all of the Data Service files and CDB files
		UnSetList removeList
		preRemoveList=""
		AppendListToList preRemoveList SCIListI
		AppendListToList preRemoveList SMAListI
		#How to add all of the Data Services?
		let tmpCount=1
		while [ ${tmpCount} -le ${DSCOUNTER} ]; do
			if [ -n "${DSINSTALLED[${tmpCount}]}" ]; then
				set -A tmpList ${DSINSTALLED[${tmpCount}]}
				AppendListToList preRemoveList tmpList
				set -A tmpList ""
			fi
			((tmpCount += 1))
		done
		if [ -n "${preRemoveList[*]}" ]; then
			echo "Removing all non-Client packages."
			tmpInteractive="${INTERACTIVE}"
			INTERACTIVE="no"
			RemoveList "preRemoveList"
			INTERACTIVE="${tmpInteractive}"
		fi
		rm -f ${CONFIGDIR}/default_clustername
		rm -f ${CONFIGDIR}/${CDBFILE}
		rm -f ${CONFIGDIR}/${CCDINITFILE}
		rm -f ${CONFIGDIR}/ccd.database.orig 2>/dev/null
		rm -f ${CONFIGDIR}/ccdd.pid 2>/dev/null
		rm -f ${CONFIGDIR}/ccd.database.savecopy 2>/dev/null
		rm -f ${CONFIGDIR}/ccd.database.shadow 2>/dev/null
		rm -f ${CONFIGDIR}/initccd.save 2>/dev/null
		rmdir ${CONFIGDIR}/hanfs 2>/dev/null
		rmdir ${CONFIGDIR}/ccdssa 2>/dev/null
		rmdir ${CONFIGDIR} 2>/dev/null
		rm -rf /var/opt/SUNWcluster /var/opt/SUNWpnm
	fi
}

#Perform the pre-remove routines when removing the SUNWccd package.
PreRemoveCCD () {

	typeset CCDINSTALL="/opt/SUNWcluster/bin/ccdinstall"
	typeset confdir="/etc/opt/SUNWcluster/conf"
	typeset ccdkey
	typeset nodeid
	typeset initkey
	
	if [ -n "${OBSOLETEI[*]}" ]; then
		echo ""
		echo "Removing obsolete packages:"
		echo "${OBSOLETEI[*]}"
		echo ""
		for obsPackage in ${OBSOLETEI[*]}; do
			pkgrm ${ARG} ${obsPackage}
			modified_pkgs="yes"
			
		done
	fi
	echo "Removing config info from ccd.database.init file"
	for ccdkey in clustname ccdfilename ccdfilename.ssa ccddevice.ssa \
		pidfile nservers onenode.quorum server.0.hname \
		server.1.hname server.2.hname server.3.hname server.0.nodeid \
		server.1.nodeid server.2.nodeid server.3.nodeid; do

		initkey=ccd.${ccdkey}
		${CCDINSTALL} -i rem ${initkey} ${confdir}/initccd.save
	done
	for nodeid in 0 1 2 3; do
		initkey=cluster.node.${nodeid}.hahost
		${CCDINSTALL} -i rem ${initkey} ${confdir}initccd.save
	done
	# Remove TCMON rows from the CCD
	${CCDINSTALL} rem TCMON /dev/null
}

#Remove a list of packages
#
# Returns:
#  0 on success
#  1 on not root user
#  2 on error removing a patch
#
RemoveList() {
	typeset packageList=$1

	typeset theList
	typeset tmpList
	typeset tmpList2
	typeset package
	typeset modified_pkgs="no"
	typeset closeLoop="no"
	typeset obsPackage
	typeset cmds="yes no list close quit help"

	eval tmpList=\$\{${packageList}[*]\}
	set -A tmpList2 ${tmpList}
	theList=$(ReverseList tmpList2)
	if [ -z "${theList[*]}" ]; then
		return 0
	fi
	if (( MYUID != 0 )) ; then
		echo "${badUserID}"
		return 1
	fi
	echo ""
	echo "Removing the following packages: ${theList[*]}"
	if [ "${INTERACTIVE}" == "yes" ]; then
		GetInstallMode theList "Remove" removeModeHelp
	else
		ARG="-n -a ${ADMINFILE}"; 
	fi
	if [ "${ARG}" == "Close" ]; then

		#
		# 4175619: In case OPS was selected, but the package was not
		#	   actually installed then reset bit 0 of PDBAPPS
		#
		if [ `pkginfo -q ${OPSList[0]} >/dev/null 2>&1` ] && \
		    (( PDBAPPS & (1 << 0) )); then
			let PDBAPPS=$((PDBAPPS+(1 << 0)))
		fi
		return 0
	fi
	for package in ${theList[*]} ; do
		if [ "${closeLoop}" == "yes" ]; then
			continue
		fi
		while : ; do
			if [ "${INTERACTIVE}" == "no" ]; then
				answer="yes"
			elif [ -z "${ARG}" ]; then
				MyRead -p "Remove ${package}?" -d "yes" \
				    -c "${cmds}" -h "${removeHelp}"
				answer="${ANSWER}"
			else
				answer="yes"
			fi
			case ${answer} in
			[yY]|[yY][eE]|[yY][eE][sS])
				if pkginfo -q ${package} > /dev/null ; then
					case ${package} in
					SUNWccd)
						PreRemoveCCD
						;;
					SUNWsc)
						PreRemoveSC
						;;
					*)
						;;
					esac
					CheckForPatchID ${package}
					if [ $? -ne 0 ]; then
						Echo "Error cannot complete"
						echo " package removal."
						Echo "Please resolve the patch"
						Echo " issue before attempting"
						Echo " to remove packages"
						echo " again."
						if [ "${INTERACTIVE}" == "yes" ]; then
							ReInit
						fi
						return 2
					fi
					if pkginfo -q ${package} > /dev/null ; 
					then
						pkgrm ${ARG} ${package}
						modified_pkgs="yes"
					fi
				fi
				break
				;;
			[nN]|[nN][oO])
				break
				;;
		     	[lL]|[lL][iI]|[lL][iI][sS]|[lL][iI][sS][tT])
		 		pkginfo -l ${package}
				;;
		     	[hH]|[hH][eE]|[hH][eE][lL]|[hH][eE][lL][pP])
		 		echo "${removeHelp}"
				Pause
				;;
			[cC]|[cC][lL]|[cC][lL][oO]|[cC][lL][oO][sS]|[cC][lL][oO][sS][eE])
				closeLoop="yes"
				break
				;;
			[qQ]|[qQ][uU]|[qQ][uU][iI]|[qQ][uU][iI][tT])
				exit 0
				;;
			*)
				printf "    Error: unrecognized response.  Please retry.\n${removeHelp}"
				;;
			esac
		done
	done
	if [ "${INTERACTIVE}" == "yes" ] && [ "${modified_pkgs}" == "yes" ]; then 
		ReInit
	fi
	return 0
}

#Install packages from a list of packages
# $1 = packageList - the name of the list to install
#
#Returns:
# 0 on no Error
# 1 on installation error.
InstallList() {
	typeset packageList=$1

	typeset theList
	typeset package
	typeset pkgDir="${MEDIA}"
	typeset cmds="yes no list close quit help"
	typeset answer
	typeset inst_args
	typeset argp
	typeset pd
	typeset modified_pkgs="no"
	typeset closeLoop="no"
	typeset tmpInteractive

	eval theList=\$\{${packageList}[*]\}
	if [ -z "${theList[*]}" ]; then
		return 0
	fi

	if (( MYUID != 0 )) ; then
		echo "${badUserID}"
		return 1
	fi
	echo ""
	echo "Installing the following packages: ${theList[*]}"
	if [ "${INTERACTIVE}" == "yes" ]; then
		GetInstallMode theList "Install" installModeHelp
		echo ""
	else
		assaRespFileArg="-r ${assaRespFile}"
		ARG="-n -a ${ADMINFILE}"; 
	fi
	if [ "${ARG}" == "Close" ]; then

		#
		# 4175619: In case OPS was selected, but the package was not
		#	   actually installed then reset bit 0 of PDBAPPS
		#
		if [ ! `pkginfo -q  ${OPSList[0]} >/dev/null 2>&1` ] && \
		    (( PDBAPPS & (1 << 0) )); then
			let PDBAPPS=$((PDBAPPS-(1 << 0)))
		fi
		return 0
	fi
	for package in ${theList[*]} ; do
		if [ "${closeLoop}" == "yes" ]; then
			continue
		fi
		if pkginfo -q ${package}.\* >/dev/null 2>&1 ; then
			continue
		fi
		while : ; do
			if [ "${INTERACTIVE}" == "no" ]; then
				answer="yes"
				assarespfilearg="-r ${assarespfile}"
			elif [ -z "${ARG}" ]; then
				MyRead -p "Install ${package}?" -d "yes" \
				 -c "${cmds}" -h "${installHelp}"
				answer="${ANSWER}"
			else
				answer="yes"
			fi
			case ${answer} in
			[yY]|[yY][eE]|[yY][eE][sS])
			 	# Special installation cases
		 		case ${package} in
		 		SUNWsccf)
			 		argp=`echo ${ARG} | sed 's/-n//'`
				 	inst_args="${argp} -d ${pkgDir}"
				 	;;
		 		SUNWsci)
					argp=`echo ${ARG} | sed 's/-n//'`
				 	inst_args="${argp} -d ${pkgDir}"
			 		;;
			 	SUNWasevm)
				 	inst_args="${ARG} -d ${pkgDir} ${assaRespFileArg}"
				 	;;
			 	SUNWudlm)
			 		inst_args="${ARG} -d ${pkgDir} ${assaRespFileArg}"
				 	;;
			 	*)
				 	inst_args="${ARG} -S -d ${pkgDir}"
				 	;;
		 		esac    # Special installation cases

				if [ ! -d "${pkgDir}/${package}" ]; then
					Echo "Error: Package ${package} was "
					Echo "not found in the directory: "
					echo "${pkgDir}"
					return 1
				fi
				echo "\nPackage directory: ${pkgDir}"
				pkgadd ${inst_args} ${package}
				let status=$?

			 	# Check result of package installation 
			 	case ${status} in 
			 	0|10|20) # No error on install
			 		;;
			 	*)	# An error while installing a package
					Echo "pkgadd of ${package} failed"
					Echo " - exit code ${status} - "
					echo "removing it"
			 		if pkginfo -q ${package}.\* >/dev/null 2>&1 ; then
			 			pkgrm -n -a ${ADMINFILE} ${package}
				 	fi
					return 1
			 	 	;;
		 		esac    
			 	modified_pkgs="yes"
			 	break
			 	;;
			[nN]|[n|N][oO]) 
				break 
				;;
		     	[lL]|[lL][iI]|[lL][iI][sS]|[lL][iI][sS][tT])
		 		echo "Package directory: ${pkgDir}"
		 		pkginfo -d ${pkgDir} -l ${package}
		 		;;
		     	[hH]|[hH][eE]|[hH][eE][lL]|[hH][eE][lL][pP])
		 		echo ""
		 		echo "Answer yes to install the package."
		 		echo "Answer no to skip to the next package."
				echo "Answer list to see information about the current package."
		 		echo "Answer help to see this table."
		 		echo "Answer quit to exit the program."
				Pause
		 		;;
			[cC]|[cC]l|[cC][lL][oO]|[cC][lL][oO][sS]|[cC][lL][oO][sS][eE])
				closeLoop="yes"
		 		break
		 		;;
			[qQ]|[qQ][uU]|[qQ][uU][iI]|[qQ][uU][iI][tT])
		 		exit 0
		 		;;
		     	*)  
				printf "Error: unrecognized response."
				printf "Please retry.\n"
				;;
		     	esac
		done
	done
	if [ "${INTERACTIVE}" == "yes" ] && [ "${modified_pkgs}" == "yes" ]; then 
		ReInit
	fi
	return 0
}

###
#
# subroutines_basic_package_install
#
#     Install packages from a list of packages. It was created to install the
#     SDS support packages. It should only be used interactively.
#
#     Input:
#	$1 = packageList - the name of the list to install
#
#     Return:
#	0 on no Error
#	1 on installation error.
#
function subroutines_basic_package_install
{
	typeset packageList=$1

	typeset theList
	typeset package
	typeset pkgDir="${MEDIA}"
	typeset inst_args
	integer status

	eval theList=\$\{${packageList}[*]\}
	if [ -z "${theList[*]}" ]; then
		return 0
	fi

	if (( MYUID != 0 )) ; then
		echo "${badUserID}"
		return 1
	fi
	ARG="-n -a ${ADMINFILE}"; 
	for package in ${theList[*]} ; do
		if pkginfo -q ${package}.\* >/dev/null 2>&1 ; then
			continue
		fi

		if [ ! -d "${pkgDir}/${package}" ]; then
			Echo "ERROR:  Package ${package} was "
			Echo "not found in the directory: "
			echo "${pkgDir}"
			return 1
		fi
		inst_args="${ARG} -S -d ${pkgDir}"
		printf "    $(gettext \
		    'Installing') \"%s\" ... " "${package}"
		pkgadd ${inst_args} ${package} > ${SCTMPDIR}/${package}.out 2>&1
		let status=$?

		# Check result of package installation 
		case ${status} in 
		0|10|20) # No error on install
			printf "$(gettext 'done')\n"
			;;
		*)	# An error while installing a package
			printf "$(gettext \
			    'failed with an error status of') \"%d\".\n" "${status}"
			cat ${SCTMPDIR}/${package}.out
			printf "\n    $(gettext \
			    'Installation of \"%s\" failed, removing it').\n" \
			    "${package}"
			if pkginfo -q ${package}.\* >/dev/null 2>&1 ; then
				pkgrm -n -a ${ADMINFILE} ${package}
			fi
			return 1
			;;
		esac    
	done

	#
	# Normally a ReInit would go here, but this will be left as a
	# choice for the caller of this function. Ideally, this function
	# could be called non-interactively, which is where ReInit is
	# useful.
	#

	return 0
}

################
# Code from request.ksh to install by pieces
#

###
#
# SelectVolumeManager
#
#     Choose which volume manager is to be used by the cluster.
#
#     Return:
#		 0	Volume manager chosen successfully
#		 1	Volume manager chosen, but packages may need to be
#			installed
#
SelectVolumeManager() {
	typeset continueStr="yes"
	typeset answerStr
	typeset promptHolder="${PS3}"
	integer volstatus=0	# 0 - choose packages, 1 - packages installed

	# If OPS has been selected,
	if (( PDBAPPS & (1 << 0) )); then
		# Set CVM
		echo ""
		printf "$(gettext \
		    'OPS has been configured, configuring CVM')...\n\n"
		echo "${warningCVM}"
		Pause
		let PDBAPPS=$((PDBAPPS+(1 << 3)))
		return 0
	fi 

	PS3="$(gettext 'Choose the Volume Manager'): "
	continueStr="yes"
	while [ "${continueStr}" == "yes" ]; do
		printf "\n$(gettext 'Volume Manager Selection')\n\n"
		printf "$(gettext \
		    'Please choose the Volume Manager that will be used')\n"
		printf "$(gettext 'on this node'):\n\n"
		select answerStr in "Cluster Volume Manager (CVM)" \
		    "Sun StorEdge Volume Manager (SSVM)" \
		    "Solstice DiskSuite (SDS)"; do
			case ${answerStr} in
			"Cluster Volume Manager (CVM)") 
				echo "${warningCVM}"
				Pause
				let PDBAPPS=$((PDBAPPS+(1 << 3)))
				continueStr="no"
				break
				;;
			"Sun StorEdge Volume Manager (SSVM)") 
				echo "${warningSEVM}"
				Pause
				let PDBAPPS=$((PDBAPPS+(1 << 4)))
				continueStr="no"
				break
				;;
			"Solstice DiskSuite (SDS)") 
				let PDBAPPS=$((PDBAPPS+(1 << 5)))
				continueStr="no"
				break
				;;
			*) printf "$(gettext 'Invalid selection').\n"
				break
				;;
			esac
		done
	done
	PS3="${promptHolder}"
	return 1
}


# Remove the CVM, SEVM or SDS Volume Manager 
RemoveVolumeManager() {
	if (( PDBAPPS & (1 << 3) )); then
		echo ""

		#
		# Don't allow the removal of CVM's configuration if OPS is still
		# around
		#
		if (( PDBAPPS & (1 << 0) )); then
			printf "!!!!!!!!!!!!!!!! $(gettext \
			    'WARNING') !!!!!!!!!!!!!!!!!!!!!\n\n"
			printf "$(gettext \
			    'OPS is still configured on this system. CVM cannot be unconfigured until')\n"
			printf "$(gettext \
			    'the OPS cluster software is first removed').\n\n"
			Pause
			return 0
		else
			let PDBAPPS=$((PDBAPPS-(1 << 3)))
			SavePDBAPPS
			printf "$(gettext 'CVM has been unconfigured').\n\n"
		fi
	fi
 
	if (( PDBAPPS & (1 << 4) )); then
		let PDBAPPS=$((PDBAPPS-(1 << 4)))
		SavePDBAPPS
		echo ""
		printf "$(gettext 'SSVM has been unconfigured').\n\n"
	fi
 
	if (( PDBAPPS & (1 << 5) )); then
		let PDBAPPS=$((PDBAPPS-(1 << 5)))
		SavePDBAPPS
		echo ""
		printf "$(gettext 'SDS has been unconfigured').\n\n"
	fi
	printf "*** $(gettext \
	    'The volume manager packages should now be removed').\n\n"
}


# Configure Volume Manager for CVM, SEVM or SDS
ConfigureVolumeManager() {

	typeset volumeManagerLoop="loop"
	integer status
	integer selstatus
	typeset vmAnswer
	typeset whichList
	
	while [ "${volumeManagerLoop}" == "loop" ]; do

		#Select the volume manager
		SelectVolumeManager
		let selstatus=$?
		if [ ${selstatus} -eq 0 ]; then
			volumeManagerLoop="stop"
			continue
		fi

		# Has more than one volume manager already been installed?
		if (( PDBAPPS & (1 << 4) )) && (( PDBAPPS & (1 << 5) )) || \
		    (( PDBAPPS & (1 << 3) )) && (( PDBAPPS & (1 << 4) )) || \
		    (( PDBAPPS & (1 << 3) )) && (( PDBAPPS & (1 << 5) )); then
			printf "\n*** $(gettext \
			    'Multiple volume managers cannot co-exist on the same cluster')! ***\n"
			Pause
			let PDBAPPS=$((PDBAPPS-(1 << 3)))
			let PDBAPPS=$((PDBAPPS-(1 << 4)))
			let PDBAPPS=$((PDBAPPS-(1 << 5)))
			continue
		fi

		#Install the volume manager
		if (( PDBAPPS & (1 << 3) )); then
			let MINQUORUM=0
			volumeManagerLoop="stop"
			continue
		elif (( PDBAPPS & (1 << 4) )); then
			let MINQUORUM=0
			volumeManagerLoop="stop"
			continue
		elif (( PDBAPPS & (1 << 5) )); then
			let MINQUORUM=1
			if [ -z "${SDSshortListU}" ]; then
				volumeManagerLoop="stop"
				echo "${warningSDS}"
				Pause
				continue
			else
				printf "\n$(gettext \
				    'Installing Solstice DiskSuite support packages').\n"
				GetMediaLocation "Volume Manager"

				#
				# 4179135: Make sure SUNWdidx is installed
				# before SUNWdid for 2.7 systems by creating a
				# separate list, SDSshort27List*, and installing
				# it before SDSshortListU.
				#
				# This will have to be reworked if a member of
				# SDSshort27List has a dependency on a member of
				# SDSshortList, which shouldn't happen because
				# members of SDSshort27List should only be the
				# 64-bit counterparts of members in
				# SDSshortList.
				#
				subroutines_basic_package_install \
				    "SDSshort27ListU"
				subroutines_basic_package_install \
				    "SDSshortListU"
				if [ $? -eq 1 ]; then
					echo "${volumeManagerInstallError}"
					vmAnswer="yes"
					vmAnswer=$(ckyorn -Q -d "yes" -W 150 \
					    -h "A yes answer will allow you to configure a Volume Manager again." \
					    -p "Would you like to try and configure a Volume Manager again? [yes]")
					case ${vmAnswer} in
					[nN]|[nN][oO])
						if (( PDBAPPS & (1 << 5) )); then
							PDBAPPS=$((PDBAPPS-(1 << 5)))
						fi
						volumeManagerLoop="stop"
						;;
					*)
						continue
						;;
					esac
				else
					volumeManagerLoop="stop"
					echo "${warningSDS}"
					Pause
				fi
			fi
		elif [ ${selstatus} -eq 99 ]; then
			volumeManagerLoop="stop"
			continue
		fi
	done
	SavePDBAPPS

	return 0
}

# Print the table of selected data services 
# $1 = paAddorRemove 0 - Add Services; 1 - Remove Services
PrintAppChoices() {
	integer paAddorRemove=$1

	integer tmpCounter=1
	typeset paFunction

	if (( paAddorRemove )); then
		paFunction="REMOVE "
		paFunctionStr="removed from"
	else
		paFunction="INSTALL"
		paFunctionStr="installed onto"
	fi
	echo "${selectAppHeader}"
	print "Please select which of the following data services"
	print "are to be ${paFunctionStr} this cluster. Select singly,"
	print "or in a space separated list."
	print "Note: Sun Cluster HA for NFS and Sun Cluster for Informix XPS"
	print "are installed automatically with the Server Framework."
	print
	print "You may de-select a data service by selecting it "
	print "a second time."
	print
	print "Select DONE when finished selecting the configuration."
	print

	
	while [ ${tmpCounter} -lt ${DSCOUNTER} ]; do 
		if (( paAddorRemove )); then
			if [ -z "${DSINSTALLED[${tmpCounter}]}" ]; then
				((tmpCounter += 1))
				continue
			fi
		else
			if [ -z "${DSUNINSTALLED[${tmpCounter}]}" ]; then
				((tmpCounter += 1))
				continue
			fi
			if (( PDBAPPS & (1 << 4) )) || \
			    (( PDBAPPS & (1 << 5) )); then
				if [ "${DSNAMES[${tmpCounter}]}" == \
				    "Sun Cluster for Oracle Parallel Server" ]; then
					((tmpCounter += 1))
					continue
				fi
			fi
		fi

		if [ "${selectApps[${tmpCounter}]}" == "1" ]; then
			print -n "${paFunction} "
		else
			print -n "        "
		fi
		printf "%i) %s" ${paCount} "${DSNAMES[${tmpCounter}]}"
		print
		paArray[${paCount}]="${tmpCounter}"
		((paCount += 1))
		((tmpCounter += 1))
	done
	print
	if [[ ${dsSelected} -eq 0 ]]; then
		print -n "${paFunction} "
	else
		print -n "        "
	fi
	printf "%i) No Data Services" ${paCount} 

	((paCount += 1))
	print
	printf "        %i) DONE" ${paCount}
	print
}

################################################################################
# Select data services
#
# Allow user to choose which data services to install on the cluster.
#
# $1 = saAddorRemove 0 - Add Services; 1 - Remove Services
SelectApps() {
	integer saAddorRemove=$1

	integer appLoop=1
	typeset choiceString
	integer choice
	integer maxChoice
	integer paCount
	integer noDataServices

	print
	if [ ${DSCOUNTER} -eq 1 ]; then
		SetDataServices
		CheckDataServices
	fi
	if [ ${DSCOUNTER} -eq 1 ]; then
		echo "There are no Data Services to configure."
		echo "Exiting the Data Service Selection Menu."
		echo ""
		return
	fi
	let tmpCount=1
	while [ ${tmpCount} -lt ${DSCOUNTER} ]; do
		selectApps[${tmpCount}]="0"
		((tmpCount += 1))
	done
	let dsSelected=0
	while [[ "${appLoop}" -eq 1 ]] ; do
		choiceString=""
		let paCount=1
		set -A paArray ""
		PrintAppChoices  ${saAddorRemove}
		((noDataServices = paCount - 1))
		((maxChoice = paCount))
		choiceString=$(ckstr -Q -r "^[0-9 ]\{1,\}$" -l 80 \
		    -e "$(gettext 'Illegal value(s), please try again')." \
		    -p "Choose a data service:")
		for choice in ${choiceString}; do
			if [ ${choice} -le 0 ] || [ ${choice} -gt ${maxChoice} ]; then
				print "Please choose one, or more, of the numbers shown."
				break
			elif [ ${choice} -eq ${maxChoice} ]; then
				# Done
				let appLoop=0
				break
			elif [ ${choice} -eq ${noDataServices} ]; then
				# None
				let tmpCount=1
				while [ ${tmpCount} -lt ${DSCOUNTER} ]; do
					selectApps[${tmpCount}]="0"
					((tmpCount += 1))
				done
				let dsSelected=0
			else
				#choose the Data Service
				if [ "${selectApps[${paArray[${choice}]}]}" == "1" ]; then
					selectApps[${paArray[${choice}]}]="0"
					((dsSelected -= 1))
				else
					selectApps[${paArray[${choice}]}]="1"
					((dsSelected += 1))
				fi
			fi
		done
	done
}

#Remove Data Service packages
RemoveDataServices() {

	integer tmpCount=1
	integer numbeingremoved=0
	integer status
	UnSetList appList
	UnSetList tmpList
	set -A tmpRevList ""
		
	while [ ${tmpCount} -lt ${DSCOUNTER} ]; do
		if [ "${selectApps[${tmpCount}]}" == "1" ]; then
			set -A tmpList "${DSINSTALLED[${tmpCount}]}"
			AppendListToList appList tmpList
			UnSetList tmpList

			#
			# 4175619: Also, when OPS is removed, its PDBAPPS should
			#	   get unset.
			#
			if [ "${DSNAMES[${tmpCount}]}" == \
			    "Sun Cluster for Oracle Parallel Server" ]; then
				let PDBAPPS=$((PDBAPPS-(1 << 0)))
			fi

			((numbeingremoved += 1))
		fi
		((tmpCount += 1))
	done

	#
	# if all data service packages are being removed, then so should
	# the SCDS packages
	#
	if (( numbeingremoved == DSINSTCOUNT )) && \
	    [ -n "${SCDSListI[*]}" ]; then
		AppendListToList tmpRevList SCDSList
		AppendListToList tmpRevList appList
		set -A appList ""
		AppendListToList appList tmpRevList
	fi

	echo ""
	echo "Removing Data Service packages."
	RemoveList "appList"
	let status=$?

	# 4175619: PDBAPPS needs to be stored in case OPS was removed
	if (( status == 0 )); then
		SavePDBAPPS
	fi

	return ${status}
}

#Install Data Service packages
InstallDataServices() {

	integer tmpCount=1
	integer status
	UnSetList appList 
	UnSetList tmpList 

	if (( DSINSTCOUNT == 0 )); then
		set -A appList "${SCDSList[*]}"
	fi
	while [ ${tmpCount} -lt ${DSCOUNTER} ]; do
		if [ "${selectApps[${tmpCount}]}" == "1" ]; then
			if [ "${DSNAMES[${tmpCount}]}" == \
			    "Sun Cluster for Oracle Parallel Server" ]; then
				let PDBAPPS=$((PDBAPPS+(1 << 0)))
				if (( PDBAPPS & (1 << 4) )) || \
				    (( PDBAPPS & (1 << 5) )); then
					echo "${warningOPS}"
					Pause
				fi
				if ! (( PDBAPPS & (1 << 3) )); then
					let PDBAPPS=$((PDBAPPS+(1 << 3)))
					printf "\n    $(gettext \
					    'Since Oracle Parallel Server (OPS) has been selected,')\n"
					printf "    $(gettext \
					    'CVM must be installed before OPS can be started').\n"
					Pause
				fi
			fi
			set -A tmpList "${DSUNINSTALLED[${tmpCount}]}"
			AppendListToList appList tmpList
			UnSetList tmpList ""
		fi
		((tmpCount += 1))
	done

	echo ""
	echo "Installing Data Service packages."
	InstallList "appList"
	let status=$?

	# 4175619: PDBAPPS needs to be stored in case OPS was installed
	if (( status == 0 )); then
		SavePDBAPPS
	fi

	return ${status}
}

#Configure Data Services
# $1 = AddorRemove 0 - Add Services; 1 - Remove Services
ConfigureDataServices() {
	integer AddorRemove=$1

	typeset dataServiceLoop="loop"
	integer status
	typeset dsAnswer
	integer dsSelected=0
	typeset dsFunction

	if (( AddorRemove )); then
		dsFunction="Remove"
	else
		dsFunction="Install"
	fi
	
	while [ "${dataServiceLoop}" == "loop" ]; do

		#Select the Data Services
		SelectApps ${AddorRemove}
		if [ ${dsSelected} -eq 0 ]; then
			#No Data Services have been selected
			dataServiceLoop="stop"
			continue
		fi
		
#		let PDBAPPS=$((PDBAPPS+dsSelected))

		#where is the media?
		if [ ${AddorRemove} -eq 0 ]; then
			GetMediaLocation "Data Services"
		fi
		
		#Install Data Services packages
		if (( AddorRemove )); then
			RemoveDataServices
			let status=$?
		else
			InstallDataServices  
			let status=$?
		fi
		if [ ${status} -ne 0 ]; then
			ReInit
			if (( AddorRemove )); then
				echo "${dataServiceRemoveError}"
			else
				echo "${dataServiceInstallError}"
			fi
			dsAnswer="yes"
			dsAnswer=$(ckyorn -Q -d "yes" -W 150\
				-h "Answer yes to attempt to ${dsFunction} Data Services again. Or, no to end attempts to install Data Services."\
			-p "Attempt to ${dsFunction} Data Services again [yes]?")
			case ${dsAnswer} in
			[nN]|[nN][oO])
				dataServiceLoop="stop"
				;;
			*)
				;;
			esac
		else
			dataServiceLoop="stop"
		fi
	done
}



#Is cluster connected to a Direct Connect Device
DirectConnect() {

	typeset SC_DC=""

	let DIRECTC=0
	if (( NUMNODEACTIVE > 2 )); then
		SC_DC=$(ckyorn -Q -d "no" \
			-p "Does the ${CLUSTERNAME} cluster have a disk storage device that is connected to all nodes in the cluster [no]?" \
			-e "Please answer yes or no" )
		if [[ "${SC_DC}" = @((y|Y)?((e|E)(s|S))) ]]; then
			let DIRECTC=1
		fi
	fi
}

# This function performs the following:
#
# Asks if the user which optimization policy to use
# if lower, set SBOPT = 1
# if higher, set SBOPT = 2
function Opt_policy
{

	integer correct=0
	typeset TEMP

print " "
print "You have a choice of two policies:  "
print " "
print "     lowest -- The subset containing the node with the"
print "               lowest node ID value automatically becomes the"
print "               new cluster.  All other subsets must be"
print "               manually aborted."
print " "
print "    highest -- The subset containing the node with the"
print "               highest node ID value automatically becomes the"
print "               new cluster.  All other subsets must be"
print "               manually aborted."
print " "

	while [[ "${correct}" -eq 0 ]]; do
		TEMP=$(ckstr -Q -d lowest \
		-p "Select the selection policy for handling partitions (lowest|highest) [lowest]:")
		case ${TEMP} in
		[Ll]|[Ll][Oo][Ww][Ee][Ss][Tt])
			let correct=1
			let SBOPT=1
			;;
		[Hh]|[Hh][Ii][Gg][Hh][Ee][Ss][Tt])
			let correct=1
			let SBOPT=2
			;;
		*)
			print Unrecognized response. Please enter either "lowest" or "highest"
			;;
		esac
	done
}

# OptPartitions
function OptPartitions
{
	integer correct=0
	typeset TEMP

print "In the event that the cluster is partitioned into two or more"
print "subsets of nodes, the Cluster Membership Monitor may request"
print "input from the operator as to how it should proceed (abort or"
print "form a cluster) within each subset.  The Cluster Membership"
print "Monitor can be configured to make a policy-dependent automatic"
print "selection of a subset to become the next reconfiguration of the"
print "cluster."
print " "
print "In case the cluster partitions into subsets, which subset"
print "should stay up?"
print "    ask)    the system will always ask the operator."
print "    select) automatic selection of which subset should stay up."
print " "
	while [[ "${correct}" -eq 0 ]]; do
		TEMP=$(ckstr -Q -d ask \
		-p "Please enter your choice (ask|select) [ask]:")
		case ${TEMP} in
		[Ss]|[Ss][Ee][Ll][Ee][Cc][Tt])
			let correct=1
			Opt_policy
			;;
		[Aa]|[Aa][Ss][Kk])
			let correct=1
			SBOPT=0
			;;
		*)
			print Unrecognized response. Please enter either "select" or "ask"
			;;
		esac
	done
}

#Select Quorum Device
SetQuorum() {

	integer i
	integer j
	
	if [ ${DIRECTC} -eq 1 ]; then
		${BINDIR}/scconf ${CLUSTERNAME} -q -D
	else
		let i=1
		while (( i < NUMNODEACTIVE )); do
			let j=i+1
			while [ ${j} -le ${NUMNODEACTIVE} ]; do
				${BINDIR}/scconf ${CLUSTERNAME} -q ${NODENAMES[${i}]} ${NODENAMES[${j}]}
				let j=j+1
			done
			let i=i+1
		done
	fi
}
#Configure SCI/Ether
# For all clusters, allows choice of ether or SCI.
# For all clusters, disable SMA (SET bit 9 in PDBAPPS)
AssignNetIfType() {

	integer netLoop=1

	DIFN="scid0"
	DIFM="scid1"
	POUND="#"
	let PDBAPPS=$((PDBAPPS+(1 << 9)))
	while [[ "${netLoop}" -eq 1 ]] ; do
		NETIFTYPE=$(ckstr -Q \
		-d "SCI"\
		-p "What type of network interface will be used for this configuration (ether|SCI) [SCI]?")
		case ${NETIFTYPE} in
		[Ee]|[Ee][Tt][Hh][Ee][Rr])
			NETIFTYPE="ether"
			DIFN="hme0"
			DIFM="hme1"
			POUND=""
			netLoop=0
			;;
		[Ss]|[Ss][Cc][Ii])
			NETIFTYPE="SCI"
			netLoop=0
			;;
		*)
			print Invalid network interface: please enter "ether" or "SCI"
			;;
		esac
	done
}

#Configure the CCD
# This function allows the user to select the option to have a shared
# volume for CCD operations on a 2-node only cluster
SelectSharedCCD() {

	typeset resp1="0"

	print " "	
	print "On a 2-node configured cluster you may have a volume on"
	print "the shared disk media for use by the CCD. This volume is"
	print "used by the CCD to keep a copy of the database for increased"
	print "availability, in case only 1 node is operational at a given"
	print "time."
 
	while [ "${resp1}" != "yes" ] && [ "${resp1}" != "no" ]; do
		resp1=$(ckstr -Q \
			-d "no" \
			-p "Do you want a shared volume for CCD (yes|no) [no]?")
		case ${resp1} in
			[yY]|[yY][eE][sS])
				resp1="yes"
			;;
			[nN]|[nN][oO])
				resp1="no"
			;;
			*)
				echo "Please answer yes or no."
			;;
		esac
	done
	
	if [ "${resp1}" == "yes" ] ; then
		print ""
		print "!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!"
		print ""
		print "Selecting two disks for CCD volume implies"
		print "that you cannot use these disks for other"
		print "uses such as a database. These two disks will"
		print "effectively be dedicated for CCD internal use"
		print ""
		resp1="0"
		while [ "${resp1}" != "yes" ] && [ "${resp1}" != "no" ]; do
			resp1=$(ckstr -Q \
				-d "yes" \
				-p "Are you sure (yes|no) [yes]?")
			case ${resp1} in
				[yY]|[yY][eE][sS])
					resp1="yes"
				;;
				[nN]|[nN][oO])
					resp1="no"
				;;
				*)
					echo "Please answer yes or no."
				;;
			esac
		done
		if [ "${resp1}" == "yes" ] ; then	
			print ""
			print "Please be sure to run the 'confccdssa' command"
			print "after completion of install. This will allow"
			print "you to select the 2 disks for the CCD volume."
			print "This command should be run on a SINGLE node."
			print ""
			CCDDEVICE="ccdvol"
			return
		fi
	fi
	print ""
	print "No shared CCD volume will be installed"
	print ""
	CCDDEVICE="none"
}

# storeNodeinfo
# Saves the node related TC/SSP information in arrays  
StoreNodeInfo() {
	typeset nodeNum=$1
	typeset tc_num=$2
	typeset arch=$3
	typeset port=$4

	if [ "${arch}" == "SSP" ]; then
		TC_SSP_ARCH[${nodeNum}]="E10000"
	else
		TC_SSP_ARCH[${nodeNum}]="other"
	fi
	TC_SSP_PORT[${nodeNum}]="${tc_num}.${port}"
} 

# StoreTC_SSP
#
# Saves the TC/SSP device related TC/SSP information in arrays  
StoreTC_SSP() {
	integer counter=$1
	typeset tmp_ak=$2
	typeset infotype=$3
	typeset ip_addr=$4
	typeset name=$5

	eval TC_SSP_IP[${counter}]=${ip_addr}
	eval TC_SSP_Type[${counter}]=${infotype}
	TC_SSP_AK[${counter}]="${tmp_ak}"
	eval TC_SSP_Name[${counter}]=${name}
}

# GetTC_AK
#
# call tcak to get the password for the TC/SSP.
GetTC_AK() {
	typeset infotype=$1

	typeset baseDir
	typeset prodDir
	
	baseDir="/"
	prodDir=`pkgparam SUNWsc PRODUCTDIR`
	echo ""
	${baseDir}/opt/${prodDir}/bin/tcak "${infotype}" ${SCTMPDIR}/tcak.$$
	tmp_ak=`/bin/cat ${SCTMPDIR}/tcak.$$`
	/bin/rm -f ${SCTMPDIR}/tcak.$$
}

# VerifyTC_IP
#
# check if a TC or SSP entry already exists
#
# tc_ip = the IP address that is being checked
#
# returns the index for the TC/SSP entry if found.  If the return value is less
# 	than the number of entries so far, then an entry exists.
#
function VerifyTC_IP {
	typeset tc_ip=$1

	integer cnt
	
	cnt=0
	while [ ${cnt} -lt ${TC_SSP_Counter} ]; do
		if [[ ${TC_SSP_IP[${cnt}]} == ${tc_ip} ]]; then
			return ${cnt}
		fi
		((cnt=cnt+1))
	done
	return ${cnt}
}

# VerifyTCPort
#
# check if a TC port is already in use
#
# tc_ip = the IP address that is being checked
# tc_port = the port number being checked
#
# returns the number of the node that already has the port, else it returns
# 	a value greater than the total number of node entries so far.
#
# Note: this could be used to check for SSP entries by setting tc_port to -1.
#
function VerifyTCPort {
	typeset tc_ip=$1
	typeset tc_port=$2

	integer cnt
	
	cnt=0
	while [ ${cnt} -le ${LOOPCNTR} ]; do
		if [[ (${TC_PORT_IP[${cnt}]} == ${tc_ip}) \
			&& (${TC_PORT_NUM[${cnt}]} == ${tc_port}) ]]; then
			return ${cnt}
		fi
		((cnt=cnt+1))
	done
	return ${cnt}
}

# GetTCPortNumber
#
# Get the physical port number of the TC that the node is attached to
#
# If nodeLock = 0, then the port number is not for node locking
# If nodeLock = 1, then the port number is for node locking.
#
# The port number is passed back to the calling routine through $2
# $3 should be the name of the variable that the port number is to be stored.
#
# NodeName is a variable containing the name of the current host.
GetTCPortNumber() {
	integer nodeLock=$1
	typeset node_ip=$2

	typeset portLoop="loop"
	typeset tc_port
	integer tc_found

	while [ "${portLoop}" == "loop" ]; do
		tc_port=""
		if [ ${nodeLock} -eq 1 ]; then
			tc_port=$(ckstr -Q \
			-r "^[0-9]\{1,\}$" \
			-p "Which unused physical port on the Terminal Concentrator is to be used for node locking:" \
			-e "Please enter a value in the range of 1-64." )
		else
			tc_port=$(ckstr -Q \
			-r "^[0-9]\{1,\}$" \
			-p "Which physical port on the Terminal Concentrator is ${NodeName} connected to:" \
			-e "Please enter a value in the range of 1-64." )
		fi
		if [[ ( ${tc_port} -gt 0 ) && ( ${tc_port} -lt 65) ]]; then 
			VerifyTCPort ${node_ip} ${tc_port}
			if [ $? -le ${LOOPCNTR} ]; then
				echo ""
				echo "That port is already in use."	
			else
				portLoop="stop"
			fi
		else
			echo "Please enter a value from 1 to 64"
		fi
	done
	eval $3=${tc_port}
}

# NewTC_SSPInfo
#
# Get the required information about a TC or SSP device.
#
# 4187383: This function is now also used during the upgrade process which sets
#	   the TC/SSP info using scconf. Whereas, initial installation sets the
#	   TC/SSP info by editing the CDB file. The solution to this bug is to
#	   expand this function's arguments in order to sensitize it to which
#	   process is using it.
#
# Usage:
#     NewTC_SSPInfo [ -u ] -t TC -h <hostname>
#     NewTC_SSPInfo [ -u ] -t SSP
#
# infotype = which type of device information is for: either "TC" or "SSP"
#
# returns 0 if an attempt is made to create an entry for a device that already
#	exists
# returns 1 on successful new entry
#
NewTC_SSPInfo() {
	typeset nameofnode
	typeset infotype
	typeset skippasswd="FALSE"
	typeset c

	while getopts uh:t: c
	do
		case ${c} in
		u)
			skippasswd="TRUE"
			;;
		h)
			nameofnode="${OPTARG}"
			;;
		t)
			infotype="${OPTARG}"
			if [[ "${infotype}" != "TC" ]] && \
			    [[ "${infotype}" != "SSP" ]]; then
				printf "$(gettext \
				    '[NewTC_SSPInfo] \"TC\" or \"SSP\" are only legal values').\n"
				return 1
			fi
			;;
		\?)
			printf "$(gettext \
			    'Incorrect options passed to NewTC_SSPInfo')\n"
			return 1
			;;
		esac
	done
	shift `expr ${OPTIND} - 1`

	if [[ -z "${infotype}" ]]; then
		printf "$(gettext \
		    '[NewTC_SSPInfo] \"-t TC|SSP\" is missing').\n"
		return 1
	fi

	# Check for "-t TC -h <hostname>"
	if [[ ${infotype} == "TC" ]]; then
		if [ -z "${nameofnode}" ]; then
			printf "$(gettext \
			    '[NewTC_SSPInfo] A hostname must be specified').\n"
			return 1
		fi
	fi

	typeset tmp_name
	typeset tmp_ip
	typeset tmp_port
	typeset tmp_ak
	typeset good_name
	typeset infoString

	if [ "${infotype}" == "SSP" ]; then
		infoString="System Service Processor"
		tmp_name=$(ckstr -Q \
			-d "NO_NAME" \
			-r "^[]a-zA-Z0-9_@#%^+=~}:.,-]\{1,\}$" \
			-p "What is the name of the System Service Processor [NO_NAME]?" \
	   		-e "The device name should not contain spaces or special characters")
	else
		infoString="Terminal Concentrator"
		tmp_name=$(ckstr -Q \
			-d "NO_NAME" \
			-r "^[]a-zA-Z0-9_@#%^+=~}:.,-]\{1,\}$" \
			-p "What is the name of the Terminal Concentrator connected to the serial port of ${nameofnode} [NO_NAME]?" \
	   		-e "The device name should not contain spaces or special characters")
	fi
	set -A tmp_ip `grep ${tmp_name} /etc/hosts | awk '{print $1}'`
	tmp_ip=`arp ${tmp_name} | sed -e "s/.*(//" | sed -e "s/).*//"| grep -v "unknown host"`
	if [ -n "${tmp_ip[0]}" ]; then
		good_name=""
		while [ -z "${good_name}" ]; do
			good_name=$(ckstr -Q -d "YES" \
				-p "Is ${tmp_ip[0]} the correct IP address for this ${infoString} (yes | no) [yes]?" \
				-e "Please enter yes or no.")
			case ${good_name} in
			[yY]|[yY][eE][sS])
				good_name="YES"
				;;
			[nN]|[nN][oO])
				good_name="NO"
				;;
			*)
				echo "Please answer yes or no."
				good_name=""
				;;
			esac
		done
	else
		echo "Cannot find an IP address for a host with that name."
		good_name="NO"
	fi

	if [ "${good_name}" == "NO" ]; then
		tmp_ip[0]=$(ckstr -Q \
		-r "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$" \
		-p "What is the IP address of the ${infoString}?" \
		-e "The IP address must be in the form 123.456.789.012")

	fi
	VerifyTC_IP ${tmp_ip[0]}
	if [ $? -lt ${TC_SSP_Counter} ]; then
		print "	ERROR: There is already an entry for that device"
		return 0
	fi

	# 4187383: When '-u' is specified, skip this step.
	if [[ "${skippasswd}" == "FALSE" ]]; then
		GetTC_AK ${infotype} 
	fi

	if [ "${infotype}" == "TC" ]; then
		GetTCPortNumber 0 ${tmp_ip[0]} tmp_port 
	else
		tmp_port="-1"
	fi
	StoreNodeInfo "${LOOPCNTR}" "${TC_SSP_Counter}" ${infotype} ${tmp_port}
	StoreTC_SSP ${TC_SSP_Counter} "${tmp_ak}" "${infotype}" "${tmp_ip[0]}" "${tmp_name}"
	TC_PORT_NUM[${LOOPCNTR}]="${tmp_port}"
	TC_PORT_IP[${LOOPCNTR}]="${tmp_ip[0]}"
	((TC_SSP_Counter=TC_SSP_Counter+1))
	return 1
}

# PrintTCTable
#
# Print a table of current TC or SSP devices, and allow the user to
# choose one or create a new entry.
#
# Usage:
#     PrintTCTable [ -u ] -t TC|SSP -h <hostname>
#
# infotype = which type of device information is for: either "TC" or "SSP"
#
PrintTCTable() {
	typeset nameofnode
	typeset infotype
	typeset skippasswd="FALSE"
	typeset c

	while getopts uh:t: c
	do
		case ${c} in
		u)
			skippasswd="TRUE"
			;;
		h)
			nameofnode="${OPTARG}"
			;;
		t)
			infotype="${OPTARG}"
			if [[ "${infotype}" != "TC" ]] && \
			    [[ "${infotype}" != "SSP" ]]; then
				printf "$(gettext \
				    '[PrintTCTable] \"TC\" or \"SSP\" are only legal values').\n"
				return 1
			fi
			;;
		\?)
			printf "$(gettext \
			    'Incorrect options passed to PrintTCTable')\n"
			return 1
			;;
		esac
	done
	shift `expr ${OPTIND} - 1`

	# Check for "... -t TC|SSP"
	if [[ -z "${infotype}" ]]; then
		printf "$(gettext \
		    '[PrintTCTable] \"-t TC|SSP\" is missing').\n"
		return 1
	fi

	# Check for "... -h <hostname>"
	if [ -z "${nameofnode}" ]; then
		printf "$(gettext \
		    '[PrintTCTable] A hostname must be specified').\n"
		return 1
	fi

	integer counter
	integer listCnt
	integer tmp_cnt=0
	typeset choice
	typeset tmp_port
	typeset continueStr="1"
	typeset chooseStr="1"
	typeset listStr
	typeset x

	if [ "${infotype}" == "SSP" ]; then
		listStr="System Service Processor"
	else
		listStr="Terminal Concentrator"
	fi
	while [ "${continueStr}" == "1" ]; do
		chooseStr="1"
		while [ "${chooseStr}" == "1" ]; do
			counter=0
			listCnt=0
			echo ""
			echo "Which ${listStr} is ${nameofnode} connected to:"
			echo ""
			for x in ${TC_SSP_IP[*]} ; do
				if [ "${TC_SSP_Type[${counter}]}" == "${infotype}" ]; then 
					echo "${listCnt}) ${TC_SSP_Name[${counter}]} \t ${x}"
					listCnt=`eval echo "${listCnt}+1"`
				fi
				counter=`eval echo "${counter}+1"`
			done
			echo "${listCnt}) Create A New ${listStr} Entry"
			choice=$(ckstr -Q \
				-r "^[0-9]\{1,\}$" \
				-p "Select a device:" \
				-e "Choose by number shown")
			if  [[ ( ${choice} -ge 0 ) \
					&& ( ${choice} -le ${listCnt} ) ]]; then
				chooseStr="0"
			else
				echo "Please enter one of the numbers shown."
			fi
		done
		if [ "${choice}" == "${listCnt}" ]; then
			if [[ "${skippasswd}" == "TRUE" ]]; then
				NewTC_SSPInfo -u -t ${infotype} -h ${nameofnode}
			else
				NewTC_SSPInfo -t ${infotype} -h ${nameofnode}
			fi
			if [ $? -eq 1 ]; then
				if [ "${infotype}" == "SSP" ]; then
					SSP_Counter="Many"
				else
					TC_Counter="Many"
				fi
				continueStr="0"
			else
				continueStr="1"
			fi
		else
			#find the right device
			listCnt=-1
			tmp_cnt=-1
	
			while [ "${tmp_cnt}" != "${choice}" ]; do
				listCnt=`eval echo "${listCnt}+1"`
				if [ "${TC_SSP_Type[${listCnt}]}" == "${infotype}" ]; then
					tmp_cnt=`eval echo "${tmp_cnt}+1"`
				fi
			done
	
			if [ "${infotype}" == "TC" ]; then
				GetTCPortNumber 0 ${TC_SSP_IP[${listCnt}]} tmp_port
			else
				tmp_port="-1"
			fi
			StoreNodeInfo "${LOOPCNTR}" "${listCnt}" ${infotype} \
			    ${tmp_port}
			TC_PORT_NUM[${LOOPCNTR}]="${tmp_port}"
			TC_PORT_IP[${LOOPCNTR}]="${TC_SSP_IP[${listCnt}]}"
			continueStr="0"
		fi
	done
}	

# NodeLockTable
#
# Print a table of current TC or SSP devices, and allow the user to
# choose one to be the node lock device.
NodeLockTable() {
	typeset list=$1

	integer counter
	integer listCount
	integer tmp_cnt=0
	typeset choice
	typeset tmp_port
	typeset continueStr="1"
	typeset listStr

	if [ "${list}" == "SSP" ]; then
		listStr="System Service Processor"
	else
		listStr="Terminal Concentrator"
	fi
	while [ "${continueStr}" == "1" ]; do
		counter=0
		listCount=0
		echo ""
		echo "Select a device for Node Locking:"
		echo ""
		for x in ${TC_SSP_IP[*]} ; do
			if [ "${TC_SSP_Type[${counter}]}" == "${list}" ]; then 
				echo "${listCount}) ${TC_SSP_Name[${counter}]} \t ${x}"
				listCount=`eval echo "${listCount}+1"`
			fi
			counter=`eval echo "${counter}+1"`
		done
		choice=$(ckstr -Q \
			-r "^[0-9]\{1,\}$" \
			-p "Which ${listStr} should be used for the node lock mechanism?" \
			-e "Please enter one of the numbers shown.")
		if  [[ ( ${choice} -ge 0 ) && ( ${choice} -lt ${listCount} ) ]]; then
			continueStr="0"
		else
			echo "Please enter one of the numbers shown."
		fi
	done
	#find the right device
	listCount=-1
	tmp_cnt=-1
	while [ "${tmp_cnt}" != "${choice}" ]; do
		listCount=`eval echo "${listCount}+1"`
		if [ "${TC_SSP_Type[${listCount}]}" == "${list}" ]; then
			tmp_cnt=`eval echo "${tmp_cnt}+1"`
		fi
	done
	if [ "${list}" == "TC" ]; then
		GetTCPortNumber 1 ${TC_SSP_IP[${listCount}]} tmp_port
	else
		tmp_port="-1"
	fi
	TC_SSP_NODELOCK="${listCount}.${tmp_port}"
}

# GetNodeLock
#
# Determine the node lock device and its port, if necessary. If the  
# the device can be determined because there is only one TC/SSP device, or a
# single SSP, then choose it.
GetNodeLock() {

	typeset tmp_port
	
	if [ "${SSP_Counter}" != "None" ]; then
		if [ "${SSP_Counter}" != "Many" ]; then
			TC_SSP_NODELOCK="${SSP_Counter}.-1"
		else
			NodeLockTable SSP
		fi
	else
		if [ "${TC_Counter}" != "None" ]; then
			if [ "${TC_Counter}" != "Many" ]; then
				GetTCPortNumber 1 ${TC_SSP_IP[${TC_Counter}]} tmp_port
				TC_SSP_NODELOCK="${TC_Counter}.${tmp_port}"
			else
				NodeLockTable TC
			fi
		else
			echo "You need at least one Terminal Concentrator or System Service Processor"
		fi
	fi
}

# GetNodeInfo
#
# Get the node architecture.  Then allow the user to associate the node with
# a TC or SSP device.
GetNodeInfo() {
	typeset NodeName=$1

	typeset archType
	typeset continueStr="1"
	typeset loopStr

	while [ "${continueStr}" == "1" ] ; do
		archType=$(ckstr -Q \
			-d "other" \
			-p "What type of architecture does ${NodeName} have (E10000|other) [other]?")
		case "${archType}" in
		e|e1|e10|e100|e1000|e10000|E|E1|E10|E100|E1000|E10000)
			archType="E10000"
			if [ "${SSP_Counter}" == "None" ]; then 
				SSP_Counter="${TC_SSP_Counter}"
				loopStr="1"
				while [ ${loopStr} == "1" ]; do
					NewTC_SSPInfo -t SSP
					if [ $? -eq 1 ]; then
						loopStr="0"
					fi
				done
			else
				PrintTCTable -t SSP -h ${NodeName}
			fi
			continueStr="0"
		;;
		o|ot|oth|othe|other|O|OT|OTH|OTHE|OTHER)
			archType="other"
			if [ "${TC_Counter}" == "None" ]; then 
				TC_Counter="${TC_SSP_Counter}"
				loopStr="1"
				while [ ${loopStr} == "1" ]; do
					NewTC_SSPInfo -t TC -h ${NodeName}
					if [ $? -eq 1 ]; then
						loopStr="0"
					fi
				done
			else
				PrintTCTable -t TC -h ${NodeName}
			fi
			continueStr="0"
		;;
		*)
			echo "Please enter E10000 or other."
		;;
		esac
	done
}

#Get Ethernet addresses
# Prompts the user for an ethernet address and ads it to the string 
# containing those values.
GetEthernet() {
	
	typeset tPhys=""

	echo "\nYou will now be prompted for ethernet addresses of"
	echo "the host. There is only one ethernet address for each host"
	echo "regardless of the number of interfaces a host has. You can get"
	echo "this information in one of several ways:"
	echo ""
	echo "1. use the 'banner' command at the ok prompt,"
	echo "2. use the 'ifconfig -a' command (need to be root),"
	echo "3. use ping, arp and grep commands. ('ping exxon; arp -a | grep exxon')"
	echo ""
	echo "Ethernet addresses are given as six hexadecimal bytes separated"
	echo "by colons. (ie, 01:23:45:67:89:ab)\n"

	tPhys=$(ckstr -Q \
	-r '^[0-9a-fA-F]\{1,2\}\:[0-9a-fA-F]\{1,2\}\:[0-9a-fA-F]\{1,2\}\:[0-9a-fA-F]\{1,2\}\:[0-9a-fA-F]\{1,2\}\:[0-9a-fA-F]\{1,2\}$' \
	-p "What is ${FOO}'s ethernet address?" -l 17 \
	-e "Address is in the form of 01:23:45:67:89:ab with hex numbers")
	PHYS[${PHYSCNTR}]="${tPhys}"
	((PHYSCNTR=PHYSCNTR+1))
}

#Get the Names of the Nodes
# For each node in the cluster:
#       assign a name
# For clusters with ethernet interconnect:
#       ask for the private network interface
#       assign ethernet addresses
AssignNodeNames() {

	typeset fooLoop
	typeset fooCheck
	typeset IF0
	typeset IF1
	integer infacecntr
	integer nodecntr
	
	let infacecntr=1
	let PHYSCNTR=1
	let nodecntr=1

	UnSetList2 NODENAMES

	let LOOPCNTR=0
	while (( LOOPCNTR < ${NUMOFNODES} )) ; do
		fooLoop="1"
		while [ "${fooLoop}" == "1" ]; do
			FOO=$(ckstr -Q -d "node${LOOPCNTR}" \
			    -p "What is the hostname of node ${LOOPCNTR} [node${LOOPCNTR}]?"\
			    -r "^[]a-zA-Z0-9_@#%^+=~}:.,-]\{1,\}$" \
			    -e "Hostnames should not contain spaces or special characters")
			fooCheck=`echo "${NODENAMES[*]}" | grep -w "${FOO}"`
			if [ -z "${fooCheck}" ]; then
				fooLoop="0"
			else
				print "	ERROR:" ${FOO} "is already a name for a node."
			fi
		done
		NODENAMES[${nodecntr}]="${FOO}"
		((nodecntr += 1))

		if [[ "${NETIFTYPE}" == "ether" ]] ; then
			IF0=$(ckstr -Q \
			-d ${DIFN} \
			-p "What is ${FOO}'s first private network interface [${DIFN}]?")
			IF1=$(ckstr -Q \
			-d ${DIFM} \
			-p "What is ${FOO}'s second private network interface [${DIFM}]?")
			INFACE[${infacecntr}]="${IF0}"
			((infacecntr += 1))
			INFACE[${infacecntr}]="${IF1}"
			((infacecntr += 1))
			GetEthernet
		else
			INFACE[${infacecntr}]="${DIFN}"
			((infacecntr += 1))
			INFACE[${infacecntr}]="${DIFM}"
			((infacecntr += 1))
		fi
		(( LOOPCNTR = LOOPCNTR + 1 ))
	done
}

#Get the number of Nodes
# ask for total number of nodes, and then the number of active nodes
# 2-node active cluster will need to select the share CCD partition
AssignNumOfNodes() {
	
	integer numLoop=0

	while [[ "${numLoop}" -eq 0 ]] ; do

#		Currently, a cluster must have 1-4 nodes.
		NUMOFNODES=$(ckstr -Q -r "^[1-4]$" -d 4 \
			-p "How many potential nodes will ${CLUSTERNAME} have [4]?" \
			-e "There can only be 1-4 potential nodes.")

		#indicate a CCD
		if ! (( PDBAPPS & (1 << 7) )); then
			let PDBAPPS=$((PDBAPPS+(1 << 7)))
		fi
#
#	Select the number of active nodes since now we will install all the time
#	with 4 nodes for upgrade purpose
#
		NUMNODEACTIVE=$(ckstr -Q -r "^[1-9]$" -d ${NUMOFNODES} \
		-p "How many of the initially configured nodes will be active [${NUMOFNODES}]?" \
		-e "There can only be 1-${NUMOFNODES} active nodes.")

#	Make sure that there are not more active nodes than potential nodes
		if [[ ${NUMNODEACTIVE} -gt 0 && \
		    ${NUMNODEACTIVE} -le ${NUMOFNODES} ]] ; then
			let numLoop=1
		else
			echo "	ERROR: You must have at least one active node"
			echo "\tand the number of active nodes must be less"
			echo "\tthan or equal to the number of potential nodes."
		fi
	done
#	if 2-node active cluster 
#	we need to select the share CCD partition
	CCDDEVICE="none"
#
# Shared ccd volumes are not support with SDS.   Yet, we don't
# yet know whether or not SDS or VM will be configured as the volume
# manager.  To best prevent users from inadvertantly configuring a shared
# ccd on SDS systems, shared ccd configuration must now be done as an
# independent operation, using scconf(1m).
#
# jhc - 04/24/98
#
#	if [[ ${NUMNODEACTIVE} -eq 2 ]] ;  then
#		SelectSharedCCD
#	fi
}

#Get the Cluster name
# check to see if old user scripts exist and if so, remove these.
AssignClusterName() {

	typeset dummy=""
	typeset dOpt=""

	if [ -n "${CLUSTERNAME}" ]; then
		dOpt="-d ${CLUSTERNAME}"
	fi
	CLUSTERNAME=$(ckstr -Q -p "What is the name of the cluster?" \
		${dOpt} \
		-r "^[]a-zA-Z0-9_@#%^+=~}:.,-]\{1,\}$" \
		-e "The cluster name should not contain spaces or special characters")

}

#Install NETIF packages
InstallNETIF() {

	typeset tmpInteractive

	echo ""
	tmpInteractive="${INTERACTIVE}"
	INTERACTIVE="no"
        if [ "${NETIFTYPE}" == "SCI" ] ; then
		if [ -n "${SCIListU[*]}" ]; then
			echo "Installing SCI Network Interface packages."
			GetMediaLocation "Network Interface Packages"
	                InstallList SCIListU
			ReInit
		else 
			echo "SCI Network Interface packages are already installed."
		fi
        else
		if [ -n "${SMAListU[*]}" ]; then
			echo "Installing ethernet Network Interface packages."
			GetMediaLocation "Network Interface Packages"
                	InstallList SMAListU
			ReInit
		else
			echo "Ether Network Interface packages are already installed."
		fi
        fi
	INTERACTIVE="${tmpInteractive}"
}
#! /usr/bin/ksh
#
# ident	"@(#)sclhosts_subroutines.ksh	1.4	01/03/28 SMI"
#
# Copyright (c) 1998 by Sun Microsystems, Inc.
# All rights reserved.
#

############################################################################
############################################################################
##
## sclhosts_subroutines
##
##	Functions:
##
##		sclhosts_initialize
##			sclhosts_setsubnets
##			sclhosts_nafo_initialize
##			sclhosts_add
##				sclhosts_list
##			sclhosts_nafo_initialize
##				sclhosts_nafo_print
##		sclhosts_change
##			sclhosts_initialize
##				sclhosts_setsubnets
##				sclhosts_nafo_initialize
##					sclhosts_nafo_print
##				sclhosts_add
##					sclhosts_list
##			sclhosts_add
##				sclhosts_list
##				sclhosts_setsubnets
##				sclhosts_nafo_initialize
##					sclhosts_nafo_print
##			sclhosts_remove
##			sclhosts_list
##		sclhosts_nafo_initialize
##			sclhosts_nafo_print
##		sclhosts_nafo_change
##			sclhosts_nafo_initialize
##				sclhosts_nafo_print
##			sclhosts_nafo_print
##
##	Other functions:
##
##		prompt_yesno
##		setnodenames
##
############################################################################
############################################################################

###
#
# prompt_yesno "prompt" default
#
#	prompt  - the guts of the prompt
#	default - must be ${YES} or ${NO} or "none"
#
#	In the C locale (or any locale where "${YES} is yes" and
#	"${NO} is no"), the user may type y, yes, Y, YES, n, no, N, NO;
#	otherwise, the response must be ${YES} or ${NO}.
#	Function will print "${YES}" or "${NO}" on stdout
#	once user has responded correctly.
#
#	I/O uses file descriptors 3 and 4 for stdin/stdout.  Response
#	is printed on stdout (fd 1).
#
#	Return:
#		zero		Success
#		non-zero	Failure or user typed ^D
#
prompt_yesno()
{
	typeset prompt
	typeset default
	typeset foo
	typeset c

	if [ $# -ne 2 ]; then
		printf "$(gettext 'Internal error - bad call to prompt_yesno().')\n" >&2
		return 1
	fi
	if [ "$2" != "${YES}" -a "$2" != "${NO}" -a "$2" != "none" ]; then
		printf "$(gettext 'Internal error - bad call to prompt_yesno().')\n" >&2
		return 1
	fi

	prompt="$1 (${YES}/${NO})"
	default="$2"
	c=

	case ${default} in
	"${YES}" | "${NO}")
		prompt="${prompt} [${default}]?"
		;;

	"none")
		default=
		prompt="${prompt}?"
		;;
	esac

	c=
	while [ -z "${c}" ]
	do
		printf "${prompt}  " >&4
		read c <&3
		if [ $? -ne 0 ]; then		# typed ^D
			printf "\n" >&4
			return 1
		fi
		if [ -z "${c}" ]; then
			c=${default}
		fi
		if [ "${YES}" = "yes" -a "${NO}" = "no" ]; then
			case ${c} in
			yes | y | YES | Y)
				c="${YES}"
				;;

			no | n | NO | N)
				c="${NO}"
				;;

			*)
				c=
				;;
			esac
		else
			case ${c} in
			"${YES}")
				c="${YES}"
				;;

			"${NO}")
				c="${NO}"
				;;

			*)
				c=
				;;
			esac
		fi

	done
	printf "${c}"

	return 0
}

###
#
# setnodenames
#
#	Set or reset the NODENAMES array from the cdb file.
#
#	Return:
#		Zero		is always returned
#
#		On success, "NODENAMES" is set.
#		On failure or no node names in cdb, "NODENAMES" is cleared.
#
setnodenames()
{
	integer i
	integer j

	set -A NODENAMES ""

	i=$(${CDBMATCH} cluster.number.nodes ${CONFIGDIR}/${CLUSTERNAME}.cdb 2>/dev/null)
	j=0
	while [ ${j} -lt ${i} ]
	do
		NODENAMES[${j}]=$(${CDBMATCH} cluster.node.${j}.hostname ${CONFIGDIR}/${CLUSTERNAME}.cdb 2>/dev/null)
		((j += 1))
	done
}

###
#
# sclhosts_initialize
#
#	Initialize the list of logical hosts for the cluster.
#	This should only be called when installing, or initializing,
#	a cluster for the first time.  The cluster may not be
#	"RUNNING" and there must be NO registered data services.
#	If any logical hosts are already configured, the user is
#	warned and asked to agree to the deletion of all logical
#	hosts configuration data before continuing.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
sclhosts_initialize()
{
	typeset prompt
	typeset answer
	typeset lhost
	integer lhostnum
	integer status
	typeset i
	typeset foo
	typeset lhostslist

	set -A lhostslist ""

	#
	# make sure that CLUSTERNAME and NODENAMES are set
	#
	if [ -z "${CLUSTERNAME}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "CLUSTERNAME" >&2
		return 1
	fi
	if [ -z "${NODENAMES[*]}" ] ||
	    [ $(set -- ${NODENAMES[*]}; echo $#) -lt 2 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "NODENAMES" >&2
		return 1
	fi

	#
	# verify that the cluster is NOT RUNNING
	#
    	if [ "${RUNNING}" != "no" ]; then
		printf "$(gettext 'Internal error - %s is running.')\n" "clustd" >&2
		return 1
	fi

	#
	# make sure that there is an HA ccd file on this host
	#
	if [ ! -f ${CONFIGDIR}/${HACCDFILE} ]; then
		printf "$(gettext 'Cannot find \"%s\".')\n" "${CONFIGDIR}/${HACCDFILE}" >&2
		printf "$(gettext 'Make sure that \"%s\" has been correctly installed.')\n" "${PKG_SCCF}" >&2
		return 1
	fi

	#
	# See if any logical hosts are already configured
	#
	grep ^${HACCDLOGHOST}: ${CONFIGDIR}/${HACCDFILE} >/dev/null 2>&1
	if [ $? -eq 0 ]; then

		# See if any data services are registered
		grep ^${HACCDDS}: ${CONFIGDIR}/${HACCDFILE} >/dev/null 2>&1
		if [ $? -eq 0 ]; then
			printf "$(gettext 'Unable to re-initialize logical hosts while data services are registered.')\n" >&2
			return 1
		fi

		# OK to wipe out old logical hosts data?
		printf "\n"
		printf "$(gettext 'WARNING:  One or more logical hosts are already configured!')\n"
		printf "$(gettext 'WARNING:  Re-initialization will delete the configuration!')\n"
		printf "\n"
		prompt=$(gettext 'Are you sure you want to continue with re-initialization')
		answer=$(prompt_yesno "${prompt}" "${NO}")
		if [ "${answer}" != "${YES}" ]; then
			return 0
		fi
		printf "\n"

		# delete all of the old logical hosts data and CCD_CHK
		sed \
			-e "/^${HACCDLOGHOST}:/ d" \
			-e "/^${HACCDLOGHOST_MSTATE}:/ d" \
			-e "/^${HACCDLOGIP}:/ d" \
			-e "/^CCD_CHK:/ d" \
		<${CONFIGDIR}/${HACCDFILE} >${CONFIGDIR}/${HACCDFILE}.tmp.$$
		if [ $? -ne 0 ]; then
			printf "$(gettext 'Unable to reset \"%s\".')\n" "${HACCDFILE}" >&2
			return 1
		fi
		# add new CCD_CHK back in
		ccdadm -x ${CONFIGDIR}/${HACCDFILE}.tmp.$$
		if [ $? -ne 0 ]; then
			printf "$(gettext 'Unable to reset \"%s\" - checksum generation failed.')\n" "${HACCDFILE}" >&2
			return 1
		fi
		mv ${CONFIGDIR}/${HACCDFILE}.tmp.$$ ${CONFIGDIR}/${HACCDFILE}
		if [ $? -ne 0 ]; then
			printf "$(gettext 'Unable to reset \"%s\" - rename failed.')\n" "${HACCDFILE}" >&2
			return 1
		fi
	fi

	#
	# All LOGIP data has been cleared from the ccd file - reset LOGIFNUM
	#
	LOGIFNUM=1

	#
	# Set up the SUBNETS array
	#
	sclhosts_setsubnets
	if [ -z "${SUBNETS[0]}" ]; then
		return 1
	fi
	sclhosts_nafo_initialize
	if [ $? -ne 0 ]; then
		set -A SUBNETS ""
		return 1
	fi

	#
	# Add logical hosts
	#
	lhostnum=0
	lhostslist=
	while :
	do
		# enter the list of logical hosts
		printf "\n"
		printf "$(gettext 'Enter the list of logical hosts you want to add (one per line):')\n"
		printf "\n"
		while :
		do
			printf "\t$(gettext 'Logical host (^D to finish):')  "
			lhost=
			foo=
			read lhost foo
			if [ $? -ne 0 ]; then
				printf "\n"
				break
			fi
			if [ -z "${lhost}" ]; then
				continue
			fi
			if [ "${foo}" ]; then
				printf "\n$(gettext 'Please enter only one name per line!')\n\n"
				continue
			fi
			for i in ${lhostslist[*]}
			do
				if [ "${i}" = "${lhost}" ]; then
					printf "\n$(gettext '\"%s\" already entered!')\n\n"
					continue 2
				fi
			done

			lhostslist[${lhostnum}]=${lhost}
			((lhostnum += 1))
		done

		# verify that the list is correct
		printf "\n"
		printf "$(gettext 'The list of logical hosts is:')\n"
		printf "\n"
		for i in ${lhostslist[*]}
		do
			printf "\t${i}\n"
		done
		if [ -z "${lhostslist[*]}" ]; then
			printf "\t<$(gettext 'none')>\n"
		fi
		printf "\n"
		prompt="$(gettext 'Is this list correct')"
		answer=$(prompt_yesno "${prompt}" "${YES}")
		if [ $? -ne 0 ]; then		# probably typed ^D
			printf "\n"
			return 0
		fi
		if [ "${answer}" = "${YES}" ]; then
			break
		else
			set -A lhostslist ""
		fi
	done

	for i in ${lhostslist[*]}
	do
		sclhosts_add ${i}
		status=$?
		if [ ${status} -ne 0 ]; then
			return ${status}
		fi
	done

	return 0
}

###
#
# sclhosts_nafo_initialize
#
#	Initialize the list of logical hosts for the cluster.
#	This should only be called when installing, or initializing,
#	a cluster for the first time.
#
#	If the "pnmconfig" file already exists, the user is
#	warned before asking if it is okay to continue.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
sclhosts_nafo_initialize()
{
	typeset node
	typeset prompt
	typeset default
	typeset answer
	typeset nafoctlr
	typeset line

	integer s
	integer status
	integer nafogroup

	#
	# make sure that RUNNING, NODENAMES, and LOCALHOSTNAME are correctly set
	#
	if [ "${RUNNING}" != "yes" ] &&
	    [ "${RUNNING}" != "no" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "RUNNING" >&2
		return 1
	fi
	if [ -z "${NODENAMES[*]}" ] ||
	    [ $(set -- ${NODENAMES[*]}; echo $#) -lt 2 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "NODENAMES" >&2
		return 1
	fi
	if [ -z "${LOCALHOSTNAME}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "LOCALHOSTNAME" >&2
		return 1
	fi

	# LOCALHOSTNAME must be one of the NODENAMES
	status=1
	for node in ${NODENAMES[*]}
	do
		if [ "${node}" = "${LOCALHOSTNAME}" ]; then
			status=0
			break
		fi
	done
	if [ $status -ne 0 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "LOCALHOSTNAME" >&2
		return 1
	fi

	#
	# OK to continue?
	#
	if [ -s "${PNMCONFIG}" ]; then
		prompt=$(gettext 'Re-initialize NAFO on \"%s\" with one ctlr per group')
		prompt=$(printf "${prompt}" "${LOCALHOSTNAME}")
		default="none"
	else
		prompt=$(gettext 'Initialize NAFO on \"%s\" with one ctlr per group')
		prompt=$(printf "${prompt}" "${LOCALHOSTNAME}")
		default=${YES}
	fi
	answer=$(prompt_yesno "${prompt}" "${default}")
	if [ $? -ne 0 ]; then		# probably typed ^D
		printf "\n"
		return 0
	fi
	if [ "${answer}" = "${NO}" ]; then
		if [ ! -s "${PNMCONFIG}" ]; then
			printf "$(gettext 'Remember to run %s on each node after the cluster has started.')\n" "${PNMSET}(1m)"
		fi
		return 0
	fi
	if [ -s "${PNMCONFIG}" ]; then
		printf "\n"
		printf "$(gettext 'The NAFO configuration for \"%s\" is:')\n" "${LOCALHOSTNAME}"
		printf "\n"
		sclhosts_nafo_print
		printf "\n"
		printf "$(gettext 'Re-initializing NAFO will delete this configuration.')\n"
		prompt="$(gettext 'Are you sure that you want to continue')"
		answer=$(prompt_yesno "${prompt}" "none")
		if [ "${answer}" = "${NO}" ]; then
			return 0
		fi
		printf "\n"
	fi

	#
	# Set up the SUBNETS array, if it has not already been done
	#
	if [ -z "${SUBNETS[0]}" ]; then
		sclhosts_setsubnets
		if [ -z "${SUBNETS[0]}" ]; then
			return 1
		fi
	fi

	#
	# If the cluster is not running, remove old PNM rows from ccd file.
	#
    	if [ "${RUNNING}" = "no" ] &&
	    [ -f ${CONFIGDIR}/${HACCDFILE} ]; then
		sed \
			-e "/^${HACCDPNM}:/ d" \
			-e "/^CCD_CHK:/ d" \
		<${CONFIGDIR}/${HACCDFILE} >${CONFIGDIR}/${HACCDFILE}.tmp.$$
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Failed to update %s!')\n\n" "${HACCDFILE}" >&2
			rm -f ${CONFIGDIR}/${HACCDFILE}.tmp.$$
			return 1
		fi

		# add new CCD_CHK back in
		ccdadm -x ${CONFIGDIR}/${HACCDFILE}.tmp.$$
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Failed to update %s!')\n\n" "${HACCDFILE}" >&2
			rm -f ${CONFIGDIR}/${HACCDFILE}.tmp.$$
			return 1
		fi

		# rename
		mv ${CONFIGDIR}/${HACCDFILE}.tmp.$$ ${CONFIGDIR}/${HACCDFILE}
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Failed to update %s!')\n\n" "${HACCDFILE}" >&2
			rm -f ${CONFIGDIR}/${HACCDFILE}.tmp.$$
			return 1
		fi
	fi

	#
	# Write out the new file
	#
	rm -f ${PNMCONFIG}.tmp.$$
	s=0
	nafogroup=0
	nafoctlr=
	while [ "${SUBNETS[${s}]}" ]
	do
		nafoctlr=$(
			set -- ${SUBNETS[${s}]}
			shift 1
			while [ $# -gt 1 ]
			do
				if [ "$1" = "${LOCALHOSTNAME}" ]; then
					echo $2
					break
				fi
				shift 2
			done
	    	)
		if [ -z "${nafoctlr}" ]; then
			printf "\n$(gettext 'Unable to update %s!')\n\n" "${PNMCONFIG}" >&2	
			rm -f ${PNMCONFIG}.tmp.$$
			return 1
		fi
		printf "nafo%d %s\n" ${nafogroup} "${nafoctlr}" >>${PNMCONFIG}.tmp.$$
		((nafogroup += 1))
		((s += 1))
	done
	if [ ! -s ${PNMCONFIG}.tmp.$$ ]; then
		printf "\n$(gettext 'Failed to update %s!')\n\n" "${PNMCONFIG}" >&2
		rm -f ${PNMCONFIG}.tmp.$$
		return 1
	fi

	# Save the original
	if [ -s "${PNMCONFIG}" ]; then
		mv ${PNMCONFIG} ${PNMCONFIG}.save.$$
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Failed to update %s!')\n\n" "${PNMCONFIG}" >&2
			rm -f ${PNMCONFIG}.tmp.$$
			return 1
		fi
	fi

	# Use the tmp file
	mv ${PNMCONFIG}.tmp.$$ ${PNMCONFIG}
	if [ $? -ne 0 ]; then
		printf "\n$(gettext 'Failed to update %s!')\n\n" "${PNMCONFIG}" >&2
		rm -f ${PNMCONFIG}.tmp.$$
		if [ -s "${PNMCONFIG}.save.$$" ]; then
			mv ${PNMCONFIG}.save.$$ ${PNMCONFIG}
		fi
		return 1
	fi

	#
	# kick the pnmd
	#

	# RPC call from pnmset(1m) could timeout
	printf "$(gettext 'Attempting to run %s ... ')" "${PNMSET}"

	# run pnmset
	${PNMSET} -n >/dev/null 2>${SCTMPDIR}/pnmsetlog.$$
	if [ $? -ne 0 ]; then
		printf "$(gettext 'failed')\n"
		if [ -s ${SCTMPDIR}/pnmsetlog.$$ ]; then
			printf "\n"
			printf "$(gettext '%s failed with the following error:')\n\n" "${PNMSET}"
			while read line
			do
				printf "\t%s\n" "${line}"
			done <${SCTMPDIR}/pnmsetlog.$$
			printf "\n"
		else
			printf "\n$(gettext '%s failed!')\n\n" "${PNMSET}"
		fi
		rm -f ${SCTMPDIR}/pnmsetlog.$$
		if [ -s "${PNMCONFIG}.save.$$" ]; then
			mv ${PNMCONFIG}.save.$$ ${PNMCONFIG}
			printf "$(gettext 'Attempting to reset %s ... ')" "${PNMSET}"
			${PNMSET} -n >/dev/null 2>&1
			if [ $? -ne 0 ]; then
				printf "$(gettext 'failed')\n"
			else
				printf "$(gettext 'done')\n"
			fi
		fi
		return 1
	fi
	printf "$(gettext 'done')\n"
	rm -f ${SCTMPDIR}/pnmsetlog.$$
	rm -f ${PNMCONFIG}.save.$$

	return 0
}

###
#
# sclhosts_change
#
#	Display menu for adding, removing, or listing logical hosts
#	within a cluster.  The cluster must be "RUNNING" in order to
#	use this menu for adding or removing logical hosts.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
sclhosts_change()
{
	# menu items when cluster is up
	integer itemAdd
	integer itemRemove

	# menu items when cluster is down
	integer itemInit

	# menu items regardless of whether cluster is up or down
	integer itemList
	integer itemReturn
	integer itemQuit

	typeset option
	typeset foo
	typeset lhost
	typeset lhosts

	#
	# make sure that CLUSTERNAME, NODENAMES, and RUNNING are set
	#
	if [ -z "${CLUSTERNAME}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "CLUSTERNAME" >&2
		return 1
	fi
	if [ "${RUNNING}" != "yes" ] &&
	    [ "${RUNNING}" != "no" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "RUNNING" >&2
		return 1
	fi
	if [ -z "${NODENAMES[*]}" ] ||
	    [ $(set -- ${NODENAMES[*]}; echo $#) -lt 2 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "NODENAMES" >&2
		return 1
	fi

	#
	# Loop until "Return" or "Quit"
	#
	while :
	do
		#
		# Show menu
		#

		printf "\n"
		printf "\n"

		# Cluster IS Running
		if [ "${RUNNING}" = "yes" ]; then
			itemAdd=1
			itemRemove=2
			itemList=3
			itemReturn=4
			itemQuit=5

			printf "$(gettext '====== Logical Hosts Configuration ======')\n"
			printf "\n"

			# Add
			printf "$(gettext '%d) Add     - Add a logical host to the cluster.')\n" ${itemAdd}

			# Remove
			printf "$(gettext '%d) Remove  - Remove a logical host from the cluster.')\n" ${itemRemove}

		# Cluster is NOT Running
		else
			itemInit=1
			itemList=2
			itemReturn=3
			itemQuit=4

			printf "$(gettext '===== Logical Hosts Initialization ======')\n"
			printf "\n"

			# Re-initialize
			printf "$(gettext '%d) Init    - Re-initialize logical hosts.')\n" ${itemInit}
		fi

		# List
		printf "$(gettext '%d) List    - List the logical hosts in the cluster.')\n" ${itemList}

		# Return and Quit
		printf "\n"
		printf "$(gettext '%d) Close   - Return to the previous menu.')\n" ${itemReturn}
		printf "$(gettext '%d) Quit    - Exit.')\n" ${itemQuit}
		printf "\n"
		printf "\n"

		#
		# Prompt for user to respond with menu option
		#
		while :
		do
			printf "$(gettext 'Please choose an option:  ')"

			option=
			foo=
			read option foo
			if [ $? -ne 0 ]; then		# typed ^D
				printf "\n"
				return 0
			fi
			if [ -z "${option}" ] ||
			    [ "${foo}" ]; then
				continue
			fi

			# Convert from option number to option name
			if [ "${RUNNING}" = "yes" ]; then
				case ${option} in
				${itemAdd}) option="Add" ;;
				${itemRemove}) option="Remove" ;;
				${itemList}) option="List" ;;
				${itemReturn}) option="Return" ;;
				${itemQuit}) option="Quit" ;;
				*) option= ;;
				esac
			else
				case ${option} in
				${itemInit}) option="Init" ;;
				${itemList}) option="List" ;;
				${itemReturn}) option="Return" ;;
				${itemQuit=}) option="Quit" ;;
				*) option= ;;
				esac
			fi
			if [ -z "${option}" ]; then
				printf "$(gettext 'Unknown option!')\n\n"
				continue
			fi
			break
		done

		printf "\n"
		printf "\n"

		#
		# Switch on option
		#
		case "${option}" in

		# Add a logical host
		Add)
			if [ -z "${SUBNETS[0]}" ]; then
				sclhosts_setsubnets
				if [ ! -z "${SUBNETS[0]}" ]; then
					sclhosts_nafo_initialize
					if [ $? -ne 0 ]; then
						set -A SUBNETS ""
					fi
				fi
			fi
			if [ ! -z "${SUBNETS[0]}" ]; then
				sclhosts_add
			fi
			;;

		Init)
			set -A SUBNETS ""
			sclhosts_initialize
			;;

		# Remove a logical host
		Remove)
			sclhosts_remove
			;;

		# List the logical hosts
		List)
			# get the list
			lhosts=$(sclhosts_list)

			# print the list
			printf "\n"
			printf "$(gettext 'The list of logical hosts is:')\n"
			printf "\n"
			if [ -z "${lhosts}" ]; then
				printf "\t<$(gettext 'none')>\n"
			else
				for lhost in ${lhosts}
				do
					printf "\t${lhost}\n"
				done
			fi
			printf "\n"
			printf "$(gettext 'Hit <RETURN> to continue:')  "
			read foo
			if [ $? -ne 0 ]; then
				printf "\n"
			fi
			;;

		# Return to the previous menu
		Return)
			return 0
			;;

		# Quit
		Quit)
			exit 0
			;;
		esac
	done

	return 0
}

###
#
# sclhosts_nafo_change
#
#	Display menu for initializing or listing the NAFO configuration
#	for the node from which this is run.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
sclhosts_nafo_change()
{
	# menu items
	integer itemInit=1
	integer itemList=2
	integer itemReturn=3
	integer itemQuit=4

	typeset option
	typeset node

	integer status

	#
	# make sure that RUNNING, NODENAMES, and LOCALHOSTNAME are correctly set
	#
	if [ "${RUNNING}" != "yes" ] &&
	    [ "${RUNNING}" != "no" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "RUNNING" >&2
		return 1
	fi
	if [ -z "${NODENAMES[*]}" ] ||
	    [ $(set -- ${NODENAMES[*]}; echo $#) -lt 2 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "NODENAMES" >&2
		return 1
	fi

	# LOCALHOSTNAME must be one of the NODENAMES
	status=1
	for node in ${NODENAMES[*]}
	do
		if [ "${node}" = "${LOCALHOSTNAME}" ]; then
			status=0
			break
		fi
	done
	if [ $status -ne 0 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "LOCALHOSTNAME" >&2
		return 1
	fi

	#
	# Loop until "Return" or "Quit"
	#
	while :
	do
		#
		# Show menu
		#

		printf "\n"
		printf "\n"

		printf "$(gettext '========== NAFO Configuration ===========')\n"
		printf "\n"

		# Initialize
		if [ -f "${PNMCONFIG}" ]; then
			printf "$(gettext '%d) Init    - Re-initialize NAFO for this node.')\n" ${itemInit}
		else
			printf "$(gettext '%d) Init    - Initialize NAFO for this node.')\n" ${itemInit}
		fi

		# List
		printf "$(gettext '%d) List    - Show the NAFO configuration for this node.')\n" ${itemList}

		# Return and Quit
		printf "\n"
		printf "$(gettext '%d) Close   - Return to the previous menu.')\n" ${itemReturn}
		printf "$(gettext '%d) Quit    - Exit.')\n" ${itemQuit}
		printf "\n"
		printf "\n"

		#
		# Prompt for user to respond with menu option
		#
		while :
		do
			printf "$(gettext 'Please choose an option:  ')"

			option=
			foo=
			read option foo
			if [ $? -ne 0 ]; then		# typed ^D
				printf "\n"
				return 0
			fi
			if [ -z "${option}" ] ||
			    [ "${foo}" ]; then
				continue
			fi

			# Convert from option number to option name
			case ${option} in
			${itemInit}) option="Init" ;;
			${itemList}) option="List" ;;
			${itemReturn}) option="Return" ;;
			${itemQuit}) option="Quit" ;;
			*) option= ;;
			esac
			if [ -z "${option}" ]; then
				printf "$(gettext 'Unknown option!')\n\n"
				continue
			fi
			break
		done

		printf "\n"
		printf "\n"

		#
		# Switch on option
		#
		case "${option}" in

		# Initialize NAFO configuration for this node
		Init)
			set -A SUBNETS ""
			sclhosts_nafo_initialize
			if [ $? -ne 0 ]; then
				set -A SUBNETS ""
			fi
			;;

		# List the logical hosts
		List)
			printf "\n"
			printf "$(gettext 'The NAFO configuration for \"%s\" is:')\n" "${LOCALHOSTNAME}"
			printf "\n"
			sclhosts_nafo_print
			printf "\n"
			printf "$(gettext 'Hit <RETURN> to continue:')  "
			read foo
			if [ $? -ne 0 ]; then
				printf "\n"
			fi
			;;

		# Return to the previous menu
		Return)
			return 0
			;;

		# Quit
		Quit)
			exit 0
			;;
		esac
	done

	return 0
}

###
#
# sclhosts_setsubnets
#
#	Set up the "SUBNETS" array for each subnet served by the
#	cluster.  Each array element has the following format:
#
#		"<subnet> <<node> <netctlr>> <<node> <netctlr>>..."
#
#	The "subnet" name can actually be anything;  it is not
#	checked against /etc/networks and does not become part of
#	the configuration;  it is used as a convenient point of
#	reference when prompting the user.  "subnet" is set to "-"
#	for the primary net.
#
#	Return:
#		Zero		is always returned
#
#		On success, "SUBNETS" is set.
#		On failure, "SUBNETS" is cleared.
#
sclhosts_setsubnets()
{
	typeset node
	typeset netctlr
	typeset netctlrtype
	typeset prompt
	typeset answer
	typeset foo

	integer s=0
	integer s2

	# clear the "SUBNETS" array
	set -A SUBNETS ""

	#
	# make sure that NODENAMES is set
	#
	if [ -z "${NODENAMES[*]}" ] ||
	    [ $(set -- ${NODENAMES[*]}; echo $#) -lt 2 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "NODENAMES" >&2
		return 0
	fi

	#
	# get the netctlrs for the primary public net
	#
	s=0
	SUBNETS[${s}]="-"
	for node in ${NODENAMES[*]}
	do
		while :
		do
			printf "$(gettext 'What is the primary public network controller for "\%s\"?  ')" "${node}"
			read netctlr foo
			if [ $? -ne 0 ]; then		# typed ^D
				printf "\n"
				set -A SUBNETS ""
				return 0
			fi
			if [ -z "${netctlr}" ] ||
			    [ "${foo}" ]; then
				continue
			fi
			netctlrtype=$(echo ${netctlr} | sed -n 's/^\([^0-9][^0-9]*\)[0-9][0-9]*$/\1/p')
			if [ -z "${netctlrtype}" ]; then
				printf "\n"
				printf "$(gettext 'WARNING:  Unrecognized network controller - \"%s\".')\n" "${netctlr}"
				prompt="$(gettext 'WARNING:  Do you want to use it anyway')"
				answer=$(prompt_yesno "${prompt}" "${NO}")
				printf "\n"
				if [ "${answer}" = "${NO}" ]; then
					continue
				fi
			elif [ ! -c /dev/${netctlrtype} ]; then
				printf "\n"
				printf "$(gettext 'WARNING:  Unrecognized network controller type - \"%s\".')\n" "${netctlr}"
				prompt="$(gettext 'WARNING:  Do you want to use it anyway')"
				answer=$(prompt_yesno "${prompt}" "${NO}")
				printf "\n"
				if [ "${answer}" = "${NO}" ]; then
					continue
				fi
			fi
			break
		done
		SUBNETS[${s}]="${SUBNETS[${s}]} ${node} ${netctlr}"
	done
	
	#
	# Get the names of the secondary subnets
	#
	prompt="$(gettext 'Does the cluster serve any secondary public subnets')"
	answer=$(prompt_yesno "${prompt}" "${NO}")
	if [ $? -ne 0 ]; then		# probably typed ^D
		printf "\n"
		set -A SUBNETS ""
		return 0
	fi
	if [ "${answer}" = "${YES}" ]; then
		while :
		do
			# enter the list of additional subnets
			printf "\n"
			printf "$(gettext 'Please enter a unique name for each of these additional subnets:')\n"
			printf "\n"
			while :
			do
				printf "\t$(gettext 'Subnet name (^D to finish):')  "
				read subnetname foo
				if [ $? -ne 0 ]; then	# typed ^D
					printf "\n"
					break
				fi
				if [ -z "${subnetname}" ]; then
					continue
				fi
				if [ "$foo" ]; then
					printf "\n$(gettext 'Please enter only one name per line!')\n\n"
					continue
				fi
				s2=1
				while [ "${SUBNETS[${s2}]}" ]
				do
					foo=$(set -- ${SUBNETS[${s2}]}; echo $1)
					if [ "${foo}" = "${subnetname}" ]; then
						printf "\n$(gettext '\"%s\" already entered!')\n\n" "${subnetname}"
						continue 2
					fi
					((s2 += 1))
				done
				((s += 1))
				SUBNETS[${s}]=${subnetname}
			done

			# verify that the list is correct
			printf "\n"
			printf "$(gettext 'The list of secondary public subnets is:')\n"
			printf "\n"
			s2=1
			while [ "${SUBNETS[${s2}]}" ]
			do
				foo=$(set -- ${SUBNETS[${s2}]}; echo $1)
				printf "\t${foo}\n"
				((s2 += 1))
			done
			if [ ${s2} -eq 1 ]; then
				printf "\t<$(gettext 'none')>\n"
			fi
			printf "\n"
			prompt="$(gettext 'Is this list correct')"
			answer=$(prompt_yesno "${prompt}" "${YES}")
			if [ $? -ne 0 ]; then		# probably typed ^D
				printf "\n"
				set -A SUBNETS ""
				return 0
			fi
			if [ "${answer}" = "${YES}" ]; then
				break
			else
				s=0
				s2=1
				while [ "${SUBNETS[${s2}]}" ]
				do
					SUBNETS[${s2}]=
					((s2 += 1))
				done
			fi
		done
	fi

	#
	# get the netctlrs for the secondary subnets
	#
	s=1
	while [ "${SUBNETS[${s}]}" ]
	do
		subnetname=$(set -- ${SUBNETS[${s}]}; echo $1)
		printf "\n"
		printf "$(gettext 'For subnet \"%s\" ...')\n" "${subnetname}"
		for node in ${NODENAMES[*]}
		do
			while :
			do
				printf "\t$(gettext 'What network controller is used for "\%s\"?')  " "${node}"
				read netctlr foo
				if [ $? -ne 0 ]; then		# typed ^D
					printf "\n"
					continue
				fi
				if [ -z "${netctlr}" ] ||
				    [ "${foo}" ]; then
					continue
				fi
				netctlrtype=$(echo ${netctlr} | sed -n 's/^\([^0-9][^0-9]*\)[0-9][0-9]*$/\1/p')
				if [ -z "${netctlrtype}" ]; then
					printf "\n"
					printf "$(gettext 'WARNING:  Unrecognized network controller - \"%s\".')\n" "${netctlr}"
					prompt="$(gettext 'WARNING:  Do you want to use it anyway')"
					answer=$(prompt_yesno "${prompt}" "${NO}")
					printf "\n"
					if [ "${answer}" = "${NO}" ]; then
						continue
					fi
				elif [ ! -c /dev/${netctlrtype} ]; then
					printf "\n"
					printf "$(gettext 'WARNING:  Unrecognized network controller type - \"%s\".')\n" "${netctlr}"
					prompt="$(gettext 'WARNING:  Do you want to use it anyway')"
					answer=$(prompt_yesno "${prompt}" "${NO}")
					printf "\n"
					if [ "${answer}" = "${NO}" ]; then
						continue
					fi
				fi

				# check for already used netctlrs
				s2=0
				foo=
				while [ "${SUBNETS[${s2}]}" ]
				do
					foo=$(
						typeset netname

						set -- ${SUBNETS[${s2}]}
						netname=$1
						shift 1
						while [ $# -gt 1 ]
						do
							if [ "$1" = "${node}" ]  &&
							    [ "$2" = "${netctlr}" ]; then
								echo "${netname}"	
								break
							fi
							shift 2
						done
				    	)
					if [ "${foo}" ]; then
						break
					fi
					((s2 += 1))
				done
				if [ "${foo}" = "-" ]; then
					printf "\n$(gettext '\"%s\" is already used for the primary subnet!')\n\n" "${netctlr}"
					continue
				fi

				if [ "${foo}" ]; then
					printf "\n$(gettext '\"%s\" is already used for subnet \"%s\"!')\n\n" "${netctlr}" "${foo}"
					continue
				fi
				break
			done
			SUBNETS[${s}]="${SUBNETS[${s}]} ${node} ${netctlr}"
		done
		((s += 1))
	done
	printf "\n"

	return 0
}

###
#
# sclhosts_list
#
#	Print a list of all configured logical hosts to stdout.
#
#	Logical hosts are listed regardless of whether or not the
#	cluster is "RUNNING".  However, if the cluster is not
#	"RUNNING", only the local CCD file is consulted.
#
#	Return:
#		Zero		Zero is always returned
#
sclhosts_list()
{
	typeset selectcmd
	typeset loghost_row
	typeset lname

	#
	# make sure that CLUSTERNAME and RUNNING are set
	#
	if [ -z "${CLUSTERNAME}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "CLUSTERNAME" >&2
		return 1
	fi
	if [ "${RUNNING}" != "yes" ] &&
	    [ "${RUNNING}" != "no" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "RUNNING" >&2
		return 1
	fi

	#
	# If RUNNING, get data from the CCD;   otherwise, grep the CCD file
	#
	if [ "${RUNNING}" = "yes" ]; then
		selectcmd="${SCCCD} ${CLUSTERNAME} ${HACCDLOGHOST} query lname \"\""
	else
		selectcmd="grep ^${HACCDLOGHOST}: ${CONFIGDIR}/${HACCDFILE}"
	fi
		
	eval ${selectcmd} 2>/dev/null | while read loghost_row
	do
		lname=$(IFS=: ; set -- ${loghost_row}; echo $2)
		if [ "${lname}" ]; then
			printf "%s\n" "${lname}"
		fi
	done

	return 0
}

###
#
# sclhosts_nafo_print
#
#	Print the nafo configuration to stdout.
#
#	This may be run regardless of whether or not the cluster is
#	running.
#
#	Return:
#		Zero		Zero is always returned
#
sclhosts_nafo_print()
{
	typeset nafogroup
	typeset nafoctlrs

	if [ -s "${PNMCONFIG}" ]; then
		while read nafogroup nafoctlrs
		do
			case ${nafogroup} in
			'#'* | '')	# ignore comments and empty lines
					continue
					;;
			esac

			# skip lines w/ no ctlrs
			if [ -z "${nafoctlrs}" ]; then
				continue
			fi
			printf "\t%8-s - %s\n" "${nafogroup}" "${nafoctlrs}"
		done < ${PNMCONFIG}
	fi

	return 0
}

###
#
# sclhosts_add [lhost]
#
#	Add the given logical host name ("lhost") to the cluster.
#	If "lhost" is not given, the user is prompted for the logical
#	host to add.  The user is engaged in a dialog for gathering all the
#	information necessary for configuring a logical host.  The
#	data base is then updated.
#
#	Logical hosts may be added regardless of whether or not the
#	cluster is "RUNNING".   However, if the cluster is not "RUNNING",
#	only the local CCD file is consulted and updated.   In this
#	state, it is the user's responsibility to duplicate the addition
#	of logical hosts on each node.  If the cluster is "RUNNING",
#	logical hosts can be added from only one node;  the updates
#	are then propogated throughout the cluster by the CCD.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
sclhosts_add()
{
	typeset lhost=$1

	integer nodenum
	integer r
	integer s

	typeset node
	typeset subnet
	typeset netname
	typeset netctlr
	typeset diskgroup
	typeset autofailback="-m"
	typeset nodeslist
	typeset netnameslist
	typeset scconf_args
	typeset nodelist_field
	typeset dglist_field
	typeset iplist_field
	typeset mode_field
	typeset iflist_field
	typeset loghost_row
	typeset logip_rows
	typeset foo
	typeset i

	#
	# make sure that CLUSTERNAME, NODENAMES, RUNNING, and SUBNETS are set
	#
	if [ -z "${CLUSTERNAME}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "CLUSTERNAME" >&2
		return 1
	fi
	if [ "${RUNNING}" != "yes" ] &&
	    [ "${RUNNING}" != "no" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "RUNNING" >&2
		return 1
	fi
	if [ -z "${SUBNETS}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "SUBNETS" >&2
		return 1
	fi
	if [ -z "${NODENAMES[*]}" ] ||
	    [ $(set -- ${NODENAMES[*]}; echo $#) -lt 2 ]; then
		printf "$(gettext 'Internal error - %s is not correctly set.')\n" "NODENAMES" >&2
		return 1
	fi

	printf "\n"

	# compile the list of already configured logical hosts
	lhosts=$(sclhosts_list)

	# if not supplied, prompt for the name of the new logical host
	if [ -z "${lhost}" ]; then
		while :
		do
			printf "$(gettext 'What is the name of the new logical host?')  "
			foo=
			read lhost foo
			if [ $? -ne 0 ]; then		# typed ^D
				printf "\n"
				return 0
			fi
			if [ "${foo}" ]; then
				continue
			fi

			# make sure that it is not already configured
			for i in ${lhosts}
			do
				if [ "${i}" = "${lhost}" ]; then
					printf "\n$(gettext '\"%s\" is already configured.')\n\n" "${lhost}"
					continue 2
				fi
			done

			# if lhost is set, exit loop
			if [ "${lhost}" ]; then
				break
			fi
		done
	else
		# make sure that it is not already configured
		for i in ${lhosts}
		do
			if [ "${i}" = "${lhost}" ]; then
				printf "\n$(gettext '\"%s\" is already configured.')\n\n" "${lhost}"
				return 1
			fi
		done
	fi

	#
	# get per node data for this logical host
	#
	nodenum=-1
	set -A nodeslist ""

	#
	# The first node - the default master
	#
	while :
	do
		printf "$(gettext 'What is the name of the default master for \"%s\"?')  " "${lhost}"
		read node foo
		if [ $? -ne 0 ]; then		# typed ^D
			printf "\n"
			return 0
		fi
		if [ -z "${node}" ] ||
		    [ "${foo}"]; then
			continue
		fi
		foo="error"
		for i in ${NODENAMES[*]}
		do
			if [ "${i}" = "${node}" ]; then
				foo=
				break
			fi
		done
		if [ "${foo}" = "error" ]; then
			printf "\n$(gettext 'Unrecognized node name.')\n\n"
			continue
		fi
		((nodenum += 1))
		nodeslist[${nodenum}]=${node}
		break
	done

	#
	# The other nodes
	#

	# only two nodes?
	if [ $(set -- ${NODENAMES[*]}; echo $#) -eq 2 ]; then
		for node in ${NODENAMES[*]}
		do
			if [ "${node}" != "${nodeslist[0]}" ]; then
				nodeslist[1]=${node}
				break
			fi
		done
		nodenum=1

	# more than two nodes
	else

		while :
		do
			# enter the list of nodes
			printf "\n"
			printf "$(gettext 'Enter a list of other nodes capable of mastering \"%s\":')\n" "${lhost}"
			printf "\n"
			while :
			do
				while [ ${nodenum} -eq 0 ]
				do
					printf "\t$(gettext 'Node name:')  "
					read node foo
					if [ $? -ne 0 ] ||
					    [ -z "${node}" ]; then
						printf "\n$(gettext 'You must enter at least one other node name!')\n\n"
						continue
					fi
					break
				done
				while [ ${nodenum} -gt 0 ]
				do
					printf "\t$(gettext 'Node name (^D to finish):')  "
					read node foo
					if [ $? -ne 0 ]; then	# typed ^D
						printf "\n"
						break 2
					fi
					if [ "${node}" ]; then
						break
					fi
				done
				if [ "${foo}"]; then
					printf "\n$(gettext 'Please enter only one name per line!')\n\n"
					continue
				fi

				foo="error"
				for i in ${NODENAMES[*]}
				do
					if [ "${i}" = "${node}" ]; then
						foo=
						break
					fi
				done
				if [ "${foo}" = "error" ]; then
					printf "\n$(gettext 'Unrecognized node name.')\n\n"
					continue
				fi

				if [ "${nodeslist[0]}" = "${node}" ]; then
					printf "\n$(gettext 'The name you gave is the name of the default master!')\n\n"
					continue
				fi
				for i in ${nodeslist[*]}
				do
					if [ "${i}" = "${node}" ]; then
						printf "\n$(gettext 'You already gave this name!')\n\n"
						continue 2
					fi
				done
				((nodenum += 1))
				nodeslist[${nodenum}]=${node}
			done
		
			# verify that the list is correct
			printf "\n"
			printf "$(gettext 'The list that you entered is:')\n"
			printf "\n"
			nodenum=1
			while [ "${nodeslist[${nodenum}]}" ]
			do
				printf "\t${nodeslist[${nodenum}]}\n"
				((nodenum += 1))
			done
			printf "\n"
			prompt="$(gettext 'Is this list correct')"
			answer=$(prompt_yesno "${prompt}" "${YES}")
			if [ $? -ne 0 ]; then		# probably typed ^D
				printf "\n"
				return 0
			fi
			if [ "${answer}" = "${YES}" ]; then
				break
			else
				nodenum=1
				while [ "${nodeslist[${nodenum}]}" ]
				do
					nodeslist[${nodenum}]=
					((nodenum += 1))
				done
				nodenum=0
			fi
		done
	fi

	#
	# Automatic failback disabled (-m option to scconf(1m))? 
	#
	prompt="$(gettext 'Enable automatic failback for \"%s\"')"
	prompt="$(printf "${prompt}" "${lhost}")"
	answer=$(prompt_yesno "${prompt}" "${NO}")
	if [ $? -ne 0 ]; then		# probably typed ^D
		printf "\n"
		return 0
	fi
	if [ "${answer}" = "${YES}" ]; then
		autofailback=
		mode_field=0
	else
		autofailback="-m"
		mode_field=1
	fi

	#
	# Get the list of net names for each subnet
	#
	s=0
	set -A netnameslist ""
	while [ "${SUBNETS[${s}]}" ]
	do
		subnet=$(set -- ${SUBNETS[${s}]}; echo $1)
		if [ "${subnet}" = "-" ]; then
			netname="${lhost}"
		else
			while :
			do
				printf "$(gettext 'What is the net name for \"%s\" on subnet \"%s\"?')  " "${lhost}" "${subnet}"
				read netname foo
				if [ $? -ne 0 ]; then	# typed ^D
					printf "\n"
					return 0
				fi
				if [ -z "${netname}" ] ||
				    [ "${foo}" ]; then
					continue
				fi
				if [ "${lhost}" = "${netname}" ]; then
					printf "\n$(gettext 'This net name is already assigned to the primary net!')\n\n"
					continue
				fi
				for i in ${netnameslist[*]}
				do
					if [ "${i}" = "${netname}" ]; then
						printf "\n$(gettext 'This name was already given!')\n\n"
						continue 2
					fi
				done
				break
			done
		fi
		netnameslist[${s}]=${netname}
		((s += 1))
	done

	#
	# Get the name of the diskgroup
	#
	while :
	do
		printf "$(gettext 'Disk group name for logical host \"%s\" [%s]?')  " "${lhost}" "${lhost}"
		read diskgroup foo
		if [ $? -ne 0 ]; then		# typed ^D
			printf "\n"
			return 0
		fi
		if [ -z "${foo}" ]; then
			if [ -z "${diskgroup}" ]; then
				diskgroup="${lhost}"
			fi
			break
		fi
	done

	#
	# Construct the scconf argument list and ccd rows
	#
	scconf_args="${CLUSTERNAME} -L ${lhost}"
	loghost_row=
	set -A logip_rows ""
	r=0

	# add the nodes list
	nodelist_field=
	for node in ${nodeslist[*]}
	do
		if [ "${nodelist_field}" ]; then
			nodelist_field="${nodelist_field},"
		fi
		nodelist_field="${nodelist_field}${node}"
	done
	scconf_args="${scconf_args} -n ${nodelist_field}"

	# add the diskgroup
	dglist_field=${diskgroup}
	scconf_args="${scconf_args} -g ${dglist_field}"

	# add the logaddrinfo
	iplist_field=
	s=0
	while [ "${SUBNETS[${s}]}" ]
	do
		subnet="${SUBNETS[${s}]}"
		netname="${netnameslist[${s}]}"

		iflist_field=

		for node in ${nodeslist[*]}
		do
			netctlr=$(
				set -- ${subnet}
				shift 1
				while [ $# -gt 1 ]
				do
					if [ "$1" = "${node}" ]; then
						echo "$2"
						break
					fi
					shift 2
				done
			)
			if [ -z "${netctlr}" ]; then
				printf "$(gettext 'Internal error - cannot set \"%s\".')\n" "netctlr" >&2
				return 1
			fi
			if [ "${iflist_field}" ]; then
				iflist_field="${iflist_field},"
			fi
			iflist_field="${iflist_field}${netctlr}"
		done

		if [ -z "${iflist_field}" ]; then
			printf "$(gettext 'Internal error - cannot set controller list.')\n" >&2
			return 1
		fi
		scconf_args="${scconf_args} -i ${iflist_field},${netname}"
		logip_rows[${r}]="${HACCDLOGIP}:${nodelist_field}:${iflist_field}:${netname}:${LOGIFNUM}"
		if [ "${iplist_field}" ]; then
			iplist_field="${iplist_field},"
		fi
		iplist_field="${iplist_field}${LOGIFNUM}"
		((LOGIFNUM += 1))
		((r += 1))
		((s += 1))
	done

	# add auto failback
	scconf_args="${scconf_args} ${autofailback}"

	# finish formatting the loghost row
	loghost_row="${HACCDLOGHOST}:${lhost}:${nodelist_field}:${dglist_field}:${iplist_field}:${mode_field}"

	# OK to update?
	prompt="$(gettext 'Is it okay to add logical host \"%s\" now')"
	prompt="$(printf "${prompt}" "${lhost}")"
	answer=$(prompt_yesno "${prompt}" "${YES}")
	if [ $? -ne 0 ]; then		# probably typed ^D
		printf "\n"
		return 0
	fi
	if [ "${answer}" != "${YES}" ]; then
		return 0
	fi

	#
	# If the cluster is "RUNNING", we use scconf to update the CCD.
	# Otherwise, we edit the local CCD file directly.  Note that
	# this should only happen if the cluster is being initialized!
	#
	if [ "${RUNNING}" = "yes" ]; then
		${SCCONF} ${scconf_args}
		if [ $? -ne 0 ]; then
			printf "\n$(gettext '%s failed to add \"%s\".')\n\n" "${SCCONF}" "${lhost}"
			return 1
		fi
	elif [ "${RUNNING}" = "no" ]; then

		#
		# generate script file to:
		#
		#	- delete the old CCD_CHK (checksum) entry
		#	- add the LOGHOST row
		#	- add the LOGHOST_MSTATE row to turn off maint mode
		#	- add the first LOGIP row (for the primary net)
		#
		cat <<EOF >${SCTMPDIR}/sed.tmp.$$
/CCD_CHK:/ d
/LOGHOST_sync:/ a\\
${loghost_row}
/LOGHOST_MSTATE_sync:/ a\\
${HACCDLOGHOST_MSTATE}:${lhost}:1
/LOGIP_sync:/ a\\
${logip_rows[0]}
EOF

		#
		# append commands to the script to:
		#
		#	- add a LOGIP row for each secondary subnet
		#
		r=1
		while [ "${logip_rows[${r}]}" ]
		do
			cat <<EOF >>${SCTMPDIR}/sed.tmp.$$
/LOGIP_sync:/ a\\
${logip_rows[${r}]}
EOF
			((r += 1))
		done

		# use sed(1) and the new script to generate a temp CCD file
		sed -f ${SCTMPDIR}/sed.tmp.$$ <${CONFIGDIR}/${HACCDFILE} >${CONFIGDIR}/${HACCDFILE}.tmp.$$ 
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Update failed!')\n\n"
			rm -f ${SCTMPDIR}/sed.tmp.$$
			rm -f ${CONFIGDIR}/${HACCDFILE}.tmp.$$
			return 1
		fi

		# remove the sed script
		rm -f ${SCTMPDIR}/sed.tmp.$$

		# generate a new checksum for the ccdfile
		ccdadm -x ${CONFIGDIR}/${HACCDFILE}.tmp.$$
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Update failed - unable to generate new checksum!')\n\n"
			rm -f ${CONFIGDIR}/${HACCDFILE}.tmp.$$
			return 1
		fi

		# rename the temp CCD file
		mv ${CONFIGDIR}/${HACCDFILE}.tmp.$$ ${CONFIGDIR}/${HACCDFILE}
		if [ $? -ne 0 ]; then
			printf "\n$(gettext 'Update failed!')\n\n"
			rm -f ${CONFIGDIR}/${HACCDFILE}.tmp.$$
			return 1
		fi
	fi

	return 0
}

###
#
# sclhosts_remove
#
#	Remove a logical host from the cluster configuration.  The
#	cluster must be running and there mustbe no data services
#	registered for this logical host (see scconf(1m)).
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
sclhosts_remove()
{
	typeset i
	typeset lhosts
	typeset lhost

	integer status

	#
	# make sure that CLUSTERNAME and RUNNING are set
	#
	if [ -z "${CLUSTERNAME}" ]; then
		printf "$(gettext 'Internal error - %s is not set.')\n" "CLUSTERNAME" >&2
		return 1
	fi
    	if [ "${RUNNING}" != "yes" ]; then
		printf "$(gettext 'Internal error - %s is not running.')\n" "clustd" >&2
		return 1
	fi

	# compile the list of already configured logical hosts
	lhosts=$(sclhosts_list)

	# if there are no logical hosts, return
	if [ -z "${lhosts}" ]; then
		printf "\n"
		printf "$(gettext 'There are no logical hosts configured!')\n"
		printf "$(gettext 'Hit <RETURN> to continue:')  "
		read foo
		if [ $? -ne 0 ]; then
			printf "\n"
		fi
		return 0
	fi

	# print the list of already configured logical hosts
	printf "\n"
	printf "$(gettext 'The list of logical hosts is:')\n"
	printf "\n"
	for lhost in ${lhosts}
	do
		printf "\t${lhost}\n"
	done
	printf "\n"

	# prompt for the name of the logical host to remove
	lhost=
	while [ -z "${lhost}" ]
	do
		printf "$(gettext 'Which one do you want to remove?')  "
		foo=
		read lhost foo
		if [ $? -ne 0 ]; then		# typed ^D
			printf "\n"
			return 0
		fi
		if [ -z "${lhost}" ]; then
			return 0
		fi
		if [ "${foo}" ]; then
			lhost=
		fi

		# make sure that it is configured
		status=1
		for i in ${lhosts}
		do
			if [ "${i}" = "${lhost}" ]; then
				status=0
				break
			fi
		done
		if [ ${status} -ne 0 ]; then
			printf "\n$(gettext '\"%s\" is not configured.')\n\n" "${lhost}"
			lhost=
		fi
	done

	# remove it
	${SCCONF} ${CLUSTERNAME} -L ${lhost} -r
	if [ $? -ne 0 ]; then
		printf "\n$(gettext '%s failed to remove \"%s\".')\n\n" "${SCCONF}" "${lhost}"
		return 1
	fi

	return 0
}
#
# ident "@(#)upgrade_subs.ksh 1.33   01/03/28 SMI"
#
# Copyright (c) 1998 by Sun Microsystems, Inc.
# All rights reserved.
#

############################################################################
############################################################################
##
## upgrade_subs
##
## These are the functions defined in this module:
##
##	add_ccd_pkgs				reverse_list
##	add_ether_pkgs				save_ccd_config
##	add_sci_pkgs				save_sci_config
##	checkNumInstance			save_shared_ccd_config
##	checkPkgInstances			set_tc
##	check_for_sc_packages			umount_shared_ccd
##	complete_cdb_upgrade			upgrade_ccd_config
##	complete_upgrade			upgrade_cdb_config
##	enccdmatch				upgrade_check_for_product
##	encdbmatch				upgrade_dbms_methods
##	generic_pkg_add				upgrade_from_ha
##	generic_pkg_rm				upgrade_from_sc
##	get_node_info				upgrade_fw_pkgs
##	get_node_names				upgrade_ha_methods
##	get_nodeids				upgrade_hadbms_pkgs
##	mount_shared_ccd			upgrade_inetpro_pkgs
##	program_sci_cards			upgrade_mstate
##	remove_ccd_pkgs				upgrade_nfs_methods
##	remove_ether_pkgs			upgrade_nsmail_methods
##	remove_from_list			upgrade_pvtlinks
##	remove_sci_pkgs				upgrade_reset_pnm
##	restore_ccd_config			upgrade_udlm_pkgs
##	restore_sci_config			upgrade_uninstall_solstice_ha
##
## These are external functions used in this module:
##
##	AddToList				ReverseList
##	AppendListToList			StoreNodeInfo
##	NewTC_SSPInfo				StoreTC_SSP
##	PrintTCTable				VerifyTCPort
##	prompt_yesno				VerifyTC_IP
##
############################################################################
############################################################################

###
#
# remove_from_list
#
#     listname - the name of the array from which item will be removed. The
#		 contents of the content of listname is changed by this
#		 function.
#     package  - the item
#
#     Remove and item from an array and shift everything over one to
#     eliminate the space left by removed item.
#
#     Return:
#		0	Success
#		1	Unable to remove item
#
remove_from_list() {
	typeset listname
	typeset package

	typeset ppackage
	typeset found=no
	integer positionInList=0		# Where are we in the list?
	integer i=0
	integer j=0
	integer elements=0

	if [ $# -ne 2 ]; then
		printf "$(gettext 'Two arguments expected')\n"
		return 1
	fi

	listname=$1
	package=$2

	#
	# There is a bug possibly in AppendListToList which puts several
	# elements into one cell. In order to get a correct count of the number
	# of elements in the array, the following is used in place of
	# ${#listname[*]}
	#
#	elements=`eval echo \\$\{#$listname[*]\}`
	for ppackage in `eval echo \\$\{$listname[*]\}`; do
		(( elements += 1 ))
	done
	if (( elements == 0 )); then
		if (( VERBOSE == 1 )); then
			printf "$(gettext 'The list is empty').\n"
		fi
		return 1
	fi

	for ppackage in `eval echo \\$\{$listname[*]\}`; do
		if [ "${package}" = "${ppackage}" ]; then
			found=yes
			break
		fi
		(( positionInList += 1 ))
	done

	if (( positionInList == elements )); then
		if (( VERBOSE == 1 )); then
			printf "$(gettext 'Item not found in list').\n"
		fi
		return 0
	fi

	if (( VERBOSE == 1 )); then
		printf "$(gettext 'Before removing') %s...\n" "${package}"
		while (( i < elements )); do
			printf "\tlistname[%d] = %s\n" "$i" \
			    "`eval echo \\$\{$listname[$i]\}`"
			(( i += 1 ))
		done
	fi

	let i=$positionInList
	while (( i < elements )); do
		(( j = i + 1 ))
		if (( j == elements )); then
			break
		fi
		eval $listname[$i]=\${$listname[$j]}
		(( i += 1 ))
	done
	eval unset $listname[$i]

	if (( VERBOSE == 1 )); then
		printf "$(gettext 'After removing') %s...\n" "${package}"
		let i=0
		let elements=`eval echo \\$\{#$listname[*]\}`
		while (( i < elements )); do
			printf "\tlistname[%d] = %s\n" "$i" \
			    "`eval echo \\$\{$listname[$i]\}`"
			(( i += 1 ))
		done
		echo ""
	fi

	return 0
}

###
#
# reverse_list
#
#     Rlistname - the name of the array whose contents will be reversed. The
#		  contents of the content of Rlistname is changed by this
#		  function.
#
#     Reverse the order of the elements in the array.
#
#     Return:
#		0	Success
#
function reverse_list {
	typeset Rlistname
	set -A newlist ""
	integer i=0
	integer n
	integer N

	Rlistname=$1
	integer n=`eval echo \\$\{#${Rlistname}[*]\}`
	integer N=n-1

	if (( VERBOSE == 1 )); then
		let i=0
		printf "Before reversing...\n"
		while (( i < n )); do
			printf "\tRlistname[%d] = %s\n" "$i" \
			    "`eval echo \\$\{${Rlistname}[$i]\}`"
			(( i += 1 ))
		done
	fi

	let i=0
	while (( i < n )); do
		newlist[$i]=`eval echo \\$\{${Rlistname}[$N]\}`
		((i = i + 1))
		((N = N - 1))
	done

	let n=${#newlist[*]}
	let i=0
	while (( i < n )); do
		eval $Rlistname[$i]=\${newlist[$i]}
		((i = i + 1))
	done

	if (( VERBOSE == 1 )); then
		let i=0
		let n=`eval echo \\$\{#${Rlistname}[*]\}`
		printf "After reversing...\n"
		while (( i < n )); do
			printf "\tRlistname[%d] = %s\n" "$i" \
			    "`eval echo \\$\{${Rlistname}[$i]\}`"
			(( i += 1 ))
		done
		echo ""
	fi

	return 0
}

###
#
# generic_pkg_add
#
#	This is a generic function that will add the pkgs
#	that are passed in as parameters. A special admin or
#	response file can be use. These would be passed in 
#	with the -a and/or -r flags.
#
#	If the package is already installed, the identified package will
#	not be installed.
#
function generic_pkg_add
{

	typeset responsefile
	typeset adminfile
	typeset pkglist
	typeset tmpadmin=${SCTMPDIR}/scinstall.admin.$$
	integer status

	while getopts p:r:a: c
	do
		case $c in
		r)
			responsefile=$OPTARG
			;;
		a)
			adminfile=$OPTARG
			;;
		p)
			pkgdir=$OPTARG
			;;
		*)
			;;
		esac
	done

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

	if [ -n "$responsefile" ]; then
		if [ ! -f "$responsefile" -a ! -d "$responsefile" ]; then
			responsefilearg=""
		else
			responsefilearg="-r $responsefile"
		fi
	else
		responsefilearg=""
	fi

	if [ -z "$adminfile" ]; then
		adminfile=$tmpadmin
		cat <<!EOF >$tmpadmin
mail=
instance=overwrite
partial=nocheck
runlevel=nocheck
idepend=quit
rdepend=nocheck
space=nocheck
setuid=nocheck
conflict=nocheck
action=nocheck
basedir=default
!EOF
	fi

	arg="-n -a $adminfile"
	inst_args="$arg -S -d $pkgdir $responsefilearg"
	set -A pkglist $*

	if (( VERBOSE == 1 )); then
		printf "$(gettext 'Packages to be added')...\n"
		integer elements=${#pkglist[*]}
		integer i=0
		while (( i < elements )); do
			printf "\tpkglist[%d] = %s\n" "$i" "${pkglist[$i]}"
			(( i += 1 ))
		done
	fi

	for pkg in ${pkglist[*]}; do
		if ! pkginfo -q ${pkg} >/dev/null 2>&1
		then
			if (( VERBOSE == 1 )); then
				print "  pkgadd ${inst_args} ${pkg}"
			fi
			printf "    $(gettext 'Installing') \"%s\" ... " \
			    "${pkg}"
			pkgadd $inst_args ${pkg} >${SCTMPDIR}/${pkg}.out 2>&1
			status=$?
			if [ $status -ne 0 -a $status -ne 10 ]; then
				printf "$(gettext 'failed')\n"
				cat ${SCTMPDIR}/${pkg}.out
				printf "$(gettext \
				    'Installation of \"%s\" failed')\n" "${pkg}"
				return 1
			fi
			printf "$(gettext 'done')\n"
		fi
	done

	if (( VERBOSE == 1 )); then
		echo ""
	fi

	/bin/rm -rf $tmpadmin

	return 0
}

###
#
# generic_pkg_rm
#
#	This is a generic function that will remove all instances
#	of the packages passed in as parameters.
#
#	Depends on CheckForPatchID in subroutines.ksh
#
function generic_pkg_rm
{
	typeset pkglist
	typeset c
	typeset arg
	typeset adminfile
	typeset responsefile
	typeset tmpadmin=${SCTMPDIR}/scinstall.admin.$$

	while getopts a:ir: c
	do
		case $c in
		a)
			adminfile=$OPTARG
			;;
		r)
			responsefile=$OPTARG
			;;
		*)
			;;
		esac
	done

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

	set -A pkglist $*

	if [ -n "$responsefile" ]; then
		if [ ! -f "$responsefile" -a ! -d "$responsefile" ]; then
			responsefilearg=""
		else
			responsefilearg="-r $responsefile"
		fi
	else
		responsefilearg=""
	fi

	if [ -z ${adminfile} ]; then
		adminfile=$tmpadmin
		cat <<!EOF >$tmpadmin
mail=
instance=overwrite
partial=nocheck
runlevel=nocheck
idepend=quit
rdepend=nocheck
space=nocheck
setuid=nocheck
conflict=nocheck
action=nocheck
basedir=default
!EOF
	fi

	arg="-n -a ${adminfile} ${responsefilearg}"
	set -A LOADEDPKGS ""

	for pkgset in ${pkglist[*]}; do
		set -A pkgs $(pkginfo | grep -w ${pkgset} | awk '{print $2}' | \
		    tr '\n' ' ')

		for pkg in ${pkgs[*]}; do
			CheckForPatchID ${pkg}
			if pkginfo -q ${pkg} >/dev/null 2>&1; then
				if (( VERBOSE == 1 )); then
					print "  pkgrm ${arg} ${pkg}"
				fi
				printf "    $(gettext 'Removing') \"%s\" ... " \
				    "${pkg}"
				pkgrm ${arg} ${pkg} >${SCTMPDIR}/${pkg}.out 2>&1
				if [ $? -eq 1 -o $? -eq 4 ]; then
					printf "$(gettext 'failed')\n"
					cat ${SCTMPDIR}/${pkg}.out
					printf "$(gettext \
					    'Removal of \"%s\" failed')\n" \
					    "${pkg}"
					return 1
				fi
				printf "$(gettext 'done')\n"
				AddToList LOADEDPKGS ${pkg}
			fi
		done

	done
	if (( VERBOSE == 1 )); then
		printf "$(gettext 'Packages removed'): %s\n\n" \
		    "${LOADEDPKGS[*]}"
	fi
	/bin/rm -rf $tmpadmin

	return 0
}

#
# This function will read the configuration that is stored
# in ${SAVEDIR}/sci_adapter_info and program that data
# back into the cards. This data has been overwritten
# by the pkgadd of the SUNWsci pkg.
function program_sci_cards
{
	typeset conffile="${SAVEDIR}/sci_adapter_info" 
	typeset FIRMLG="-totadpt -config"

	set -A slot $(egrep found ${conffile} | awk '{print $9}'|tr '\n' ' ')
	set -A adp $(egrep '^Adapter number:' ${conffile} | awk '{print $3,$4}')
	set -A nodeid $(egrep '^NodeId:' ${conffile} | awk '{print $2,$4}')

	# just a sanity check, ${#adp[*]} better equal ${#nodeid[*]} which
	# also better equal ${#slot[*]} or else :(.

	if (( (${#adp[*]} != ${#nodeid[*]}) || \
	    (${#adp[*]} != ${#slot[*]}) )); then
		print "Cannot restore previous configuration. You will need"
		print "to rerun sm_config(1m) to configure sci cards."
		exit 1
	fi

	let i=0
	while (( i < ${#adp[*]} )); do
		# program the SCI card
		if (( VERBOSE == 1 )); then
			print "Programming card with nodeid ${nodeid[$i]}, adapter ${adp[$i]}"
		fi
		NODEID="-nodeid ${nodeid[$i]} -adapter ${adp[$i]}"
		if (( VERBOSE == 1 )) ;then
			print "${SCIADM} -b ${slot[$i]} ${NODEID} ${FIRMLG}"
		fi
		${SCIADM} -b ${slot[$i]} ${NODEID} ${FIRMLG} >> ${SCTMPDIR}/sciprog \
		    2>&1

		(( i = i + 1 ))
	done

	if (( VERBOSE == 1 )); then
		print "Verify the following information:"
		${SCIADM} -identify 2> /dev/null
	fi

}

# We need to save the following:
#	/etc/sma.config
#	/etc/sma.ip
#	/etc/sci.ifconf
#	the sci adapter/nodeid's (obtained with sciadm -ident)
#
function save_sci_config
{
	if [[ ! -d $SAVEDIR ]]; then
		/bin/mkdir -p $SAVEDIR
	fi

	if (( VERBOSE == 1 )); then
		print "Saving the following sci configuration files:"
		print "\t/etc/sma.config"
		print "\t/etc/sci.ifconf"
		print "\t/etc/sma.ip"
	fi
	/bin/cp /etc/sma.config /etc/sma.ip ${SAVEDIR}
	/bin/cp /etc/sci.ifconf ${SAVEDIR}

	if (( VERBOSE == 1 )); then
		print "Saving the current sci card configuration settings..."
	fi
	${SCIADM} -ident >${SAVEDIR}/sci_adapter_info 2>/dev/null

	touch ${SAVEDIR}/scifiles_saved
}

add_sci_pkgs()
{
	reverse_list LOADEDPKGS
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
		generic_pkg_add -p ${MEDIA} ${SCI27List[*]}
		if [ $? -eq 1 ]; then
			return 1
		fi
	fi

	return 0
}

# Restore the original sci configuration. Copy the /etc files
# we saved previously and then call program_sci_cards to
# restore the node ids.
restore_sci_config()
{
	if [[ -f ${SAVEDIR}/scifiles_saved ]]; then
		if (( VERBOSE == 1 )) ; then
			print "Restoring the following sci configuration files:"
			print "\t/etc/sma.config"
			print "\t/etc/sci.ifconf"
			print "\t/etc/sma.ip"
		fi
		/bin/cp ${SAVEDIR}/sma.ip ${SAVEDIR}/sma.config /etc
		/bin/cp ${SAVEDIR}/sci.ifconf /etc
		program_sci_cards
		/bin/rm -rf ${SAVEDIR}/scifiles_saved
	fi
}

# wrapper call to generic_pkg_rm. This is used to
# setup the pkgrm list.
remove_sci_pkgs()
{
	generic_pkg_rm ${SCI27List[*]}

	# 4167286: Remove packages in correct dependency order.
	reverse_list SCIList

	generic_pkg_rm ${SCIList[*]}
}

function remove_ether_pkgs
{
        generic_pkg_rm ${SMA27List[*]}
        generic_pkg_rm ${SMAList[*]}

	generic_pkg_rm "SUNWccm"
	if [ $? -eq 1 ]; then
		return 1
	fi

	return 0
}

function add_ether_pkgs
{
	generic_pkg_add -p ${MEDIA} ${SMAList[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
		generic_pkg_add -p ${MEDIA} ${SMA27List[*]}
		if [ $? -eq 1 ]; then
			return 1
		fi
	fi

	return 0
}

# This function will check to see if the shared ccd is
# mountable. That is if the other node in a two node
# cluster is up then it will have the shared ccd mounted
# and the ccd.database file will exist on this node
# and we would just proceed as normal. 
#
# If however no one is a cluster member then the ccd.database
# file will not exist and we will have to mount the shared
# ccd and operate on that. 
#
# If we need to mount the shared ccd and we cannot (for
# whatever reason), we will continue but make no ccd updates.
# This is ok because if we cannot import sc_dg its most likely
# because the other node is using it. If that is the case
# the ccd has already been updated and we will get that copy
# when we join the cluster.
function save_shared_ccd_config
{
	typeset sharedccd

	sharedccd=""

	if [[ ! -d $SAVEDIR ]]; then
		/bin/mkdir -p $SAVEDIR
	fi

	# First check for local ccd.database
	if [[ ! -f ${CONFIGDIR}/ccd.database ]]; then
		#
		# check if the device is in fact mounted
		#
		if [ `/usr/sbin/mount -v | grep ${CONFIGDIR}/ccdssa \
			| /bin/wc -l` -eq 1 ]; then
			if [[ -f ${CONFIGDIR}/ccdssa/ccd.database.ssa ]]; then
				sharedccd="ccdssa/ccd.database.ssa"
			fi
		else

			# ok its not mounted but lets see if the dg is imported
			if /usr/sbin/vxdg -q list | /bin/grep sc_dg >/dev/null
			then

				# ok the dg is imported, lets just mount it.
				mount_shared_ccd
			else

				# not imported lets do that first.
				if (( VERBOSE == 1 )); then
					print "Importing sc_dg..."
				fi
				/usr/sbin/vxdg -t import sc_dg
				if (( $? == 20 )); then
					touch ${SAVEDIR}/did_not_import_ccd
				else
					touch ${SAVEDIR}/imported_shared_ccd
					mount_shared_ccd
				fi
			fi
			if [[ -f ${CONFIGDIR}/ccdssa/ccd.database.ssa ]]; then
				touch ${SAVEDIR}/shared_ccdfiles_saved
			elif [[ ! -f ${SAVEDIR}/did_not_import_ccd ]]; then

				# Major error. Both the local ccd and the share
				# ccd don't exist. We will really never fall
				# into this block since one of the above
				# conditions will always be true. 
				print "FATAL: Neither the local ccd\n"
				print " (ccd.database), or the shared"
				print "copy exists (ccdssa/ccd.database.ssa)."
				print "Cannot continue with upgrade."
				exit 10
			fi
		fi
		# if we import the shared ccd we will need to upgrade it.
		# However, none of the ccd tools that are used will operate on
		# the ccd.database.ssa. Only ccd.database or ${UPGRD_CCDINITFILE}.
		# In this case what I'm doing is copying the ccd.database.ssa to
		# ccd.database (the local copy) and will upgrade this. When I'm
		# all done I will copy ccd.database back to ccd.database.ssa 
		# (actually I will move it so that the local copy will no longer
		# exist - as it did not to start).
		if [[ -f ${SAVEDIR}/imported_shared_ccd ]]; then
			/bin/cp ${CONFIGDIR}/ccdssa/ccd.database.ssa \
			    ${CONFIGDIR}/ccd.database
		fi
	fi

}

# Save the existing ccd files.
function save_ccd_config
{
	typeset ccdtosave

	if (( $# == 1 )); then
		ccdtosave="$1"
	else
		ccdtosave="ccd.database"
	fi

	if [[ ! -d $SAVEDIR ]]; then
		/bin/mkdir -p $SAVEDIR
	fi

	if [[ -f ${CONFIGDIR}/${ccdtosave} ]]; then
		/bin/cp ${CONFIGDIR}/${ccdtosave} ${SAVEDIR}
        	touch ${SAVEDIR}/ccdfiles_saved
	fi
	if [[ -f ${CONFIGDIR}/${UPGRD_CCDINITFILE} ]]; then
		/bin/cp ${CONFIGDIR}/${UPGRD_CCDINITFILE} ${SAVEDIR}
	fi

	if [[ -f ${CONFIGDIR}/${CDBFILE} ]]; then
		/bin/cp ${CONFIGDIR}/${CDBFILE} ${SAVEDIR}
	fi

	if [[ -f ${CONFIGDIR}/default_clustername ]]; then
		/bin/cp ${CONFIGDIR}/default_clustername ${SAVEDIR}
	fi
}

function remove_ccd_pkgs
{
	typeset ccdpkgs="SUNWccd"

	generic_pkg_rm "${ccdpkgs}"
}

function add_ccd_pkgs
{
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
}

# Restore the CCD files after the pkg upgrade. If the shared
# CCD is mounted the restore to that otherwise its just the
# local file. Unmount the deport the sc_dg if we mounted
# and imported. Do some final cleanup steps.
function complete_upgrade
{
	typeset sharedccd=""
	integer prdct_type=$1
	integer numofnodes=$2

	if [[ -f ${SAVEDIR}/shared_ccdfiles_saved ]]; then
		if [ `/usr/sbin/mount -v | grep ${CONFIGDIR}/ccdssa \
		    | /bin/wc -l` -eq 1 ]; then
			/bin/mv ${CONFIGDIR}/ccd.database \
			    ${CONFIGDIR}/ccdssa/ccd.database.ssa
		else
			print "Error shared ccd not mounted."
		fi
	fi

	# Finish up by unmounting the shared ccd if we mounted it.
        if [[ -f ${SAVEDIR}/mounted_shared_ccd ]]; then
                umount_shared_ccd
		if [ $? -eq 1 ]; then
			return 1
		fi
                if [[ -f ${SAVEDIR}/imported_shared_ccd ]]; then
                        if (( VERBOSE == 1 ));then
                                print "Deporting sc_dg ..."
                        fi
                        /usr/sbin/vxdg deport sc_dg
			if [ $? -ne 0 ]; then
				printf "$(gettext \
				    'Problems deporting sc_dg')\n"
				return 1
			fi
                        /bin/rm -rf ${SAVEDIR}/imported_shared_ccd
                fi
        fi
	if [[ -f ${SAVEDIR}/did_not_import_ccd ]]; then
		/bin/rm -rf ${CONFIGDIR}/ccd.database
		/bin/rm -rf ${SAVEDIR}/did_not_import_ccd
	fi
	if [[ -f ${CONFIGDIR}/ccd.database && ${prdct_type} == 20 ]]; then
		# We need to copy this file just in case we have to do a
		# ccdadm -r to bring the new node up to date.
		/bin/cp ${CONFIGDIR}/ccd.database \
		    ${CONFIGDIR}/ccd.database.post_sc2.0_upgrade

	fi

	if (( (prdct_type == 20) && (numofnodes > 2) )); then
		complete_cdb_upgrade
	fi

        /bin/rm -rf ${SAVEDIR}/shared_ccdfiles_saved
	/bin/mv ${SAVEDIR} ${SAVEDIR}.$$

	return 0
}

# This function will copy the CCD files that were saved
# previously back to the configuration directory. 
function restore_ccd_config
{
	if [[ $# == 1 ]]; then
		ccdtorestore=$(basename $1)
		ccdlocation="$1"
	else
		ccdtorestore="ccd.database"
		ccdlocation="."
	fi

	# always restore the init CCD.
	/bin/cp ${SAVEDIR}/${UPGRD_CCDINITFILE} ${CONFIGDIR}
	/bin/cp ${SAVEDIR}/${CDBFILE} ${CONFIGDIR}
	/bin/cp ${SAVEDIR}/default_clustername ${CONFIGDIR}
	if [[ -f ${SAVEDIR}/ccdfiles_saved ]]; then
		/bin/cp ${SAVEDIR}/${ccdtorestore} ${CONFIGDIR}/${ccdlocation}
		/bin/rm -rf ${SAVEDIR}/ccdfiles_saved
	fi
}

function upgrade_ccd_config
{

	if (( VERBOSE == 1 )); then
		print "Upgrading the CCD from SC2.0 to SC2.2 ..."
	fi
	if [[ -f ${CONFIGDIR}/ccd.database ]]; then

		tokenCK=`grep "DS_SUN_sync" ${CONFIGDIR}/ccd.database`
		if [ -z "${tokenCK}" ]; then
			if (( VERBOSE == 1 )); then
				print "Adding the DS_SUN format to the ccd ..."
			fi
			# add the DS_SUN format to the ccd.database file
			CCDDSSUNFILE=${SCTMPDIR}/dssun.ccd
			/bin/cat >> ${CCDDSSUNFILE} << EOF
#
# Data Service Info
#
DS_SUN_fmt:ds_name:lic_type:lic_ver:pkg:rdir:st:sp:ab:stn:spn:abn:fmi:fmst:fmsp:fmck
DS_SUN_idx:0
DS_SUN_sync:ccd_nofreeze

DS_SUN:nfs:::SUNWsc:/ha/nfs/:60:60:60:60:60:60:60:60:60:60
EOF

			${CCDINSTALL} add ${CCDDSSUNFILE}
			/bin/rm -f ${CCDDSSUNFILE}
		fi

		tokenCK=`grep "TCMON_fmt" ${CONFIGDIR}/ccd.database`
		if [ -z "${tokenCK}" ]; then
			# add TC/SSP monitoring format to the ccd.database file
			if (( VERBOSE == 1 )); then
				print "Adding the TCMON format to the ccd ..."
			fi
			CCDTCMONFILE=${SCTMPDIR}/tcmon.ccd
			/bin/cat > ${CCDTCMONFILE} << EOF

#
# TC/SSP monitoring - Status information
#

TCMON_fmt:tc_ssp_ip:status
TCMON_idx:0
TCMON_sync:ccd_nofreeze

EOF

			${CCDINSTALL} add ${CCDTCMONFILE}
			/bin/rm -f ${CCDTCMONFILE}
		fi

		upgrade_mstate
		upgrade_ha_methods

	fi
}

# This function will upgrade the method call back values
# that have changed from SC2.0 to SC2.2.
function upgrade_ha_methods
{
	# cycle through all of the registered data services.
	/bin/egrep '^DS_STATE:' ${CONFIGDIR}/ccd.database | \
	    awk -F: '{print $2}' | \
	    while read ds; do
		case $ds in
		'nfs')
			upgrade_nfs_methods
			;;
		'nsmail' )
			upgrade_nsmail_methods
			;;
		'sybase'|'informix'|'oracle')
			upgrade_dbms_methods $ds
			if [ $? -eq 1 ]; then
				return 1
			fi
			;;
		esac	
	done

	return 0
}

# If we are upgrading from SC2.0 to SC2.2 there is a chance
# that the user will be using netscape 2.0. In this case we
# need to upgrade the NSMAIL_CONF. Actually what we need
# to do is add the new NSMAIL3_CONF and populate it
# with the original values.
function upgrade_nsmail_methods
{
	typeset ccdfile="${CONFIGDIR}/ccd.database"
	typeset ccdmail="${SCTMPDIR}/mail.$$"
	typeset formatpre=NSMAIL3_CONF

	/bin/cat > ${ccdmail} << EOF

#
# Netscape 3.0
#

${formatpre}_fmt:name:VariableName:Value
${formatpre}_idx:0
${formatpre}_sync:ccd_nofreeze

EOF

	#
	# First check to see if there are any netscape 2.0 entries
	# that need to be convered.
	if /bin/grep 'NSMAIL_CONF:' ${ccdfile} >/dev/null 2>&1; then
		set -A mail_format \
		    $(/bin/grep 'NSMAIL_CONF_fmt' ${ccdfile} | tr ':' ' ')
		/bin/grep 'NSMAIL_CONF:' ${ccdfile} | while read line; do
			set -A mail_values $(print ${line} | tr ':' ' ')

			instance=${mail_values[1]}
			let i=2
			while (( i < ${#mail_format[*]} )); do
				if (( VERBOSE == 1 )); then
					print "Converting the following from Netscape 2.0 to 3.0..."
					print "${formatpre}:${instance}:${mail_format[i]}:${mail_values[i]}"
				fi
				print "${formatpre}:${instance}:${mail_format[i]}:${mail_values[i]}" >> ${ccdmail}

				(( i = i + 1 ))
			done
		done
	fi

	tokenCK=`grep "${formatpre}" ${CONFIGDIR}/ccd.database`
	if [ -z "${tokenCK}" ]; then

		${CCDINSTALL} add ${ccdmail}
		if (( VERBOSE == 1 )); then
			print "Adding the ${formatpre} format to the ccd ..."
		fi

	fi
	/bin/rm -rf ${ccdmail}

}

# upgrade the CCD to SC2.2 levels, if not already done.
function upgrade_nfs_methods
{
	typeset tmppath="${SCTMPDIR}"
	typeset sedfile="${tmppath}/sed.tmp$$"
	typeset ccdfile="${CONFIGDIR}/ccd.database"

	if /bin/egrep 'nfs\.' ${ccdfile} >/dev/null 2>&1
	then
		if (( VERBOSE == 1 )); then
			printf "Updating nfs callback methods from nfs to nfs_svc_ ..."
		fi
		echo "/^DS_METHOD_PATH:nfs:/s|nfs\.|nfs_svc_|g" >> $sedfile
	fi

	if /bin/egrep 'DS_NM_PATH:nfs::60::60::15' ${ccdfile} >/dev/null 2>&1
	then
		if (( VERBOSE == 1 )); then
			print "Adding the nfs net methods ..."
		fi
		echo "/^DS_NM_PATH:nfs/c\\
DS_NM_PATH:nfs:/opt/SUNWcluster/ha/nfs/nfs_svc_start_net:60:/opt/SUNWcluster/ha/nfs/nfs_svc_stop_net:60:/opt/SUNWcluster/ha/nfs/nfs_svc_abort_net:15" >> $sedfile
	fi
	if [[ -f ${sedfile} ]]; then
		${CCDADM} -p ${ccdfile} >/dev/null 2>&1
		retval=$?
		if [[ $retval != 0 ]]; then
			echo "${ccdfile} is corrupted"
			exit 1;
		fi

		sed -f $sedfile ${ccdfile}.pure > ${tmppath}/tmpccdinit

		${CCDADM} -x ${tmppath}/tmpccdinit
		mv ${tmppath}/tmpccdinit ${ccdfile}
		/bin/rm -rf $sedfile
	fi
}

# upgrade the CCD to SC2.2 levels, if not already done.
function upgrade_mstate
{
	typeset tmppath="${SCTMPDIR}"
	typeset sedfile="${tmppath}/sed.tmp$$"
	typeset ccdfile="${CONFIGDIR}/ccd.database"

	if /bin/egrep 'LOGHOST_MSTATE_sync:ccd_nofreeze' ${ccdfile} >/dev/null 2>&1
	then
		if (( VERBOSE == 1 )); then
			printf "Updating LOGHOST_MSTATE sync command from ccd_nofreeze to mstate_sync ..."
		fi
		echo "/^LOGHOST_MSTATE_sync/s|ccd_nofreeze|/opt/SUNWcluster/bin/mstate_sync|g" >> $sedfile
	fi

	if [[ -f ${sedfile} ]]; then
		${CCDADM} -p ${ccdfile} >/dev/null 2>&1
		retval=$?
		if [[ $retval != 0 ]]; then
			echo "${ccdfile} is corrupted"
			exit 1;
		fi

		sed -f $sedfile ${ccdfile}.pure > ${tmppath}/tmpccdinit

		${CCDADM} -x ${tmppath}/tmpccdinit
		mv ${tmppath}/tmpccdinit ${ccdfile}
		/bin/rm -rf $sedfile
	fi
}

# Upgrade the ccd for the dbms ha methods to SC2.2 levels.
function upgrade_dbms_methods
{
        typeset tmppath="${SCTMPDIR}"
        typeset sedfile="${tmppath}/sed.tmp$$"
        typeset ccdfile="${CONFIGDIR}/ccd.database"

	ds=${1}

	dspath=$(egrep "^DS_INFO:${ds}:.*:.*:.*:.*" ${ccdfile}| sed 's/^.*:.*:.*:.*:.*:\(.*\)$/\1/')
	dspath=$(dirname ${dspath})

	if /bin/egrep "DS_FM_PATH:${ds}:.*:60:.*:60:.*:60::" ${ccdfile} \
		>/dev/null 2>&1
	then
		if (( VERBOSE == 1 )); then
			print "Adding the ${ds}_fm_check to the fault monitor callback methods ..."
		fi
		echo "/^DS_FM_PATH:${ds}:.*:60:.*:60:.*:60::/s|::|:${dspath}/${ds}_fm_check:|" >> ${sedfile}
	fi
        if /bin/egrep "DS_METHOD_PATH:${ds}::" ${ccdfile} >/dev/null 2>&1
        then
		if (( VERBOSE == 1 )); then
			print "Adding the ${ds} start/stop/abort callback methods ..."
		fi
                echo "/^DS_METHOD_PATH:${ds}/c\\
DS_METHOD_PATH:${ds}:${dspath}/${ds}_svc_start:60:${dspath}/${ds}_svc_stop:60:${dspath}/${ds}_svc_abort:15" >> ${sedfile}
        fi
        if [[ -f ${sedfile} ]]; then
                ${CCDADM} -p ${ccdfile} >/dev/null 2>&1
                retval=$?
                if [[ $retval != 0 ]]; then
                        echo "${ccdfile} is corrupted"
                        return 1;
                fi

                sed -f $sedfile ${ccdfile}.pure > ${tmppath}/tmpccdinit

                ${CCDADM} -x ${tmppath}/tmpccdinit
                if [[ $? != 0 ]]; then
                        printf "$(gettext \
			    'Unable to convert new CCD file').\n"
                        return 1;
                fi
                mv ${tmppath}/tmpccdinit ${ccdfile}
                /bin/rm -rf $sedfile
        fi

	return 0
}

# This function will modify the pre SC2.2 CDB file 
# to bring it up to the SC2.2 levels.
function upgrade_cdb_config
{
	typeset tmppath="${SCTMPDIR}"
	typeset sedfile="${tmppath}/sed.tmp$$"
	integer keynotexist=1		# 0 - exists, 1 - doesn't exist
	integer stop_timeout
	integer abort_timeout
	integer step1_timeout
	integer step2_timeout
	integer step3_timeout
	integer step6_timeout
	integer step10_timeout
	integer step11_timeout
	integer udlm_abort_timeout

	if (( VERBOSE == 1 )); then
		print "Upgrading the CDB file from SC2.0 to SC2.2 ..."
	fi
	cp ${CONFIGDIR}/${CDBFILE} ${CONFIGDIR}/${CDBFILE}.orig

	# These are values that have changed since 2.0:

	stop_timeout=$(encdbmatch cmm.transition.stop.timeout)
	abort_timeout=$(encdbmatch cmm.transition.abort.timeout)
	step1_timeout=$(encdbmatch cmm.transition.step1.timeout)
	step2_timeout=$(encdbmatch cmm.transition.step2.timeout)
	step3_timeout=$(encdbmatch cmm.transition.step3.timeout)
	step6_timeout=$(encdbmatch cmm.transition.step6.timeout)
	step10_timeout=$(encdbmatch cmm.transition.step10.timeout)
	step11_timeout=$(encdbmatch cmm.transition.step11.timeout)
	udlm_abort_timeout=$(encdbmatch udlm.abort_timeout)

	echo "/cmm.transition.stop.timeout/s/${stop_timeout}/210/" >> $sedfile
	echo "/cmm.transition.abort.timeout/s/${abort_timeout}/200/" >> $sedfile
	echo "/cmm.transition.step1.timeout/s/${step1_timeout}/75/" >> $sedfile
	echo "/cmm.transition.step2.timeout/s/${step2_timeout}/230/" >> $sedfile
	echo "/cmm.transition.step3.timeout/s/${step3_timeout}/250/" >> $sedfile
	echo "/cmm.transition.step6.timeout/s/${step6_timeout}/150/" >> $sedfile
	echo "/cmm.transition.step10.timeout/s/${step10_timeout}/720/" >> $sedfile
	echo "/cmm.transition.step11.timeout/s/${step11_timeout}/720/" >> $sedfile
	echo "/udlm.abort_timeout/s/${udlm_abort_timeout}/100/" >> $sedfile

	# There are new values since 2.0, but may have been added via a patch:
	tokenCK=`grep "loghost.update_timeout" ${CONFIGDIR}/${CDBFILE}`
	if [ -z "${tokenCK}" ]; then
		if (( VERBOSE == 1 )); then
			print "Adding loghost update timeout value ..."
		fi
		echo "" >> ${CONFIGDIR}/${CDBFILE}
		echo "#" >> ${CONFIGDIR}/${CDBFILE}
		echo "# update timeout to be used by scccd command when" \
			>> ${CONFIGDIR}/${CDBFILE}
		echo "# adding/removing logical host from CCD." \
			>> ${CONFIGDIR}/${CDBFILE}
		echo "#" >> ${CONFIGDIR}/${CDBFILE}
		echo "loghost.update_timeout          :       180" \
			>> ${CONFIGDIR}/${CDBFILE}
	fi

# These are new values since SC2.0:
# Since there are all new tokens since SC2.0 we are going to take the 
# easy approach to inserting them. Rather than checking
# for each and everyone, we are only going to check for
# one, say cluster.node.0.arch. If that exists we won't add
# any of them assuming they are all there. This is pretty
# safe since there is no way these could be in the 
# current cdb without having loaded the SC2.2 packages or
# by hand editing the file. Since we are going to do error
# checking in the beginning of this to determine if SC2.2 is
# already loaded again we should be ok here with this
# limited check.

	tokenCK=`grep "cluster.node.0.arch" ${CONFIGDIR}/${CDBFILE}`
	if [ -z "${tokenCK}" ]; then
		if (( VERBOSE == 1 )); then
			print "Adding the TC/SSP Information ..."
		fi

		cat >> ${CONFIGDIR}/${CDBFILE} <<!EOF
cmm.directattacheddevice	: 0

#
# TC/SSP Information
#
# cluster node information
cluster.node.0.arch		: 
cluster.node.1.arch		: 
cluster.node.2.arch		:
cluster.node.3.arch		: 
cluster.node.0.tc_ssp.port	: 
cluster.node.1.tc_ssp.port	: 
cluster.node.2.tc_ssp.port	: 
cluster.node.3.tc_ssp.port	: 

# individual TC/SSP information
cluster.tc_ssp.0.ip	: 
cluster.tc_ssp.1.ip	: 
cluster.tc_ssp.2.ip	: 
cluster.tc_ssp.3.ip	: 
cluster.tc_ssp.0.ak	: 
cluster.tc_ssp.1.ak	: 
cluster.tc_ssp.2.ak	: 
cluster.tc_ssp.3.ak	: 

# Node Lock Mechanism
cluster.tc_ssp.lock	: 
cluster.tc_ssp.to	: 35

#
# TC/SSP monitoring section
#
tcmon.ping_timeout	: 10
tcmon.cycletime		: 120

#
# SMA Link Monitor Failure Detect Time (in seconds)
#
sma.down_time		: 5
!EOF
	fi

	#
	# These values, as a set, do not exist in SC2.0 and an early
	# release of SC2.1, but they do exist in a SC2.1 patch release...
	#
	egrep "pnmd.inactive_time" ${CONFIGDIR}/${CDBFILE} >/dev/null 2>&1
	keynotexist=$(echo $?)
	if (( keynotexist == 1 )); then
		cat >> ${CONFIGDIR}/${CDBFILE} <<!EOF

#
# PNM Tuneable parameters.  See pnmd(1M) man page for further details.
#
pnmd.inactive_time	: 5
pnmd.ping_timeout	: 4
pnmd.repeat_test	: 3
pnmd.slow_network	: 2
!EOF
	fi
        if (( PDBAPPS & (1 << 3) )); then
                let MINQUORUM=0
        elif (( PDBAPPS & (1 << 4) )); then
                let MINQUORUM=0
        elif (( PDBAPPS & (1 << 5) )); then
                let MINQUORUM=1
        fi
	# See BugId: 4148497
	egrep "cmm.minquorum" ${CONFIGDIR}/${CDBFILE} >/dev/null 2>&1
	keynotexist=$(echo $?)
	if (( keynotexist == 1 )); then
		cat >> ${CONFIGDIR}/${CDBFILE} <<!EOF

# Don't request user action on split brain if set
cmm.minquorum		: ${MINQUORUM}
!EOF
	fi

	cp ${CONFIGDIR}/${CDBFILE} ${CONFIGDIR}/${CDBFILE}.o
	sed -f $sedfile ${CONFIGDIR}/${CDBFILE}.o > ${CONFIGDIR}/${CDBFILE}
	/bin/rm -rf ${sedfile}

}

# With SC2.2 we have added several new tokens to the CDB
# file that deal with the tc/nodelocking mechanism. Even
# for two node cases we still require tc input so that
# clustmon can monitor the health of the tc. We now need
# to inform the user that they must run scconf to supply
# this data. We could run this for them if they want, after
# all you can only run that option of scconf with the 
# cluster node down and since we are down...
# and we do give the user the option now to run scconf right
# now.

function complete_cdb_upgrade
{
	typeset prompt
	typeset answer

	print "
SC2.2 will monitor the terminal concentrator and display its
status on the clustmon screen. During the SC2.2 installation
the IP address for the terminal concentrator along with the
physical port numbers that each server is connected to is
requested. This information can be changed using scconf. 

After the upgrade has completed you need to run scconf to
specify terminal concentrator information for each server.
This will need to be done on each server in the cluster.

The specific commands that need to be run are:

scconf ${CLUSTERNAME} -t <nts name> -i <nts name|IP address>
scconf ${CLUSTERNAME} -H <node 0> -p <serial port for node 0> \\
	-d <other|E10000> -t <nts name>

Repeat the second command for each node in the cluster. Repeat
the first command if you have more than one terminal concentrator
in your configuration.

Or you can choose to set this up now. The information you will need
is:

\t+terminal concentrator/system service processor names
\t+the architecture type (E10000 for SSP or other for tc)
\t+the ip address for the terminal concentrator/system service 
\t processor (these will be looked up based on the name, you 
\t will need to confirm)
\t+for terminal concentrators, you will need the physical 
\t ports the systems are connected to (physical ports 
\t (2,3,4... not the telnet ports (5002,...)

"
	prompt="$(gettext 'Do you want to set the TC/SSP info now')"
	answer=$(prompt_yesno "${prompt}" "${NO}")
	if [[ "${answer}" == "${YES}" ]]; then

		set_tc
		if [ $? -eq 1 ]; then
			printf "$(gettext \
			    'Attempt to get TC/SSP configuration failed').\n"
			return 1
		fi
	fi

	return 0
}

# called to setup the terminal concentrator/ssp.
function set_tc
{
	integer conindex
	integer use_interactive=1

	set -A nodeNames  $(get_node_names)

	if [[ -f $TC_SSP_DATA ]] && [[ ! -h $TC_SSP_DATA ]]; then
		print "Reading values from file $TC_SSP_DATA..."
		. $TC_SSP_DATA
		let use_interactive=0
	fi

	if (( use_interactive == 1 )); then
		let LOOPCNTR=0
		while (( LOOPCNTR < ${#nodeNames[*]} )); do
			get_node_info ${nodeNames[LOOPCNTR]}

			((LOOPCNTR = LOOPCNTR + 1 ))
		done
	fi

	#
	# Some small sanity checks. Does the file exist? if yes
	# then check to see if its writable (kind of silly since
	# we are running as root, but why not.)
	# If the file does not exist, check to see if its a directory.
	# if so abort.
	# Lastly, check the status of the cat command. If its not 0 then
	# don't print out the message.
	#
	if [[ ! -f ${TC_SSP_DATA} ]]; then
		if [[ -d ${TC_SSP_DATA} ]] ;then
			printf "$(gettext 'Error: \"%s\" is a directory').\n" \
			    "${TC_SSP_DATA}"
			return 1
		fi
	fi
	#
	# Check to see if it's a symbolic link (security)
	#
	if [[ -h ${TC_SSP_DATA} ]] ;then
		printf "$(gettext 'Error: \"%s\" is a symbolic link').\n" \
		    "${TC_SSP_DATA}"
		return 1
	fi
	if [[ ! -f ${TC_SSP_DATA} ]]; then
		cat > ${TC_SSP_DATA} <<!
set -A TC_SSP_Name ${TC_SSP_Name[*]}
set -A TC_SSP_IP   ${TC_SSP_IP[*]}
set -A TC_SSP_PORT ${TC_SSP_PORT[*]}
set -A TC_SSP_ARCH ${TC_SSP_ARCH[*]}
!

		if (( $? != 0 )); then
			printf "$(gettext 'Could not create') \"%s\"!\n" \
			    "${TC_SSP_DATA}"
			return 1
		else
			print "


	The terminal concentrator/system service processor (TC/SSP)
	information has been stored in file \"${TC_SSP_DATA}\".
	Please put a copy of this file into "/var/tmp" on the rest
	of the cluster nodes. This way you can avoid re-entering
	the TC/SSP values, except for the TC/SSP passwords.
"
		fi
	fi
	let i=0
	while (( i < ${#TC_SSP_Name[*]} )); do
		${SCCONF} ${CLUSTERNAME} -t ${TC_SSP_Name[i]} \
		    -i ${TC_SSP_IP[i]}
		if [ $? -eq 1 ]; then
			printf "$(gettext 'Unable to configure the TC/SSP').\n"
			return 1
		fi
		(( i = i + 1 ))
	done
	let i=0
	while (( i < ${#nodeNames[*]} )); do
		conindex=$(print "${TC_SSP_PORT[i]}" | awk -F. '{print $1}')
		port=$(print "${TC_SSP_PORT[i]}" | awk -F. '{print $2}')
		contype=${TC_SSP_ARCH[i]}
		${SCCONF} ${CLUSTERNAME} -H ${nodeNames[i]} -p ${port} \
		    -d ${contype} -t ${TC_SSP_Name[conindex]} >/dev/null
		if [ $? -eq 1 ]; then
			printf "$(gettext 'Unable to configure the TC/SSP').\n"
			return 1
		fi
		(( i = i + 1 ))
	done

	return 0
}

function mount_shared_ccd
{
	typeset ccddevpath=/dev/vx/dsk/sc_dg/ccdvol

	/usr/sbin/vxrecover -g sc_dg -sb
	if (( VERBOSE == 1 )); then
		print "Mounting the shared ccd ..."
	fi
	/usr/sbin/fsck -F ufs -y  ${ccddevpath}
	/usr/sbin/mount -F ufs  ${ccddevpath} ${CONFIGDIR}/ccdssa
	touch ${SAVEDIR}/mounted_shared_ccd

	return 0
}

function umount_shared_ccd
{
	integer err_status=0

	/usr/sbin/lockfs -h ${CONFIGDIR}/ccdssa
	if [ $? -ne 0 ]; then
		printf "$(gettext \
		    'Problems encountered trying to unmount shared CCD').\n"
		return 1
	fi
	if (( VERBOSE == 1 )); then
		print "Unmounting the shared ccd ..."
	fi
	/usr/sbin/umount ${CONFIGDIR}/ccdssa
	err_status=$?
	/bin/rm -rf ${SAVEDIR}/mounted_shared_ccd
	if (( err_status != 0 )); then
		printf "$(gettext \
		    'Problems encountered trying to unmount shared CCD').\n"
		return 1
	fi

	return 0
}

function upgrade_fw_pkgs
{
	generic_pkg_rm ${serverUpgradeList[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	if (( VERBOSE == 1 )); then
		printf "Before: %s\n" "${LOADEDPKGS[*]}"
	fi
	reverse_list LOADEDPKGS
	if (( VERBOSE == 1 )); then
		printf "After: %s\n" "${LOADEDPKGS[*]}"
	fi
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
		generic_pkg_add -p ${MEDIA} ${server27List[*]}
		if [ $? -eq 1 ]; then
			return 1
		fi
	fi
        if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
                if pkginfo -q SUNWdid >/dev/null 2>&1
                then
                        generic_pkg_add -p ${MEDIA} ${SDSshort27List[*]}
                        if [ $? -eq 1 ]; then
                                return 1
                        fi
                fi
        fi
	# 4187387: Explicitly install SC Manager
	generic_pkg_add -p ${MEDIA} "SUNWscmgr"
	if [ $? -eq 1 ]; then
		return 1
	fi

	return 0
}

function upgrade_inetpro_pkgs
{
	generic_pkg_rm ${InternetProList[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	reverse_list LOADEDPKGS

	if (( VERBOSE == 1 )); then
		integer elements=${#LOADEDPKGS[*]}
		integer i=0
		printf "List after removing packages.\n"
		while (( i < elements )); do
			printf "\tLOADEDPKGS[%d] = %s\n" "$i" \
			    "${LOADEDPKGS[$i]}"
			(( i += 1 ))
		done
		echo ""
	fi

	remove_from_list LOADEDPKGS "SUNWscpro"
	generic_pkg_add -p ${MEDIA} "SUNWscpro"
	if [ $? -eq 1 ]; then
		return 1
	fi
	generic_pkg_add -p ${MEDIA} "SUNWscds"
	if [ $? -eq 1 ]; then
		return 1
	fi
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi

	return 0
}

function upgrade_hadbms_pkgs
{
	# We do each one seperately. First haoracle:
	generic_pkg_rm "${HAOracleList[*]}"
	if [ $? -eq 1 ]; then
		return 1
	fi
	reverse_list LOADEDPKGS
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi

	# Now hasybase:
	generic_pkg_rm "${HASybaseList[*]}"
	if [ $? -eq 1 ]; then
		return 1
	fi
	reverse_list LOADEDPKGS
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi

	# and last hainformix:
	generic_pkg_rm "${HAInformixList[*]}"
	if [ $? -eq 1 ]; then
		return 1
	fi
	reverse_list LOADEDPKGS
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi

	return 0
}

function upgrade_udlm_pkgs
{
	generic_pkg_rm "${OPSList[*]}"
	if [ $? -eq 1 ]; then
		return 1
	fi
	reverse_list LOADEDPKGS
	generic_pkg_add -p ${MEDIA} ${LOADEDPKGS[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
		generic_pkg_add -p ${MEDIA} ${OPS27List[*]}
		if [ $? -eq 1 ]; then
			return 1
		fi
	fi

	return 0
}

########################################################################
# get_node_info
#
# Get the node architecture.  Then allow the user to associate the node with
# a TC or SSP device.

get_node_info() {
	typeset NodeName=$1

	typeset archType
	typeset continueStr="1"
	typeset loopStr

	while [ "${continueStr}" == "1" ]; do
		archType=$(ckstr -Q \
		    -d "other" \
		    -p "What type of architecture does ${NodeName} have? (E10000|other) [other]" )
		case "${archType}" in
		e|e1|e10|e100|e1000|e10000|E|E1|E10|E100|E1000|E10000)
			archType="E10000"
			if [ "${SSP_Counter}" == "None" ]; then 
				SSP_Counter="${TC_SSP_Counter}"
				loopStr="1"
				while [ ${loopStr} == "1" ]; do
					NewTC_SSPInfo -u -t SSP
					if [ $? -eq 1 ]; then
						loopStr="0"
					fi
				done
			else
				PrintTCTable -u -t SSP -h ${NodeName}
			fi
			continueStr="0"
		;;
		o|ot|oth|othe|other|O|OT|OTH|OTHE|OTHER)
			archType="other"
			if [ "${TC_Counter}" == "None" ]; then 
				TC_Counter="${TC_SSP_Counter}"
				loopStr="1"
				while [ ${loopStr} == "1" ]; do
					NewTC_SSPInfo -u -t TC -h ${NodeName}
					if [ $? -eq 1 ]; then
						loopStr="0"
					fi
				done
			else
				PrintTCTable -u -t TC -h ${NodeName}
			fi
			continueStr="0"
		;;
		*)
			echo "Please enter E10000 or other."
		;;
		esac
	done
}

# This function will get the configured nodes in this cluster and
# return that list. The list is based on the number of nodes
# that are configured, ie the value of cluster.number.nodes and
# not the fact that a node name token in the cdb file is non-null.
function get_node_names
{
	integer num
	integer i
	typeset nodenames 

	num=$(encdbmatch cluster.number.nodes)

	let i=0
	while (( i < ${num} )); do

		nodenames="${nodenames} \
			$(encdbmatch cluster.node.${i}.hostname)"
		(( i = i + 1 ))
	done

	print "${nodenames}"
}

# This function will simply check the current directory for
# any of the sc pkgs. Since we really don't know where they
# might be we will just check the current since we tell
# folks to run this from the pkg directory
function check_for_sc_packages
{
	if [[ ! -d ${MEDIA}/SUNWsc ]]; then
		print "Error: The current directory\n(${MEDIA})\ndoes not contain the Sun Cluster software."
		print "Please run this program from SC2.2 package directory location."
		exit 1
	fi
}

###
#
# enccdmatch
#
function enccdmatch
{
	ccdmatch $* ${CONFIGDIR}/${UPGRD_CCDINITFILE} || \
	    (log_error "$pre.4703" \
	    "ccdmatch $* ${CONFIGDIR}/${UPGRD_CCDINITFILE} failed" 1>&2; \
	    return 1)

	return 0
}

###
#
# encdbmatch
#
# lookup a value in the configuration file
function encdbmatch
{
	cdbmatch $* ${CONFIGDIR}/${CDBFILE} || \
	    (log_error "$pre.4704" \
	    "cdbmatch $* ${CONFIGDIR}/${CDBFILE} failed" 1>&2; return 1)

	return 0
}

###
#
# get_nodeids
#
# find the nodeid of the local node
function get_nodeids
{
        typeset myuname=`uname -n`
	if [ "`encdbmatch cluster.node.0.hostname`" = "${myuname}" ]
	then
		let myid=0
	elif [ "`encdbmatch cluster.node.1.hostname`" = "${myuname}" ]
	then
		let myid=1
	elif [ "`encdbmatch cluster.node.2.hostname`" = "${myuname}" ]
	then
		let myid=2
	elif [ "`encdbmatch cluster.node.3.hostname`" = "${myuname}" ]
	then
		let myid=3
	else
		let myid=-1
	fi

	return ${myid}
}

###
#
# upgrade_check_for_product
#
#     prdct	 - A name of the variable which will contain both the
#		   product name and version.
#     prdct_type - The name of the variable which will contain a number
#		   identifying the product:
#
#			 0	None found
#			13	HA1.3
#			20	SC2.0
#			21	SC2.1
#			22	SC2.2
#
#     Determine which product is installed: HA1.3, SC2.0, or SC2.1. 
#
#     Return:
#		0	Success
#		1	Unable to upgrade
#
upgrade_check_for_product()
{
	typeset prdct=$1
	typeset prdct_type=$2
	typeset pkgversion
	integer pkgstatus=$(pkginfo -q SUNWsc >/dev/null 2>&1; echo $?)

	if pkginfo -q SUNWsc >/dev/null 2>&1
	then
		pkgversion=$(pkgparam SUNWsc VERSION | cut -d, -f1)
	elif pkginfo -q SUNWpnm >/dev/null 2>&1
	then
		pkgversion=$(pkgparam SUNWpnm VERSION | cut -d, -f1)
	fi
	if [ -n "${pkgversion}" ]; then
		if [ "${pkgversion}" = "2.0" ]; then
			eval $prdct=\"Sun Cluster 2.0\"
			eval $prdct_type=20
			return 0
		elif [ "${pkgversion}" = "2.1" ]; then
			eval $prdct=\"Sun Cluster 2.1\"
			eval $prdct_type=21
			return 0
		elif [ "${pkgversion}" = "2.2" ]; then
			eval $prdct=\"Sun Cluster 2.2\"
			eval $prdct_type=22

			# make sure the customer is only upgrading the OS to 2.7
			# (or 2.8)
			if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
				return 0
			else
				return 1
			fi
		else
			printf "$(gettext 'Sun Cluster %s software has been detected, but')\n" "$pkgversion"
			printf "$(gettext 'upgrading from this version is not supported!')\n"
			Pause
			return 1
		fi

	#
	# Assuming that if hadfconfig is found, it will always be from
	# HA1.3.
	#
	# If upgrade died somewhere along the way, and the framework has
	# already been upgraded, then if SUNWsc is the last framework
	# package to be replaced (see where pkgstatus is set at the beginning
	# of this function) and it hasn't been installed then upgrade can
	# be re-run. Installed HA1.3 data service packages aren't tracked
	# so can't used their status as a way to determine where the
	# upgrade died.
	#
	elif [ -s "${HADFCONFIGDIR}/${HADFCONFIGFILE}" ] || \
	    [[ ( -s "${HADFCONFIGDIR}.obsolete/${HADFCONFIGFILE}" ) && \
	    ( ${pkgstatus} == 1 ) ]]; then
		eval $prdct=\"Solstice HA 1.3\"
		eval $prdct_type=13
		return 0
	else
		return 1
	fi
}

###
#
# upgrade_pvtlinks
#
#     Add the IP addresses for all non-local private links to /.rhosts
#
#     Return:
#		0	Success
#		1	Failed to update /.rhosts
#
function upgrade_pvtlinks
{
	typeset thishost
	typeset hahost_ipaddr
	typeset phost_ipaddr

	integer num=$(encdbmatch cluster.number.nodes)
	if [ $? -eq 1 ]; then
		printf "$(gettext \
		    'Could not access cluster configuration').\n"
		return 1
	fi

	if [ ! -f "${RHOSTS}" ]; then
		touch  ${RHOSTS}
	fi

	let i=0
	while (( i < ${num} )); do
		thishost=$(encdbmatch cluster.node.${i}.hostname)
		if [ $? -eq 1 ]; then
			printf "$(gettext \
			    'Could not access cluster configuration').\n"
			return 1
		fi
		if [ "${thishost}" = "${LOCALHOSTNAME}" ]; then
			(( i += 1 ))
			continue
		fi

		hahost_ipaddr=$(encdbmatch cluster.node.${i}.hahost)
		if [ $? -eq 1 ]; then
			printf "$(gettext \
			    'Could not access cluster configuration').\n"
			return 1
		fi

		egrep "^${hahost_ipaddr}[ 	]*root" ${RHOSTS} >/dev/null \
		    2>&1
		if [ $? -eq 1 ]; then
			printf  "%s root\n" "${hahost_ipaddr}" >> ${RHOSTS}
			if [ $? -ne 0 ]; then
				printf "$(gettext \
				    'Cannot write to \"%s\". The IP addresses of the')\n" "${RHOSTS}"
				printf "$(gettext \
				    'private links must be manually added to \"%s\".')\n" "${RHOSTS}"
				printf "$(gettext \
				    'Please refer to the manual.')\n"
				return 0
			fi
		fi

		let j=0
		while (( j < 2 )); do
			phost_ipaddr=$(encdbmatch cluster.node.${i}.phost.${j})
			if [ $? -eq 1 ]; then
				printf "$(gettext \
				    'Could not access cluster configuration').\n"
				return 1
			fi

			egrep "^${phost_ipaddr}[ 	]*root" ${RHOSTS} \
			    >/dev/null 2>&1
			if [ $? -eq 1 ]; then
				printf "%s root\n" "${phost_ipaddr}" >> \
				    ${RHOSTS}
			fi
			(( j += 1 ))
		done
		(( i += 1 ))
	done

	return 0
}

###
#
# upgrade_from_sc
#
#     prdct_type - An integer which contains a number identifying the
#		   product
#
#     Upgrading from either SC2.0 or SC2.1
#
#     Return:
#		0	Success
#		1	Failed to upgrade
#
function upgrade_from_sc
{
	integer prdct_type=$1

	# I need to get some data about the existing configuration before
	# I go too much further.
	#
	# Specifically I need:
	#		cluster.number.nodes		(from cdb)
	#		cluster.node.[0-3].hostnames 	(from cdb)
	#		cluster.pdbapps			(from cdb)
	#		cluster.net_if_type		(from cdb)
	#		ccd.ccddevice.ssa		(from init ccd)
	#

	integer numofnodes=$(encdbmatch cluster.number.nodes)
	integer mynodeid=$(get_nodeids)
	typeset private_if=$(encdbmatch cluster.net_if_type)
	typeset sharedccd=$(enccdmatch ccd.ccddevice.ssa)
	integer scapps=$(encdbmatch cluster.pdbapps)

	typeset cdbtmpltfile=${CONFIGDIR}/TEMPLATE.cdb
	typeset ccdtmpltfile=${CONFIGDIR}/ccd.TEMPLATE.init
	typeset ccdinitfile=${CONFIGDIR}/ccd.sccf.init
	typeset systmpltfile=${SYSSCRIPTDIR}/TEMPLATE.sys_script
	typeset hatmpltfile=${CONFIGDIR}/ha.ccd

# bug fix 4158084. In order to ensure that the upgrade from SC 2.1 to SC 2.2
# work with the BASEDIR parameter in SUNWsc changed from "/opt" to "/", we
# create a symbolic link /SUNWcluster to /opt/SUNWcluster so that SC 2.1
# preremove scripts don't break. Now to make sure that the user doesn't have
# anything by the name of /SUNWcluster alreday we check for it and ask the user
# to rename it for the duration of upgrade process.

	if [[ -a /SUNWcluster ]]; then
		echo "========================================================="
		echo "You have a file, directory or link in the root directory,"
		echo "by the name of SUNWcluster."
		echo "For the Upgrade procedure to SC 2.2 to function correctly"
		echo "you must rename it to something else. You'll be able to"
		echo "rename it back to /SUNWcluster after the upgrade is done."
		echo "Please rename /SUNWcluster and run the scinstall/upgrade" 
		echo "again."
		echo "========================================================="
		exit 0
	else
		ln -s /opt/SUNWcluster /SUNWcluster
	fi

	if [[ ! -d ${SAVEDIR} ]]; then
		/bin/mkdir -p ${SAVEDIR}
	fi

	if [[ "${private_if}" = "SCI" ]]; then
		save_sci_config
		remove_sci_pkgs
		if [ $? -eq 1 ]; then
			return 1
		fi
		add_sci_pkgs
		if [ $? -eq 1 ]; then
			restore_sci_config
			return 1
		fi
		restore_sci_config
	else
		remove_ether_pkgs
		if [ $? -eq 1 ]; then
			return 1
		fi
		add_ether_pkgs
		if [ $? -eq 1 ]; then
			return 1
		fi
	fi

	if [[ "${sharedccd}" = "ccdvol" ]]; then
		save_shared_ccd_config
	fi
	save_ccd_config
	generic_pkg_rm "SUNWsccf"
	if [ $? -eq 1 ]; then
		return 1
	fi
	remove_ccd_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi
	generic_pkg_add -p ${MEDIA} "SUNWsclb"
	if [ $? -eq 1 ]; then
		return 1
	fi
	add_ccd_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi
	touch ${SCTMPDIR}/upgrade_response$$
	generic_pkg_add -p ${MEDIA} -r ${SCTMPDIR}/upgrade_response$$ "SUNWsccf"
	if [ $? -eq 1 ]; then
		rm ${SCTMPDIR}/upgrade_response$$
		return 1
	fi
	rm ${SCTMPDIR}/upgrade_response$$
	restore_ccd_config
	if (( prdct_type == 20 )); then
		upgrade_ccd_config
	fi

	# There are several new tokens that have been added to the
	# cdb file between SC2.0 and SC2.2. Some may have been included
	# by patches but not all.
	upgrade_cdb_config

	# We are ready to update the remain framework pkgs. We have
	# already taken care of: 
	#		SUNWsma,SUNWscid,SUNWsci (if present)
	#		SUNWccd
	# Now we are going to deal with any remaining framework pkgs.

	upgrade_fw_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi

	upgrade_inetpro_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi
	upgrade_hadbms_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi

	upgrade_udlm_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi

	complete_upgrade ${prdct_type} ${numofnodes}
	if [ $? -eq 1 ]; then
		return 1
	fi

	upgrade_pvtlinks
	if [ $? -eq 1 ]; then
		return 1
	fi

	if [ -f ${cdbtmpltfile} ]; then
		rm -f ${cdbtmpltfile} 2>/dev/null
	fi
	if [ -f ${ccdtmpltfile} ]; then
		rm -f ${ccdtmpltfile} 2>/dev/null
	fi
	if [ -f ${ccdinitfile} ]; then
		rm -f ${ccdinitfile} 2>/dev/null
	fi
	if [ -f ${systmpltfile} ]; then
		rm -f ${systmpltfile} 2>/dev/null
	fi

#	if [ -f ${TC_SSP_DATA} ]; then
#		printf "*** $(gettext \
#		    'If it has not been done already, please remember to put' \
#		    ) ***\n"
#		printf "*** $(gettext \
#		    'a copy of \"%s\" into \"/var/tmp\" on the') ***\n" \
#		    "${TC_SSP_DATA}"
#		printf "*** $(gettext \
#		    'rest of the nodes in the cluster'). ***\n"
#	fi

# remove the symbolic link to /opt/SUNWcluster that we created at the beginning.
	if [[ -L /SUNWcluster ]]; then
		rm -f /SUNWcluster
	fi

	return 0
}

###
#
# checkNumInstance
#
#     Copied from the original (pre-SC2.2) subroutines.ksh because it
#     disappears in SC2.2.
#
checkNumInstance(){
	typeset package=$1

	if pkginfo -q ${package} >/dev/null 2>&1 ; then
		set -A info `pkginfo ${package} | tr -s " " | cut -d " " -f 2`
	else
		set -A info ""
	fi
	print "${info[*]}"
}

###
#
# checkPkgInstances
#
#     Copied from the original (pre-SC2.2) subroutines.ksh because it
#     disappears in SC2.2.
#
checkPkgInstances(){
	typeset tolist=$1
	typeset fromlist=$2

	typeset ck_package
	typeset pkginstances
	typeset i

	for ck_package in `eval echo \\$\{$fromlist[*]\}`; do
		CheckForPatchID ${ck_package}
		if [ $? -eq 1 ]; then
			return 1
		fi
		set -A pkginstances $(checkNumInstance ${ck_package})
		if [ -n "${pkginstances[*]}" ]; then
			AddToList "$tolist" ${ck_package}
		fi
	done
	return 0
}

###
#
# upgrade_uninstall_solstice_ha
#
#     dspkglist - Return the list of installed HA data service packages
#
#     Remove HA1.3 packages keeping a record in memory of which HA data
#     services are installed.
#
#     This function depends on checkPkgInstances from subroutines.ksh
#
#     Return:
#		0	Success
#		1	Unable to remove packages
#
function upgrade_uninstall_solstice_ha
{
	typeset cname_installed
	typeset clustername
	typeset pkglist
	typeset dspkglistarg
	typeset dspkglist
	typeset haadminfile
	typeset hafwlist
	typeset hadslist
	typeset pkg
	integer i

	set -A hafwlist "SUNWcmm SUNWff SUNWhagen SUNWabha"
	# list of HA1.3 data services; SUNWhapro must come after dependent pkgs
	set -A hadslist \
	    "SUNWhasap SUNWhadns SUNWhasws SUNWhansl SUNWhahtt SUNWhanew SUNWhansm SUNWhapro SUNWhainf SUNWhaor SUNWhasyb SUNWhanfs"

	dspkglistarg=$1

	# build a list of packages that are installed
	checkPkgInstances pkglist hafwlist
	if [ $? -eq 1 ]; then
		printf "$(gettext \
		    'An error occured while searching through packages').\n"
		printf "$(gettext 'No packages were removed').\n"
		return 1
	fi
	checkPkgInstances dspkglist hadslist
	if [ $? -eq 1 ]; then
		printf "$(gettext \
		    'An error occured while searching through packages').\n"
		printf "$(gettext 'No packages were removed').\n"
		return 1
	fi

	# check if CLUSTERNAME already exists
	hadfentry=$(grep CLUSTERNAME ${HADFCONFIGDIR}/${HADFCONFIGFILE} 2>&1 \
	    /dev/null)
	if [ $? -eq 0 ]; then
		clustername=$(echo $hadfentry | tr -s " " | \
		    cut -d " " -f 2)
		cname_installed=1
	else
		clustername=""
		cname_installed=0
		echo ""
	fi

	#
	# Add CLUSTERNAME keyword to hadfconfig
	#
	while [ -z "${clustername}" ]; do
		printf "$(gettext \
		    'What is the name of the cluster')? "
		read clustername
		echo "${clustername}" | grep "^[a-zA-Z]\{1,\}[a-zA-Z0-9_-]*$" \
		    > /dev/null 2>&1
		if [ $? -ne 0 -o "${clustername}" = "hadf" ]; then
			printf "\t$(gettext \
			    'ERROR:  The cluster name should not contain spaces or special')\n"
			printf "\t$(gettext \
			    'characters or be called \"hadf\"')\n\n"
			clustername=""
		fi
	done
	if [ $cname_installed -eq 0 ]; then
		printf "CLUSTERNAME\t%s\n" "${clustername}" >> \
		    ${HADFCONFIGDIR}/${HADFCONFIGFILE}
		echo ""
	fi

	haadminfile=${SCTMPDIR}/${Myname}.admin.$$
	cat >${haadminfile} <<END
basedir=default
mail=
runlevel=quit
conflict=nocheck
setuid=nocheck
action=nocheck
partial=quit
instance=unique
idepend=quit
rdepend=quit
space=quit
END

	if [ ${#dspkglist[*]} -gt 0 ]; then
		generic_pkg_rm -a ${haadminfile} ${dspkglist[*]}
		if [ $? -eq 1 ]; then
			rm -f ${haadminfile}
			return 1
		fi
	fi

	let i=0
	for pkg in ${dspkglist[*]}; do
		eval ${dspkglistarg}[${i}]=${pkg}
		(( i += 1 ))
	done
	if [ ${#pkglist[*]} -gt 0 ]; then
		set -A pkglist $(ReverseList pkglist)
		generic_pkg_rm -a ${haadminfile} ${pkglist[*]}
		if [ $? -eq 1 ]; then
			rm -f ${haadminfile}
			return 1
		fi
	fi
	rm -f ${haadminfile}

	return 0
}

###
#
# upgrade_reset_pnm
#
#     Let PNM know that there's a new configuration. The configuration was set
#     by haupgrd.
#
#     This piece of code was snipped from sclhosts_initialize_nafo.
#
#     Return:
#		0	Success
#		1	Unable to reset PNM
#
function upgrade_reset_pnm
{
	# run pnmset
	${PNMSET} -n >/dev/null 2>${SCTMPDIR}/pnmsetlog.$$
	if [ $? -ne 0 ]; then
		if [ -s ${SCTMPDIR}/pnmsetlog.$$ ]; then
			printf "\n    $(gettext '\
			    %s failed with the following error:')\n\n" "${PNMSET}"
			while read line
			do
				printf "\t%s\n" "${line}"
			done <${SCTMPDIR}/pnmsetlog.$$
			printf "\n"
		else
			printf "\n    $(gettext '%s failed!')\n\n" "${PNMSET}"
		fi
		rm -f ${SCTMPDIR}/pnmsetlog.$$
		return 1
	fi
	rm -f ${SCTMPDIR}/pnmsetlog.$$

	return 0
}

###
#
# upgrade_from_ha
#
#     Upgrade from HA1.3. Installs the SC2.2 packages.
#
#     Return:
#		0	Success
#		1	Unable to complete the upgrade
#
function upgrade_from_ha
{
	typeset pkglist
	typeset dspkglist
	typeset dspkg
	set -A hadspkgs ""
	integer scdspkg

	upgrade_uninstall_solstice_ha hadspkgs
	if [ $? -eq 1 ]; then
		printf "$(gettext \
		    'An error has occured while attempting to process')\n"
		printf "$(gettext 'Solstice HA 1.3 packages').\n"
		return 1
	fi

	set -A pkglist ${serverList[*]}
	if [ "${OSVERSION}" = "5.7" ] || [ "${OSVERSION}" = "5.8" ]; then
		AppendListToList pkglist server27List
	fi

	# construct list of new data service packages to replace HA1.3 packages
	let scdspkg=0
	for dspkg in ${hadspkgs[*]}; do
		if [ "${dspkg}" != "SUNWhanfs" ]; then
			AddToList dspkglist \
			    "$(echo ${dspkg} | sed -e 's:Wha:Wsc:')"
			if [ $? -eq 1 ]; then
				return 1
			fi
		fi

		case ${dspkg} in
		SUNWhasws|SUNWhansl|SUNWhansm|SUNWhasap|SUNWhahtt|SUNWhadns)
			scdspkg=1
			;;
		*)
			;;
		esac
	done
	remove_from_list pkglist "SUNWsccf"
	if [ $? -eq 1 ]; then
		return 1
	fi
	remove_from_list pkglist "SUNWpnm"
	if [ $? -eq 1 ]; then
		return 1
	fi
	generic_pkg_add -p ${MEDIA} ${pkglist[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi
	touch ${SCTMPDIR}/upgrade_response$$
	generic_pkg_add -p ${MEDIA} -r ${SCTMPDIR}/upgrade_response$$ "SUNWsccf"
	if [ $? -eq 1 ]; then
		rm ${SCTMPDIR}/upgrade_response$$
		return 1
	fi
	rm ${SCTMPDIR}/upgrade_response$$
	generic_pkg_add -p ${MEDIA} "SUNWpnm"
	if [ $? -eq 1 ]; then
		return 1
	fi
	add_ether_pkgs
	if [ $? -eq 1 ]; then
		return 1
	fi
	if [ ${scdspkg} -eq 1 ]; then
		generic_pkg_add -p ${MEDIA} "SUNWscpro"
		if [ $? -eq 1 ]; then
			return 1
		fi
		generic_pkg_add -p ${MEDIA} "SUNWscds"
		if [ $? -eq 1 ]; then
			return 1
		fi
	fi
	generic_pkg_add -p ${MEDIA} ${dspkglist[*]}
	if [ $? -eq 1 ]; then
		return 1
	fi

	# kick pnmd
	upgrade_reset_pnm
	if [ $? -eq 1 ]; then
		printf "\n$(gettext \
		    '*** Please execute \"%s -n\" before') ***\n" "${PNMSET}"
		printf "***       $(gettext \
		    'starting the cluster').       ***\n"
	fi

	printf "\n\n    $(gettext \
	    'The original configuration files have been')\n"
	printf "    $(gettext \
	    'saved in') \"%s\"\n" "${HADFCONFIGDIR}.obsolete"
	printf "    $(gettext \
	    'You may remove this directory at your')\n"
	printf "    $(gettext \
	    'leisure').\n"

	return 0
}
#######################################################
####  Main Program   ##################################
#######################################################

#pragma ident       "@(#)scinstall.ksh 1.52     00/08/25 SMI"

#include init.ksh
#include dialogs.ksh
#include editfiles.ksh
#include subroutines.ksh
#include sclhosts_subroutines.ksh

####################################################################
# Menus and configuration
#

#Configure Node Information
ConfigureNode() {
	typeset prompt
	typeset answer
	integer nodecntr

	#Assign cluster name
	AssignClusterName
	SaveClusterName

	#Set number of nodes
	AssignNumOfNodes

	#Set the Network Interface Type
	AssignNetIfType

	#Assign the Node Names
	AssignNodeNames
	SaveNodeInfo

	#If HA data services, initialize Logical Hosts and NAFO
	# jhc - 4/22/98
	printf "\n"
	prompt="$(gettext 'Will this cluster support any HA data services')"
	answer=$(prompt_yesno "${prompt}" "${YES}")
	if [ "${answer}" = "${YES}" ]; then
		prompt="$(gettext 'Okay to set up the logical hosts for those HA services now')"
		answer=$(prompt_yesno "${prompt}" "${YES}")
		printf "\n"
		if [ "${answer}" = "${YES}" ]; then
			sclhosts_initialize
			if [ $? -ne 0 ]; then
				printf "\n$(gettext 'Exiting due to fatal error!')\n\n"
				exit 1
			fi
		fi
	fi
	printf "\n"

	#If SDS is chosen, then failure fencing and quorum is NOT supported.
	if ! (( ${PDBAPPS} & (1 << 5) )); then

		# Failure Fencing
		if (( NUMOFNODES > 2 )); then

			# initialize global TC/SSP variables
			let TC_SSP_Counter=0
			set -A TC_SSP_IP ""
			set -A TC_SSP_AK ""
			set -A TC_SSP_ARCH ""
			set -A TC_SSP_PORT ""
			set -A TC_PORT_NUM ""
			set -A TC_PORT_IP ""
			set -A TC_SSP_Name ""
			set -A TC_SSP_Type ""
			TC_SSP_NODELOCK=""
			TC_Counter="None"
			SSP_Counter="None"

			let nodecntr=1
			let LOOPCNTR=0
			printf "$(gettext 'Configuring Failure Fencing')\n"
			while (( nodecntr <= ${NUMOFNODES} )) ; do
				GetNodeInfo ${NODENAMES[${nodecntr}]}
				
				(( LOOPCNTR += 1 ))
				(( nodecntr += 1 ))
			done

			#
			# 4171113 - Make sure this info is written to the CDB
			#	    before setting quorum
			#
			SaveNodeInfo
			echo ""
			printf "$(gettext \
			    'Finished Configuring Failure Fencing')\n\n"
		fi

		#Set Quorum
		echo ""
		echo "Performing Quorum Selection"
		echo ""
		if (( NUMNODEACTIVE > 0 )) && \
		    (( NUMNODEACTIVE <= NUMOFNODES )); then
			DirectConnect
			if [ ${DIRECTC} -eq 1 ]; then
				GetNodeLock

				#
				# 4171113 - Make sure this info is written to
				#	    the CDB before setting quorum
				#
				SaveNodeInfo
			fi
		fi
		echo ""
		SetQuorum
		echo ""
		echo "Finished Quorum Selection"
		echo ""
		echo ""

		#Set Partitions
		if (( NUMNODEACTIVE > 2 )); then
			OptPartitions
		fi
	fi

	if (( NUMNODEACTIVE > 2 )); then
		SaveNodeInfo
	fi

	#Install NETIFTYPE packages
	InstallNETIF
}

#Show the change menu
ShowChangeMenu() {
	typeset menuList=$1
	integer i 
	integer j

	echo "${changeMenuBanner}"
	if [ "${RUNNING}" == "no" ] && [ "${nodeInfoWorks}" == "yes" ]; then
		echo "${CHANGECOUNT}) Node Information      - Change the information about the nodes in this"
		echo "                           cluster."
		eval ${menuList}[${CHANGECOUNT}]="NodeInfo"
		((CHANGECOUNT += 1))
	fi
	if [ "${RUNNING}" == "no" ] && [ ${DSCOUNTER} -gt 1 ] && [ ${DSUNINSTCOUNT} -ne 0 ]; then
		echo "${CHANGECOUNT}) Add Data Services     - Install Data Service packages onto the system."
		eval ${menuList}[${CHANGECOUNT}]="AddDataService"
		((CHANGECOUNT += 1))
	fi
	if [ "${RUNNING}" == "no" ] && [ ${DSCOUNTER} -gt 1 ] && [ ${DSINSTCOUNT} -ne 0 ]; then
		echo "${CHANGECOUNT}) Remove Data Services  - Remove Data Service packages from the system."
		eval ${menuList}[${CHANGECOUNT}]="RemoveDataService"
		((CHANGECOUNT += 1))
	fi

	if [ "${RUNNING}" == "no" ]; then
		if ! (( PDBAPPS & (1 << 3) )) && ! (( PDBAPPS & (1 << 4) )) && \
		     ! (( PDBAPPS & (1 << 5) )); then
			echo "${CHANGECOUNT}) Choose Volume Manager - Select a volume manager to add to this"
			echo "                           node's configuration."
			eval ${menuList}[${CHANGECOUNT}]="AddVolumeManager"
			((CHANGECOUNT += 1))
		fi
		if (( PDBAPPS & (1 << 3) )) || (( PDBAPPS & (1 << 4) )) || \
		     (( PDBAPPS & (1 << 5) )); then
			echo "${CHANGECOUNT}) Remove Volume Manager - Remove the volume manager from this"
			echo "                           node's configuration."
			eval ${menuList}[${CHANGECOUNT}]="RemoveVolumeManager"
			((CHANGECOUNT += 1))
		fi
	fi

	if [ "${RUNNING}" == "no" ] && [ "${quorumWorks}" == "yes" ]; then
		echo "${CHANGECOUNT}) Quorum Device       - Select a device for quorum."
		eval ${menuList}[${CHANGECOUNT}]="Quorum"
		((CHANGECOUNT += 1))
	fi

	# Set NODENAMES, if not already set
	# jhc - 04/22/98
	if [ -z "${NODENAMES[*]}" ]; then
		setnodenames
	fi
		
	# NODENAMES must be set to change either lhosts or NAFO
	# jhc - 04/22/98
	if [ "${NODENAMES[*]}" ] &&
	    [ $(set -- ${NODENAMES[*]}; echo $#) -ge 2 ]; then 
		# Change the logical hosts configuration	jhc - 04/22/98
		echo "${CHANGECOUNT}) Logical Hosts         - Change the logical hosts configuration."
		eval ${menuList}[${CHANGECOUNT}]="Loghost"
		((CHANGECOUNT += 1))

		# Re-initialize NAFO				jhc - 04/22/98
		echo "${CHANGECOUNT}) NAFO                  - Re-initialize the NAFO configuration."
		eval ${menuList}[${CHANGECOUNT}]="NAFO"
		((CHANGECOUNT += 1))
	fi

	echo ""
	echo "${CHANGECOUNT}) Close  - Close this menu to return to the Main Menu."
	eval ${menuList}[${CHANGECOUNT}]="Close"
	((CHANGECOUNT += 1))
	echo "${CHANGECOUNT}) Quit   - Exit this program."
	eval ${menuList}[${CHANGECOUNT}]="Quit"
	((CHANGECOUNT += 1))
	echo "${CHANGECOUNT}) Help   - Show the Help screen."
	eval ${menuList}[${CHANGECOUNT}]="Help"
}

#Change menu routines
ChangeMenu() {

	typeset changeLoop="loop"
	integer CHANGECOUNT=1
	integer tmpAnswer
	set -A changeList ""

	typeset nodeInfoWorks="yes"
	typeset quorumWorks="no"

	while [ "${changeLoop}" == "loop" ]; do
		let CHANGECOUNT=1
		ShowChangeMenu changeList
		MyRead -i -p "Please choose a displayed option:" -d "${CHANGECOUNT}"  -h changeMenuHelp
		if [ ${ANSWER} -lt 1 ] || [ ${ANSWER} -gt ${CHANGECOUNT} ]; then
			echo "Please enter a number shown."
			continue
		fi
		let tmpAnswer=${ANSWER}
		changeAnswer=${changeList[${tmpAnswer}]}
		case "${changeAnswer}" in
		"NodeInfo")
			ConfigureNode
			;;
		"AddDataService")
			ConfigureDataServices 0
			;;
		"RemoveDataService")
			ConfigureDataServices 1
			;;
		"AddVolumeManager")
			ConfigureVolumeManager
			;;
		"RemoveVolumeManager")
			echo "Remove Volume Manager"
			RemoveVolumeManager
			;;
		"Quorum")
			echo "Quorum Selection"
			;;
		"Loghost")
			sclhosts_change
			;;
		"NAFO")
			sclhosts_nafo_change
			;;
		
		"Close")
			changeLoop="stop"
			;;
		"Quit")
			exit 0
			;;
		"Help")
			echo "${changeMenuHelp}"
			Pause
			;;
		*)
			echo "Please enter a number shown."
			;;
		esac
	done
}


#Get Location of Packages
GetMediaLocation() {
	typeset pkgType=$*

	typeset pkgpath
	typeset locationLoop="loop"

	#
	# CDIMAGEPATH and MEDIA might be set by scbootstrap. If they were,
	# then CDPATHSET is set to 1 and all three variables were exported
	# to the environment by scbootstrap and used here in place of
	# prompting for the path
	#
	if (( CDPATHSET == 0 )); then
		while [ "${locationLoop}" == "loop" ]; do
			MyRead -p "What is the path to the CD-ROM image" \
			    -d "${CDIMAGEPATH}"
			if [ -n "${CDOSNAME}" ]; then
				if [[ "${OSVERSION}" == "5.8" ]] ; then
					pkgpath="${CDPRODUCTNAME}/${CDOSNAME}/Packages"
				else
					pkgpath="${CDPRODUCTNAME}/${CDOSNAME}/Product"
				fi
			fi
			if [ ! -d "${ANSWER}/${pkgpath}" ]; then
				echo ""
				echo "    ERROR:  Invalid path."
				echo ""
			else
				CDIMAGEPATH=${ANSWER}
				ANSWER=${ANSWER}/${pkgpath}
				locationLoop="stop"
			fi
		done
		MEDIA="${ANSWER}"
	else

		# make sure prompt for path if this function is called again
		let CDPATHSET=0
	fi
}

#Remove Framework packages
RemoveServerOrClient() {
	typeset choice=$1

	typeset removeList=""
	typeset tmpInteractive
	typeset RFCHOICE=""

	echo ""
	if [ "${choice}" = "Server" ]; then
		if (( DSINSTCOUNT == 0 )); then
			echo "Removing Server packages"
			if [ -n "${SCDSListI[*]}" ]; then
				AppendListToList removeList SCDSListI
			fi
			AppendListToList removeList serverListI
		else
			printf "    $(gettext \
			    'Data Service packages must be removed first. These packages can')\n"
			printf "    $(gettext \
			    'be removed from the \"Change\" menu').\n"
			Pause
			return 1
		fi
	fi
	if [ "${choice}" == "Client" ]; then
		echo "Removing Client packages"
		AppendListToList removeList clientListI
	fi
	if [ "${choice}" == "Obsolete" ]; then
		echo "Removing Client packages"
		AppendListToList removeList obsoleteListI
	fi
	if [ "${choice}" == "Both" ]; then
		if (( DSINSTCOUNT == 0 )); then
			echo "Removing Server and Client Packages"
			if [ -n "${SCDSListI[*]}" ]; then
				AppendListToList removeList SCDSListI
			fi
			AppendListToList removeList serverListI
			AppendListToList removeList clientListI
		else
			printf "    $(gettext \
			    'Data Service packages must be removed first. These packages can')\n"
			printf "    $(gettext \
			    'be removed from the \"Change\" menu').\n"
			Pause
			return 1
		fi
	fi

	RFCHOICE="${choice}"
	RemoveList "removeList"
	if [ -z "${serverListI[*]}" ] && [ -z "${clientListI[*]}" ]; then
		#No reason to keep the install package
		tmpInteractive="${INTERACTIVE}"
		INTERACTIVE="no"
		RemoveList "installListI"
		INTERACTIVE="${tmpInteractive}"
		ReInit
	fi
}

#Install Server packages
InstallServerOrClient() {
	typeset choice=$1

	typeset installList=""

	echo ""
	if [ -z "${choice}" ]; then
		return 0
	fi
	if [ -n "${installListU[*]}" ]; then
		AppendListToList installList installListU
	fi
	if [ "${choice}" == "Server" ]; then
		echo "Installing Server packages"
		AppendListToList installList serverListU
	fi
	if [ "${choice}" == "Client" ]; then
		echo "Installing Client packages"
		AppendListToList installList clientListU
	fi
	if [ "${choice}" == "Both" ]; then
		echo "Installing Server and Client Packages"
		AppendListToList installList serverListU
		AppendListToList installList clientListU
	fi
	
	#Install the list of packages
	InstallList installList 
	return $?
}

#Client or Server or Obsolete?
ServerOrClientChoice() {
	typeset choice=$1
	typeset helpName=$2
	typeset serverName=$3
	typeset clientName=$4
	typeset obsoleteName=$5

	typeset serverList=""
	typeset clientList=""
	typeset obsoleteList=""
	typeset helpMessage=""
	typeset choiceLoop=""
	set -A frameworkChoices ""
	typeset product_string=""
	typeset action_string="Install"
	integer product_type=0
	integer counter=1

	eval serverList=\$\{${serverName}}
	eval clientList=\$\{${clientName}}
	eval obsoleteList=\$\{${obsoleteName}}
	eval helpMessage=\$\{${helpName}}

	if [ "${helpName}" == "helpRemoveFramework" ]; then
		action_string="Remove"
	fi

	while [ -z "${choiceLoop}" ]; do
		let counter=1
		echo "${helpMessage}"
		echo "Choose one:"
		if [ "${helpName}" == "helpInstallFramework" ]; then
			frameworkChoices[${counter}]="Upgrade"
			printf "%d) $(gettext 'Upgrade            Upgrade to Sun Cluster') %s" "${counter}" "${VERSION}"
			printf "$(gettext ' Server packages')\n"
			(( counter = counter + 1 ))
		fi
		if [ -n "${serverList}" ]; then
			frameworkChoices[${counter}]="Server"
			echo "${counter}) Server             ${action_string} the Sun Cluster packages needed on a server"
			(( counter = counter + 1 ))
		fi
		if [ -n "${clientList}" ]; then
			frameworkChoices[${counter}]="Client"
			echo "${counter}) Client             ${action_string} the admin tools needed on an admin workstation"
			(( counter = counter + 1 ))
		fi
		if [ -n "${serverList}" ] && [ -n "${clientList}" ]; then
			frameworkChoices[${counter}]="Both"
			echo "${counter}) Server and Client  ${action_string} both Client and Server packages"
			(( counter = counter + 1 ))
		fi
		if [ -n "${obsoleteList}" ]; then
			frameworkChoices[${counter}]="Obsolete"
			echo "${counter}) Obsolete           All of the Obsolete Client and Server packages"
			(( counter = counter + 1 ))
		fi
		echo ""
		frameworkChoices[${counter}]="Close"
		echo "${counter}) Close	      Exit this Menu"
		(( counter = counter + 1 ))
		frameworkChoices[${counter}]="Quit"
		echo "${counter}) Quit               Quit the Program"
		MyRead -i -p "Enter the number of the package set" -d "${counter}"
		if [ ${ANSWER} -lt 1 ] || [ ${ANSWER} -gt ${counter} ]; then
			echo "Please enter a number shown."
			continue
		fi
		choiceLoop="${frameworkChoices[${ANSWER}]}"
		if [ "${choiceLoop}" == "Quit" ]; then
			exit 0
		fi
	done
	eval ${choice}="${choiceLoop}"
}

#Remove the framework
RemoveFramework() {

	typeset removeLoop="loop"
	typeset serverOrClient=""
	typeset dummyU=""

	while [ "${removeLoop}" == "loop" ]; do
		#Server or Client or Both?
		ServerOrClientChoice serverOrClient helpRemoveFramework serverListI clientListI obsoleteListI
		if [ "${serverOrClient}" == "Close" ]; then
			removeLoop="stop"
		else
			RemoveServerOrClient "${serverOrClient}"
		fi
		if [ -z "${obsoleteList}" ] && [ -z "${serverListI}" ] && \
		   [ -z "${clientListI}" ]; then
			echo ""
			echo "No packages left to remove."
			echo "Closing Remove Framework Menu."
			echo ""
			removeLoop="stop"
		fi

		# 4171469 - Make sure PDBAPPS is re-read after the potential
		#	    removal of the CDB file
		GetPDBAPPS
	done
}

#Install Framework
#Returns:
# 0 - package set installed
# 1 - menu closed without installation
# 2 - error during installation
InstallFramework() {

	typeset serverLoop="loop"
	typeset serverOrClient=""
	typeset dummyU=""
	typeset product_string=""
	integer product_type=0
	integer rstatus=1

	while [ "${serverLoop}" == "loop" ]; do
		#Server or Client or Both?
		ServerOrClientChoice serverOrClient helpInstallFramework serverListU clientListU dummyU
		if [ "${serverOrClient}" == "Close" ]; then
			return 1
		fi

		if [ "${serverOrClient}" == "Upgrade" ]; then
			upgrade_check_for_product product_string product_type
			if [ $? -eq 0 ]; then
				if [[ "${OSVERSION}" == "5.8" && \
				    ${product_type} == 22 ]]; then
					printf "\n$(gettext 'Upgrading to the Solaris 2.8 version of %s').\n\n" \
				    "${product_string}"
				else
					printf "\n$(gettext 'Upgrading from %s').\n\n" \
					    "${product_string}"
				fi

				#Where is the media? - set Global Variables
				GetMediaLocation "Framework"

				if (( product_type == 13 )); then
					upgrade_from_ha
					rstatus=$?
				else
					upgrade_from_sc ${product_type}
					rstatus=$?
				fi
				if [ ${rstatus} -eq 1 ]; then
					printf "\n*** $(gettext \
					    'Upgrade failed')! ***\n\n"
					printf "    $(gettext \
					    'Unable to upgrade from \"%s\" to')\n" "${product_string}"
					printf "    $(gettext \
					    '\"Sun Cluster') %s\".\n" \
					    "${VERSION}"
					printf "\n    $(gettext \
					    'Please fix any problems encountered and')\n"
					printf "    $(gettext \
					    're-run the upgrade').\n"
					printf "\n    $(gettext \
					    'NOTE:  You may have to manually install any')\n"
					printf "    $(gettext \
					    '       data service packages').\n\n"
				else
					printf "\n*** $(gettext \
					    'Upgrade succeeded'). ***\n\n"

					SetDataServices
					ReInit
				fi
			else
				printf "\n\t$(gettext \
				    'There is nothing to upgrade')!\n"
				Pause

				#
				# this is set to avoid printing bogus error
				# dialog regarding installation
				#
				rstatus=3
			fi
		else

			#Where is the media? - set Global Variables
			GetMediaLocation "Framework"

			#Install Server and/or Client
			InstallServerOrClient "${serverOrClient}"
			rstatus=$?
		fi
		case ${rstatus} in
		0)
			serverLoop="stop"
			if [ "${serverOrClient}" == "Server" ] || \
			    [ "${serverOrClient}" == "Both" ]; then
				if [ ! -d ${VARDIR} ]; then
					mkdir -p ${VARDIR}
				fi
				if [ ! -f ${LOGFILE} ]; then
					/usr/bin/touch ${LOGFILE}
				fi
				echo "Sun Cluster software installed: `date`" >> ${LOGFILE}
			fi

			#
			# separated from previous conditional block in order to
			# print correct message in ${LOGFILE}
			#
			if [ "${serverOrClient}" == "Upgrade" ]; then
				if [ ! -d ${VARDIR} ]; then
					mkdir -p ${VARDIR}
				fi
				if [ ! -f ${LOGFILE} ]; then
					/usr/bin/touch ${LOGFILE}
				fi
				echo "Sun Cluster software upgraded: `date`" >> ${LOGFILE}
			fi
			;;
		1)
			return 2
			;;
		3)
			#
			# this is set to avoid printing bogus error
			# dialog regarding installation
			#
			return 3
			;;
		*)
			serverLoop="stop"
			;;
		esac
	done

	#Configure the server node
	if [ -z "${serverListU}" ] && \
	    [ "${serverOrClient}" == "Both" -o \
	    "${serverOrClient}" == "Server" ]; then

		#Configure Volume Manager
		#
		# This was moved here from after ConfigureDataServices
		# because the volume manager needs to be selected before
		# configuring node information, via ConfigureNode, which
		# also configures the quorum device which should not be
		# configured if SDS is the volume manager.
		#
		ConfigureVolumeManager

		#Configure Node Information 
		ConfigureNode

		#
		# This was put here because the CDB file did not exist
		# when the original attempt to store PDBAPPS occured in
		# ConfigureVolumeManager.
		#
		SavePDBAPPS

		#Configure Data Services
		ConfigureDataServices
	fi
	return 0
}

#Perform a complete installation from scratch
CompleteInstall() {
	typeset frameworkLoop="loop"

	echo ""
	echo "None of the Sun Cluster software has been installed"
	Pause

	#Configure Framework 
	while [ "${frameworkLoop}" == "loop" ]; do
		InstallFramework
		case $? in
		0)
			let PDBAPPS=0
			frameworkLoop="stop"
			;;
		1)
			echo "${needFrameworkError}"
			Pause
			;;
		2)
			echo "${frameworkInstallError}"
			Pause
			exit 1
			;;
		*)
			frameworkLoop="stop"
			;;
		esac
	done
}

# Show the list of installed client and server packages
ShowList() {

	echo ""
	echo "	List of Client and Server packages "
	echo ""
	echo "    Client packages currently installed"
	PrintList clientListI "yes"
	echo "    Client packages currently not installed:"
	PrintList clientListU "no"
	echo ""
	echo "    Server packages currently installed:"
	PrintList serverListI "yes"
	echo "    Server packages currently not installed:"
	PrintList serverListU "no"
	echo ""
	if [ "${INTERACTIVE}" == "yes" ]; then
		Pause
	fi
}

#Show the options available for the main menu
# Modify the List variable with the valid menu options
ShowMainMenu() {
	typeset List=$1

	let MENUCOUNT=1
	echo "${mainMenuBanner}"
	if [ -n "${serverListU[*]}" ] || [ -n "${clientListU[*]}" ]; then
		if [ "${RUNNING}" == "no" ] && [ ${MYUID} -eq 0 ]; then
			eval ${List}[${MENUCOUNT}]="Install"
			echo "${MENUCOUNT}) Install/Upgrade - Install or Upgrade Server"
			echo "             Packages or Install Client Packages."
			((MENUCOUNT=MENUCOUNT+1))
		fi
	fi
	if [ -n "${serverListI[*]}" ] || [ -n "${clientListI[*]}" ]; then
		if [ "${RUNNING}" == "no" ] && [ ${MYUID} -eq 0 ]; then
			eval ${List}[${MENUCOUNT}]="Remove"
			echo "${MENUCOUNT}) Remove  - Remove Server or Client Packages."
			((MENUCOUNT=MENUCOUNT+1))
	
		fi
	fi
	if [ -z "${serverListU[*]}" -o -n "${serverListI[*]}" ]; then
		if [ ${MYUID} -eq 0 ]; then
			eval ${List}[${MENUCOUNT}]="Change"
			echo "${MENUCOUNT}) Change  - Modify cluster or data service configuration"
			((MENUCOUNT=MENUCOUNT+1))
		fi
	fi
	eval ${List}[${MENUCOUNT}]="Verify"
	echo "${MENUCOUNT}) Verify  - Verify installed package sets."
	((MENUCOUNT=MENUCOUNT+1))
	eval ${List}[${MENUCOUNT}]="List"
	echo "${MENUCOUNT}) List    - List installed package sets."
	((MENUCOUNT=MENUCOUNT+1))
	eval ${List}[${MENUCOUNT}]="Quit"
	echo ""
	echo "${MENUCOUNT}) Quit    - Quit this program."
	((MENUCOUNT=MENUCOUNT+1))
	eval ${List}[${MENUCOUNT}]="Help"
	echo "${MENUCOUNT}) Help    - The help screen for this menu."
}

#Present actions available through a menu
MainMenu() {
	
	typeset menuLoop="loop"
	typeset menuChoice
	integer MENUCOUNT=1
	set -A menuList ""
	typeset product_string=""
	integer product_type=0
	integer rstatus=0

	while [ "${menuLoop}" == "loop" ]; do
		set -A menuList ""
		ShowMainMenu menuList
		MyRead -i -p "Please choose one of the menu items:" -d "${MENUCOUNT}"
		if [ ${ANSWER} -lt 1 ] || [ ${ANSWER} -gt ${MENUCOUNT} ]; then
			echo " Please enter a number shown."
			continue
		fi
		menuChoice=${menuList[${ANSWER}]}
		case ${menuChoice} in
		"Quit") 
			menuLoop="stop"
			;;
		"Verify")
			ShowVerify
			Pause
			;;
		"List")
			ShowList
			;;
		"Install")
			InstallFramework
			rstatus=$?
			;;
		"Remove")
			RemoveFramework
			rstatus=$?
			;;
		"Upgrade")
			upgrade_check_for_product product_string product_type
			if [ $? -eq 0 ]; then
 
				#Where is the media? - set Global Variables
				GetMediaLocation "Framework"
				printf "\n** $(gettext \
				    'Upgrading from') %s **\n" \
				    "${product_string}"
				if (( product_type == 13 )); then
					upgrade_from_ha
				else
					upgrade_from_sc ${product_type}
				fi
				rstatus=$?
				if [ ${rstatus} -eq 1 ]; then
					printf "\n*** $(gettext \
					    'Upgrade failed')! ***\n\n" >&2
					printf "    $(gettext \
					    'Unable to upgrade from \"%s\" to')\n" "${product_string}"
					printf "    $(gettext \
					    '\"Sun Cluster') %s\".\n" \
					    "${VERSION}"
					printf "\n    $(gettext \
					    'Please fix any problems encountered and')\n"
					printf "    $(gettext \
					    're-run the upgrade').\n"
					printf "\n    $(gettext \
					    'NOTE:  You may have to manually install any')\n"
					printf "    $(gettext \
					    '       data service packages').\n\n"
				else
					printf "\n*** $(gettext \
					    'Upgrade succeeded'). ***\n\n"

					SetDataServices
					ReInit
				fi
			else
				printf "\n\t$(gettext \
				    'There is nothing to upgrade')!\n"
				Pause

				#
				# this is set to avoid printing bogus error
				# dialog regarding installation and to keep in
				# sync with the other upgrade menu action in
				# InstallFramework()
				#
				rstatus=3
			fi
			;;
		"Change")
			ChangeMenu
			;;
		"Help")
			echo "${mainMenuHelp}"
			Pause
			;;
		*)
			echo "Please select a number shown."
			;;
		esac

		#Place holder for possible future error handling
		case ${rstatus} in
		*)
			;;
		esac
	done
}


############################################################################
# Beginning of Execution
#

CheckEcho
Initialize
SetLists
ReadOptions $@

if [[ -n "${serverListU[*]}" && -n "${clientListU[*]}" ]] && \
    [[ -z "${serverListI[*]}" && -z "${clientListI[*]}" ]]; then
	CompleteInstall

	#
	# 4175619: If the same scinstall session used to install the server
	#	   packages and data service packages, especially OPS, is used
	#	   to remove packages, then the latest recorded PDBAPPS value
	#	   should be loaded.
	#
	GetPDBAPPS
fi
MainMenu

ShowVerify
####
# Exit
if [ ! -f ${LOGFILE} ]; then
	rmdir ${VARDIR} > /dev/null 2>&1
fi
exit 0
