#! /usr/bin/ksh -p
#
# ident   "@(#)smsconfig.ksh 1.111     03/05/20 SMI"
#
# Copyright (c) 2000-2002 by Sun Microsystems, Inc.
# All rights reserved.  Use is subject to license terms.
#

#
# Setup for Internationalization
#
# begin, 4633179/ 4634829
export TEXTDOMAIN="SUNW_ESSMS_CMD"
export TEXTDOMAINDIR="/opt/SUNWSMS/lib/locale"

# I18N note:
# If grepping output from commands, be sure to set the locale to "C" in a
# subshell.  Otherwise the output may be in another language (e.g., Japanese)
# and the command will fail.  E.g.,
# ( LANG=C;LC_ALL=C;export LANG LC_ALL;pkginfo -l SUNWSMSr 2>&1|grep VERSION )
# end, 4633179/ 4634829


#
# Process information
#
command=$(basename $0)
subcommand=${1}
ACTIVE_SMS_VERSION=""
MYPID=$$

PLATFORM_NAME="xc"
DEFMASK="255.255.255.0"
RESERVED_PLAT="starcat common"
SMS_BACKUP=""
OTHER_SC=0

#
# Directory and file locations
#
ROOT=
[[ -d $HOME/smsroot && -n ${SMSCONFIG_DEBUG} ]] && ROOT=$HOME/smsroot

export SMSOPT=${ROOT}/opt/SUNWSMS
export SMSETC=${ROOT}/etc/opt/SUNWSMS
export SMSVAR=${ROOT}/var/opt/SUNWSMS
export SMSCONFIGDIR=${SMSETC}/config

export ETCDIR=${ROOT}/etc

#
# SMS and system files
#
MANCONFIGFILENAME=MAN.cf
MANCONFIGFILE=${SMSCONFIGDIR}/$MANCONFIGFILENAME
# Trailing . in following definitions is significant
HOSTNAME_BASE=$ETCDIR/hostname.
HOSTNAME_BASE6=$ETCDIR/hostname6.
I1_IFCONFIG_IFACE=scman0
I2_IFCONFIG_IFACE=scman1
GROUPCONFIGFILENAME=".sms_groups"
GROUPCONFIGFILE=${SMSETC}/$GROUPCONFIGFILENAME
RHOSTSFILE=${ROOT}/.rhosts
ETCGROUPFILE=$ETCDIR/group
ETCHOSTSFILE=$ETCDIR/inet/hosts
ETCHOSTSFILE6=$ETCDIR/inet/ipnodes
ETCNETMASKS=$ETCDIR/inet/netmasks
NDD=/usr/sbin/ndd
LOCKDIR=${SMSVAR}/data
IFCONFIG=/usr/sbin/ifconfig
GETSCNUMPATH=${ROOT}/opt/SUNWSMS/lib/smsadmin/getscnum
SMS_ENV=${SMSETC}/startup/sms_env.sh

#
# Temporary files
#
ALLSMSTMPFILES="$TMPMANCONFIGFILE $TMPCMDS $TMPFOADDRS
	$TMPGROUPCONFIGFILE $TMPRHOSTSFILE $TMPSHOSTSFILE
	$FACL_DIR_LIST $FACL_FILE_LIST"
TMPMANCONFIGFILE=${ROOT}/tmp/${MANCONFIGFILENAME}.$$
TMPCMDS=${ROOT}/tmp/MANcmds$$.sh
TMPFOADDRS=${ROOT}/tmp/foaddrs.$$
TMPGROUPCONFIGFILE=${ROOT}/tmp/$GROUPCONFIGFILENAME.$$
TMPRHOSTSFILE=${ROOT}/tmp/.rhosts.$$
TMPSHOSTSFILE=${ROOT}/tmp/.shosts.$$
# FACL = file access control list feature
# FACL_TMP_DIR - where we keep the temporary files
FACL_TMP_DIR="${ROOT}/tmp"
# FACL_DIR_LIST - file containing the names of SMS directories for ACLs config
FACL_DIR_LIST="$FACL_TMP_DIR/facl_dir_list.$$.txt"
# FACL_FILE_LIST - file containing the names of SMS files for ACLs config
FACL_FILE_LIST="$FACL_TMP_DIR/facl_file_list.$$.txt"

#
# 4750572: sms startup fails to correctly determine
#          remote SC and requires .rhosts/.shosts
#
PRIVATE_REMOTEHOST=$SMSVAR/data/.remotesc


DEBUG=
[[ "$ROOT" != "" ]] && DEBUG=TRUE && gettext "DEBUG MODE\n" >&2


#
# Global variables for security
#
# 4508204: fomd shouldn't use R* services
#
sshPath="/usr/bin/ssh"
scpPath="/usr/bin/scp"
DEBUG_ON=0
PROMPT_USER=10
defaultSSH=""
remoteSCI2HostIp=""
#
# Default ssh path list
#
# 4752041: fomd should include searching /usr/local/bin for
#          ssh and scp binaries
#
POSSIBLE_SSH_LOC="/opt/SUNWSMS/SMS/bin/ssh /usr/bin/ssh /opt/OBSDssh/bin/ssh "
POSSIBLE_SSH_LOC=$POSSIBLE_SSH_LOC"/usr/local/bin/ssh /bin/ssh"
set -A defaultSSHPath $POSSIBLE_SSH_LOC
SSH_LINK="/opt/SUNWSMS/SMS/bin/ssh"
SCP_LINK="/opt/SUNWSMS/SMS/bin/scp"
SMS_SSH_LOC="/opt/SUNWSMS/SMS/bin"
USER_ANSWER=""
useSecureShell=0

#############################################################################
#
# usage()
#
# Display usage message for command $command
#
#############################################################################
usage()
{
	case $command in

	smsbackup)
		printf "$(gettext '\Back up the SMS environment')\n" 1>&2
		printf "$(gettext 'Usage:\n   %s directory_name')\n" $command 1>&2
		printf "$(gettext '   %s -h')\n\n" $command 1>&2
		;;

	smsrestore)
		printf "$(gettext '\Restore up the SMS environment')\n" 1>&2
		printf "$(gettext 'Usage:\n   %s filename')\n" $command 1>&2
		printf "$(gettext '   %s -h')\n\n" $command 1>&2
		;;

	smsversion)
		printf "$(gettext '\Change the active SMS version')\n" 1>&2
		printf "$(gettext 'Usage:\n   %s new_version')\n" $command 1>&2
                printf "$(gettext "   %s -t")\n" $command 1>&2
		printf "$(gettext '   %s -h')\n\n" $command 1>&2
		;;

	smsmanopt)
		# TRANSLATION_NOTE: Do not translate domain_id, sc, or netmask
		printf "$(gettext '   %s -m I1 [ <domain_id> | sc | netmask ]')\n" $command 1>&2
		printf "$(gettext '   %s -m I2 [ sc0 | sc1 | netmask ]')\n" $command 1>&2
		printf "$(gettext '   %s -m L')\n" $command 1>&2
		;;

	*)
		printf "$(gettext '\nConfigure the SMS environment')\n" 1>&2
		printf "$(gettext 'Usage:\n   %s -m')\n" $command 1>&2
		printf "$(gettext '   %s -m I1 [ <domain_id> | sc | netmask ]')\n" $command 1>&2
		printf "$(gettext '   %s -m I2 [ sc0 | sc1 | netmask ]')\n" $command 1>&2
		printf "$(gettext '   %s -m L')\n" $command 1>&2
		printf "$(gettext '   %s -g')\n" $command 1>&2
		printf "$(gettext '   %s -a -u <username> -G <platform_role> platform')\n" \
						$command 1>&2
		printf "$(gettext '   %s -r -u <username> -G <platform_role> platform')\n" \
						$command 1>&2
		printf "$(gettext '   %s -a -u <username> -G <domain_role> <domain_id>')\n" \
						$command 1>&2
		printf "$(gettext '   %s -r -u <username> -G <domain_role> <domain_id>')\n" \
						$command 1>&2
		printf "$(gettext '   %s -s <security_option> ')\n" $command 1>&2
		printf "$(gettext '   %s -l <domain_id>')\n" $command 1>&2
		printf "$(gettext '   %s -l platform')\n" $command 1>&2
		printf "$(gettext '   %s -v')\n" $command 1>&2
		printf "$(gettext '   %s -h')\n" $command 1>&2
		;;
	esac

	return 0
}


#############################################################################
#
# fatal()
# fatal_nounlock()
#
# Generic routine for fatal errors.  Displays error message ($*) and exit 2.
# Normally you call fatal(), not fatal_nounlock().
#
# Note: fatal() parameters are the same format as printf():
# format string followed by zero or more parameters.
#
# $1		- Printf format string (already gettext-processed).
# $2 . . .	- Zero or more optional printf parameters
#
#############################################################################
fatal_nounlock()
{
	typeset fmt="$1"
	shift
	# Print message and log file name:
	printf "$(gettext "ERROR: ")""$fmt\n" "$@" | fmt >&2

	[[ -n "$DEBUG" ]] && yes_or_no $(gettext "Continue? ") >&2 && return 0

	if [[ -n "$LOG_FILE" ]] ; then
		printf "$(gettext "ERROR: ")""$fmt\n" "$@" >> ${LOG_FILE}
		# TRANSLATION_NOTE: %s is the localized date string
		date >> ${LOG_FILE}

		# TRANSLATION_NOTE - %s is the log file name
		printf "$(gettext 'Log file is %s.  Exiting.\\n')" ${LOG_FILE} \
			| fmt | tee -a ${LOG_FILE} >&2
	else
		gettext 'Exiting.\n'
	fi

	exit 2
}


fatal()
{
	exclusive_lock UNLOCK smsconfig
	fatal_nounlock "$@"
	# Should not return
}


#############################################################################
#
# getuid
#
# Returns the uid (integer) for the process on stdout.
#
#############################################################################
getuid()
{
	typeset uid=$(id)
	eval ${uid%%\(*} # chop everything after "(" and execute it to set $uid
	print "$uid"
}


#############################################################################
#
# getpid
#
# Returns the process id(s) (integer) for a specific process.  May return
# more than one.
#
# $1 - name of process to look for (must be short name as in ps)
# $2 - owner of process (defaults to root)
#
#############################################################################
getpid()
{
	ps -u ${2:-root} | awk '{ if ($4 == "'"$1"'") { print $1 } }'
}


#############################################################################
#
# wait4user
#
# Query the user to press Return to continue.
#
#############################################################################
wait4user()
{
	printf "$(gettext "Press RETURN to continue --> ")"
	read ANYKEY
}


#############################################################################
#
# yes_or_no
#
# Query the user for yes or no input.
#
# $1 - prompt, should not include final newline or "(y/n)"
# Returns true (0) for yes, false (1) for no.
#
#############################################################################
yes_or_no()
{
	typeset response=""
	# TRANSLATION_NOTE - this is the format for yes or no prompts - %s is
	# the actual question.
	typeset yn=$(gettext "[y,n]")
	typeset fmt="$1"
	shift

	while true
	do
		printf "$fmt $yn " "$@"
		read response
		# Examples of "locale yesexpr" and "locale noexpr":
		# $(locale yesexpr) is "^[yY]" or "[sSyY][[:alpha:]]*"
		# $(locale noexpr)  is "^[nN]" or "[nN][[:alpha:]]*"
		# You must use /usr/xpg4/bin/grep, not /usr/bin/grep for these
		print "$response" \
			| /usr/xpg4/bin/grep "$(locale yesexpr)" \
				>/dev/null 2>&1 && return 0
		print "$response" \
			| /usr/xpg4/bin/grep "$(locale noexpr)"  \
				>/dev/null 2>&1 && return 1
	done
}


#############################################################################
#
# remove_sms_startup_links()
#
# Remove the links from the run control directories to the sms startup
# script. The sms startup script starts and stops the ssd which in turn
# starts and stops all the SMS daemons and servers. These links are only
# present on the SC configured to be the main.
#
#############################################################################
remove_sms_startup_links()
{
	# remove the appropriate run control links
	if [ -f /$ETCDIR/init.d/sms ]
	then
		rm -f /$ETCDIR/rc?.d/[SK][0-9][0-9]sms >/dev/null 2>&1;
	fi
}


#############################################################################
#
# create_sms_startup_links()
#
# Create links in the appropriate run control directories to the sms startup
# script. The sms startup script starts and stops the ssd which in turn
# starts and stops all the SMS daemons and servers.
#
# Called by move_links().
#
#############################################################################
create_sms_startup_links()
{
	typeset newvers=$1
	# Set the initial return code
	typeset return_code=0;

	# create the appropriate run control links
	rm -f /$ETCDIR/rc?.d/[SK][0-9][0-9]sms >/dev/null 2>&1;
		if [[ -f /$ETCDIR/opt/SUNWSMS/SMS${newvers}/startup/sms ]]
		then
			cp /$ETCDIR/opt/SUNWSMS/SMS${newvers}/startup/sms \
				/$ETCDIR/init.d/sms >/dev/null 2>&1
			if [[ $? -ne 0 ]]; then
				gettext "ERROR: \"SMS\" run control script link creation failed.";
				return_code=1
			fi

			#
			# 4730224: When switching between SMS 1.2 & SMS 1.3 need
			#          to relocate start-up script
			#
			# Check if the new version is >= 1.3. If yes, create
			# the link in rc3.d, otherwise, create the link in rc2.d.
			#
			version_cmp $newvers "1.3"

			if [[ $? -ne 255 ]];then
				ln -f /$ETCDIR/init.d/sms /$ETCDIR/rc3.d/S99sms >/dev/null 2>&1;
			else
				ln -f /$ETCDIR/init.d/sms /$ETCDIR/rc2.d/S99sms >/dev/null 2>&1;
			fi


			if [[ $? -ne 0 ]]; then
				gettext "ERROR: \"SMS\" run control script link creation failed.";
				return_code=1
			fi
			ln -f /$ETCDIR/init.d/sms /$ETCDIR/rc1.d/K20sms >/dev/null 2>&1;
			if [[ $? -ne 0 ]]; then
				gettext "ERROR: \"SMS\" run control script link creation failed.";
				return_code=1
			fi
			ln -f /$ETCDIR/init.d/sms /$ETCDIR/rc0.d/K20sms >/dev/null 2>&1;
			if [[ $? -ne 0 ]]; then
				gettext "ERROR: \"SMS\" run control script link creation failed.";
				return_code=1
			fi
	else
		gettext "ERROR: \"SMS\" run control script not found.";
		return_code=1
	fi
	return return_code
}



#############################################################################
#
# require_args
#
# Require a specific number of arguments, $1, to match the actual number
# of arguments, $2.
#
#############################################################################
require_args()
{
	typeset reqd=$1
	typeset actual=$2
	if [[ "$reqd" -ne "$actual" ]]
	then
		usage
		print
		fatal "$(gettext "Incorrect number of arguments.")"
		exit 4
	fi
}


#############################################################################
#
# require_root
#
# Require root privileges.
#
#############################################################################
require_root()
{
	if [[ "$(getuid)" -ne 0 ]]
	then
		fatal "$(printf "$(gettext "You must be root to run %s.")" \
			$command)"
	fi
}


#############################################################################
#
# require_sms_stopped
#
# Require SMS software to be not running (fatal exit if running).
#
#############################################################################
require_sms_stopped()
{
	typeset pid

	getpid ssd | read pid
	if [[ $pid == +([[:digit:]]) ]]; then
		fatal "$(printf "$(gettext "SMS must be stopped prior to running %s.")" $command)"
	fi
	return 0
}


#############################################################################
#
# select_log
#
# Selects where to log based on the subcommand.
#
#############################################################################
select_log()
{
	if [[ -d ${ROOT}/var/sadm/system/logs ]]; then
		LOG_FILE=${ROOT}/var/sadm/system/logs/$command
	else
		LOG_FILE=${ROOT}/var/tmp/$command
	fi
	rotate_file ${LOG_FILE} 3

	# Create and truncate new file:
	gettext 'Command: ' >| ${LOG_FILE}
	print "$command $@" >>${LOG_FILE}

	# Log system information:
	date >> ${LOG_FILE}
	gettext 'System Information:\n' >>${LOG_FILE}
	uname -a >>${LOG_FILE}
	cat /etc/release >>${LOG_FILE}

	print >> ${LOG_FILE}
}


#############################################################################
#
# rotate_file
#
# Rotate a file, useful for keeping backup copies (e.g. for logs).
#
# $1 - file name (without suffix, e.g. "/var/adm/messages")
# $2 - highest numbered suffix to keep (e.g. "6" for "/var/adm/messages.6".
#
#############################################################################
rotate_file()
{
	typeset file=$1
	typeset -i num=$2
	typeset -i min

	while (( $num > 0 ))
	do
		min=$((num - 1))
		[[ -f ${file}.${min} ]] && mv -f ${file}.${min} ${file}.${num}
		num=${min}
	done
	if [[ -f ${file} ]]
	then
		mv -f ${file} ${file}.0
	fi
}


#############################################################################
#
# get_platform_name - prompts the user for the platform name
#
# $CHANGE - set to 1 if the platform name is changed
# $1 - name of variable to set (also contains default value), defaults
#      to PLATFORM_NAME
#
#############################################################################
get_platform_name()
{
	typeset _ans
	typeset _default
	typeset _fmt
	typeset _var=${1}

	eval "_default=\$${_var}"
	while true
	do
		gettext '\nThe platform name identifies the entire host
machine to the SMS software.  The platform name occupies a different
name space than domain names (hostnames of bootable systems).\n\n' | fmt

		if [[ -n "$_default" ]]
		then
			# TRANSLATION_NOTE - %s is the default platform name
			_fmt=$(gettext "What is the name of the platform this SMS will service [%s]? ")
		else
			_fmt=$(gettext "What is the name of the platform this SMS will service? ")
		fi

		printf "$_fmt" "$_default"

		read _ans
		if [[ -n "$_ans" ]]
		then
			if [[ "$_default" != "$_ans" ]]
			then
				CHANGE=TRUE
				_default="$_ans"
			fi
		else
			_ans="$_default"
		fi
		if [[ "$RESERVED_PLAT" == *(* )"$_ans"*( *) ]]
		then
			_fmt=$(gettext "ERROR!  %s is a reserved name!")
			_default=""
			printf "\n${_fmt}\n" "${_ans}"
			continue
		fi

		if [[ -n "$_ans" ]]
		then
			eval "${_var}=\"${_ans}\""
			#write it to the config file
			if [[ -f $MANCONFIGFILE ]];then
				awk '/[ 	]*#/||d==1{print;next}
					d==0{print "'"$PLATFORM_NAME"'";d=1}
					END {if(d==0) print "'"$PLATFORM_NAME"'" }' \
					$MANCONFIGFILE >| $TMPMANCONFIGFILE

			else
				echo $PLATFORM_NAME >| ${TMPMANCONFIGFILE}
			fi
			return 0
		fi
	done
}


#############################################################################
#
#  valid_ipv4_addr - accepts a user input and validates against IPv4
#                    format rules.
#  $1 - user input field
#  $2 - optional maximum valid ipv4 4th byte value (default 255)
#
# Returns:
# 0 if valid (and sets $valid_addr)
# 1 if invalid
#
#############################################################################
valid_ipv4_addr()
{
	typeset _addr=${1}
	typeset _maxbyte4=${2:-255}
	typeset _byte1 _byte2 _byte3 _byte4
	typeset _ipv4_error=$(gettext "IPv4 address error: ")

	[[ $_addr = NONE ]] && return 0
	if [[ ${_addr} == +([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]]) ]]; then
#		echo "Standard IPv4 address notation"
		echo ${_addr} | awk -F. '{print $1,$2,$3,$4}'| \
			read _byte1 _byte2 _byte3 _byte4
		if [[ ${_byte1} -le 0 || ${_byte1} -gt 255 ||
		      ${_byte2} -lt 0 || ${_byte2} -gt 255 ||
		      ${_byte3} -lt 0 || ${_byte3} -gt 255 ||
		      ${_byte4} -lt 0 || ${_byte4} -gt $_maxbyte4 ]]; then
			echo "${_ipv4_error}" 1>&2
			printf "$(gettext 'Address %s not in valid IPv4 address range.')\n" \
					$_addr 1>&2
			[[ $_maxbyte4 -ne 255 ]] &&
				printf "$(gettext 'Maximum value for 4th byte in this context is %s.')\n" \
					$_maxbyte4 1>&2
			return 1
		else
			valid_addr=${_addr}
			return 0
		fi
	#
	# is it even an IPv6 candidate
	elif [[ ${_addr} != *:* ]]; then
		echo "${_ipv4_error}" 1>&2
		printf "$(gettext "%s contains a format error.")\n" $_addr 1>&2
		return 1
	else
#		echo "${_ipv4_error}"
#		printf "$(gettext "%s contains a format error.")\n" $_addr
		return 1
	fi
}


