#! /usr/bin/ksh
#
# ident   "@(#)smsconfig.ksh 1.90     03/02/10 SMI"
#
# Copyright (c) 2000-2002 by Sun Microsystems, Inc.
# All rights reserved.
#
#
# Setup for Internationalization
#
export TEXTDOMAIN=SUNW_ESSMS_CMD
export TEXTDOMAINDIR=/opt/SUNWSMS/lib/locale

# Setup some globals
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

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

MANCONFIGFILENAME=MAN.cf
MANCONFIGFILE=${SMSCONFIGDIR}/$MANCONFIGFILENAME
TMPMANCONFIGFILE=${ROOT}/tmp/${MANCONFIGFILENAME}.$$
TMPCMDS=${ROOT}/tmp/MANcmds$$.sh
TMPFOADDRS=${ROOT}/tmp/foaddrs.$$
# 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
TMPGROUPCONFIGFILE=${ROOT}/tmp/$GROUPCONFIGFILENAME.$$
RHOSTSFILE=${ROOT}/.rhosts
TMPRHOSTSFILE=${ROOT}/tmp/.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
DATASYNC=0

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

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


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

	smsconfig)
		printf "$(gettext "\nusage:\n   %s -m")\n" $command 1>&2
		printf "$(gettext "   %s -m I1 [domain_id|sc]")\n" $command 1>&2
		printf "$(gettext "   %s -m I2 [sc0|sc1]")\n" $command 1>&2
		printf "$(gettext "   %s -m L [sc]")\n" $command 1>&2
		printf "$(gettext "   %s -g")\n\n" $command 1>&2
		printf "$(gettext "   %s -a -u username -G admn|oper|svc platform")\n" $command 1>&2
		printf "$(gettext "   %s -a -u username -G admn|rcfg     <domain_id>")\n" $command 1>&2
		printf "$(gettext "   %s -r -u username -G admn|oper|svc platform")\n" $command 1>&2
		printf "$(gettext "   %s -r -u username -G admn|rcfg     <domain_id>")\n" $command 1>&2
		printf "$(gettext "   %s -l domain_id | platform")\n" $command 1>&2
		printf "$(gettext "   %s -h")\n" $command 1>&2
		;;
	smsbackup)
		printf "$(gettext "\nusage:\n   %s directory_name")\n" $command 1>&2
		printf "$(gettext "   %s -h")\n\n" $command 1>&2
		;;
	smsrestore)
		printf "$(gettext "\nusage:\n   %s filename")\n" $command 1>&2
		printf "$(gettext "   %s -h")\n\n" $command 1>&2
		;;
	smsversion)
		printf "$(gettext "\nusage:\n   %s new_version")\n" $command 1>&2
		printf "$(gettext "   %s -h")\n\n" $command 1>&2
		;;
	smsmanopt)
		# TRANSLATION_NOTE: Do not translate domain/sc/netmask
		printf "$(gettext "\nusage:\n   %s -m [I1|I2|L] [domain | sc | netmask]")\n\n" $command 1>&2
		;;
	*)
		printf "$(gettext "\nusage:\n   %s [ -m ] | [ -g ] | [ -a | -r | -l [-u username] [-G admn|rcfg|oper|svc] {domain_id | platform} ] | [ -h ]")\n\n" $command 1>&2
		;;
	esac
	return 0
}


#############################################################################
#
# Generic routine for fatal errors.  Displays error message ($*) and exits.
#
#############################################################################
fatal_nounlock()
{
	typeset fmt="$1"
	shift
	printf "$(gettext "ERROR: ")""$fmt\n" "$@" >&2
	[[ -n "$DEBUG" ]] && yes_or_no $(gettext "Continue? ") >&2 && return 0
	print -u2 $(gettext "ABORTING.")
	exit 2
}

fatal()
{
	exclusive_lock UNLOCK smsconfig
	fatal_nounlock "$@"
}


#############################################################################
#
# getuid
#
# Returns the uid (integer) for the process on stdout.
#
#############################################################################
getuid()
{
	typeset uid=$(id)
	eval ${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
		printf "%s\n" "$response" | /usr/xpg4/bin/grep -Eq "$(locale yesexpr)" && return 0
		printf "%s\n" "$response" | /usr/xpg4/bin/grep -Eq "$(locale noexpr)" && 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.
#
#############################################################################
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.
			# This method is called by smsversion.
			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.
#
#############################################################################
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 root privileges.
#
#############################################################################
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
	print "Command: $command $1 $2 $3 $4" >| ${LOG_FILE}
	date >> ${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
		print
		gettext "The platform name identifies the entire host\n"
		gettext "machine to the SMS software.  The platform name\n"
		gettext "occupies a different name space than domain\n"
		gettext "names (hostnames of bootable systems).\n"
		print

		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)
#
#############################################################################
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 "%s not in valid IPv4 address range.")\n" $_addr 1>&2
			[[ $_maxbyte4 -ne 255 ]] &&
				printf "$(gettext "Max 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
#
#############################################################################
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} 225; 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.
#
#############################################################################
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 225; 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 225
		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
}


