#! /bin/ksh
#
# ident "@(#)scinstall_upgrade.ksh 1.34     03/03/04 SMI"
#
# Copyright 1999-2003 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

#####################################################
#
# upgd_framework cdimagebasedir
#
#       cdimagebasedir          location of .cdtoc file
#
#       Upgrade the framework packages.
#
#       This function removes old framework packages and installs new ones
#       on the node from which it is called.
#
#	If the file /etc/cluster/pnmconfig exists, this function may modify
#       /etc/hostname.<if> files on the node from which it is called.
#	Those /etc/hostname.<if> files which already include ifconfig group
#	parameters are left unmodified.
#
#	This function creates and removes temporary files under /var/cluster.
#	It also	leaves behind a log file under /var/cluster/logs/install.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_framework()
{
	# check arg
        if [[ $# != 1 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_framework()')\n" ${PROG} >&2
                return 2
        fi

        typeset -r cdimagebasedir=$1
        typeset upgradeflag

	# Check that the node is currently not upgrading other Cluster software.
        upgradeflag=$(upgd_get_upgradeflag)
        if [[ $? -eq ${SC_TRUE} ]] &&
	   [[ "${upgradeflag}" != "framework" ]];then
                printf "\n\n%s:  $(gettext 'Cannot upgrade Cluster framework.')\n" ${PROG} | logerr
                printf "%s:  $(gettext 'A %s upgrade is still in progress.')\n" ${PROG} ${upgradeflag} | logerr
                return 1
	fi

	# Check that the node is currently not a cluster member
	is_cluster_member
        if [[ $? -eq ${SC_TRUE} ]] ;then
                printf "\n\n%s:  $(gettext 'Cannot upgrade an active cluster node.')\n" ${PROG} | logerr
		return 1
	fi

	# Validate hardware configuration for upgrade to current release.
	if [[ ${upgrade_skip_hw} -eq ${SC_TRUE} ]]; then
		upgd_validate || return 1
	fi

	printf "\n\n$(gettext 'Starting upgrade of Sun Cluster framework software')\n" | logmsg

	# Check that the given IPMP configurations and -S option is valid.
        upgd_nafo_to_ipmp  "check" || return 1

	# Save cluster configurations for idempotent.
        upgd_save_config ${cdimagebasedir} || return 1

	set_noclustermode ${SC_TRUE} || return 1

	# Convert NAFO adapter configurations to IPMP groups.
        upgd_nafo_to_ipmp  "convert" || return 1

	# Save /etc/cluster/ccr directory.
        upgd_save_ccr || return 1

	# Remove all the framework packages installed on the node.
	uninstallframework "" ${SC_UPGD_FMPKGS_FILE} all || return 1

	# Install the required framework packages on the node.
	installframework ${cdimagebasedir} || return 1

	# Install other/optional cluster packages on the node.
	installothers ${cdimagebasedir} "$(cat ${SC_UPGD_FMCLS_FILE})" || return 1

	# Invoke procedure to upgrade framework documentation.
	upgd_documentation ${cdimagebasedir} "framework"

	# Set eeprom
	printf "\n" | logmsg
	set_eeprom || return 1

	# Check and rename ntp.conf file
	upgd_ntp_config || return 1

	# Restore saved configurations
	upgd_restore_config || return 1

	# Unset no-clustermode to allow the node to boot into cluster.
	set_noclustermode ${SC_FALSE} || return 1

	printf "\n\n$(gettext 'Completed Sun Cluster framework upgrade')" | logmsg

	return 0

}

#####################################################
#
# upgd_dataservices cdimagebasedir "services"
#
#       cdimagebasedir          location of .cdtoc file
#       "services"              list of services
#
#       Upgrade the data services packages.
#	This function removes old data service packages and
#	installs new ones on the node from which it is called.
#
#	This function creates and removes temporary files under /var/cluster.
#	It also leaves behind a log file under /var/cluster/logs/install.
#
#	In the event that a data services upgrade is interrupted, this function
#	is designed to be capable of restarting the upgrade. As such, an upgrade
#	flag file is kept on disk to prevent other upgrade operations
#	(e.g., framework) from starting. For data services, this upgrade flag
#	file is called "upgrading_dataservices"; and, when an individual data
#	service is in the process of being upgraded, this file contains the
#	resource type name for that service.  Also, a list of software
#	packages discovered in the PKGLIST for resource type is saved to disk
#	until all the old packages are removed.  This enables a restart of the
#	dataservices upgrade process.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################

upgd_dataservices()
{
	# check arg
        if [[ $# != 2 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_dataservices()')\n" ${PROG} >&2
                return 2
        fi

        typeset -r cdimagebasedir=$1
        typeset -r services=$2

        typeset  service
        typeset  rtname
        typeset  upgradable_rtlist
        typeset  upgradable_rt
        typeset  upgrade_rtlist
        typeset  upgrade_rt
        typeset  uninstall_pkglist
        typeset  uninstall_pkg
        typeset  upgradeflag
        integer  badservices=0
        integer  found
	typeset  pkg

	# Check that the node is currently not a cluster member
	is_cluster_member
        if [[ $? -eq ${SC_TRUE} ]] ;then
		printf "\n\n%s:  $(gettext 'Cannot upgrade an active cluster node.')\n" ${PROG} | logerr
		return 1
	fi


	# Check that the node is currently not upgrading other Cluster software.
	upgradeflag=$(upgd_get_upgradeflag)
	if [[ $? -eq ${SC_TRUE} ]] &&
	   [[ $upgradeflag != "dataservices" ]];then
		printf "\n\n%s:  $(gettext 'Cannot upgrade Sun Cluster data services.')\n" ${PROG} | logmsg
		printf "%s:  $(gettext 'A Sun Cluster %s upgrade is still in progress.')\n" ${PROG} ${upgradeflag} | logmsg
		return 1
	fi

	# List of all installed and Upgradable services on the node.
	upgradable_rtlist=$(get_installed_services "${cdimagebasedir}") || return 1

	# Check if any services can be upgraded with the current CDROM
	if [[ -z ${upgradable_rtlist} ]];then
		printf "\n\n%s:  $(gettext 'No upgradable data services found.')\n" ${PROG} | logerr
		printf "%s:  $(gettext 'Please, load the correct data services CD.')\n" ${PROG} | logerr
		return 1
	fi

	# Assemble a list of services selected for the current upgrade.
	if [[ "${services}" == "all" ]];then
		upgrade_rtlist=${upgradable_rtlist}
	else
		upgrade_rtlist=
		for service in $(upgd_get_current_dataservice) ${services}
		do
			let found=0
			for upgradable_rt in ${upgradable_rtlist}
			do
				if [[ "${upgradable_rt}" == "${service}" ]];then
					let found=1
					break
				fi
			done
			if [[ ${found} -eq 0 ]];then
				printf "\n%s:  $(gettext 'Cannot Upgrade data service "%s" with current CDROM')\n" ${PROG} ${service} | logerr
				printf "%s:  $(gettext 'Service "%s" either not installed or not-upgradable')\n" ${PROG} ${service} | logerr
				(( badservices += 1 ))
			else
				let found=0
				for upgrade_rt in ${upgrade_rtlist}
				do
					if [[ "${upgrade_rt}" == "${service}" ]];then
						let found=1
						break
					fi
				done
				if [[ ${found} -eq 0 ]];then
					upgrade_rtlist="${upgrade_rtlist} ${service}"
				fi
		  	fi
		done
		if [[ ${badservices} -gt 0 ]];then
			printf "\n\n%s:  $(gettext 'One or more dataservices specified are invalid.')\n" ${PROG} | logerr
			return 1
		fi
	fi

	printf "\n\n$(gettext 'Starting upgrade of Sun Cluster data services agents')\n" | logmsg
		
	# Output list of services and those selected for upgrade.
	printf "\n\n$(gettext 'List of upgradable data services agents:')\n" | logmsg
	printf "  $(gettext '(*) indicates selected for upgrade.')\n\n" | logmsg
	for upgradable_rt in ${upgradable_rtlist}
	do
		let found=0
		for upgrade_rt in ${upgrade_rtlist}
		do
			if [[ "${upgradable_rt}" == "${upgrade_rt}" ]];then
				let found=1
				break
			fi
		done
		if [[ $found -eq 0 ]];then
			printf "	  $(gettext '%s')\n" "${upgradable_rt}"| logmsg
		else
			printf "	$(gettext '* %s')\n" "${upgradable_rt}"| logmsg
		fi
	done
			
	# Assemble a array of localization packages installed on the node
	# Packagename V/s SUNW_PKGLIST  for the specific L10n package.
	set -A SC_L10N_PKG_MAP
	i=0
	for pkg in $(pkginfo | awk '{print $2}')
	do
		pkglist="$(pkgparam ${pkg} SUNW_PKGLIST)"
		if [[ -n "${pkglist}" ]];then
			SC_L10N_PKG_MAP[i]=${pkg}
			SC_L10N_PKG_MAP[i+1]="${pkglist}"
			(( i += 2 ))
		fi
	done

	printf "\n\n$(gettext 'Upgrading Sun Cluster data services agents software')\n" | logmsg

	# Node must not boot into clustermode until this completes.
	set_noclustermode ${SC_TRUE} || return 1

	# Set the type of upgrade.
	upgd_set_upgradeflag ${SC_TRUE} dataservices || return 1

	for rtname in ${upgrade_rtlist}
	do
		# Sets the service being upgraded.
		upgd_set_current_dataservice ${rtname}  || return 1

		# Create or get the list of packages for the service.
		if [[ ! -f ${SC_UPGD_DSPKGS_FILE} ]];then
			uninstall_pkglist=$(get_installed_service_packages ${rtname}) || return 1
			cp /dev/null ${SC_UPGD_DSPKGS_FILE} || return 1
			for uninstall_pkg in ${uninstall_pkglist}
			do
				echo ${uninstall_pkg} >> ${SC_UPGD_DSPKGS_FILE}
			done
		else
			uninstall_pkglist=$(cat ${SC_UPGD_DSPKGS_FILE})
		fi

		# Remove the service and the packages listed for the service.
		if [[ -n "${uninstall_pkglist}" ]];then
	 		uninstallservice ${rtname} "${uninstall_pkglist}" || return 1
		fi

		# Remove the list of packages for the service.
                rm -f ${SC_UPGD_DSPKGS_FILE}

		# Install the service from the CDROM
		installservices ${cdimagebasedir} ${rtname} || return 1

		# Clear the current service name.
		upgd_set_current_dataservice || return 1

	done

	if [[ "${services}" == "all" ]];then
		# Invoke procedure to upgrade data services documentation.
		upgd_documentation ${cdimagebasedir} "dataservices"
	fi

	# Unset the type of upgrade.
	upgd_set_upgradeflag ${SC_FALSE} dataservices || return 1

	# Node may boot into clustermode
	set_noclustermode ${SC_FALSE} || return 1

	printf "\n\n$(gettext 'Completed upgrade of Sun Cluster data services agents')\n" | logmsg

	return 0

}

#####################################################
#
# upgd_get_upgradeflag
#
#	This function determines whether or not either a "framework" or
#	"dataservices" upgrade is or was in progress.  In the event that an
#	upgrade is interrupted,	this file helps to provide status to scinstall
#	when it is re-started by the user.
#
#	This function checks for the presence of either ${SC_UPGD_UPFM_FILE}
#	or ${SC_UPGD_UPDS_FILE}.  If either of these two files exist, this
#	function returns ${SC_TRUE} and prints either "framework" or
#	"dataservices".  If neither of the two files exist, ${SC_FALSE} is
#	returned.
#
#       Return:
#               ${SC_TRUE}      Upgrade flag file exists
#               ${SC_FALSE}     Upgrade flag file is missing
#
#####################################################
upgd_get_upgradeflag()
{
	if [[ -f ${SC_UPGD_UPFM_FILE} ]] ; then
		echo "framework"
		return ${SC_TRUE}
	else
		if [[ -f ${SC_UPGD_UPDS_FILE} ]]; then
			echo "dataservices"
			return ${SC_TRUE}
		else
			return ${SC_FALSE}
		fi
	fi
}


#####################################################
#
# upgd_set_upgradeflag createflag type
#
#       createflag      ${SC_TRUE}  	Creates the flagfile
#                       ${SC_FALSE} 	Removes the flagfile
#
#       type            Type of flagfile to create "framework" or "dataservices"
#
#	This function creates or removes an upgrade flag file. This file is used
#	by upgd_get_upgradeflag() to determine whether or not either a
#	"framework" or "dataservices" upgrade is or was in progress.  In the
#	event that an upgrade is interrupted, this file helps to provide status
#	to scinstall when it is re-started by the user.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_set_upgradeflag()
{
	# check arg
        if [[ $# != 2 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_set_upgradeflag()')\n" ${PROG} >&2
                return 2
        fi
        integer -r createflag=$1
        typeset -r type=$2

        typeset gottype
	

	case "${createflag}" in

	${SC_TRUE})
		gottype=$(upgd_get_upgradeflag)
		if [[ $? -eq ${SC_TRUE} ]] &&
	   	   [[ "${type}" != "${gottype}" ]]; then
               		printf "\n%s:  $(gettext 'Cannot upgrade %s.')\n" ${PROG} ${type} | logerr
			printf "%s:  $(gettext 'A %s upgrade is still in progress.')\n" ${PROG} ${gottype} | logerr
			return 2
		fi
		case "${type}" in

		framework)
			touch ${SC_UPGD_UPFM_FILE} || return 1
			;;
		dataservices)
			touch ${SC_UPGD_UPDS_FILE} || return 1
			;;
		*)
			printf "%s:  $(gettext 'Internal error - Bad call to upgd_set_upgradeflag():type %s')\n" ${PROG} ${type} >&2
			return 1
			;;
		esac	
		;;

	${SC_FALSE})
		case "${type}" in
		framework)
			rm -f ${SC_UPGD_UPFM_FILE}
			;;
		dataservices)
			rm -f ${SC_UPGD_UPDS_FILE}
			;;
		*)
			printf "%s:  $(gettext 'Internal error - Bad call to upgd_set_upgradeflag():type %s')\n" ${PROG} ${type} >&2
			return 1
			;;
		esac	
		;;

	*)
		printf "%s:  $(gettext 'Internal error - Bad call to upgd_set_upgradeflag()')\n" ${PROG} >&2
		return 1
		;;

	esac	
	return 0
}