#############################################################################
#
#  valid_ipv6_addr - accepts a user input and validates against IPv6
#                    format rules.
#                    Excludes the following addresses: "::" which is
#                    the null address 0:0:0:0:0:0:0:0
#
#  $1 - user input field
#
# Returns:
# 0 if valid (and sets $valid_addr and $ipv4_compatible)
# 1 if invalid
#
#############################################################################
valid_ipv6_addr()
{
	typeset _addr=${1}
	typeset _word1 _word2 _word3 _word4 _word5 _word6 _word7 _word8
	typeset _ipv6_error=$(gettext "IPv6 address error: ")
	typeset _subnetlength

	# check for optional subnet prefix length
	if [[ ${_addr} = */* ]]; then
		_subnetlength=${_addr#*/}
		_addr=${_addr%/*}
		if [[ $_subnetlength != +([[:digit:]]) || $_subnetlength -gt 128 || $_subnetlength -lt 0 ]]; then
			printf "$(gettext 'Subnet prefix length \"%s\" is not in the range 0 - 128.')\n" \
					$_subnetlength 1>&2
			return 1
		fi
	fi

	# is it even an IPv6 candidate i.e. any ":" at all
	if [[ ${_addr} != *:* ]]; then
		return 1

	# test for a null address
	# it'll look like this "::" (and it equals 0:0:0:0:0:0:0:0)
	elif [[ ${_addr} == :: ]]; then
		echo "${_ipv6_error}" 1>&2
		printf "$(gettext "\"%s\" is a null IPv6 address.")\n" $_addr 1>&2
		return 1

	#
	# test for illegal use of "::"
	elif [[ ${_addr} == *::+(:)* || ${_addr} == *::*::* ]]; then
		echo "${_ipv6_error}" 1>&2
		printf "$(gettext "%s improper use of \"::\" notation.")\n" $_addr 1>&2
		return 1

	#
	# test for illegal use of ":"
	elif [[ ${_addr} == :[[:xdigit:]]* || ${_addr} == *[[:xdigit:]]: ]]; then
		echo "${_ipv6_error}" 1>&2
		printf "$(gettext "%s improper use of \":\" notation.")\n" $_addr 1>&2
		return 1

	# test for incomplete addresses
	elif [[ ${_addr} != +([[:xdigit:]]):+([[:xdigit:]]):+([[:xdigit:]]):+([[:xdigit:]]):+([[:xdigit:]]):+([[:xdigit:]]):+(+([[:xdigit:]]):+([[:xdigit:]])|+([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]])) && ${_addr} != *::* ]]; then
		echo "${_ipv6_error}" 1>&2
		printf "$(gettext "%s is an incomplete address.")\n" $_addr 1>&2
		return 1

	#
	#
	# test for standard notation
	# x:x:x:x:x:x:x:x  or some variation x::x:x:x, ::xxxx, etc.
	# for a quick ref. see inet_ntop(3SOCKET)
	#
	elif [[ ${_addr} == *([[:xdigit:]]):*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]]):*([[:xdigit:]]) ]]; then
#		echo "Standard IPv6 address notation"
		echo ${_addr} | awk '
{
	maxrec = 8
#split input on colons
	wcnt=split($1, _paddr, ":")
	j = 1
	for( i = 1; i <= wcnt; ++i )
	{
#check for nulls
		if( _paddr[i] == "" )
		{
			if( i == 1 || i == wcnt )
			{
				_paddr[i]="0"
				new_addr[j++] = _paddr[i]
				continue
			}
			for( zinsertcnt = (maxrec-(wcnt-1)); zinsertcnt > 0; --zinsertcnt )
			{
#insert required zeroes to fill out middle of address
				new_addr[ j++ ] = 0
			}
		}
		else
#just use the input field
			new_addr[j++] = _paddr[i]
	}
#print out each word of the address
	for( i = 1; i <= 8; ++i )
	{
		printf "%s ", new_addr[i]
	}
}' | read _word1 _word2 _word3 _word4 _word5 _word6 _word7 _word8

#		"Expanded IPv6 Address: "
#		"$_word1:$_word2:$_word3:$_word4:$_word5:$_word6:$_word7:$_word8\n"
		if (($((16#$_word1)) < 16#0 || $((16#$_word1)) > 16#FFFf ||
		   $((16#$_word2)) < 16#0 || $((16#$_word2)) > 16#FFFf ||
		   $((16#$_word3)) < 16#0 || $((16#$_word3)) > 16#FFFf ||
		   $((16#$_word4)) < 16#0 || $((16#$_word4)) > 16#FFFf ||
		   $((16#$_word5)) < 16#0 || $((16#$_word5)) > 16#FFFf ||
		   $((16#$_word6)) < 16#0 || $((16#$_word6)) > 16#FFFf ||
		   $((16#$_word7)) < 16#0 || $((16#$_word7)) > 16#FFFf ||
		   $((16#$_word8)) < 16#0 || $((16#$_word8)) > 16#FFff )) ; then
			echo "${_ipv6_error}" 1>&2
			printf "$(gettext "%s contains a format error.")\n" $_addr 1>&2
			return 1

		else
			ipv4_compatible=0
			valid_addr="$_word1:$_word2:$_word3:$_word4:$_word5:$_word6:$_word7:$_word8"
			if [[ -n ${_subnetlength} ]]; then
				valid_addr=${valid_addr}/$_subnetlength
			fi
			return 0
		fi

	# check for mixed notation
	# x:x:x:x:x:x:d.d.d.d or a variation like ::d.d.d.d
	#
	elif [[ ${_addr} == *([[:xdigit:]]):*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]])?(:)*([[:xdigit:]]):+([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]]) ]]; then
#		"IPv4-compatible IPv6 address notation"
		echo ${_addr} | awk '
{
	maxrec = 7
#split input on colons
	wcnt=split($1, _paddr, ":")
	j = 1
	for( i = 1; i <= wcnt; ++i )
	{
#check for nulls
		if( _paddr[i] == "" )
		{
			if( i == 1 )
			{
				_paddr[i]="0"
				new_addr[j++] = _paddr[i]
				continue
			}
			for( zinsertcnt = (maxrec-(wcnt-1)); zinsertcnt > 0; --zinsertcnt )
			{
#insert required zeroes to fill out middle of address
				new_addr[ j++ ] = 0
			}
		}
		else
#just use the input field
			new_addr[j++] = _paddr[i]
	}
#print out each word of the address
	for( i = 1; i <= maxrec; ++i )
	{
		printf "%s ", new_addr[i]
	}
}' | read _word1 _word2 _word3 _word4 _word5 _word6 _word7

#		"Expanded IPv4-compatible IPv6 Address: "
#		"$_word1:$_word2:$_word3:$_word4:$_word5:$_word6:$_word7\n"
		if (($((16#$_word1)) < 16#0 || $((16#$_word1)) > 16#FFFf ||
		   $((16#$_word2)) < 16#0 || $((16#$_word2)) > 16#FFFf ||
		   $((16#$_word3)) < 16#0 || $((16#$_word3)) > 16#FFFf ||
		   $((16#$_word4)) < 16#0 || $((16#$_word4)) > 16#FFFf ||
		   $((16#$_word5)) < 16#0 || $((16#$_word5)) > 16#FFFf ||
		   $((16#$_word6)) < 16#0 || $((16#$_word6)) > 16#FFFf )) ; then
			echo "${_ipv6_error}" 1>&2
			printf "$(gettext '%s contains an invalid address.')\n" \
				$_addr 1>&2
			return 1

		elif ! valid_ipv4_addr ${_word7} 255; then
			return 1
		fi

		valid_addr=$_word1:$_word2:$_word3:$_word4:$_word5:$_word6:$_word7
		if [[ -n ${_subnetlength} ]]; then
			valid_addr=${valid_addr}/$_subnetlength
		fi
		ipv4_compatible=1
		return 0

	else
		echo "${_ipv6_error}" 1>&2
		printf "$(gettext "%s contains a format error.")\n" $_addr 1>&2
		return 1
	fi
}


#############################################################################
#
# get_next_addr - return the next (numerical) address
#                 Handles optional subnet prefix length.
#           $1 - address to start from
#           $2  - var. to return next in.
#
# Called by auto_range_I1_settings(), auto_range_I2_settings().
#
#############################################################################
get_next_addr()
{
	typeset _word1 _word2 _word3 _word4 _word5 _word6 _word7 _word8
	typeset _addr=$1
	typeset _next=$2
	typeset _v4addr
	typeset -xi ipv4_compatible=0
	typeset _subnetlength

	if [[ ${_addr} = */* ]]; then
		_subnetlength=${_addr#*/}
		_addr=${_addr%/*}
	fi

	if valid_ipv4_addr $_addr 255; then
		echo ${_addr} | awk -F. '
{
	printf "%d.%d.%d.%d", $1,$2,$3,($4+1)
}' | read _addr

		if [[ -n ${_subnetlength} ]]; then
			eval "$_next=\"$_addr/$_subnetlength\""
		else
			eval "$_next=\"$_addr\""
		fi
		return 0

	elif valid_ipv6_addr $_addr; then
		if [[ $ipv4_compatible -eq 1 ]]; then
			echo ${_addr} | awk -F: '
{
	fcnt = split($7, v4addr, ".")
	printf "%s %s %s %s %s %s %d.%d.%d.%d", $1,$2,$3,$4,$5,$6,v4addr[1],v4addr[2],v4addr[3],(v4addr[4]+1)
}' | read _word1 _word2 _word3 _word4 _word5 _word6 _word7

			_addr=$_word1:$_word2:$_word3:$_word4:$_word5:$_word6:$_word7

			if [[ -n ${_subnetlength} ]]; then
				eval "$_next=\"$_addr/$_subnetlength\""
			else
				eval "$_next=\"$_addr\""
			fi
			return 0
		fi

		echo ${_addr} | awk -F: '
{
	printf "%s %s %s %s %s %s %s %s", $1,$2,$3,$4,$5,$6,$7,$8
}' | read _word1 _word2 _word3 _word4 _word5 _word6 _word7 _word8

		_word8=$(($((16#$_word8))+1))

		printf '%s:%s:%s:%s:%s:%s:%s:%x' $_word1 $_word2 $_word3 \
			$_word4 $_word5 $_word6 $_word7 $_word8 |read _addr

		if [[ -n ${_subnetlength} ]]; then
			eval "$_next=\"$_addr/$_subnetlength\""
		else
			eval "$_next=\"$_addr\""
		fi
		return 0
	fi
	return 1
}


#############################################################################
#
# get_ip_addr - prompts the user for an IP address for the host
# given as an argument and checks to make sure that the answer is at least
# of the form of an IP address.
#
# $1 - name of host to query for
# $2 - name of variable to store result in, defaults to HOST_ADDR
# $3 - required IP version (either blank, "4" or "6")
#
#############################################################################
get_ip_addr()
{
	typeset _addr=""
	typeset _var=${2}
	typeset _fmt=""
	typeset -x valid_addr
	typeset requireIPv="$3"

	_var=${_var:-HOST_ADDR}
	_fmt=$(gettext "I could not automatically determine the IP address of %s.")
	printf "\n${_fmt}\n" "${1}"
	_fmt=$(gettext "Please enter the IP address of %s: ")
	while true
	do
		printf "${_fmt}" "${1}"
		readip $_var "" $requireIPv 255
		if [[ -n "$valid_addr" ]]; then
			break
		fi
	done
	print
	gettext 'You should make sure that this host/IP address is set up properly
in the /etc/inet/hosts file or in your local name service system.' | fmt
}


#############################################################################
#
# getent_hosts_uniq()
#
# Get the first host IP address using getent(1M).
# Command getent(1M) queries hosts, ipnodes, NIS, and DNS,
# depending on the "hosts:" line in nsswitch.conf
#
# If multiple host entries exist, print a warning message to stderr
# and print to stdout only the first one found.
#
# Note: use gethostip() instead of this function to handle the special case
# of the "NONE" hostname.
# Note 2: use lookup_ip_addr() instead of this function to handle NONE and
# also look in MAN.cf if not found otherwise.
#
# Input:
# $1 - Host name to lookup.
#
# Return result in stdout.
#
#############################################################################
getent_hosts_uniq()
{
	typeset -r hn=$1

	if [[ -z "$hn" ]] ; then
		return 1
	fi

	if (( $(getent hosts $hn | uniq | wc -l| awk '{print $1}') > 1 ))
	then
		# TRANSLATION_NOTE - %s is a hostname
		printf "$(gettext \
			'Warning: multiple addresses exist for %s:')\n" $1 1>&2
		getent hosts $hn | uniq 1>&2
		printf "$(gettext 'First address %s used.')\n" $_addr 1>&2
	fi

	getent hosts $hn | uniq | head -1 | awk '{print $1}'
	return 0
}


#############################################################################
#
# get_valid_hostname - prompts the user for a hostname for the host
# given as an argument and checks to make sure that the answer
# presents no conflicts.
#
# $1 - name of host to query for
# $2 - variable to return hostname in, if successful
# $3 - network (I1, I2, or L)
#
#############################################################################

get_valid_hostname()
{
	typeset lhostname=${1}
	typeset defhostname=${2:-HNAME}
	typeset _mannet=${3}
	typeset -i validname=1
	typeset ilookup
	typeset lookup_addr
	typeset lookup_name
	typeset stuff
	typeset _net
	typeset _intface
	typeset _name
	typeset _addr

	typeset ans
	typeset -lL24 lhostans

	read ans
	lhostans=$ans

	if [[ -n "${ans}" ]]
	then
# if name ends with a ".", "-", contains a space or starts with a non-alpha;
#    then it's invalid
		echo ${lhostans} | awk '
/^[^a-z]/{
print "ERROR: hostname must start with a character in [a-z]: " $0
exit
}
/^.*\ +.*$/{
print "ERROR: hostname cannot contain spaces: "
exit
}
/^?*[.-]+$/{
print "ERROR: hostname may not end with . or -: "
exit
}
/^[a-z0-9\.-]*$/{
print "OK"
exit
}
/^.*[^a-z0-9\.-]*.*$/{
print "ERROR: hostname contains invalid characters : "
exit
}' | read errmsg

		if [[ "$ans" = NONE ]] ; then
			if [[ $_mannet == I1 ]]; then
				eval "$defhostname=\"$ans\""
				return 0
			fi
			gettext "NONE is allowed for domain exclusion in I1 network only.\n" >&2
			return 1
		fi

		if [[ $errmsg != "OK" ]]
		then
			print -u2 ${errmsg} ${ans}
			validname=0

		elif getent_hosts_uniq ${lhostans} \
				| read lookup_addr lookup_name stuff

		then
			printf "\n$(gettext 'WARNING! system hostname conflict \"%s\" (%s) already exists!')\n" \
				${lhostans} ${lookup_addr}
			validname=1

		elif [[ -f "${MANCONFIGFILE}" ]]; then
			ilookup=`grep "$ans" $MANCONFIGFILE`
			if [[ -n $ilookup ]]; then
				echo $ilookup | awk '{print $1,$2,$3,$4}' | \
					read _net _intface _name _addr
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
				printf "\n$(gettext 'WARNING! MAN hostname conflict \"%s\" (%s) already exists!')\n" \
					${lhostans} ${_addr}
				validname=1
			fi
		fi

	else
		eval "$defhostname=\"$lhostname\""
		return 0
	fi

	if [[ $validname -eq 0 ]]
	then
		return 1
	else
		eval "$defhostname=\"$ans\""
		return 0
	fi
}


#############################################################################
#
# lookup_ip_addr()
#
# Given a hostname as an argument, set the variable in $2,
# to the IP address and the return status of the match (0=OK).
# Use the first address found, if multiple IP addresses exist for a hostname.
#
# Use /etc/nsswitch.conf file (to decide between NIS+, NIS, DNS, files).
# If not there, use MAN.cf
#
# Input:
# $1 - name of host to lookup
# $2 - variable to store result in; defaults to $HOST_ADDR
#	If $1 is "NONE," set variable in $2 to "NONE."
#
# Return 0 on success, non-zero on error.
#
#############################################################################
lookup_ip_addr()
{
	typeset _net
	typeset _intface
	typeset _addr
	typeset _name
	typeset _junk
	typeset _line
	typeset _names
	typeset _hostname=$1
	typeset _var=${2:-HOST_ADDR}
	typeset ilookup

	if [[ "$hostname" = NONE ]] ; then
		eval $_var=NONE
		return 0
	fi

	getent_hosts_uniq ${1} | read _addr _name _junk
	if [[ -n "$_addr" ]]
	then
		eval "${_var}=\"${_addr}\""
		return 0
	fi

	# See if there's an IPv6 address in /etc/inet/ipnodes
	# Set environment variable in $2 to first one found, if any.
	if [[ -s "${ETCHOSTSFILE6}" ]]; then
	  while read _addr _name ; do # for each line in ipnodes
		if [[ -z "$_addr" || "$_addr" == "#"* || \
			-z "$_name" || "$_name" == "#"* ]]
		then
			# empty or comment line
			continue
		fi

		# strip off any trailing comment part
		_name=${_name%%#*}

		# there is an embedded tab in the pattern below
		if [[ "$_name" == ?(*[  \t])${1}?(.*) ]] ; then
			# short or long name matches, only at beginning of word
			eval "${_var}=\"${_addr}\""
			return 0
		fi
	  done < "${ETCHOSTSFILE6}"
	fi

	# See if there's an IPv4 address in /etc/inet/hosts
	# Set environment variable in $2 to first one found, if any.
	if [[ -s "${ETCHOSTSFILE}" ]]; then
	  while read _addr _name ; do # for each line in hosts
		if [[ -z "$_addr" || "$_addr" == "#"* || \
			-z "$_name" || "$_name" == "#"* ]]
		then
			# empty or comment line
			continue
		fi

		# strip off any trailing comment part
		_name=${_name%%#*}

		# there is an embedded tab in the pattern below
		if [[ "$_name" == ?(*[  \t])${1}?(.*) ]]
		then
			# short or long name matches, only at beginning of word
			eval "${_var}=\"${_addr}\""
			return 0
		fi
	  done < "${ETCHOSTSFILE}"
	fi

	# See if there's an IP address in MAN.cf
	# Set environment variable in $2 to first one found, if any.
	if [[ -s "${MANCONFIGFILE}" ]]; then
		ilookup=$(grep "$1" $MANCONFIGFILE | head -1)
		if [[ -n $ilookup ]]; then
			echo $ilookup | awk '{print $1,$2,$3,$4}' | \
				read  _net _intface _name _addr
			eval "${_var}=\"${_addr}\""
			return 0
		fi
	else
		# nowhere else to look (why is there no hosts or MAN.cf file???)
		return 1
	fi

	# we did not find a match
	return 1
}


#############################################################################
#
# setup_I1_network - Configure SC to Domain MAN network, I1
#
# Called by sms_man_setup() for part of smsconfig -m.
#
#############################################################################
setup_I1_network()
{
	typeset fmt=$(gettext "\nDo you want to accept these network settings?")
	typeset -i write_change=0
	typeset ichk gout
	typeset _net _intface _hostname _ip _mask

	gettext "\nConfiguring I1 Management Network - "
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
	gettext "'I1' is the Domain to SC MAN.\n"
	I1_NAME=$PLATFORM_NAME
	if [[ -f "${MANCONFIGFILE}" ]]; then
		gout=`grep "^I1" $MANCONFIGFILE`
		if [[ -n $gout ]]; then
			display_I1_settings
			if  yes_or_no "$fmt"; then
				# check to make sure the config files are there
				ichk=`grep "SC-I1" $MANCONFIGFILE`
				echo $ichk |awk '{print $1,$2,$3,$4}'|\
					read  _net _intface _hostname _ip
				mchk=`grep "NM-I1" $MANCONFIGFILE`
				echo $mchk |awk '{print $1,$2,$3,$4}'|\
					read  _net _intface _hostname _mask
				write_ifconfig_file ${I1_IFCONFIG_IFACE} ${_ip} ${_mask}
				return 0
			else
				get_platform_name PLATFORM_NAME
				I1_NAME=$PLATFORM_NAME
			fi
		fi
	fi

	while true; do
		setup_network_table "I1"
		auto_range_I1_settings $write_change
		if yes_or_no "$fmt"; then
			write_change=1
			auto_range_I1_settings $write_change $i1mask
			return 0
		fi
	done
}


#############################################################################
#
# setup_network_table
#
#  Prompt user for the base address of the requested network then
#  prompt for the netmask.
#
#  Input:
#  $1 Network name (I1 or I2)
#  $2 Optional second network name (I1 or I2)
#
#  Return the netmask result in $I1_mask or $I2_mask, as appropriate.
#
#  Called by setup_I1_network() and  setup_I2_network().
#
#############################################################################
setup_network_table()
{
	netlist="$*"
	I1_netmask_default="255.255.255.224"
	I2_netmask_default="255.255.255.252"
	C_netmask_default="255.255.255.252"
	I1_netmask=$I1_netmask_default
	I2_netmask=$I2_netmask_default
	C_netmask=$C_netmask_default
	typeset -x valid_addr
	typeset _subnetlength
	typeset _addr
	typeset _mask

	for net in $netlist; do
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
		printf "$(gettext "MAN %s Network Identification")\n" $net
		_addr=""
		while [[ -z "$_addr" ]]; do
			printf "$(gettext 'Enter the IP network number (base address) for the %s network: ')" \
				$net
			# This should be 225 to prevent overflow past the end
			#  of the legal addresses (255)
			readip ${net}_ip "" "" 225 || continue
			eval "_addr=\"\$${net}_ip\""
			if [[ -n "${_addr}" ]]; then
				if [[ ${_addr} = */* ]]; then
					_subnetlength=${_addr#*/}
					eval "${net}_netmask=\"$_subnetlength\""
				else
					eval "_mask=\"\$${net}_netmask_default\""
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
					printf "$(gettext 'Enter the netmask for the %s MAN network [ %s ]: ')" \
						$net $_mask
					readip ${net}_netmask $_mask 4 || _addr=""
					eval "_mask=\"\$${net}_netmask\""
					[[ -z "$_mask" ]] && eval "${net}_netmask=\$${net}_netmask_default"
				fi
			fi
		done
	done
}


#############################################################################
#
# display_I1_settings - Display the list of settings for the I1 MAN network,
# which is the SC to Domain MAN network.
#
# Called by setup_I1_network().
#
# $1 - variable to put the name prefix in
# $2 - variable to put the base address of the net into.
#
#############################################################################
display_I1_settings()
{
	typeset s_fmt="%14s\t%15s\t%s\n"

	printf "${s_fmt}" "$(gettext 'Hostname')" \
			"$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
	printf "${s_fmt}" '--------' '----------' ''
	awk 'BEGIN { OFS="\t";OFMT="%14s\t%15s\n";}
/^I1/{
split($0, i1)
printf OFMT, i1[3],i1[4]
}' $TMPMANCONFIGFILE
}


#############################################################################
#
# auto_range_I1_settings - Display the list of settings for the I1 MAN network,
# which is the SC to Domain MAN network.
#
# Called by setup_I1_network().
#
# $1 - variable to put the name prefix in
# $2 - variable to put the base address of the net into.
#
#############################################################################
auto_range_I1_settings()
{
	typeset ip
	typeset addr
	typeset -i write_change=$1
	typeset _mask=$I1_netmask
	typeset -u dsdname
	typeset s_fmt="%12s\t%15s\t%s\n"
	typeset _fmt="%s\t%s\t%s\t%s\n"
	typeset _ipnext

	if [[ $write_change -eq 0 ]]; then
		print
		printf "${s_fmt}" "$(gettext 'Hostname')" \
			"$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
		printf "${s_fmt}" '--------' '----------' ''
	else
		if [[ -f $TMPMANCONFIGFILE ]];then
			sed -e "/^I1/d" $TMPMANCONFIGFILE >| $TMPMANCONFIGFILE.$$
			mv -f $TMPMANCONFIGFILE.$$ $TMPMANCONFIGFILE
		elif [[ -f $MANCONFIGFILE ]];then
			sed -e "/^I1/d" $MANCONFIGFILE >| $TMPMANCONFIGFILE
		fi
	fi

	addr=$I1_ip
	if [[ $write_change -eq 1 ]]; then
		printf "${_fmt}" 'I1' 'NM-I1' 'netmask-i1' "${_mask}" \
			>>${TMPMANCONFIGFILE}
	else
		printf "${s_fmt}" 'netmask-i1' "${_mask}"
	fi
	for i in sc-i1 a b c d e f g h i j k l m n o p q r
	do
		get_next_addr ${addr} _ipnext
		_ip=$_ipnext
		dsdname=$i

		if [[ $i == "sc-i1" ]]; then
			if [[ $write_change -eq 1 ]]; then
				printf "${_fmt}" 'I1' 'SC-I1' \
					"${I1_NAME}-${i}" \ "${_ip}" \
					>>${TMPMANCONFIGFILE}
				write_ifconfig_file ${I1_IFCONFIG_IFACE} ${_ip} ${_mask}
			else
				printf "${s_fmt}" "${I1_NAME}-${i}" "${_ip}"
			fi
		else
			if [[ $write_change -eq 1 ]]; then
				printf "${_fmt}" 'I1' "D${dsdname}-I1" \
					"${I1_NAME}-${i}" "${_ip}" \
					>>${TMPMANCONFIGFILE}
			else
				printf "${s_fmt}" "${I1_NAME}-${i}" "${_ip}"
			fi
		fi
		addr=$_ipnext
	done
}


#############################################################################
#
# write_ifconfig_file
#
# create, or update, the ifconfig input file IFCONFIG_IFACE on the sc. If it
# fails, fatal exit.
#
# Called by setup_I1_network(), and auto_range_I1_settings(),
# setup_I2_network(), and auto_range_I2_settings().
#
#############################################################################
write_ifconfig_file()
{
	typeset _interface=$1
	typeset _sc_ip=$2
	typeset _nm_ip=$3

	[[ "${_sc_ip}" = NONE ]] && return
	if [[ ${_sc_ip} = *:* ]]; then
		_ifcf=${HOSTNAME_BASE6}${_interface}
		ADDRESS_FAM=inet6
		IFCOPTIONS=
		[[ -f ${HOSTNAME_BASE}${_interface} ]] && \
			/bin/rm -f ${HOSTNAME_BASE}${_interface}
	else
		_ifcf=${HOSTNAME_BASE}${_interface}
		ADDRESS_FAM=inet
		IFCOPTIONS="netmask + broadcast +"
		[[ -f ${HOSTNAME_BASE6}${_interface} ]] && \
			/bin/rm -f ${HOSTNAME_BASE6}${_interface}
	fi

	LINE="$_sc_ip $IFCOPTIONS private up"

	# If the file doesn't exist or doesn't have an entry for this interface
	# in it, then we need to replace it.
	grep "$LINE" $_ifcf >/dev/null 2>&1 || echo "$LINE" >| $_ifcf
	[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
		"%s Unable to update %s.")\n" $command $_ifcf)"

	# plumb the scman(0/1) interface then configure the addresses on it
	${IFCONFIG} ${_interface} $ADDRESS_FAM plumb >/dev/null 2>&1
	[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
		"%s: Unable to plumb %s interface.")\n" $command $_interface)"
	${IFCONFIG} ${_interface} $ADDRESS_FAM $_sc_ip $IFCOPTIONS private up \
		>/dev/null 2>&1
	[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
		"%s: Unable to configure %s interface.")\n" \
		$command $_interface)"
}


#############################################################################
#
# prompt_sc_number
#
# Prompt the user to determine if we are configuring SC0 or SC1
# Called by get_sc_number() when it can't be deteremined automatically.
#
# Sets both $THIS_SC and $OTHER_SC to 0 or 1.
#
#############################################################################
prompt_sc_number()
{
	typeset _ans
	typeset _prompt

	_prompt=$(gettext "Which System Controller are you configuring? [Choose 0 or 1]: ")
	while [[ -z "$THIS_SC" ]] ;do
		printf "$_prompt"
		read _ans
		if [[ -n $_ans ]]; then
			if [[ $_ans == $(gettext "0") ]]; then
				THIS_SC=0
				OTHER_SC=1
				break;
			elif [[ $_ans == $(gettext "1") ]]; then
				THIS_SC=1
				OTHER_SC=0
				break;
			else
				gettext 'Please enter only 0 or 1 to indicate
which SC you are currently configuring.\n' | fmt
			fi
		fi
	done
}


#############################################################################
#
# get_sc_number
#
# Determine if we are configuring SC0 or SC1
# Do this by running getscnum and cache the result.
#
# Sets both $THIS_SC and $OTHER_SC to 0 or 1.
#
#############################################################################
get_sc_number()
{
    typeset scnum

    if [[ -z "$THIS_SC" ]] ; then
	if [[ -x $GETSCNUMPATH ]] ; then
	    if scnum=$($GETSCNUMPATH); then
		case "$scnum" in
		    0|1) THIS_SC=$scnum; OTHER_SC=$((!$THIS_SC));;
		    *) printf "$(gettext \
				'Warning: %s returned invalid SC number: %s\\n')" \
				$GETSCNUMPATH "$scnum"
		       ;;
		esac
	    fi
	fi
	[[ -z "$THIS_SC" ]] && prompt_sc_number
    fi
}


#############################################################################
#
# set_rhosts_file
#
# Modify the systems hosts.equiv file to properly identify the "other" sc
# SC1-I2
#
# Called by sms_man_setup (for part of smsconfig -m).
#
#############################################################################
set_rhosts_file()
{
	typeset _net _intface _hostname _ip
	typeset gout
	typeset _sc_hostname=$1

	if [[ -f $MANCONFIGFILE ]];then
		gout=`grep "SC${OTHER_SC}-I2" $MANCONFIGFILE`
		if [[ -n  $gout ]]; then
			echo $gout |awk '{print $1,$2,$3,$4}'|\
				read  _net _intface _hostname _ip
			_sc_hostname=$_hostname
		else
			fatal "$(printf "$(gettext "%s: I2 network not configured for failover.")\n" $command)"
		fi
	else
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
		fatal "$(printf "$(gettext "%s: MAN network not properly configured for failover.")\n" $command)"
	fi

	# Create /.rhosts
	userlist="root"
	printf "$(gettext 'Creating %s to facilitate file propagation ... ')" $RHOSTSFILE
	if [[ -f $RHOSTSFILE ]]; then
		cp $RHOSTSFILE $TMPRHOSTSFILE >> /dev/null 2>&1
		[[ $? -ne 0 ]] && fatal "$(printf "$(gettext "%s: /tmp filesystem full")\n" $command)"
		chmod u+w $TMPRHOSTSFILE > /dev/null 2>&1
	else
		touch $TMPRHOSTSFILE
	fi

	for name in $userlist; do
		# check to see if that usr and hostname are already there
		grepchk=`grep "$_sc_hostname.*$name" $TMPRHOSTSFILE`
		if [[ -z $grepchk ]]; then
			echo "${_sc_hostname} $name" >>$TMPRHOSTSFILE
		fi
	done

	mv -f $TMPRHOSTSFILE $RHOSTSFILE >>/dev/null 2>&1
	if [[ $? -ne 0 ]]; then

		#
		# TRANSLATION_NOTE
		#
		# "failed" is used to denote the unsuccessful completion of a
		# task. e.g., when a task starts the user will see:
		#
		#    Creating /.rhosts to facilitate file propagation ...
		#
		# and when the task did not complete the user will see:
		#
		#    Creating /.rhosts to facilitate file propagation ... failed
		#
		print "$(gettext 'failed')"
		fatal "$(printf "$(gettext "%s: Failover not configured: Unable to save .rhosts.")\n" $command)"
		return 1
	fi
	chmod 400 $RHOSTSFILE >/dev/null 2>&1
	chown root:sys $RHOSTSFILE >/dev/null 2>&1

	#
	# TRANSLATION_NOTE
	#
	# "done" is used to denote the successful completion of a task.
	# e.g., when a task starts the user will see:
	#
	#     Creating /.rhosts to facilitate file propagation ...
	#
	# and when the task successfully completes the user will see:
	#
	#     Creating /.rhosts to facilitate file propagation ... done
	#
	print "$(gettext 'done')"

	#
	# 4750572: sms startup fails to correctly determine
	#          remote SC and requires .rhosts/.shosts
	#
	# Store the remote host entry in a private file.
	#
	if [[ ! -e $PRIVATE_REMOTEHOST ]]; then
		echo "${_sc_hostname} $name" >> $PRIVATE_REMOTEHOST
		chmod 400 $PRIVATE_REMOTEHOST >/dev/null 2>&1
		chown root:sys $PRIVATE_REMOTEHOST >/dev/null 2>&1
	fi
}


#############################################################################
#
# auto_range_I2_settings - Display the list of settings for the I2 MAN network,
# which is the SC to SC MAN network.
#
# Called by setup_I2_network().
#
# $1 - variable to put the name prefix in
# $2 - variable to put the base address of the net into.
#
#############################################################################
auto_range_I2_settings()
{
	typeset ip
	typeset addr
	typeset -i write_change=$1
	typeset _mask=$I2_netmask
	typeset s_fmt="%12s\t%15s\t%s\n"
	typeset _fmt="%s\t%s\t%s\t%s\n"
	typeset _ipnext
	typeset _ip

	if [[ $write_change -eq 0 ]]; then
		print
		printf "${s_fmt}" "$(gettext 'Hostname')" \
			"$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
		printf "${s_fmt}" '--------' '----------' ''
	else
		if [[ -f $TMPMANCONFIGFILE ]];then
			sed -e "/^I2/d" $TMPMANCONFIGFILE >| $TMPMANCONFIGFILE.$$
			mv -f $TMPMANCONFIGFILE.$$ $TMPMANCONFIGFILE
		elif [[ -f $MANCONFIGFILE ]];then
			sed -e "/^I2/d" $MANCONFIGFILE >| $TMPMANCONFIGFILE
		fi
	fi

	addr=$I2_ip
	if [[ $write_change -eq 1 ]]; then
		printf "${_fmt}" 'I2' 'NM-I2' 'netmask-i2' "${_mask}" \
			>>${TMPMANCONFIGFILE}
	else
		printf "${s_fmt}" 'netmask-i2' "${_mask}"
	fi

	for i in sc0-i2 sc1-i2
	do
		get_next_addr ${addr} _ipnext
		_ip=$_ipnext

		if [[ $i == "sc0-i2" ]]; then
			if [[ $write_change -eq 1 ]]; then
				printf "${_fmt}" 'I2' 'SC0-I2' "${I2_NAME}-${i}" "${_ip}" \
					>>${TMPMANCONFIGFILE}
				if [[ $OTHER_SC == "1" ]]; then
					write_ifconfig_file ${I2_IFCONFIG_IFACE} ${_ip} ${_mask}
				fi
			else
				printf "${s_fmt}" "${I2_NAME}-${i}" "${_ip}"
			fi
		else
			if [[ $write_change -eq 1 ]]; then
				printf "${_fmt}" 'I2' 'SC1-I2' "${I2_NAME}-${i}" "${_ip}" \
					>>${TMPMANCONFIGFILE}
				if [[ $OTHER_SC == "0" ]]; then
					write_ifconfig_file ${I2_IFCONFIG_IFACE} ${_ip} ${_mask}
				fi
			else
				printf "${s_fmt}" "${I2_NAME}-${i}" "${_ip}"
			fi
		fi
		addr=$_ipnext
	done
}


#############################################################################
#
# setup_I2_network - Configure the SC to SC MAN network, I2.
#
# Called by sms_man_setup() for part of smsconfig -m.
#
#############################################################################
setup_I2_network()
{
	typeset ichk mchk check_sc
	typeset _net _intface _hostname _mask
	typeset -i write_change=0
	typeset i2mask="255.255.255.252"
	typeset I2_NAME=$PLATFORM_NAME
	typeset fmt=$(gettext "\nDo you want to accept these network settings?")

	gettext "\nConfiguring I2 Management Network - "
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
	gettext "'I2' is for SC to SC MAN.\n"
	get_sc_number
	if [[ -f "${MANCONFIGFILE}" ]]; then
		gout=`grep "^I2" $MANCONFIGFILE`
		if [[ -n $gout ]]; then
			display_I2_settings
			if  yes_or_no "$fmt"; then
			#check to make sure the config files are there
				check_sc="SC${THIS_SC}-I2"
				ichk=`grep "$check_sc" $MANCONFIGFILE`
				echo $ichk |awk '{print $1,$2,$3,$4}'|\
					read  _net _intface _hostname _ip
				mchk=`grep "NM-I2" $MANCONFIGFILE`
				echo $mchk |awk '{print $1,$2,$3,$4}'|\
					read  _net _intface _hostname _mask
				write_ifconfig_file ${I2_IFCONFIG_IFACE} ${_ip} ${_mask}
				return 0
			fi
		fi
	fi

	while true; do
		setup_network_table "I2"
		auto_range_I2_settings $write_change
		if yes_or_no "$fmt"; then
			write_change=1
			auto_range_I2_settings $write_change $i2mask
			return 0
		fi
	done
}