#############################################################################
#
# 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 succssful
# $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 ${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,
# and the return status of the match (0=OK)
#
# Use /etc/nsswitch.conf file (to decide between NIS+, NIS, DNS, files).
#
# $1 - name of host to lookup
# $2 - variable to store result in, defaults to HOST_ADDR
#
#############################################################################
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 ${1} | read _addr _name _junk
	if [[ -n "$_addr" ]]
	then
		eval "${_var}=\"${_addr}\""
		return 0
	fi

	if [[ -f "${ETCHOSTSFILE6}" ]]; then
	while read _addr _name
	do
		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
	if [[ -f "${ETCHOSTSFILE}" ]]; then
	while read _addr _name
	do
		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
	if [[ -f "${MANCONFIGFILE}" ]]; then
		ilookup=`grep "$1" $MANCONFIGFILE `
		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
#
#
#############################################################################
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.
#
#############################################################################
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
			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 setting for the I1 MAN 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} "Hostname" "IP Address" " (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 setting for the I1 MAN 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} "Hostname" "IP Address" "(platform=$PLATFORM_NAME)"
	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.
#
#############################################################################
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 configurng SC0 or SC1
#
# Sets THIS_SC and OTHER_SC accordingly.
#
#############################################################################
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"
			fi
		fi
	done
}

#############################################################################
#
# get_sc_number
#
# Determine if we are configuring SC0 or SC1
#
# Sets THIS_SC and OTHER_SC accordingly.
#
#############################################################################
get_sc_number()
{
    typeset scnum
    typeset warnmsg="Warning: %s returned invalid SC number: %s\n"

    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 "$warnmsg")\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
#
#############################################################################
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.
	#
	echo "${_sc_hostname} $name" >> $PRIVATE_REMOTEHOST
	chmod 400 $PRIVATE_REMOTEHOST >/dev/null 2>&1
	chown root:sys $PRIVATE_REMOTEHOST >/dev/null 2>&1
}

#############################################################################
#
# auto_range_I2_settings - Display the list of setting for the I2 MAN 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 [[ $1 -eq 0 ]]; then
		print
		printf ${s_fmt} "Hostname" "IP Address" "(platform=$PLATFORM_NAME)"
	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 [[ $1 -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 [[ $1 -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 [[ $1 -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 SC to SC MAN network
#
#
#############################################################################
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 I1 MAN 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} "Hostname" "IP Address" " (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
}


#############################################################################
#
# get_avail_nics - get list of available nics
#
#
#############################################################################
get_avail_nics()
{
	# Should get this from ifconfig -a after plumbing all
	list="hme0 eri1 qfe0 qfe1 qfe2 qfe3"
	echo "$list"
}


############################################################################
#
# validate_nic - validate a nic using various ifconfig commands.
#
#
#############################################################################
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
}

#############################################################################
#
# validate_nics -  validate nics for one Community External Network.
#
# $1 - Community name
# $2 - 1st nic to validate
# $3 - 2nd nic to validate
#
# At least one nic has to be defined.
# Invalid nics are: eri0 eri2-19 hme1
#
#############################################################################
validate_nics()
{
	typeset commname=$1
	typeset nic1=$2
	typeset nic2=$3

	[[ -z "$1" && -z "$2" ]] && return 1
	for nic in $nic1 $nic2
	do
		case $nic in
		eri0|eri[2-9]|eri1[0-9]|hme1)
			printf "$(gettext "%s: Invalid NIC device for external network")\n" "$nic" >&2
			return 1 ;;
		"")	: ;;
		*) validate_nic $nic || [[ -n "$DEBUG" ]] || return 1
		esac
		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)
#
# Returns 0 (success) if user enters a valid IPv4/6 address, or nothing (just enter).
# Returns 1 (failure) if user enters EOF (like read)
#############################################################################
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 adddress required.")\n" 1>&2
		elif [[ -n "${ip}" && $requiredIPv = "6" && ${ip} != *:* ]]; then
			printf "$(gettext "IPv6 adddress 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
