#! /bin/ksh -p
#
# ident "@(#)scsetup.ksh 1.18     01/09/13 SMI"
#
# Copyright (c) 1999-2001 by Sun Microsystems, Inc.
# All rights reserved.
#

#####################################################
#
# Global constants which may be set from the environment
#
# SC_DEBUG can be set to non-NULL to turn on additional debug information.
#  And, if it is set to 2, assume installmode is disabled - init cluster.
#
# SC_MAXNODEID is the maximum node id;  it does not necessarily indicate
#  the maximum number of nodes supported in the cluster for this release.
#
# SC_SCADMINDIR can be set to to point to an alternate lib dir
#
#####################################################
typeset -r SC_DEBUG=${SC_DEBUG:-}
typeset -r SC_MAXNODEID=${SC_MAXNODEID:-12}
typeset -r SC_SCADMINDIR=${SC_SCADMINDIR:-/usr/cluster/lib/scadmin}

# debugging
typeset PRINTDEBUG
if [[ -n "${SC_DEBUG}" ]]; then
	PRINTDEBUG="echo \n"
	PRINTFDEBUG="printf"
else
	PRINTDEBUG=:
	PRINTFDEBUG=:
fi

#####################################################
#
# I18N
#
#####################################################
typeset -rx TEXTDOMAIN=SUNW_SC_CMD
typeset -x TEXTDOMAINDIR=/usr/cluster/lib/locale

#####################################################
#
# Constant globals
#
#####################################################

# Set the PATH
typeset SC_BINDIRS=/usr/cluster/bin
PATH=${SC_BINDIRS}:${PWD}:/bin:/usr/bin:/sbin:/usr/sbin:${PATH}; export PATH

# Program name
typeset -r PROG=${0##*/}

# Global internationalized constant strings
typeset -r YES=$(gettext 'yes')		# I18N "yes"
typeset -r NO=$(gettext 'no')		# I18N "no"

# Libs
typeset -r SC_SCADMINLIBDIR=${SC_SCADMINDIR}/lib
typeset -r SC_LIB_SC=sc_common

# Device groups
typeset -r SCSETUP_DG_VXVM_SET=vxvm
typeset -r SCSETUP_DG_VXVM_LOOKUP=VxVM

# Cluster transport
typeset -r SCSETUP_WILDCAT_ADAPTER="wrsm"
typeset -r SCSETUP_WILDCAT_JUNCTION="sw_wrsm"

# Other constants
typeset -r SC_SCCONF=scconf
typeset -r SC_SCRGADM=scrgadm
typeset -r SC_SCSWITCH=scswitch

#####################################################
#
# Variable globals
#
#####################################################
integer SC_LOADED_COMMON=0		# set to 1 when common libs loaded
integer SCSETUP_ISMEMBER=0		# set to 1, if we are in the cluster
typeset SCSETUP_CMD_LOG			# set to log file, if there is one
typeset SCSETUP_DO_CMDSET		# input to scsetup_do_cmdset()

####################################################
#
# Create descriptor 4 as a dup of the original stdout.
# Functions which want to print user visible output
# to the original stdout have the option of using
# descriptor 4.
#
####################################################
exec 4>&1

#####################################################
#####################################################
##
## General housekeeping and other useful functions
##
#####################################################
#####################################################

#####################################################
#
# print_usage()
#
#	Print usage message to stderr
#
#####################################################
print_usage()
{
	printf "$(gettext 'usage: %s [-f <logfile>]')\n" "${PROG}" >&2

	return 0
}

#####################################################
#
# loadlib() libname flag
#
#	If the "flag" is not set to 1, load the
#	named include file.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
#####################################################
loadlib()
{
	typeset libname=$1
	typeset flag=$2

	# Check flag
	if [[ "${flag}" = 1 ]]; then
		return 0
	fi

	# Load the library
	. ${libname}
	if [[ $? -ne 0 ]]; then
		printf "$(gettext '%s:  Unable to load \"%s\"')\n" "${PROG}" "${libname}" >&2
		return 1
	fi
}

#####################################################
#
# scsetup_continue()
#
#	Is it okay to continue [yes]?
#
#	Return:
#		zero		continue
#		non-zero	do not continue		
#
#####################################################
scsetup_continue()
{
	typeset answer

	answer=$(sc_prompt_yesno "$(gettext 'Is it okay to continue?')" "${YES}") || return 1

	[[ "${answer}" != "yes" ]] && return 1

	return 0
}

#####################################################
#
# scsetup_do_cmdset() [noconfirm]
#
#	noconfirm	- if given, do not re-confirm the update
#			- if 1, just run command
#			- if 2, don't run command, but may ask to log
#
#	Process the list of commands found in the
#	SCSETUP_DO_CMDSET array.
#
#	Return:
#		0		Completed
#		1		Failure occured or user typed Ctrl-D
#		2		User decided not to update
#
#####################################################
scsetup_do_cmdset()
{
	typeset noconfirm=${1}

	sctxt_p1_cmd="$(gettext '
		DEBUG: Please consider the following command:
	')"
	sctxt_p1_cmds="$(gettext '
		DEBUG: Please consider the following commands:
	')"

	integer index
	integer logthem=0
	typeset answer

	# Make sure that SCSETUP_DO_CMDSET is set
	if [[ -z "${SCSETUP_DO_CMDSET[0]}" ]]; then
		return 1
	fi

	# If DEBUG, print command list
	if [[ -n "${SC_DEBUG}" ]]; then

		# Print Messages
		if [[ -z "${SCSETUP_DO_CMDSET[1]}" ]]; then
			sc_print_para "${sctxt_p1_cmd}"
		else
			sc_print_para "${sctxt_p1_cmds}"
		fi

		# Print the command(s)
		let index=0
		while [[ -n "${SCSETUP_DO_CMDSET[index]}" ]]
		do
			printf "           %s\n" "${SCSETUP_DO_CMDSET[index]}"
			((index += 1))
		done
		echo
	fi

	# If we are a cluster member, see if command(s) should be run
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

		# Okay to run?
		if [[ -n "${noconfirm}" ]]; then
			if [[ "${noconfirm}" == 2 ]]; then
				answer="no"
			else
				answer="yes"
			fi
		else
			answer=$(sc_prompt_yesno "$(gettext 'Is it okay to proceed with the update?')" "${YES}") || return 1
		fi
		if [[ "${answer}" = "yes" ]]; then

			# Run and log them
			let index=0
			while [[ -n "${SCSETUP_DO_CMDSET[index]}" ]]
			do
				# Run command
				echo "${SCSETUP_DO_CMDSET[index]}"
				eval ${SCSETUP_DO_CMDSET[index]} 2>&1

				# Check for command success
				if [[ $? -ne 0 ]]; then
					echo
					printf "$(gettext 'Command failed.')\n\n\a"
					sc_prompt_pause
					return 1
				fi

				# If it succeeded, log it, if there is a log
				if [[ -n "${SCSETUP_CMD_LOG}" ]]; then
					echo "${SCSETUP_DO_CMDSET[index]}" >>${SCSETUP_CMD_LOG}
				fi

				# Next
				((index += 1))
			done

			# If we got this far, command(s) must have succeeded
			echo
			if [[ -z "${SCSETUP_DO_CMDSET[1]}" ]]; then
				sc_print_para "$(gettext 'Command completed successfully.')"
			else
				sc_print_para "$(gettext 'Commands completed successfully.')"
			fi

		# Just log it/them?
		elif [[ -n "${SCSETUP_CMD_LOG}" ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'Do you just want to add a commands record to the log?')" "${YES}") || return 1

			# Just log them
			if [[ "${answer}" = "yes" ]]; then
				let logthem=1
			else
				return 2
			fi
		else
			return 2
		fi
	elif [[ -n "${SCSETUP_CMD_LOG}" ]]; then
		# Debug mode, okay to log?
		if [[ -z "${SCSETUP_DO_CMDSET[1]}" ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'DEBUG:  Do you want to log this command?')" "${YES}") || return 1
		else
			answer=$(sc_prompt_yesno "$(gettext 'DEBUG:  Do you want to log these commands?')" "${YES}") || return 1
		fi
		if [[ "${answer}" = "yes" ]]; then
			let logthem=1
		fi
	fi

	# Just log commands?
	if [[ ${logthem} -eq 1 ]] && [[ -n "${SCSETUP_CMD_LOG}" ]]; then
		let index=0
		while [[ -n "${SCSETUP_DO_CMDSET[index]}" ]]
		do
			# Log command
			echo "${SCSETUP_DO_CMDSET[index]}" >>${SCSETUP_CMD_LOG}

			# Next
			((index += 1))
		done
	fi

	sc_prompt_pause || return 1

	return 0
}

#####################################################
#
# scsetup_prompt_nodename() "nodelist" "[prompt]"
#
#	Prompt for a node name, then verify that it is one
#	of the names in the "nodelist".  If "prompt" is not given,
#	a default prompt is used.
#
#	The prompt is printed on file descriptor 4, and the answer
#	is printed to stdout.  File descriptor 4 should be
#	dupped to the original stdout before this function is called.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_prompt_nodename()
{
	typeset nodelist="${1}"
	typeset prompt="${2}"

	typeset dflt_prompt="$(gettext 'Node name?')"
	integer found
	typeset answer
	typeset node

	# If no prompt is given, use the default
	if [[ -z "${prompt}" ]]; then
		prompt="${dflt_prompt}"
	fi

	#
	# The caller of this function should have already opened
	# descriptor 4 as a dup of the original stdout.
	#
	# Dup this function's stdout to descriptor 5.
	# Then, re-direct stdout to descriptor 4.
	#
	# So, the default stdout from this function will go to
	# the original stdout (probably the tty).  Descriptor 5
	# has the answer printed to it.
	#
	exec 5>&1
	exec 1>&4

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the node name
		answer=$(sc_prompt "${prompt}") || return 1

		# Make sure it is a known node
		let found=0
		for node in ${nodelist}
		do
			if [[ "${answer}" = "${node}" ]]; then
				let found=1
				break
			fi
		done

		# If there is a nodelist, but the node is not found, print err
		if [[ -n "${nodelist}" ]] && [[ ${found} -eq 0 ]]; then
			printf "$(gettext 'Unknown node name.')\n\n\a"
			continue
		fi

		# okay
		echo ${answer} >&5
		break
	done

	return 0
}

#####################################################
#####################################################
##
## Get config data functions
##
#####################################################
#####################################################

#####################################################
#
# scsetup_get_installmode()
#
#	This function prints 1 if installmode is set and
#	zero if it is not.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_installmode()
{
	typeset mode

	(
		LANG=C; export LANG
		mode="$(${SC_SCCONF} -p | sed -n 's/^Cluster install mode:[   ]*\([^ ]*\).*/\1/p')"
		if [[ -n "${mode}" ]] && [[ "${mode}" = "enabled" ]]; then
			echo 1
		else
			echo 0
		fi
	)

	return 0
}

#####################################################
#
# scsetup_get_nodelist()
#
#	Print the list of configured nodes.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_nodelist()
{
	(
		LANG=C; export LANG;
		${SC_SCCONF} -p | sed -n 's/^ *Cluster nodes:[  ]*\(.*\)/\1/p'
	)

	return 0
}

#####################################################
#
# scsetup_get_adapterlist() nodename
#
#	Print the list of configured adapters for the given node.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_adapterlist()
{
	typeset nodename=${1}
	typeset list
	typeset item

	if [[ -z "${nodename}" ]]; then
		return 0
	fi

	list="$(
		LANG=C; export LANG;
		${SC_SCCONF} -pv | sed -n 's/^ *('${nodename}') Node transport adapters:[  ]*\(.*\)/\1/p'
	)"
	for item in ${list}
	do
		if [[ ${item} != "<NULL>" ]]; then
			echo ${item}
		fi
	done

	return 0
}

#####################################################
#
# scsetup_get_junctionlist()
#
#	Print the list of configured junctions.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_junctionlist()
{
	(
		LANG=C; export LANG;
		${SC_SCCONF} -p | sed -n 's/^ *Cluster transport junctions:[  ]*\(.*\)/\1/p'
	)

	return 0
}

#####################################################
#
# scsetup_get_trtypes()
#
#	Print the list of configured transport types.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_trtypes()
{
	typeset trtypes
	typeset trtype
	
	# Get the types
	trtypes="$(
		LANG=C; export LANG;
		${SC_SCCONF} -p | sed -n 's/^ *Adapter transport type:[  ]*\(.*\)/\1/p'
	)"

	# List each one only once
	for trtype in ${trtypes}
	do
		echo ${trtype}
	done | sort | uniq

	return 0
}

#####################################################
#
# scsetup_get_endpoints()
#
#	Print the list of configured transport cable endpoints.
#	Each pair of endpoints in the list identifies a cable.
#	Note that the port number is printed for each endpoint.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_endpoints()
{
	(
		LANG=C; export LANG;
		${SC_SCCONF} -p | sed -n 's/^ *Transport cable:[ 	]*\([^ ]*\) *\([^ ]*\).*/\1 \2/p'
	)

	return 0
}

#####################################################
#
# scsetup_get_devicegroup_type() groupname
#
#	Print the list device group type for the given "groupname".
#
#	This function always returns zero.
#
#####################################################
scsetup_get_devicegroup_type()
{
	typeset groupname=${1}

	# If name is not given, simply return
	if [[ -z "${groupname}" ]]; then
		return 0
	fi

	(
		LANG=C; export LANG;
		${SC_SCCONF} -pvv | nawk '{
			if ($1 == "('${groupname}')" &&
			    $2 == "Device" &&
			    $3 == "group" &&
			    $4 == "type:") {
				print $5
			}
		}'
	)

	return 0
}

#####################################################
#
# scsetup_get_devicegroup_nodes() groupname
#
#	Print the list device group nodes for the given "groupname".
#
#	This function always returns zero.
#
#####################################################
scsetup_get_devicegroup_nodes()
{
	typeset groupname=${1}
	typeset groupnodes
	typeset node

	# If name is not given, simply return
	if [[ -z "${groupname}" ]]; then
		return 0
	fi

	# Get the list of nodes
	groupnodes="$(
		LANG=C; export LANG;
		${SC_SCCONF} -pvv | nawk '{
			if ($1 == "('${groupname}')" &&
			    $2 == "Device" &&
			    $3 == "group" &&
			    $4 == "node" &&
			    $5 == "list:") {
				for (i = 6;  i <= NF;  i++) {
					split($i, node, ",");
					print node[1];
				}
			}
		}'
	)"

	# Strip out any commas
	for node in ${groupnodes}
	do
		(IFS=, ; echo ${node})
	done

	return 0
}

#####################################################
#
# scsetup_get_qdevlist()
#
#	Print the list of configured quorum devices.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_qdevlist()
{
	typeset list
	typeset item

	list="$(
		LANG=C; export LANG;
		${SC_SCCONF} -p | sed -n 's/^ *Quorum devices:[  ]*\(.*\)/\1/p'
	)"
	for item in ${list}
	do
		if [[ ${item} != "<NULL>" ]]; then
			echo ${item}
		fi
	done

	return 0
}

#####################################################
#
# scsetup_get_rglist() [rgname] [rgtype] [rstype]
#
#	if "rgname" is not null, only return the given "rgname",
#	if it exists and matches the optional "rgtype" and "rstype".
#
#	If "rgtype" is given, only return resource groups of the given
#	type.  And, if "rstype" is also given, only resource groups of the
#	given "rgtype" and "rstype" are returned.
#
#	Print the list of configured resource groups.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rglist()
{
	typeset rgname=${1}
	typeset -l rgtype=${2}		# lower case
	typeset -l rstype=${3}		# lower case

	typeset list
	typeset item
	typeset -l itemtype		# lower case
	typeset -l itemresources	# lower case
	typeset foo

	integer found

	list="$(
		LANG=C; export LANG;
		${SC_SCRGADM} -p -g . | sed -n 's/^ *Res Group name:[  ]*\(.*\)/\1/p'
	)"
	for item in ${list}
	do
		if [[ ${item} = "<NULL>" ]]; then
			continue
		fi
		if [[ -n "${rgname}" ]] &&
		    [[ ${item} != ${rgname} ]]; then
			continue
		fi
		if [[ -n "${rgtype}" ]]; then
			itemtype="$(
				LANG=C; export LANG;
				${SC_SCRGADM} -pv -g ${item} 2>/dev/null | sed -n 's/^ *('${item}') Res Group mode:[ 	]*\(.*\)/\1/p'
			)"
			if [[ "${itemtype}" != "${rgtype}" ]]; then
				continue
			fi
		fi
		if [[ -n "${rstype}" ]]; then
			itemresources="$(
				LANG=C; export LANG;
				${SC_SCRGADM} -pv -g ${item} 2>/dev/null | sed -n 's/^ *('${item}':.*) Res resource type:[ 	]*\(.*\)/\1/p'
			)"
			let found=0
			for foo in ${itemresources}
			do
				if [[ "${foo}" = "${rstype}" ]]; then
					let found=1
				fi
			done
			if [[ ${found} -ne 0 ]]; then
				echo ${item}
			fi
		else
			echo ${item}
		fi
	done

	return 0
}

#####################################################
#
# scsetup_get_rgtype() rgname
#
#	Print the type of resource group, "failover" or "scalable".
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rgtype()
{
	typeset rgname=${1}

	typeset -l rgtype		# lower case

	rgtype="$(
		LANG=C; export LANG;
		${SC_SCRGADM} -pv -g ${rgname} 2>/dev/null | sed -n 's/^ *('${rgname}') Res Group mode:[ 	]*\(.*\)/\1/p'
	)"

	if [[ "${rgtype}" == "failover" ]] ||
	    [[ "${rgtype}" == "scalable" ]]; then
		echo ${rgtype}
	fi

	return 0
}

#####################################################
#
# scsetup_get_rslist() [rsname] [rstype]
#
#	if "rsname" is not null, only return the given "rsname",
#	if it exists and matches the optional "rstype".
#
#	If "rstype" is also given, only resources of the
#	given "rstype" are returned.
#
#	Print the list of configured resource.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rslist()
{
	typeset rsname=${1}
	typeset -l rstype=${2}		# lower case

	typeset list
	typeset item
	typeset -l itemtype		# lower case
	typeset -l itemresources	# lower case
	typeset foo

	# Get the list
	list="$(
		LANG=C; export LANG;
		if [[ -n "${rsname}" ]]; then
			foo=${rsname}
		else
			foo=.
		fi
		${SC_SCRGADM} -p -j ${foo} 2>/dev/null | sed -n 's/^ *Res name:[  ]*\(.*\)/\1/p'
	)"
	for item in ${list}
	do
		if [[ ${item} = "<NULL>" ]]; then
			continue
		fi
		if [[ -n "${rstype}" ]]; then
			itemtype="$(
				LANG=C; export LANG;
				${SC_SCRGADM} -p -j ${item} 2>/dev/null | sed -n 's/^ *Res resource type:[ 	]*\(.*\)/\1/p'
			)"
			if [[ "${itemtype}" != "${rstype}" ]]; then
				continue
			fi
		fi

		# Okay
		echo ${item}
	done

	return 0
}

#####################################################
#
# scsetup_get_registered_rstypes()
#
#	Set the following arrays:
#
#	SCSETUP_RT_NAMES_REG		- each element contains the name of
#						a registered resource type.
#	SCSETUP_RT_DESCS_REG		- each element contains the description
#						of a corresponding rs type.
#	SCSETUP_RT_MODE_REG		- each element contains "failover" or
#						"scalable" for a corresponding
#						resource type.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_registered_rstypes()
{
	set -A SCSETUP_RT_NAMES_REG
	set -A SCSETUP_RT_DESCS_REG
	set -A SCSETUP_RT_MODE_REG

	integer index
	typeset rstype
	typeset -l lfoo			# lower case

	# Please wait...
	printf "$(gettext 'Please wait - looking up resource types .')"

	# Get the types
	set -A SCSETUP_RT_NAMES_REG $(
		LANG=C; export LANG;
		${SC_SCRGADM} -p -t . | sed -n 's/^ *Res Type name:[  ]*\(.*\)/\1/p'
	)

	# And, the descriptions and types
	let index=0
	for rstype in ${SCSETUP_RT_NAMES_REG[*]}
	do
		echo ".\c"
		SCSETUP_RT_DESCS_REG[index]="$(
			LANG=C; export LANG;
			${SC_SCRGADM} -p -t ${rstype} 2>/dev/null | sed -n 's/^ *Res Type description:[  ]*\(.*\)/\1/p'
		)"
		echo ".\c"
		SCSETUP_RT_MODE_REG[index]=$(
			LANG=C; export LANG;
			lfoo="$(${SC_SCRGADM} -pv -t ${rstype} 2>/dev/null | sed -n 's/^ *(.*) *Res Type failover:[ 	]*\(.*\)/\1/p')"
			if [[ "${lfoo}" == "false" ]]; then
				echo scalable
			else
				echo failover
			fi
		)

		# Next
		((index += 1))
	done

	# Done waiting
	echo
	echo

	return 0
}