#############################################################################
#
# display_I2_settings - Display the list of setting for the I2 MAN network,
# which is the SC to SC MAN network.
#
# Called by setup_I2_network().
#
# $1 - variable to put the name prefix in
# $2 - variable to put the base address of the net into.
#
#############################################################################
display_I2_settings()
{
	typeset s_fmt="%14s\t%15s\t%s\n"

	printf "${s_fmt}" "$(gettext 'Hostname')" "$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
	printf "${s_fmt}" '--------' '----------' ''
	awk 'BEGIN { OFS="\t";OFMT="%14s\t%15s\n";}
/^I2/{
split($0, i1)
printf OFMT, i1[3],i1[4]
}' $TMPMANCONFIGFILE
}


############################################################################
#
# validate_nic - validate a NIC using various ifconfig commands.
#
# $1 - NIC to validate
#
# Return 0 if valid or non-zero if invalid.
#
# Called by validate_nics() and get_sc_board_type().
#
#############################################################################
validate_nic()
{
	nic=$1

	[[ -z "$nic" ]] && return 1

	${IFCONFIG} $nic >/dev/null 2>&1 && return 0 # Valid - Already plumbed.

	if ${IFCONFIG} $nic plumb >/dev/null 2>&1
	then
		${IFCONFIG} $nic unplumb >/dev/null 2>&1
		return 0
	fi
	return 1
}


#############################################################################
#
# get_sc_board_type
#
# Determine the SC hardware we're running on.
# Used to set the default NICs (as they vary).
# RFE 4736411
#
# Set the result in $SCBOARDTYPE, if not already set, to:
# 0	Unknown
# 1	CP1500 "Nordica" class
# 2	CP2140 or similar "Othello+" class
#
# Note: These numbers are arbitrary and have meaning only to this shell script.
#
#############################################################################
get_sc_board_type()
{
	if [[ -z "$SCBOARDTYPE" ]] ; then
		SCBOARDTYPE=0

		case "$(uname -i)" in
		'SUNW,UltraSPARC-IIi-cEngine') # Nordica CP1500
		SCBOARDTYPE=1
			;;
		'SUNW,UltraSPARCengine_CP-40') # Othello+ CP2140
		SCBOARDTYPE=2
			;;
		*)
		SCBOARDTYPE=0
        	gettext 'This is not a recognized SunFire System Controller.\n'
		printf "$(gettext 'The %s command command should only be \
executed on a SunFire System Controller.')\n" $command | fmt
			;;
		esac
	fi
	return $SCBOARDTYPE
}


#############################################################################
#
# validate_nics -  validate NICs for use with one Community External Network
#			(with IPMP).
#
# $1 - Community name
# $2 - 1st NIC to validate
# $3 - 2nd NIC to validate
#
# At least one NIC has to be defined.
#
# Valid NICs are:
# Nordica:  eri1 hme0
# Othello+: eri3 eri0
#
# Invalid NICs are:
# Nordica:  eri0     eri2-19      hme1
# Othello+:     eri1 eri2 eri4-21 hme0 hme1 (NO hme on Othello+)
#
# Return 0 if valid or non-zero if invalid.
#
# Called by setup_C_network().
#
#############################################################################
validate_nics()
{
	typeset commname=$1
	typeset nic1=$2
	typeset nic2=$3
	typeset invalidnics

	#
	# Invalid NIC set depends on whether we're on a Nordica or Othello+:
	# RFE 4736411
	#
	get_sc_board_type
	case $SCBOARDTYPE in
	1) # Nordica
		invalidnics='eri0|eri[2-9]|eri1[0-9]|hme1'
		;;
	2) # Othello+
		invalidnics='eri1|eri2|eri[4-9]|eri1[0-9]|eri2[01]|hme[01]'
		;;
	*) # Unknown board--invalid boards unknown
		invalidnics=''
		fatal "$(gettext \
			"%s must run on a Starfire System Controller.")" \
			$command
		;;
	esac
	# End, RFE 4736411

	[[ -z "$1" && -z "$2" ]] && return 1
	for nic in $nic1 $nic2
	do
		case $nic in
		$invalidnics)
			printf "$(gettext '%s: Invalid NIC device for external network')\n" \
					"$nic" >&2
			return 1 ;;
		"")	: ;;
		*) validate_nic $nic || [[ -n "$DEBUG" ]] || return 1
		esac

		# Verify the NIC hasn't already been used
		if grep '^C' $TMPMANCONFIGFILE | \
				grep -v ".-${commname}[ 	]" | \
				grep $nic >/dev/null; then
			printf "$(gettext '%s: Duplicate NIC device for external network')\n" \
					"$nic" >&2
			return 1
		fi
	done
	return 0
}


#############################################################################
# readip - read a value from user; validate value as a IPv4/6 address
#
# $1 - variable to hold IP address
# $2 - (optional) default value (for re-prompt)
# $3 - (optional) required IP version (either blank, "4" or "6")
# $4 - (optional) maximum valid ipv4 4th byte value (default 255)
#
# Return 0 (success) if user enters a valid IPv4/6 address, or an empty string.
#	Set the environment variable specified by $2 to the IP address.
#	Set it to the empty string, "", if the default value (Return) entered.
# Return 1 (failure) if user enters EOF (as with the "read" command).
#
#############################################################################
readip()
{
	typeset ip
	typeset outarg="$1"
	typeset def="$2"
	typeset requiredIPv="$3"
	typeset _maxbyte4="$4"

	valid_addr=""
	while read ip; do
		if [[ -n "${ip}" && $requiredIPv = "4" && ${ip} = *:* ]]; then
			printf "$(gettext 'IPv4 address required.')\n" 1>&2
		elif [[ -n "${ip}" && $requiredIPv = "6" && ${ip} != *:* ]]; then
			printf "$(gettext 'IPv6 address required.')\n" 1>&2

		elif [[ -z "$ip" ]] || valid_ipv4_addr $ip $_maxbyte4 || \
				valid_ipv6_addr $ip; then
			if [[ ${ip} = *:* && ${ip} != */* ]]; then
				printf "$(gettext '%s is missing subnet prefix information.')\n" \
					$ip 1>&2
			else
				eval "$outarg=\"$valid_addr\""
				return 0
			fi
		fi
		printf "> "
		[[ -n "$def" ]] && printf "[%s]: " "$def"
	done

	eval $outarg=
	return 1
}


#############################################################################
#
# setup_C_network - Configure one SC External Community Network using IPMP
#
# $1 - Community Name (C1, C2, . . .)
#
# Called by setup_C_networks().
#
# 4736411 - Add Othello+ support
#
#############################################################################
setup_C_network()
{
	typeset -r COMNAME=$1
	typeset lmask="255.255.255.252"
	typeset L_NAME=$PLATFORM_NAME
	typeset fmt_accept=$(gettext '\nDo you want to accept these network settings?')
	typeset DEFNIC1
	typeset DEFNIC2
	typeset DEFNICS
	typeset fmt_defcommunity=$(gettext "\nDo you want to define this Community?")
	typeset resp
	typeset requireIPv

	#
	# Default NICs depend on whether we're on a Nordica or Othello+:
	# RFE 4736411
	#
	get_sc_board_type
	case $SCBOARDTYPE in
	1) # Nordica
		DEFNIC1="hme0"
		DEFNIC2="eri1"
		DEFNICS=" [$DEFNIC1 $DEFNIC2]"
		;;
	2) # Othello+
		DEFNIC1="eri0"
		DEFNIC2="eri3"
		DEFNICS=" [$DEFNIC1 $DEFNIC2]"
		;;
	*) # Unknown board--no defaults
		DEFNIC1=""
		DEFNIC2=""
		DEFNICS=""
		;;
	esac
	# End, RFE 4736411

	#
	# Display settings for this community and ask if we want to
	# keep or change the settings
	#
	get_sc_number
	printf "$(gettext "\nConfiguring External Network for Community %s.")\n" \
		$COMNAME
	if [[ -f "${TMPMANCONFIGFILE}" ]]; then
		if grep "^C" $TMPMANCONFIGFILE | grep "FLOATER-$COMNAME" \
				>/dev/null 2>&1; then
			while true ; do
				display_C_settings $COMNAME
				cat <<_END_MENU_

$(gettext "Do you want to:")
    1) $(gettext "Accept these network settings.")
    2) $(gettext "Edit these network settings.")
    3) $(gettext "Delete these network settings and go onto the next community.")

_END_MENU_
				printf "  > "
				read resp || return 0
				printf "\n"
				case $resp in
				1) return 0 ;;
				2) break;;
				3) # Delete hostname.<interface> and
				   # hostname6.<interface> files for these NICs
					awk '$2 ~ /SC-TEST-.*-'$COMNAME/' { split($2,a,"-");
					printf "/bin/rm -f '${HOSTNAME_BASE}'%s '${HOSTNAME_BASE6}'%s\n", a[3], a[3]}' \
						${TMPMANCONFIGFILE} >> $TMPCMDS

					ed $TMPMANCONFIGFILE >/dev/null 2>&1 <<_END_ED_
g/^C.*-$COMNAME[ 	]/d
w
q
_END_ED_
					return 0 ;;
				*) printf "%s\n\n" "$(gettext "Please select 1, 2, or 3.")"
					continue ;;
				esac
				break
			done
		else
			yes_or_no "$fmt_defcommunity" || return 1
		fi
	else
		yes_or_no "$fmt_defcommunity" || return 1
	fi

	[[ $COMNAME != C1 ]] && DEFNIC1="" DEFNIC2="" DEFNICS=""

	#
	# Loop forever until NICs are configured without error:
	#
	while true; do
		curnics=$(awk '$2 ~ /SC-TEST-.*-'$COMNAME/' { split($2,a,"-"); print a[3]}' \
			$TMPMANCONFIGFILE)
		if [[ -n "$curnics" ]]; then
			set $curnics
			DEFNIC1=$1 DEFNIC2=$2
			DEFNICS=" [$DEFNIC1 $DEFNIC2]"
		fi

		#
		# Get the device names for the NICs we are going to use for
		# this community (using IPMP)
		#

		# 4677418/4640632 begin
		gettext '\nTwo network interface controllers (NICs) are
required for IPMP network failover.\n' | fmt
		# 4677418/4640632 end

		printf "$(gettext 'Enter NICs associated with community %s%s: ')" \
				$COMNAME "$DEFNICS"
		read NIC1 NIC2 || return 0
		[[ -z "$NIC1" && -z "$NIC2" ]] && NIC1="$DEFNIC1" NIC2="$DEFNIC2"
		[[ -z "$NIC1" && -z "$NIC2" ]] && continue
		validate_nics $COMNAME "$NIC1" "$NIC2" || continue

		# Put any NICs that were assigned to this community, and are no
		# longer, in a list.  This list will be used later to delete
		# associated /etc/hostname.<nic> files.
		DELNICS=""
		for nic in $curnics; do
			echo $NIC1 $NIC2 | grep $nic > /dev/null \
				|| DELNICS="$DELNICS $nic"
		done

		#
		# Get information on the 1st of 2 NICs for use with IPMP:
		#
		if [[ -n "$NIC1" ]]; then
			NIC1_IP=""
			get_sc_number
			NIC1_HOSTNAME=$(awk '$2 == "SC-TEST-'$NIC1-$COMNAME'" {print $3}' \
						"$TMPMANCONFIGFILE")
			[[ -z $NIC1_HOSTNAME ]] && NIC1_HOSTNAME=$PLATFORM_NAME-sc${THIS_SC}-$NIC1
			printf "\n$(gettext 'Enter hostname for %s [%s]: ')" \
				$NIC1 $NIC1_HOSTNAME
			read tmpname
			if [[ $tmpname = NONE ]]; then
				gettext "NONE is allowed for domain exclusion in I1 network only.\n"
				continue
			fi
			[[ -n "$tmpname" ]] && NIC1_HOSTNAME=$tmpname

			# Loop forever until we get a valid IP address:
			tmp_ipaddr=$(gethostip ${NIC1_HOSTNAME} | awk '{print $1}')
			while [[ -z "$NIC1_IP" ]] ; do
				if [[ -z "$tmp_ipaddr" ]]; then
					printf "$(gettext 'Enter IP address for %s: ')" \
						$NIC1_HOSTNAME
					readip NIC1_IP "" $requireIPv \
						|| continue 2
				else
					printf "$(gettext 'Enter IP address for %s [%s]: ')" \
						$NIC1_HOSTNAME "$tmp_ipaddr"
					readip NIC1_IP "$tmp_ipaddr" \
						$requireIPv || continue 2
				fi
				[[ -z "$NIC1_IP" ]] && NIC1_IP="$tmp_ipaddr"
			done
		fi

		#
		# Get information on the 2nd of 2 NICs for use with IPMP:
		#
		if [[ -n "$NIC2" ]]; then
			NIC2_IP=""
			get_sc_number
			NIC2_HOSTNAME=$(awk '$2 == "SC-TEST-'$NIC2-$COMNAME'" {print $3}' \
				"$TMPMANCONFIGFILE")
			[[ -z $NIC2_HOSTNAME ]] && NIC2_HOSTNAME=$PLATFORM_NAME-sc${THIS_SC}-$NIC2
			printf "\n$(gettext 'Enter hostname for %s [%s]: ')" \
				$NIC2 $NIC2_HOSTNAME
			read tmpname
			if [[ $tmpname = NONE ]]; then
				gettext "NONE is allowed for domain exclusion in I1 network only.\n"
				continue
			fi
			[[ -n "$tmpname" ]] && NIC2_HOSTNAME=$tmpname

			# Loop forever until we get a valid IP address:
			tmp_ipaddr=$(gethostip ${NIC2_HOSTNAME} | awk '{print $1}')
			while [[ -z "$NIC2_IP" ]] ; do
				if [[ -z "$tmp_ipaddr" ]]; then
					printf "$(gettext 'Enter IP address for %s: ')" \
						$NIC2_HOSTNAME
					readip NIC2_IP "" $requireIPv \
						|| continue 2
				else
					printf "$(gettext 'Enter IP address for %s [%s]: ')" \
						$NIC2_HOSTNAME "$tmp_ipaddr"
					readip NIC2_IP "tmp_ipaddr" \
						$requireIPv || continue 2
				fi
				[[ -z "$NIC2_IP" ]] && NIC2_IP="$tmp_ipaddr"
			done
		fi

		#
		# Get the IPMP "floating" hostname and IP address for use
		# with this community:
		# 4677418/4640632: to avoid confusion, ask these questions
		# AFTER asking for the IP addresses of the 2 underlying NICs
		#
		FLOATER_IP=""
		FLOATER_HOSTNAME=$(awk '$2 == "SC-FLOATER-'$COMNAME'" {print $3}' \
			"$TMPMANCONFIGFILE")
		[[ -z "$FLOATER_HOSTNAME" ]] \
				&& FLOATER_HOSTNAME=$PLATFORM_NAME-sc-$COMNAME

		# 4677418/4640632 begin
		gettext '\nThe Logical/Floating IP hostname and address will
"float" over to whichever system controller (SC0 or SC1) is acting as
the main SC.\n' | fmt
		# 4677418/4640632 end

		printf "$(gettext 'Enter Logical/Floating IP hostname for community %s [%s]: ')" \
			"$COMNAME" "$FLOATER_HOSTNAME"
		read tmpname || continue
		if [[ $tmpname = NONE ]]; then
			gettext "NONE is allowed for domain exclusion in I1 network only.\n"
			continue
		fi
		[[ -n "$tmpname" ]] && FLOATER_HOSTNAME=$tmpname

		# Ask for and validate the "floating" IP address:
		tmp_ipaddr=$(gethostip ${FLOATER_HOSTNAME} | awk '{print $1}')
		if [[ -z "$tmp_ipaddr" ]]
		then
			while [[ -z "$FLOATER_IP" ]] ; do
				printf "$(gettext 'Enter IP address for %s: ')" \
					"$FLOATER_HOSTNAME"
				readip FLOATER_IP || continue 2
			done
		else
			printf "$(gettext 'Enter IP address for %s [%s]: ')" \
				"$FLOATER_HOSTNAME" "$tmp_ipaddr"
			readip FLOATER_IP "$tmp_ipaddr" || continue
			[[ -z "$FLOATER_IP" ]] && FLOATER_IP="$tmp_ipaddr"
		fi

		if [[ ${FLOATER_IP} = *:* ]]; then
			NETMASK="${FLOATER_IP#*/}"
		else
			# Loop forever until we get a valid IP netmask for
			# this community:
			NETMASK=""
			default_nmask=$(getent netmasks ${FLOATER_IP} \
					| head -1 | awk '{print $2}')
			while [[ -z "$NETMASK" ]] ; do
				if [[ -z "$default_nmask" ]]; then
					printf "$(gettext 'Enter netmask for community %s: ')" \
						"$COMNAME"
					readip NETMASK "" 4 || continue 2
				else
					printf "$(gettext 'Enter netmask for community %s [%s]: ')" \
						"$COMNAME" "$default_nmask"
					readip NETMASK "$default_nmask" 4 \
						|| continue 2
				fi
				[[ -z "$NETMASK" ]] && NETMASK="$default_nmask"
			done
		fi

		# Check to see if the IP address is IPv6 or IPv4:
		if [[ ${FLOATER_IP} = *:* ]]; then
			requireIPv="6"
		else
			requireIPv="4"
		fi

		#
		# Get Failover Address
		#
		# If more than one NIC is in the pathgroup, we need an IPMP
		# failover address for the group as well.
		# 4677418/4640632: to avoid confusion, ask these questions
		# AFTER asking for the IP addresses of the 2 underlying NICs
		#
		COMM_FAILOVER_IP=""
		COMM_FAILOVER_HOSTNAME=""
		if [[ -n "$NIC1" && -n "$NIC2" ]]; then
			[[ -f ${HOSTNAME_BASE6}$NIC1 ]] &&
				COMM_FAILOVER_HOSTNAME=$(awk '/addif/ {print $2; exit}' \
					${HOSTNAME_BASE6}$NIC1)
			[[ -f ${HOSTNAME_BASE}$NIC1 ]] &&
				COMM_FAILOVER_HOSTNAME=$(awk '/addif/ {print $2; exit}' \
					${HOSTNAME_BASE}$NIC1)
			[[ -z $COMM_FAILOVER_HOSTNAME ]] && get_sc_number && \
				COMM_FAILOVER_HOSTNAME=$PLATFORM_NAME-sc${THIS_SC}-$COMNAME-failover
			printf "\n$(gettext 'Enter hostname for community %s failover [%s]: ')" \
				$COMNAME $COMM_FAILOVER_HOSTNAME
			read tmpname || continue
			[[ -n "$tmpname" ]] && COMM_FAILOVER_HOSTNAME=$tmpname

			tmp_ipaddr=$(gethostip ${COMM_FAILOVER_HOSTNAME} \
				| awk '{print $1}')
			while [[ -z "$COMM_FAILOVER_IP" ]] ; do
				if [[ -z "$tmp_ipaddr" ]]; then
					printf "$(gettext 'Enter IP address for %s: ')" \
						$COMM_FAILOVER_HOSTNAME
					readip COMM_FAILOVER_IP "" \
						$requireIPv || continue 2
				else
					printf "$(gettext 'Enter IP address for %s [%s]: ')" \
						$COMM_FAILOVER_HOSTNAME "$tmp_ipaddr"
					readip COMM_FAILOVER_IP $tmp_ipaddr \
						$requireIPv || continue 2
				fi
				[[ -z "$COMM_FAILOVER_IP" ]] \
					&& COMM_FAILOVER_IP="$tmp_ipaddr"
			done
		fi

		# Display MAN.cf settings # and ask if they are OK
		# before writing them:
		auto_range_C_settings $COMNAME 0 \
					"$FLOATER_HOSTNAME" \
					"$FLOATER_IP" \
					"$NETMASK" \
					"$NIC1" \
					"$NIC1_HOSTNAME" \
					"$NIC1_IP" \
					"$COMM_FAILOVER_HOSTNAME" \
					"$COMM_FAILOVER_IP" \
					"$NIC2" \
					"$NIC2_HOSTNAME" \
					"$NIC2_IP"

		if yes_or_no "$fmt_accept"; then
			# Delete hostname.<nic> and hostname6.<nic> files for
			# any NICs that were just changed.
			for nic in $DELNICS; do
				echo "/bin/rm -f ${HOSTNAME_BASE}$nic ${HOSTNAME_BASE6}$nic" \
					>> $TMPCMDS
                        done

			# Write settings to MAN.cf
			auto_range_C_settings $COMNAME 1  \
					"$FLOATER_HOSTNAME" \
					"$FLOATER_IP" \
					"$NETMASK" \
					"$NIC1" \
					"$NIC1_HOSTNAME" \
					"$NIC1_IP" \
					"$COMM_FAILOVER_HOSTNAME" \
					"$COMM_FAILOVER_IP" \
					"$NIC2" \
					"$NIC2_HOSTNAME" \
					"$NIC2_IP"
			return 0
		fi
	done
}


#############################################################################
#
# setup_C_networks - Configure SC External Community Networks
#
# Note: almost all of the time there's either 0 or 1 community networks.
#
# Called by sms_man_setup() for part of smsconfig -m.
#
#############################################################################
setup_C_networks()
{
	typeset -i COMNUM=1
	cp /dev/null $TMPFOADDRS

	# Community names are hard-wired: C1, C2, ...
	COMNAME=C$COMNUM
	MAXCOMNUM=$(awk '
		BEGIN {max=0 }
		$2 ~ /SC-FLOATER-C*/ { n=substr($2, 13); if (n>max) max=n }
		END {print max}' $TMPMANCONFIGFILE)
	while setup_C_network $COMNAME || (( COMNUM < MAXCOMNUM )) ; do
		COMNUM=COMNUM+1
		COMNAME=C$COMNUM
	done
}


#############################################################################
#
# update_tmp_foaddrs
#
# Update temporary FailOver addresses;
# these will be used to update the /etc/inet/hosts file.
#
# Called by auto_range_C_settings().
#
# $1 - hostname
# $2 - IP address
#
#############################################################################
update_tmp_foaddrs()
{
	typeset hostname=$1
	typeset ipaddr=$2

	printf "%s %s\n" $hostname $ipaddr >> $TMPFOADDRS
}


#############################################################################
#
# auto_range_C_settings - Display the list of setting for the L MAN network
#
# Called by setup_C_network().
#
# $1 - community name
# $2 - 0 = nowrite; 1 = write MAN.cf
# $3 - Logical (floating) IP hostname
# $4 - Logical (floating) IP address
# $5 - Netmask for community
# $6 - NIC1 device name (e.g. eri1)
# $7 - NIC1 hostname
# $8 - NIC1 IP address
# $9 - Community IPMP failover hostname
# $10 - Community IPMP failover IP address
# $11 - NIC2 device name (e.g. hme0 for Nordica or eri0 for Othello+)
# $12 - NIC2 hostname
# $13 - NIC2 IP address
#
#############################################################################
auto_range_C_settings()
{
	typeset -r commname=$1
	typeset -ri write_change=$2
	typeset -r floathost=$3
	typeset -r floatipaddr=$4
	typeset -r commmask=$5
	typeset -r nic1name=$6
	typeset -r nic1host=$7
	typeset -r nic1ipaddr=$8
	typeset -r failoverhost=$9
	shift 4
	typeset -r failoveripaddr=$6
	typeset -r nic2name=$7
	typeset -r nic2host=$8
	typeset -r nic2ipaddr=$9
	typeset -r s_fmt="%-20s\t%-15s\t%s\n"
	typeset -r _fmt="%s\t%s\t%s\t%s\n"
	typeset -r _ipnext

	if [[ $write_change -eq 0 ]]; then
		print
		printf "${s_fmt}" "$(gettext 'Hostname')" \
			"$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
		printf "${s_fmt}" '--------' '----------' ''
	else
		if [[ -f $TMPMANCONFIGFILE ]];then
			sed -e "/^C.*-${commname}[ 	]/d" $TMPMANCONFIGFILE \
				>| $TMPMANCONFIGFILE.$$
			mv -f $TMPMANCONFIGFILE.$$ $TMPMANCONFIGFILE
		elif [[ -f $MANCONFIGFILE ]];then
			sed -e "/^C.*-${commname}[ 	]/d" $MANCONFIGFILE \
				>| $TMPMANCONFIGFILE
		fi
	fi

	flcol2=SC-FLOATER-$commname
	flcol3=$floathost
	flcol4=$floatipaddr

	t1col2=SC-TEST-$nic1name-$commname
	t1col3=$nic1host
	t1col4=$nic1ipaddr

	focol2=SC-FAILOVER-$commname
	focol3=$failoverhost
	focol4=$failoveripaddr

	t2col2=SC-TEST-$nic2name-$commname
	t2col3=$nic2host
	t2col4=$nic2ipaddr

	if [[ $write_change -eq 1 ]]; then
		#
		# Note we don't add the IPMP failover address to any files, but
		# do display it in the else part.
		#
		printf "${_fmt}" C $flcol2 $flcol3 $flcol4 >>${TMPMANCONFIGFILE}
		if [[ -n "$nic1host" ]];  then
			printf "${_fmt}" C $t1col2 $t1col3 "" >>${TMPMANCONFIGFILE}
			update_tmp_foaddrs $nic1host $nic1ipaddr
			if [[ -n "$failoverhost" ]]; then
				if [[ ${nic1ipaddr} = *:* ]]; then
					echo echo $nic1ipaddr deprecated -failover group $commname up\> ${HOSTNAME_BASE6}$nic1name \
						>> ${TMPCMDS}
					echo echo addif $failoveripaddr up\>\> ${HOSTNAME_BASE6}$nic1name \
						>> ${TMPCMDS}
				else
					echo echo $nic1ipaddr deprecated -failover netmask + broadcast + group $commname up\> ${HOSTNAME_BASE}$nic1name \
						>> ${TMPCMDS}
					echo echo addif $failoveripaddr netmask + broadcast + up\>\> ${HOSTNAME_BASE}$nic1name \
						>> ${TMPCMDS}
				fi
			else
				if [[ ${nic1ipaddr} = *:* ]]; then
					echo echo $nic1ipaddr -failover group $commname up\> ${HOSTNAME_BASE6}$nic1name \
						>> ${TMPCMDS}
				else
					echo echo $nic1ipaddr -failover netmask + broadcast + group $commname up\> ${HOSTNAME_BASE}$nic1name \
						>> ${TMPCMDS}
				fi
			fi
		fi
		[[ -n "failoverhost" && -n "$failoveripaddr" ]] &&
			update_tmp_foaddrs $failoverhost $failoveripaddr
		if [ -n "$nic2host" ];  then
			printf "${_fmt}" C $t2col2 $t2col3 "" >>${TMPMANCONFIGFILE}
			update_tmp_foaddrs $t2col3 $t2col4
			if [[ ${nic1ipaddr} = *:* ]]; then
				echo echo $nic2ipaddr deprecated -failover group $commname up\> ${HOSTNAME_BASE6}$nic2name \
					>> ${TMPCMDS}
			else
				echo echo $nic2ipaddr deprecated -failover netmask + broadcast + group $commname up\> ${HOSTNAME_BASE}$nic2name \
					>> ${TMPCMDS}
			fi
		fi
	else
		printf "${s_fmt}" $flcol3 $flcol4
		if [[ -n "$failoverhost" ]]; then
			printf "${s_fmt}" $focol3 $focol4 ""
		fi
		if [[ -n "$nic1host" ]];  then
			printf "${s_fmt}" $t1col3 $t1col4 ""
		fi
		if [[ -n "$nic2host" ]];  then
			printf "${s_fmt}" $t2col3 $t2col4 ""
		fi
	fi
}


#############################################################################
#
# display_C_settings - Display the list of setting for the C MAN network
#
# $1 - Community name
#
#############################################################################
display_C_settings()
{
	typeset s_fmt="%-20s\t%-15s\t%s\n"
	typeset -r COMMNAME="$1"
	typeset -r OFMT="%-20s\t%-15s\n"

	printf "${s_fmt}" "$(gettext 'Hostname')" "$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
	printf "${s_fmt}" '--------' '----------' ''
	awk 'BEGIN { OFS="\t";OFMT="'"$OFMT"'";}
/^C/ && /-'$COMMNAME'[ 	]/ {
split($0, i1)
printf OFMT, i1[3],i1[4]
}' $TMPMANCONFIGFILE | while read line; do
			set $line
			case $# in
			1) printf "$OFMT" "$1"  $(gethostip "$1") ;;
			*) echo "$line" ;;
			esac
		done
}


#############################################################################
#
# gethostip()
#
# Get the host IP address using getent(1M).
# If multiple entries exist, use the first one found.
#
# If hostname is set to "NONE", print "NONE" to stdout
#
# $1 - Host name to lookup.
#
# Return result in stdout.
#
#############################################################################
gethostip()
{
	typeset -r hn=$1
	typeset ip

	if [[ "$hn" = NONE ]]; then
		echo NONE
		return 0
	fi

	if [[ -n "$DEBUG" ]]; then # for debug use only
		ip=$(awk '/[ 	]'$hn'[ 	]/ || /[ 	]'$hn'$/ { print $1 }' \
			$ETCHOSTSFILE | head -1)
		if [[ -n "$ip" ]] ; then
			echo $ip
			return 0
		fi
	fi

	getent_hosts_uniq $hn
}