#
# $1 - Community Name
#
#############################################################################
setup_C_network()
{
	typeset -r COMNAME=$1
	typeset lmask="255.255.255.252"
	typeset L_NAME=$PLATFORM_NAME
	typeset fmt=$(gettext "\nDo you want to accept these network settings?")
	typeset DEFNIC1="hme0"
	typeset DEFNIC2="eri1"
	typeset DEFNICS=" [$DEFNIC1 $DEFNIC2]"
	typeset fmt_defcommunity=$(gettext "\nDo you want to define this Community?")
	typeset resp
	typeset requireIPv

	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=""

	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
		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

		DELNICS=
		# Put any nics that were assigned to this community that are no longer
		# in the list to have associated hostname.<nic> files deleted.
		for nic in $curnics; do
			echo $NIC1 $NIC2 | grep $nic > /dev/null || DELNICS="$DELNICS $nic"
		done

		FLOATER_IP=""
		FLOATER_HOSTNAME=$(awk '$2 == "SC-FLOATER-'$COMNAME'" {print $3}' $TMPMANCONFIGFILE)
		[[ -z "$FLOATER_HOSTNAME" ]] && FLOATER_HOSTNAME=$PLATFORM_NAME-sc-$COMNAME
		printf "\n$(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

		tmp_ipaddr=$(gethostip ${FLOATER_HOSTNAME} | awk '{print $1}')
		if [[ -z "$tmp_ipaddr" ]]
		then
			while [[ -z "$FLOATER_IP" ]] ; do
				printf "$(gettext "Enter IPMP IP address for %s: ")" \
					$FLOATER_HOSTNAME
				readip FLOATER_IP || continue 2
			done
		else
			printf "$(gettext "Enter IPMP 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
			NETMASK=""
			default_nmask=$(getent netmasks ${FLOATER_IP} | 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
		if [[ ${FLOATER_IP} = *:* ]]; then
			requireIPv="6"
		else
			requireIPv="4"
		fi

		#
		# If more than one NIC in pathgroup, need an IPMP failover address for
		# group as well.
		#
		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 IPMP hostname for community %s failover address [%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 IPMP IP address for %s: ")" \
						$COMM_FAILOVER_HOSTNAME
					readip COMM_FAILOVER_IP "" $requireIPv || continue 2
				else
					printf "$(gettext "Enter IPMP 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

		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 IPMP 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

			tmp_ipaddr=$(gethostip ${NIC1_HOSTNAME} | awk '{print $1}')
			while [[ -z "$NIC1_IP" ]] ; do
				if [[ -z "$tmp_ipaddr" ]]; then
					printf "$(gettext "Enter IPMP IP address for %s: ")" \
						$NIC1_HOSTNAME
					readip NIC1_IP "" $requireIPv || continue 2
				else
					printf "$(gettext "Enter IPMP 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

		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 IPMP 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

			tmp_ipaddr=$(gethostip ${NIC2_HOSTNAME} | awk '{print $1}')
			while [[ -z "$NIC2_IP" ]] ; do
				if [[ -z "$tmp_ipaddr" ]]; then
					printf "$(gettext "Enter IPMP IP address for %s: ")" \
						$NIC2_HOSTNAME
					readip NIC2_IP "" $requireIPv || continue 2
				else
					printf "$(gettext "Enter IPMP 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

		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"; 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
			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
#
#
#############################################################################
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 addresseses; these will be used to update the /etc/hosts file.
#
# $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
#
# $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)
# $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} "Hostname" "IP Address" "(platform=$PLATFORM_NAME)"
	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 dont 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} "Hostname" "IP Address" " (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()
{
	typeset -r hn=$1
	typeset ip

	if [[ "$hn" = NONE ]]; then
		echo NONE
		return 0
	fi
	if [[ -n "$DEBUG" ]]; then
		ip=$(awk '/[ 	]'$hn'[ 	]/ || /[ 	]'$hn'$/ { print $1 }' $ETCHOSTSFILE)
		if [[ -n "$ip" ]] ; then
			echo $ip
			return 0
		fi
	fi
	getent hosts $hn | awk '{print $1}'
}

#############################################################################
#
# parse_man_cf
#
# Reads an existing MAN.cf file and displays (optionally) output
# Creates temporary MAN.cf copy.
#
#############################################################################
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} "Hostname" "IP Address" " (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

		I1)
			case $_id in
				SC) lookupid="SC"
					write_new_ifconfig=1
					;;
				[A-R]) lookupid=D${_id}
					;;
				NETMASK) lookupid="NM"
					;;
				*)
					command="smsmanopt"
					exclusive_lock UNLOCK smsconfig
					usage
					exit 2
					;;
			esac
			;;
		I2)
			case $_id in
				SC0) lookupid="SC0"
					;;
				SC1) lookupid="SC1"
					;;
				NETMASK) lookupid="NM"
					;;
				*)
					command="smsmanopt"
					exclusive_lock UNLOCK smsconfig
					usage
					exit 2
					;;
			esac
			;;
		L)
			case $_id in
				SC) lookupid="SC"
					;;
				NETMASK) lookupid="NM"
					;;
				*)
					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 225
			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
	if [[ -z "$_ans" ]]; then
		_ans="$_default"
	fi
	validate_backup_args "$_ans"
}