#####################################################
#
# upgd_get_current_dataservice
#
#	This function prints the name of the resource type, or data service,
#	currently being upgraded.  For data service upgrades, the name of the
#	resource type being upgraded is stored in the data services upgrade flag
#	file, ${SC_UPGD_UPDS_FILE}. In the event that an upgrade is interrupted,
#	this information helps to provide status to scinstall when it is
#	re-started by the user.
#
#       Return:
#               zero            Always
#
#####################################################
upgd_get_current_dataservice()
{
	if [[ -f ${SC_UPGD_UPDS_FILE} ]];then
		(cat ${SC_UPGD_UPDS_FILE})
	fi
	return 0
}

#####################################################
#
# upgd_set_current_dataservice [service]
#
#       [service]              Service name to set ( Optional )
#
#	This function sets the name of the resource type, or data service,
#	currently being upgraded to the given data service name.  For data
#	service upgrades, the name of the resource type being upgraded is
#	stored in the data services upgrade flag file, ${SC_UPGD_UPDS_FILE}.
#	In the event that an upgrade is interrupted, this information helps to
#	provide status to scinstall when it is re-started by the user.
#
#	Whenever the current data service name is either cleared or set to a
#	new service name, the ${SC_UPGD_DSPKGS_FILE} is first also removed,
#	if it exists.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_set_current_dataservice()
{
        typeset -r service=$1

	typeset gotservice

	if [[ ! -f ${SC_UPGD_UPDS_FILE} ]];then
               	printf "\n%s:  $(gettext 'Cannot locate file %s')\n" ${PROG} ${SC_UPGD_UPDS_FILE} | logerr
		return 1
	fi

	if [[ -n ${service} ]];then
		gotservice=$(cat ${SC_UPGD_UPDS_FILE})
		if [[ -n ${gotservice} ]] &&
		   [[ "${gotservice}" != "${service}" ]];then
               		printf "\n%s:  $(gettext 'Cannot upgrade data service "%s"')\n" ${PROG} ${service} | logerr
               		printf "%s:  $(gettext 'Upgrade of dataservice "%s" is in progress')\n" ${PROG} ${gotservice} | logerr
			return 1
		fi
		echo ${service} > ${SC_UPGD_UPDS_FILE} || return 1
	else
		cat /dev/null > ${SC_UPGD_UPDS_FILE} || return 1
	fi

	return 0
}