#############################################################################
#
# parse_man_cf
#
# Reads an existing MAN.cf file and displays (optionally) output
# Creates temporary MAN.cf copy.
#
# Called by sms_man_setup() for part of smsconfig -m.
#
#############################################################################
parse_man_cf()
{
	typeset -i _disp=$1

	if [[ ! -f $MANCONFIGFILE ]]; then     #no file
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
		printf "$(gettext "%s: MAN configuration file not found!")\n" \
			$command
		get_platform_name PLATFORM_NAME
		return 0
	else
		cp $MANCONFIGFILE $TMPMANCONFIGFILE
		# read current platform name
		PLATFORM_NAME=`grep -v "^#" $TMPMANCONFIGFILE | head -1 `
	fi
	if [[ $_disp -eq 1 ]]; then
	typeset s_fmt="%14s\t%15s\t%s\n"

	printf "${s_fmt}" "$(gettext 'Hostname')" "$(gettext 'IP Address')" \
			"($(gettext 'Platform') = $PLATFORM_NAME)"
	printf "${s_fmt}" '--------' '----------' ''
	awk 'BEGIN { OFS="\t";OFMT="%14s\t%15s\n";}
/^I1/{
split($0, i1)
printf OFMT, i1[3],i1[4]
}
/^I2/{
split($0, i2)
printf OFMT, i2[3],i2[4]
}
/^C/{
split($0, cx)
printf OFMT, cx[3],cx[4]
}' $TMPMANCONFIGFILE
	fi
}


#############################################################################
#
# set_single_man_netid
#
#  $1: network to set up
#  $2: entity on that net
#
#############################################################################
set_single_man_netid()
{
	typeset -u _net=$1
	typeset -u _id=$2
	typeset _intface
	typeset write_new_ifconfig=0
	typeset -i SCHANGE=0
	typeset _ip
	typeset requireIPv
	typeset lookupid
	typeset _nmnet
	typeset _nmintface
	typeset _nmhostname
	typeset _mask
	typeset ilookup
	typeset -x valid_addr

	case $_net in

		[Ii]1)
			case $_id in
				[Ss][Cc]) lookupid="SC"
					write_new_ifconfig=1
					;;
				[A-R]|[a-r]) lookupid=D${_id}
					;;
				[Nn][Ee][Tt][Mm][Aa][Ss][Kk]) lookupid="NM"
					;;
				*)
					command="smsmanopt"
					exclusive_lock UNLOCK smsconfig
					usage
					exit 2
					;;
			esac
			;;
		[Ii]2)
			case $_id in
				[Ss][Cc]0) lookupid="SC0"
					;;
				[Ss][Cc]1) lookupid="SC1"
					;;
				[Nn][Ee][Tt][Mm][Aa][Ss][Kk]) lookupid="NM"
					;;
				*)
					command="smsmanopt"
					exclusive_lock UNLOCK smsconfig
					usage
					exit 2
					;;
			esac
			;;
		L|l)
			case $_id in
				*)
					command="smsmanopt"
					exclusive_lock UNLOCK smsconfig
					usage
					exit 2
					;;
			esac
			;;
	esac
	_intface=${lookupid}-${_net}
#	grep "$_intface" $MANCONFIGFILE
	print
	_hostname=${lookupid}-${_net}
	_ip=""
	if [[ -f $MANCONFIGFILE ]]; then
		ilookup=`grep $_intface $MANCONFIGFILE `
		if [[ -n $ilookup ]]; then
			echo $ilookup |awk '{print $1,$2,$3,$4}'|\
				read  _net _intface _hostname _ip
		fi
	fi
	if [[ -z "${_ip}" ]]; then
		requireIPv=""
	else
		if [[ ${_ip} = *:* ]]; then
			requireIPv="6"
		else
			requireIPv="4"
		fi
	fi
	while true;
	do
		while true;
		do
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
			printf "$(gettext 'Enter the MAN hostname for %s [ %s ]: ')" \
					$_intface $_hostname
			get_valid_hostname $_hostname HNAME $_net
			if [[ -n "$HNAME" ]]; then
				_hostname=${HNAME}
				HNAME=""
				SCHANGE=1
				break
			fi
		done
		if [[ $_hostname = NONE ]]; then
			_ip=NONE
		elif ! lookup_ip_addr $_hostname _ip; then
			get_ip_addr $_hostname _ip $requireIPv
		else
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
			printf "$(gettext 'Enter the MAN IP address for %s [ %s ]: ')" \
					$_intface $_ip
			readip ans $_ip $requireIPv 255
			if [[ -n "$ans" ]]; then
				_ip=$ans
				SCHANGE=1
			fi
		fi
		printf "$(gettext "\nNetwork: %s ")" $_net
		echo $_intface
		printf "$(gettext "Hostname: %s  ")" $_hostname
		printf "$(gettext "IP Address: %s")\n\n" $_ip
		if [[ $SCHANGE -eq 1 ]]; then
			fmt=$(gettext "Do you want to accept these settings?")
			if yes_or_no "$fmt";then
				if [[ -n $ilookup ]]; then
					# IPv6 address contains "/" so sed needs a different separator
					sed -e "s#${ilookup}#$_net	$_intface	$_hostname	$_ip#" \
                      $MANCONFIGFILE >|$TMPMANCONFIGFILE
				else
					echo "$_net\t$_intface\t$_hostname\t$_ip" >> $TMPMANCONFIGFILE
				fi
				if [[ $write_new_ifconfig -eq 1 ]]; then
					i1masklookup=`grep NM-I1 $TMPMANCONFIGFILE `
					if [[ -n $i1masklookup ]]; then
						echo $i1masklookup |awk '{print $1,$2,$3,$4}'|\
							read  _nmnet _nmintface _nmhostname _mask
						write_ifconfig_file ${I1_IFCONFIG_IFACE} ${_ip} ${_mask}
					else
						fatal "$(printf "$(gettext "%s: Invalid netmask for I1 network.")\n" $command)"
					fi
				fi
				break;
			fi
		else
			printf "$(gettext "%s: No changes made.")\n" $command
			break;
		fi
	done
}



#############################################################################
#
# get_backup_destination - prompts the user for the name of the directory
# to store the backup in - or the name of the tape device.
#
#############################################################################
get_backup_destination()
{
	typeset _ans
	typeset _default
	typeset _fmt

	_default="/var/tmp"
	printf "$(gettext \
'To move to a different version of SMS an archive of critical files will be
created. What is the name of the directory or tape device where the archive
will be stored? [%s] ')" \
		$_default | fmt -w 55

	read _ans
        #  Check for null string
	if [[ -z "$_ans" ]]; then
		_ans="$_default"
	fi
        # Pass the answer and the version number
	validate_backup_args "$_ans" $1
}