#####################################################
#
# scsetup_get_unregistered_rstypes()
#
#	Set the following arrays:
#
#	SCSETUP_RT_NAMES_UNREG		- each element contains the name of
#						an unregistered type.
#	SCSETUP_RT_DESCS_UNREG		- each element contains the description
#						of a corresponding unreg. type.
#	SCSETUP_RT_MODE_UNREG		- each element contains "failover" or
#						"scalable" for a corresponding
#						resource type.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_unregistered_rstypes()
{
	set -A SCSETUP_RT_NAMES_UNREG
	set -A SCSETUP_RT_DESCS_UNREG
	set -A SCSETUP_RT_MODE_UNREG

	integer index
	typeset rstype
	typeset file
	typeset key
	typeset vid

	# Get from files
	let index=0
	for file in /usr/cluster/lib/rgm/rtreg/*
	do
		# Name
		SCSETUP_RT_NAMES_UNREG[index]=$(
			LANG=C; export LANG;
			key="$(grep -i '^[ 	]*resource_type' ${file} | sed -n 's/^[ 	]*\([^ 	=]*\).*/\1/p')"
			key=$(set - ${key}; echo ${1})
			sed -n 's/^[ 	]*'${key}'[ 	]*=[ 	"]*\([^";]*\).*/\1/p' ${file}
		)
		if [[ -z "${SCSETUP_RT_NAMES_UNREG[index]}" ]]; then
			((index += 1))
			continue
		fi

		# Pre-pend venor ID
		vid=$(
			LANG=C; export LANG;
			key="$(grep -i '^[ 	]*vendor_id' ${file} | sed -n 's/^[ 	]*\([^ 	=]*\).*/\1/p')"
			key=$(set - ${key}; echo ${1})
			sed -n 's/^[ 	]*'${key}'[ 	]*=[ 	"]*\([^";]*\).*/\1/p' ${file}
		)
		if [[ -n "${vid}" ]]; then
			SCSETUP_RT_NAMES_UNREG[index]=${vid}.${SCSETUP_RT_NAMES_UNREG[index]}
		fi

		# Description
		SCSETUP_RT_DESCS_UNREG[index]="$(
			key="$(grep -i '^[ 	]*rt_description' ${file} | sed -n 's/^[ 	]*\([^ 	=]*\).*/\1/p')"
			key=$(set - ${key}; echo ${1})
			sed -n 's/^[ 	]*'${key}'[ 	]*=[ 	"]*\([^";]*\).*/\1/p' ${file}
		)"

		# Failover or scalable?
		SCSETUP_RT_MODE_UNREG[index]=$(
			key="$(grep -i '^[ 	]*failover' ${file} | sed -n 's/^[ 	]*\([^ 	=]*\).*/\1/p')"
			key=$(set - ${key}; echo ${1})
			lfoo="$(sed -n 's/^[ 	]*'${key}'[ 	]*=[ 	"]*\([^";]*\).*/\1/p' ${file})"
			if [[ "${lfoo}" == "true" ]]; then
				echo "failover"
			else
				echo "scalable"
			fi
		)

		# Next
		((index += 1))
	done

	return 0
}

#####################################################
#
# scsetup_get_rstype_extprops() rstype_name
#
#	Set the following arrays for the given resource type name:
#
#	SCSETUP_RT_PROP_NAMES		- each element contains the name of
#						a resource property.
#	SCSETUP_RT_PROP_DESCS		- each element contains the description
#						of a corresponding rs property.
#	SCSETUP_RT_PROP_TYPES		- each element contains the type of
#						rs property.
#	SCSETUP_RT_PROP_DFLTS		- each element contains the default
#						value of an rs property.
#
#	We only look at registered resource types.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rstype_extprops()
{
	typeset rstype_name=${1}

	set -A SCSETUP_RT_PROP_NAMES
	set -A SCSETUP_RT_PROP_DESCS
	set -A SCSETUP_RT_PROP_TYPES
	set -A SCSETUP_RT_PROP_DFLTS

	typeset name
	typeset namelist

	integer index

	# Please wait...
	printf "$(gettext 'Please wait - looking up resource properties .')"

	# Get the names of all the extension properties
	namelist="$(
		LANG=C; export LANG;
		${SC_SCRGADM} -pvv -t ${rstype_name} 2>/dev/null | sed -n 's/^ *('${rstype_name}':\(.*\)) Res Type param extension:[ 	]*True/\1/p'
	)"
	# Weed out properties we don't want to show
	let index=0
	set -A SCSETUP_RT_PROP_NAMES
	for name in ${namelist}
	do
		if [[ "${name}" == "Paramtable_version" ]]; then
			continue
		fi
		SCSETUP_RT_PROP_NAMES[index]=${name}
		((index += 1))
	done

	# Get the descriptions, types, and values
	let index=0
	set -A SCSETUP_RT_PROP_DESCS
	set -A SCSETUP_RT_PROP_TYPES
	set -A SCSETUP_RT_PROP_DFLTS
	for name in ${SCSETUP_RT_PROP_NAMES[*]}
	do
		echo ".\c"
		SCSETUP_RT_PROP_DESCS[index]="$(
			LANG=C; export LANG;
			${SC_SCRGADM} -pvv -t ${rstype_name} 2>/dev/null | sed -n 's/^ *('${rstype_name}':'${name}') Res Type param description:[ 	]*\(.*\)/\1/p'
		)"
		echo ".\c"
		SCSETUP_RT_PROP_TYPES[index]="$(
			LANG=C; export LANG;
			${SC_SCRGADM} -pvv -t ${rstype_name} 2>/dev/null | sed -n 's/^ *('${rstype_name}':'${name}') Res Type param type:[ 	]*\(.*\)/\1/p'
		)"
		echo ".\c"
		SCSETUP_RT_PROP_DFLTS[index]="$(
			LANG=C; export LANG;
			${SC_SCRGADM} -pvv -t ${rstype_name} 2>/dev/null | sed -n 's/^ *('${rstype_name}':'${name}') Res Type param default:[ 	]*\(.*\)/\1/p'
		)"

		((index += 1))
	done

	# Done waiting
	echo
	echo

	return 0
}

#####################################################
#
# scsetup_print_rstype_extprops() rstype_name
#
#	Print the extenstion properties using the following input arrays:
#
#	SCSETUP_RT_PROP_NAMES		- each element contains the name of
#						a resource property.
#	SCSETUP_RT_PROP_DESCS		- each element contains the description
#						of a corresponding rs property.
#
#	This function always returns zero.
#
#####################################################
scsetup_print_rstype_extprops()
{
	typeset rstype_name=${1}

	typeset propname
	typeset propdflt
	integer index

	# List the properties
	sc_print_prompt "$(gettext 'Here are the extension properties for this resource:')"
	echo
	echo
	printf "\t%-25s %-25.25s\n" "$(gettext 'Property Name')" "$(gettext 'Default Setting')"
	printf "\t%-25s %-25.25s\n" "=============" "==============="
	echo

	let index=0
	for propname in ${SCSETUP_RT_PROP_NAMES[*]}
	do
		# Set the default value
		propdflt="${SCSETUP_RT_PROP_DFLTS[index]}"
		if [[ -z "${propdflt}" ]]; then
			propdflt="$(printf "<%s>" "$(gettext 'no default')")"
		fi

		# Print the property name and its default value, if any
		printf "\t%-25s %-25.25s\n" "${propname}" "${propdflt}"
		((index += 1))
	done | more
	echo

	return 0
}

#####################################################
#
# scsetup_get_rstype_extprop_type() ${propname}
#
#	Print the extenstion property type of the given propname using
#	the following arrays:
#
#	SCSETUP_RT_PROP_NAMES		- each element contains the name of
#						a resource property.
#	SCSETUP_RT_PROP_TYPES		- each element contains the type
#						of a corresponding rs property.
#
#	Case is ignored.
#
#	Return values:
#
#		-1		Unknown property
#		0		Success
#
#####################################################
scsetup_get_rstype_extprop_type()
{
	typeset -l propname=${1}		# lower case

	typeset -l name				# lower case
	integer index
	integer found

	# Get the index
	let index=0
	let found=0
	for name in ${SCSETUP_RT_PROP_NAMES[*]}
	do
		if [[ "${propname}" == "${name}" ]]; then
			let found=1
			break
		fi

		((index += 1))
	done

	# If we didn't find it, return -1
	if [[ ${found} -ne 1 ]]; then
		return 1
	fi

	# Print the type
	echo ${SCSETUP_RT_PROP_TYPES[index]}

	return 0
}

#####################################################
#
# scsetup_get_rstype_extprop_desc() ${propname}
#
#	Print the extenstion property description of the given propname using
#	the following arrays:
#
#	SCSETUP_RT_PROP_NAMES		- each element contains the name of
#						a resource property.
#	SCSETUP_RT_PROP_DESCS		- each element contains the description
#						of a corresponding rs property.
#
#	Case is ignored.
#
#	Return values:
#
#		-1		Unknown property
#		0		Success
#
#####################################################
scsetup_get_rstype_extprop_desc()
{
	typeset -l propname=${1}		# lower case

	typeset -l name				# lower case
	integer index
	integer found

	# Get the index
	let index=0
	let found=0
	for name in ${SCSETUP_RT_PROP_NAMES[*]}
	do
		if [[ "${propname}" == "${name}" ]]; then
			let found=1
			break
		fi

		((index += 1))
	done

	# If we didn't find it, return -1
	if [[ ${found} -ne 1 ]]; then
		return 1
	fi

	# Print the type
	echo ${SCSETUP_RT_PROP_DESCS[index]}

	return 0
}

#####################################################
#
# scsetup_get_rstype_extprop_dflt() ${propname}
#
#	Print the extenstion property default of the given propname using
#	the following arrays:
#
#	SCSETUP_RT_PROP_NAMES		- each element contains the name of
#						a resource property.
#	SCSETUP_RT_PROP_DFLTS		- each element contains the default
#						of a corresponding rs property.
#
#	Case is ignored.
#
#	Return values:
#
#		-1		Unknown property
#		0		Success
#
#####################################################
scsetup_get_rstype_extprop_dflt()
{
	typeset -l propname=${1}		# lower case

	typeset -l name				# lower case
	integer index
	integer found

	# Get the index
	let index=0
	let found=0
	for name in ${SCSETUP_RT_PROP_NAMES[*]}
	do
		if [[ "${propname}" == "${name}" ]]; then
			let found=1
			break
		fi

		((index += 1))
	done

	# If we didn't find it, return -1
	if [[ ${found} -ne 1 ]]; then
		return 1
	fi

	# Print the type
	echo ${SCSETUP_RT_PROP_DFLTS[index]}

	return 0
}

#####################################################
#
# scsetup_get_prop_default() rstype property
#
#	Test to see if the "property" exists for the given resource type.
#	If it does, print the default value.
#
#	Note that we cannot use the scha_cmds(1ha) here, since there are
#	no options for getting resource type parameters.
#
#	Return values:
#
#		-1		Unknown property
#		0		Success
#
#####################################################
scsetup_get_prop_default()
{
	typeset rstype=${1}
	typeset property=${2}

	typeset item
	typeset list
	typeset default

	integer found

	# See if the property even exists for this resource type
	list="$(
		LANG=C; export LANG;
		${SC_SCRGADM} -pvv -t ${rstype} 2>/dev/null | sed -n 's/^ *('${rstype}') Res Type param name:[ 	]*\(.*\)/\1/p'
	)"
	let found=0
	for item in ${list}
	do
		if [[ "${item}" == "${property}" ]]; then
			let found=1
			break
		fi
	done
	if [[ ${found} -eq 0 ]]; then
		return -1
	fi

	# If the property exists, print the default value
	default="$(
		LANG=C; export LANG;
		${SC_SCRGADM} -pvv -t ${rstype} 2>/dev/null | sed -n 's/^ *('${rstype}:${property}') Res Type param default:[ 	]*\(.*\)/\1/p'
	)"

	if [[ -n "${default}" ]]; then
		echo "${default}"
	fi

	return 0
}

#####################################################
#
# scsetup_get_resource() rsname
#
#	Test to see if the resource exists. If it does, print the name.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_resource()
{
	typeset rsname=${1}

	typeset list

	list="$(
		LANG=C; export LANG;
		${SC_SCRGADM} -p -j ${rsname} 2>/dev/null | sed -n 's/^ *Res name:[ 	]*\(.*\)/\1/p'
	)"
	if [[ "${list}" == "${rsname}" ]]; then
		echo "${rsname}"
	fi

	return 0
}

#####################################################
#
# scsetup_is_network_rstype() rstype
#
#	Test to see if this is a network resource type.
#
#	Return values:
#
#		1	Yes, it is.
#		0	No,  it is not.
#
#####################################################
scsetup_is_network_rstype()
{
	typeset -l rstype=${1}

	if [[ "${rstype}" == "sunw.logicalhostname" ]] ||
	    [[ "${rstype}" == "sunw.sharedaddress" ]] ||
	    [[ "${rstype}" == "logicalhostname" ]] ||
	    [[ "${rstype}" == "sharedaddress" ]]; then
		return 1
	fi

	return 0
}

#####################################################
#####################################################
##
## Main help text
##
#####################################################
#####################################################

#####################################################
#
# scsetup_help_main_quorum()
#
#	Print the main help message for quorum.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_quorum()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - Quorum ***
	')"
	typeset sctxt_p1="$(gettext '
		A quorum disk is a disk connected to at least two
		nodes and configured to participate in computing the
		quorum for the cluster. Both nodes and quorum devices
		contribute votes to the quorum.  A simple majority of
		votes must be present in order to establish quorum
		and form a cluster.
	')"
	typeset sctxt_p2="$(gettext '
		Each cluster node has a default quorum vote count of
		one. If configured, each quorum device has a quorum
		vote count of N-1, where N is the number of
		disk-to-node paths configured for the disk. For
		example, a quorum device consisting of a disk with two
		disk-to-node paths has a quorum vote count of 1.
	')"
	typeset sctxt_p3="$(gettext '
		Both nodes and quorum devices may be placed
		in a quorum maintenance state.  This is achieved by
		setting their vote counts to zero.  Resetting this
		maintenance state restores vote counts to their default
		values.  Please refer to the scconf(1M) man page and
		other Sun Cluster documentation for information
		on changing the quorum maintenance state.
	')"
	typeset sctxt_p4="$(gettext '
		The minimum requirement for configuring quorum is
		that all two-node clusters have at least one quorum disk.
		For more information regarding disk layout, quorum topologies,
		and recommendations for configuring quorum, please refer
		to the Sun Cluster documentation.
	')"

	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"
	sc_print_para "${sctxt_p3}"
	sc_print_para "${sctxt_p4}"

	return 0
}

#####################################################
#
# scsetup_help_main_rgm()
#
#	Print the main help message for resource groups.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_rgm()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - Resource Groups ***
	')"
	typeset sctxt_p1="$(gettext '
		The cluster uses resource groups to manage data service
		and network resources.   A resource group is a
		container into which resources of various types may be
		placed.   There are different types of resources,
		including the two possible types of network resources
		and any number of data service resource types.   But,
		there are only two types of resource groups, failover
		and scalable.
	')"
	typeset sctxt_p2="$(gettext '
		The two types of network resources are
		LogicalHostname resources and SharedAddress
		resources.   Both of these two possible network
		resource types are pre-registered with the cluster.
		Each data service is also associated with its own data
		service resource type.  But, data service resource
		types are not pre-registered and must be registered
		with the cluster after they have been installed.
	')"
	typeset sctxt_p3="$(gettext '
		A failover resource group typically contains one or
		more of the resources of one or both of the network
		resource types.  Usually, there is at least one network
		resource for each subnet.  In addition, each failover
		resource group may contain one or more data services
		resources.
	')"
	typeset sctxt_p4="$(gettext '
		A scalable resource group never contains network resources,
		but always depends upon a failover resource group that
		includes at least one SharedAddress resource.
	')"

	(
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"
		sc_print_para "${sctxt_p3}"
		sc_print_para "${sctxt_p4}"
	) | more

	return 0
}

#####################################################
#
# scsetup_help_main_transport()
#
#	Print the main help message for cluster interconnect.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_transport()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - Cluster Interconnect ***
	')"
	typeset sctxt_p1="$(gettext '
		The cluster interconnect facilitates high speed private
		communications between nodes in the cluster.  One of
		the more imporant uses of the interconnect is the
		synchronization of cluster membership information.
	')"
	typeset sctxt_p2="$(gettext '
		There must be at least two points of connection to the
		cluster interconnect for each node in the cluster.
		Each such endpoint is connected to the interconnect by
		a cable.  In two-node clusters with interconnect
		hardware which supports direct-connect cabling, both
		endpoints of a transport cable may be directly attached
		to transport adapters.  But, all configurations support
		cabling with a cluster transport junction at one
		endpoint and a cluster transport adapter at the other.
	')"

	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"

	return 0
}

#####################################################
#
# scsetup_help_main_privatehosts()
#
#	Print the main help message for private hostnames.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_privatehosts()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - Private Hostnames ***
	')"
	typeset sctxt_p1="$(gettext '
		Nodes may contact other nodes in the cluster 
		over the cluster interconnect by accessing them using
		their private hostnames.   Default private hostnames
		are assigned during cluster installation.
	')"
	typeset sctxt_p2="$(gettext '
		Note that private hostnames should never be stored
		in the hosts(4) or other naming services databases.
		A special nsswitch facility (see nsswitch.conf(4))
		performs all hostname lookups for private hostnames.
	')"
		
	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"

	return 0
}

#####################################################
#
# scsetup_help_main_devicegroups()
#
#	Print the main help message for device groups.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_devicegroups()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - Device Groups ***
	')"
	typeset sctxt_p1="$(gettext '
		A device group is a group of devices which can
		be mastered as a single set.  The most common
		types of device groups are disk device groups.
	')"
	typeset sctxt_p2="$(gettext '
		VERITAS Volume Manager disk groups are always managed
		by the cluster as device groups.   For example, each
		Solstice DiskSuite diskset is also a cluster device
		group;   and, each VxVM disk group is a cluster device
		group.  In addition, it is possible for individual
		disks to be grouped together into device groups.
	')"
	typeset sctxt_p3="$(gettext '
		Note that Solstice DiskSuite is Sun Cluster aware and,
		so, most device group administration occurs
		automatically through the Solstice Disksuite command
		set, or GUI interface, for Disksuite disksets.
		However, VxVM disk groups and volumes must each be
		registered with the cluster using either scsetup(1M)
		or scconf(1M).
	')"

	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"
	sc_print_para "${sctxt_p3}"

	return 0
}

#####################################################
#
# scsetup_help_main_auth()
#
#	Print the main help message for managing authorization
#	for nodes which want to add themselves to the cluster.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_auth()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - New Nodes ***
	')"
	typeset sctxt_p1="$(gettext '
		To be added as a cluster node, a machine must appear in
		the list of hosts that are permitted to install themselves
		into cluster configuration.  If this list is empty, any
		machine may add itself to the cluster configuration.
	')"
	typeset sctxt_p2="$(gettext '
		The identity of machines contacting the cluster over
		the public network for installation purposes may be
		confirmed using either standard UNIX or the more secure
		Diffie-Hellman, or DES, authentication.  However, DES
		authentication is not usually considered necessary for
		this purpose, since machines which are not physically
		connected to the private cluster interconnect will
		never be able to actually join the cluster membership
		anyway.
	')"
	typeset sctxt_p3="$(gettext '
		If DES authentication is selected, you must also configure
		all necessary encryption keys before a node can join
		(see keyserv(1M), publickey(4)).
	')"

	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"
	sc_print_para "${sctxt_p3}"

	return 0
}

#####################################################
#
# scsetup_help_main_other()
#
#	Print the main help message for other cluster properties.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_main_other()
{
	typeset sctxt_title="$(gettext '
		*** Help Screen - Other Cluster Properties ***
	')"
	typeset sctxt_p1="$(gettext '
		Currently, the only other cluster-wide property
		which may be changed from scsetup is the name of
		the cluster.
	')"

	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"

	return 0
}

#####################################################
#####################################################
##
## Quorum
##
#####################################################
#####################################################