#####################################################
#
# upgd_validate cdimagebasedir
#
#       cdimagebasedir          location of .cdtoc file
#
#	This function verify that the existing cluster may be legally upgraded
#	to the version of Sun Cluster on the CD.
#
#	Validate hardware support for the upgrade.
#
#	This function currently does nothing as there are no Hardware
#	restrictions for the upgrade to take place.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_validate()
{
        typeset -r cdimagebasedir=$1

	return 0
}


#####################################################
#
# upgd_save_config
#
#       cdimagebasedir          location of .cdtoc file
#
#	This function creates several files under the Upgrade directory 
#	${SC_UPGD_DIR}(/var/cluster/upgrade). Finally, it calls 
#	upgd_set_upgradeflag() to set the "framework" upgrade flag file.
#
#	The purpose of this function is to preserve important framework
#	configuration data throughout the course of a framework upgrade.
#	It also saves copies of the dot.cdtoc, dot.order, and dot.clustertoc
#	files from the installed cluster.
#	
#	And, it creates the ${SC_UPGD_FMPKGS_FILE} and ${SC_UPGD_FMCLS_FILE}
#	files. These two files list framework packages and software clusters,
#	respectively, installed on the node at the time that a framework upgrade
#	is first begun. In the event that an upgrade is interrupted and must be
#	restarted, these two files preserve the original list of framework
#	packages and software clusters to upgrade.
#
#	Lastly upgd_set_upgradeflag() is called to create the "framework"
#	upgrade flag file.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_save_config()
{
	# check arg
        if [[ $# != 1 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_save_config()')\n" ${PROG} >&2
                return 2
        fi

        typeset -r cdimagebasedir=$1

        typeset realcdimage
        typeset productdir
        typeset pkglist

	typeset	gottype
	typeset	clstr
	typeset pkg
	typeset docpkg
	integer i
	integer j
	integer k
	integer found
	integer usebuiltin=1
        typeset dot_order		# Array of Packages in the dot.order file
	typeset dot_cltoc		# Array of Clusters in the dot.clustertoc
	typeset dot_cltoc_pkgs		# Array of Packages for each dot_cltoc
	typeset installed_package	# Array of installed packages
	typeset installed_cluster	# Array of installed clusters
	typeset pkg_in_cluster		# Array of Cluster for installed_package
	typeset embedded_clusters	# List of Clusters embedded in others
	typeset sc_doc_pkgs

	# locate directory containing the product directory
	realcdimage=$(find_cdimagebasedir "${cdimagebasedir}" "${SC_PRODUCT}" "${SC_CLUSTER}") || return 1

	# get the name of the product directory
	productdir=$(getproduct ${realcdimage}/${SC_CDTOC} "${SC_PRODUCT}" ${SC_CLUSTER} "dir") || return 1

	gottype=$(upgd_get_upgradeflag)
	if [[ $? -eq ${SC_TRUE} ]];then
		if [[ "${gottype}" == "framework" ]];then
			printf "\n\n$(gettext 'Resuming the upgrade using saved configurations')\n" | logmsg
			return 0
		else
			return 1
		fi
	fi

	printf "\n\n$(gettext 'Saving current Sun Cluster configuration')\n" | logmsg

	rm -f ${SC_UPGD_DIR}/dot.cdtoc
	rm -f ${SC_UPGD_DIR}/dot.order
	rm -f ${SC_UPGD_DIR}/dot.clustertoc
	rm -f ${SC_UPGD_FMPKGS_FILE}
	rm -f ${SC_UPGD_FMCLS_FILE}

	cp ${SC_BASEDIR}/usr/cluster/lib/scadmin/dot.cdtoc ${SC_UPGD_DIR} || return 1
	cp ${SC_BASEDIR}/usr/cluster/lib/scadmin/dot.order ${SC_UPGD_DIR} || return 1
	cp ${SC_BASEDIR}/usr/cluster/lib/scadmin/dot.clustertoc ${SC_UPGD_DIR} || return 1

	#
	# The procedure below creates these two files
	#
        # SC_UPGD_FMPKGS_FILE : List of installed packages in correct order.
	# SC_UPGD_FMCLS_FILE  : List of Software-Clusters to install for
	#			Upgrade
	#
	# using the information in files  /usr/cluster/lib/scadmin/dot.order
	# and /usr/cluster/lib/scadmin/dot.clustertoc augmented using a
	# builtin listing of packages.
	#
	#

	touch ${SC_UPGD_FMPKGS_FILE} || return 1
	touch ${SC_UPGD_FMCLS_FILE} || return 1

        set -A dot_order $(cat ${SC_UPGD_DIR}/dot.order)

	# Compiling List of CLUSTERs from  dot.clustertoc file
	# METACLUSTERs are not being included in this array.

	set -A dot_cltoc $(nawk -F= '/^CLUSTER=/{print $2}' ${SC_UPGD_DIR}/dot.clustertoc)
	set -A dot_cltoc_pkgs
	set -A installed_package
	set -A installed_cluster
	set -A pkg_in_cluster

	let i=0
	while [[ ${i} -lt ${#dot_cltoc[*]} ]]
	do
		dot_cltoc_pkgs[i]=$(print_clustertoc ${SC_UPGD_DIR}/dot.clustertoc ${dot_cltoc[i]} "packages" )
		embedded_clusters="${embedded_clusters} $(print_clustertoc ${SC_UPGD_DIR}/dot.clustertoc ${dot_cltoc[i]} "clusters")"
        	(( i += 1 ))
	done

	let i=0
        while [[ ${i} -lt ${#dot_cltoc[*]} ]]
        do
		for clstr in ${embedded_clusters}
		do
			if [[ "${dot_cltoc[i]}" == "${clstr}" ]];then
				dot_cltoc[i]=
				dot_cltoc_pkgs[i]=
				break
			fi
		done
        (( i += 1 ))
	done

        #
        #Check if all Packages in the Dot Order file are present
        #in the builtin order list. If any package is newer we
        #use the order specified in dot_order instead of builtin
        #
        for pkg in ${dot_order[*]}
        do
		let found=0
		let i=0
		while [[ $i -lt ${#SC_UPGD_PKG_MAP[*]} ]]
		do
			if [[ "${pkg}" == "${SC_UPGD_PKG_MAP[i]}" ]];then
				let found=1
				break
			fi
			(( i += 2 ))
		done
                if [ $found -eq 0 ];then
                        let usebuiltin=0
                fi
        done

        #
        #If the Dot Order list is greater or equivalent to
        #the builtin order list. we use the order specified in
        #dot_order instead of builtin
        #
        if [[ ${usebuiltin} -eq 1 ]] &&
           [[ $(expr ${#SC_UPGD_PKG_MAP[*]} / 2) -le ${#dot_order[*]} ]];then
                let usebuiltin=0
        fi
        if [[ ${usebuiltin} -eq 0 ]];then
		pkglist=${dot_order[*]}
	else
		pkglist=
		let i=0
		while [[ $i -lt ${#SC_UPGD_PKG_MAP[*]} ]]
		do
			pkglist="${pkglist} ${SC_UPGD_PKG_MAP[i]}"
                	(( i += 2 ))
		done
	fi

	sc_doc_pkgs=$(print_clustertoc ${SC_UPGD_DIR}/dot.clustertoc "SUNWCscfab" "packages")

	let j=0
	for pkg in ${pkglist}
	do
        	pkginfo -q ${pkg}
        	if [[ $? -eq 0 ]]; then
			let found=0
			for docpkg in ${sc_doc_pkgs}
			do
				if [[ "${pkg}" == "${docpkg}" ]];then
					let found=1
					break
				fi
			done
			if [[ ${found} -eq 0 ]];then
                		installed_package[j]=${pkg};
                		(( j += 1 ))
			fi
        	fi
	done
	
	let i=0
	while [[ $i -lt ${#installed_package[*]} ]]
	do
        	let j=0
        	let found=0
        	while [[ $j -lt ${#dot_cltoc[*]} ]]
                do
			for pkg in ${dot_cltoc_pkgs[j]}
			do
                       		if [[ "${pkg}" == "${installed_package[i]}" ]];then
                               		pkg_in_cluster[i]=${dot_cltoc[j]};
					let found=1
                               		break 2
                        	fi
			done
                        (( j += 1 ))
                done
        	if [[ $found -eq 0 ]];then
                	let j=0
                	while [[ $j -lt ${#SC_UPGD_PKG_MAP[*]} ]]
                	do
                        	if [[ "${SC_UPGD_PKG_MAP[j]}" == "${installed_package[i]}" ]];then
                                	let found=1
                                	pkg_in_cluster[i]=${SC_UPGD_PKG_MAP[j+1]};
                                	break
                        	fi
                        	(( j += 2 ))
                	done
        	fi
        	if [[ $found -eq 0 ]];then
                	printf "%s:  $(gettext 'Unidentified package %s')\n" ${PROG} ${installed_package[i]} | logerr
                	return 1
        	fi
        	(( i += 1 ))
	done

	let j=0
	installed_cluster[j]="SUNWCsc"
	let i=0
	while [[ ${i} -lt  ${#pkg_in_cluster[*]} ]]
	do
		let found=0
		for clstr in ${installed_cluster[*]}
		do
        		if [[  "${clstr}" == "${pkg_in_cluster[i]}" ]];then
				let found=1
				break
			fi
		done
        	if [[ ${found} -eq 0 ]];then
			(( j += 1 ))
                	installed_cluster[j]=${pkg_in_cluster[i]}
        	fi
        	(( i += 1 ))
	done

	let k=0
	while [[ $k -lt ${#SC_RETIRED_PKG_MAP[*]} ]]
	do
        	pkginfo -q ${SC_RETIRED_PKG_MAP[k]}
        	if [[ $? -eq 0 ]]; then
			let found=0
			for pkg in ${installed_package[*]}
			do
        			if [[  "${pkg}" == "${SC_RETIRED_PKG_MAP[k]}" ]];then
					let found=1
					break
				fi
			done
        		if [[ ${found} -eq 0 ]];then
				installed_package[i]=${SC_RETIRED_PKG_MAP[k]}
        			(( i += 1 ))
        		fi

			let found=0
			for clstr in ${installed_cluster[*]}
			do
        			if [[  "${clstr}" == "${SC_RETIRED_PKG_MAP[k+1]}" ]];then
					let found=1
					break
				fi
			done
        		if [[ ${found} -eq 0 ]];then
				(( j += 1 ))
                		installed_cluster[j]=${SC_RETIRED_PKG_MAP[k+1]}
        		fi
        	fi
        	(( k += 2 ))
	done

	let i=0
	while [[ ${i} -lt ${#installed_cluster[*]} ]]
	do
		# get the list of packages
		print_clustertoc ${productdir}/${SC_CLUSTERTOC} ${installed_cluster[i]} "description" > /dev/null
		if [[ $? -eq 0 ]];then
			echo ${installed_cluster[i]} >> ${SC_UPGD_FMCLS_FILE}
		else
			missing_clusters="${missing_clusters} ${installed_cluster[i]}"
		fi
		(( i += 1 ))
	done


	let i=0
	while [[ ${i} -lt ${#installed_package[*]} ]]
	do
		let found=0
		for clstr in ${missing_clusters}
		do
			if [[ "${pkg_in_cluster[i]}" == "${clstr}" ]];then
				let found=1
				break
			fi
		done
		if [[ ${found} -eq 0 ]];then
			echo ${installed_package[i]} >> ${SC_UPGD_FMPKGS_FILE}
		else
        		printf "\n%s:  $(gettext 'Cannot upgrade package "%s" using current CDROM.')\n" ${PROG} ${installed_package[i]} | logerr
		fi
		(( i += 1 ))
	done

        upgd_set_upgradeflag ${SC_TRUE} "framework"

	return $?
}

#####################################################
#
# upgd_save_ccr
#
#	This function saves the cluster ccr by renaming :
#	/etc/cluster/ccr to etc/cluster/ccr.upgrade
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_save_ccr()
{
	if [[ ! -d "${SC_BASEDIR}/etc/cluster/ccr.upgrade" ]];then
		if [[ -d "${SC_BASEDIR}/etc/cluster/ccr" ]];then
			mv ${SC_BASEDIR}/etc/cluster/ccr ${SC_BASEDIR}/etc/cluster/ccr.upgrade || return 1
			printf "\n$(gettext 'Renamed "%s" to "%s".')\n" "${SC_BASEDIR}/etc/cluster/ccr" "${SC_BASEDIR}/etc/cluster/ccr.upgrade" | logmsg
		else
			printf "\n%s:  $(gettext 'Missing Cluster Configuration : "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/cluster/ccr" | logerr
			return 1
		fi
	fi

	return 0
}

#####################################################
#
# upgd_restore_config
#
#	This function restores the cluster ccr by renaming :
#	/etc/cluster/ccr.upgrade to etc/cluster/ccr
#
#	And, it calls upgd_set_upgradeflag() to clear the "framework" upgrade
#	flag file.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_restore_config()
{
	# check arg
        if [[ $# != 0 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_restore_config()')\n" ${PROG} >&2
                return 2
        fi

	if [[ -d "${SC_BASEDIR}/etc/cluster/ccr.upgrade" ]];then
		if [[ -d "${SC_BASEDIR}/etc/cluster/ccr" ]];then
			rm -fr ${SC_BASEDIR}/etc/cluster/ccr
		fi
			mv ${SC_BASEDIR}/etc/cluster/ccr.upgrade ${SC_BASEDIR}/etc/cluster/ccr || return 1
			printf "\n$(gettext 'Restored  %s to %s')\n" "${SC_BASEDIR}/etc/cluster/ccr.upgrade" "${SC_BASEDIR}/etc/cluster/ccr" | logmsg
	else
		printf "\n%s:  $(gettext 'Error - cannot restore "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/cluster/ccr" | logerr
		return 1
	fi

        upgd_set_upgradeflag ${SC_FALSE} "framework"

	return $?
}

#####################################################
#
# upgd_nafo_to_ipmp
#
#	The purpose of this function is to use the NAFO data found in the
#	/etc/cluster/pnmconfig file to create new IPMP groups.  The new IPMP
#	group names will be the same as the old NAFO group names.  Since each
#	adapter in an IPMP group requires one test address, users must supply
#	test addresses for each of the adapters in each of the new IPMP groups.
#	Users specify the addresses with "-S testaddr" command line options or
#	interactively by using "-S interact".
#
#	This function may modify one or more /etc/hostname.<if> files.  It will
#	also rename :-
#
#	/etc/cluster/pnmconfig to /etc/cluster/pnmconfig.obsolete.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_nafo_to_ipmp()
{
	# check arg
        if [[ $# != 1 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_nafo_to_ipmp()')\n" ${PROG} >&2
                return 2
        fi
        typeset -r runtype=$1
	
	if [[ ! -f ${SC_BASEDIR}/etc/cluster/pnmconfig ]]; then
		if [[ ${SC_UPGD_TST_ASKME} -eq ${SC_TRUE} ]] ||
		   [[ -n ${SC_UPGD_TST_IF} ]];then
			if [[ "${runtype}" == "check" ]];then
				printf "$(gettext '"%s" file does not exist ...')" "${SC_BASEDIR}/etc/cluster/pnmconfig" | logmsg
				printf "$(gettext '...option -S ignored')\n" ${PROG} | logmsg
			fi
		fi
		return 0
	fi
	typeset ip_script=${SC_SCLIBDIR}/${SC_IP_PERL}
	typeset nafo			# Array of NAFO GROUPS in pnmconfig
	typeset nafoip			# Array of IPs for each Nafo group
	typeset nafonetmask		# Array of netmasks for nafo group
	typeset adapter			# Adapters in pnmconfig
	typeset ipmpgroup		# Array of IPMP group for Adapter
	typeset pnmgroup		# Array of NAFO/PNM group for Adapter
	typeset adapter_config 		# Array of adapter_config for Adapter
	typeset testaddr 		# Array of Test-address for Adapter
	typeset address 		# Array of Base-IP-Address for Adapter
	set -A pnmgroup
	set -A nafo
	set -A nafoip
	set -A nafonetmask
	set -A ipmpgroup
	set -A adapter
	set -A adapter_config
	set -A testaddr
	set -A address
	integer i
	integer j
	integer k
	integer found
	typeset entry
	typeset entry_1
	typeset entry_2
	typeset	read_flag
	typeset	okay
	typeset	-l lnetmask
	integer	testaddr_flag
	integer	deprecated_flag
	integer	count_testaddr
	integer	wordcount
	integer	read_addr
	integer	incomplete
	integer	config_errors
	typeset sctxt_p1="$(gettext '
		The upgrade of Sun Cluster software on this node
		requires conversion of NAFO adapter groups to IP Network
		Multipathing (IPMP) groups. IPMP uses test addresses to detect
		network adapter failures. As part of this process, you will
		be asked to provide a test address for each adapter which does
		not already have a test address assigned. The test address that
		you assign to an adapter must be a unique unused IP address in
		the same subnet as the group that adapter belongs to.
	')"


	if [[ "${runtype}" == "check" ]];then
		printf "\n\n$(gettext 'Checking IP Multipathing configuration in "%s" files')\n" "${SC_BASEDIR}/etc/hostname.<adapter>" | logmsg
	fi

	let j=0
	let i=0
	while read nafo[j] adapter_list
	do
		for entry in $adapter_list
		do
			adapter[i]=${entry}
			adapter_j[i]=${j}
			pnmgroup[i]=${nafo[j]}
			nafoip[j]=${nafoip[j]:-$(${ip_script} get_adapter_ip ${adapter[i]})}
			nafonetmask[j]=${nafonetmask[j]:-$(${ip_script} get_adapter_netmask ${adapter[i]})}
			(( i += 1 ))
		done
		(( j += 1 ))
	done < ${SC_BASEDIR}/etc/cluster/pnmconfig

	# Parse /etc/hostname.<adapter> files
	let i=0
	while [[ ${i} -lt ${#adapter[*]} ]]
	do
		let testaddr_flag=0
		let deprecated_flag=0
		let count_testaddr=0
		let wordcount=0
		read_flag="addr"
		let read_addr=0
		adapterconfig=$(nawk -F# '{print $1}' ${SC_BASEDIR}/etc/hostname.${adapter[i]} 2> /dev/null)
		for word in ${adapterconfig}
		do
			(( wordcount += 1 ))
			case ${word} in
			group)
				read_flag="group"
				;;
			addif)
                		if [[ $testaddr_flag -eq 1 ]] ;then
                               		((count_testaddr += 1))
                       			if [[ $deprecated_flag -eq 1 ]] ; then
                               			testaddr[i]=${address[i]}
                               			testaddr_ip[i]=$(${ip_script} get_ip_in_hosts ${testaddr[i]})
                       			else
                               			adapter_config[i]="wrong"
                               			printf "\n%s:  $(gettext 'Configuration error in "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
                               			printf "%s:  $(gettext 'test address (-failover) must be deprecated.')\n" ${PROG} | logerr
                       			fi
                		fi
				let testaddr_flag=0
				let deprecated_flag=0
				read_flag="addr"
				;;
			-failover)
				let testaddr_flag=1
				;;
			deprecated)
				let deprecated_flag=1
				;;
			netmask|broadcast|destination|index|metric|mtu)
				read_flag="skip"
				;;
			\\|-*|up|down)
				;;
			*)
				case ${read_flag} in
				group)
					ipmpgroup[i]=${word}
					read_flag=
					;;
				addr)
					address[i]=${word}
					address_ip=$(${ip_script} get_ip_in_hosts ${testaddr[i]})
					if [[ -z $address_ip ]];then
                               			printf "\n%s:  $(gettext 'Configuration error in "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
						printf "%s:  $(gettext 'Hostname "%s" is not in "%s".')\n" ${PROG} ${word} "${SC_BASEDIR}/etc/hosts" | logerr
						adapter_config[i]="wrong"
					fi
								
					read_flag=
					let read_addr=1
					;;
				skip)
					read_flag=
					;;
				*)
					;;
				esac
				if [[ ${read_addr} -eq 0 ]];then
					read_flag="addr"
				fi
				;;
			esac
		done
		if [[ $testaddr_flag -eq 1 ]] ;then
			((count_testaddr += 1))
			if [[ $deprecated_flag -eq 1 ]] ; then
				testaddr[i]=${address[i]}
				testaddr_ip[i]=$(${ip_script} get_ip_in_hosts ${testaddr[i]})
			else
				adapter_config[i]="wrong"
                               	printf "\n%s:  $(gettext 'Configuration error in "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
                                printf "%s:  $(gettext 'testaddress (-failover) must be deprecated.')\n" ${PROG} | logerr
			fi
		fi

		case ${wordcount}  in
		0)
			adapter_config[i]="missing";
			;;
		1)
			adapter_config[i]="needed";
			;;
		*)
			case ${count_testaddr} in
			0)
				adapter_config[i]="wrong"
				printf "\n%s:  $(gettext 'File "%s" contains pre-configured options.')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
				printf "%s:  $(gettext 'Please add IPMP test address configuration to "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
				;;
			1)
				if [[ "${ipmpgroup[i]}" != "${pnmgroup[i]}" ]];then
                               		printf "\n%s:  $(gettext 'Configuration error in "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
                                	printf "%s:  $(gettext 'Groupname must be set to %s.')\n" ${PROG} ${pnmgroup[i]} | logerr
					adapter_config[i]="wrong"
				else
					if [[ "${adapter_config[i]}" != "wrong" ]];then
						adapter_config[i]="complete"
					fi
				fi
				;;
			*)
				adapter_config[i]="wrong"
                               	printf "\n%s:  $(gettext 'Configuration error in "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logerr
                                printf "%s:  $(gettext 'Only one "-failover" address can be configured on an adapter.')\n" ${PROG} | logerr
				;;
			esac
			;;
		esac
		if [[ -n "${readflag}" ]] then
				adapter_config[i]="wrong"
		fi

	(( i += 1 ))
	done


	if [[ "${runtype}" == "check" ]] &&
	   [[ -n "${SC_UPGD_TST_IF}" ]] ;then
		printf "\n\n$(gettext 'Checking "-S" option IP Multipathing test addresses')\n" ${PROG} | logmsg
	fi


	for entry in ${SC_UPGD_TST_IF}
	do
		let found=0
		let i=0
		while [[ ${i} -lt ${#adapter[*]} ]]
		do
			entry_1=$(IFS=@ ;set -- ${entry};echo $1)
			entry_2=$(IFS=@ ;set -- ${entry};echo $2)
			if [[ "${entry_2}" == "${adapter[i]}" ]]; then
				if  [[ "${adapter_config[i]}" == "complete" ]]||
			    	    [[ "${adapter_config[i]}" == "wrong" ]] ;then
					if [[ "${runtype}" == "check" ]];then
                                		printf "\n%s:  $(gettext 'Adapter already configured in %s/etc/hostname.%s')\n" ${PROG} "${SC_BASEDIR}" ${adapter[i]} | logmsg
                                		printf "%s:  $(gettext 'Command-line test address will be ignored for adapter %s.')\n\n" ${PROG} ${adapter[i]}| logmsg
					fi
				else
					testaddr[i]=${entry_1}
					testaddr_ip[i]=$(${ip_script} get_ip_in_hosts ${testaddr[i]})
					ipmpgroup[i]=${pnmgroup[i]}
				fi
				let found=1
				break
			fi
			(( i += 1 ))
		done
		if [[ ${found} -eq 0 ]];then
                        printf "\n%s:  $(gettext 'Invalid Adapter in -S option: %s')\n" ${PROG} ${entry_2} | logerr
                        printf "%s:  $(gettext 'Adapter %s is not in any nafo group')\n" ${PROG} ${entry_2} | logerr
			return 1
		fi
	done

	let i=0
	let config_errors=0
	let incomplete=0
	while [[ ${i} -lt ${#adapter[*]} ]]
	do
		case ${adapter_config[i]} in

		"wrong")
			(( config_errors += 1 ))
			;;
		"missing"|"needed"|"complete")
			if [[ "${adapter_config[i]}" != "complete" ]];then
				let incomplete=1
			fi
			if [[ -z "${testaddr[i]}" ]] ;then
	   			if [[ ${SC_UPGD_TST_ASKME} -eq ${SC_FALSE} ]] ;then
					printf "\n%s:  $(gettext 'Configuration incomplete for adapter "%s".')\n" ${PROG} ${adapter[i]}| logmsg
					printf "%s:  $(gettext 'Use "-S interact" option to configure all test addresses.')\n" ${PROG} | logmsg
					(( config_errors += 1 ))
				fi
				(( i += 1 ))
				continue
			fi

			j=${adapter_j[i]}
			gotaddr="${testaddr[i]}"
			gotaddr_ip=$(${ip_script} get_ip_in_hosts ${gotaddr})

			if [[ -z "${gotaddr_ip}" ]];then
				printf "\n%s:  $(gettext 'Invalid test address for adapter(%s) "%s".')\n" ${PROG} ${adapter[i]} ${testaddr[i]} | logerr
				printf "%s:  $(gettext 'Cannot resolve address "%s" using "%s" file.')\n" ${PROG} "${gotaddr}" "${SC_BASEDIR}/etc/hosts" | logerr
				gotaddr=
			fi

			if [[ "${gotaddr_ip}" == "${nafoip[j]}" ]];then
				printf "\n%s:  $(gettext 'Invalid test address for adapter(%s) "%s".')\n" ${PROG} ${adapter[i]} ${testaddr[i]} | logerr
				printf "%s:  $(gettext 'Test address must be different than adapter address.')\n" ${PROG} | logerr
				gotaddr=
			fi

			if [[ -n "${gotaddr}" ]];then
				let k=0
				while [[ ${k} -lt ${#adapter[*]} ]]
				do
					if [[ "${gotaddr_ip}" == "${testaddr_ip[k]}" ]] &&\
					   [[ ${i} -ne ${k} ]];then
						printf "\n%s:  $(gettext 'Invalid test address for adapter(%s) "%s".')\n" ${PROG} ${adapter[i]} ${testaddr[i]} | logerr
						printf "%s:  $(gettext 'Test address is already in use on adapter %s.')\n" ${PROG} ${adapter[k]} | logerr
						gotaddr=
						break
					fi
					(( k += 1 ))
				done
			fi

			if [[ -n "${gotaddr}" ]];then
				let k=0
				while [[ ${k} -lt ${#nafoip[*]} ]]
				do
					if [[ "${gotaddr_ip}" == "${nafoip[k]}" ]];then
						printf "\n%s:  $(gettext 'Invalid test address for adapter(%s) "%s".')\n" ${PROG} ${adapter[i]} ${testaddr[i]} | logerr
						printf "%s:  $(gettext 'Test address is already in use on group %s.')\n" ${PROG} ${nafo[k]} | logerr
						gotaddr=
						break
					fi
					(( k += 1 ))
				done
			fi
			if [[ -n "${gotaddr}" ]];then
				gotaddrsubnet=$(${ip_script} calculate_subnet ${gotaddr_ip} ${nafonetmask[j]})
				nafosubnet=$(${ip_script} calculate_subnet ${nafoip[j]} ${nafonetmask[j]})
				if [[ ${gotaddrsubnet} -ne ${nafosubnet} ]];then
					printf "\n%s:  $(gettext 'Invalid test address for adapter(%s) "%s".')\n" ${PROG} ${adapter[i]} ${testaddr[i]} | logerr
					printf "%s:  $(gettext 'Test address for adapter %s must be in the same subnet as:')\n" ${PROG} ${adapter[i]} | logerr
					lnetmask=${nafonetmask[j]}
					printf "%s:  $(gettext '	Group:%s IP:%s Netmask:%s')\n" ${PROG} ${nafo[j]} ${nafoip[j]} ${lnetmask} | logerr
					gotaddr=
				fi
			fi
			if [[ -z "${gotaddr}" ]];then
				(( config_errors += 1 ))
			fi
			;;
		*)
			printf "\n%s:  $(gettext 'Internal Error : Invalid adapter_config for %s.')\n" ${PROG} ${adapter[i]} ${testaddr[i]} >&2
			return 2
			;;
		esac
	(( i += 1 ))
	done

	if [[ ${config_errors} -gt 0 ]];then
		printf "\n%s:  $(gettext 'Check above IP Multipathing requirements/errors before upgrade.')\n" ${PROG} | logerr
		return 1
	fi

	if [[ ${incomplete} -eq 0 ]];then
		mv /etc/cluster/pnmconfig /etc/cluster/pnmconfig.obsolete || return 1
		return 0
	fi

	while [[ ${SC_UPGD_TST_ASKME} -eq ${SC_TRUE} ]]
	do

		sc_print_title "$(gettext 'Conversion of NAFO to IP Network Multipathing groups.')"

		sc_print_para "${sctxt_p1}"

		printf "    $(gettext 'Here is a list of public network adapters on this node:')\n\n"

		printf "%10.10s %-8s %-8s %-18s %-14s %-16s\n" "" "$(gettext 'Adapter')" "$(gettext 'Group')" "$(gettext 'Failover Address')" "$(gettext 'Netmask')" "$(gettext 'Test Address')"
		printf "%10.10s %-8s %-8s %-18s %-14s %-16s\n\n" "" "=======" "=====" "================" "=======" "============"
		let i=0
		while [[ ${i} -lt ${#adapter[*]} ]]
		do
			j=${adapter_j[i]}
			lnetmask=${nafonetmask[j]}
			if [[ -z "${testaddr[i]}" ]];then
				printf "%10.10s %-8s %-8s %-18s %-14s %-16s\n" "" "${adapter[i]}" "${pnmgroup[i]}" "${nafoip[j]}" "${lnetmask}" "<none>"
			else
				printf "%10.10s %-8s %-8s %-18s %-14s %-16s\n" "" "${adapter[i]}" "${pnmgroup[i]}" "${nafoip[j]}" "${lnetmask}" "${testaddr[i]}"
			fi
			(( i += 1 ))
		done

		let i=0
		while [[ ${i} -lt ${#adapter[*]} ]]
		do
			if [[ -n "${testaddr[i]}" ]] ;then
				(( i += 1 ))
				continue
			fi

			ipmpgroup[i]=${pnmgroup[i]}
			j=${adapter_j[i]}
			gotaddr=
			while [[ -z "${gotaddr}" ]]
			do
				printf "\n"
				gotaddr=$(sc_prompt "$(gettext 'What test address do you want to assign to') \"${adapter[i]}\"?" "") || return 1
				gotaddr_ip=$(${ip_script} get_ip_in_hosts ${gotaddr})

				if [[ -z "${gotaddr_ip}" ]];then
					printf "$(gettext 'Invalid test address : cannot resolve "%s" using "%s" file.')\n" "${gotaddr}" "${SC_BASEDIR}/etc/hosts"
					gotaddr=
					continue
				fi

				if [[ "${gotaddr}" == "${nafoip[j]}" ]];then
					printf "$(gettext 'Invalid test address : must be different than adapter address.')\n"
					gotaddr=
					continue
				fi

				let k=0
				while [[ ${k} -lt ${#adapter[*]} ]]
				do
					if [[ "${gotaddr_ip}" == "${testaddr_ip[k]}" ]];then
						printf "$(gettext 'Test address "%s" is already in use on adapter %s.')\n" "${gotaddr}" "${adapter[k]}"
						gotaddr=
						continue 2
					fi
					(( k += 1 ))
				done

				let k=0
				while [[ ${k} -lt ${#nafoip[*]} ]]
				do
					if [[ "${gotaddr_ip}" == "${nafoip[k]}" ]];then
						printf "$(gettext 'Test Address "%s" is already in use on group %s.')\n" "${gotaddr}" "${nafo[k]}"
						gotaddr=
						continue 2
					fi
					(( k += 1 ))
				done

				gotaddrsubnet=$(${ip_script} calculate_subnet ${gotaddr_ip} ${nafonetmask[j]})
				nafosubnet=$(${ip_script} calculate_subnet ${nafoip[j]} ${nafonetmask[j]})
				if [[ ${gotaddrsubnet} -ne ${nafosubnet} ]];then
					printf "$(gettext 'Invalid test address : must provide address in the same subnet as the group.')\n"
					lnetmask=${nafonetmask[j]}
					printf "$(gettext 'Adapter %s belongs to Group %s (Address %s Netmask %s)')\n" "${adapter[i]}" "${nafo[j]}" "${nafoip[j]}" "${lnetmask}"
					gotaddr=
					continue
				fi
			done
			testaddr[i]=${gotaddr}
			testaddr_ip[i]=${gotaddr_ip}
			(( i += 1 ))
		done

		printf "    $(gettext 'This is the list of test addresses you entered:')\n\n"
		printf "%10.10s %-8s %-8s %-18s\n" "" "$(gettext 'Adapter')" "$(gettext 'Group')" "$(gettext 'Test Address')"
		printf "%10.10s %-8s %-8s %-18s\n\n" "" "=======" "=====" "============"
		let i=0
		while [[ ${i} -lt ${#adapter[*]} ]]
		do
			if [[ ${adapter_config[i]} == "missing" ]] || \
			   [[ ${adapter_config[i]} == "needed" ]];then
				printf "%10.10s %-8s %-8s %-18s \n" "" "${adapter[i]}" "${pnmgroup[i]}" "${testaddr[i]}"
			fi
			(( i += 1 ))
		done

		# Confirm before continuuing
		echo
		okay=$(sc_prompt_yesno "$(gettext 'Is this list correct?')" "${YES}") || return 1

		# Zero out the test address to re-prompt addresses.
		if [[ ${okay} != "yes" ]];then
			let i=0
			while [[ ${i} -lt ${#adapter[*]} ]]
			do
				if [[ ${adapter_config[i]} == "missing" ]] || \
			   	   [[ ${adapter_config[i]} == "needed" ]];then
					testaddr[i]=
					testaddr_ip[i]=
				fi
				(( i += 1 ))
			done
		else
			let i=0
			while [[ ${i} -lt ${#adapter[*]} ]]
			do
				if [[ ${adapter_config[i]} == "missing" ]] || \
	  		 	   [[ ${adapter_config[i]} == "needed" ]];then
					SC_UPGD_TST_IF="${SC_UPGD_TST_IF} ${testaddr[i]}@${adapter[i]}"
				fi
				(( i += 1 ))
			done
			SC_UPGD_TST_ASKME=${SC_FALSE}
		fi

	done


	if [[ "${runtype}" == "check" ]];then
		return 0
	fi

	let i=0
	while [[ ${i} -lt ${#adapter[*]} ]]
	do
		case ${adapter_config[i]} in
		"missing")
			printf "\n$(gettext 'Creating "%s".')\n" "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logmsg
			echo "${testaddr[i]} deprecated -failover netmask + broadcast + group ${ipmpgroup[i]} up" > ${SC_BASEDIR}/etc/hostname.${adapter[i]} || return 1
			;;
		"needed")
			printf "\n$(gettext 'Updating "%s".')\n" "${SC_BASEDIR}/etc/hostname.${adapter[i]}" | logmsg
			echo "${address[i]} netmask + broadcast + group ${ipmpgroup[i]} up \\" > ${SC_BASEDIR}/etc/hostname.${adapter[i]} || return 1
			echo "addif ${testaddr[i]} deprecated -failover netmask + broadcast + up" >> ${SC_BASEDIR}/etc/hostname.${adapter[i]} || return 1
			;;
			*)
			;;
		esac
	(( i += 1 ))
	done
	mv /etc/cluster/pnmconfig /etc/cluster/pnmconfig.obsolete
	return 0
}

#####################################################
#
# upgd_ntp_config
#
#	The purpose of this function is to rename the default SC3.0 ntp.conf
#	files to their new ntp.conf.cluster names.  The rc script for starting
#	the NTP daemon changed in Solaris 9 in such a way that the default
#	ntp.conf file which was shipped with SC3.0[u[1,2]] causes cluster
#	startup to hang . The current fix to this problem is a new NTP rc
#	startup script for Sun Cluster.
#
#	If ntp.conf exists, this new startup script does nothing, allowing the
#	standard startup script to do its job.
#
#	But, if the file does not exist, it will startup NTP using
#	ntp.conf.cluster, if that file exists.
#
#	Users who want to use their own ntp.conf files are normally instructed
#	to add them as /etc/inet/ntp.conf. However, since this function has no
#	way of knowing whether the original ntp.conf file was derived from the
#	Sun Cluster default file or not, this function always renames ntp.conf
#	to ntp.conf.cluster whenever ntp.conf.cluster is not present.  This
#	means that user-written ntp.conf files will also end up being called
#	ntp.conf.cluster after the upgrade.  This will not hurt anything, since
#	the new Sun Cluster rc script is derived directly from the Solaris 8
#	NTP rc script.
#
#	On the other hand, it is far safer to take this action than to risk
#	hanging the node on the next boot attempt.  A message is printed to the
#	user indicating that ntp.conf has been renamed to ntp.conf.cluster
#
#	The documentation instructs users who are using their own ntp.conf files
#	on how to prevent the upgrade process from renaming their NTP config
#	files.
#
#	If /etc/inet/ntp.cluster is copied to /etc/inet/ntp.conf.cluster prior
#	to upgrade, the original ntp.conf file is left untouched.  The
#	documentation also includes a description of the change which was made
#	to the Solaris 9 NTP rc script.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_ntp_config()
{
        if [[ $# != 0 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_ntp_config()')\n" ${PROG} >&2
                return 2
        fi

        if [[ ! -f "${SC_BASEDIR}/etc/inet/ntp.conf.cluster" ]] &&
           [[ -f "${SC_BASEDIR}/etc/inet/ntp.conf" ]];then
		mv ${SC_BASEDIR}/etc/inet/ntp.conf ${SC_BASEDIR}/etc/inet/ntp.conf.cluster
		if [[ $? -ne 0 ]];then
			printf "\n%s:  $(gettext 'Error moving "%s" to "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/inet/ntp.conf" "${SC_BASEDIR}//etc/inet/ntp.conf.cluster" | logerr
			return 1
		else
			printf "\n%s:  $(gettext 'Renamed "%s" to "%s".')\n" ${PROG} "${SC_BASEDIR}/etc/inet/ntp.conf" "${SC_BASEDIR}/etc/inet/ntp.conf.cluster" | logmsg
		fi
	fi

	return 0
}

#####################################################
#
# upgd_documentation cdimagebasedir flag
#
#       cdimagebasedir          location of .cdtoc file
#       flag			"framework" or "dataservices"
#
#	This function checks if the type of documentation "framework" or
#	"dataservices" is installed on the node
#
#	If documentation is found on the cluster node, the procedure
#	"installdocs" is called to add the newer documentation packages
#	avaiable on the CDROM.
#
#       Return:
#               zero            Success
#               non-zero        Failure
#
#####################################################
upgd_documentation()
{
        typeset -r cdimagebasedir=$1
        typeset -r flag=$2
	typeset abcluster
	integer installed=0

        if [[ $# != 2 ]]  then
                printf "%s:  $(gettext 'Internal error - bad call to upgd_documentation()')\n" ${PROG} >&2
                return 2
        fi

	case ${flag} in
		framework)
			abcluster="SUNWCscfab"
			;;
		dataservices)
			abcluster="SUNWCscdab"
			;;
		*)
                	printf "%s:  $(gettext 'Internal error - Invalid flag to upgd_documentation()')\n" ${PROG} >&2
                	return 2
			;;
	esac
	# get the directory on CD containing the .cdtoc file
	realcdimage=$(find_cdimagebasedir "${cdimagebasedir}" "" "${abcluster}") || return 1

	# get the name of the product directory
	productdir=$(getproduct ${realcdimage}/${SC_CDTOC} "" ${abcluster} "dir" 2>/dev/null)

	# get list of packages on the CD in the documentation cluster
	pkglist=$(print_clustertoc ${productdir}/.clustertoc ${abcluster} "packages")

	for pkg in ${pkglist}
	do
		pkginfo -q ${pkg}
		if [[ $? -eq 0 ]];then
			let installed=1
		fi
	done

	# Only if some documentation packages are installed
	if [[ ${installed} -eq 1 ]];then
		installdocs ${cdimagebasedir} "${abcluster}" || return 1
	fi

	return 0
}