#############################################################################
#
# validate_backup_args
#
# Validate that the argument to sms_backup is a valid directory
# Save target file or tape as $SMS_BACKUP
# Handle special cases of . ./ .. ../ by converting to absolute directories.
# Abort if the target is not a directory or tape device. 4634829
#
# Parameters:
# $1 is the backup destination directory or tape device
# $2 is the backup version
#
#############################################################################
validate_backup_args()
{
	typeset filename_cpio=sms_backup.${2}.cpio
	typeset destdir=${1}

	if [ -d "$destdir" ]; then
		/usr/bin/df -F ufs "$destdir" 2>&1 | \
		/usr/bin/grep "mounted as a tmpfs file system" > /dev/null 2>&1

		if [ $? -eq 0 ]; then
			fatal "$(printf "$(gettext \
'%s: cannot backup to a TMPFS filesystem, %s.  Please specify a directory that is mounted on a UFS filesystem.')\n" \
				$command $destdir)"
		fi

		# Convert relative directory to absolute directory 4633179
		# begin, 4633179/ 4634829
		case "$destdir" in
		.)	destdir=$(pwd)
			;;
		./)	destdir=$(pwd)
			;;
		..)	destdir=$(dirname $(pwd))
			;;
		../)	destdir=$(dirname $(pwd))
			;;
		./*)	destdir=$(pwd)/$(print $destdir | cut -f2 -d/ )
			;;
		../*)	destdir=$(dirname $(pwd))/$(print $destdir|cut -f2 -d/)
			;;
		/*)	destdir=$destdir # Absolute
			;;
		*)	destdir=$(pwd)/$destdir # Under current directory
			;;
		esac
		# end, 4633179/ 4634829

		# form backup filename: <specified directory>/sms_backup.cpio
		SMS_BACKUP=${destdir}/${filename_cpio} # 4633179/ 4634829
		if [ -a ${SMS_BACKUP} ]; then
			rotate_file ${SMS_BACKUP} 6
		fi

	else # Not directory, check if tape
		# begin, 4633179/ 4634829
		mt -f "$destdir" status > /dev/null 2>&1
		if [ $? -ne 0 ]; then # not a directory or tape 4634829
			fatal "$(printf \
"$(gettext '%s: Invalid backup destination %s is not a directory or tape device.')\n" \
					$command $destdir)"
		else
			SMS_BACKUP="$destdir"
		fi
		# end, 4633179/ 4634829
	fi
}


#############################################################################
#
# set_convert_flag
# This function checks the active version and the backup versions
#  and identifies if the backup version is going to be lower than
#  the active version.
#
# Parameters
# Takes the backup version and the only parameter
# Stores the output in global CONVERT_FLAG
#   0 indicates that backup is greater or equal
#   1 indicates that backup is less
#
#############################################################################
set_convert_flag()
{
   typeset BACKUP_SMS_VERSION=$1
   typeset back_major
   typeset active_major
   typeset back_minor
   typeset active_minor

   # global flag used by smsbackup to detect if
   #  file conversion is necessary
   CONVERT_FLAG=0

   # Restore to different version than was used to back up.
   back_major=${BACKUP_SMS_VERSION%.[0-9]}
   back_minor=${BACKUP_SMS_VERSION#[0-9].}
   active_major=${ACTIVE_SMS_VERSION%.[0-9]}
   active_minor=${ACTIVE_SMS_VERSION#[0-9].}
   if [[ ${back_major} -gt ${active_major} ]]; then
      # If the version we are switching to is higher
      CONVERT_FLAG=0
   elif [[ ${back_major} -lt ${active_major} ]]; then
      # If the version we are switching to is lower
      CONVERT_FLAG=1
   elif [[ ${back_minor} -lt ${active_minor} ]]; then
      # less
      CONVERT_FLAG=1
   else
      # greater or equal
      CONVERT_FLAG=0
   fi
}


#############################################################################
#
# create_cpio
#
# Generate a file list to send to cpio, which archives the files into
# the specified directory as filename sms_backup.#.#.cpio or to the magnetic
# tape device.
#
#############################################################################
create_cpio()
{
        typeset SMSOPT=${ROOT}/opt/SUNWSMS
        typeset SMSETC=${ROOT}/etc/opt/SUNWSMS
        typeset SMSVAR=${ROOT}/var/opt/SUNWSMS
	typeset SMSHOME=${ROOT}/export/home/sms-svc

	# Get the list of files into cpio, stripping off leading "/"
	# Note: the "\" MUST be the last character in continuation lines.
	(umask 177; cd $ROOT/; find \
        ${SMSOPT}/SMS \
        ${SMSOPT}/bin/scp \
        ${SMSOPT}/bin/ssh \
        ${SMSHOME}/.sms_env \
	${SMSHOME}/.cshrc \
	${SMSHOME}/.login \
	$GROUPCONFIGFILE \
	${SMSETC}/config/.postrc \
	${SMSETC}/config/MAN.cf \
	${SMSETC}/config/platform/.postrc \
	${SMSETC}/config/platform/blacklist \
	${SMSETC}/config/dsmd_tuning.txt \
	${SMSETC}/config/esmd_tuning.txt \
	${SMSETC}/config/fomd.cf \
	${SMSETC}/config/fomd_sys_datasync.cf \
	${SMSETC}/config/kmd_policy.cf \
	${SMSETC}/config/platform/.postrc \
	${SMSETC}/config/platform/blacklist \
	${SMSETC}/config/[A-R]/.postrc \
	${SMSETC}/config/[A-R]/blacklist \
	${SMSETC}/config/[A-R]/dsmd_tuning.txt \
	${SMSETC}/startup/ssd_start \
	${SMSETC}/startup/sms_env.sh \
	${SMSVAR}/.pcd/domain_info \
	${SMSVAR}/.pcd/platform_info \
	${SMSVAR}/.pcd/sysboard_info \
	${SMSVAR}/adm/.logger \
	${SMSVAR}/adm/[A-R]/console \
	${SMSVAR}/adm/[A-R]/console.[0-9] \
	${SMSVAR}/adm/[A-R]/messages \
	${SMSVAR}/adm/[A-R]/messages.[0-9] \
	${SMSVAR}/adm/[A-R]/anonymous/dump/* \
	${SMSVAR}/adm/[A-R]/anonymous/post/* \
	${SMSVAR}/adm/[A-R]/dump/* \
	${SMSVAR}/adm/[A-R]/post/* \
	${SMSVAR}/adm/platform/messages \
	${SMSVAR}/adm/platform/messages.[0-9] \
	${SMSVAR}/data/.wcapp/Domains.ncslices \
	${SMSVAR}/data/osdTimeDeltas \
	${SMSVAR}/data/[A-R]/.dxsPort \
	${SMSVAR}/data/[A-R]/nvramdata \
	${SMSVAR}/data/[A-R]/idpromdata \
	${SMSVAR}/data/[A-R]/idprom.image \
	${SMSVAR}/data/[A-R]/bootparamdata \
        ${SMSVAR}/data/.cod/license_info \
        ${SMSVAR}/data/.failover/fomd/fomd_usr_datasync.cf \
        ${SMSVAR}/data/[A-R]/fmnodeid \
	${SMSVAR}/data/[A-R]/w* \
	-print 2> /dev/null \
		| sed -e "s#${ROOT}/##" \
		| cpio -Pocv -O ${SMS_BACKUP} >> ${LOG_FILE} 2>&1 )

	CPIO_STAT=$?
	if [[ $CPIO_STAT != 0 ]]; then
		fatal "$(printf "$(gettext "%s: backup failed, see log: %s")\n" \
			$command $LOG_FILE)"
	fi

}


#############################################################################
#
# perform_backup
#
# This covers two cases
#
# Case 1
# This case covers when smsversion is called and a backup file compatible
#  with the previous version is needed
#  A cpio is created and dumped to a temporary directory
#  The the contents are converted using fileconvert (command)
#  The contents are cpioed up into the final backup file
#
# Case 2
# This is the case for a normal backup of the current active version
#   A cpio file is created as the backup file
#
#############################################################################
perform_backup()
{
   typeset TEMP_BACKUP="/var/tmp/tmp_cpio_backup$$"
   typeset TEMP_DIR="/var/tmp/temproot$$"

   # Case 1
   # If CONVERT_FLAG is set then we know we need to create a backup file
   #  formatted for the previous version of SMS
   if [[ ${CONVERT_FLAG} -eq 1 ]]; then
      # Prepare for the backup process by cleaning up
      /usr/bin/rm -rf $TEMP_DIR
      /usr/bin/rm -f $TEMP_BACKUP

      # Backup the SMS_BACKUP variable so that we can change the value
      SMS_BACKUP_ORIG=${SMS_BACKUP}
      SMS_BACKUP=$TEMP_BACKUP

      # Create the temporary backup file
      create_cpio

      # Restore the final SMS_BACKUP value
      SMS_BACKUP=${SMS_BACKUP_ORIG}

      # Dump out the cpio file
      /usr/bin/mkdir $TEMP_DIR
      cd $TEMP_DIR
      cpio -Picvdum -I ${TEMP_BACKUP} >> ${LOG_FILE} 2>&1
      if [[ $? -ne 0 ]]; then
         /usr/bin/rm -rf $TEMP_DIR
         /usr/bin/rm -f $TEMP_BACKUP
         fatal "$(printf "$(gettext "%s: The command cpio failed causing backup to fail.")\n" $command)"
         print
      fi

      # Delete the temporary cpio file
      /usr/bin/rm -f $TEMP_BACKUP

      # Call the file conversion script if necessary
      /opt/SUNWSMS/lib/smsadmin/fileconvert -c -d $TEMP_DIR
      if [[ $? -ne 0 ]]; then
         # cd to root or the rm will fail since it is the active directory
         cd /
         /usr/bin/rm -rf $TEMP_DIR
         fatal "$(printf "$(gettext "%s: File conversion failed causing backup to fail.")\n" $command)"
         print
      fi

      # Backup the root value
      SMS_ROOT_ORIG=${ROOT}
      # Assign the new root value
      ROOT=$TEMP_DIR

      print "SMS backup filename: $SMS_BACKUP\n" >> ${LOG_FILE}
      # Create the file cpio backup file
      create_cpio

      # Restore the ROOT value
      ROOT=${SMS_ROOT_ORIG}

      # We need to move our active location since we cannot delete
      #  the temp directory if we are in it (it will fail)
      cd $ROOT
      # Remove the SMS directories
      /usr/bin/rm -rf $TEMP_DIR
   else
      # This is case 2 we are simply backing up the current
      #  settings
      print "SMS backup filename: $SMS_BACKUP\n" >> ${LOG_FILE}
      create_cpio
   fi


   if [[ -f ${SMS_BACKUP} ]]; then
      printf "$(gettext "%s: Backup configuration file created: %s")\n" $command $SMS_BACKUP
   else
      printf "$(gettext "%s: Backup to tape succeeded: %s")\n" $command $SMS_BACKUP
   fi


}


#############################################################################
#
# validate_restore_args
#
# Validate that the argument to sms_restore is a valid filename
#
#############################################################################
validate_restore_args()
{
	sms_restore_filename=${1}

	if [ ! -f $1 ]
	then
		# Not file, check if tape
		mt -f $1 status > /dev/null 2>&1
		if [ $? -ne 0 ]
		then
			fatal "$(printf "$(gettext "%s: Invalid restore source specified.")\n" $command)"
			print
		fi
	fi
}


#############################################################################
#
# restore_acls
#
# Restore the acls by reading the /etc/group file and calling
# facl_add_user which will set the file values
#
#############################################################################
restore_acls()
{
   typeset COUNTER
   typeset INNER
   typeset numusers
   typeset userids
   typeset individual
   typeset dmnjob
   typeset dmnstring
   typeset facl_cmd_arg_old
   typeset facl_username_old
   typeset facl_domain_id_old
   typeset facl_sms_group_old
   typeset facl_run_mode_old

   # This is the platform user roles in the /etc/group file
   set -A people platadmn platoper platsvc
   # These are the name of the roles as passed to the smsconfig command
   set -A job admn oper svc

   # Backup of some globals since they will get modified
   facl_cmd_arg_old=$FACL_CMD_ARG
   facl_username_old=$FACL_USERNAME
   facl_domain_id_old=$FACL_DOMAIN_ID
   facl_sms_group_old=$FACL_SMS_GROUP
   facl_run_mode_old=$FACL_RUN_MODE


   # Step through the list platform roles and scan the /etc/group file
   COUNTER=0
   while (( $COUNTER < ${#people[*]} )) do
      # Find the users assigned to each role in the file
      # This can be optimized
      numusers=`cat $ETCGROUPFILE |grep "^${people[$COUNTER]}" | \
                awk -F:  '{print $4}' | sed -e 's,\,,'" "',g' | wc -w`

      userids=`cat $ETCGROUPFILE |grep "^${people[$COUNTER]}" | \
               awk -F: '{print $4}' | sed -e 's,\,,'" "',g'`

      # For each user we have to reinitialize his facls
      INNER=1
      while (( $INNER <= ${numusers} )) do
         # Grab the name out of the list
         individual=`print $userids | awk '{print $'$INNER'}'`

         # Set the global values for a platform user
         # The facl_add_user is a function for the smsconfig -a command
         # We cannot call the smsconfig command directly due to a locking
         #  variable
         FACL_CMD_ARG="platform"
         FACL_USERNAME="$individual"
         FACL_DOMAIN_ID="platform"
         FACL_SMS_GROUP="${job[$COUNTER]}"
         FACL_RUN_MODE="add-user"

         # Add user's facls
         facl_add_user >> $LOG_FILE
         let INNER=$INNER+1
      done

      let COUNTER=$COUNTER+1
   done

   # The list of all the domains
   set -A dmnletters a b c d e f g h i j k l m n o p q r
   # Contains the two roles for a domain user admn and rcfg
   dmnjob="admn"

   # Loop through all the domain and reactivate their facls
   COUNTER=0
   while (( $COUNTER < ${#dmnletters[*]} )) do
      # The string used to identify the roles in the group file
      #   dmn[a-r][admn-rcfg]
      dmnstring="dmn"${dmnletters[$COUNTER]}$dmnjob

      # Find the list of the domain's users
      numusers=`cat $ETCGROUPFILE |grep $dmnstring | \
                awk -F:  '{print $4}' | sed -e 's,\,,'" "',g' | wc -w`
      userids=`cat $ETCGROUPFILE |grep $dmnstring | \
               awk -F: '{print $4}' | sed -e 's,\,,'" "',g'`

      # Loop through all the users activating their facls
      INNER=1
      while (( $INNER <= ${numusers} )) do
         # Get a user from the list
         individual=`print $userids | awk '{print $'$INNER'}'`

         # Set all the global variables for a domain user
         # The facl_add_user is a function for the smsconfig -a command
         # We cannot call the smsconfig command directly due to a locking
         #  variable
         FACL_CMD_ARG="${dmnletters[$COUNTER]}"
         FACL_USERNAME="$individual"
         FACL_DOMAIN_ID=`echo $FACL_CMD_ARG |/usr/bin/tr "[a-r]" "[A-R]"`
         FACL_SMS_GROUP="$dmnjob"
         FACL_RUN_MODE="add-user"

         # Set the user facls
         facl_add_user >> $LOG_FILE
         let INNER=$INNER+1
      done

      # Set all the domain admn users then do all the domain rcfg users
      let COUNTER=$COUNTER+1
      if (( $COUNTER == ${#dmnletters[*]} )) && [[ $dmnjob == "admn" ]] then
         dmnjob="rcfg"
         COUNTER=0
      fi


   done

   # Restore all the global values
   FACL_CMD_ARG=$facl_cmd_arg_old
   FACL_USERNAME=$facl_username_old
   FACL_DOMAIN_ID=$facl_domain_id_old
   FACL_SMS_GROUP=$facl_sms_group_old
   FACL_RUN_MODE=$facl_run_mode_old
}


#############################################################################
#
# perform_restore
#
# This function does a lot more than it used to.  It fixes the .fomd_uids.cf
# problem (redundant in SMS1.3 but left jic
#
# Restore Case 1
# If the backup version and the active version are the same the backup file
#   is simply dumped over the existing installation.
#   No attempt is made to preserve existing information
#
# Restore Case 2
# This case handles when the backup file is one level down from the active
#   installation.  I have hard coded the values to force review of this
#   code for SMS1.4
#   The backup file is dumped to a temporary directory.  The files are
#   converted to the current format using fileconvert (command)
#   The files are then bundled up using cpio and a list of files stored
#   in the temp file (output of cpio from the previous dump)
#   A second cpio is used to prevent trashing of the directory permissions
#   as would be experienced with tar
#   The second cpio file is then dumped onto the root directory structure
#
# Restore Case 3
# Anything else is an error
#
#############################################################################
perform_restore()
{

   typeset fomduid_name=".fomd_uids.cf"
   typeset fomduidfile="${SMSETC}/SMS${ACTIVE_SMS_VERSION}/config/.fomd_uids.cf"
   typeset fomduid_temp="/var/tmp/.fomd_uids.cf"
   typeset path_name

   # Workaround for bugid 4633197 the .fomd_uids.cf file is missing
   #  after an upgrade when a previous SMS version exists

   # If the .fomd_uids.cf file does not exist
   if [[ ! -a ${fomduidfile} ]]; then
      # If the file is still in temp directory from SUNWSMSr postinstall
      if [[ -a ${fomduid_temp} ]]; then
         # Move the file to the correct location
         /bin/mv ${fomduid_temp} ${fomduidfile} >/dev/null 2>&1
         if [[ $? -ne 0 ]]; then
            printf "$(gettext 'Warning: Attempt to move %s to %s failed.\\n')" \
		${fomduid_temp} ${fomduidfile}
            gettext "SMS should not be started without this file.\n"
         else
            # Set the correct file permissions
            /bin/chown root:sys ${fomduidfile}
            /bin/chmod 0400 ${fomduidfile}
         fi
      else
         # Scan the whole /etc/opt/SUNWSMS part of the disk for the
         #   files and take the last one which should be the most recent
         path_name=`/bin/find ${SMSETC} -name ${fomduid_name} -depth | tail -1`

         # Check to see if we found a replacement file
         if [[ -a ${path_name} ]]; then
            # Copy the file to the empty location
            /bin/cp ${path_name} ${fomduidfile} >/dev/null 2>&1
            if [[ $? -ne 0 ]]; then
               printf "$(gettext 'Warning: Attempt to copy %s to %s failed.')\n" \
			${fomduid_temp} ${fomduidfile}
               gettext "SMS should not be started without this file.\n"
            else
               # Set the correct file permissions
               /bin/chown root:sys ${fomduidfile}
               /bin/chmod 0400 ${fomduidfile}
            fi
         else
            # Print an error if we cannot find a replacement file
            printf "$(gettext 'Warning: Missing %s.')\n" ${fomduidfile}
            gettext "SMS should not be started without this file.\n"
         fi # Replacement file
      fi # Temporary file
   fi # Main if, original check


   # We have to search the backup file for the version since an
   #    SMS1.1 backfiles cannot be dumped to a temp directory since
   #    they have absolute paths
   BACKUP_SMS_VERSION=`cat ${sms_restore_filename} |grep SMS_VERSION=SMS | sed -e 's,=SMS,'" "',g' | awk '{print $2}'`

   # Check to see if we found a version
   if [[ -z $BACKUP_SMS_VERSION ]]; then
      fatal "$(printf "$(gettext "%s: Unable to restore archive version identifier: %s.")\n" $command $sms_restore_filename)"
   fi

   # Restoring to the same version
   if [[ $BACKUP_SMS_VERSION = $ACTIVE_SMS_VERSION ]]; then
      # Restore same version than was used to back up
      ( cd $ROOT/; cpio -Picvdum -I ${sms_restore_filename} -f ${SMSOPT#${ROOT}/}/SMS >>${LOG_FILE} 2>&1 )
      if [[ $? -ne 0 ]]; then
         fatal "$(printf "$(gettext "%s: Unable to restore archive: %s.")\n" $command $sms_restore_filename)"
      fi

      # The ACLs are not necessarily reconfigured when we restore the files
      #  so this function restores them
      restore_acls
      # No file changes after calling restore_acls
   else
   # Restore to different versions

      typeset TEMP_ROOT=/var/tmp/temproot$$
      typeset TEMP_CPIO=/var/tmp/backup_cpio.$$
      typeset TEMP_LOG=/var/tmp/cpio_temp_log$$

      # If you are working on this code
      #  become well informed about all issues before making changes
      # This case covers when a prior version backup is being restored on the
      #  current installation.
      if [[ $BACKUP_SMS_VERSION = 1.2 && $ACTIVE_SMS_VERSION = 1.3 ]]; then

         # Cleanup the stray log, if we can't then we cannot continue
         #  since it will interfere with our ability to track which files
         #  were backed up.
         /usr/bin/rm -rf ${TEMP_LOG}
         if [[ $? -ne 0 ]]; then
            fatal "$(printf "$(gettext "%s: Unable to clear file /var/tmp/cpio_temp_log.")\n" $command)"
         fi

         # Cleanup any stray files or directories left from a previous run
         /usr/bin/rm -rf ${TEMP_ROOT}
         /usr/bin/rm -f ${TEMP_CPIO}

         # Make the temp directory
         /usr/bin/mkdir "${TEMP_ROOT}"
         if [[ $? -ne 0 ]]; then
            fatal "$(printf "$(gettext "%s: Command /usr/bin/mkdir failed.")\n" $command)"
         fi

         # Dump out the cpio file into the temp directory
         (cd ${TEMP_ROOT}; cpio -Picvdum -I ${sms_restore_filename} \
				-f ${SMSOPT#${ROOT}/}/SMS >> ${TEMP_LOG} 2>&1 )
         if [[ $? -ne 0 ]]; then
            /usr/bin/rm -rf ${TEMP_ROOT}
            /usr/bin/rm -f ${TEMP_LOG}
            fatal "$(printf "$(gettext "%s: Attempt to decompress %s was unsuccessful.")\n" $command $sms_restore_filename)"
         fi

         # Convert all the files that fileconvert has listed
         /opt/SUNWSMS/lib/smsadmin/fileconvert -p -d "${TEMP_ROOT}" >/dev/null 2>&1
         if [[ $? -ne 0 ]]; then
            /usr/bin/rm -rf ${TEMP_ROOT}
            /usr/bin/rm -f ${TEMP_LOG}
            fatal "$(printf "$(gettext "%s: File conversion was unsuccessful.")\n" $command $sms_restore_filename)"
         fi

         # Take the existing files listed in the log (removing the block count) and
         #   cpio them up
         cd "${TEMP_ROOT}"
         find `cat ${TEMP_LOG}` 2> /dev/null | grep -v block \
			| cpio -Pocv -O ${TEMP_CPIO} > /dev/null 2>&1
         if [[ $? -ne 0 ]]; then
            /usr/bin/rm -rf ${TEMP_ROOT}
            /usr/bin/rm -f ${TEMP_CPIO}
            /usr/bin/rm -f ${TEMP_LOG}
            fatal "$(printf "$(gettext "%s: Attempt to create cpio archive of files located in %s failed.")\n" $command $TEMP_ROOT)"
         fi

         if [[ ! -r ${TEMP_LOG}  || ! -s ${TEMP_LOG} ]]; then
            /usr/bin/rm -rf ${TEMP_ROOT}
            /usr/bin/rm -f ${TEMP_CPIO}
            /usr/bin/rm -f ${TEMP_LOG}
            fatal "$(printf "$(gettext "%s: Intermediate restore file %s has been corrupted.")\n" $command $TEMP_LOG)"
         fi

         # Restore the backup onto the SMS file structure
         cd $ROOT/
         cpio -Picvdum -I ${TEMP_CPIO} -f ${SMSOPT#${ROOT}/}/SMS >>${LOG_FILE} 2>&1
         if [[ $? -ne 0 ]]; then
            /usr/bin/rm -rf ${TEMP_ROOT}
            /usr/bin/rm -f ${TEMP_CPIO}
            /usr/bin/rm -f ${TEMP_LOG}
            fatal "$(printf "$(gettext "%s: Unable to restore backup onto existing installation: %s.")\n" $command $TEMP_CPIO)"
         fi

         # Clean up the temp files
         /usr/bin/rm -f ${TEMP_CPIO}
         /usr/bin/rm -rf ${TEMP_ROOT}
         /usr/bin/rm -f ${TEMP_LOG}

      else
         # If the version is not the current or prior version of SMS we are not equipped to
         #  handle this situation
         fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      fi # Restoring a prior backup into the current system


      # The ACLs are not reconfigured when we restore the files
      #  so this function restores them
      restore_acls

      # No file modifications after the call to restore_acls
   fi
}


#############################################################################
#
# check_active_version
#
# Display which version of SMS software we're running. Determine this
#  by checking that all 3 req'd links are pointing to the same version
#  number
#
#############################################################################
check_active_version()
{
	typeset active_version_directory
	typeset smsopt_version="0.0"
	typeset smsvar_version
	typeset smsetc_version
	#
	# first thing to do, check for active version numbers on all dirs
	#
	if [[ -d ${SMSOPT}/SMS ]]; then
		# trim target pathname to primary component e.g. "SMS1.0"
		smsopt_version=`ls -l ${SMSOPT}/SMS |cut -f2 -d'>'`
		smsopt_version=${smsopt_version##*/}
		if [[ -d ${SMSVAR}/SMS ]]; then
			smsvar_version=`ls -l ${SMSVAR}/SMS |cut -f2 -d'>'`
			smsvar_version=${smsvar_version##*/}
			if [[ -d ${SMSETC}/SMS ]]; then
				smsetc_version=`ls -l ${SMSETC}/SMS |cut -f2 -d'>'`
				smsetc_version=${smsetc_version##*/}
			fi
		fi
	fi
	if [[ $smsopt_version != $smsvar_version || $smsopt_version != $smsetc_version ]]; then
		fatal "$(printf "$(gettext "%s: Invalid SMS version configuration found")\n" $command)"
	fi


	# read sms_env.sh and check value of SMS_VERSION
	if [[ ! -r "$SMS_ENV" ]]; then
		fatal "$(printf "$(gettext "%s: sms_env.sh file missing or not readable")\n" $command)"
	fi
        SMS_VERSION=`grep "SMS_VERSION=" $SMS_ENV | sed -e 's,=,'" "',g' | awk '{print $2}'`
	if [[ $SMS_VERSION != $smsopt_version ]]; then
		fatal "$(printf "$(gettext '%s: $SMS_VERSION in sms_env.sh does not match SMS version symlinks')\n" $command)"
	fi
	active_version_directory=`basename $smsopt_version`
	ACTIVE_SMS_VERSION=${active_version_directory#SMS}
}


#############################################################################
#
# print_active_version
#
# Display the name of the ACTIVE version of SMS software
#
#############################################################################
print_active_version()
{
		printf "$(gettext "%s: Active SMS version < %s >")\n" $command $ACTIVE_SMS_VERSION
}


#############################################################################
#
# print_terse_version
#
# Display the name of the ACTIVE version of SMS software in a terse format
#
#############################################################################
print_terse_version()
{
		echo $ACTIVE_SMS_VERSION
}


#############################################################################
#
# find_highest_installed_version
#
# Search through the installed versions of SMS and identify the newest
#  (numerically highest) version that has an smsversion.cf file
#
# Parameters
#  $1 call by reference variable to hold highest version
#
# Returns
#  none
#
#############################################################################
find_highest_installed_version()
{
   typeset ret_val="$1"
   typeset tmajor=1
   typeset tminor=1
   typeset high_major=0
   typeset high_minor=0
   typeset active_major=$(print ${ACTIVE_SMS_VERSION} | cut -d. -f1)
   typeset active_minor=$(print ${ACTIVE_SMS_VERSION} | cut -d. -f2)

   # Search through all the possible releases of SMS and see what is
   #   installed on the SC
   while (($tmajor <= 9)); do
      while (($tminor <= 19)); do
         # If the version is installed on the SC then check to see if
         #   it has a smsversion.cf file
         if find_version "$tmajor.$tminor" > /dev/null ; then
            # We're only interested if it has an smsversion.cf file
            #  for us to read
            check_for_smsversion_cf_file "$tmajor.$tminor"
            if [[ $? -eq 0 ]]; then
              high_major=${tmajor}
              high_minor=${tminor}
            fi
         fi
         tminor=$(($tminor+1))
      done
      tminor=0
      tmajor=$(($tmajor+1))
   done

   # Exit with an error if the file is too old, or if we didn't find a
   #  file at all
   if (( ${high_major} == 0 )); then
      fatal "$(gettext "A valid smsversion.cf file could not be located.")"
   elif (( ${active_major} > ${high_major} )); then
      fatal "$(gettext "A valid smsversion.cf file could not be located.")"
   elif (( ${active_major} == ${high_major} && \
           ${active_minor} > ${high_minor} )); then
      fatal "$(gettext "A valid smsversion.cf file could not be located.")"
   fi

   # Return the version number in format #.#
   eval "$ret_val=\"${high_major}.${high_minor}\""


}

#############################################################################
#
# find_consecutive_up_down()
#
# Scan the list of released versions of SMS from the file and determine
#  which one is the previous release and which of any is the following
#  release
#
# Parameters
# $1 call by reference return variable for prior release
# $2 call by reference return for next release
# $3 version of SMS with the newest smsversion.cf file
# Returns "" if there is no listing
#
#############################################################################
find_consecutive_up_down()
{
   typeset highest_version=$3
   typeset return_low=$1
   typeset return_high=$2
   typeset COUNTER=1  # start at one because the first entry is a key word
   typeset smsversion_file=${SMSETC}/SMS${highest_version}/config/smsversion.cf

   set -A listofversions `cat ${smsversion_file} 2>/dev/null | \
                             grep "^RELEASE"`
   # If we failed to get the list of versions of SMS then print
   #   an error
   if ((${#listofversions[*]} == 0)); then
      fatal "$(printf "$(gettext "Contents of %s have been corrupted")\n" \
         "${smsversion_file}")"
   fi

   COUNTER=1
   while (( $COUNTER < ${#listofversions[*]} )); do
      version_cmp ${ACTIVE_SMS_VERSION} ${listofversions[$COUNTER]}
      # if version_cmp returns 0 the values are equal
      if [[ $? -eq 0 ]]; then
         break
      fi
      let COUNTER=$COUNTER+1
   done

   eval "$return_low=\"\""
   eval "$return_high=\"\""

   # If we didn't find ACTIVE_SMS_VERSION in the list of
   #  released version of SMS then we have a problem
   if (( $COUNTER == ${#listofversions[*]} )); then
      fatal "$(printf "$(gettext "The active version of SMS is not a valid release listed in %s.")\n" "${SMSETC}/config/smsversion.cf")"
   # first entry
   elif (( $COUNTER == 1 )); then
      eval "$return_high=\"${listofversions[$COUNTER+1]}\""
   # last entry
   elif (( $COUNTER == (( ${#listofversions[*]}-1 )) )); then
      eval "$return_low=\"${listofversions[$COUNTER-1]}\""
   # regular entry
   else
      eval "$return_low=\"${listofversions[$COUNTER-1]}\""
      eval "$return_high=\"${listofversions[$COUNTER+1]}\""
   fi
}

#############################################################################
#
# get_sc_driver_version()
#
# Find all the SUNWscdvr packages installed on the system
#  and use the version of the newest one
#
#############################################################################
get_sc_driver_version()
{
    # Locate the newest SUNWscdvr[.#] installed on the system
    #  Must set the local we we don't get foreign language info
    newest_driver=`( LANG=C;LC_ALL=C;export LANG LC_ALL; pkginfo 2>&1 | \
                     grep SUNWscdvr |tail -1 | awk '{print $2}' )`
    if [[ "$newest_driver" = "" ]]; then
       fatal "$(gettext "Error: SUNWscdvr package not found")"
    fi

    # Find the version of the newest driver
    #  Must set the local so we don't get foreign language info
    dvr_version=`( LANG=C;LC_ALL=C;export LANG LC_ALL; \
                   pkginfo -l $newest_driver 2>&1|grep VERSION | \
                   cut -f6 -d' ' | cut -f1 -d',' )`
    if [[ "$dvr_version" = "" ]]; then
       fatal "$(gettext "Error: Version of SUNWscdvr package not found")"
    fi
    echo $dvr_version
}


#############################################################################
#
# check_for_smsversion_cf_file
#
# Check for the smsversion.cf file
#
# Parameters
# $1 release to check (#.#)
#
# Return
# 0 file was successfully located
# 1 file was not found or inaccessible
#
#############################################################################
check_for_smsversion_cf_file()
{
   # Setup the file path
   smsversion_cf="${SMSETC}/SMS${1}/config/smsversion.cf"

   # Check to see if the file is readable
   if [[ ! -r "${smsversion_cf}" ]]; then
      # %s is the SMS version number eg. 1.2
      # Failed
      return 1
   fi
   # successful
   return 0
}


#############################################################################
#
# check_release_requirements()
#
# Check the system requirements for specified release of SMS
#  We use the newest copy (highest release) of the smsversion.cf file
#  to ensure the most recent data
#
# Parameters
# $1 release to check (#.#)
# $2 release of smsversion.cf file
#
# Return
# 0 for SUCCESS
# 1 for FAILURE
#
#############################################################################
check_release_requirements()
{
   typeset current_solaris_release=$(uname -r)
   typeset current_sc_driver=$(get_sc_driver_version)
   typeset os_list
   typeset driver_list
   typeset smsversion_file=${SMSETC}/SMS${2}/config/smsversion.cf
   typeset release=${1}

   # The first entry in the list is the key word
   set -A driver_list `cat ${smsversion_file} | \
      grep "^DRIVER:${release}"`
   if (( ${#driver_list[*]} <= 1 )); then
      fatal "$(printf "$(gettext "Error: Driver entries missing in %s for version SMS%s\n")" $smsversion_file $1)"
   fi

   # The first entry in the list is the key word
   set -A os_list `cat ${smsversion_file} | \
      grep "^OS:${release}"`
   if (( ${#os_list[*]} <= 1 )); then
      fatal "$(printf "$(gettext "Error: OS entries missing in %s for version SMS%s\n")" $smsversion_file $1)"
   fi

   # check the list for the driver version
   temp=`echo ${driver_list[*]} | grep -w ${current_sc_driver}`
   if [[ "$temp" = "" ]]; then
      return 1
   fi

   # check the list for the os version
   temp=`echo ${os_list[*]} | grep -w ${current_solaris_release}`
   if [[ "$temp" = "" ]]; then
      return 1
   fi

   return 0
}

#############################################################################
#
# version_cmp()
#
# Compare two dotted-triple version number strings, $1 and $2.
# For example, "1.3.0" and "1.2.0".  Return comparison result in $?:
#       0       if equal
#       255     if $1 is < $2 (Note: -1 is out of the range 0 - 255)
#       1       if $1 is > $2
# Warning: the patch number may be absent from the string.
# E.g., "1.3" or "1.3." instead of "1.3.0".
#
#############################################################################
version_cmp()
{
        typeset major1=$(print $1 | cut -d. -f1)
        typeset minor1=$(print $1 | cut -d. -f2)
        typeset patch1=$(print $1 | cut -d. -f3)
        typeset major2=$(print $2 | cut -d. -f1)
        typeset minor2=$(print $2 | cut -d. -f2)
        typeset patch2=$(print $2 | cut -d. -f3)

        if [[  "$major1" -eq "$major2" ]] ; then
                if [[  "$minor1" -eq "$minor2" ]] ; then
                        if [[  "$patch1" -eq "$patch2" ]] ; then
                                return 0
                        elif [[ "$patch1" -lt "$patch2" ]] ; then
                                return 255
                        else
                                return 1
                        fi
                elif [[ "$minor1" -lt "$minor2" ]] ; then
                        return 255
                else
                        return 1
                fi
        elif [[ "$major1" -lt "$major2" ]] ; then
                return 255
        else
                return 1
        fi
}

#############################################################################
#
# check_and_choose_version()
#
# Check to see what versions of SMS are properly installed - this is
# based on whether or not the proper directories are present. After
# determining the list of installed versions, present the choices
# to the user and process their response.
# If a version number is specifically requested on the command line
# limit our checking to that version.
#
#############################################################################
check_and_choose_version()
{
	# check and see if the directories are actually installed
	#  that would match the package information and inform user
	#
	typeset installed_vers
	typeset -i installed_vers_cnt=0
	typeset -i tmajor=1
	typeset -i tminor=0
	typeset pid

	getpid ssd | read pid
	if [[ -n ${1} ]]; then   # only need to check for one version
		printf "$(gettext "You have requested SMS Version %s")" ${1} | fmt
		print
		if yes_or_no "$(gettext "Is this correct?")"
		then
                   typeset up_o
                   typeset down_o
                   typeset highest_v
                   typeset check1
                   typeset check2

                   # Find the highest installed version of SMS
                   find_highest_installed_version highest_v

                   # Find the consecutive release to the active release
                   #  down_one up_one passed kornshell style call by ref
                   find_consecutive_up_down down_o up_o "$highest_v"

                   validate_version_request "$1"

                   version_cmp "$down_o" "${1}"
                   check1="$?"

                   version_cmp "$up_o" "${1}"
                   check2="$?"

                   if [[ "$check2" -ne 0 && "$check1" -ne 0 ]]; then
                      fatal "$(printf "$(gettext "%s: SMS%s is not a consecutive release of SMS\n")"  $command $1)"
                   fi

                   check_release_requirements "$1" "$highest_v"
                   if [[ $? -ne 0 ]]; then
                      printf "$(gettext "%s: SMS %s is not supported in this system configuration.")\n" $command $1
                      return 1
                   fi

		   if find_version "${1}"; then
			if [[ $pid == +([[:digit:]]) ]]; then
				fatal "$(gettext "SMS must be stopped prior to version switching.")"
			fi
			return 0
		    else
			printf "$(gettext "%s: SMS %s is not installed.")\n" $command $1
			return 1
		    fi
		else
			return 1
		fi
	else	# check for consecutive versions of SMS

           #
           #
           # Version switching is only supported for consecutive
           #  releases of SMS.  This includes major and minor
           #  releases
           #
           #
           typeset up_one
           typeset down_one
           typeset highest_version

           # Find the highest installed version of SMS
           find_highest_installed_version highest_version

           # Find the consecutive release to the active release
           #  down_one up_one passed kornshell style call by ref
           find_consecutive_up_down down_one up_one "$highest_version"

           # If we found a previous consecutive install in the list
           #   check to see if its installed and put it in the display
           #   list
           check_release_requirements "$down_one" "$highest_version"
           if [[ $? -eq 0 ]]; then
              if find_version "$down_one"; then
                 version_list=${version_list:+$version_list }"$down_one "
                 installed_vers_cnt=$(($installed_vers_cnt+1))
              fi
           fi

           # Check to see if the active version of sms is installed
           #   and put it into the list.  Its a waste but is more consistent
           #   with the previous releases
           if find_version "$ACTIVE_SMS_VERSION"; then
              version_list=${version_list:+$version_list }"$ACTIVE_SMS_VERSION "
              installed_vers_cnt=$(($installed_vers_cnt+1))
           fi

           # If we found a newer consecutive release check to see if its
           #  installed and add it to the display list
           check_release_requirements "$up_one" "$highest_version"
           if [[ $? -eq 0 ]]; then
              if find_version "$up_one"; then
                 version_list=${version_list:+$version_list }"$up_one "
                 installed_vers_cnt=$(($installed_vers_cnt+1))
              fi
           fi


	fi # checking for installed releases

	if [[ installed_vers_cnt -le 1 ]]; then
		return 1  # nothing's installed
	else
		gettext "Please select from one of the following installed SMS versions:\n"
		version_list=${version_list:+$version_list }"Exit "
	fi

	while true
	do

		PS3="Select version: "
		select target_version in ${version_list}
		do
			if [[ $REPLY > $installed_vers_cnt || $REPLY < 1 ]]; then
				gettext "No SMS version changes will be made.\n"
				return 1;
			else
				break;
			fi
		done	# select target_version
		printf "$(gettext "You have selected SMS Version %s")" $target_version | fmt
		print
		if yes_or_no "$(gettext "Is this correct?")"
		then
			subcommand=${target_version}
                        validate_version_request ${target_version}
			break
		fi
	done

	if [[ $pid == +([[:digit:]]) ]]; then
		fatal "$(gettext "SMS must be stopped prior to version switching.")"
	fi
	return 0
}


#############################################################################
#
# find_version()
#
# Check to see that all expected directories are there for a particular
# version.
#
#############################################################################
find_version()
{
	typeset vers=$1
        typeset hwad_binary=""

        if [[ "$vers" == "" ]]; then
           return 1
        fi

        # It is necessary to cd to root because find will fail if
        #  the current directory path is partially restricted
        #  Otherwise find will return 1 because find does not work, NOT
        #  because the directory is not there.
        cd ${ROOT}
	if find ${SMSOPT}/SMS$vers ${SMSVAR}/SMS$vers \
		${SMSETC}/SMS$vers -type d -prune >> ${LOG_FILE} 2> /dev/null
	then
           hwad_binary=`find ${SMSOPT}/SMS$vers/bin/hwad 2>/dev/null`
           if [[ "${hwad_binary}" != "" ]]; then
		printf "$(gettext "%s: SMS version %s installed")\n" $command $vers
		return 0
           fi
	fi
        return 1
}


#############################################################################
#
# validate_version_request()
#
# Perform some format checking.
# Print a informative message about the version switch taking place.
# A non-switch (selecting the active version) will result in an error
# A downward switch will print an warning about feature loss
#
#############################################################################
validate_version_request()
{
        typeset cmp_ret
        typeset dest_ver
        dest_ver="$1"

        # is the version number properly formed?
        echo $1 | grep "^[1-9]\.[0-9]$" >>/dev/null 2>&1
        if [[ $? -gt 0 ]]; then
                fatal "$(printf "$(gettext "%s: Improper version number specified - use <x.x>")\n" $command)"
        fi

        version_cmp "$dest_ver" "$ACTIVE_SMS_VERSION"
        cmp_ret=$?

        if [[ $cmp_ret == 0 ]]; then
                fatal "$(printf "$(gettext "%s: SMS version <%s> is already installed and active.")" \
                        $command $dest_ver)"
        elif [[ $cmp_ret == 1 ]]; then
                printf "$(gettext '%s: Upgrading SMS from <%s> to <%s>.')\n" \
                        $command $ACTIVE_SMS_VERSION $dest_ver
                return 0
        elif [[ $cmp_ret == 255 ]]; then
                printf "$(gettext '%s: Downgrading SMS from <%s> to <%s>.')\n" \
                        $command $ACTIVE_SMS_VERSION $dest_ver
                return 0
        fi
}

#############################################################################
#
# move_links() - Create new links in the appropriate SMS version directory
#          $1  - new version being activated
#
#############################################################################
move_links()
{
	typeset newvers=$1

	create_sms_startup_links $newvers
	[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
		"%s: Link Error: Unable to activate SMS Version %s\n")" \
		$command $1)"
	rm -f ${SMSOPT}/SMS ${SMSETC}/SMS ${SMSVAR}/SMS >/dev/null 2>&1;

#	link new version; if it fails back out the links
	if ln -s ${SMSOPT}/SMS${newvers} ${SMSOPT}/SMS; then
		if ln -s ${SMSETC}/SMS${newvers} ${SMSETC}/SMS; then
			if ln -s ${SMSVAR}/SMS${newvers} ${SMSVAR}/SMS; then
				printf "$(gettext "%s: New Version <%s> Active")\n" \
					$command $newvers
				return 0;
			else
				ln -s ${SMSOPT}/SMS${ACTIVE_SMS_VERSION} ${SMSOPT}/SMS
				[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
					"%s: Link Error: Unable to activate SMS Version %s\n")" \
					$command $1)"
				ln -s ${SMSETC}/SMS${ACTIVE_SMS_VERSION} ${SMSETC}/SMS
				[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
					"%s: Link Error: Unable to activate SMS Version %s\n")" \
					$command $1)"
			fi
		else
			ln -s ${SMSOPT}/SMS${ACTIVE_SMS_VERSION} ${SMSOPT}/SMS
			[[ $? -ne 0 ]] && fatal "$(printf "$(gettext \
				"%s: Link Error: Unable to activate SMS Version %s\n")" $command $1)"
		fi
	fi

	fatal "$(printf "$(gettext \
		"%s: Link Error: Unable to activate SMS Version %s\n")" \
		$command $1)"
}


###############################################################
#
# remove_ipnode_hosts_entries
#
# Edits the ipnode file or the hosts file and remove any entry
#  with the comment #smsconfig-entry#
# (which were added with smsconfig using update_hosts(), below)
#
# Parameters
#  $1 filename
#
# Returns
# 0 Success
# 1 Error
#
###############################################################
remove_ipnode_hosts_entries()
{
   clearfile=$1
   #
   # Remove the entries from the file
   #
   if [ -f "$clearfile" ]
   then
      line1=`grep "#smsconfig-entry#" ${clearfile}` 2>/dev/null
      if [ -n "$line1" ]
      then
         (echo "1,\$g/#smsconfig-entry#\$/d"
          echo 'w';
          echo 'q' ) | ed -s ${clearfile} > /dev/null
      fi

      # Caller prints the error message that the clearing
      #  of entries failed
      if [ $? -ne 0 ]; then
         return 1;
      fi
      # Successfully cleared the file
      return 0
   fi
   # If the file did not exist then we do not need to clear
   #  any entries
   return 0
}


###############################################################
#
# update_hosts
#
# Update hosts or ipnodes file or both from information in MAN.cf.
#
# Adds any entries in MAN.cf that are not in hosts or ipnodes to hosts
# and/or ipnodes.
#
# If any entry for a host has a different IP address, the entry
# in the hosts file is deleted and a new one is added with the
# ip address from the MAN.cf file.
#
# If an entry for an ip address exists in the hosts file with a hostname
# that does not match the name in the MAN.cf file, it is removed from the
# hosts file.
#
# Does not handle the case where an address is removed from the MAN.cf (it
# is not removed from the hosts file).
#
# Entries added must have the comment #smsconfig-entry#
# so they can be removed later by remove_ipnode_hosts_entries()
#
# Input:
#  $1: MAN.cf filename (saved as $mancf).
#  Also uses file $TMPFOADDRS.
#
# Return 0 on success or non-zero on failure.
#
###############################################################
update_hosts()
{
	typeset mancf="$1"
	typeset TMP_HOSTEDCMDS=/tmp/smsconfig_host_ed_cmds$$
	typeset TMP_HOSTEDCMDS6=/tmp/smsconfig_host_ed_cmds6$$
	typeset TMP_HOSTEDINFO=/tmp/smsconfig_host_ed_info$$
	typeset TMP_HOSTEDINFO6=/tmp/smsconfig_host_ed_info6$$
	typeset TMP_EDERRS=/tmp/smsconfig_host_ed_errs$$
	typeset TMP_EDERRS6=/tmp/smsconfig_host_ed_errs6$$
	typeset ADD=$(gettext "ADD")
	typeset hosthostip=""
	typeset hosthostip_aliases=""
	typeset hosthostip_loghost=""
	typeset hosthostname_loghost=""
	typeset manhostname=""
	typeset manhostip=""
	typeset manhostipnosubnet=""
	typeset addloghost=""
	typeset -i loghostsadded=0
	typeset hostschecksum="$(cksum $ETCHOSTSFILE)"
	typeset hosts6checksum="$(cksum $ETCHOSTSFILE6)"

	[ -z "$mancf" ] && return 1
	[ -f "$mancf" -a -f "$ETCHOSTSFILE" ] || return 2

	rm -f $TMP_HOSTEDCMDS $TMP_HOSTEDCMDS6 $TMP_HOSTEDINFO \
		$TMP_HOSTEDINFO6 $TMP_EDERRS $TMP_EDERRS6

	#
	# Parse hostname/ip pairs from MAN.cf
	# and use hostname/ip pairs in file $TMPFOADDRS.
	#
	# Save the pairs in $TMP_HOSTEDINFO for display and
	# save ed editor cmds in $TMP_HOSTEDCMDS for editing the IPv4 hosts file.
	#
	# Likewise, use $TMP_HOSTEDINFO6 and $TMP_HOSTEDCMDS6 for the
	# IPv6 ipnodes file.
	#
	(
	awk '
	/^[ 	]*#/ {next}
	$2 ~ /^NM-/ {next}
	$3 == "" {next}
	$4 == "" {next}
	{print $3, $4}' $mancf
	cat $TMPFOADDRS 2>/dev/null
	) | sort -u | \
	while read manhostname manhostip
	do
		[[ "$manhostname" = NONE ]] && continue

		if [[ ${manhostip} != *:* ]]; then # Handle IPv4
			# Get IP Address
			hosthostip=$(cut -f1 -d'#' $ETCHOSTSFILE | \
				awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" {print $1}' | \
				head -1)
			hosthostip_aliases=$(cut -f1 -d'#' $ETCHOSTSFILE | \
				awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" \
					{for(i=3; i<=NF; i++) print $i}' \
				| sort -u)

			# Determine of this is a loghost
			hosthostip_loghost=
			if echo $hosthostip_aliases | grep -w loghost \
						> /dev/null; then
				hosthostip_loghost=" loghost"
			fi

			# Get hostname(s)
			hosthostname=$(cut -f1 -d'#' $ETCHOSTSFILE | \
				awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" {print $2}' | \
				head -1)
			hosthostname_aliases=$(cut -f1 -d'#' $ETCHOSTSFILE | \
				awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" \
					{for(i=3; i<=NF; i++) print $i}' | \
				sort -u)

			# Determine of this is a loghost
			hosthostname_loghost=
			if echo $hosthostname_aliases | grep -w loghost \
						> /dev/null; then
				hosthostname_loghost=" loghost"
				printf "\n$(gettext 'Host \"%s\" is a loghost.')\n" \
					"$manhostname"
				(( loghostsadded += 1 ))
				addloghost="$hosthostip_loghost"
			fi

			# If either the ip or hostname we are now adding
			# currently has loghost associated with it, then
			# it will be removed and lost.  So, we check for
			# this so we can include it when we add the line.
			if grep "$ADD:.* loghost " $TMP_HOSTEDINFO >/dev/null \
						2>&1; then
				# Already will be added, so don't add second time.
				addloghost=""
			else
				[[ -z "$addloghost" ]] && \
					addloghost="$hosthostname_loghost"
			fi

			if [ -n "$hosthostname" -a "$hosthostname" != "$manhostname" ]
			then
				echo "g/^[^#]*$manhostip.*$hosthostname/d" \
						>> $TMP_HOSTEDCMDS
				delinfo=$(sed -n "/^[^#]*$manhostip.*$hosthostname/p" \
						$ETCHOSTSFILE | head -1)
				printf $(gettext "DEL:")" %s\n" "$delinfo" \
						>> $TMP_HOSTEDINFO
			fi

			if [ -z "$hosthostip" ]
			then
				printf "\$a\n$manhostip\t$manhostname$addloghost #smsconfig-entry#\n.\n" \
						>> $TMP_HOSTEDCMDS
				printf "$ADD: %s\n" "$manhostip ${manhostname}$addloghost #smsconfig-entry#" \
						>> $TMP_HOSTEDINFO
			elif [ "$hosthostip" != "$manhostip" ]
			then
				echo "g/^[^#]*$hosthostip.*$manhostname/d" \
					>> $TMP_HOSTEDCMDS
				delinfo=$(sed -n "/^[^#]*$hosthostip.*$manhostname/p" \
						$ETCHOSTSFILE | head -1)
				printf $(gettext "DEL:")" %s\n" "$delinfo" \
						>> $TMP_HOSTEDINFO
				printf "i\n$manhostip\t${manhostname}$addloghost #smsconfig-entry#\n.\n" \
						>> $TMP_HOSTEDCMDS
				printf "$ADD: %s\t%s\n" "$manhostip" "$manhostname$addloghost #smsconfig-entry#" \
						>> $TMP_HOSTEDINFO
			fi

		else	# Handle IPv6
			# Get IP Address
			hosthostip=$(cut -f1 -d'#' $ETCHOSTSFILE6 | \
				awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" {print $1}' | \
				head -1)
			hosthostip_aliases=$(cut -f1 -d'#' $ETCHOSTSFILE6 | \
				awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" \
					{for(i=3; i<=NF; i++) print $i}' | \
				sort -u)

			# Determine of this is a loghost
			hosthostip_loghost=
			if echo $hosthostip_aliases | grep -w loghost \
					> /dev/null; then
				hosthostip_loghost=" loghost"
			fi

			# Get hostname(s)
			hosthostname=$(cut -f1 -d'#' $ETCHOSTSFILE6 | \
					awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" {print $2}' | \
					head -1)
			hosthostname_aliases=$(cut -f1 -d'#' $ETCHOSTSFILE6 | \
					awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" \
						{for(i=3; i<=NF; i++) print $i}' | \
					sort -u)

			# Determine of this is a loghost
			hosthostname_loghost=
			if echo $hosthostname_aliases | grep -w loghost \
					> /dev/null; then
				hosthostname_loghost=" loghost"
				printf "\n$(gettext 'Host \"%s\" is a loghost.')\n" \
					"$manhostname"
				(( loghostsadded += 1 ))
				addloghost="$hosthostip_loghost"
			fi

			# If either the ip or hostname we are now adding
			# currently has loghost associated with it, then
			# it will be removed and lost.  So, we check for
			# this so we can include it when we add the line.
			if grep "$ADD:.* loghost " $TMP_HOSTEDINFO >/dev/null \
						2>&1; then
				# Already will be added, so don't add second time.
				addloghost=""
			else
				[[ -z "$addloghost" ]] && \
					addloghost="$hosthostname_loghost"
			fi

			# Strip off subnet part (unlike IPv4, the IPv6 subnet
			# length MUST be specified)
			if [[ ${manhostip} = */* ]]; then
				manhostipnosubnet=${manhostip%/*}
			else
				manhostipnosubnet=$manhostip
			fi

			if [ -n "$hosthostname" -a "$hosthostname" != "$manhostname" ]
			then
				echo "g/^[^#]*$manhostipnosubnet.*$hosthostname/d" \
					>> $TMP_HOSTEDCMDS6
				delinfo=$(sed -n "/^[^#]*$manhostip.*$hosthostname/p" \
					$ETCHOSTSFILE6)
				printf $(gettext "DEL:")" %s\n" "$delinfo" \
					>> $TMP_HOSTEDINFO6
			fi

			if [ -z "$hosthostip" ]
			then
				printf "\$a\n$manhostipnosubnet\t$manhostname$addloghost #smsconfig-entry#\n.\n" \
					>> $TMP_HOSTEDCMDS6
				printf "$ADD: %s\n" "$manhostipnosubnet	$manhostname$addloghost #smsconfig-entry#" \
					>> $TMP_HOSTEDINFO6
			elif [ "$hosthostip" != "$manhostipnosubnet" ]
			then
				echo "g/^[^#]*$hosthostip.*$manhostname/d" \
					>> $TMP_HOSTEDCMDS6
				delinfo=$(sed -n "/^[^#]*$hosthostip.*$manhostname/p" \
					$ETCHOSTSFILE6)
				printf $(gettext "DEL:")" %s\n" "$delinfo" \
					>> $TMP_HOSTEDINFO6
				printf "i\n$manhostipnosubnet\t${manhostname}$addloghost #smsconfig-entry#\n.\n" \
					>> $TMP_HOSTEDCMDS6
				printf "$ADD: %s\n" "$manhostipnosubnet\t${manhostname}$addloghost #smsconfig-entry#" \
					>> $TMP_HOSTEDINFO6
			fi
		fi
	done
	rm -f $TMPFOADDRS

	#
	# Display warning if no loghost is being edited
	#
	if (( loghostsadded == 0 )) ; then
		if grep -v '^#' $ETCHOSTSFILE $ETCHOSTSFILE6 2>/dev/null | grep -w loghost \
			> /dev/null ; then
			gettext 'Loghost hosts or ipnodes file entries are:\n'
			grep -v '^#' $ETCHOSTSFILE $ETCHOSTSFILE6 2>/dev/null \
				| grep -w loghost
			gettext '\"loghost\" will not be changed.\n'
		else
			gettext 'No loghost is present in the hosts or ipnodes file.\n'
		fi
	fi

	#
	# Display warning if the IPv4 hosts file has changed recently
	#
	if [[ $(cksum $ETCHOSTSFILE) != $hostschecksum ]] ; then
		printf "$(gettext 'Warning: hosts file \"%s\" has been changed
recently by another process.')\n" \
			$ETCHOSTSFILE | fmt
		gettext 'Those changes will be removed if you continue.\n'
        fi

	#
	# Display and confirm IPv4 address changes, if any
	#
	if [[ -s $TMP_HOSTEDINFO ]] ; then
		printf "$(gettext 'The following changes are about to be applied to the \"%s\" hosts file:')\n" \
			$ETCHOSTSFILE | fmt
		echo ----------------------
		[[ -t 0 ]] && more $TMP_HOSTEDINFO || cat $TMP_HOSTEDINFO
		echo ----------------------

		if yes_or_no "$(printf "$(gettext \
			"Update the hosts file, \\\"%s\\\", with these changes?")" \
			$ETCHOSTSFILE)"
		then
			# Display warning if the IPv4 hosts file has changed
			# recently:
			if [[ $(cksum $ETCHOSTSFILE) != $hostschecksum ]] ; then
				printf "$(gettext 'Warning: hosts file \"%s\"
has been changed recently by another process.')\n" \
							$ETCHOSTSFILE | fmt
				gettext 'Those changes will be removed.\n'
        		fi

			# Apply changes to IPv4 hosts file
			cp -p $ETCHOSTSFILE $ETCHOSTSFILE.old
			printf "w\nq\n" >> $TMP_HOSTEDCMDS
			if ed $ETCHOSTSFILE >$TMP_EDERRS 2>&1 < $TMP_HOSTEDCMDS; then
				printf "$(gettext 'Hosts file \"%s\" has been updated.')\n" \
					$ETCHOSTSFILE
				# Attempt to clear IPv6 settings in case they
				# are switching:
				remove_ipnode_hosts_entries "$ETCHOSTSFILE6"
				if [ $? -ne 0 ] ;  then
				printf "$(gettext 'Error: Removal of old entries from %s failed')\n" \
					$ETCHOSTSFILE6
				fi

			else	# error editing IPv4 hosts file
				printf "$(gettext 'Hosts file %s update edit failed.')\n" \
						$ETCHOSTSFILE
				printf "$(gettext 'See %s for edit commands.')\n" \
						$TMP_HOSTEDCMDS
				printf "$(gettext 'See %s for edit errors.')\n" \
						$TMP_EDERRS
				wait4user
				rm -f $TMP_HOSTEDINFO
				return 4
			fi
		fi
		rm -f $TMP_HOSTEDCMDS $TMP_HOSTEDINFO $TMP_EDERRS
	fi

	#
	# Display warning if the IPv6 hosts file has changed recently
	#
	if [[ $(cksum $ETCHOSTSFILE6) != $hosts6checksum ]] ; then
		printf "$(gettext 'Warning: hosts file \"%s\" has been changed
recently by another process.')\n" \
				$ETCHOSTSFILE6 | fmt
		gettext 'Those changes will be removed if you continue.\n'
        fi


	#
	# Display and confirm IPv6 address changes, if any
	#
	if [[ -s $TMP_HOSTEDINFO6 ]] ; then
		printf "$(gettext "The following changes are about to be applied to the \"%s\" hosts file:")\n" \
			$ETCHOSTSFILE6 | fmt
		echo ----------------------
		[[ -t 0 ]] && more $TMP_HOSTEDINFO6 || cat $TMP_HOSTEDINFO6
		echo ----------------------

		if yes_or_no "$(printf "$(gettext \
			"Update the hosts file, \\\"%s\\\", with these changes?")" \
			$ETCHOSTSFILE6)"
		then
			#
			# Display warning if IPv6 hosts file has changed recently
			#
			if [[ $(cksum $ETCHOSTSFILE6) != $hosts6checksum ]]
			then
				printf "$(gettext 'Warning: hosts file \"%s\"
has been changed recently by another process.')\n" \
						$ETCHOSTSFILE6 | fmt
				gettext 'Those changes will be removed.\n'
        		fi


			# Apply changes to IPv6 ipnodes file
			cp -p $ETCHOSTSFILE6 $ETCHOSTSFILE6.old
			printf "w\nq\n" >> $TMP_HOSTEDCMDS6
			if ed $ETCHOSTSFILE6 >$TMP_EDERRS6 2>&1 < $TMP_HOSTEDCMDS6; then
				printf "$(gettext "Hosts file \"%s\" has been updated.")\n" \
					$ETCHOSTSFILE6
				# Attempt to clear the IPv4 settings in case they are switching
				remove_ipnode_hosts_entries "$ETCHOSTSFILE"
				if [ $? -ne 0 ] ; then
					printf "$(gettext "Error: Removal of old entries from %s failed")\n" \
						$ETCHOSTSFILE
				fi

			else	# error editing IPv6 ipnodes file
				printf "$(gettext 'Hosts file %s update edit failed.')\n" \
						$ETCHOSTSFILE6
				printf "$(gettext "See %s for edit commands.")\n" \
					$TMP_HOSTEDCMDS6
				printf "$(gettext "See %s for edit errors.")\n" \
					$TMP_EDERRS6
				wait4user
				rm -f $TMP_HOSTEDINFO6
				return 4
			fi
		fi
		rm -f $TMP_HOSTEDCMDS6 $TMP_HOSTEDINFO6 $TMP_EDERRS6
	fi

	rm -f $TMP_HOSTEDCMDS $TMP_HOSTEDCMDS6 $TMP_HOSTEDINFO \
		$TMP_HOSTEDINFO6 $TMP_EDERRS $TMP_EDERRS6
	return 0
}


###############################################################
# getnw
#
# Get network address for specified IP and Network Mask
# This is an IPv4 only routine.
#
# $1 = IP Address in decimal dot notation.
# $2 = Network mask in decimal dot notation.
###############################################################
getnw()
{
	typeset ip=$1 # IP address
	typeset m=$2 # Network Mask

	[ $# -eq 2 ] || return 1
        valid_ipv4_addr $ip || return 2
        valid_ipv4_addr $m || return 3

	IFS=.
	set $ip; ip1=$1 ip2=$2 ip3=$3 ip4=$4
	set $m; m1=$1 m2=$2 m3=$3 m4=$4

	printf "%d.%d.%d.%d\n" $((ip1&m1)) $((ip2&m2)) $((ip3&m3)) $((ip4&m4))
}


###############################################################
# update_netmask
#
# Update netmasks file
#
# Checks specified info and adds to or updates /etc/inet/netmasks as required.
# This is an IPv4 only routine.
#
#  $1: ip address
#  $2: netmask
#  $3: file to put ed commands into
#  $4: file to put change info into
#
###############################################################
update_netmask()
{
	typeset ip="$1"
	typeset nm="$2"
	typeset EDCMDS="$3"
	typeset CGINFO="$4"
	typeset goterr=0

	nw=$(getnw $ip $nm) || return $?

	# If nw and nm match: nothing to do.
	# if nw match found, but nm doesn't match: change the entry.
	# Otherwise, nw not found: add an entry.
	awk '
	BEGIN {a=1}
	$1 == "'$nw'" && $2 == "'$nm'" { a=0; exit }
	$1 == "'$nw'" && $2 != "'$nm'" { a=0; printf "/^'$nw'/s/^.*$/'$nw'	'$nm'/\n"; exit }
	END { if (a) printf "$a\n'$nw'	'$nm'\n.\n" }
		' $ETCNETMASKS >> $EDCMDS

	awk '
	BEGIN {a=1}
	$1 == "'$nw'" && $2 == "'$nm'" { a=0; exit }
	$1 == "'$nw'" && $2 != "'$nm'" { a=0; printf "UPD network: %s, old mask %s, new mask: %s\n", "'$nw'", $2, "'$nm'"; exit }
	END { if (a) printf "ADD network: %s, mask: %s\n", "'$nw'", "'$nm'" }
		' $ETCNETMASKS >> $CGINFO

	return 0
}


###############################################################
# update_netmasks
#
# Update netmasks file from information in MAN.cf.
#
# Adds appropriate entries in /etc/inet/netmasks for I1 and I2 networks
# in MAN.cf.
#
# If any entry for a network has a different netmask, the entry
# in the netmasks file is deleted and a new one is added with the
# network and mask from the MAN.cf file.
#
# If an entry for a network exists in the netmasks file with a mask
# that does not match the mask in the MAN.cf file, it is removed from the
# hosts file.
#
# Only IPv4 addresses are examined; IPv6 addresses are ignored.
#
# Does not handle the case where an address is removed from the MAN.cf (it
# is not removed from the netmasks file).
#
#  $1: MAN.cf file.
#
###############################################################
update_netmasks()
{
	typeset mancf="$1"
	typeset TMP_EDCMDS=/tmp/smsconfig_netmasks_ed_cmds$$
	typeset TMP_CGINFO=/tmp/smsconfig_netmasks_cginfo$$
	typeset TMP_EDERRS=/tmp/smsconfig_netmasks_ed_errs$$

	[[ -n "$mancf" ]] || return 1
	[[ -f "$mancf" ]] || return 2

	rm -f $TMP_EDCMDS $TMP_CGINFO $TMP_EDERRS

	awk '
	/^[ 	]*#/ {next}
	$1 == "I1" && $2 ~ /^NM-/ {i1nm=$4; next}
	$1 == "I2" && $2 ~ /^NM-/ {i2nm=$4; next}
	$1 == "I1" && i1ip == "" {i1ip=$4; next}
	$1 == "I2" && i2ip == "" {i2ip=$4; next}
	END {print i1ip,i1nm,i2ip,i2nm }' $mancf | read I1IP I1NM I2IP I2NM

	[[ -n "$I1IP" && "$I1IP" != NONE && -n "$I1NM" && ${I1IP} != *:* ]] && \
		update_netmask $I1IP $I1NM $TMP_EDCMDS $TMP_CGINFO
	[[ -n "$I2IP" && -n "$I2NM" && ${I2IP} != *:* ]] && \
		update_netmask $I2IP $I2NM $TMP_EDCMDS $TMP_CGINFO

	if test -s $TMP_EDCMDS; then
		printf "$(gettext "The following information is about to be applied to the \"%s\" file:")\n" \
			$ETCNETMASKS
		echo ----------------------
		cat $TMP_CGINFO
		echo ----------------------

		if yes_or_no "$(printf "$(gettext "Update the netmasks file, \"%s\", with these changes?")" $ETCNETMASKS)"
		then
			cp -p $ETCNETMASKS $ETCNETMASKS.old
			printf "w\nq\n" >> $TMP_EDCMDS

			if ed $ETCNETMASKS >$TMP_EDERRS 2>&1 < $TMP_EDCMDS; then
				printf "$(gettext "Netmasks file \"%s\" has been updated.")\n" $ETCNETMASKS
			else
				printf "$(gettext "Netmasks file update/edit failed.")\n"
				printf "$(gettext "See %s for edit commands.")\n" $TMP_EDCMDS
				printf "$(gettext "See %s for edit errors.")\n" $TMP_EDERRS
				wait4user
				goterr=1
			fi
		fi
	fi
	[[ $goterr = 0 ]] && rm -f $TMP_EDCMDS $TMP_EDERRS $TMP_CGINFO
}


###############################################################
#
# sms_man_setup
#
# Prepare for and setup the  Management Network (aka MAN)
# Implements smsconfig -m.
#
###########################################################################
sms_man_setup()
{
	typeset sendmandHUP=""

	parse_man_cf 0

	if [[ $# -eq 1 ]]; then
		case "$1" in
		[iI]1*)
			if [[ -z $PLATFORM_NAME ]]; then
				get_platform_name PLATFORM_NAME
			fi
			setup_I1_network $PLATFORM_NAME
			sendmandHUP="HUP"
			;;
		[iI]2*)
			if [[ -z $PLATFORM_NAME ]]; then
				get_platform_name PLATFORM_NAME
			fi
			setup_I2_network
			sendmandHUP="HUP"
			;;
		[lL]*)
			if [[ -z $PLATFORM_NAME ]]; then
				get_platform_name PLATFORM_NAME
			fi
			setup_C_networks
			;;
		*)
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
			fatal "$(gettext "Invalid MAN network.")"
			;;
		esac

	elif [[ $# -gt 1 ]]; then
		set_single_man_netid $*
		case "$1" in
		[iI]1*)
			sendmandHUP="HUP"
			;;
		[iI]2*)
			sendmandHUP="HUP"
			;;
		*)
			;;
		esac

	else
		if [[ -z $PLATFORM_NAME ]]; then
			get_platform_name PLATFORM_NAME
		fi
		setup_C_networks
		setup_I1_network $PLATFORM_NAME
		setup_I2_network
		sendmandHUP="HUP"
	fi

	cp -p ${MANCONFIGFILE} ${MANCONFIGFILE}.old
	cp ${TMPMANCONFIGFILE} ${MANCONFIGFILE}
	set_rhosts_file
	[[ -n "$DEBUG" ]] || /usr/sbin/eeprom local-mac-address\?=true
	[ -n "$sendmandHUP" ] && /usr/bin/pkill -HUP -x mand
	if [ -f ${TMPCMDS} ]; then
		/bin/sh ${TMPCMDS}
# TRANSLATION_NOTE: "MAN" refers to a product feature;do not translate
		format=$(gettext \
			"\nMAN Network configuration modified!")
		printf "$format\n"
		format=$(gettext \
			"Changes will take affect on next reboot.")
		printf "$format\n"
	fi
	rm -f ${TMPMANCONFIGFILE} ${TMPCMDS}

	# Match host info in /etc/inet/hosts with host info in MAN.cf
	update_hosts $MANCONFIGFILE
	update_netmasks $MANCONFIGFILE
}


###############################################################
#
# group_exists
#
# Checks using getent(1M) for the existence of the provided
# group. The group can take the form of a number or string.
#
# $1 - group (numeric or string)
# Returns true (0) for "yes" the group exists, and false (1)
# for "no" the group does not exist.
#
###############################################################
group_exists()
{
	getent group $1 >/dev/null 2>&1;
	if [ $? -eq 0 ]; then
		return 0;
	else
		return 1;
	fi
}


###############################################################
#
# lookup_sms_group - checks for the existence of a
# .sms_groups file and acquire from it (if it exists) the
# currently configured group for the provided SMS
# administration
#
# $1 - default name of SMS administration group to query for
# $2 - name of variable to store result in
#
###############################################################
lookup_sms_group()
{
	typeset _group_name="${1}"
	typeset _result=${2}
	typeset result

	# default to the group name if a configured group is not found
	result=$_group_name

	if [[ -s $GROUPCONFIGFILE && -r $GROUPCONFIGFILE ]]
	then
		# check the current configuration in the $GROUPCONFIGFILE file
		lookup=`grep "$_group_name:" $GROUPCONFIGFILE`
		if [[ -n $lookup ]]
		then
			# strip down to only the configured group
			lookup=${lookup##$_group_name:}
			if [[ -n "$lookup" ]]
			then
				result=$lookup
			fi
		fi
	fi

	eval "$_result=\"$result\""
}


###############################################################
#
# prompt_sms_group - prompts the user for a UNIX group for the
# SMS administration group given as an argument and checks
# to make sure that the group the user supplies exists.
#
# $1 - name of SMS administration group to query for
# $2 - current group for the SMS administration group in question
# $3 - name of variable to store result in
#
###############################################################
prompt_sms_group()
{
	typeset _ans
	typeset _format
	typeset _group_name="${1}"
	typeset _default=${2}
	typeset _result=${3}

	_format=$(gettext 'Enter the name of the %s group [%s]? ')
	printf "$_format" "$_group_name" $_default

	read _ans
	if [[ ! -n "$_ans" ]]
	then
		# If an answer was not provided, then use the default
		_ans="$_default"
	fi

	# Check to make sure that the provided group exists
	if ! group_exists $_ans; then
		printf "\n$(gettext 'ERROR! \"%s\" group does not exist!')\n" \
				$_ans
		return 1;
	else
		eval "$_result=\"$_ans\""
		return 0;
	fi
}


###############################################################
#
# sms_group_main
#
# Display sms group configuration options and call appropriate
# function.
# Implements smsconfig -g.
#
###############################################################
sms_group_main()
{
	PS3="Select one of the above options: "
	select i in "Edit current configuration" "Restore default groups" Quit
	do	case $i in
		"Edit current configuration") sms_group_setup;;
		"Restore default groups") sms_group_restore_default;;
		"Quit") break;;
		"")	print -u2 $(gettext "Invalid option, please select again.");;
		esac
	# reset env. REPLY to re-display menu
	REPLY=
	done
}


###############################################################
#
# sms_group_restore_default
#
# restore the SMS groups to their defaults
#
###############################################################
sms_group_restore_default()
{
	cp /dev/null $GROUPCONFIGFILE >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		fatal
	fi
	printf "$(gettext "Default configuration restored.")\n\n"
}


###############################################################
#
# sms_group_setup
#
# setup the SMS administration groups
#
###############################################################
sms_group_setup()
{
	typeset _group
	typeset _current_cfg
	typeset _plat_admn='platadmn'
	typeset _plat_oper='platoper'
	typeset _plat_svc='platsvc'
	typeset _domain_admns=''
	typeset _domain_rcfgs=''

	for i in a b c d e f g h i j k l m n o p q r ; do
		_domain_admns="$_domain_admns dmn${i}admn"
		_domain_rcfgs="$_domain_rcfgs dmn${i}rcfg"
	done

	print
	gettext 'NOTE: In order to configure a new group the group must already
exist.' | fmt
	print

	#
	# Platform Administrator
	#

	print
	gettext 'The Platform Administrator group has configuration control, a
means to get environmental status, the ability to assign boards to domains,
power control and other generic service processor functions.' | fmt
	print

	lookup_sms_group $_plat_admn _current_cfg
	while true; do
		if prompt_sms_group "Platform Administrator" $_current_cfg _group; then
			break;
		fi
	done
	echo "$_plat_admn:$_group" > $TMPGROUPCONFIGFILE

	#
	# Platform Operator
	#

	print
	gettext 'The Platform Operator group has a subset of the platform
privileges, limited generally to platform power control and platform status' \
			| fmt
	print

	lookup_sms_group $_plat_oper _current_cfg
	while true; do
		if prompt_sms_group "Platform Operator" $_current_cfg _group; then
			break;
		fi
	done
	echo "$_plat_oper:$_group" >> $TMPGROUPCONFIGFILE

	#
	# Platform Service
	#

	print
	gettext 'The Platform Service group possess platform service command
privileges in addition to limited platform control and platform configuration
status privileges.' | fmt
	print

	lookup_sms_group $_plat_svc _current_cfg
	while true; do
		if prompt_sms_group "Platform Service" $_current_cfg _group; then
			break;
		fi
	done
	echo "$_plat_svc:$_group" >> $TMPGROUPCONFIGFILE

	typeset _name
	typeset -u _domain_id

	#
	# Domain Administrator
	#
	print
	gettext 'The Domain Administrator group possess domain control and
status, and console access privileges (for the respective domain), but does not
possess platfrom wide control or platform resource allocation privileges.' | fmt
	print

	for admn_group in $_domain_admns; do
		_tmp_id=${admn_group#dmn}
		_domain_id=${_tmp_id%%admn}
		while true; do
			lookup_sms_group $admn_group _current_cfg
			_name="Domain "$_domain_id" Administrator"
			if prompt_sms_group "$_name" $_current_cfg _group
			then
				break;
			fi
		done
		echo "$admn_group:$_group" >> $TMPGROUPCONFIGFILE
	done

	#
	# Domain Reconfiguration
	#

	print
	gettext 'The Domain Reconfiguration group possess a subset of the
Domain Administration group privileges. This group has no domain control other
than board power and reconfiguration (for the respective domain).' | fmt
	print

	for rcfg_group in $_domain_rcfgs; do
		_tmp_id=${rcfg_group#dmn}
		_domain_id=${_tmp_id%%rcfg}
		while true; do
			lookup_sms_group $rcfg_group _current_cfg
			_name="Domain "$_domain_id" Reconfiguration"
			if prompt_sms_group "$_name" $_current_cfg _group
			then
				break;
			fi
		done
		echo "$rcfg_group:$_group" >> $TMPGROUPCONFIGFILE
	done

	cp $TMPGROUPCONFIGFILE $GROUPCONFIGFILE >/dev/null 2>&1;
	if [[ $? -ne 0 ]]; then
		fatal "$(gettext "Error updating group configuration file.")\n"
	fi
	rm -f $TMPGROUPCONFIGFILE

	printf "$(gettext "Configuration complete.")\n\n"
}


# Notes: file access control list feature
#
# 1) Global variables are in uppercase and have the prefix FACL_.
# 2) Names of functions are in lowercase and have the prefix facl_.

# Initialize global variables
typeset facl_test_version=0
typeset facl_debug=0
typeset FACL_USERNAME=""
typeset FACL_CMD_ARG=""
typeset FACL_DOMAIN_ID=""
typeset FACL_SMS_GROUP=""
typeset FACL_RUN_MODE=""
typeset FACL_OPT_U=0
typeset FACL_OPT_CAP_G=0
typeset FACL_OPT_A=0
typeset FACL_OPT_R=0
typeset FACL_OPT_L=0



##########################################################################
#
# facl_display() displays a debug message if $facl_debug is non-zero.
#
# Arguments - $* = string to be displayed.
##########################################################################
facl_display()
{
  [ $facl_debug -ne 0 ] && print "DEBUG: $*"
}


#############################################################################
#
# facl_cleanup_and_exit() - remove all temp files generated
#
# Arguments - $1 = integer exit code.
#
#############################################################################
facl_cleanup_and_exit()
{
  facl_display "Entering facl_cleanup_and_exit()\n"
  if [ $facl_debug -eq 0 ]; then
    /usr/bin/rm -f $ALLSMSTMPFILES
  fi
  exclusive_lock UNLOCK smsconfig
  facl_display "Leaving facl_cleanup_and_exit()\n"

  if [[ -n "$LOG_FILE" ]] ; then
	printf "$(gettext '%s exiting.  Log file is %s.\\n')" $command >$LOG_FILE
  else
	printf "$(gettext '%s exiting.\\n')" $command
  fi

  exit $*
}


##########################################################################
#
# facl_setup_platform_dirs() - generate a file containing the list of
# directories that a platform administrator needs to have access.
#
# Arguments - none.
#
##########################################################################
facl_setup_platform_dirs()
{
  facl_display "Entering facl_setup_platform_dirs()\n"

  if [ $facl_test_version -ne 0 ]; then   # debugging code only
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X./test[1-2]
X./test1/[A-B]
X./test2/[A-B]
END_OF_FILE

  else
    # Platform admins need to have ACLs setup for the following directories
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X/etc/opt/SUNWSMS/SMS
X/etc/opt/SUNWSMS/SMS/config
X/etc/opt/SUNWSMS/SMS/config/platform
X/var/opt/SUNWSMS/SMS
X/var/opt/SUNWSMS/SMS/.lock
X/var/opt/SUNWSMS/SMS/data
X/var/opt/SUNWSMS/SMS/doors
X/var/opt/SUNWSMS/SMS/adm
X/var/opt/SUNWSMS/SMS/adm/platform
X/var/opt/SUNWSMS/SMS/adm/platform/dump
X/var/opt/SUNWSMS/SMS/adm/anonymous
X/var/opt/SUNWSMS/SMS/adm/anonymous/post
X/var/opt/SUNWSMS/SMS/adm/anonymous/dump
END_OF_FILE

    # Platform admins need to have ACLs setup for the following files
    sed "s/^X//" > $FACL_FILE_LIST << END_OF_FILE
X/opt/SUNWSMS/SMS/lib/smsadmin/getscnum
END_OF_FILE

  fi

  facl_display "Leaving facl_setup_platform_dirs()\n"
}


##########################################################################
#
# facl_setup_domain_dirs() - generate a file containing the list of
# directories that a domain administrator needs to have access.
#
# Arguments - none.
#
##########################################################################
facl_setup_domain_dirs()
{
  facl_display "Entering facl_setup_domain_dirs()\n"

  if [ $facl_test_version -ne 0 ]; then    # debugging code only
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X./test[1-2]
X./test1/[A-B]
X./test2/[A-B]
END_OF_FILE

  else
    # Directories applicable to domain admins
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X/etc/opt/SUNWSMS/SMS
X/etc/opt/SUNWSMS/SMS/config
X/etc/opt/SUNWSMS/SMS/config/${FACL_DOMAIN_ID}
X/etc/opt/SUNWSMS/SMS/config/platform
X/var/opt/SUNWSMS/SMS
X/var/opt/SUNWSMS/SMS/.lock
X/var/opt/SUNWSMS/SMS/.lock/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/adm
X/var/opt/SUNWSMS/SMS/adm/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/adm/${FACL_DOMAIN_ID}/post
X/var/opt/SUNWSMS/SMS/adm/${FACL_DOMAIN_ID}/dump
X/var/opt/SUNWSMS/SMS/data
X/var/opt/SUNWSMS/SMS/data/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/doors
X/var/opt/SUNWSMS/SMS/doors/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/pipes
X/var/opt/SUNWSMS/SMS/pipes/${FACL_DOMAIN_ID}
END_OF_FILE
  fi

  facl_display "Leaving facl_setup_domain_dirs()\n"
}


##########################################################################
#
# facl_setup_domain_specific_dirs() -
# This function will be called when the system administrator invokes smsconfig
# to remove a user's domain privileges, and this user currently has both
# domain and platform privileges.
# There is a set of common directories that a user with both domain and
# platform privileges has access to, we construct a list of directories that
# is derived from the set of domain dirs minus the set of platform dirs.  This
# list contains names of directories that are safe to have ACLs cleared.
#
# Arguments - none.
#
##########################################################################
facl_setup_domain_specific_dirs()
{
  facl_display "Entering facl_setup_domain_specific_dirs()\n"

  if [ $facl_test_version -ne 0 ]; then    # debugging code only
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X./test[1-2]
X./test1/[A-B]
X./test2/[A-B]
END_OF_FILE

  else
    # Directories applicable to domain admins
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X/etc/opt/SUNWSMS/SMS/config/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/.lock/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/adm/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/adm/${FACL_DOMAIN_ID}/post
X/var/opt/SUNWSMS/SMS/adm/${FACL_DOMAIN_ID}/dump
X/var/opt/SUNWSMS/SMS/data/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/doors/${FACL_DOMAIN_ID}
X/var/opt/SUNWSMS/SMS/pipes/${FACL_DOMAIN_ID}
END_OF_FILE
  fi

  facl_display "Leaving facl_setup_domain_specific_dirs()\n"
}


##########################################################################
#
# facl_setup_platform_specific_dirs() -
# This function will be called when the system administrator invokes smsconfig
# to remove a user's platform privileges, and this user currently has both
# domain and platform privileges.
# There is a set of common directories that a user with both domain and
# platform privileges has access to, we construct a list of directories that
# is derived from the set of platform dirs minus the set of domain dirs.
# This list contains names of directories that are safe to have ACLs cleared.
#
# Arguments - none.
#
##########################################################################
facl_setup_platform_specific_dirs()
{
  facl_display "Entering facl_setup_platform_specific_dirs()\n"

  if [ $facl_test_version -ne 0 ]; then    # debugging code only
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X./test[1-2]
X./test1/[A-B]
X./test2/[A-B]
END_OF_FILE

  else
    # Directories applicable to domain admins
    sed "s/^X//" > $FACL_DIR_LIST << END_OF_FILE
X/var/opt/SUNWSMS/SMS/adm/platform
X/var/opt/SUNWSMS/SMS/adm/platform/dump
X/var/opt/SUNWSMS/SMS/adm/anonymous
X/var/opt/SUNWSMS/SMS/adm/anonymous/post
X/var/opt/SUNWSMS/SMS/adm/anonymous/dump
END_OF_FILE

    # Files applicable to
    sed "s/^X//" > $FACL_FILE_LIST << END_OF_FILE
X/opt/SUNWSMS/SMS/lib/smsadmin/getscnum
END_OF_FILE

  fi

  facl_display "Leaving facl_setup_platform_specific_dirs()\n"
}


############################################################################
#
# facl_chk_user_in_group() - checks to see if $FACL_USERNAME belongs to a
# group that correspond to value of $FACL_DOMAIN_ID (A-R, platform).
# For example, suppose user jdoe belongs to dmnarcfg, then a call to this
# function with $1="rcfg", $2="realGroupName", the function finds that
# user jdoe does belong to group dmnarcfg and so it will return 0 to indicate
# success, and store the value "dmnarcfg" in the variable $realGroupName
#
# Arguments - $1 = symbolic group name from global variable $FACL_SMS_GROUP
#                  {admn, rcfg, oper, svc}
#             $2 = name of variable to store the name of the real group
#                  correspond to the symbolic group $1
#
# Return -  0 if the user is a member of group $1
#           1 if the user is not a member of group $1
############################################################################
facl_chk_user_in_group()
{
  facl_display "Entering facl_chk_user_in_group() domain=$FACL_DOMAIN_ID symbolicGroup=$FACL_SMS_GROUP\n"

  typeset symbolicGroup=${1}
  typeset realGroupName=${2}
  typeset lookupGroup=""
  typeset user_list
  typeset rc=1

  # 4474012 - smsconfig does not setup ACLs for users whose Unix
  # groups are maintained on NIS
  typeset dname=`echo $FACL_DOMAIN_ID |/usr/bin/tr "[A-R]" "[a-r]"`
  typeset sGroup

  if [ "$dname" != "platform" ]; then
    sGroup="dmn${dname}${symbolicGroup}"
  else
    sGroup="plat${symbolicGroup}"
  fi
  eval "$realGroupName=\"\""

  facl_map_real_group $symbolicGroup $FACL_DOMAIN_ID lookupGroup
  if [ "$lookupGroup" = "$sGroup" ]; then
    # check user_name in local group database /etc/group
    user_list=`awk -F: '/^'${lookupGroup}':/ {print $4}' $ETCGROUPFILE`
    # grep for the exact user in the list for the particular group
    if echo "$user_list" | grep -w $FACL_USERNAME > /dev/null; then
      rc=0
    fi
  elif [[ "$lookupGroup" != "" && "$lookupGroup" != "$sGroup" ]]; then
    if [ $rc -eq 1 ]; then
      # check user_name in NIS group database
      /usr/bin/groups $FACL_USERNAME > /dev/null
      rc=$?
    fi
  fi
  eval "$realGroupName=\"$lookupGroup\""
  facl_display "Leaving facl_chk_user_in_group()\n"
  return $rc

}


############################################################################
#
# facl_map_real_group() - takes args $1 and $2 and map to a real,
# and valid SMS group.
#
# Arguments - $1 = symbolic group name from global variable $FACL_SMS_GROUP
#                  {admn, rcfg, oper, svc}
#             $2 = value from global variable $FACL_DOMAIN_ID
#                  $FACL_DOMAIN_ID has possible values [A-R], platform
#             $3 = name of variable to store the name of the mapped SMS group
# Example of function call:
#   facl_map_real_group "rcfg" "k" realGroupName
# then facl_map_real_group() sets the value of realGroupName to be
# "dmnkrcfg", or a corresponding group name as defined in $GROUPCONFIGFILE
############################################################################
facl_map_real_group()
{
  facl_display "Entering facl_map_real_group()\n"

  typeset symbolicGroup="${1}"
  typeset domain_name=`echo $2 |/usr/bin/tr "[A-R]" "[a-r]"`
  typeset resultValue=${3}
  typeset smsGroup

  if [ "$domain_name" != "platform" ]; then
    smsGroup="dmn${domain_name}${symbolicGroup}"
  else
    smsGroup="plat${symbolicGroup}"
  fi

  output=$(/usr/bin/getent group $smsGroup 2>&1 | head -1)
  if [ $? -ne 0 ]; then
    fatal "$(gettext 'group %s does not exist\\n')" "$smsGroup"
  else
    /usr/bin/grep "^$smsGroup:" $ETCGROUPFILE > /dev/null
    if [ $? -ne 0 ]; then
      printf "$(gettext 'ERROR: the group \"%s\" cannot be found in %s.\\n')" \
		"$smsGroup" "$ETCGROUPFILE"
      gettext 'The group database is probably maintained on a NIS server.\n'
      printf "$(gettext 'Please manually add user \"%s\" to the administrative\\n')" \
		$FACL_USERNAME
      printf "$(gettext 'group \"%s\" then run \"%s\" again.\\n\\n')" \
		"$smsGroup" "$command"
      facl_cleanup_and_exit 2
    fi
  fi

  # if $GROUPCONFIGFILE exists, then lookup the custom group name associated
  # with default sms group name
  if [[ -s $GROUPCONFIGFILE && -r $GROUPCONFIGFILE ]]; then
    typeset lookup=`grep "$smsGroup:" $GROUPCONFIGFILE`
    if [ -n $lookup ]; then
      lookup=${lookup##$smsGroup:}
      if [ -n $lookup ]; then
        smsGroup=$lookup
      fi
    fi
  fi
  eval "$resultValue=\"$smsGroup\""

  facl_display "Leaving facl_map_real_group()\n"
}


############################################################################
#
# facl_add_user() configure ACLs for a user
#
# Arguments - none.
#
############################################################################
facl_add_user()
{
  facl_display "Entering facl_add_user()\n"
  typeset smsGroup=""
  typeset groupMembership="no"

  # check to see if $USERNAME already belong to a proper SMS group
  # (platadmn, platoper, platsvc, dmn[a-r]admn, or dmn[a-r]rcfg, or to a
  # custom SMS group defined in the group map file $GROUPCONFIGFILE)
  facl_chk_user_in_group $FACL_SMS_GROUP smsGroup
  if [ $? -eq 0 ]; then
    groupMembership="yes"
  fi

  # Check if $FACL_USERNAME is already a member of group $FACL_SMS_GROUP
  # if yes, then proceed with setting up ACLs for user.  If user is not
  # a group member then see if the group is locally defined (/etc/group).
  # If yes, then we silently add the user to the group, otherwise, complain
  # then abort.
  if [ "$groupMembership" = "no" ]; then
    if /usr/bin/grep "^${smsGroup}:" $ETCGROUPFILE > /dev/null;  then
      user_list=`awk -F: '/^'${smsGroup}':/ {print $4}' $ETCGROUPFILE`
      if [ "$user_list" = "" ]; then
        facl_display "group $smsGroup has no member"
        # empty user-list, eg "other::1:"
        sed -e '1,$ s!^\('${smsGroup}':.*\)$!\1'${FACL_USERNAME}'!' \
          $ETCGROUPFILE > ${ETCGROUPFILE}_TXT
	/usr/bin/cp -f ${ETCGROUPFILE}_TXT $ETCGROUPFILE
	if [ $? -ne 0 ]; then
		printf "$(gettext 'ERROR: /usr/bin/cp -f %s %s\\n')" \
			"${ETCGROUPFILE}_TXT" "$ETCGROUPFILE"
		printf "$(gettext \
			'Please manually restore file %s from %s\\n')" \
			"$ETCGROUPFILE" "${ETCGROUPFILE}_TXT"
		exclusive_lock UNLOCK smsconfig
		exit 2
	else
		/usr/bin/rm -f ${ETCGROUPFILE}_TXT > /dev/null
          	printf "$(gettext '%s has been added to group %s.\\n')" \
			"$FACL_USERNAME" "$smsGroup"
	fi
      else
        facl_display "group $smsGroup has member(s): $user_list"
        # non-empty user-list, eg "bin::2:root,bin,daemon"
        # grep for the exact user in the list for the particular group
        if ! echo "$user_list" | grep -w ${FACL_USERNAME} > /dev/null; then
           sed -e '1,$ s!^\('${smsGroup}':.*\)$!\1,'${FACL_USERNAME}'!' \
              $ETCGROUPFILE > ${ETCGROUPFILE}_TXT
           /usr/bin/cp -f ${ETCGROUPFILE}_TXT $ETCGROUPFILE
           if [ $? -ne 0 ]; then
	      printf "$(gettext 'ERROR: /usr/bin/cp -f %s %s\\n')" \
			"${ETCGROUPFILE}_TXT" "$ETCGROUPFILE"
	      printf "$(gettext \
			'Please manually restore file %s from %s\\n')" \
			"$ETCGROUPFILE" "${ETCGROUPFILE}_TXT"
	      facl_cleanup_and_exit 2
           else
	      /usr/bin/rm -f ${ETCGROUPFILE}_TXT > /dev/null
              printf "$(gettext '%s has been added to group %s.\\n')" \
			"$FACL_USERNAME" "$smsGroup"
           fi
        fi
      fi
    else
      fatal "$(gettext 'user %s needs to be added to group %s.\\n')"  \
			"$FACL_USERNAME" "$smsGroup"
    fi
  fi

  # generate a list of directories based on the value of $FACL_DOMAIN_ID
  if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
    facl_setup_domain_dirs
  else
    facl_setup_platform_dirs
  fi


  # (begin, fix 4754697 file not found error)
  if [[ -f $FACL_DIR_LIST ]] ; then
    modifyAclEntry="user:${FACL_USERNAME}:rwx"
    modifyFileEntry="user:${FACL_USERNAME}:--x"

    # Set the facls for all the list directories
    for eachDir in `/usr/bin/cat $FACL_DIR_LIST`
    do
      if [ -d $eachDir ]; then
        facl_display "/usr/bin/setfacl -m $modifyAclEntry $eachDir\n"
        # 4472531 - call to setfacl should check for error codes
        /usr/bin/setfacl -m $modifyAclEntry $eachDir > /dev/null 2>&1
        if [ $? != 0 ]; then
          printf "$(gettext '%s: failed to set ACL entries.\\n')" "$eachDir"
        fi
      else
        printf "$(gettext 'ERROR: %s does not exist.\\n')" "$eachDir"
      fi
    done

    # Set the Facls for all list files
    if [[ -s $FACL_FILE_LIST ]] ; then
       for eachFile in `/usr/bin/cat ${FACL_FILE_LIST}`
       do
          if [ -a $eachFile ]; then
             facl_display "/usr/bin/setfacl -m $modifyFileEntry $eachFile\n"
             # 4472531 - call to setfacl should check for error codes
             /usr/bin/setfacl -m $modifyFileEntry $eachFile > /dev/null 2>&1
             if [ $? != 0 ]; then
		printf "$(gettext '%s: failed to set ACL entries.\\n')" \
			"$eachFile"
             fi
          else
		printf "$(gettext 'ERROR: %s does not exist.\\n')" "$eachFile"
          fi
       done
    fi


    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
      printf "$(gettext 'All privileges to domain %s have been applied.\\n')" \
		"$FACL_DOMAIN_ID"
    else
      gettext "All privileges to the platform have been applied.\n"
    fi

  else
	printf "$(gettext 'ERROR: File %s not found.\\n')" \
		"$FACL_DIR_LIST" | fmt
	facl_cleanup_and_exit 2
  fi
  # (end, fix 4754697 file not found error)

  facl_display "Leaving facl_add_user()\n"
}


############################################################################
#
# facl_remove_user() unconfigure ACLs for a user
#
# Arguments - none.
#
############################################################################
facl_remove_user()
{
  facl_display "Entering facl_remove_user()\n"
  typeset smsGroup=""
  typeset groupMembership="no"
  typeset userRemovedFromGroup=0

  # check to see if $USERNAME already belong to a proper SMS group
  # (platadmn, platoper, platsvc, dmn[a-r]admn, or dmn[a-r]rcfg, or to a
  # custom SMS group defined in the group map file $GROUPCONFIGFILE)
  # Also, we can only delete the user from group $smsGroup only if
  # the group is defined locally in the database /etc/group.
  facl_chk_user_in_group $FACL_SMS_GROUP smsGroup
  if [ $? -eq 0 ]; then
    groupMembership="yes"
  fi

  if [ "$groupMembership" = "yes" ]; then
    facl_display "Checking $FACL_USERNAME for $smsGroup group membership\n"

    user_list=`awk -F: '/^'${smsGroup}':/ {print $4}' $ETCGROUPFILE`
    saveFields=`awk -F: '/^'${smsGroup}':/ {print $1 ":" $2 ":" $3 ":"}' $ETCGROUPFILE`
    # grep for the exact user in the list for the particular group
    echo "$user_list" | grep -w ${FACL_USERNAME} > /dev/null
    rc=$?
    if [ $rc -eq 0 ]; then
      # grep for the exact user in the list for the particular group
      if echo "$user_list" | grep -w ${FACL_USERNAME} > /dev/null; then
         # Add commas to the string so each user appears ,USERNAME, it makes
         #    it easier to remove them.  sed removes the users and then
         #    strips the leading and trailing commas
         user_list=`echo ",$user_list," | sed "s/,${FACL_USERNAME},/,/" | sed 's/^[ ,]*//;s/[ ,]*$//'`
      fi

      new_entry="${saveFields}${user_list}"
      facl_display "new_entry=${new_entry}"
      sed -e '1,$ s!^'${smsGroup}':.*$!'${new_entry}'!' $ETCGROUPFILE > ${ETCGROUPFILE}_TXT
      /usr/bin/cp -pf ${ETCGROUPFILE}_TXT $ETCGROUPFILE
      if [ $? -ne 0 ]; then
	printf "$(gettext 'ERROR: /usr/bin/cp -pf %s %s\\n')" \
			"${ETCGROUPFILE}_TXT" "$ETCGROUPFILE"
	printf "$(gettext \
			'Please manually restore file %s from %s\\n')" \
			"$ETCGROUPFILE" "${ETCGROUPFILE}_TXT"
	exclusive_lock UNLOCK smsconfig
	exit 2
      else
	/usr/bin/rm -f ${ETCGROUPFILE}_TXT > /dev/null
	printf "$(gettext '%s has been removed from group %s.\\n')" \
			"$FACL_USERNAME" "$smsGroup"
        userRemovedFromGroup=1
      fi
    elif [ $rc -ne 0 ]; then
      /usr/bin/groups $FACL_USERNAME > /dev/null
      rc=$?
      userRemovedFromGroup=1
	printf "$(gettext \
		'Please remember to manually remove user \"%s\" from group %s.\\n')" \
		"$FACL_USERNAME" "$smsGroup"
    else
	printf "$(gettext '%s is not a member of group %s.\\n')" \
			"$FACL_USERNAME" "$smsGroup"
    fi
  fi

  # If we just removed $FACL_USERNAME from $smsGroup then before we
  # proceed with the removing of the domain or platform ACLs, we need to
  # check to see if $FACL_USERNAME also belong to another administrative
  # group of the same domain or platform.  If that is the case, then we
  # don't remove the domain or platform ACLs.  Example, the system admin
  # runs setup the ACLs for user jdoe for domain A as follows:
  # smsconfig -a -u jdoe -G admn A
  # smsconfig -a -u jdoe -G rcfg A
  # Then the system admin wants to remove user jdoe from domain A's
  # reconfigurator group, he runs
  # smsconfig -r -u jdoe -G rcfg A
  # So the command should remove jdoe from domain A's reconfigurator group
  # and then check to see whether jdoe also belong to domain A's admin
  # group.  If jdoe is not in domain A admin group, then proceed to remove
  # the domain ACLs.  If jdoe is in domain A admin group, then only print
  # a confirmation message that the user has been removed from domain A rcfg
  # group, but it do not remove the domain ACLs.

  if [ -n "$userRemovedFromGroup" ]; then
    typeset ok_to_remove_acls="yes"
  else
    typeset ok_to_remove_acls="no"
  fi
  typeset tmpGroup=""
  typeset saved_facl_domain_id=$FACL_DOMAIN_ID
  typeset userInDmPfGroups=0
  typeset userInAdmnRcfgDomainGroups=0
  typeset userInMultDomainGroups=0
  typeset userInMultPlatformGroups=0

  # display message if user jdoe also belong to an alternate domain/platform
  # group
  if [[ "$FACL_SMS_GROUP" = "admn" && "$FACL_DOMAIN_ID" = "platform" ]]; then
    # the command line looks like: $0 -r -u user-id -G admn platform
    # we need to check to see if user-id is also in oper & svc groups
    for otherGroup in oper svc; do
      facl_chk_user_in_group "$otherGroup" tmpGroup
      if [ $? -eq 0 ]; then
	printf "$(gettext '%s belongs to group %s.\\n')" \
			"$FACL_USERNAME" "$tmpGroup"
        ok_to_remove_acls="no"
        userInMultPlatformGroups=1
      fi
    done

  elif [[ "$FACL_SMS_GROUP" = "oper" && "$FACL_DOMAIN_ID" = "platform" ]]; then
    # the command line looks like: $0 -r -u user-id -G oper platform
    # we need to check to see if user-id is also in admn & svc groups
    for otherGroup in admn svc; do
      facl_chk_user_in_group "$otherGroup" tmpGroup
      if [ $? -eq 0 ]; then
	printf "$(gettext '%s belongs to group %s.\\n')" \
			"$FACL_USERNAME" "$tmpGroup"
        ok_to_remove_acls="no"
        userInMultPlatformGroups=1
      fi
    done

  elif [[ "$FACL_SMS_GROUP" = "svc" && "$FACL_DOMAIN_ID" = "platform" ]]; then
    # the command line looks like: $0 -r -u user-id -G svc platform
    # we need to check to see if user-id is also in admn & oper groups
    for otherGroup in admn oper; do
      facl_chk_user_in_group "$otherGroup" tmpGroup
      if [ $? -eq 0 ]; then
	printf "$(gettext '%s belongs to group %s.\\n')" \
			"$FACL_USERNAME" "$tmpGroup"
        ok_to_remove_acls="no"
        userInMultPlatformGroups=1
      fi
    done

  elif /usr/bin/expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
    if [ "$FACL_SMS_GROUP" = "admn" ]; then
      # the command line looks like: $0 -r -u user-id -G admn <domain_id>
      # we need to check to see if user-id is also in domain_id rcfg group
      facl_chk_user_in_group "rcfg" tmpGroup
      if [ $? -eq 0 ]; then
	printf "$(gettext '%s belongs to group %s.\\n')" \
			"$FACL_USERNAME" "$tmpGroup"
        ok_to_remove_acls="no"
        userInAdmnRcfgDomainGroups=1
      fi

    elif [ "$FACL_SMS_GROUP" = "rcfg" ]; then
      # the command line looks like: $0 -r -u user-id -G rcfg <domain_id>
      # we need to check to see if user-id is also in domain_id admn group
      facl_chk_user_in_group "admn" tmpGroup
      if [ $? -eq 0 ]; then
	printf "$(gettext '%s belongs to group %s.\\n')" \
			"$FACL_USERNAME" "$tmpGroup"
        ok_to_remove_acls="no"
        userInAdmnRcfgDomainGroups=1
      fi
    fi

    # the command line looks like: $0 -r -u user-id -G admn|rcfg <domain_X>
    # need to check to see if user-id is also in other domain groups
    domain_range="A B C D E F G H I J K L M N O P Q R"
    domains_to_check=`echo $domain_range | sed -e 's!'$FACL_DOMAIN_ID'! !'`
    for i in `echo $domains_to_check`; do
      FACL_DOMAIN_ID=$i
      for otherGroup in admn rcfg; do
	facl_chk_user_in_group $otherGroup tmpGroup
	if [ $? -eq 0 ]; then
		ok_to_remove_acls="no"
		userInMultDomainGroups=1
		break
	fi
      done
    done
    FACL_DOMAIN_ID=$saved_facl_domain_id
  fi

  if [ "$FACL_DOMAIN_ID" = "platform" ]; then
    # the command line looks like: $0 -r -u user-id -G admn|oper|svc platform>
    # need to check to see if user-id is in also other domain groups
    for i in A B C D E F G H I J K L M N O P Q R; do
      FACL_DOMAIN_ID=$i
      for otherGroup in admn rcfg; do
	facl_chk_user_in_group "$otherGroup" tmpGroup
	if [ $? -eq 0 ]; then
		ok_to_remove_acls="no"
		userInDmPfGroups=1
		break
	fi
      done
    done

  elif /usr/bin/expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
    # the command line looks like: $0 -r -u user-id -G admn|rcfg domain_X
    # need to check to see if user-id is in also other platform groups
    FACL_DOMAIN_ID="platform"
    for otherGroup in admn oper svc; do
      facl_chk_user_in_group "$otherGroup" tmpGroup
      if [ $? -eq 0 ]; then
	ok_to_remove_acls="no"
	userInDmPfGroups=1
	break
      fi
    done
  fi
  FACL_DOMAIN_ID=$saved_facl_domain_id

  if [ $facl_debug -ne 0 ]; then
    print "DEBUG# ok_to_remove_acls=$ok_to_remove_acls"
    print "DEBUG# userInDmPfGroups=$userInDmPfGroups"
    print "DEBUG# userInMultPlatformGroups=$userInMultPlatformGroups"
    print "DEBUG# userInMultDomainGroups=$userInMultDomainGroups"
    print "DEBUG# userInAdmnRcfgDomainGroups=$userInAdmnRcfgDomainGroups"
  fi

  if [ "$ok_to_remove_acls" = "no" ]; then
    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
      if [ $userInAdmnRcfgDomainGroups -ne 0 ]; then
	printf "$(gettext 'Access to domain %s remains unchanged.\\n')" \
			"$FACL_DOMAIN_ID"
      elif [[ $userInMultDomainGroups -ne 0 || $userInDmPfGroups -ne 0 ]]; then
        facl_setup_domain_specific_dirs
        ok_to_remove_acls="yes"
      fi

    else
      if [ $userInMultPlatformGroups -ne 0 ]; then
	gettext "Access to the platform remains unchanged.\n"
      elif [[ $userInMultDomainGroups -ne 0 || $userInDmPfGroups -ne 0 ]]; then
        facl_setup_platform_specific_dirs
        ok_to_remove_acls="yes"
      fi
    fi

  else
    # generate a list of directories based on the value of $FACL_DOMAIN_ID
    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
      facl_setup_domain_dirs
      ok_to_remove_acls="yes"
    else
      facl_setup_platform_dirs
      ok_to_remove_acls="yes"
    fi
  fi

  # (begin, fix 4754697 file not found error)
  if [[ "$ok_to_remove_acls" = "yes" && -f $FACL_DIR_LIST ]] ; then
    deleteAclEntry="user:$FACL_USERNAME"

    # Remove the facl for each listed directory
    for eachDir in `/usr/bin/cat $FACL_DIR_LIST`
    do
      if [ -d $eachDir ]; then
	facl_display "/usr/bin/setfacl -d $deleteAclEntry $eachDir\n"
        # 4472531 - call to setfacl should check for error codes
	/usr/bin/setfacl -d $deleteAclEntry $eachDir > /dev/null 2>&1
        if [ $? != 0 ]; then
		printf "$(gettext '%s: failed to unset ACL entries.\\n')" \
			"$eachDir"
        fi
      else
		printf "$(gettext 'ERROR: %s does not exist.\\n')" "$eachDir"
      fi
    done

    # Remove the facl for each listed file
    if [[ -s $FACL_FILE_LIST ]] ; then
       for eachFile in `/usr/bin/cat $FACL_FILE_LIST`
       do
          if [ -a $eachFile ]; then
             facl_display "/usr/bin/setfacl -d $deleteAclEntry $eachFile\n"
             # 4472531 - call to setfacl should check for error codes
             /usr/bin/setfacl -d $deleteAclEntry $eachFile > /dev/null 2>&1
             if [ $? != 0 ]; then
		printf "$(gettext '%s: failed to unset ACL entries.\\n')" \
			"$eachFile"
             fi
          else
		printf "$(gettext 'ERROR: %s does not exist.\\n')" "$eachFile"
          fi
       done
    fi

    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
	printf "$(gettext 'All privileges to domain %s are now denied.\\n')" \
			"$FACL_DOMAIN_ID"
    else
      gettext "All privileges to the platform are now denied.\n"
    fi

  elif [ "$ok_to_remove_acls" = "yes" ]; then
	printf "$(gettext 'ERROR: File %s not found.\\n')" \
		"$FACL_DIR_LIST" | fmt
	facl_cleanup_and_exit 2
  fi
  # (end, fix 4754697 file not found error)

  facl_display "Leaving facl_remove_user()\n"
}


############################################################################
#
# facl_list_users() list all users who have platform or domain ACL
# defined.
#
# Arguments - none.
#
############################################################################
facl_list_users()
{
  facl_display "Entering facl_list_users()\n"

  if [ $facl_test_version -ne 0 ]; then        # debugging code
    aDir="./test1/A"
  else
    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
      aDir="${SMSVAR}/adm/${FACL_DOMAIN_ID}"
    else
      aDir="${SMSVAR}/adm/platform"
    fi
  fi

  if [ -d $aDir ]; then
    facl_info="$FACL_TMP_DIR/facl_info.txt"
    user_list="$FACL_TMP_DIR/facl_authorized_users.txt"
    tmp_file="$FACL_TMP_DIR/facl_tmp_file.txt"

    facl_display "getfacl $aDir > $tmp_file | sed '....' > $facl_info"

    /usr/bin/getfacl $aDir > $tmp_file
    /usr/bin/cat $tmp_file | \
      sed -e 's!		#effective.*!!'  \
          -e 's!\# file:.*!!'   \
          -e 's!\# owner:.*!!'  \
          -e 's!\# group:.*!!'  \
          -e 's!user::.*!!'     \
          -e 's!group::.*!!'    \
          -e 's!mask:.*!!'      \
          -e 's!other:.*!!'     > $facl_info

    # start with a blank file
    [ -f $user_list ] && /usr/bin/rm -f $user_list

    # Verify that $facl_into_file exist & has size greater than zero
    if [ -s $facl_info ]; then
      # parse each line in $facl_info
      for line in `/usr/bin/cat $facl_info`
      do
        if [ "$line" = "" ]; then
          continue
        fi

        user_name=`echo $line | awk -F: '/^user/ {print $2}'`
        print "$user_name" >> $user_list
        facl_display "user_name=$user_name"
      done
    fi

  else
    printf "$(gettext 'ERROR: Directory %s not found.\\n')" "$aDir"
    facl_cleanup_and_exit 2
  fi

  # display list of authorized platform or domain users
  if [ -s $user_list ]; then
    /usr/bin/cat "$user_list"
  else
    gettext "no authorized users\n"
  fi

  facl_display "Leaving facl_list_users()\n"
}


###########################################################################
#
# facl_validate_opts_args() verify that smsconfigacl was invoked with the
# appropriate options and arguments.
#
# Arguments - none.
###########################################################################
facl_validate_opts_args()
{
  facl_display "Entering facl_validate_opts_args()\n"

  # verify that the command line argument (if specified) has a valid value
  if [ "$FACL_CMD_ARG" != "" ]; then
    facl_display "command argument: $FACL_CMD_ARG"
  fi
  case "$FACL_CMD_ARG" in
    [a-rA-R])
       FACL_DOMAIN_ID=`echo $FACL_CMD_ARG |/usr/bin/tr "[a-r]" "[A-R]"`
       ;;
    platform)
       FACL_DOMAIN_ID="platform"
       ;;
    *)
       if [ "$FACL_CMD_ARG" = "" ]; then
         gettext "command argument not specified\n"
       else
         gettext "invalid command argument\n"
       fi
       usage
       exclusive_lock UNLOCK smsconfig
       exit 2
       ;;
  esac

  # verify the argument to -G option has a valid value (if the option was set)
  if [ $FACL_OPT_CAP_G -ne 0 ]; then
    case "$FACL_SMS_GROUP" in
      admn | rcfg | oper | svc)
         ;;
      *) gettext "invalid argument specified for option -G\n"
         usage
         exclusive_lock UNLOCK smsconfig
         exit 2
         ;;
    esac
  fi

  # if $FACL_USERNAME is set, then verify that it is a valid username
  if [ $FACL_OPT_U -ne 0 ]; then
    /usr/bin/id "$FACL_USERNAME" > /dev/null 2>&1
    if [ $? -ne 0 ]; then
      fatal "$(gettext 'Invalid user name %s')" "$FACL_USERNAME"
    fi
  fi


  if [[ "$FACL_RUN_MODE" = "add-user" || "$FACL_RUN_MODE" = "remove-user" ]]
  then
    if [ $(($FACL_OPT_U + $FACL_OPT_CAP_G)) -lt 2 ]; then
      printf "$(gettext 'Both -u and -G options are required.\n')"
      usage
      exclusive_lock UNLOCK smsconfig
      exit 2
    fi
    # make sure that we don't have inconsistency situations like
    # $command -a -u jdoe -G rcfg platform
    # $command -a -u jdoe -G oper D, or
    if [[ "$FACL_SMS_GROUP" = "rcfg" && "$FACL_DOMAIN_ID" = "platform" ]]; then
      fatal "$(gettext 'Group %s cannot access the platform')" \
		"$FACL_SMS_GROUP"
    fi
    if [[ "$FACL_SMS_GROUP" = "oper" || "$FACL_SMS_GROUP" = "svc" ]]; then
      case "$FACL_DOMAIN_ID" in
      [a-rA-R])
        fatal "$(gettext 'Group %s cannot access a domain')" \
		"$FACL_SMS_GROUP"
        ;;
      esac
    fi
  fi

  facl_display "Leaving facl_validate_opts_args()\n"
}


##########################################################
#
# exclusive_lock
#
# $1 LOCK or UNLOCK
# $2 lock name
#
##########################################################
exclusive_lock()
{
    [[ -z "$1" ]] && fatal_nounlock "$(gettext "getlock called without a lock arg.")"
    [[ "$1" == LOCK || "$1" == UNLOCK ]] ||
	fatal_nounlock "$(gettext "getlock called without a valid lock arg.")"
    [[ -z "$2" ]] && fatal_nounlock "$(gettext "getlock called without a lock name.")"
    LOCKARG=$1 # LOCK or UNLOCK
    LOCKNAME=$2 # Usually program name
    [[ -d $LOCKDIR ]] || fatal_nounlock "$(printf "$(gettext "LOCKDIR \"%s\" does not exist")\n" $LOCKDIR)"

    mainlock=$LOCKDIR/"$LOCKNAME".lock
    dellockbase=$LOCKDIR/"$LOCKNAME".DELETE.lock

    if [[ "$LOCKARG" == UNLOCK ]];  then
        lockpid=$(ls -l $mainlock 2>/dev/null | awk '{print $NF}')
        # Only UNLOCK if I created the lock.
        if [[ -n "$lockpid" ]] && (( lockpid == $$ )); then
            rm -f $mainlock
            return 0
        fi
        return 1
    fi

    typeset cnt=0
    while (( cnt < 5 )); do
	cnt=$((cnt + 1))

	# Try to create the lock, a symbolic that points the PID ($$) of this
        # process.  This creates the lock with a fixed name along with the
        # PID in an atomic operation.
	if ln -s $$ ${mainlock} 2>/dev/null; then
		# Successfully got the lock, delete any delete locks
		# for clean-up purposes.
		rm -f ${dellockbase}.[1-9]*
		return 0 # Won the lock.
	fi

	# See if existing lock is valid (associated PID is alive).
	lockpid=$(ls -l $mainlock 2>/dev/null | awk '{print $NF}')
	[[ -z "$lockpid" ]] && continue # Lock disappeared! Try again.

	if kill -0 $lockpid 2>/dev/null ; then
		echo $lockpid # Return PID of locking process.
		return 1 # LOCKED
	fi

	# Main lock is invalid; try to win DELETE lock to blow it away.
	# Delete lock name is based on PID of process that locked mainlock,
	# plus a sequence number.  There is a tiny chance that the delete
	# lock will be invalid, so we do it in a loop, sleeping a random
	# number of seconds each iteration to avoid a race condition.
	ndellocks=0
	dellock=$dellockbase.$lockpid.$ndellocks

	until ln -s $$ $dellock 2>/dev/null; do
		dellockpid=$(ls -l $dellock 2>/dev/null | awk '{print $NF}')
		[[ -z "$dellockpid" ]] && break # Lock disappeared.
		kill -0 $dellockpid && break # Valid delete lock.
		ndellocks=$((ndellocks + 1))
		dellock=$dellockbase.$lockpid.$ndellocks
		sleep $((RANDOM % 5 + 1))
	done

	# Did we win a delete lock?
	dellockpid=$(ls -l $dellock 2>/dev/null | awk '{print $NF}')
	[[ "$dellockpid" == $$ ]] || continue

	# Before deleting main lock, make sure it's still there and
	# is still allocated for the same PID.
	curlockpid=$(ls -l $mainlock 2>/dev/null | awk '{print $NF}')
	[[ -n "$curlockpid" && "$curlockpid" == "$lockpid" ]] && rm -f $mainlock
    done
    return 2
}


##########################################################################
#
# displayDebugMsg()
#
# Display debug message. This method can be a generic method
# for debugging.
#
# 4508204: fomd shouldn't use R* services
##########################################################################
displayDebugMsg()
{
	if [[ $DEBUG_ON == 1 ]]; then
		print "DEBUG:" $1
	fi
}


##########################################################################
#
# validateShellOptsArgs()
#
# $1 - security function, e.g: ssh
# $2 - command line argument associated with $1, e.g: ssh path.
#
# return:
# 0     - success
# 1     - fail
#
# 4508204: fomd shouldn't use R* services
##########################################################################
validateShellOptsArgs()
{
	displayDebugMsg "In validateShellOptsArgs()"

	case $1 in
		rsh)	useSecureShell=0
			;;
		ssh)
			useSecureShell=1
			;;
		*)
			printf "$(gettext "ERROR: Invalid argument %s \n")" \
									"${1}"
			usage
			exit 1
			;;
	esac
}

##########################################################################
# checkSSHExist()
#
# This method checks to see if ssh & scp exist in /usr/bin.
#
##########################################################################
checkSSHExist()
{
	displayDebugMsg "In checkSSHExist()"

	#
	# check if /usr/bin/ssh and /usr/bin/scp exist.
	#
	if [[ ! -e ${sshPath} ]]; then
		printf "$(gettext "%s does not exist.")\n" "${sshPath}"
		return 1
	fi

	if [[ ! -e ${scpPath} ]]; then
		printf "$(gettext "%s does not exist.")\n" "${scpPath}"
		return 1
	fi

	#
	# check if /usr/bin/ssh and /usr/bin/scp executable.
	#
	if [[ ! -x ${sshPath} ]]; then
		printf "$(gettext "%s is not executable.")\n" "${sshPath}"
		return 1
	fi

	if [[ ! -x ${scpPath} ]]; then
		printf "$(gettext "%s is not executable.")\n" "${scpPath}"
		return 1
	fi

	return 0
}

##########################################################################
#
# promptUser()
#
# This method is the generic method used to prompt the user
# $1    - prompting string
# $2    - the default answer if there is one.
#
##########################################################################
promptUser()
{
	displayDebugMsg "In promptUser()"
	set -f
	typeset prompt="$(echo ${1})"
	typeset default="$(echo ${2})"
	set +f
	typeset answer=""
	typeset trailer=""

	#
	# if there is a default value, shift the terminating ? or : character
	#
	# e.g: prompt: "abcde?"
	#      after shift: "abcde [default]?"
	#
	if [[ -n "${default}" ]]; then

		if [[ "${prompt}" == *\? ]]; then
			trailer="?"
		elif [[ "${prompt}" == *: ]]; then
			trailer=":"
		fi

		if [[ -n "${trailer}" ]];then
			prompt="${prompt} [${default}]${trailer}"
		else
			prompt="${prompt} [${default}]"
		fi
	fi

	#
	# Display the prompt and get the user's response.
	#
	# Loop until an answer is given. Or, if there is a default,
	# the user does not need to supply an answer.
	#
	# It is illegal for the user to supply more than one value
	# at the prompt.
	#

	echo
	let i=0
	while true
	do
		#
		# If it is not the first time through, beep.
		#
		[[ ${i} -gt 0 ]] && echo "\a\c"
		let i=1
		#
		# Prompt and get response
		#
		printf "$(gettext "%s ")" "${prompt}"
		read answer foo

		#
		# Return 1 on EOF and error
		#
		if [[ $? -eq 1 ]]; then
			echo
			return 1
		fi

		#
		# If there is more than one arg, repeat prompt
		#
		if [[ -n "${foo}" ]]; then
			continue
		fi

		#
		# If no answer, default is the answer given that default
		# has value.
		#
		if [[ -z "${answer}" ]] && [[ -n "${default}" ]];then
			answer="${default}"
		fi

		#
		# If no answer and no default, repeat prompt
		#
		if [[ -z "${answer}" ]]; then
			echo ""
			continue
		fi


		#
		# Get the answer
		#
		break
	done

	USER_ANSWER=$answer
	printf  "$(gettext "%s")" ${USER_ANSWER}
	echo
}

##########################################################################
#
# checkSSHEnabled()
#
# This method verifies if ssh works between the local and remote systems.
# on the I2 (SC<->SC) network.
# The method will execute a remote command. If the remote command is hung,
# it means:
# 1. ssh is not configured to allow root login without password
# 2. the remote system is down.
# 3. the I2 network is down.
#
# In any of the above cases, we conclude that ssh is not enabled on
# the system, and will try to fall back to rsh.
#
# Argument:
# ${1}  - ssh path
# ${2}  - remote SC IP address
#
# Return:
# 0     - ssh is enabled
# 1     - ssh is not enabled
#
# 4508204: fomd shouldn't use R* services
##########################################################################
checkSSHEnabled()
{

	displayDebugMsg "In checkSSHEnabled()"

	typeset SSH=${sshPath}

	#
	# $SSH should not have zero size.
	#
	if [[ ! -s ${SSH} ]]; then
		return 1
	fi

	rm /tmp/.sshout >/dev/null 2>&1

	printf "$(gettext "\nEnabling ssh...")\n"
	gettext "Password/passphrase authentication can be ignored\n"


	#
	# In case the process hangs in password prompt,
	# put the process in background.
	#
	${SSH} ${remoteSCI2HostIp} touch /tmp >/tmp/.sshout 2>&1 &

	#
	# Get the ssh process ID.
	#
	sshPid=$!
	displayDebugMsg "sshPid: $sshPid"

	#
	# Added 1 sec delay so that it can capture the error message.
	#
	sleep 1

	#
	# if the remote ssh process is still running, it
	# can be either stuck in the password prompt, or
	# experiencing network delay. Let's wait for
	# 15 secs because it takes ~15 seconds for
	# ssh to be fully functioning.
	#
	i=0
	while [ "$i" -lt 15 ]
	do

		#
		# Check if there is error message generated.
		#
		# When the sshd server is disabled, the ssh
		# connection request will be timeout with
		# a error message from ssh.
		#
		if [ -s "/tmp/.sshout" ];then
			displayDebugMsg "/tmp/.sshout contains ssh error msg."
			break
		fi

		#
		# When gets here, it means no error message found.
		# Check to see if sshPid exists. If ps can't
		# find the sshPid, it means the ssh exits with
		# no error.
		#
		ps -p $sshPid > /dev/null

		if [[ $? != 0 ]]; then
			return 0
		fi
		sleep 1
		(( i += 1 ))
		continue
	done

	#
	# Checking if the ssh still exists. If yes, it is most likely
	# that ssh is waiting for password input. It implies that ssh
	# is not configured right, let's terminate the ssh.
	#
	ps -p $sshPid > /dev/null
	if [[ $? == 0 ]]; then
		kill -15 $sshPid >/dev/null 2>&1
		sleep 2
		kill -9 $sshPid >/dev/null 2>&1
		printf "$(gettext "\n%s: Permission denied.")\n" "${SSH}"

	fi
	return 1
}

##########################################################################
#
# createSoftLinks()
#
# This method creates ssh/scp softlink under /opt/SUNWSMS/bin/ to the
# standard the ssh/scp location, /usr/bin. These softlinks are the flag
# to tell SMS software ssh/scp instead of rsh/rcp.
#
# 4508204: fomd shouldn't use R* services
##########################################################################
createSoftLinks()
{
	displayDebugMsg "In createSoftLink()"

	/usr/bin/rm -f ${SSH_LINK} >/dev/null 2>&1
	/usr/bin/rm -f ${SCP_LINK} >/dev/null 2>&1

	/usr/bin/ln -fs $sshPath ${SSH_LINK}
	/usr/bin/ln -fs $scpPath ${SCP_LINK}
}


##########################################################################
#
# getRemoteSCI2Ip()
#
# It requires to have MAN.cf set up. It gets the remote IP from MAN.cf
# and .remotesc files.
#
# 4508204: fomd shouldn't use R* services
##########################################################################
getRemoteSCI2Ip()
{
	displayDebugMsg "In getRemoteSCI2Ip() "

	typeset MANCONFIGFILE
	MANCONFIGFILE="/etc/opt/SUNWSMS/config/MAN.cf"

	if [[ ! -e ${MANCONFIGFILE} ]]; then

		$gettext 'smsconfig -m has not been run:
unable to get remote SC IP address\n' | fmt
		exit 2
	fi

	grep -v "^\#" ${MANCONFIGFILE} > /dev/null 2>&1
	if [[ $? != 0 ]]; then

		gettext 'smsconfig -m has not been run:
unable to get remote SC IP address\n' | fmt
		exit 2
	fi

	i2SC0Host=`egrep SC0-I2 ${MANCONFIGFILE} | egrep -v "^#" | \
							awk '{print $3}'`
	i2SC1Host=`egrep SC1-I2 ${MANCONFIGFILE} | egrep -v "^#" | \
							awk '{print $3}'`

	i2SC0HostIp=`egrep SC0-I2 ${MANCONFIGFILE} | egrep -v "^#" | \
							awk '{print $4}' `
	i2SC1HostIp=`egrep SC1-I2 ${MANCONFIGFILE} | egrep -v "^#" | \
							awk '{print $4}' `

	remoteSCI2Host=$i2SC1Host
	remoteSCI2HostIp=$i2SC1HostIp

	displayDebugMsg "sc0host: $i2SC0Host, sc0hostIp: $i2SC0HostIp"
	displayDebugMsg "sc1host: $i2SC1Host, sc1hostIp: $i2SC1HostIp"

	if [[ -f ${PRIVATE_REMOTEHOST} ]]; then
		egrep "$i2SC0Host" ${PRIVATE_REMOTEHOST} >/dev/null 2>&1
	else
		gettext 'Unable to obtain remote SC IP address\n' | fmt
		return 1
	fi

	if [[ $? == 0 ]]; then
		remoteSCI2Host=$i2SC0Host
		remoteSCI2HostIp=$i2SC0HostIp
	fi
	displayDebugMsg "Remote SC I2 Ip: $remoteSCI2HostIp"

	return 0

}

##########################################################################
# useRShell()
#
# It removes the ssh/scp softlinks in /opt/SUNWSMS/bin, and unhardens
# the r* service via enableRservices
#
##########################################################################
useRShell()
{
        /usr/bin/rm -f $SSH_LINK >/dev/null 2>&1
        /usr/bin/rm -f $SCP_LINK >/dev/null 2>&1
	printf "$(gettext "\nEnabling rsh...")\n"
        eval /opt/SUNWSMS/SMS/lib/smsadmin/enableRservices
	if [[ $? -ne 0 ]]; then
		printf "$(gettext 'Failed to enable rsh')\n"
		return 1
	fi
	return 0
}

##########################################################################
#
# enableShellOnSystem()
#
# Implements smsconfig -s.
#
# This method does the following:
# - Validate the command arguments.
# - Enable ssh/rsh according to the command arguments.
# - Check if ssh exists on the system
# - Prompt the user for ssh path if can't find ssh on the system.
# - Check if ssh is enabled in such way to allow root login without password.
# - If yes, create a softlink to identify the ssh/scp location.
#
# Argument:
# $1    - remote SC IP address.
#
# Return:
# 0     - success
# 1     - fail
#
# 4508204: fomd shouldn't use R* services
##########################################################################
enableShellOnSystem()
{
	displayDebugMsg "In enableShellOnSystem()"

	typeset rc=0

	#
	# Function calls
	#
	validateShellOptsArgs $@

	if [[ $useSecureShell == 0 ]]; then

		useRShell
		if [[ $? -eq 0 ]]; then
			printf "$(gettext "\nSystem will use rsh. ")\n\n"
			return 0
		fi
		return 1
	fi

	getRemoteSCI2Ip
	if [[ $? != 0 ]]; then
		printf "$(gettext "%s is not enabled.")\n\n" "${sshPath}"
		return 1
	fi

	checkSSHExist
	if [[ $? != 0 ]]; then
		printf "$(gettext "%s is not enabled.")\n\n" "${sshPath}"
		return 1
	fi

	checkSSHEnabled
	if [[ $? != 0 ]]; then
		printf "$(gettext "%s is not enabled.")\n\n" "${sshPath}"
		return 1
	fi

	createSoftLinks

	printf "$(gettext "\nSystem will use %s.")\n" "${sshPath}"
	echo
	return 0
}


##########################################################################
#
# displaySystemConfiguration
#
# Display system configuration including ACL, man network, remote shell
# Implements smsconfig -v.
#
# Note: For now, we only display the remote shell.
#
#########################################################################
displaySystemConfiguration()
{

	#
	# Display remote shell
	#
	echo
	gettext "Remote Shell\n"
	gettext "============\n"
	displayRemoteShell
	echo
}


##########################################################################
#
# displayRemoteShell()
#
# Display which remote shell the SMS software is using.
# Called by displaySystemConfiguration to implement smsconfig -v.
#
# This method will check to see if ssh/scp link exists in
# /opt/SUNWSMS/SMS/bin. If yes, the method will display the actual
# Secure Shell the link references.
#
##########################################################################
displayRemoteShell()
{

	typeset actualsshPath
	#
	# Check if the ssh/scp link exists.
	#
	if [[ -e ${SSH_LINK} && -e ${SCP_LINK} ]]; then

		actualsshPath=`ls -l $SSH_LINK  | cut -d'>' -f2`
		printf "$(gettext "Remote Shell \t\t %s")\n" "${actualsshPath}"
	else
		printf "$(gettext "Remote Shell \t\t %s")\n" "/usr/bin/rsh"

	fi
}





##########################################################
#
# MAIN CODE STARTS HERE
#
##########################################################
trap 'print "\n$command \c"; gettext "interrupted; exiting.\n"|tee -a $LOG_FILE; \
	/usr/bin/rm -rf $ALLSMSTMPFILES; exit 3' \
	HUP INT QUIT TERM
umask 033 # No write or execute permission for group or others for new files
PATH=$PATH:/usr/sbin:/usr/bin
/usr/bin/rm -rf $ALLSMSTMPFILES

# check for a help request
[[ $1 = "-h" ]] && usage && exit 0

# Make sure only one instance of the command is running.
lockPid=$(exclusive_lock LOCK smsconfig)
lockStat=$?
[[ $lockStat = 2 ]] && exit 1
[[ $lockStat = 0 ]] ||
	fatal_nounlock "$(printf "$(gettext "An smsconfig command, with PID %s, is already running.")" $lockPid)"

# Install full interrupt handler now that locking is complete:
trap 'exclusive_lock UNLOCK smsconfig; \
	print "\n$command \c"; gettext "interrupted; exiting.\n" | \
	tee -a $LOG_FILE; /usr/bin/rm -rf $ALLSMSTMPFILES; exit 3' \
	HUP INT QUIT TERM


#
# Check the command used, parse arguments, and call the appropriate functions.
#
case "$command" in
smsbackup)
	require_root
	#require_sms_stopped
	select_log
	check_active_version
	validate_backup_args ${1:-/var/tmp} ${ACTIVE_SMS_VERSION}
	perform_backup
	;;

smsrestore)
	require_args 1 $#
	require_root
	#require_sms_stopped
	select_log
	check_active_version
	validate_restore_args $1
	perform_restore
	;;

smsversion)
	require_root
	select_log
	check_active_version
        # Just getting the version number
	if [[ $subcommand == "-t" ]]; then
	   print_terse_version
	   exclusive_lock UNLOCK smsconfig
	   exit 0
	fi

        # Actual version switching
	print_active_version
	check_and_choose_version $*
	if [[ $? -eq 0 ]]; then
           get_backup_destination $subcommand
           # determine if we are falling back and set flag
           #  for perform_backup
           set_convert_flag $subcommand
	   perform_backup
           printf "$(gettext '%s: Switching to target version <%s>.')\n" \
              $command $subcommand
           version_cmp $subcommand $ACTIVE_SMS_VERSION
           v_result=$?

           # Switch downward
           if [[ "$v_result" == "255" ]]; then
              /opt/SUNWSMS/SMS${ACTIVE_SMS_VERSION}/lib/smsadmin/updatesys -c -d /var/tmp
              update_result=$?
              if [[ "$update_result" == "0" ]]; then
                 move_links $subcommand
              fi

           # Switch upward
           elif [[ "$v_result" == "1" ]]; then
              move_links $subcommand
              /opt/SUNWSMS/SMS$subcommand/lib/smsadmin/updatesys -p -d /var/tmp
              update_result=$?

              if [[ "$update_result" != "0" ]]; then
                 move_links $ACTIVE_SMS_VERSION
              fi

           # Switch to the same version
           else
              move_links $subcommand
              update_result=0
           fi

           if [[ "$update_result" != "0" ]]; then
              fatal "$(printf "$(gettext "%s: updatesys command failed to update the system with %s, version switch failed.")" \
                 $command $update_result)"
           fi
	   check_active_version
	   print_active_version
           printf "$(gettext 'To restore previous the SMS configuration setting type: smsrestore %s')\n" \
              $SMS_BACKUP
        else
           # If check_and_choose returned non-zero there was an error
           #  and we need to exit with a non-zero value to indicate that
           exit 1
	fi
	;;

smsconfig)
        # ###################################################################
        # Make sure the options are valid and consistent
        # The user is allowed to configure only one thing at a time, that is,
        # there is four mutually exclusive actions: 1) -h, 2) -m, 3) -g,
        # and 4) -a -r -l -u, and -G
        # ###################################################################
        opt_acl=0
        opt_man=0
        opt_group=0
        opt_help=0
	opt_ssh=0       # ssh
	opt_verbose=0
        opt_unknown=0
        while getopts hmgu:G:arls:d:v optname $*
        do
          case "$optname" in
          m) opt_man=1 ;;
          g) opt_group=1 ;;
          a) opt_acl=1
             FACL_OPT_A=1
             FACL_RUN_MODE="add-user"
             ;;
          r) opt_acl=1
             FACL_OPT_R=1
             FACL_RUN_MODE="remove-user"
             ;;
          l) opt_acl=1
             FACL_OPT_L=1
             FACL_RUN_MODE="list-users"
             ;;
          u) opt_acl=1
             FACL_USERNAME=$OPTARG
             FACL_OPT_U=1
             ;;
          G) opt_acl=1
             FACL_SMS_GROUP=$OPTARG
             FACL_OPT_CAP_G=1
             ;;
	  s) opt_ssh=1          # ssh
	     ;;
	  v) opt_verbose=1
	     ;;
	  #
	  # While adding secure section, add debug option.
	  #
	  d) DEBUG_ON=1
	     shift
	     subcommand=$1
	     ;;
          h) opt_help=1 ;;
          *) opt_unknown=1 ;;
          esac
        done

        sum_opts=$(($opt_man +$opt_group +$opt_acl +$opt_help + $opt_unknown
						+ $opt_ssh + $opt_verbose))
        if [ $sum_opts -gt 1 ]; then
		usage
		exclusive_lock UNLOCK smsconfig
		exit 2
        fi
        sum_opts=$(($FACL_OPT_A + $FACL_OPT_R + $FACL_OPT_L))
        if [ $sum_opts -gt 1 ]; then
		usage
		exclusive_lock UNLOCK smsconfig
		exit 2
        fi


        #
        # Check the options
        #
        case "$subcommand" in
	-m)
		shift
		require_root
		select_log
		sms_man_setup $* 2>&1 | tee ${LOG_FILE}
		;;

	-g)
		require_args 1 $#
		require_root
		select_log
		sms_group_main
		;;

        -a | -r | -u | -G | -l)
                shift $(( OPTIND - 1 ))
                FACL_CMD_ARG=$1
		require_root
		facl_validate_opts_args
		case "$FACL_RUN_MODE" in
		"add-user")     facl_add_user ;;
		"remove-user")  facl_remove_user ;;
		"list-users")   facl_list_users ;;
		esac
		;;

	#
	# smsconfig -s ssh [ssh_path]
	# After shift:
	# $1: -s
	# $2: ssh_path if provided
	#
	-s)
		shift
		if [[ $# > 1 ]]; then
			usage
			exit 2
		fi

		require_root

		enableShellOnSystem $@
		if [[ "$?" != 0 ]]; then
			exit 2
		fi
		;;
	-v)
		shift
		if [[ $# > 1 ]]; then
			usage
			exit 2
		fi
		require_root

		displaySystemConfiguration
		if [[ "$?" != 0 ]]; then
			exit 2
		fi
		;;
	*)
		usage
		exclusive_lock UNLOCK smsconfig
		exit 2
		;;
	esac
	;;
*)
	usage
        exclusive_lock UNLOCK smsconfig
	exit 2
	;;
esac

#
# Normal cleanup and exit
#
exclusive_lock UNLOCK smsconfig
date >>$LOG_FILE
# begin, 4633179/ 4634829
if [[ -n "$LOG_FILE" ]] ; then
	printf "$(gettext '%s complete.  Log file is %s.\\n')" \
		$command $LOG_FILE | tee -a $LOG_FILE
else
	printf "$(gettext '%s complete.\\n')" $command
fi
/usr/bin/rm -rf $ALLSMSTMPFILES
# end, 4633179/ 4634829


exit 0