#####################################################
#
# scsetup_menu_quorum_addev() [nohelp]
#
#	nohelp		- if this flag is given, do not
#			    clear screen, print title, print help,
#			    or ask for confirmation to continue
#
#	Add a quorum device to the cluster.
#
#	Note that the scsetup_initcluster() calls this function with "nohelp".
#	If it has it's own help information to print, it should do so
#	before calling this function.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_menu_quorum_addev()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Add a Quorum Disk <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to add a quorum disk to the cluster
		configuration.  SCSI-2 disks can be used for
		dual-ported quorum devices.   However, SCSI-3 PGR disks
		must be used when there are more than two node-to-disk
		paths.  You can use a disk containing user data or one
		that is a member of a device group as a quorum device.
		For more information on supported quorum device
		topologies, see the Sun Cluster documentation.
	')"
	typeset sctxt_p2="$(gettext '
		Each quorum disk must be connected to at least two
		nodes.  Adding a quorum device automatically configures
		node-to-disk paths for all nodes attached to the disk.
		Later, if you add more nodes to the cluster, you might
		need to update these paths by removing then adding back
		the quorum device.
	')"

	typeset answer
	typeset globaldev

	# Unless nohelp is specified, print help and get confirmation
	if [[ -z "${nohelp}" ]]; then

		# Clear screen, print title and help
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the name of the global device
		answer=$(sc_prompt "$(gettext 'Which global device do you want to use (d<N>)?')") || return 1

		# Make sure they use the d<N> format
		if [[ $(expr "${answer}" : 'd[0-9][0-9]*') -ne ${#answer} ]]; then
			printf "$(gettext 'The global device name must be given as d<N>.')\n"
			if [[ "${answer}" = /* ]]; then
				printf "$(gettext 'It is not necessary to use the full pathname.')\n"
			fi
			printf "\n\a"

			# Retry from the top
			continue
		fi

		# Set the global device name
		globaldev=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -q globaldev=${globaldev}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_quorum_rmdev() [nohelp]
#
#	nohelp		- if this flag is given, do not
#			    clear screen, print title, print help,
#			    or ask for confirmation to continue
#
#	Remove a quorum device from the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_menu_quorum_rmdev()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Remove a Quorum Disk <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to remove a quorum disk from the
		cluster configuration.  When a quorum disk is removed,
		it no longer participates in the voting to establish
		quorum.
	')"
	typeset sctxt_p2="$(gettext '
		Note that all two-node clusters require that at least
		one quorum device be configured.  So, if this is
		the last quorum disk on a two-node cluster, scconf(1M)
		will fail to remove the device from the configuration.
	')"

	typeset answer
	typeset globaldev

	# Unless nohelp is specified, print help and get confirmation
	if [[ -z "${nohelp}" ]]; then

		# Clear screen, print title and help
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the name of the global device
		answer=$(sc_prompt "$(gettext 'Which quorum disk do you want to remove (d<N>)?')") || return 1

		# Make sure they use the d<N> format
		if [[ $(expr "${answer}" : 'd[0-9][0-9]*') -ne ${#answer} ]]; then
			printf "$(gettext 'The global device name must be given as d<N>.')\n"
			if [[ "${answer}" = /* ]]; then
				printf "$(gettext 'It is not necessary to use the full pathname.')\n"
			fi
			printf "\n\a"

			# Retry from the top
			continue
		fi

		# Set the global device name
		globaldev=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -q globaldev=${globaldev}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_help_quorum_menu()
#
#	Print help information from the quorum menu.
#	This is the same help information as is printed
#	from the MAIN help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_quorum_menu()
{
	clear
	scsetup_help_main_quorum
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_quorum_menuoption()
#
#	Print the quorum menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_quorum_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** Quorum Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Add a quorum disk')"
	typeset sctxt_option_002="$(gettext 'Remove a quorum disk')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_quorum()
#
#	Quorum menu
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_quorum()
{
	# Loop around the quorum menu
	while true
	do
		case $(scsetup_get_quorum_menuoption) in
		'1')    scsetup_menu_quorum_addev ;;
		'2')    scsetup_menu_quorum_rmdev ;;
		'?')    scsetup_help_quorum_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Resource Group Management
##
#####################################################
#####################################################

#####################################################
#
# scsetup_menu_rgm_rg_create() [nohelp]
#
#	nohelp		- if this flag is given, do not
#			    clear screen, print title, print help,
#			    or ask for confirmation to continue
#
#	Create a resource group.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_menu_rgm_rg_create()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Create a Resource Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to create a new resource group.  It
		also supports the creation of new resources for the new
		group.
	')"
	typeset sctxt_p2="$(gettext '
		A resource group is a container into which you can
		place resources of various types, such as network and
		data service resources.   The cluster uses resource
		groups to manage its resource types.  There are but two
		types of resource groups, failover and scalable.
	')"
	typeset sctxt_p3="$(gettext '
		Only failover resource groups may contain network
		resources.  A network resource, in turn, is either a
		LogicalHostname or SharedAddress resource.
	')"
	typeset sctxt_p4="$(gettext '
		It is important to remember that each scalable resource
		group depends upon a failover resource group which
		contains one or more network resources of the
		SharedAddress resource type.
	')"

	typeset sctxt_p1_pprefix="$(gettext '
		Some types of resources (e.g., HA for NFS) require the
		use of an area in a global file system for storing
		configuration data.  If any of the resources that will
		later be added to this group will require such support,
		you can specify the full directory path name now.  
	')"
	typeset sctxt_p2_pprefix="$(gettext '
		Please remember that this directory must be located on
		a global file system.
	')"

	typeset sctxt_p1_scalable="$(gettext '
		Each scalable resource group has a tightly defined
		dependency on a failover resource group which contains
		one or more network resources of the SharedAddress resource
		type.
	')"
	typeset sctxt_p1_no_sharedaddr="$(gettext '
		You must create a failover resource group with
		one or more SharedAddress network resources upon which
		a scalable resource group can depend, before you can
		create that scalable resource group.
	')"

	typeset sctxt_p1_2nodes="$(gettext '
		Since this cluster has two nodes, the new resource
		group will be configured to be hosted by both cluster
		nodes.
	')"

	typeset sctxt_p1_node_list="$(gettext '
		You must specify an ordered list of the nodes from
		which this group may be hosted.
	')"
	typeset sctxt_p2_node_list="$(gettext '
		List one node name per line.   At least two node nodes
		must be given.  When finished, type Control-D:
	')"
	typeset sctxt_node_prompt1="$(gettext 'Node name:')"
	typeset sctxt_node_prompt2="$(gettext 'Node name (Ctrl-D to finish):')"

	typeset sctxt_p1_network_rsl="$(gettext '
		If a failover resource group contains LogicalHostname
		resources, the most common configuration is to have one
		LogicalHostname resource for each subnet.  Therefore,
		scsetup(1M) assumes that there will be one such
		resource for each subnet.
	')"
	typeset sctxt_p1_network_rss="$(gettext '
		If a failover resource group contains SharedAddress
		resources, the most common configuration is to have one
		SharedAddress resource for each subnet.  Therefore,
		scsetup(1M) assumes that there will be one such
		resource for each subnet.
	')"
		
	typeset foo
	typeset answer
	typeset answers
	typeset node
	typeset nodelist
	typeset rglist=
	typeset rgname
	typeset rgdescription
	typeset rgtype
	typeset rgdependency
	typeset rgnodelist
	typeset net_rstype
	typeset default

	integer nodecount
	integer found
	integer listcount
	integer total
	integer index

	# Unless nohelp is specified, print help and get confirmation
	if [[ -z "${nohelp}" ]]; then

		# Clear screen, print title and help
		(
			sc_print_title "${sctxt_title}"
			sc_print_para "${sctxt_p1}"
			sc_print_para "${sctxt_p2}"
			sc_print_para "${sctxt_p3}"
			sc_print_para "${sctxt_p4}"
		) | more

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Get the RG type
	rgtype=
	case $(scsetup_get_rgm_rgtype_menuoption) in
	'1')	rgtype="failover" ;;
	'2')	rgtype="scalable" ;;
	esac

	# Get the RG name
	while true
	do
		# Get the name of the resource group
		answer=$(sc_prompt "$(gettext 'What is the name of the group you want to add?')") || return 1

		# Get the list of configured resource groups
		rglist=
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			rglist="$(scsetup_get_rglist)"
		fi

		# See if our rg is already configured
		for rgname in ${rglist}
		do
			if [[ "${answer}" = "${rgname}" ]]; then
				printf "$(gettext 'Resource group \"%s\" is already configured.')\n\n\a" "${answer}"
				continue 2
			fi
		done

		# Okay
		rgname=${answer}

		# Done
		break
	done

	# Get the RG description
	rgdescription=
	while true
	do
		# Add a description?
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to add an optional description?')" "${NO}") || return 1

		# If so, get the description
		if [[ "${answer}" == "yes" ]]; then

			sc_print_prompt "$(gettext 'Description:')"
			read rgdescription || continue
			echo
		fi

		# Done
		break
	done

	# Scalable resource groups depend upon a failover RG
	rgdependency=
	if [[ "${rgtype}" = "scalable" ]]; then
		# Print message - scalable groups depend on failover groups
		sc_print_para "${sctxt_p1_scalable}"

		# Get the name of the group
		answer=$(sc_prompt_yesno "$(gettext 'Have you already configured such a group?')" "${YES}") || return 1
		if [[ "${answer}" = "yes" ]]; then
			while true
			do
				answer=$(sc_prompt "$(gettext 'What is the name of that group?')") || return 1
				if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
					let found=0
					for foo in ${rglist}
					do
						if [[ "${foo}" = "${answer}" ]]; then
							let found=1
							break
						fi
					done
					if [[ ${found} -ne 1 ]]; then
						printf "$(gettext 'Unknown resource group.')\n\n\a"
						continue
					fi
					foo="$(scsetup_get_rglist ${answer} FAILOVER SUNW.SharedAddress)"
					if [[ "${foo}" != "${answer}" ]]; then
						printf "$(gettext '%s does not include any %s resources.')\n\n\a" "${answer}" "SharedAddress"
						continue
					fi
				fi

				# Set the dependency to the failover group
				rgdependency=${answer}

				# Done
				break
			done
		else
			sc_print_para "${sctxt_p1_no_sharedaddr}"
			sc_prompt_pause
			return 1
		fi
	fi

	#
	# Establish the nodelist
	#

	# Get the configured list of cluster nodes (nodelist)
	nodelist=
	let nodecount=0
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

		# Get nodelist
		nodelist="$(scsetup_get_nodelist)"

		# Make sure we have a nodelist
		if [[ -z "${nodelist}" ]]; then
			printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
			sc_prompt_pause
			return 1
		fi

		# Set node count
		let nodecount=$(set -- ${nodelist}; echo $#)

		# Must have at least two nodes
		if [[ ${nodecount} -lt 2 ]]; then
			printf "$(gettext 'There are fewer than two nodes in the cluster.')\n\n\a"
			sc_prompt_pause
			return 1
		fi

	# If debug mode, just assume a count of SC_MAXNODEID
	else
		let nodecount=${SC_MAXNODEID}
	fi

	# If this is a two-node cluster, we have the nodelist
	if [[ ${nodecount} -eq 2 ]]; then
		
		# Set the listcount and rgnodelist
		rgnodelist="${nodelist}"
		let listcount=2

		# Print message - two nodes
		sc_print_para "${sctxt_p1_2nodes}"

		# If failover, get the preferred node
		while [[ "${rgtype}" == "failover" ]]
		do
			# reset rgnodelist
			rgnodelist=

			# Which node is prefered?
			answer=$(sc_prompt "$(gettext 'Which is the preferred node for hosting this group?')") || return 1

			# Set the nodelist
			set -A foo ${nodelist}
			if [[ "${foo[0]}" == "${answer}" ]]; then
				rgnodelist="${foo[0]} ${foo[1]}"
			elif [[ "${foo[1]}" == "${answer}" ]]; then
				rgnodelist="${foo[1]} ${foo[0]}"
			else
				printf "$(gettext 'Unknown node.')\n\n\a"
				set -A foo
				continue
			fi
			set -A foo

			# Done
			break
		done

	# otherwise, let the user specify
	else
		# Get the list of nodes
		let listcount=0
		rgnodelist=
		while [[ ${listcount} -lt 2 ]]
		do
			let listcount=0
			answers=

			# Print message
			sc_print_para "${sctxt_p1_node_list}"
			sc_print_para "${sctxt_p2_node_list}"

			# Get the added list
			while [[ ${listcount} -lt ${nodecount} ]]
			do
				# Get node
				if [[ ${listcount} -lt 2 ]]; then
					answer=$(sc_prompt "${sctxt_node_prompt1}" "" "nonl") || continue
				else
					answer=$(sc_prompt "${sctxt_node_prompt2}" "" "nonl") || break
				fi

				# If there is a nodelist, we must be in it.
				if [[ -n "${nodelist}" ]]; then
					let found=0
				else
					let found=1
				fi
				for node in ${nodelist}
				do
					if [[ "${answer}" = "${node}" ]]; then
						let found=1
						break
					fi
				done

				# Make sure we found it
				if [[ ${found} -eq 0 ]]; then
					echo
					printf "$(gettext 'Unknown node name.')\n\n\a"
					continue
				fi

				# Make sure it is not a duplicate
				for node in ${answers}
				do
					if [[ "${answer}" = "${node}" ]]; then
						echo
						printf "$(gettext '\"%s\" already entered.')\n\n\a" "${answer}"
						continue 2
					fi
				done

				# Okay, add it to list of answers
				answers="${answers} ${answer}"

				# Next
				((listcount += 1))
			done

			# Verify that the list is correct
			echo
			sc_print_para "$(gettext 'This is the list of nodes you entered:')"
			for node in ${answers}
			do
				printf "\t${node}\n"
			done
			echo
			answer=$(sc_prompt_yesno "$(gettext 'Is it correct?')" "${YES}") || return 1
			if [[ "${answer}" != "yes" ]]; then
				let listcount=0
			fi
		done

		# Set rgnodelist
		rgnodelist="${answers}"
	fi

	# Get the pathprefix
	rgpathprefix=
	while true
	do
		# Print message
		sc_print_para "${sctxt_p1_pprefix}"

		# Add a pathprefix?
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to specify such a directory now?')" "${NO}") || return 1

		# If not, we are done
		if [[ "${answer}" != "yes" ]]; then
			break
		fi

		# Get the directory name
		while [[ -z "${rgpathprefix}" ]]
		do
			# Set default
			default=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]] &&
			     [[ -d /global/${rgname} ]]; then
				default=/global/${rgname}
			fi

			# Print message
			sc_print_para "${sctxt_p2_pprefix}"

			# Get the name and verify
			while true
			do
				# Get the name
				answer=$(sc_prompt "$(gettext 'What is the name of the directory (i.e., \"Pathprefix\")?')" "${default}") || continue 2

				if [[ "${answer}" != /* ]]; then
					printf "$(gettext 'The name of the directory must begin with /.')\n\n\a"
					continue
				fi

				# If not in debug mode, make sure it is there
				if [[ ${SCSETUP_ISMEMBER} -eq 1 ]] &&
				    [[ ! -d "${answer}" ]]; then
					printf "$(gettext 'Directory not found - %s.')\n\n\a" "${answer}"
					continue
				fi

				# Done
				break
			done

			rgpathprefix=${answer}
		done

		# Done
		break
	done

	#
	# Set up the command set
	#

	# Initialize
	set -A SCSETUP_DO_CMDSET

	#
	# Add the command
	#

	# Basic command
	SCSETUP_DO_CMDSET[0]="${SC_SCRGADM} -a -g ${rgname}"

	# RG nodelist
	if [[ -n "${rgnodelist}" ]]; then
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -h "

		let count=0
		for node in ${rgnodelist}
		do
			if [[ ${count} -gt 0 ]]; then
				SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},"
			fi
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]}${node}"
			((count += 1))
		done
	fi

	# RG type
	if [[ "${rgtype}" == "scalable" ]]; then
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -y Maximum_primaries=${listcount} -y Desired_primaries=${listcount}"
	fi

	# RG dependencies
	if [[ -n "${rgdependency}" ]]; then
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -y RG_dependencies=${rgdependency}"
	fi

	# Add-on change commands
	let index=1

	# RG pathprefix
	if [[ -n "${rgpathprefix}" ]]; then
		SCSETUP_DO_CMDSET[${index}]="${SC_SCRGADM} -c -g ${rgname}"
		SCSETUP_DO_CMDSET[${index}]="${SCSETUP_DO_CMDSET[${index}]} -y Pathprefix=${rgpathprefix}"
		((index += 1))
	fi

	# RG description
	if [[ -n "${rgdescription}" ]]; then
		SCSETUP_DO_CMDSET[${index}]="${SC_SCRGADM} -c -g ${rgname}"
		SCSETUP_DO_CMDSET[${index}]="${SCSETUP_DO_CMDSET[${index}]} -y RG_description=\"${rgdescription}\""
	fi

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	# If FAILOVER RG, add check for network resources
	net_rstype=
	while [[ "${rgtype}" = "failover" ]]
	do
		net_rstype=

		# Add any network resources?
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to add any network resources now?')" "${YES}") || return 1

		# No, break out
		if [[ "${answer}" != "yes" ]]; then
			break
		fi

		# LogicalHostname or SharedAddress?
		net_rstype=
		case $(scsetup_get_rgm_net_rstype_menuoption) in
		'1')	net_rstype="logicalhostname" ;;
		'2')	net_rstype="sharedaddress" ;;
		esac

		# How many subnets/resources?
		if [[ "${net_rstype}" = "LogicalHostname" ]]; then
			sc_print_para "${sctxt_p1_network_rsl}"
		else
			sc_print_para "${sctxt_p1_network_rss}"
		fi
		answer=
		while [[ -z "${answer}" ]]
		do
			foo="$(printf "$(gettext 'For how many subnets do you want to add such a resource?')" "${net_rstype}")"
			answer="$(sc_prompt "${foo}" "1")" || return 1
			if [[ $(expr "${answer}" : '[0-9]*') -ne ${#answer} ]]; then
				printf "$(gettext '\"%s\" is not numeric.')\n\n\a" "${answer}"
				answer=
				continue
			fi
		done
		let total=${answer}
		let count=1
		while [[ ${count} -le ${total} ]]
		do
			# Configure?
			case ${count} in
			1)	foo="$(gettext 'first')" ;;
			2)	foo="$(gettext 'second')" ;;
			3)	foo="$(gettext 'third')" ;;
			4)	foo="$(gettext 'fourth')" ;;
			5)	foo="$(gettext 'fifth')" ;;
			6)	foo="$(gettext 'sixth')" ;;
			7)	foo="$(gettext 'seventh')" ;;
			8)	foo="$(gettext 'eighth')" ;;
			*)	foo="$(gettext 'next')" ;;
			esac
			foo="$(printf "$(gettext 'Is it okay to configure the %s %s resource?')" "${foo}" "${net_rstype}")"
			answer=$(sc_prompt_yesno "${foo}" "${YES}") || break
			if [[ "${answer}" != "yes" ]]; then
				answer="$(sc_prompt_yesno "$(gettext 'Are you sure?')")" || break
				if [[ "${answer}" == "yes" ]]; then
					break
				fi
			fi

			# Add resource with appropriate help text
			if [[ ${count} -eq 1 ]]; then
				foo="nohelp"
			else
				foo="NOHELP2"
			fi
			scsetup_menu_rgm_rs_addnet "${foo}" "${rgname}" "${rgtype}" "${net_rstype}" "1"
			if [[ $? -eq 0 ]]; then
				((count += 1))
			fi
		done
		
		# Done
		break
	done

	let count=0
	while true
	do
		# Add any data service resources?
		if [[ ${count} -eq 0 ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'Do you want to add any data service resources now?')" "${YES}") || return 1
		else
			answer=$(sc_prompt_yesno "$(gettext 'Do you want to add any additional data service resources?')" "${NO}") || return 1
		fi

		# No, break out
		if [[ "${answer}" != "yes" ]]; then
			break
		fi

		# Add resource
		scsetup_menu_rgm_rs_addds "nohelp" "${rgname}" "${rgtype}" "1"

		# Next
		((count += 1))
	done

	# Bring it online?
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
		# Initialize
		set -A SCSETUP_DO_CMDSET
		SCSETUP_DO_CMDSET[0]="${SC_SCSWITCH} -Z -g ${rgname}"

		answer=$(sc_prompt_yesno "$(gettext 'Do you want to bring this resource group online now?')" "${YES}") || return 1
		if [[ "${answer}" == "yes" ]]; then

			# Do it, without re-confirming
			scsetup_do_cmdset 1 || return 1

		elif [[ -n "${SCSETUP_CMD_LOG}" ]]; then

			# Just ask if they want to log
			scsetup_do_cmdset 2 || return 1
		fi
	fi

	return 0
}

#####################################################
#
# scsetup_menu_rgm_rs_addnet() [nohelp rgname rgtype net_rstype [noenable]]
# scsetup_menu_rgm_rs_addnet() [nohelp]
#
#	nohelp		- if this flag is given, do not
#			    clear screen, print title, print help,
#			    or ask for confirmation to continue
#			- if the flag is set to "NOHELP2", do not print
#			    any help whatsoever
#
#	rgname		- the name of the resource group
#
#	rgtype		- if given, must be "failover"
#
#	net_rstype	- "logicalhostname" or "sharedaddress"
#
#	Add a network resource to a resource group.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_menu_rgm_rs_addnet()
{
	typeset nohelp=${1}
	typeset rgname=${2}
	typeset -l rgtype=${3}		# lower case
	typeset -l net_rstype=${4}	# lower case
	typeset noenable=${5}

	typeset sctxt_title="$(gettext '
		>>> Add a Network Resource to a Resource Group <<<
	')"

	typeset sctxt_p1="$(gettext '
		There are two types of network resources,
		LogicalHostname and SharedAddress.  Only failover
		resource groups may contain network resources.  If a
		failover resource group includes any network resources,
		it typically includes one resource, of one or both of
		the network resource types, for each subnet to which
		the cluster is connected.
	')"
	typeset sctxt_lhostname_p1="$(gettext '
		Each network resource manages a list of one or more
		logical hostnames for a single subnet.  This is true
		whether the resource is a LogicalHostname or
		SharedAddress resource type.  The most common
		configuration is to assign a single logical hostname to
		each network resource for each subnet.  Therefore,
		scsetup(1M) only supports this configuration.  If you
		need to support more than one hostname for a given
		subnet, the additional support can be added using
		scrgadm(1M).
	')"
	typeset sctxt_lhostname_p2="$(gettext '
		Before scsetup(1M) can create a network resource for
		any logical hostname, that hostname must first be
		specified in the hosts(4) data for each node in the cluster.
		In addition, NAFO-configured network adapters must be
		actively available on each of the nodes.
	')"

	typeset rsname
	typeset answer
	typeset rglist
	typeset foo
	
	integer error
	integer count

	# Check arguments
	let error=0
	if [[ -n "${rgname}" ]]; then
		if [[ "${rgtype}" != "failover" ]]; then
			let error=1
		elif [[ "${net_rstype}" != "logicalhostname" ]] &&
		    [[ "${net_rstype}" != "sharedaddress" ]]; then
			let error=1
		fi
		if [[ ${error} -ne 0 ]]; then
			printf "$(gettext 'Internal error.')\n\n\a"
			return -1
		fi
	fi

	# Unless nohelp is specified, print help and get confirmation
	if [[ -z "${nohelp}" ]]; then

		# Clear screen, print title and help
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Get the network resource type
	if [[ -z "${net_rstype}" ]]; then
		case $(scsetup_get_rgm_net_rstype_menuoption) in
		'1')	net_rstype="logicalhostname" ;;
		'2')	net_rstype="sharedaddress" ;;
		esac
	fi

	# Get the network resource name
	rsname=
	let count=0
	while [[ -z "${rsname}" ]]
	do
		if [[ ${count} -eq 0 ]] &&
		    [[ "${nohelp}" != "NOHELP2" ]]; then
			sc_print_para "${sctxt_lhostname_p1}"
			sc_print_para "${sctxt_lhostname_p2}"
			((count += 1))
		fi

		foo="$(printf "$(gettext 'What logical hostname do you want to add?')")"
		answer=$(sc_prompt "${foo}") || return 1
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			rsname="$(scsetup_get_resource ${answer})"
			if [[ -n "${rsname}" ]]; then
				printf "$(gettext '\"%s\" already exists!')\n\n\a" "${rsname}"
				rsname=
				continue
			fi
		fi

		# Done
		rsname=${answer}
	done

	# Get the rgname
	while [[ -z "${rgname}" ]]
	do
		# Get the name of the resource group
		answer=$(sc_prompt "$(gettext 'To which group do you want to add the new resource?')") || return 1

		# Make sure it is a confiugred FAILOVER group
		rglist=
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			rglist="$(scsetup_get_rglist ${answer})"
			if [[ "${rglist}" != "${answer}" ]]; then
				printf "$(gettext 'Unknown resource group.')\n\n\a"
				continue
			fi
			rglist="$(scsetup_get_rglist ${answer} FAILOVER)"
			if [[ "${rglist}" != "${answer}" ]]; then
				printf "$(gettext '\"%s\" is not a %s resource group.')\n\n\a" "${answer}" "FAILOVER"
				continue
			fi
		fi

		# Done checking rg for type
		rgname=${answer}
		rgtype=failover
	done

	# Initialize
	set -A SCSETUP_DO_CMDSET

	# Basic command
	if [[ "${net_rstype}" = "logicalhostname" ]]; then
		SCSETUP_DO_CMDSET[0]="${SC_SCRGADM} -a -L -g ${rgname} -l ${rsname}"
	elif [[ "${net_rstype}" = "sharedaddress" ]]; then
		SCSETUP_DO_CMDSET[0]="${SC_SCRGADM} -a -S -g ${rgname} -l ${rsname}"
	fi

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	# Bring this resource online?
	if [[ -z "${noenable}" ]]; then

		# Initialize
		set -A SCSETUP_DO_CMDSET
		SCSETUP_DO_CMDSET[0]="${SC_SCSWITCH} -e -j ${rsname}"
		SCSETUP_DO_CMDSET[1]="${SC_SCSWITCH} -e -M -j ${rsname}"

		# Enable it?
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to enable this resource?')" "${YES}")
		if [[ "${answer}" == "yes" ]]; then

			# Do it, without re-confirming
			scsetup_do_cmdset 1 || return 1

		elif [[ -n "${SCSETUP_CMD_LOG}" ]]; then

			# Just ask if they want to log
			scsetup_do_cmdset 2 || return 1
		fi
	fi

	return 0
}

#####################################################
#
# scsetup_menu_rgm_rs_addds() [nohelp rgname rgtype [noenable]]
# scsetup_menu_rgm_rs_addds() [nohelp]
#
#	nohelp		- if this flag is given, do not
#			    clear screen, print title, print help,
#			    or ask for confirmation to continue
#
#	rgname		- the name of the resource group
#
#	rgtype		- if given, must be "failover"
#
#	noenable	- if set, do not ask about enabling the resource.
#
#	Add a data service resource to a resource group.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_menu_rgm_rs_addds()
{
	typeset nohelp=${1}
	typeset rgname=${2}
	typeset -l rgtype=${3}		# lower case
	typeset noenable=${4}

	typeset sctxt_title="$(gettext '
		>>> Add a Data Service Resource to a Resource Group <<<
	')"

	typeset sctxt_p1="$(gettext '
		This option allows you to add a data service resource
		to a resource group.  If the resource type for the data
		service is not yet registered with the cluster, you
		will have the opportunity to register that type.
	')"
	typeset sctxt_reg_p1="$(gettext '
		The type of resource you selected is not yet
		registered.  Each resource type must be registered with
		the cluster before any resources of the selected type
		can be added to a resource group.
	')"
	typeset sctxt_reg_p2="$(gettext '
		Registration of a resource type simply updates the
		cluster-wide configuration with the resource type data
		copied to an individual node at the time that the
		resource type was installed.   However, it is important
		that the same resource type, or data service, software
		has been installed on each node in the cluster.
	')"
	typeset sctxt_reg_p3="$(gettext '
		If you do not register the resource type now, you will
		not be able to add this resource.
	')"
	typeset sctxt_netused_p1="$(gettext '
		For scalable resources, you must specify a list of
		SharedAddress resources upon which the new scalable
		resource depends.  Since network resources can only
		belong to failover resource groups, the SharedAddress
		resources that you name must live in a different
		resource group.
	')"
	typeset sctxt_netused_p2="$(gettext '
		Please list one SharedAddress resource dependency per line.
		At least one such resource must be given.  When finished,
		type Control-D.
	')"
	typeset sctxt_netused_prompt1="$(gettext 'SharedAddress resource:')"
	typeset sctxt_netused_prompt2="$(gettext 'SharedAddress resource (Ctrl-D to finish):')"

	typeset sctxt_portlist_p1="$(gettext '
		This data service uses the \"Port_list\" property.  The
		default \"Port_list\" for this data service is as
		follows:
	')"
	typeset sctxt_portlist_p2="$(gettext '
		This data service requires that you explicitly set the
		\"Port_list\" property.
	')"
	typeset sctxt_portlist_p3="$(gettext '
		Please check the documentation for this resource type
		for more information on how the list should be set for
		this resource.
        ')"
	typeset sctxt_portlist_prompt1="$(gettext 'Port number (Ctrl-D to finish):')"
	typeset sctxt_portlist_prompt2="$(gettext 'Is this a TCP port?')"

	typeset sctxt_extprops_p1="$(gettext '
		Some resource types support the setting of certain
		extension properties.   Please check the documentation
		for your data service to determine whether or not you
		need to set any extension properties for the resource
		you are adding.
	')"
	typeset sctxt_extprops_prompt1="    $(gettext 'Property name:       ')"
	typeset sctxt_extprops_prompt2="    $(gettext 'Property description:')"
	typeset sctxt_extprops_prompt3="    $(gettext 'Property value:      ')"

	typeset SCSETUP_RT_NAMES_REG		# registered rs names
	typeset SCSETUP_RT_MODE_REG		# "failover" or "scalable"
	typeset SCSETUP_RT_DESCS_REG		# registered rs descripts
	typeset SCSETUP_RT_NAMES_UNREG		# UNregistered rs names
	typeset SCSETUP_RT_MODE_UNREG		# "failover" or "scalable"
	typeset SCSETUP_RT_DESCS_UNREG		# UNregistered rs descripts

	typeset SCSETUP_RT_PROP_NAMES		# Property names
	typeset SCSETUP_RT_PROP_DESCS		# Property descriptions
	typeset SCSETUP_RT_PROP_TYPES		# Property types
	typeset SCSETUP_RT_PROP_DFLTS		# Property defaults

	typeset rstypes

	typeset answer
	typeset name
	typeset answers
	typeset rglist
	typeset rsname
	typeset rsmode
	typeset rstype
	typeset -l lrstype		# lower case
	typeset rsdesc
	typeset rsscalable
	typeset rsnetused
	typeset rsportlist
	typeset foo
	typeset -l lfoo			# lower case
	typeset propname
	typeset propnames
	typeset -l proptype		# lower case
	typeset propvalue
	typeset propvalues
	typeset propdesc

	integer j
	integer index
	integer index_reg
	integer index_unreg
	integer counter
	integer rstype_register
	integer found
	integer error

	# Check arguments
	let error=0
	if [[ -n "${rgname}" ]]; then
		if [[ "${rgtype}" != "failover" ]] &&
		    [[ "${rgtype}" != "scalable" ]]; then
			printf "$(gettext 'Internal error.')\n\n\a"
			return -1
		fi
	fi

	# Unless nohelp is specified, print help and get confirmation
	if [[ -z "${nohelp}" ]]; then

		# Clear screen, print title and help
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Get the rgname
	while [[ -z "${rgname}" ]]
	do
		# Get the name of the resource group
		answer=$(sc_prompt "$(gettext 'To which group do you want to add the new resource?')") || return 1

		# Make sure it is a confiugred group
		rglist=
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			rglist="$(scsetup_get_rglist ${answer})"
			if [[ "${rglist}" != "${answer}" ]]; then
				printf "$(gettext 'Unknown resource group.')\n\n\a"
				continue
			fi
		fi

		# Done checking for rg
		rgname=${answer}
	done

	# Get the rg type
	if [[ -z "${rgtype}" ]]; then
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			rgtype="$(scsetup_get_rgtype ${rgname})"
			if [[ -z "${rgtype}" ]]; then
				printf "$(gettext 'Unable to discover what type of resource group this is!')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		else
			# Get the RG type
			rgtype=
			case $(scsetup_get_rgm_rgtype_menuoption) in
			'1')	rgtype="failover" ;;
			'2')	rgtype="scalable" ;;
			esac
		fi
	fi

	# Get the resource type name
	while true
	do
		# Initialize resource type
		rstype=
		let rstype_register=0

		#
		# Set up the following arrays:
		#
		#	SCSETUP_RT_NAMES_REG	# registered resource names
		#	SCSETUP_RT_DESCS_REG	# registered resource descripts
		#	SCSETUP_RT_MODE_REG	# "failover" or "scalable"
		#
		#	SCSETUP_RT_NAMES_UNREG	# unregistered resource names
		#	SCSETUP_RT_DESCS_UNREG	# unregistered resource descrips
		#	SCSETUP_RT_MODE_UNREG	# "failover" or "scalable"
		#
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			scsetup_get_registered_rstypes
			scsetup_get_unregistered_rstypes
		else
			set -A SCSETUP_RT_NAMES_REG
			set -A SCSETUP_RT_DESCS_REG
			set -A SCSETUP_RT_MODE_REG

			set -A SCSETUP_RT_NAMES_UNREG
			set -A SCSETUP_RT_DESCS_UNREG
			set -A SCSETUP_RT_MODE_UNREG

			# If debug, set some debug resource types
			if [[ -n "${SC_DEBUG}" ]]; then
				set -A SCSETUP_RT_NAMES_REG Debug1 Debug2
				SCSETUP_RT_DESCS_REG[0]="Failover resource type debug1"
				SCSETUP_RT_DESCS_REG[1]="Scalable resource type debug2"
				SCSETUP_RT_MODE_REG[0]="failover"
				SCSETUP_RT_MODE_REG[1]="scalable"

				set -A SCSETUP_RT_NAMES_UNREG unreg_Debug3 unreg_Debug4
				SCSETUP_RT_DESCS_UNREG[0]="Failover resource type debug3"
				SCSETUP_RT_DESCS_UNREG[1]="Scalable resource type debug4"
				SCSETUP_RT_MODE_UNREG[0]="failover"
				SCSETUP_RT_MODE_UNREG[1]="scalable"
			else
				rstype=$(sc_prompt "$(gettext 'What is the resource type for this new resource?')") || return 1
				if [[ "${rgtype}" == "scalable" ]]; then
					answer=$(sc_prompt_yesno "$(gettext 'Does this resource type support scalable resources?')")
					if [[ "${answer}" != "yes" ]]; then
						printf "$(gettext 'Only scalable resources can be added to scalable resource groups!')\n\n\a"
						continue
					fi
				fi
				answer=$(sc_prompt_yesno "$(gettext 'Does it need to be registered?')" "${YES}") || return 1
				if [[ "${answer}" == "yes" ]]; then
					let rstype_register=1
				fi

				# We are done getting type
				break
			fi
		fi

		# Print the list of resources
		rsdesc=
		let index_reg=0
		let index_unreg=0
		let counter=0
		set -A rstypes
		sc_print_prompt "$(gettext 'Please select the type of resource you want to add:')"
		echo
		echo
		while true
		do
			if [[ -n "${SCSETUP_RT_NAMES_REG[index_reg]}" ]]; then
				rstype=${SCSETUP_RT_NAMES_REG[index_reg]}
				rsdesc="${SCSETUP_RT_DESCS_REG[index_reg]}"
				rsmode=${SCSETUP_RT_MODE_REG[index_reg]}
				((index_reg += 1))
				scsetup_is_network_rstype ${rstype} || continue
				if [[ "${rgtype}" == "scalable" ]] &&
				    [[ "${rsmode}" != "scalable" ]]; then
					continue
				fi
			elif [[ -n "${SCSETUP_RT_NAMES_UNREG[index_unreg]}" ]]; then
				rstype=${SCSETUP_RT_NAMES_UNREG[index_unreg]}
				rsdesc="${SCSETUP_RT_DESCS_UNREG[index_unreg]}"
				rsmode=${SCSETUP_RT_MODE_UNREG[index_unreg]}
				((index_unreg += 1))
				scsetup_is_network_rstype ${rstype} || continue
				if [[ "${rgtype}" == "scalable" ]] &&
				    [[ "${rsmode}" != "scalable" ]]; then
					continue
				fi

				# Make sure it is not already listed
				lrstype=${rstype}
				for lfoo in ${SCSETUP_RT_NAMES_REG[*]}
				do
					if [[ "${lfoo}" == "${lrstype}" ]]; then
						continue 2
					fi
				done
			else
				# End of list
				break
			fi
			rstypes[counter]=${rstype}
			((counter += 1))
			printf "\t%2s) %-18s %s\n" "${counter}" "${rstype}" "${rsdesc}"
		done
		if [[ ${counter} -eq 0 ]]; then
			if [[ "${rgtype}" == "scalable" ]]; then
				printf "$(gettext 'Cannot find any scalable data service resource types!')\n\n\a"
			else
				printf "$(gettext 'Cannot find any data service resource types!')\n\n\a"
			fi
			sc_prompt_pause
			return 1
		fi
		echo

		# Select a resource
		answer=
		while [[ -z "${answer}" ]]
		do
			answer=$(sc_prompt "$(gettext 'Option:')") || return 1

			# In range?
			if [[ $(expr ${answer} : '[0-9]*') -ne $(expr ${answer} : '.*') ]] ||
			    [[ ${answer} -lt 1 ]] ||
			    [[ ${answer} -gt ${counter} ]]; then
				echo "\a\c"
				answer=
			else
				break
			fi
		done

		# Set the resource type
		rstype=${rstypes[answer - 1]}
		lrstype=${rstype}

		# See if it is unregistered
		let found=0
		for lfoo in ${SCSETUP_RT_NAMES_REG[*]}
		do
			if [[ "${lrstype}" == "${lfoo}" ]]; then
				let found=1
				break
			fi
		done

		# If unregistered, register it now?
		while [[ ${found} -eq 0 ]]
		do
			# Print message
			sc_print_para "${sctxt_reg_p1}"
			sc_print_para "${sctxt_reg_p2}"

			# Is the software installed on each node?
			answer=$(sc_prompt_yesno "$(gettext 'Is the software for this service installed on each node?')" "${YES}") || return 1
			if [[ "${answer}" != "yes" ]]; then
				printf "$(gettext 'Please install the software on each node, then try again.')\n\n\a"
				return 1
			fi

			# Okay to register the data service
			answer=$(sc_prompt_yesno "$(gettext 'Is it okay to register this resource type now?')" "${YES}") || return 1
			if [[ "${answer}" != "yes" ]]; then
				
				# Print message
				sc_print_para "${sctxt_reg_p3}"

				# Confirm
				answer=$(sc_prompt_yesno "$(gettext 'Are you sure?')" "${NO}") || return 1
				if [[ "${answer}" != "yes" ]]; then
					printf "$(gettext 'Then you must select another resource type!')\n\n\a"
					sc_prompt_pause
					return 1
				fi
			fi

			# Okay to register
			let rstype_register=1

			# Done
			break
		done

		# Done
		break
	done

	# Register the resource type, if needed
	if [[ -n "${rstype}" ]] && [[ ${rstype_register} -ne 0 ]]; then

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCRGADM} -a -t ${rstype}"

		# Attempt to issue the command, without re-confirmation
		scsetup_do_cmdset 1 || return 1
	fi

	# Get the resource name
	rsname=
	while [[ -z "${rsname}" ]]
	do
		# Get the name of the resource
		answer="$(sc_prompt "$(gettext 'What is the name of the resource you want to add?')")" || return 1

		# If the resource already exists, print error
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			foo="$(scsetup_get_resource ${answer})"
			if [[ -n "${foo}" ]]; then
				printf "$(gettext 'Resource \"%s\" is already configured.')\n\n\a" "${answer}"
				continue
			fi
		fi

		# Done
		rsname=${answer}
	done

	# See if we must set the Scalable property
	rsscalable=
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
		scsetup_get_prop_default ${rstype} Scalable 2>/dev/null 1>&2
		if [[ $? -eq 0 ]]; then
			rsscalable=doit
		fi
	elif [[ "${rgtype}" == "scalable" ]]; then
		rsscalable=doit
	fi
	if [[ -n "${rsscalable}" ]]; then
		if [[ "${rgtype}" == "scalable" ]]; then
			rsscalable=true
		else
			rsscalable=false
		fi
	fi

	# Get the network_resources_used list for scalable RGs, if required
	rsnetused=
	if [[ "${rgtype}" == "scalable" ]]; then

		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			scsetup_get_prop_default ${rstype} Network_resources_used 2>/dev/null 1>&2
			if [[ $? -eq 0 ]]; then
				rsnetused=doit
			fi
		else
			rsnetused=doit
		fi
	fi
	if [[ "${rsnetused}" == "doit" ]]; then
		rsnetused=

		# Get the rsnetused list
		while [[ -z "${rsnetused}" ]]
		do

			let counter=0
			answers=

			# Print help
			sc_print_para "${sctxt_netused_p1}"
			sc_print_para "${sctxt_netused_p2}"

			# Get the list of addresses
			while true
			do
				# Get the name of the resource
				if [[ ${counter} -lt 1 ]]; then
					answer=$(sc_prompt "${sctxt_netused_prompt1}" "" "nonl") || continue
				else
					answer=$(sc_prompt "${sctxt_netused_prompt2}" "" "nonl") || break
				fi

				# Make sure it is not a duplicate
				for foo in ${answers}
				do
					if [[ "${answer}" == "${foo}" ]]; then
						echo
						printf "$(gettext '\"%s\" already entered.')\n\n\a" "${answer}"
						continue 2
					fi
				done

				# Make sure that it is a resource
				if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
					foo=$(scsetup_get_rslist ${answer})
					if [[ -z "${foo}" ]]; then
						echo
						printf "$(gettext 'Unknown resource.')\n\n\a)"
						continue
					fi
				fi

				# And, it must be shared address
				if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
					foo=$(scsetup_get_rslist ${answer} "sunw.sharedaddress")
					if [[ -z "${foo}" ]]; then
						echo
						printf "$(gettext 'Not a shared address resource.')\n\n\a)"
						continue
					fi
				fi

				# Okay, add it to the list of answers
				answers="${answers} ${answer}"

				# Next
				((counter += 1))
			done

			# Verify that the list is correct
			echo
			sc_print_para "$(gettext 'This is the list you entered of SharedAddress resources used:')"
			for answer in ${answers}
			do
				printf "\t${answer}\n"
			done
			echo
			answer=$(sc_prompt_yesno "$(gettext 'Is it correct?')" "${YES}") || return 1
			if [[ "${answer}" != "yes" ]]; then
				continue
			fi        

			# Okay, set rsnetused
			for answer in ${answers}
			do
				if [[ -n "${rsnetused}" ]]; then
					rsnetused="${rsnetused},"
				fi
				rsnetused="${rsnetused}${answer}"
			done
		done
	fi

	# See if a portlist is required
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
		rsportlist_dflt="$(scsetup_get_prop_default ${rstype} Port_list)"
		# If Port_list is an unknown property, set dflt to "notused"
		if [[ $? -ne 0 ]]; then
			rsportlist_dflt=notused
		fi

	# If debugging and "scalable", port list is required
	elif [[ "${rgtype}" == "scalable" ]]; then
		rsportlist_dflt=

	# If debugging and not "scalable", no port list
	else
		rsportlist_dflt=notused
	fi

	# Get the rsportlist, if required
	rsportlist=
	while [[ "${rsportlist_dflt}" != "notused" ]] &&
	    [[ -z "${rsportlist}" ]]
	do

		# Reset port list?
		if [[ -n "${rsportlist_dflt}" ]]; then

			# Print help
			sc_print_para "${sctxt_portlist_p1}"

			# Print default setting
			for foo in ${rsportlist_dflt}
			do
				printf "\t${foo}\n"
			done
			echo

			# Print more help
			sc_print_para "${sctxt_portlist_p3}"

			# Override the default?
			answer=$(sc_prompt_yesno "$(gettext 'Do you want to override the default?')" "${NO}")
			if [[ "${answer}" != "yes" ]]; then
				break
			fi
		else
			# Print help
			sc_print_para "${sctxt_portlist_p2}"
			sc_print_para "${sctxt_portlist_p3}"
		fi

		# Get the list of ports
		answers=
		while true
		do
			# Get the port number
			answer=$(sc_prompt "${sctxt_portlist_prompt1}" "" "nonl") || break
			if [[ "${answer}" != [0-9]* ]]; then
				echo
				printf "$(gettext '\"%s\" is not numeric.')\n\n\a" "${answer}"
				continue
			fi
			let j=${answer}
			if [[ ${j} -lt 1 ]]; then
				echo
				printf "$(gettext 'The port number must be greater than zero.')\n\n\a"
				continue
			fi

			# TCP?
			foo=$(sc_prompt_yesno "${sctxt_portlist_prompt2}" "${YES}") || continue
			if [[ "${foo}" == "yes" ]]; then
				answer="${answer}/tcp"
			else
				answer="${answer}/udp"
			fi

			# Make sure it is not a duplicate
			for foo in ${answers}
			do
				if [[ "${answer}" == "${foo}" ]]; then
					printf "$(gettext '\"%s\" already entered.')\n\n\a" "${answer}"
					continue 2
				fi
			done

			# Okay, add it to the list of answers
			answers="${answers} ${answer}"
		done

		# Did they enter anything?
		if [[ -z "${answers}" ]]; then
			break
		fi

		# Verify that the list is correct
		echo
		sc_print_para "$(gettext 'This is the Port_list which you entered:')"
		for answer in ${answers}
		do
			printf "\t${answer}\n"
		done
		echo
		answer=$(sc_prompt_yesno "$(gettext 'Is it correct?')" "${YES}") || return 1
		if [[ "${answer}" != "yes" ]]; then
			continue
		fi        

		# Okay, set rsportlist
		for answer in ${answers}
		do
			if [[ -n "${rsportlist}" ]]; then
				rsportlist="${rsportlist},"
			fi
			rsportlist="${rsportlist}${answer}"
		done
	done

	#
	# Get the extension properties for this resource type
	#
	#	SCSETUP_RT_PROP_NAMES	# names of all the properties
	#	SCSETUP_RT_PROP_DESCS	# description of each property in list
	#	SCSETUP_RT_PROP_TYPES	# type of each property in list
	#	SCSETUP_RT_PROP_DFLTS	# default values for each property
	#
	set -A SCSETUP_RT_PROP_NAMES
	set -A SCSETUP_RT_PROP_DESCS
	set -A SCSETUP_RT_PROP_TYPES
	set -A SCSETUP_RT_PROP_DFLTS
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
		scsetup_get_rstype_extprops ${rstype}

	# Debug mode
	else
		set -A SCSETUP_RT_PROP_NAMES Prop_int Prop_string Prop_array Prop_other
		SCSETUP_RT_PROP_DESCS[0]="Integer property"
		SCSETUP_RT_PROP_DESCS[1]="String property"
		SCSETUP_RT_PROP_DESCS[2]="String array property"
		SCSETUP_RT_PROP_DESCS[3]="Other property"

		SCSETUP_RT_PROP_TYPES[0]=Int
		SCSETUP_RT_PROP_TYPES[1]=String
		SCSETUP_RT_PROP_TYPES[2]=Stringarray
		SCSETUP_RT_PROP_TYPES[3]=

		SCSETUP_RT_PROP_DFLTS[0]=20
		SCSETUP_RT_PROP_DFLTS[1]="hello"
		SCSETUP_RT_PROP_DFLTS[2]=
		SCSETUP_RT_PROP_DFLTS[3]=
	fi

	# Get the extension property settings
	set -A propnames
	set -A propvalues
	while [[ -n "${SCSETUP_RT_PROP_NAMES[0]}" ]]
	do
		let index=0
		set -A propnames
		set -A propvalues

		# Print help
		sc_print_para "${sctxt_extprops_p1}"

		# Set any properties now?
		answer=$(sc_prompt_yesno "$(gettext 'Any extension properties you would like to set?')" "${YES}") || return 1
		if [[ "${answer}" != "yes" ]]; then
			break
		fi

		# List the properties, if we kown them
		scsetup_print_rstype_extprops ${rstype}

		# Get the list of names and values
		printf "    %s\n" "$(gettext 'Please enter the list of properties you want to set:')"
		printf "      %s\n" "$(gettext '(Type Ctrl-D to finish  OR  "?" for help)')"
		while true
		do

			propname=
			propdesc=
			proptype=
			propvalue=
			propdflt=

			# Get the name
			echo
			propname=$(sc_prompt "${sctxt_extprops_prompt1}" "" "nonl" "space") || break

			# Need help?
			if [[ "X${propname}" == "X?" ]]; then
				scsetup_print_rstype_extprops ${rstype}
				continue
			fi

			# Make sure it is known
			proptype=$(scsetup_get_rstype_extprop_type ${propname})
			if [[ $? -ne 0 ]]; then
				echo
				printf "$(gettext 'Unknown extension property.')\n\a"
				continue
			fi

			# Print the description
			sc_print_prompt "${sctxt_extprops_prompt2}" "space"
			propdesc="$(scsetup_get_rstype_extprop_desc ${propname})"
			echo "${propdesc}"

			# Get the value
			while true
			do
				propvalue=$(sc_prompt "${sctxt_extprops_prompt3}" "" "nonl" "space") || continue 2

				# Need help?
				if [[ "X${propvalue}" == "X?" ]]; then
					propdflt="$(scsetup_get_rstype_extprop_dflt ${propname})"
					echo
					if [[ -z "${propdflt}" ]]; then
						printf "$(gettext 'This property has no default.')\n\n"
					else
						printf "$(gettext 'The default is \"%s\".')\n\n" "${propdflt}"
					fi
					continue
				fi

				#
				# Attempt to make sure the value is in some
				# kind of legal range.  Note that we currently
				# do not check for all value types.
				#
				case ${proptype} in
				"int")
					if [[ $(expr "${propvalue}" : '[0-9]*') -ne ${#propvalue} ]]; then
						echo
						printf "$(gettext '\"%s\" is not numeric.')\n\n\a" "${propvalue}"
						continue
					fi
					;;

				"stringarray")
					;;

				*)
					if [[ "${propvalue}" == *,* ]]; then
						echo
						printf "$(gettext 'Stringarray is not expected.')\n\n\a"
						continue
					fi
					;;
				esac

				# Done
				break
			done

			# Reset the value, if the name already set once
			let j=0
			while [[ -n "${propnames[j]}" ]]
			do
				if [[ "${propname}" == "${propnames[j]}" ]]; then
					propvalues[j]=${propvalue}
					break
				fi
				((j += 1))
			done

			# Or, if not yet set, add it to the list
			if [[ -z "${propnames[j]}" ]]; then
				propnames[index]=${propname}
				propvalues[index]=${propvalue}

				# Next
				((index += 1))
			fi
		done

		# Verify that the list is correct
		echo
		sc_print_prompt "$(gettext 'Here is the list of extension properties you entered:')"
		echo
		echo
		let index=0
		for propname in ${propnames[*]}
		do
			printf "\t${propname}=${propvalues[index]}\n"
			((index += 1))
		done
		echo
		answer=$(sc_prompt_yesno "$(gettext 'Is it correct?')" "${YES}") || return 1
		if [[ "${answer}" == "yes" ]]; then
			break
		fi
	done

	#
	# Add the resource
	#

	# Initialize
	set -A SCSETUP_DO_CMDSET

	# Basic command
	SCSETUP_DO_CMDSET[0]="${SC_SCRGADM} -a -j ${rsname}"
	SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -g ${rgname}"
	SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -t ${rstype}"

	# Add Scalable=true|false
	if [[ -n "${rsscalable}" ]]; then
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -y Scalable=${rsscalable}"
	fi

	# Add Network_resources_used
	if [[ -n "${rsnetused}" ]]; then
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -y Network_resources_used=${rsnetused}"
	fi

	# Add the Port_list, if set
	if [[ -n "${rsportlist}" ]]; then
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -y Port_list=${rsportlist}"
	fi

	# Add extension properties, if there are any
	let index=0
	for propname in ${propnames[*]}
	do
		SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]} -x ${propname}=${propvalues[index]}"
		((index += 1))
	done

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	# Bring this resource online?
	if [[ -z "${noenable}" ]]; then

		# Enable it?
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to enable this resource?')" "${YES}")
		if [[ "${answer}" == "yes" ]]; then
			set -A SCSETUP_DO_CMDSET
			SCSETUP_DO_CMDSET[0]="${SC_SCSWITCH} -e -j ${rsname}"
			SCSETUP_DO_CMDSET[1]="${SC_SCSWITCH} -e -M -j ${rsname}"
			scsetup_do_cmdset || return 1
		fi
	fi

	return 0
}

#####################################################
#
# scsetup_help_rgm_menu()
#
#	Print help information from the rgm menu.
#	This is the same help information as is printed
#	from the MAIN RGM help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_rgm_menu()
{
	clear
	scsetup_help_main_rgm
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_rgm_menuoption()
#
#	Print the RGM menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rgm_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** Resource Group Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Create a resource group')"
	typeset sctxt_option_002="$(gettext 'Add a network resource to a resource group')"
	typeset sctxt_option_003="$(gettext 'Add a data service resource to a resource group')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the previous Menu')"

	# Return
	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
		"S+0+3+${sctxt_option_003}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_rgm()
#
#	RGM menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_rgm()
{
	# Loop around the RGM RG menu
	while true
	do
		case $(scsetup_get_rgm_menuoption) in
		'1')    scsetup_menu_rgm_rg_create ;;
		'2')    scsetup_menu_rgm_rs_addnet ;;
		'3')    scsetup_menu_rgm_rs_addds ;;
		'?')    scsetup_help_rgm_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#
# scsetup_get_rgm_rgtype_menuoption()
#
#	Print the rg type menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rgm_rgtype_menuoption()
{
	typeset sctxt_title_2="$(gettext 'Select the type of resource group you want to add:')"
	typeset sctxt_option_001="Failover Group"
	typeset sctxt_option_002="Scalable Group"

	# Return
	option=$(sc_get_menuoption \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_get_rgm_net_rstype_menuoption()
#
#	Print the network resource type menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_rgm_net_rstype_menuoption()
{
	typeset sctxt_title_2="$(gettext 'Select the type of network resource you want to add:')"
	typeset sctxt_option_001="LogicalHostname"
	typeset sctxt_option_002="SharedAddress"

	# Return
	option=$(sc_get_menuoption \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#####################################################
##
## Cluster transport
##
#####################################################
#####################################################

#####################################################
#
# scsetup_prompt_transport_adapter() "[prompt]"
#
#	Prompt for the transport adapter name, then
#	perform simple verification.  If "prompt" is not given,
#	a default prompt is used.
#
#	The prompt is printed on file descriptor 4, and the answer
#	is printed to stdout.  File descriptor 4 should be
#	dupped to the original stdout before this function is called.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_prompt_transport_adapter()
{
	typeset prompt="${1}"

	typeset dflt_prompt="$(gettext 'Name of adapter?')"
	typeset answer

	# If no prompt is given, use the default
	if [[ -z "${prompt}" ]]; then
		prompt="${dflt_prompt}"
	fi

	#
	# The caller of this function should have already opened
	# descriptor 4 as a dup of the original stdout.
	#
	# Dup this function's stdout to descriptor 5.
	# Then, re-direct stdout to descriptor 4.
	#
	# So, the default stdout from this function will go to
	# the original stdout (probably the tty).  Descriptor 5
	# has the answer printed to it.
	#
	exec 5>&1
	exec 1>&4

	# Loop until we get the value or Ctrl-D is typed
	while true
	do
		# Get the adapter name
		answer=$(sc_prompt "${prompt}") || return 1

		# Adapter name must be <alpha><numeric>
		if [[ "${answer}" = *:* ]] ||
		    [[ $(expr "${answer}" : '[a-z][a-z]*[0-9][0-9]*') -ne ${#answer} ]]; then
			printf "$(gettext 'Invalid adapter name.')\n\n\a"
			continue
		fi

		# okay
		echo ${answer} >&5
		break
	done

	return 0
}

#####################################################
#
# scsetup_prompt_transport_junction() "[prompt]"
#
#	Prompt for the transport junction name, then
#	perform simple verification.  If "prompt" is not given,
#	a default prompt is used.
#
#	The prompt is printed on file descriptor 4, and the answer
#	is printed to stdout.  File descriptor 4 should be
#	dupped to the original stdout before this function is called.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_prompt_transport_junction()
{
	typeset prompt="${1}"

	typeset dflt_prompt="$(gettext 'Name of cluster transport junction?')"
	typeset answer

	# If no prompt is given, use the default
	if [[ -z "${prompt}" ]]; then
		prompt="${dflt_prompt}"
	fi

	#
	# The caller of this function should have already opened
	# descriptor 4 as a dup of the original stdout.
	#
	# Dup this function's stdout to descriptor 5.
	# Then, re-direct stdout to descriptor 4.
	#
	# So, the default stdout from this function will go to
	# the original stdout (probably the tty).  Descriptor 5
	# has the answer printed to it.
	#
	exec 5>&1
	exec 1>&4

	# Loop until we get the value or Ctrl-D is typed
	while true
	do
		# Get the junction name
		answer=$(sc_prompt "${prompt}") || return 1

		# Junc name must begin with alpha and may not include : or @.
		if [[ "${answer}" = [!a-zA-Z]* ]] ||
		    [[ "${answer}" = *[@:]* ]]; then
			printf "$(gettext 'Invalid junction name.')\n\n\a"
			continue
		fi

		# Junc name must be <= 256 characters
		if [[ ${#answer} -gt 256 ]]; then
			printf "$(gettext 'Junction name is too long.')\n\n\a"
			continue
		fi

		# okay
		echo ${answer} >&5
		break
	done

	return 0
}

#####################################################
#
# scsetup_prompt_transport_endpoint()
#
#	Get the adapter endpoint of an existing transport cable.
#
#	The prompt is printed on file descriptor 4, and the answer
#	is printed to stdout.  File descriptor 4 should be
#	dupped to the original stdout before this function is called.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_prompt_transport_endpoint()
{
	typeset answer

	typeset sctxt_p1="$(gettext '
		Each existing cluster transport cable can be
		identified by naming one of the cable endpoints.
		Since one of the two endpoints is always attached to a
		node, you will be asked to supply the node and adapter
		names of one of the endpoints of the cable you are
		trying to identify.
	')"

	integer found
	typeset nodelist
	typeset nodename
	typeset adapterlist
	typeset adaptername
	typeset adapter
	typeset endpointlist
	typeset endpoint
	typeset prompt
	typeset answer

	#
	# The caller of this function should have already opened
	# descriptor 4 as a dup of the original stdout.
	#
	# Dup this function's stdout to descriptor 5.
	# Then, re-direct stdout to descriptor 4.
	#
	# So, the default stdout from this function will go to
	# the original stdout (probably the tty).  Descriptor 5
	# has the answer printed to it.
	#
	exec 5>&1
	exec 1>&4

	# Print help
	sc_print_para "${sctxt_p1}"

	# Loop until we get the value or Ctrl-D is typed
	while true
	do
		# Get nodelist
		nodelist=
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		fi

		# Get the node name for the endpoint
		answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'To which node is the cable attached?')") || return 1
		nodename=${answer}

		# Get the adaptername
		prompt="$(printf "$(gettext 'Name of the adapter on \"%s\"?')" "${nodename}")"
		while true
		do
			# Prompt for adapter name
			answer=$(scsetup_prompt_transport_adapter "${prompt}") || continue 2

			# Get the list of configured adapters for this node
			adapterlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				adapterlist="$(scsetup_get_adapterlist ${nodename})"
			fi

			# See if this adapter is configured
			let found=0
			for adapter in ${adapterlist}
			do
				if [[ "${answer}" = "${adapter}" ]]; then
					let found=1
					break
				fi
			done

			#
			# If there is a adapterlist, but the adapter
			# is not found, print error.
			#
			if [[ -n "${adapterlist}" ]] && [[ ${found} -eq 0 ]]; then
				printf "$(gettext 'Unknown adapter.')\n\n\a"
				continue
			fi

			# Okay
			adaptername=${answer}
			break
		done

		# Get the list of configured endpoints
		endpointlist=
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			endpointlist="$(scsetup_get_endpoints)"
		fi

		# See if this endpoint is configured
		let found=0
		answer="${nodename}:${adaptername}@0"
		for endpoint in ${endpointlist}
		do
			if [[ "${answer}" = "${endpoint}" ]]; then
				let found=1
				break
			fi
		done
		answer="${nodename}:${adaptername}"

		#
		# If there is an endpointlist, but the endpoint
		# is not found, print error.
		#
		if [[ -n "${endpointlist}" ]] && [[ ${found} -eq 0 ]]; then
			printf "$(gettext 'Unknown cable.')\n\n\a"
			continue
		fi

		# okay
		echo ${answer} >&5
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_addcable() [nohelp]
#
#	nohelp		- if this flag is given, do not
#			    clear screen, print title, print help,
#			    or ask for confirmation to continue
#
#	Add a cluster transport cable to the cluster, along with
#	any necessary adapters and junctions used to create the cable.
#
#	Return:
#		zero		Completed
#		non-zero	Not completed
#
#####################################################
scsetup_menu_transport_addcable()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Add a Cluster Transport Cable <<<
	')"
        typeset sctxt_p1="$(gettext '
		Each cluster transport cable either directly connects
		two cluster nodes or connects a cluster node to a port
		on a transport junction.  Only two-node clusters may
		use directly-connected cables;  all cables on clusters
		with more than two nodes must be cabled to junctions.
	')"
	typeset sctxt_p2="$(gettext '
		This option is used to add a new cluster transport
		cable to the cluster configuration.  If either of the
		two endpoints of the cable do not already exist,
		they will also be added to the configuration.
	')"
	typeset sctxt_p1_directconnect="$(gettext '
		Since this is a two-node cluster, direct-connect cabling
		of the transport cables may be supported.  Refer to the
		documentation for your cluster transport adapters for
		more information on whether or not your hardware supports
		direct-connect cabling.  Some adapter types may require
		the use of junctions even on two-node clusters.
	')"
	typeset sctxt_p2_directconnect="$(gettext '
		Note that direct-connect cabling can complicate the
		later addition of a third node to the cluster.
	')"
	typeset sctxt_p1_selected_direct="$(gettext '
		Since the cable you are adding is a direct-connect
		cable, each cable endpoint must be attached directly to
		an adapter on each of the two nodes in the cluster.
		You will be asked to supply the names of each of these
		two adapters.
	')"
	typeset sctxt_p1_not_directconnect="$(gettext '
		Since there are more than two nodes in this cluster,
		all transport cables must have one end connected to
		a transport adapter on a node and the other end connected
		to a port on a cluster transport junction.  Direct-connect
		cabling is not supported on clusters with greater than
		two nodes.
	')"
	typeset sctxt_p1_selected_not_direct="$(gettext '
		Since the cable you are adding is not a direct-connect cable,
		one end must be attached to a node and the other attached
		to a cluster transport junction.  You will be asked to
		supply the name of the node and adapter for the first
		endpoint, as well as the name of the junction and port
		for the second endpoint.
	')"
	typeset sctxt_p1_dfltport="$(gettext '
		Each adapter is cabled to a particular port on a
		transport junction, and each port is assigned a
		name.  You may explicitly assign a name to each port,
		or, for certain junction types, you may allow scsetup
		to assign a default name for you.   The default port
		name assignment sets the name to the node number of the
		node hosting the transport adapter at the other end of
		the cable.
	')"
        typeset sctxt_p2_dfltport="$(gettext '
		Please remember that some types of cluster transport
		junctions are not compatible with the default port
		naming assignments.  For more information regarding
		port naming requirements, refer to the
		scconf_transp_jct family of man pages (for example,
		scconf_transp_jct_dolphinswitch(1M)).
	')"
	typeset sctxt_prompt_dfltport="$(gettext '
		Okay to use the default for this cable connection?
	')"

	integer twonodes
	integer directconnect
	integer index1
	integer index2
	integer found
	typeset trtype
	typeset list
	typeset nodelist
	typeset adapterlist
	typeset junctionlist
	typeset node
	typeset adapter
	typeset junction
	typeset endpoint_nodelist
	typeset endpoint_adapterlist
	typeset endpoint_junction
	typeset endpoint_junctionport
	typeset answer
	typeset prompt
	typeset thisadapterdriver
	typeset thisadapter

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Initialize
		let twonodes=0
		let directconnect=0
		trtype=
		nodelist=
		adapterlist=
		endpoint_nodelist=
		endpoint_adapterlist=

		# Get nodelist, twonodes, and trtype
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi

			# Set "twonodes" based on number of nodes in node list
			if [[ $(set -- ${nodelist}; echo $#) -eq 2 ]]; then
				let twonodes=1
			fi

			# Get trtype
			trtype="$(scsetup_get_trtypes)"

			# Make sure we have only one transport type
			if [[ -z "${trtype}" ]]; then
				printf "$(gettext 'Unable to determine transport type.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
			if [[ $(set -- ${trtype}; echo $#) -gt 1 ]]; then
				printf "$(gettext 'Scsetup does not support clusters with mixed transport types.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		else
			# We must be running in DEBUG mode
			answer=$(sc_prompt_yesno "$(gettext 'DEBUG:  Is this a two-node cluster?')" "${YES}") || return 1
			if [[ "${answer}" = "yes" ]]; then
				let twonodes=1

				#
				# Since this is just DEBUG mode, we do
				# not error-check node name responses.
				#
				answer=$(sc_prompt "$(gettext 'DEBUG:  What is the name of the first node?')" "node1") || return 1
				nodelist="${answer}"

				answer=$(sc_prompt "$(gettext 'DEBUG:  What is the name of the second node?')" "node2") || return 1
				nodelist="${nodelist} ${answer}"
			fi

			# Since this is just DEBUG mode, do not check trtype
			answer=$(sc_prompt "$(gettext 'DEBUG:  What transport type are you using?')" "dlpi") || return 1
			trtype=${answer}
		fi

		# Two node clusters may be directly connected.
		if [[ ${twonodes} -eq 1 ]]; then
			sc_print_para "${sctxt_p1_directconnect}"
			sc_print_para "${sctxt_p2_directconnect}"
			answer=$(sc_prompt_yesno "$(gettext 'Are you adding a directly-connected cable?')" "${NO}") || return 1
			if [[ "${answer}" = "yes" ]]; then
				let directconnect=1
			fi
		else
			sc_print_para "${sctxt_p1_not_directconnect}"
		fi

		# Direct connect
		if [[ ${directconnect} -eq 1 ]]; then

			# Print help
			sc_print_para "${sctxt_p1_selected_direct}"

			# Get the two adapters for the two nodes
			endpoint_nodelist="${nodelist}"
			endpoint_adapterlist=
			for node in ${endpoint_nodelist}
			do
				# Get the adapter name
				while true
				do
					prompt="$(printf "$(gettext 'Name of the adapter to use on \"%s\"?')" "${node}")"
					answer=$(scsetup_prompt_transport_adapter "${prompt}") || return 1
					thisadapterdriver=$(expr ${answer} : '\([a-z]*\)')
					if [[ "${thisadapterdriver}" = "${SCSETUP_WILDCAT_ADAPTER}" ]]; then
						printf "$(gettext 'WCI transport adapters cannot be configured without junctions.')\n\n\a"
						continue;
					fi
					break
				done

				# add it to the list
				endpoint_adapterlist="${endpoint_adapterlist} ${answer}"
			done

		# NOT direct connect
		else
			# Print help
			sc_print_para "${sctxt_p1_selected_not_direct}"

			# Get the node name for first endpoint
			answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'To which node do you want to add the cable?')") || return 1
			endpoint_nodelist=${answer}

			# Get the adapter name for first endpoint
			prompt="$(printf "$(gettext 'Name of the adapter to use on \"%s\"?')" "${endpoint_nodelist}")"
			answer=$(scsetup_prompt_transport_adapter "${prompt}") || return 1
			endpoint_adapterlist="${endpoint_adapterlist} ${answer}"

			# if Wildcat, we know the Junction name
			thisadapter=${answer}
			thisadapterdriver=$(expr ${answer} : '\([a-z]*\)')

			if [[ "${thisadapterdriver}" = "${SCSETUP_WILDCAT_ADAPTER}" ]]; then
				thisadapterinst=$(expr ${answer} : '[a-z]*\([0-9]*\)')
				answer=${SCSETUP_WILDCAT_JUNCTION}${thisadapterinst}
				text="$(printf "$(gettext 'Adapter \"%s\" is connected to virtual switch \"%s\".')" "${thisadapter}" "${answer}")"
				sc_print_para "${text}"
			# Otherwise, the user specifies the Junction name
			else
				# Get the name of the junction for the second endpoint
				answer=$(scsetup_prompt_transport_junction "$(gettext 'Name of the junction at the other end of the cable?')") || return 1
			fi

			endpoint_junction=${answer}
			# Use default junction ports?
			sc_print_para "${sctxt_p1_dfltport}"
			sc_print_para "${sctxt_p2_dfltport}"
			answer=$(sc_prompt_yesno "${sctxt_prompt_dfltport}" "${YES}") || return 1

			# If answer is yes, set port to "@"
			if [[ "${answer}" = "yes" ]]; then
				answer="@"

			# otherwise, prompt for the name
			else
				answer=$(sc_prompt "$(gettext 'What is the name of the port you want to use?')") || return 1
			fi
			endpoint_junctionport=${answer}
		fi

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET
		let index1=0

		# Create any needed adapters
		set -A list ${endpoint_adapterlist}
		let index2=0
		for node in ${endpoint_nodelist}
		do
			# Get the list of configured adapters for this node
			adapterlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				adapterlist="$(scsetup_get_adapterlist ${node})"
			fi

			# See if our adapter is already configured
			let found=0
			for adapter in ${adapterlist}
			do
				if [[ "${list[index2]}" = "${adapter}" ]]; then
					let found=1
					break
				fi
			done

			# If not, add command to create adapter
			if [[ ${found} -eq 0 ]]; then
				SCSETUP_DO_CMDSET[index1]="${SC_SCCONF} -a -A trtype=${trtype},name=${list[index2]},node=${node}"
				((index1 += 1))
			fi

			# Next
			((index2 += 1))
		done

		# Create any needed junctions
		if [[ -n ${endpoint_junction} ]]; then

			# Get the list of configured junctions
			junctionlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				junctionlist="$(scsetup_get_junctionlist)"
			fi

			# See if our junction is already configured
			let found=0
			for junction in ${junctionlist}
			do
				if [[ "${endpoint_junction}" = "${junction}" ]]; then
					let found=1
					break
				fi
			done

			# If not, add command to create junction
			if [[ ${found} -eq 0 ]]; then
				SCSETUP_DO_CMDSET[index1]="${SC_SCCONF} -a -B type=switch,name=${endpoint_junction}"
				((index1 += 1))
			fi
		fi

		# Add command to create cable
		SCSETUP_DO_CMDSET[index1]="${SC_SCCONF} -a -m "
		set -A list ${endpoint_adapterlist}
		let index2=0

		# Add all node endpoints
		for node in ${endpoint_nodelist}
		do
			# Add adapter endpoint to command
			if [[ ${index2} -gt 0 ]]; then
				SCSETUP_DO_CMDSET[index1]="${SCSETUP_DO_CMDSET[index1]},"
			fi
			SCSETUP_DO_CMDSET[index1]="${SCSETUP_DO_CMDSET[index1]}endpoint=${node}:${list[index2]}"

			# Next
			((index2 += 1))
		done

		# Add the junction endpoint
		if [[ -n "${endpoint_junction}" ]]; then
			SCSETUP_DO_CMDSET[index1]="${SCSETUP_DO_CMDSET[index1]},endpoint=${endpoint_junction}"

			# And, the junction endpoint port
			if [[ -n "${endpoint_junctionport}" ]] &&
			    [[ "${endpoint_junctionport}" != "@" ]]; then
				SCSETUP_DO_CMDSET[index1]="${SCSETUP_DO_CMDSET[index1]}@${endpoint_junctionport}"
			fi
		fi

		# Attempt to issue the command(s)
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_addjunction() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Add a cluster transport junction to the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_addjunction()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Add a Cluster Transport Junction <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to add a new cluster transport
		junction to the cluster configuration.
	')"

	typeset junctionlist
	typeset junctionname
	typeset junction
	typeset answer
	typeset prompt

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the junctionname
		while true
		do
			# Prompt for junction name
			answer=$(scsetup_prompt_transport_junction "$(gettext 'Name of the junction to add?')") || return 1

			# Get the list of configured junctions
			junctionlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				junctionlist="$(scsetup_get_junctionlist)"
			fi

			# See if our junction is already configured
			for junction in ${junctionlist}
			do
				if [[ "${answer}" = "${junction}" ]]; then
					printf "$(gettext 'Junction \"%s\" is already configured on \"%s\".')\n\n\a" "${answer}" "${nodename}"
					continue 2
				fi
			done

			# Okay
			junctionname=${answer}
			break
		done

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -B type=switch,name=${junctionname}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_addadapter() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Add a cluster transport adapter to the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_addadapter()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Add a Cluster Transport Adapter to a Node <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to add a new cluster transport
		adapter to the cluster configuration.
	')"
	typeset sctxt_p1_adapterdata="$(gettext '
		You will be asked to supply both the name of the adapter
		and the name of the node on which the adapter is found.
	')"

	typeset nodelist
	typeset nodename
	typeset adapterlist
	typeset adaptername
	typeset adapter
	typeset trtype
	typeset answer
	typeset prompt

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get nodelist and trtype
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi

			# Get trtype
			trtype="$(scsetup_get_trtypes)"

			# Make sure we have only one transport type
			if [[ -z "${trtype}" ]]; then
				printf "$(gettext 'Unable to determine transport type.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
			if [[ $(set -- ${trtype}; echo $#) -gt 1 ]]; then
				printf "$(gettext 'Scsetup does not support clusters with mixed transport types.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		else
			# Since this is just DEBUG mode, do not check trtype
			answer=$(sc_prompt "$(gettext 'DEBUG:  What transport type are you using?')" "dlpi") || return 1
			trtype=${answer}
		fi

		# Print help
		sc_print_para "${sctxt_p1_adapterdata}"

		# Get the nodename
		answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'To which node do you want to add the adapter?')") || return 1
		nodename=${answer}

		# Get the adaptername
		prompt="$(printf "$(gettext 'Name of the adapter to add to \"%s\"?')" "${nodename}")"
		while true
		do
			# Prompt for adapter name
			answer=$(scsetup_prompt_transport_adapter "${prompt}") || continue 2

			# Get the list of configured adapters for this node
			adapterlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				adapterlist="$(scsetup_get_adapterlist ${nodename})"
			fi

			# See if our adapter is already configured
			for adapter in ${adapterlist}
			do
				if [[ "${answer}" = "${adapter}" ]]; then
					printf "$(gettext 'Adapter \"%s\" is already configured on \"%s\".')\n\n\a" "${answer}" "${nodename}"
					continue 2
				fi
			done

			# Okay
			adaptername=${answer}
			break
		done

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -A trtype=${trtype},name=${adaptername},node=${nodename}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_rmcable() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Remove a cluster transport cable.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_rmcable()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Remove a Cluster Transport Cable <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to remove an existing
		cluster transport cable from the cluster configuration.
		However, the two endpoints of the cable will remain
		configured.
	')"
	typeset sctxt_p2="$(gettext '
		It is very important that you not disable or remove
		the last remaining healthy connection to an active cluster
		node.  Please check the status of other cables before
		you proceed.
	')"

	typeset endpoint

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the endpoint
		endpoint=$(scsetup_prompt_transport_endpoint) || return 1

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -m endpoint=${endpoint}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_rmadapter() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Remove a cluster transport adapter from the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_rmadapter()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Remove a Cluster Transport Adapter <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to remove an existing cluster transport
		adapter from the cluster configuration.  An adapter cannot
		be removed if it is still in use as an endpoint in a
		transport cable.
	')"
	typeset sctxt_p1_adapterdata="$(gettext '
		You will be asked to supply both the name of the adapter
		and the name of the node on which the adapter is found.
	')"

	integer found
	typeset nodelist
	typeset nodename
	typeset adapterlist
	typeset adaptername
	typeset adapter
	typeset answer
	typeset prompt

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get nodelist
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		fi

		# Print help
		sc_print_para "${sctxt_p1_adapterdata}"

		# Get the nodename
		answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'On which node is the adapter found?')") || return 1
		nodename=${answer}

		# Get the adaptername
		prompt="$(printf "$(gettext 'Name of the adapter to remove from \"%s\"?')" "${nodename}")"
		while true
		do
			# Prompt for adapter name
			answer=$(scsetup_prompt_transport_adapter "${prompt}") || continue 2

			# Get the list of configured adapters for this node
			adapterlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				adapterlist="$(scsetup_get_adapterlist ${nodename})"
			fi

			# See if our adapter is configured
			let found=0
			for adapter in ${adapterlist}
			do
				if [[ "${answer}" = "${adapter}" ]]; then
					let found=1
					break
				fi
			done

			#
			# If there is an adapterlist, but the adapter
			# is not found, print error.
			#
			if [[ -n "${adapterlist}" ]] && [[ ${found} -eq 0 ]]; then
				printf "$(gettext 'Unknown adapter.')\n\n\a"
				continue
			fi

			# Okay
			adaptername=${answer}
			break
		done

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -A name=${adaptername},node=${nodename}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_rmjunction() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Remove a cluster transport junction from the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_rmjunction()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Remove a Cluster Transport Junction <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to remove an existing cluster transport
		junction from the cluster configuration.  A junction cannot
		be removed if any of the ports are still in use as a endpoints
		in any transport cables.
	')"

	integer found
	typeset junctionlist
	typeset junctionname
	typeset junction
	typeset answer

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the junctionname
		while true
		do
			# Prompt for junction name
			answer=$(scsetup_prompt_transport_junction "$(gettext 'Name of the junction to remove?')") || return 1

			# Get the list of configured junctions
			junctionlist=
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				junctionlist="$(scsetup_get_junctionlist)"
			fi

			# See if our junction is configured
			let found=0
			for junction in ${junctionlist}
			do
				if [[ "${answer}" = "${junction}" ]]; then
					let found=1
					break
				fi
			done

			#
			# If there is a junctionlist, but the junction
			# is not found, print error.
			#
			if [[ -n "${junctionlist}" ]] && [[ ${found} -eq 0 ]]; then
				printf "$(gettext 'Unknown junction.')\n\n\a"
				continue
			fi

			# Okay
			junctionname=${answer}
			break
		done

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -B name=${junctionname}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_cableon() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Enable a cluster transport cable.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_cableon()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Enable a Cluster Transport Cable <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to enable an already existing
		cluster transport cable.
	')"

	typeset endpoint

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the endpoint
		endpoint=$(scsetup_prompt_transport_endpoint) || return 1

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -m endpoint=${endpoint},state=enabled"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_transport_cableoff() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Disable a cluster transport cable.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_transport_cableoff()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Disable a Cluster Transport Cable <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to disable an existing
		cluster transport cable.
	')"
	typeset sctxt_p2="$(gettext '
		It is very important that you not disable or remove
		the last remaining healthy connection to an active cluster
		node.  Please check the status of other cables before
		you proceed.
	')"

	typeset endpoint

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the endpoint
		endpoint=$(scsetup_prompt_transport_endpoint) || return 1

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -m endpoint=${endpoint},state=disabled"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_help_transport_menu()
#
#	Print help information from the transport menu.
#	This is the same help information as is printed
#	from the MAIN help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_transport_menu()
{
	clear
	scsetup_help_main_transport
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_transport_menuoption()
#
#	Print the cluster transport menu, and return
#	the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_transport_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** Cluster Interconnect Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Add a transport cable')"
	typeset sctxt_option_002="$(gettext 'Add a transport adapter to a node')"
	typeset sctxt_option_003="$(gettext 'Add a transport junction')"
	typeset sctxt_option_004="$(gettext 'Remove a transport cable')"
	typeset sctxt_option_005="$(gettext 'Remove a transport adapter from a node')"
	typeset sctxt_option_006="$(gettext 'Remove a transport junction')"
	typeset sctxt_option_007="$(gettext 'Enable a transport cable')"
	typeset sctxt_option_008="$(gettext 'Disable a transport cable')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
		"S+0+3+${sctxt_option_003}" \
		"S+0+4+${sctxt_option_004}" \
		"S+0+5+${sctxt_option_005}" \
		"S+0+6+${sctxt_option_006}" \
		"S+0+7+${sctxt_option_007}" \
		"S+0+8+${sctxt_option_008}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_transport()
#
#	Cluster transport menu
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_transport()
{
	# Loop around the cluster transport menu
	while true
	do
		case $(scsetup_get_transport_menuoption) in
		'1')    scsetup_menu_transport_addcable ;;
		'2')    scsetup_menu_transport_addadapter ;;
		'3')    scsetup_menu_transport_addjunction ;;
		'4')    scsetup_menu_transport_rmcable ;;
		'5')    scsetup_menu_transport_rmadapter ;;
		'6')    scsetup_menu_transport_rmjunction ;;
		'7')    scsetup_menu_transport_cableon ;;
		'8')    scsetup_menu_transport_cableoff ;;
		'?')    scsetup_help_transport_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Private hostnames
##
#####################################################
#####################################################

#####################################################
#
# scsetup_menu_privatehosts_namechange() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Change the private hostname for a given node in the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_privatehosts_namechange()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Change a Private Hostname <<<
	')"
	typeset sctxt_p1="$(gettext '
		Nodes may contact other nodes in the cluster 
		over the cluster interconnect by accessing them using
		their private hostnames.   Default private hostnames
		are assigned during cluster installation.
	')"
	typeset sctxt_p2="$(gettext '
		Note that private hostnames should never be stored
		in the hosts(4) or other naming services databases.
		A special nsswitch facility (see nsswitch.conf(4))
		performs all hostname lookups for private hostnames.
	')"
	typeset sctxt_p3="$(gettext '
		This option is used to change the private hostname
		for a given cluster node.   Any application or service
		which might cache private hostnames should be stopped
		before this change is made, then re-started after the
		change.  Please refer to the Sun Cluster documentation
		for additional information regarding changes to private
		hostnames before attempting to make any changes.
	')"

	typeset nodelist
	typeset nodename
	typeset privatename
	typeset answer
	typeset prompt

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"
		sc_print_para "${sctxt_p3}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get nodelist
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		fi

		# Get the nodename
		answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'Which cluster node do you want to change?')") || return 1
		nodename=${answer}

		# Get the new private hostname
		prompt="$(printf "$(gettext 'What is the new private hostname for \"%s\"?')" "${nodename}")"
		answer=$(sc_prompt "${prompt}") || return 1
		privatename=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -P node=${nodename},privatehostname=${privatename}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_help_privatehosts_menu()
#
#	Print help information from the private hostnames menu.
#	This is the same help information as is printed
#	from the MAIN help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_privatehosts_menu()
{
	clear
	scsetup_help_main_privatehosts
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_privatehosts_menuoption()
#
#	Print the private hostnames menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_privatehosts_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** Private Hostnames Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Change a private hostname')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_privatehosts()
#
#	Private hostnames menu
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_privatehosts()
{
	# Loop around the private hostnames menu
	while true
	do
		case $(scsetup_get_privatehosts_menuoption) in
		'1')    scsetup_menu_privatehosts_namechange ;;
		'?')    scsetup_help_privatehosts_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Device Groups
##
#####################################################
#####################################################

#####################################################
#
# scsetup_menu_devicegroups_addvxvm() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Register a VxVM disk group as a cluster device group.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_devicegroups_addvxvm()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Register a VxVM Disk Group as a Device Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		VERITAS Volume Manager disk groups are always managed by
		the cluster as cluster device groups.  This option is
		used to register a VxVM disk group with the
		cluster as a cluster device group.
	')"
	typeset sctxt_p1_preferenced="$(gettext '
		Primary ownership of a device group is determined by
		either specifying or not specifying a preferred
		ordering of the nodes that can own the device group. If
		an order is specified, this will be the order in which
		nodes will attempt to establish ownership. If an order
		is not specified, the first node thet attempts to
		access a disk in the device group becomes the owner.
	')"
	typeset sctxt_p1_list1="$(gettext '
		Please list the nodes which are directly attached to
		all of the disks in this disk group and are, therefore,
		eligible to take primary ownership of the group.
	')"
	typeset sctxt_p1_list2="$(gettext '
		Please list the nodes which are directly attached to
		all of the disks in this disk group and are, therefore,
		eligible to take primary ownership of the group.  The
		order in which you list these names is important,
		as it also specifies the order in which nodes will
		attempt to establish ownership of the group.
	')"
	typeset sctxt_p1_list3="$(gettext '
		Please list the order in which nodes should attempt
		to establish ownership of the group.
	')"
	typeset sctxt_p2_list1="$(gettext '
		List one node name per line.   At least two node nodes
		must be given.  When finished, type Control-D:
	')"
	typeset sctxt_p2_list2="${sctxt_p2_list1}"
	typeset sctxt_p2_list3="$(gettext '
		List one node name per line:
	')"
	typeset sctxt_node_prompt1="$(gettext 'Node name:')"
	typeset sctxt_node_prompt2="$(gettext 'Node name (Ctrl-D to finish):')"

	typeset dgname
	typeset dgtype
	typeset dg_nodelist
	typeset preferenced
	typeset failback

	integer nodecount
	integer getlist
	integer count
	integer found
	typeset nodelist
	typeset node
	typeset list
	typeset foo
	typeset answer
	typeset answers

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Initialize
		let nodecount=0
		nodelist=
		dg_nodelist=
		preferenced=
		failback=

		# Get nodelist and nodecount
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi

			# Set node count
			let nodecount=$(set -- ${nodelist}; echo $#)
		else
			# We must be running in DEBUG mode
			answer=$(sc_prompt_yesno "$(gettext 'DEBUG:  Is this a two-node cluster?')" "${YES}") || return 1
			if [[ "${answer}" = "yes" ]]; then

				# Set nodecount
				let nodecount=2

				#
				# Since this is just DEBUG mode, we do
				# not error-check node name responses.
				#
				answer=$(sc_prompt "$(gettext 'DEBUG:  What is the name of the first node?')" "node1") || return 1
				nodelist="${answer}"

				answer=$(sc_prompt "$(gettext 'DEBUG:  What is the name of the second node?')" "node2") || return 1
				nodelist="${nodelist} ${answer}"
			else
				# If not two, then get the node count
				while true
				do
					answer=$(sc_prompt "$(gettext 'DEBUG:  How  many nodes are in the cluster?')") || return 1

					# In range?
					if [[ $(expr ${answer} : '[0-9]*') -ne $(expr ${answer} : '.*') ]] ||
					    [[ ${answer} -lt 2 ]] ||
					    [[ ${answer} -gt ${SC_MAXNODEID} ]]; then
						printf "\a"
					else
						break
					fi
				done

				# Set nodecount
				let nodecount=${answer}

				# Set nodelist (node1, node2, node3, ...)
				count=0
				while [[ ${count} -lt ${nodecount} ]]
				do
					((count += 1))
					nodelist="${nodelist} node${count}"
				done
				
			fi
		fi

		# Get the name of the device group
		answer=$(sc_prompt "$(gettext 'Name of the VxVM disk group you want to register?')") || return 1
		dgname=${answer}

		# Make sure it is not already registered
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			dgtype=$(scsetup_get_devicegroup_type ${dgname})
			if [[ -n "${dgtype}" ]]; then
				printf "$(gettext '\"%s\" is already registered as a device group')\n\n\a" "${dgname}"
				continue
			fi
		fi

		# Preferenced?
		sc_print_para "${sctxt_p1_preferenced}"
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to configure a preferred ordering?')" "${YES}") || return 1
		if [[ "${answer}" = "yes" ]]; then
			preferenced="true"
		else
			preferenced="false"
		fi

		# Two node cluster
		if [[ ${nodecount} -eq 2 ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'Are both nodes attached to all disks in this group?')" "${YES}") || return 1

			# They MUST be!
			if [[ "${answer}" != "yes" ]]; then
				printf "$(gettext 'In a two-node cluster, all disks in the group must be dual-ported.')\n\n\a"
				continue
			fi

			# If preferenced is true, find out who is first
			if [[ "${preferenced}" = "true" ]]; then
				answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'Which node is the preferred primary for this device group?')") || return 1
				set -A list ${nodelist}
				if [[ "${answer}" = "${list[0]}" ]]; then
					dg_nodelist="${list[0]} ${list[1]}"
				elif [[ "${answer}" = "${list[1]}" ]]; then
					dg_nodelist="${list[1]} ${list[0]}"
				else
					printf "$(gettext 'Internal error in scsetup_menu_devicegroups_addvxvm()')\n\n\a"
					sc_prompt_pause
					return 1
				fi
			fi

		# More than two nodes
		else
			answer=$(sc_prompt_yesno "$(gettext 'Are all nodes attached to all disks in this group?')" "${YES}") || return 1

			# Clear flag to get node list
			let getlist=0

			# Get list of disks, no preferenced order
			if [[ "${answer}" = "no" ]] &&
			    [[ "${preferenced}" = "false" ]]; then
				let getlist=1

			# Get list of disks, preferenced ordering
			elif [[ "${answer}" = "no" ]] &&
			    [[ "${preferenced}" = "true" ]]; then
				let getlist=2

			# Get the preference list
			elif [[ "${answer}" = "yes" ]] &&
			    [[ "${preferenced}" = "true" ]]; then
				let getlist=3
			fi

			# Get the nodelist
			while [[ ${getlist} -gt 0 ]]
			do
				# Initialize
				answers=

				# Prompt based on type
				case ${getlist} in
				1)	# list of disks, no order
					sc_print_para "${sctxt_p1_list1}"
					sc_print_para "${sctxt_p2_list1}"
					;;

				2)	# list of disks, ordered
					sc_print_para "${sctxt_p1_list2}"
					sc_print_para "${sctxt_p2_list2}"
					;;

				3)	# Preference order only
					sc_print_para "${sctxt_p1_list3}"
					sc_print_para "${sctxt_p2_list3}"
					;;
				esac

				# Get the dg nodelist
				let count=0
				while [[ ${count} -lt ${nodecount} ]]
				do
					#
					# Cannot use Ctrl-D if we have not yet
					# typed in at least two node names or
					# if we are just typing preference list.
					#
					if [[ ${count} -lt 2 ]] ||
					    [[ ${getlist} -eq 3 ]]; then
						answer=$(sc_prompt "${sctxt_node_prompt1}" "" "nonl") || continue
					else
						answer=$(sc_prompt "${sctxt_node_prompt2}" "" "nonl") || break
					fi

					# must be in our nodelist
					let found=0
					for node in ${nodelist}
					do
						if [[ "${answer}" = "${node}" ]]; then
							let found=1
							break
						fi
					done

					# Make sure we found it
					if [[ -n "${nodelist}" ]] &&
					    [[ ${found} -eq 0 ]]; then
						echo
						printf "$(gettext 'Unknown node name.')\n\n\a"
						continue
					fi

					# Make sure it is not a duplicate
					for node in ${answers}
					do
						if [[ "${answer}" = "${node}" ]]; then
							echo
							printf "$(gettext '\"%s\" already entered.')\n\n\a" "${answer}"
							continue 2
						fi
					done

					# Okay, add it to list of answers
					answers="${answers} ${answer}"

					# Next
					((count += 1))
				done

				# Verify that the list is correct
				echo
				case ${getlist} in
				1)	sc_print_para "$(gettext 'This is the list of nodes:')" ;;
				2|3)	
					sc_print_para "$(gettext 'This is the ordered list of nodes:')" ;;
				esac
				for node in ${answers}
				do
					printf "\t${node}\n"
				done
				echo
				answer=$(sc_prompt_yesno "$(gettext 'Is it correct?')" "${YES}") || return 1
				if [[ "${answer}" != "yes" ]]; then
					continue
				fi

				# Set dg_nodelist
				dg_nodelist="${answers}"

				# Done
				break
			done
		fi

		# If the dg_nodelist is not set, set to the default
		if [[ -z "${dg_nodelist}" ]]; then
			dg_nodelist="${nodelist}"
		fi

		# Reformat the dg_nodelist to give to scconf
		foo="${dg_nodelist}"
		dg_nodelist=
		for node in ${foo}
		do
			if [[ -n "${dg_nodelist}" ]]; then
				dg_nodelist="${dg_nodelist}:"
			fi
			dg_nodelist="${dg_nodelist}${node}"
		done

		# Failback
		failback=
		if [[ "${preferenced}" = "true" ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'Enable \"failback\" for this disk device group?')" "${NO}") || return 1
			if [[ "${answer}" = "yes" ]]; then
				failback="enabled"
			fi
		fi

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -D type=${SCSETUP_DG_VXVM_SET},name=${dgname}"

		# Nodelist?	(the default is all nodes)
		if [[ -n "${dg_nodelist}" ]]; then
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},nodelist=${dg_nodelist}"
		fi

		# Preferenced?	("false" is the default)
		if [[ "${preferenced}" = "true" ]]; then
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},preferenced=true"
		fi

		# Failback?	("disabled" is the default)
		if [[ "${failback}" = "enabled" ]]; then
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},failback=enabled"
		fi

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_devicegroups_syncvxvm() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Synchronize volume information for a VxVM device group.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_devicegroups_syncvxvm()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Synchronize Volume Information for a VxVM Device Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		VERITAS Volume Manager disk groups are always managed
		by the cluster as cluster device groups.  This option
		is used to synchronize volume information for a VxVM
		device group between the VxVM software and the
		clustering software.  It should be selected anytime a
		volume is either added to or removed from a VxVM disk
		group.  Otherwise, the cluster will be unaware of the
		changes.
	')"
	typeset dgname
	typeset dgtype

	typeset answer

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do

		# Get the name of the device group
		answer=$(sc_prompt "$(gettext 'Name of the VxVM device group you want to synchronize?')") || return 1
		dgname=${answer}

		# Make sure it is a VxVM device group
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			dgtype=$(scsetup_get_devicegroup_type ${dgname})
			if [[ -z "${dgtype}" ]] ||
			    [[ "${dgtype}" != "${SCSETUP_DG_VXVM_LOOKUP}" ]]; then
				printf "$(gettext '\"%s\" is not a %s device group.')\n\n\a" "${dgname}" "${SCSETUP_DG_VXVM_LOOKUP}"
				continue
			fi
		fi

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -D name=${dgname},sync"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_devicegroups_rmvxvm() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Unregister a VxVM disk group as a cluster device group.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_devicegroups_rmvxvm()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Unregister a VxVM Disk Group as a Device Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		VERITAS Volume Manager disk groups are always managed
		by the cluster as cluster device groups.  This option is used
		to unregister a VxVM cluster device group.
	')"
	typeset sctxt_p2="$(gettext '
		Before you attempt to unregister this group, please be sure
		that there are no mounts or other active references to
		any of the devices in the group.
	')"

	typeset dgname
	typeset dgtype
	typeset answer

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do

		# Get the name of the device group
		answer=$(sc_prompt "$(gettext 'Name of the VxVM device group you want to unregister?')") || return 1
		dgname=${answer}

		# Make sure it is a VxVM device group
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			dgtype=$(scsetup_get_devicegroup_type ${dgname})
			if [[ -z "${dgtype}" ]] ||
			    [[ "${dgtype}" != "${SCSETUP_DG_VXVM_LOOKUP}" ]]; then
				printf "$(gettext '\"%s\" is not a %s device group.')\n\n\a" "${dgname}" "${SCSETUP_DG_VXVM_LOOKUP}"
				continue
			fi
		fi

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -D name=${dgname}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_devicegroups_addnodevxvm() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Add a node to a VxVM device group.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_devicegroups_addnodevxvm()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Add a Node to a VxVM Device Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		VERITAS Volume Manager disk groups are always managed by
		the cluster as cluster device groups.  This option is
		used to add a node to an already existing VxVM cluster
		device group.
	')"

	typeset nodelist
	typeset nodename
	typeset node
	typeset list
	typeset dgname
	typeset dgtype
	typeset answer

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		#Initialize
		nodelist=

		# Get the name of the device group
		answer=$(sc_prompt "$(gettext 'Name of the VxVM device group to which you want to add a node?')") || return 1
		dgname=${answer}

		# Make sure it is a VxVM device group
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			dgtype=$(scsetup_get_devicegroup_type ${dgname})
			if [[ -z "${dgtype}" ]] ||
			    [[ "${dgtype}" != "${SCSETUP_DG_VXVM_LOOKUP}" ]]; then
				printf "$(gettext '\"%s\" is not a %s device group.')\n\n\a" "${dgname}" "${SCSETUP_DG_VXVM_LOOKUP}"
				continue
			fi
		fi

		# Get the nodelist
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi
		fi

		# Get the nodename
		while true
		do
			answer=$(scsetup_prompt_nodename "${nodelist}" "$(gettext 'Name of the node to add to this group?')") || return 1

			# Make sure it is not already there
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				list="$(scsetup_get_devicegroup_nodes ${dgname})"
				for node in ${list}
				do
					if [[ "${answer}" = "${node}" ]]; then
						printf "$(gettext '\"%s\" is already part of this group.')\n\n\a" "${answer}"
						continue 2
					fi
				done
			fi

			# Done
			break
		done

		# Okay
		nodename=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -D type=${SCSETUP_DG_VXVM_SET},name=${dgname},nodelist=${nodename}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_devicegroups_rmnodevxvm() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Remove a node from a VxVM device group.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_devicegroups_rmnodevxvm()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Remove a Node from a VxVM Device Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		VERITAS Volume Manager disk groups are always managed by
		the cluster as cluster device groups.  This option is
		used to remove a node from an already existing
		VxVM cluster device group.
	')"

	integer found
	typeset nodelist
	typeset nodename
	typeset node
	typeset list
	typeset dgname
	typeset dgtype
	typeset answer

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		#Initialize
		nodelist=

		# Get the name of the device group
		answer=$(sc_prompt "$(gettext 'Name of the VxVM device group from which you want to remove a node?')") || return 1
		dgname=${answer}

		# Make sure it is a VxVM device group
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			dgtype=$(scsetup_get_devicegroup_type ${dgname})
			if [[ -z "${dgtype}" ]] ||
			    [[ "${dgtype}" != "${SCSETUP_DG_VXVM_LOOKUP}" ]]; then
				printf "$(gettext '\"%s\" is not a %s device group.')\n\n\a" "${dgname}" "${SCSETUP_DG_VXVM_LOOKUP}"
				continue
			fi
		fi

		# Get the dg nodelist
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			nodelist="$(scsetup_get_devicegroup_nodes ${dgname})"
		fi

		# Get the nodename
		while true
		do
			answer=$(sc_prompt "$(gettext 'Name of the node to remove from this group?')") || return 1

			# Make sure the node is in the list
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
				list="$(scsetup_get_devicegroup_nodes ${dgname})"
				let found=0
				for node in ${list}
				do
					if [[ "${answer}" = "${node}" ]]; then
						let found=1
						break
					fi
				done
				if [[ ${found} -ne 1 ]]; then
					printf "$(gettext '\"%s\" is not a part of this group.')\n\n\a" "${answer}"
					continue
				fi
			fi

			# Done
			break
		done

		# Okay
		nodename=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -D name=${dgname},nodelist=${nodename}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_devicegroups_changeprops() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Change the preference and/or failback properties of a device group.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_devicegroups_changeprops()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Change Key Properties of a Device Group <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to change the \"preferenced\" and/or
		\"failback\" properties of a device group.
	')"
	typeset sctxt_p2="$(gettext '
		The scheme for establishing the primary ownership of a
		device group is based on the setting of a special
		ownership preference attribute.  If the attribute is
		not set, the primary owner of an otherwise unowned
		device group is the first node which attempts to access
		a disk in that group. However, if this attribute is
		set, you must specify the preferred order in which
		nodes will attempt to establish ownership.
	')"
	typeset sctxt_p3="$(gettext '
		If you disable the \"preferenced\" attribute, then the
		\"failback\" attribute is also automatically disabled.
		However, if you attempt to enable or re-enable the
		\"preferenced\" attribute, you will have the choice
		of enabling or disabling the \"failback\" attribute.
	')"
	typeset sctxt_p4="$(gettext '
		Note that if the \"preferenced\" attribute is either
		enabled or re-enabled that you will be required to
		re-establish the order of nodes in the primary ownership
		preference list.
	')"
	sctxt_p1_list="$(gettext '
		Please list the order in which nodes should attempt
		to establish ownership of the group.
	')"
	sctxt_p2_list="$(gettext '
		List one node name per line:
	')"

	typeset dgname
	typeset dgtype
	typeset dg_nodelist
	typeset preferenced
	typeset failback

	integer found
	integer count
	integer listcount
	typeset nodename
	typeset node
	typeset list
	typeset foo
	typeset answer
	typeset answers

	#
	# Print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"
		sc_print_para "${sctxt_p3}"
		sc_print_para "${sctxt_p4}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		#Initialize
		dg_nodelist=
		preferenced=
		failback=

		# Get the name of the device group
		answer=$(sc_prompt "$(gettext 'Name of the device group you want to change?')") || return 1
		dgname=${answer}

		# Make sure it is a known device group
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			dgtype=$(scsetup_get_devicegroup_type ${dgname})
			if [[ -z "${dgtype}" ]]; then
				printf "$(gettext '\"%s\" is not a known device group.')\n\n\a" "${dgname}"
				continue
			fi
		fi

		# Disable "preferenced"?
		answer=$(sc_prompt_yesno "$(gettext 'Do you want to disable the \"preferenced\" attribute?')") || return 1
		if [[ "${answer}" = "yes" ]]; then
			preferenced="false"
			failback="disabled"
		fi

		# Disable "failback"?
		if [[ -z "${preferenced}" ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'Do you just want to disable \"failback\"?')") || return 1
			if [[ "${answer}" = "yes" ]]; then
				failback="disabled"
			fi
		fi

		# Enable "preferenced"?
		if [[ -z "${preferenced}" ]] && [[ -z "${failback}" ]]; then
			answer=$(sc_prompt_yesno "$(gettext 'Do you want to enable the \"preferenced\" attribute?')") || return 1
			if [[ "${answer}" = "yes" ]]; then
				preferenced="true"
			else
				sc_print_prompt "\n$(gettext 'Type ENTER to return to the menu:')"
				read
				echo
				return 1
			fi
		fi

		# Establish list of nodes currently in device group
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			list="$(scsetup_get_devicegroup_nodes ${dgname})"
			if [[ -z "${list}" ]]; then
				printf "$(gettext 'Unable to establish the list of nodes for this device group.')\n\n\a"
				sc_print_pause
				return 1
			fi
		fi

		# If "preferenced" is true, get the nodelist and "failback"
		if [[ "${preferenced}" = "true" ]]; then

			# Change the preference order?
			sc_print_para "$(gettext 'Consider the following node preference order for this group:')"
			dg_nodelist="${list}"
			for node in ${list}
			do
				printf "\t${node}\n"
			done
			echo
			answer=$(sc_prompt_yesno "$(gettext 'Do you want to change it?')" "${NO}") || return 1

			# Yes, change the order
			if [[ "${answer}" = "yes" ]]; then
				dg_nodelist=
			fi
			let listcount=$(set -- ${list}; echo $#)
			while [[ -z "${dg_nodelist}" ]]
			do
				# Initialize
				let count=0
				answers=

				# Prompt
				sc_print_para "${sctxt_p1_list}"
				sc_print_para "${sctxt_p2_list}"

				# Get the new order
				while [[ ${count} -lt ${listcount} ]]
				do
					answer=$(sc_prompt "$(gettext 'Node name:')" "" "nonl") || return 1

					# Must be in our list
					let found=0
					for node in ${list}
					do
						if [[ "${answer}" = "${node}" ]]; then
							let found=1
							break
						fi
					done

					# Make sure we found it
					if [[ ${found} -eq 0 ]]; then
						echo
						printf "$(gettext 'Node is not part of this device group.')\n\n\a"
						continue
					fi

					# Make sure it is not a duplicate
					for node in ${answers}
					do
						if [[ "${answer}" = "${node}" ]]; then
							echo
							printf "$(gettext '\"%s\" already entered.')\n\n\a" "${answer}"
							continue 2
						fi
					done

					# Okay, add it to list of answers
					answers="${answers} ${answer}"

					# Next
					((count += 1))
				done

				# Verify that the list is correct
				echo
				sc_print_para "$(gettext 'This is the new preference order:')"
				for node in ${answers}
				do
					printf "\t${node}\n"
				done
				echo
				answer=$(sc_prompt_yesno "$(gettext 'Is it correct?')" "${YES}") || return 1
				if [[ "${answer}" != "yes" ]]; then
					continue
				fi

				# Set the dg nodelist
				dg_nodelist="${answers}"

				# Done
				break
			done

			# Failback?
			failback=
			answer=$(sc_prompt_yesno "$(gettext 'Enable \"failback\" for this disk device group?')" "${NO}") || return 1
			if [[ "${answer}" = "yes" ]]; then
				failback="enabled"
			else
				failback="disabled"
			fi
		fi

		# If the dg_nodelist is not set, set to the default
		if [[ -z "${dg_nodelist}" ]]; then
			dg_nodelist="${list}"
		fi

		# Reformat the dg_nodelist to give to scconf
		foo="${dg_nodelist}"
		dg_nodelist=
		for node in ${foo}
		do
			if [[ -n "${dg_nodelist}" ]]; then
				dg_nodelist="${dg_nodelist}:"
			fi
			dg_nodelist="${dg_nodelist}${node}"
		done

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -D name=${dgname}"

		# Nodelist?
		if [[ -n "${dg_nodelist}" ]]; then
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},nodelist=${dg_nodelist}"
		fi

		# Preferenced?
		if [[ -n "${preferenced}" ]]; then
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},preferenced=${preferenced}"
		fi

		# Failback?
		if [[ -n "${failback}" ]]; then
			SCSETUP_DO_CMDSET[0]="${SCSETUP_DO_CMDSET[0]},failback=${failback}"
		fi

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break

	done

	return 0
}

#####################################################
#
# scsetup_help_devicegroups_menu()
#
#	Print help information from the device groups menu.
#	This is the same help information as is printed
#	from the MAIN help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_devicegroups_menu()
{
	clear
	scsetup_help_main_devicegroups
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_devicegroups_menuoption()
#
#	Print the device groups menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_devicegroups_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** Device Groups Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Register a VxVM disk group as a device group')"
	typeset sctxt_option_002="$(gettext 'Synchronize volume information for a VxVM device group')"
	typeset sctxt_option_003="$(gettext 'Unregister a VxVM device group')"
	typeset sctxt_option_004="$(gettext 'Add a node to a VxVM device group')"
	typeset sctxt_option_005="$(gettext 'Remove a node from a VxVM device group')"
	typeset sctxt_option_006="$(gettext 'Change key properties of a device group')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
		"S+0+3+${sctxt_option_003}" \
		"S+0+4+${sctxt_option_004}" \
		"S+0+5+${sctxt_option_005}" \
		"S+0+6+${sctxt_option_006}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_devicegroups()
#
#	Device groups menu
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_devicegroups()
{
	# Loop around the devicegroups menu
	while true
	do
		case $(scsetup_get_devicegroups_menuoption) in
		'1')    scsetup_menu_devicegroups_addvxvm ;;
		'2')	scsetup_menu_devicegroups_syncvxvm ;;
		'3')    scsetup_menu_devicegroups_rmvxvm ;;
		'4')    scsetup_menu_devicegroups_addnodevxvm ;;
		'5')    scsetup_menu_devicegroups_rmnodevxvm ;;
		'6')    scsetup_menu_devicegroups_changeprops ;;
		'?')    scsetup_help_devicegroups_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Authentication of nodes able to install into the cluster
##
#####################################################
#####################################################

#####################################################
#
# scsetup_menu_auth_alloff() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen or print title.
#
#	Prevent any new machines from installing into the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_auth_alloff()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Prevent Any New Machines from Installing into the Cluster <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to prevent any new machines from
		installing themselves into the cluster.  It does this
		by setting an attribute which tells the processes
		responsible for helping new machines to add themselves
		to the cluster to ignore all such add requests coming
		in over the public network.
	')"

	#
	# Clear screen and print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
	fi

	# Print help
	sc_print_para "${sctxt_p1}"

	#
	# Set up the command set
	#

	# Initialize
	set -A SCSETUP_DO_CMDSET

	# Add the command
	SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -T node=."

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	return 0
}

#####################################################
#
# scsetup_menu_auth_allon() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen or print title.
#
#	Allow any machine to install into the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_auth_allon()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Permit Any Machine to Install itself into the Cluster <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to permit any machine to install
		itself into the cluster.  It does this by completely
		clearing the list of machines recognized as being
		permitted to install themselves into the cluster.  An
		empty list means that any node can add itself.  When
		the processes responsible for helping new machines to
		add themselves to the cluster confirm that the list is
		empty, they attempt to honor all such add requests
		coming in over the public network.
	')"
	typeset sctxt_p2="$(gettext '
		Of course, any machine attempting to install itself as
		a cluster node must first have all of the necessary
		software and hardware correctly installed and configured,
		including a good physical connection to the private cluster
		interconnect.  Refer to the Sun Cluster installation
		documentation and the scinstall(1M) man page for more
		information regarding installation and adding new machines
		to the cluster.
	')"

	#
	# Clear screen and print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
	fi

	# Print help
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"

	#
	# Set up the command set
	#

	# Initialize
	set -A SCSETUP_DO_CMDSET

	# Add the command
	SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -r -T all"

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	return 0
}

#####################################################
#
# scsetup_menu_auth_addnode() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Add a machine to the list of nodes permitted to install into
#	the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_auth_addnode()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Specify a Machine which may Install itself into the Cluster <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to permit a given machine to
		install itself into the cluster.  It does this by
		adding the node name that you give to the list of nodes
		recognized as being permitted to install themselves
		into the cluster.
	')"
	typeset sctxt_p2="$(gettext '
		Of course, any machine attempting to install itself as
		a cluster node must first have all of the necessary
		software and hardware correctly installed and configured,
		including a good physical connection to the private cluster
		interconnect.  Refer to the Sun Cluster installation
		documentation and the scinstall(1M) man page for more
		information regarding installation and adding new machines
		to the cluster.
	')"

	typeset addhost
	typeset answer

	#
	# Clear screen and print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"
		sc_print_para "${sctxt_p2}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the name of the machine
		answer=$(sc_prompt "$(gettext 'Name of the host to add to the list of recognized machines?')") || return 1
		addhost=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -a -T node=${addhost}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_menu_auth_unix() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen or print title.
#
#	Use standard UNIX authentication methods for install.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_auth_unix()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Use standard UNIX Authentication <<<
	')"
	typeset sctxt_p1="$(gettext '
		To be added as a cluster node, a machine must appear in
		the list of hosts that are permitted to install themselves
		into cluster configuration.  If this list is empty, any
		machine may add itself to the cluster configuration.
	')"
	typeset sctxt_p2="$(gettext '
		The identity of machines contacting the cluster over
		the public network for installation purposes may be
		confirmed using either standard UNIX or the more secure
		Diffie-Hellman, or DES, authentication.  However, DES
		authentication is not usually considered necessary for
		this purpose, since machines which are not physically
		connected to the cluster interconnect will never be
		able to actually join the cluster membership anyway.
	')"
	typeset sctxt_p3="$(gettext '
		Standard UNIX authentication is the default.  This option
		is used to restore this default.
	')"

	#
	# Clear screen and print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
	fi

	# Print help
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"
	sc_print_para "${sctxt_p3}"

	#
	# Set up the command set
	#

	# Initialize
	set -A SCSETUP_DO_CMDSET

	# Add the command
	SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -T authtype=unix"

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	return 0
}


#####################################################
#
# scsetup_menu_auth_des() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen or print title.
#
#	Use DES authentication methods for install.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_auth_des()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Use Diffie-Hellman Authentication <<<
	')"
	typeset sctxt_p1="$(gettext '
		To be added as a cluster node, a machine must appear in
		the list of hosts that are permitted to install themselves
		into cluster configuration.  If this list is empty, any
		machine may add itself to the cluster configuration.
	')"
	typeset sctxt_p2="$(gettext '
		The identity of machines contacting the cluster over
		the public network for installation purposes may be
		confirmed using either standard UNIX or the more secure
		Diffie-Hellman, or DES, authentication.  However, DES
		authentication is not usually considered necessary for
		this purpose, since machines which are not physically
		connected to the private cluster interconnect will
		never be able to actually join the cluster membership
		anyway.
	')"
	typeset sctxt_p3="$(gettext '
		This option is used to select DES authentication methods
		for use during node installation.  Remember that if
		DES authentication is selected, you must also configure
		all necessary encryption keys before a node can join
		(see keyserv(1M), publickey(4)).
	')"

	#
	# Clear screen and print title
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
	fi

	# Print help
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"
	sc_print_para "${sctxt_p3}"

	#
	# Set up the command set
	#

	# Initialize
	set -A SCSETUP_DO_CMDSET

	# Add the command
	SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -T authtype=des"

	# Attempt to issue the command
	scsetup_do_cmdset || return 1

	return 0
}

#####################################################
#
# scsetup_help_auth_menu()
#
#	Print help information from the auth menu.
#	This is the same help information as is printed
#	from the MAIN help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_auth_menu()
{
	clear
	scsetup_help_main_auth
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_auth_menuoption()
#
#	Print the authentication menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_auth_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** New Nodes Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Prevent any new machines from being added to the cluster')"
	typeset sctxt_option_002="$(gettext 'Permit any machine to add itself to the cluster')"
	typeset sctxt_option_003="$(gettext 'Specify the name of a machine which may add itself')"
	typeset sctxt_option_004="$(gettext 'Use standard UNIX authentication')"
	typeset sctxt_option_005="$(gettext 'Use Diffie-Hellman authentication')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"S+0+2+${sctxt_option_002}" \
		"S+0+3+${sctxt_option_003}" \
		"S+0+4+${sctxt_option_004}" \
		"S+0+5+${sctxt_option_005}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_auth()
#
#	Authentication menu
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_auth()
{
	# Loop around the auth menu
	while true
	do
		case $(scsetup_get_auth_menuoption) in
		'1')    scsetup_menu_auth_alloff ;;
		'2')    scsetup_menu_auth_allon ;;
		'3')    scsetup_menu_auth_addnode ;;
		'4')    scsetup_menu_auth_unix ;;
		'5')    scsetup_menu_auth_des ;;
		'?')    scsetup_help_auth_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Other cluster-wide options
##
#####################################################
#####################################################

#####################################################
#
# scsetup_menu_other_clustername() [nohelp]
#
#	nohelp		- if this flag is given, do not
#				clear screen, print title, print help,
#				or ask for confirmation to continue.
#
#	Change the the name of the cluster.
#
#	Return:
#		zero		Completed
#		non-zero	Note completed
#
#####################################################
scsetup_menu_other_clustername()
{
	typeset nohelp=${1}

	typeset sctxt_title="$(gettext '
		>>> Changing the Name of the Cluster <<<
	')"
	typeset sctxt_p1="$(gettext '
		This option is used to change the name of the cluster.
	')"

	typeset answer
	typeset clustername

	#
	# Print help
	#
	if [[ -z "${nohelp}" ]]; then
		clear
		sc_print_title "${sctxt_title}"
		sc_print_para "${sctxt_p1}"

		# Okay to continue?
		scsetup_continue || return 1
	fi

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Get the new cluster name
		answer=$(sc_prompt "$(gettext 'What name do you want to assign to this cluster?')") || return 1
		clustername=${answer}

		#
		# Set up the command set
		#

		# Initialize
		set -A SCSETUP_DO_CMDSET

		# Add the command
		SCSETUP_DO_CMDSET[0]="${SC_SCCONF} -c -C cluster=${clustername}"

		# Attempt to issue the command
		scsetup_do_cmdset || return 1

		# Done
		break
	done

	return 0
}

#####################################################
#
# scsetup_help_other_menu()
#
#	Print help information from the other cluster props menu.
#	This is the same help information as is printed
#	from the MAIN help menu.  But, we ask for confirmation
#	before returning to the previous menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_help_other_menu()
{
	clear
	scsetup_help_main_other
	sc_prompt_pause

	return 0
}

#####################################################
#
# scsetup_get_other_menuoption()
#
#	Print the other cluster options menu, and return the selected option.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_other_menuoption()
{
	typeset sctxt_title_1="$(gettext '*** Other Cluster Properties Menu ***')"
	typeset sctxt_title_2="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_option_001="$(gettext 'Change the name of the cluster')"
	typeset sctxt_option_help="$(gettext 'Help')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	option=$(sc_get_menuoption \
		"T1+++${sctxt_title_1}" \
		"T2+++${sctxt_title_2}" \
		"S+0+1+${sctxt_option_001}" \
		"R+++" \
		"S+0+?+${sctxt_option_help}" \
		"S+0+q+${sctxt_option_return}" \
	)

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_menu_other()
#
#	Other cluster properties menu
#
#	This function always returns zero.
#
#####################################################
scsetup_menu_other()
{
	# Loop around
	while true
	do
		case $(scsetup_get_other_menuoption) in
		'1')    scsetup_menu_other_clustername ;;
		'?')    scsetup_help_other_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Main menu
##
#####################################################
#####################################################

#####################################################
#
# scsetup_get_main_menuoption() [help]
#
#	help	- if given, print the main help menu
#
#	Print the main menu, and return the selected option.
#	If the "help" option is given, the menu is processed
#	as the main help menu.
#
#	This function always returns zero.
#
#####################################################
scsetup_get_main_menuoption()
{
	typeset help=${1}

	typeset sctxt_title_1_main="$(gettext '*** Main Menu ***')"
	typeset sctxt_title_2_main="$(gettext 'Please select from one of the following options:')"
	typeset sctxt_title_1_help="$(gettext '*** Main Menu Help ***')"
	typeset sctxt_title_2_help="$(gettext 'Please select from one of the following HELP options:')"
	typeset sctxt_option_001="$(gettext 'Quorum')"
	typeset sctxt_option_002="$(gettext 'Resource groups')"
	typeset sctxt_option_003="$(gettext 'Cluster interconnect')"
	typeset sctxt_option_004="$(gettext 'Device groups and volumes')"
	typeset sctxt_option_005="$(gettext 'Private hostnames')"
	typeset sctxt_option_006="$(gettext 'New nodes')"
	typeset sctxt_option_007="$(gettext 'Other cluster properties')"
	typeset sctxt_option_help="$(gettext 'Help with menu options')"
	typeset sctxt_option_exit="$(gettext 'Quit')"
	typeset sctxt_option_return="$(gettext 'Return to the Main Menu')"

	if [[ -n "${help}" ]]; then
		option=$(sc_get_menuoption \
			"T1+++${sctxt_title_1_help}" \
			"T2+++${sctxt_title_2_help}" \
			"S+0+1+${sctxt_option_001}" \
			"S+0+2+${sctxt_option_002}" \
			"S+0+3+${sctxt_option_003}" \
			"S+0+4+${sctxt_option_004}" \
			"S+0+5+${sctxt_option_005}" \
			"S+0+6+${sctxt_option_006}" \
			"S+0+7+${sctxt_option_007}" \
			"R+++" \
			"S+0+q+${sctxt_option_return}" \
		)
	else
		option=$(sc_get_menuoption \
			"T1+++${sctxt_title_1_main}" \
			"T2+++${sctxt_title_2_main}" \
			"S+0+1+${sctxt_option_001}" \
			"S+0+2+${sctxt_option_002}" \
			"S+0+3+${sctxt_option_003}" \
			"S+0+4+${sctxt_option_004}" \
			"S+0+5+${sctxt_option_005}" \
			"S+0+6+${sctxt_option_006}" \
			"S+0+7+${sctxt_option_007}" \
			"R+++" \
			"S+0+?+${sctxt_option_help}" \
			"S+0+q+${sctxt_option_exit}" \
		)
	fi

	echo "${option}"

	return 0
}

#####################################################
#
# scsetup_help_main_menu 
#
#	Print help information for the main menu.
#
#####################################################
scsetup_help_main_menu()
{
	while true
	do
		case $(scsetup_get_main_menuoption help) in
		'1')	scsetup_help_main_quorum ;;
		'2')	scsetup_help_main_rgm ;;
		'3')	scsetup_help_main_transport ;;
		'4')	scsetup_help_main_devicegroups ;;
		'5')	scsetup_help_main_privatehosts ;;
		'6')	scsetup_help_main_auth ;;
		'7')	scsetup_help_main_other ;;
		'q')	break ;;
		esac

		echo
		sc_print_prompt "$(gettext 'Type ENTER to return to the previous menu:')" || return 1
		read
		echo
	done

	return 0
}

#####################################################
#
# scsetup_menu()
#
#	Menu driven scsetup.
#
#	This function always returns zero.
#
#####################################################
scsetup_menu()
{
	# Loop around the main menu
	while true
	do
		case $(scsetup_get_main_menuoption) in
		'1')    scsetup_menu_quorum ;;
		'2')	scsetup_menu_rgm ;;
		'3')    scsetup_menu_transport ;;
		'4')    scsetup_menu_devicegroups ;;
		'5')    scsetup_menu_privatehosts ;;
		'6')    scsetup_menu_auth ;;
		'7')    scsetup_menu_other ;;
		'?')    scsetup_help_main_menu ;;
		'q')    break ;;
                esac 
	done

	return 0
}

#####################################################
#####################################################
##
## Initialize cluster
##
#####################################################
#####################################################

#####################################################
#
# scsetup_initcluster()
#
#	The purpose of this function is to provide an interactive
#	dialog to the user at initial install time for setting up
#	quorum, resetting installmode, etc.
#
#	This function should only be called if installmode is enabled.
#
#	Return:
#		zero 		Success
#		non-zero	Failure
#
#####################################################
scsetup_initcluster()
{
	typeset sctxt_title="$(gettext '
		>>> Initial Cluster Setup <<<
	')"
	typeset sctxt_p1="$(gettext '
		This program has detected that the cluster \"installmode\"
		attribute is still enabled.  As such, certain initial
		cluster setup steps will be performed at this time.
		This includes adding any necessary quorum devices,
		then resetting both the quorum vote counts and the
		\"installmode\" property.
	')"
	typeset sctxt_p2="$(gettext '
		Please do not proceed if any additional nodes have yet
		to join the cluster.
	')"
	typeset sctxt_p1_qdev="$(gettext '
		Dual-ported SCSI-2 disks may be used as quorum devices
		in two-node clusters.  However, clusters with more than
		two nodes require that SCSI-3 PGR disks be used for all
		disks with more than two node-to-disk paths.  You can
		use a disk containing user data or one that is a member
		of a device group as a quorum device.
	')"
	typeset sctxt_p2_qdev="$(gettext '
		Each quorum disk must be connected to at least
		two nodes.  Please refer to the Sun Cluster documentation
		for more information on supported quorum device topologies.
	')"
	typeset sctxt_p1_reset="$(gettext '
		Once the \"installmode\" property has been reset,
		this program will skip \"Initial Cluster Setup\"
		each time it is run again in the future.  However,
		quorum devices can always be added to the cluster
		using the regular menu options.  Resetting this
		property fully activates quorum settings and is
		necessary for the normal and safe operation of
		the cluster.
	')"
	typeset sctxt_reset_cmd1="${SC_SCCONF} -c -q reset"
	typeset sctxt_reset_cmd2="${SC_SCCONF} -a -T node=."

	integer nodecount
	integer qdevcount
	integer status
	typeset nodelist
	typeset qdevlist
	typeset answer

	#
	# Print help
	#
	clear
	sc_print_title "${sctxt_title}"
	sc_print_para "${sctxt_p1}"
	sc_print_para "${sctxt_p2}"

	# Okay to continue?
	scsetup_continue || return 1

	# Loop until done or Ctrl-D is typed
	while true
	do
		# Initialize
		let nodecount=0
		let qdevcount=0
		nodelist=
		qdevlist=

		# Get nodelist and nodecount
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Get nodelist
			nodelist="$(scsetup_get_nodelist)"

			# Make sure we have a nodelist
			if [[ -z "${nodelist}" ]]; then
				printf "$(gettext 'Unable to establish the list of cluster nodes.')\n\n\a"
				sc_prompt_pause
				return 1
			fi

			# Set node count
			let nodecount=$(set -- ${nodelist}; echo $#)
		else
			# We must be running in DEBUG mode
			while true
			do
				answer=$(sc_prompt "$(gettext 'DEBUG:  How  many nodes are in the cluster?')") || return 1

				# In range?
				if [[ $(expr ${answer} : '[0-9]*') -ne $(expr ${answer} : '.*') ]] ||
				    [[ ${answer} -lt 1 ]] ||
				    [[ ${answer} -gt ${SC_MAXNODEID} ]]; then
					printf "\a"
				else
					break
				fi
			done

			# Set nodecount
			let nodecount=${answer}
		fi

		# Make sure that we have at least two nodes
		if [[ ${nodecount} -lt 2 ]]; then
			printf "$(gettext 'The cluster must have at least two nodes before running %s.')\n\n\a" "${PROG}"
			return 1
		fi

		# Add any needed quorum devices
		while true
		do
			# Do you want to add any quorum devices?
			answer=$(sc_prompt_yesno "$(gettext 'Do you want to add any quorum disks?')" "${YES}") || return 1

			# Okay, add device
			if [[ "${answer}" = "yes" ]]; then

				# Print help
				sc_print_para "${sctxt_p1_qdev}"
				sc_print_para "${sctxt_p2_qdev}"

				# Add it
				while true
				do
					# Try again?
					scsetup_menu_quorum_addev "nohelp"
					if [[ $? -ne 0 ]]; then
						answer=$(sc_prompt_yesno "$(gettext 'Do you want to try again?')") || return 1
					else
						answer=$(sc_prompt_yesno "$(gettext 'Do you want to add another quorum disk?')") || return 1
						# If DEBUG, add to qdevcount
						if [[ ${SCSETUP_ISMEMBER} -eq 0 ]]; then
							((qdevcount += 1))
						fi
					fi
					if [[ "${answer}" = "no" ]]; then
						break
					fi
				done
			fi

			#
			# Get qdevlist and qdevcount
			# Note that if we are not a cluster member,
			# we must be in DEBUG mode.  In DEBUG, the qdevcount
			# was alredy adjusted for us on successful return
			# from scsetup_menu_quorum_addev().
			#
			if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

				# Get qdevlist
				qdevlist="$(scsetup_get_qdevlist)"

				# Set qdevcount count
				let qdevcount=$(set -- ${qdevlist}; echo $#)
			fi

			# All two node clusters must have at least one qdev
			if [[ ${nodecount} -eq 2 ]] &&
			    [[ ${qdevcount} -lt 1 ]]; then
				printf "$(gettext 'All two-node clusters must have at least one quorum disk.')\n\n\a"
				return 1
			fi

			# Done
			break
		done

		# Reset installmode
		sc_print_para "${sctxt_p1_reset}"
		answer=$(sc_prompt_yesno "$(gettext 'Is it okay to reset \"installmode\"?')" "${YES}") || return 1
		if [[ "${answer}" = "yes" ]] &&
		    [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then

			# Run the commands
			echo
			echo "${sctxt_reset_cmd1}"
			${sctxt_reset_cmd1} 2>&1
			status=$?
			if [[ ${status} -eq 0 ]]; then
				echo "${sctxt_reset_cmd2}"
				${sctxt_reset_cmd2} 2>&1
				status=$?
			fi

			# Failed
			if [[ ${status} -ne 0 ]]; then
				echo
				printf "$(gettext 'Command failed.')\n\n\a"
				return 1
			fi

			# Log it
			if [[ -n "${SCSETUP_CMD_LOG}" ]]; then
				echo "${sctxt_reset_cmd1}" >>${SCSETUP_CMD_LOG}
				echo "${sctxt_reset_cmd2}" >>${SCSETUP_CMD_LOG}
			fi

			# Success message
			echo
			sc_print_para "$(gettext 'Cluster initialization is complete.')"

			# Pause
			echo
			sc_print_prompt "$(gettext 'Type ENTER to proceed to the main menu:')" || return 1
			read
			echo

		# If no reset to installmode, return error
		elif [[ "${answer}" = "no" ]]; then
			return 1
		fi

		# Done
		break
	done

	return 0
}

#####################################################
#####################################################
##
## Main
##
#####################################################
#####################################################
main()
{
	typeset c
	integer isinstallmode=0
	integer result

	# load common functions
	loadlib ${SC_SCADMINLIBDIR}/${SC_LIB_SC} ${SC_LOADED_COMMON} || return 1
	let SC_LOADED_COMMON=1

	# must be root
	verify_isroot || return 1

	# Make sure that we are a member of the cluster
        if [[ -x /usr/sbin/clinfo ]]; then
                eval /usr/sbin/clinfo >/dev/null 2>&1
                if [[ $? -eq 0 ]]; then
			let SCSETUP_ISMEMBER=1
		elif [[ -z "${SC_DEBUG}" ]]; then
			printf "$(gettext '%s:  This node is not currently in the cluster')\n" "${PROG}" >&2
			return 1
		fi
	fi

	# If installmode is enabled, we do not want to do menu driven interface
	let isinstallmode=0
	if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
		let isinstallmode=$(scsetup_get_installmode)
	fi

	# Get command line options, if there are any.
	while getopts f: c 2>/dev/null
	do
		case ${c} in
		f)	# Log file

			# Make sure the log file is not already set
			if [[ -n "${SCSETUP_CMD_LOG}" ]]; then
				print_usage
				return 1
			fi

			# Set the logfile
			SCSETUP_CMD_LOG=${OPTARG}

			# Add heading for this session to the log file
			if [[ -s "${SCSETUP_CMD_LOG}" ]]; then
				printf "\n" >>${SCSETUP_CMD_LOG} 2>/dev/null
			fi
			printf "#\n" >>${SCSETUP_CMD_LOG} 2>/dev/null
			if [[ $? -ne 0 ]]; then
				printf "$(gettext '%s:  Unable to write to the command log.')\n" "${PROG}" >&2
				return 1
			fi
			printf "# %s - %s\n" "${PROG}" "$(date)" >>${SCSETUP_CMD_LOG}
			printf "#\n" >>${SCSETUP_CMD_LOG}
			;;

		\?)	# bad option
			print_usage
			return 1
			;;

		*)	# we missed something!
			printf "$(gettext '%s:  Internal error checking usage')\n" "${PROG}" >&2
			return 1
			;;
		esac
	done
			

	# If isinstallmode, initialize cluster before proceeding to menu
	if [[ ${isinstallmode} -eq 1 ]] || [[ "${SC_DEBUG}" = "2" ]]; then
		# Init cluster
		scsetup_initcluster || return 1

		# Make sure isinstallmode was cleared
		let isinstallmode=0
		if [[ ${SCSETUP_ISMEMBER} -eq 1 ]]; then
			let isinstallmode=$(scsetup_get_installmode)
		fi

		# If isinstallmode is not set, do not proceed to menu
		if [[ ${isinstallmode} -eq 1 ]]; then
			return 0
		fi
	fi

	# Go to the menu
	scsetup_menu

	# Return
	return 0
}

	# Run it
	main $*

	# Done
	exit $?