#############################################################################
#
# validate_backup_args
#
# Validate that the argument to sms_backup is a valid directory
#
#############################################################################
validate_backup_args()
{
	typeset filename_cpio=sms_backup.${ACTIVE_SMS_VERSION}.cpio

	if [ -d $1 ]; then
            /usr/bin/df -F ufs $1 2>&1 | \
            /usr/bin/grep "mounted as a tmpfs file system" > /dev/null 2>&1
            if [ $? -eq 0 ]; then
		fatal "$(printf "$(gettext "%s: fails to backup to $1, a TMPFS files system.  Please specify a directory that is mounted on a UFS filesystem.")\n" $command)"
	fi
	# form backup filename: <specified directory>/sms_backup.cpio
		SMS_BACKUP=${1}/${filename_cpio}
		if [ -a ${SMS_BACKUP} ]; then
			rotate_file ${SMS_BACKUP} 6
		fi
	else
	# Not directory, check if tape
		mt -f $1 status > /dev/null 2>&1
		if [ $? -ne 0 ]; then
			printf "$(gettext "%s: Invalid backup target specified.\nBackup file will be: /var/tmp/%s.")\n"  $command $filename_cpio
			SMS_BACKUP=/var/tmp/${filename_cpio}
		else
			SMS_BACKUP=${1}
		fi
	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 "/"
        (umask 177; cd $ROOT/; find ${SMSOPT}/SMS ${SMSHOME}/.sms_env \
        ${SMSHOME}/.cshrc \
        ${SMSHOME}/.login \
        ${SMSETC}/.sms_groups \
        ${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]/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/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/.failover/fomd/fomd_usr_datasync.cf \
        -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

}


#############################################################################
#
# create_datasync_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_datasync_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 "/"
        (umask 177; cd $ROOT/; find ${SMSOPT}/SMS ${SMSHOME}/.sms_env \
        ${SMSHOME}/.cshrc \
        ${SMSHOME}/.login \
        ${SMSETC}/.sms_groups \
        ${SMSETC}/config/.postrc \
        ${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]/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.remote \
        ${SMSVAR}/adm/platform/messages.[0-9].remote \
        ${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/.failover/fomd/fomd_usr_datasync.cf \
        -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 setdatasync backup is called and a backup file 
#  compatable with the remote SC is needed
#  A cpio is created and dumped to a temporary directory
#  The the contents are modified 
#  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 DATASYNC is set then we know we need to create a backup file
   #  formated for the remote SC 
   if [[ ${DATASYNC} -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

      # Domain message logs are always identical between SCs.
      # To be compatable with setdatasync backup the messages logs need to
      #  be renamed to messages(.#).remote
      # perform the renames of the message files
      typeset COUNTER=0
      set -A message_files `find . -name messages* -depth 2>/dev/null | \
                            grep platform`
      while (( $COUNTER < ${#message_files[*]} )); do
         print ${message_files[$COUNTER]}
         /usr/bin/mv ${message_files[$COUNTER]} ${message_files[$COUNTER]}.remote
         let COUNTER=$COUNTER+1
      done

      # 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_datasync_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

gettext "Reinitializing all SMS users...\n"

# 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
   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'}'`
      # echo configuring ${people[$COUNTER]} " : " $individual " : "${job[$COUNTER]}

      # 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
      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'}'`
      # echo configuring $dmnstring " : " $individual " : " $dmnjob

      # 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

      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
gettext "All SMS users configured.\n"

# 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


}

#############################################################################
#
# copy_before_restore_one_point_two 
#
# Backup a list of files that need to be restored after SMS1.1 is restored
#  over SMS1.2 
#
# Parameters : the temporary restore directory
#
#############################################################################
copy_before_restore_one_point_two()
{
   typeset tmprestoredir=$1

   /bin/cp -p ${SMSETC}/config/esmd_tuning.txt \
      $tmprestoredir/esmd_tuning.txt
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p ${SMSETC}/config/dsmd_tuning.txt \
      $tmprestoredir/dsmd_tuning.txt
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p ${SMSETC}/config/fomd_sys_datasync.cf \
      $tmprestoredir/fomd_sys_datasync.cf
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p ${SMSETC}/config/fomd.cf \
      $tmprestoredir/fomd.cf
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p ${SMSETC}/startup/ssd_start \
      $tmprestoredir/ssd_start
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p ${SMSETC}/startup/sms_env.sh \
      $tmprestoredir/sms_env.sh
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi


}

#############################################################################
#
# copy_after_restore_one_point_two
#
# Copy the good SMS1.2 files over the restored (bad) SMS1.1 files 
#
# Parameters : the temporary restore directory
#
#############################################################################
copy_after_restore_one_point_two()
{
   typeset tmprestoredir=$1

   /bin/cp -p $tmprestoredir/esmd_tuning.txt \
      ${SMSETC}/config/esmd_tuning.txt 
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p $tmprestoredir/dsmd_tuning.txt \
      ${SMSETC}/config/dsmd_tuning.txt
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

  /bin/cp -p $tmprestoredir/fomd_sys_datasync.cf \
      ${SMSETC}/config/fomd_sys_datasync.cf
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p $tmprestoredir/fomd.cf \
      ${SMSETC}/config/fomd.cf 
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p $tmprestoredir/ssd_start \
      ${SMSETC}/startup/ssd_start 
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

   /bin/cp -p $tmprestoredir/sms_env.sh \
      ${SMSETC}/startup/sms_env.sh 
   if [[ $? -ne 0 ]]; then
      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
      print
   fi

}



#############################################################################
#
# perform_restore
#
# Restore a backup done using sms_backup.
#
#############################################################################
perform_restore()
{
        typeset back_major
        typeset back_minor
        typeset active_major
        typeset active_minor
        typeset highver=$ACTIVE_SMS_VERSION

        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


        # This is a temporary directory for staging some files
        SMSTMPRESTORE=$ROOT/tmp/SMSRESTORE.$$

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

        # If the 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
                 gettext "Warning: Attempt to move ${fomduid_temp} to ${fomduidfile} failed.\n"
                 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
                    gettext "Warning: Attempt to copy ${fomduid_temp} to ${fomduidfile} failed.\n"
                    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
                 gettext "Warning: Missing ${fomduidfile}.\n"
                 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

        if [[ $BACKUP_SMS_VERSION = $ACTIVE_SMS_VERSION ]]; then
                # Restore same version than was used to back up
                # v1.1 -> v1.2 is special case - no conversion needed
                ( 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)"
                        print
                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 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
                        highver=$BACKUP_SMS_VERSION
                elif [[ ${back_major} -lt ${active_major} ]]; then
                        highver=$ACTIVE_SMS_VERSION
                elif [[ ${back_minor} -gt ${active_minor} ]]; then
                        highver=$BACKUP_SMS_VERSION
                else
                        highver=$ACTIVE_SMS_VERSION
                fi

                # SMS1.1 to SMS1.2 is a special case.  If you are working on this code 
                #  become well informed about all issues before making changes  
                if [[ $BACKUP_SMS_VERSION = 1.1 && $ACTIVE_SMS_VERSION = 1.2 ]]; then
                   mkdir $SMSTMPRESTORE

                   # Back up some files we don't want wiped out by the restore
                   copy_before_restore_one_point_two $SMSTMPRESTORE

                   # Restore the backup file over the existing SMS1.2 installation
                   ( cd $ROOT/; cpio -Picvdum -I ${sms_restore_filename} -f ${SMSOPT#${ROOT}/}/SMS >> ${LOG_FILE} 2>&1 )
                   if [[ $? -ne 0 ]]; then
                      /bin/rm -rf $SMSTMPRESTORE
                      fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
                      print
                   fi
                   # Restore the files we previously protected
                   copy_after_restore_one_point_two $SMSTMPRESTORE

                  /bin/rm -rf $SMSTMPRESTORE
                else  
                   # If the version is not sms1.1 or sms1.2 then we are not equipped to
                   #  handle this situation
                   fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
                      print
                fi # SMS1.1->SMS1.2 special case

            
                # 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
}


old_perform_restore()
{
        typeset back_major
        typeset back_minor
        typeset active_major
        typeset active_minor
        typeset highver=$ACTIVE_SMS_VERSION

        SMSTMPRESTORE=$ROOT/tmp/SMSRESTORE.$$
        mkdir $SMSTMPRESTORE
        ( cd $SMSTMPRESTORE; cpio -icvdum -I ${sms_restore_filename} ${SMSOPT#${ROOT}/}/SMS > /dev/null 2>&1 )
        if [[ $? -ne 0 ]]; then
                /bin/rm -rf $SMSTMPRESTORE
                fatal "$(printf "$(gettext "%s: Unable to restore archive version identifier: %s.")\n" $command $sms_restore_filename)"
        fi
        if [[ -L $SMSTMPRESTORE${SMSOPT}/SMS ]]; then
                BACKUP_SMS_VERSION=`ls -l $SMSTMPRESTORE${SMSOPT}/SMS |cut -f2 -d'>'`
                BACKUP_SMS_VERSION=${BACKUP_SMS_VERSION##*/SMS}
        else
                BACKUP_SMS_VERSION=1.1
        fi
        /bin/rm -rf $SMSTMPRESTORE
        if [[ $BACKUP_SMS_VERSION = $ACTIVE_SMS_VERSION || \
              ( $BACKUP_SMS_VERSION = 1.1 && $ACTIVE_SMS_VERSION = 1.2 ) ]]; then
                # Restore same version than was used to back up
                # v1.1 -> v1.2 is special case - no conversion needed
                ( 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)"
                        print
                 fi
        else
                # Restore to different version than was used to back up. Call smsconvert.
                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
                        highver=$BACKUP_SMS_VERSION
                elif [[ ${back_major} -lt ${active_major} ]]; then
                        highver=$ACTIVE_SMS_VERSION
                elif [[ ${back_minor} -gt ${active_minor} ]]; then
                        highver=$BACKUP_SMS_VERSION
                else
                        highver=$ACTIVE_SMS_VERSION
                fi
                if [[ ! -x $SMSOPT/SMS$highver/lib/smsadmin/smsconvert ]]; then
                        fatal "$(printf "$(gettext "%s: Unable to process archive: %s.")\n" $command $sms_restore_filename)"
                fi
                mkdir $SMSTMPRESTORE
                ( cd $SMSTMPRESTORE; cpio -Picvdum -I ${sms_restore_filename} >>${LOG_FILE} 2>&1 )
                if [[ $? -ne 0 ]]; then
                        /bin/rm -rf $SMSTMPRESTORE
                        fatal "$(printf "$(gettext "%s: Unable to restore archive: %s.")\n" $command $sms_restore_filename)"
                        print
                fi
                $SMSOPT/SMS$highver/lib/smsadmin/smsconvert $SMSTMPRESTORE $BACKUP_SMS_VERSION | tee -a ${LOG_FILE}
                if [[ $? -ne 0 ]]; then
                        fatal "$(printf "$(gettext "%s: Unable to upgrade/downgrade from archive: %s.")\n" $command $sms_restore_filename)"
                        print
                 fi
                /bin/rm -rf $SMSTMPRESTORE
        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)"
	else
		active_version_directory=`basename $smsopt_version`
		ACTIVE_SMS_VERSION=${active_version_directory#SMS}
	fi
}

#############################################################################
#
# 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
}

#############################################################################
#
# 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
			validate_version_request "${1}"
			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 everything from 1.0 --> 3.9
	while (($tmajor <= 3)); do
		while (($tminor <= 9)); do
			if find_version "$tmajor.$tminor" ; then
				version_list=${version_list:+$version_list }"$tmajor.$tminor "
				installed_vers_cnt=$(($installed_vers_cnt+1))
			fi
			tminor=$(($tminor+1))
		done
		tminor=0
		tmajor=$(($tmajor+1))
	done
	fi
	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

	if find ${SMSOPT}/SMS$vers ${SMSVAR}/SMS$vers \
		${SMSETC}/SMS$vers -type d -prune >> ${LOG_FILE} 2>&1
	then
		printf "$(gettext "%s: SMS version %s installed")\n" $command $vers
		return 0
	else
		return 1
	fi
}

#############################################################################
#
# validate_version_request()
#
# Check to see thatthe user has entered a valid version number as a
#  target. A user may switch from 2.0 -> 2.1, but not from 2.0 -> 3.1
#
#############################################################################
validate_version_request()
{
	typeset req_major
	typeset req_minor
	typeset active_major
	typeset active_minor

	req_major=${1%.[0-9]}
	req_minor=${1#[0-9].}
	active_major=${ACTIVE_SMS_VERSION%.[0-9]}
	active_minor=${ACTIVE_SMS_VERSION#[0-9].}
	# 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
	if [[ ${1} == $ACTIVE_SMS_VERSION ]]; then
		fatal "$(printf "$(gettext "%s: SMS version <%s.%s> is already installed and active.")" $command $req_major $req_minor)"
	elif [[ ${req_major} -gt ${active_major} ]]; then
		printf "$(gettext "%s: Upgrading SMS from <%s.%s> to <%s.%s>.")\n" $command $active_major $active_minor $req_major $req_minor
		return 0
	elif [[ ${req_major} -lt ${active_major} ]]; then
		printf "$(gettext "%s: Downgrading SMS from <%s.%s> to <%s.%s>.")\n" $command $active_major $active_minor $req_major $req_minor
		return 0
	elif [[ $req_minor -eq $(($active_minor - 1)) ]]; then
		printf "$(gettext "%s: Downgrading SMS from <%s.%s> to <%s.%s>.")\n" $command $active_major $active_minor $req_major $req_minor
		return 0
	elif [[ $req_minor -eq $(($active_minor + 1)) ]]; then
		printf "$(gettext "%s: Upgrading SMS from <%s.%s> to <%s.%s>.")\n" $command $active_major $active_minor $req_major $req_minor
		return 0
	else
		fatal "$(printf "$(gettext "%s failed: Upgrade not permitted to a non-adjacent release.")" $command)"
	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)"
}

###############################################################
# update_hosts
#
# Update hosts file 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).
#
#  $1: MAN.cf file.
#
###############################################################
update_hosts()
{
	mancf="$1"
	TMP_HOSTEDCMDS=/tmp/smsconfig_host_ed_cmds$$
	TMP_HOSTEDCMDS6=/tmp/smsconfig_host_ed_cmds6$$
	TMP_HOSTEDINFO=/tmp/smsconfig_host_ed_info$$
	TMP_HOSTEDINFO6=/tmp/smsconfig_host_ed_info6$$
	TMP_EDERRS=/tmp/smsconfig_host_ed_errs$$
	TMP_EDERRS6=/tmp/smsconfig_host_ed_errs6$$
	ADD=$(gettext "ADD")

	[ -z "$mancf" ] && return 1
	[ -f "$mancf" -a -f "$ETCHOSTSFILE" ] || return 2
	(
	awk '
	/^[ 	]*#/ {next}
	$2 ~ /^NM-/ {next}
	$3 == "" {next}
	$4 == "" {next}
	{print $3, $4}' $mancf
	cat $TMPFOADDRS 2>/dev/null
	) | sort | \
	while read manhostname manhostip
	do
		[[ "$manhostname" = NONE ]] && continue
		if [[ ${manhostip} != *:* ]]; then
			# Handle IPv4
			hosthostip=$(awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" {print $1}' $ETCHOSTSFILE)
			hosthostip_aliases=$(awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" \
				{for(i=3; i<=NF; i++) print $i}' $ETCHOSTSFILE)
			hosthostip_loghost=
			if echo $hosthostip_aliases | grep -w loghost > /dev/null; then
				hosthostip_loghost=" loghost"
			fi

			hosthostname=$(awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" {print $2}' $ETCHOSTSFILE)
			hosthostname_aliases=$(awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" \
				{for(i=3; i<=NF; i++) print $i}' $ETCHOSTSFILE)
			hosthostname_loghost=
			if echo $hosthostname_aliases | grep -w loghost > /dev/null; then
				hosthostname_loghost=" 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
				addloghost="$hosthostip_loghost"
				[[ -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)
				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)
				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
			hosthostip=$(awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" {print $1}' $ETCHOSTSFILE6)
			hosthostip_aliases=$(awk '/^[ 	]*#/ {next} $2 == "'$manhostname'" \
				{for(i=3; i<=NF; i++) print $i}' $ETCHOSTS6FILE)
			hosthostip_loghost=
			if echo $hosthostip_aliases | grep -w loghost > /dev/null; then
				hosthostip_loghost=" loghost"
			fi

			hosthostname=$(awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" {print $2}' $ETCHOSTSFILE6)
			hosthostname_aliases=$(awk '/^[ 	]*#/ {next} $1 == "'$manhostip'" \
				{for(i=3; i<=NF; i++) print $i}' $ETCHOSTS6FILE)
			hosthostname_loghost=
			if echo $hosthostname_aliases | grep -w loghost > /dev/null; then
				hosthostname_loghost=" 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
				addloghost="$hosthostip_loghost"
				[[ -z "$addloghost" ]] && addloghost="$hosthostname_loghost"
			fi

			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" $ETCHOSTS6FILE)
				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" $ETCHOSTS6FILE)
				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

	if test -s $TMP_HOSTEDINFO; then
		printf "$(gettext "The following changes are about to be applied to the \"%s\" hosts file.")\n" $ETCHOSTSFILE
		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
			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
			else
				printf "$(gettext "Hosts file update edit failed.")\n"
				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
	if test -s $TMP_HOSTEDINFO6; then
		printf "$(gettext "The following changes are about to be applied to the \"%s\" hosts file.")\n" $ETCHOSTSFILE6
		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
			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
			else
				printf "$(gettext "Hosts file update edit failed.")\n"
				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
	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()
{
	ip=$1 # IP address
	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/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()
{
	ip="$1"
	nm="$2"
	EDCMDS="$3"
	CGINFO="$4"
	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/networks 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()
{
	mancf="$1"
	TMP_EDCMDS=/tmp/smsconfig_netmasks_ed_cmds$$
	TMP_CGINFO=/tmp/smsconfig_netmasks_cginfo$$
	TMP_EDERRS=/tmp/smsconfig_netmasks_ed_errs$$

	[[ -n "$mancf" ]] || return 1
	[[ -f "$mancf" ]] || return 2
	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
			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)
#
###########################################################################
sms_man_setup()
{
	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 ${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/hosts with host info in MAN.cf
	update_hosts $MANCONFIGFILE
	update_netmasks $MANCONFIGFILE
}

###############################################################
#
# sms_group_cleanup
#
# clean up before exiting from "smsconfig -group"
#
###############################################################
sms_group_cleanup()
{
	rm -f $TMPGROUPCONFIGFILE >/dev/null 2>&1
}

###############################################################
#
# group_exists
#
# Checks using getent(1M) for the existance 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 existance 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 adminstration 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
#
###############################################################
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()
{
	# make sure we clean up the temporary group config file
	trap sms_group_cleanup EXIT

	typeset _group
	typeset _current_cfg
	typeset _plat_admn="platadmn"
	typeset _plat_oper="platoper"
	typeset _plat_svc="platsvc"
	typeset _domain_admns="dmnaadmn dmnbadmn dmncadmn dmndadmn dmneadmn dmnfadmn dmngadmn dmnhadmn dmniadmn dmnjadmn dmnkadmn dmnladmn dmnmadmn dmnnadmn dmnoadmn dmnpadmn dmnqadmn dmnradmn"
	typeset _domain_rcfgs="dmnarcfg dmnbrcfg dmncrcfg dmndrcfg dmnercfg dmnfrcfg dmngrcfg dmnhrcfg dmnircfg dmnjrcfg dmnkrcfg dmnlrcfg dmnmrcfg dmnnrcfg dmnorcfg dmnprcfg dmnqrcfg dmnrrcfg"

	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 posses 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 posses domain control and status, and console access privileges (for the respective domain), but does not posses 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 posses 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_TMP_DIR - where we keep the temporary files
FACL_TMP_DIR="/tmp"

# FACL_LOCK_FILE - using lock file to prevent multiple sessions running
FACL_LOCK_FILE="$FACL_TMP_DIR/facl_lock"

# FACL_DIR_LIST - file containing the names of SMS directories for ACLs config
FACL_DIR_LIST="$FACL_TMP_DIR/facl_dir_list.txt"


# #########################################################################
# 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 ${FACL_TMP_DIR}/facl_* 2> /dev/null
  fi
  exclusive_lock UNLOCK smsconfig
  facl_display "Leaving facl_cleanup_and_exit()\n"

  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
  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
  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`
    if echo "$user_list" | grep $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`
  if [ $? -ne 0 ]; then
    fatal "$(gettext "group $smsGroup does not exist\n")"
  else
    /usr/bin/grep "^$smsGroup:" $ETCGROUPFILE > /dev/null
    if [ $? -ne 0 ]; then
      gettext "ERROR: the group \"$smsGroup\" cannot be found in $ETCGROUPFILE\n"
      gettext "The group database is probably maintained on a NIS server.\n"
      gettext "Please manually add user \"$FACL_USERNAME\" to the administrative\n"
      gettext "group \"$smsGroup\" then run $command again\n\n"
      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
		gettext "ERROR: /usr/bin/cp -f ${ETCGROUPFILE}_TXT $ETCGROUPFILE\n"
		gettext "Please manually restore the $ETCGROUPFILE from ${ETCGROUPFILE}_TXT\n"
		exclusive_lock UNLOCK smsconfig
		exit 2
	else
		/usr/bin/rm -f ${ETCGROUPFILE}_TXT > /dev/null
          gettext "$FACL_USERNAME has been added to the $smsGroup group.\n"
	fi
      else
        facl_display "group $smsGroup has member(s): $user_list"
        # non-empty user-list, eg "bin::2:root,bin,daemon"
        if ! echo "$user_list" | grep ${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
			gettext "ERROR: /usr/bin/cp -pf ${ETCGROUPFILE}_TXT $ETCGROUPFILE\n"
			gettext "Please manually restore $ETCGROUPFILE from ${ETCGROUPFILE}_TXT\n"
            facl_cleanup_and_exit 2
		else
			/usr/bin/rm -f ${ETCGROUPFILE}_TXT > /dev/null
			gettext "$FACL_USERNAME has been added to the $smsGroup group.\n"
		fi
        fi
      fi
    else
      fatal "$(gettext "user $FACL_USERNAME needs to be added to group $smsGroup\n")"
    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


  if [ -f $FACL_DIR_LIST ]; then
    modifyAclEntry="user:${FACL_USERNAME}:rwx"
    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
          gettext "$eachDir: failed to set acl entries\n"
        fi
      else
        gettext "ERROR: $eachDir does not exist\n"
      fi
    done
    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
      gettext "All privileges to domain $FACL_DOMAIN_ID have been applied.\n"
    else
      gettext "All privileges to the platform have been applied.\n"
    fi
  else
    gettext "ERROR: File $FACL_DIR_LIST not found\n"
    facl_cleanup_and_exit 2
  fi

  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`
    echo "$user_list" | grep $FACL_USERNAME > /dev/null
    rc=$?
    if [ $rc -eq 0 ]; then
      if echo "$user_list" | grep ",${FACL_USERNAME}" > /dev/null; then
	user_list=`echo $user_list | sed -e 's!,'$FACL_USERNAME'!!g'`
      elif echo "$user_list" | grep "${FACL_USERNAME}," > /dev/null; then
	user_list=`echo $user_list | sed -e 's!'$FACL_USERNAME',!!g'`
      elif [ "$user_list" =  "${FACL_USERNAME}" ]; then
	user_list=`echo $user_list | sed -e 's!'$FACL_USERNAME'!!g'`
      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
	gettext "ERROR: /usr/bin/cp -pf ${ETCGROUPFILE}_TXT $ETCGROUPFILE\n"
	gettext "Please manually restore $ETCGROUPFILE from ${ETCGROUPFILE}_TXT\n"
	exclusive_lock UNLOCK smsconfig
	exit 2
      else
	/usr/bin/rm -f ${ETCGROUPFILE}_TXT > /dev/null
        gettext "$FACL_USERNAME has been removed from the $smsGroup group.\n"
        userRemovedFromGroup=1
      fi
    elif [ $rc -ne 0 ]; then
      /usr/bin/groups $FACL_USERNAME > /dev/null
      rc=$?
      userRemovedFromGroup=1
      gettext "Please remember to manually remove user \"$FACL_USERNAME\" from the group $smsGroup\n"
    else
      gettext "$FACL_USERNAME is not a member of group $smsGroup\n"
    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
        gettext "$FACL_USERNAME belongs to the $tmpGroup group.\n"
        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
        gettext "$FACL_USERNAME belongs to the $tmpGroup group.\n"
        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
        gettext "$FACL_USERNAME belongs to the $tmpGroup group.\n"
        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
        gettext "$FACL_USERNAME belongs to the $tmpGroup group.\n"
        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
        gettext "$FACL_USERNAME belongs to the $tmpGroup group.\n"
        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
        gettext "Access to domain $FACL_DOMAIN_ID remains unchanged.\n"
      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

  if [[ "$ok_to_remove_acls" = "yes" && -f $FACL_DIR_LIST ]]; then
    deleteAclEntry="user:$FACL_USERNAME"
    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
          gettext "$eachDir: failed to unset acl entries\n"
        fi
      else
	gettext "ERROR: $eachDir does not exist\n"
      fi
    done
    if expr "$FACL_DOMAIN_ID" : '[A-R]' > /dev/null; then
      gettext "All privileges to domain $FACL_DOMAIN_ID are now denied.\n"
    else
      gettext "All privileges to the platform are now denied.\n"
    fi
  elif [ "$ok_to_remove_acls" = "yes" ]; then
    gettext "ERROR: File $FACL_DIR_LIST not found\n"
    facl_cleanup_and_exit 2
  fi

  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
    gettext "ERROR: File $facl_info not found\n"
    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 verifty 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\n")"
    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 "require both options -u, and -G\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 $FACL_SMS_GROUP cannot access the platform\n")"
    fi
    if [[ "$FACL_SMS_GROUP" = "oper" || "$FACL_SMS_GROUP" = "svc" ]]; then
      case "$FACL_DOMAIN_ID" in
      [a-rA-R])
        fatal "$(gettext "group $FACL_SMS_GROUP cannot access a domain\n")"
        ;;
      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

    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
}

#############################################################################
#
# 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

}



##
## MAIN CODE STARTS HERE
##
umask 033
# check for a help request
[[ $1 = "-h" ]] && usage && exit 4

# Check to see if we are running a backup for the
#  setdatasync backup command
if [[ "$command" = "smsbackup" ]]; then
   if [[ $1 = "-s" ]]; then
      shift
      DATASYNC=1
   fi
fi

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

#
# Check the command used
#
case "$command" in

smsbackup)
	require_root
	#require_sms_stopped
	select_log
	check_active_version
	validate_backup_args ${1:-/var/tmp}
	perform_backup
	gettext "SMS backup complete.\n"
	;;

smsrestore)
	require_args 1 $#
	require_root
	#require_sms_stopped
	select_log
	check_active_version
	validate_restore_args $1
	perform_restore
        gettext "SMS restore complete.\n"
	;;

smsversion)
	require_root
	select_log
	check_active_version
	if [[ $subcommand == "-t" ]]; then
		print_terse_version
		exclusive_lock UNLOCK smsconfig
		exit 0
	fi
	print_active_version
	check_and_choose_version $*
	if [[ $? -eq 0 ]]; then
           get_backup_destination
           perform_backup
           printf "$(gettext "%s: Switching to target version <%s>.")\n" \
              $command $subcommand
           version_cmp $subcommand $ACTIVE_SMS_VERSION
           v_result=$?

           # Switch upward
           if [[ "$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
                 fatal "$(printf "$(gettext "%s: updatesys command failed to update the system with %s, version switch failed.")" $command $update_result)" 
              fi

           # Switch to the same version or lower version
           else
              move_links $subcommand
           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_unknown=0
        while getopts hmgu:G:arl 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
             ;;
          h) opt_help=1 ;;
          *) opt_unknown=1 ;;
          esac
        done

        sum_opts=$(($opt_man +$opt_group +$opt_acl +$opt_help +$opt_unknown))
        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 `expr $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
		;;

	*)
		usage
		exclusive_lock UNLOCK smsconfig
		exit 2
		;;
	esac
	;;
*)
	usage
        exclusive_lock UNLOCK smsconfig
	exit 2
	;;
esac

exclusive_lock UNLOCK smsconfig
exit 0
