#!/usr/bin/ksh
#
# ident "@(#)ssp_config.ksh	1.95    03/06/27     SMI"
#
# Copyright (c) 1996-2001 by Sun Microsystems, Inc.
# All rights reserved.
#
#

#
# SSP Shell script for:
# ssp_config, ssp_unconfig, ssp_install, ssp_upgrade, ssp_post_os_upgrade,
# ssp_backup, ssp_restore, and ssp_terminate.
#

#
# Some globals we use
#
SSPOPT=${SSPOPT:-/opt/SUNWssp}		export SSPOPT
SSPETC=${SSPETC:-/etc/opt/SUNWssp}	export SSPETC
SSPVAR=${SSPVAR:-/var/opt/SUNWssp}	export SSPVAR
SSPLOGGER=${SSPLOGGER:-${SSPVAR}/adm}	export SSPLOGGER
TEXTDOMAIN=${TEXTDOMAIN:-SUNW_SSP}	export TEXTDOMAIN

PLATFORM_TYPE=Ultra-Enterprise-10000
CBCONFIGFILE=${SSPVAR}/.ssp_private/cb_config
FADCONFIGFILE=${SSPVAR}/.ssp_private/fad_files
ETHERSFILE=/etc/ethers
HOSTSFILE=/etc/hosts
INITTAB=/etc/inittab
RESERVED_PLAT="starfire common"
ENV=${SSPETC}/ssp_env.sh
MYPID=$$
EDD_ERC=edd.erc
EDD_EMC=edd.emc
# All X terminal apps that can have a SSP program name (title bar)
# on the command line:
XTERMS='xterm|dtterm|cmdtool|shelltool'

# Append a suffix names to files to be saved.
UPGRADE_TAG="__upgrade"

#
# The current shipping version is required.
# This number must be changed if a newer PROM version is required by a
# particular SSP release.
PROM_REQUIRED=3.47

# The following line should be commented out when a version newer than 3.46
# is released - but it won't hurt if left alone but remember to uncomment
# the line in check_proms where PROM_CURRENT is set.
PROM_CURRENT=3.46

# Location of the flash PROM file
FLASH_BOOT_FILE=${SSPOPT}/cbobjs/flash_boot.ima

#
# Location of the floating main SSP IP info file
#
MAIN_SSP_NAME_FILE=${SSPVAR}/.ssp_private/main_ssp_name

# Used for debugging purposes, read from environment
typeset -r SSP_DEBUG=${SSP_DEBUG:-}

#############################################################################
#
# Display usage message
#
#############################################################################
usage()
{
    gettext "Usage: ssp_config [cb|float]\n       ssp_terminate\n       ssp_upgrade <package-dir>\n       ssp_install <package-dir>\n       ssp_backup <target-dir>\n       ssp_restore <backup-file>\n       ssp_post_os_upgrade\n"
}

#############################################################################
#
# Generic routine for fatal errors.  Displays error message ($*) and exits.
#
#############################################################################
fatal()
{
    typeset format=$(gettext "ERROR!")
    print -u2 "$format  $*"
    print -u2 $(gettext "ABORTING!")
    exit 2
}

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

#############################################################################
#
# 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.
# Must use /usr/bin/ps, not /usr/ucb/ps.
#
# $1 - name of process to look for (must be short (8 character) name as in ps)
# $2 - owner of process (defaults to root)
#
#############################################################################
getpid()
{
	/usr/bin/ps -u ${2:-root} -o 'pid,fname=COMMAND_NAME' | \
	    awk '{if ($2 == "'"$1"'") {print $1}}'
}


#############################################################################
#
# 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 -l ans=""
    # TRANSLATION_NOTE - these are the shell globs for an affirmative or a
    # negative answer, respectively.  The comparison is done after the
    # input is converted to lower case (using any locale specific case
    # conversion).  The defaults are any words starting with "y" or "n".
    typeset ansYes="$(gettext "y*")"
    typeset ansNo="$(gettext "n*")"
    typeset prompt="${1}"
    # TRANSLATION_NOTE - this is the format for yes or no prompts - %s is
    # the actual question.
    typeset format="$(gettext "%s (y/n) ")"

    while true
    do
	printf "$format" "$prompt"
	read ans
	case "$ans" in
	$ansYes)
	    return 0;;
	$ansNo)
	    return 1;;
	esac
    done
}

###########################################################################
#
# save_n_copy
#
# save dst file before copying from src file
# $1 - dst
# $2 - src
# $3 - mode
# $4 - owner
#
###########################################################################
save_n_copy()
{
    typeset dst=${1}
    typeset src=${2}
    typeset mode=${3}
    typeset owner=${4}

    if [[ ! -f "${src}" ]]
    then
	# source file doesn't exist, don't do anything
	return
    fi

    if [[ -f "${dst}" ]]
    then
	if cmp -s ${dst} ${src}
	then
	    # no copy necessary
	    return
	fi
	rotate_file ${dst} 8
    fi

    if cp ${src} ${dst}
    then
	chmod "${mode}" ${dst}
	chown "${owner}" ${dst}
    else
	# TRANSLATION_NOTE - %s is destination file
	fatal "$(printf "$(gettext 'Could not create %s!')" "${dst}!")"
    fi
}

#############################################################################
#
# lookup_ip_addr()
#
# Given a hostname as an argument, set the variable in $2,
# and the return status of the match (0=OK)
#
# Bugids 4023717, 4086719, 4056209:
# 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 _addr
    typeset _name
    typeset _junk
    typeset _line
    typeset _names
    typeset _file=${HOSTSFILE:-/etc/hosts}
    typeset _var=${2:-HOST_ADDR}
    getent hosts ${1} | read _addr _name _junk
    if [[ -n "$_addr" ]]
    then
	eval "${_var}=\"${_addr}\""
	return 0
    fi

    if [[ ! -f "${_file}" ]]
    then
	# nowhere else to look (why is there no hosts file???)
	return 1
    fi

    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 < "${_file}"

    # we did not find a match
    return 1
}


#############################################################################
#
# lookup_etheraddr()
#
# Given a hostname as an argument, set the ETHER_ADDR variable,
# and the return status of the match (0=OK)
#
# Bugids 4023717, 4086719, 4056209:
# Use /etc/nsswitch.conf file (to decide between NIS+, NIS, DNS, files).
#
# $1 - name of host to look for
# $2 - variable to save address in, defaults to ETHER_ADDR
#
#############################################################################
lookup_etheraddr()
{
    typeset _name
    typeset _addr
    typeset _junk
    typeset _var=${2:-ETHER_ADDR}
    typeset _file=${ETHERSFILE:-/etc/ethers}
    getent ethers ${1} | read _name _addr _junk
    if [[ -n "$_addr" ]]
    then
	eval "${_var}=\"${_addr}\""
	return 0
    fi

    if [[ ! -f "${_file}" ]]
    then
	# no where else to look!
	return 1
    fi

    while read _name _addr _junk
    do
	if [[ -z "$_name" || "$_name" == "#"* || \
	      -z "$_addr" || "$_addr" == "#"* ]]
	then
	    # skip comments and whitespace
	    continue
	fi

	if [[ "$_name" == ${1}?(.*) ]]
	then
	    eval "${_var}=\"${_addr}\""
	    return 0
	fi
    done < "${_file}"

    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
#
#############################################################################
get_ip_addr()
{
    typeset _ip_glob="+([0-9]).+([0-9]).+([0-9]).+([0-9])"
    typeset _ipset=false
    typeset _addr=""
    typeset _var=${2}
    typeset _fmt=""

    _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}"
	read _addr
	if [[ -n "$_addr" ]]
	then
	    if [[ "${_addr}" == +([0-9]).+([0-9]).+([0-9]).+([0-9]) ]]
	    then
		eval "$_var=\"$_addr\""
		break
	    else
		printf "\n$(gettext "ERROR! \"%s\" is not an IP address!")\n" \
		    "$_addr"
	    fi
	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_procspeed - prompts the user for the processor/interconnect frequencies
#
#############################################################################
get_procspeed()
{
    typeset options
    typeset procspeed
    typeset procmultiple
    typeset interconnect
    typeset -i cpuspeed

    while true
    do
        print
        gettext "You must specify what type of processor modules you have installed in your Enterprise-10000 platform.  Please select one of the options below." | fmt
	set -A options \
		"$(gettext '250 MHz processors')" \
	 	"$(gettext '336 MHz processors')" \
	 	"$(gettext '400 MHz processors')" \
		"$(gettext '466 MHz processors')" \
	 	"$(gettext 'Unlisted (manually enter clock values)')"
	print

	PS3=$(gettext "\nWhat speed of processors do you have installed? ")
	select procspeed in "${options[0]}" "${options[1]}" "${options[2]}" "${options[3]}" "${options[4]}"
	do

	  case "$procspeed" in

	  "${options[0]}")
	      # 250 MHz procs
	      interconnect=83333333
	      procmultiple=three-to-two
	      cpuspeed=250
	      ;;

	  "${options[1]}")
	      # 336 MHz procs
	      interconnect=83333333
	      procmultiple=two-to-one
	      cpuspeed=336
	      ;;

	  "${options[2]}")
	      # 400 MHz procs
	      interconnect=100000000
	      procmultiple=two-to-one
	      cpuspeed=400
	      ;;

	  "${options[3]}")
              # 466 MHz procs
              interconnect=93000000
              procmultiple=five-to-two
              cpuspeed=466
              ;;
 
          "${options[4]}")
	      # manually entered values
	      print
	      gettext 'You have selected options which should only be used by Sun authorized personnel.  Incorrect data entry can result in damage to your processors! ' | fmt
	          # return to processor speed menu
	      if ! yes_or_no "$(gettext '\nAre you sure you want to proceed?')"
	      then
	          # return to processor speed menu
	          continue
	      fi

	      # collect the interconnect frequency
	      interconnect=
	      while [[ -z "$interconnect" ]]
	      do
		  print
	          gettext 'Enter the interconnect frequency in Hertz.  For example, 83.333 MHz is\ngiven as 83333333.  Be careful, incorrect values can cause damage.' | fmt
		  gettext '\nWhat is the interconnect frequency (in Hertz)? '
		  read interconnect
		  if [[ "$interconnect" != +([0-9]) ]]
		  then
		       interconnect=
		       gettext '\nInterconnect frequency must be a number.\n'
		  elif expr "$interconnect" \< 40000000 >/dev/null 2>&1
		  then
		      interconnect=
		      gettext '\nInterconnect frequency must be at least 40000000 (40MHz)\n'
		  elif expr "$interconnect" \> 120000000 >/dev/null 2>&1
		  then
		      interconnect=
		      gettext '\nInterconnect frequency must be less than 120000000 (120MHz)\n'
		  fi
	      done

	      # collect the processor multiplier
	      print
	      gettext 'You must specify the processor clock multipler.  Please select one of the options below.' | fmt
	      print
	      PS3="$(gettext "\nWhat is the processor clock multiplier? ")"
	      select procmultiple in "two-to-one" "three-to-one" "three-to-two" "five-to-two"
	      do
		  case $procmultiple in
		  two-to-one)
		      cpuspeed=$(( 2 * 2 * $interconnect / 1000000 ))
		      break
		      ;;
		  three-to-one)
		      cpuspeed=$(( 2 * 3 * $interconnect / 1000000 ))
		      break
		      ;;
		  three-to-two)
		      cpuspeed=$(( 3 * $interconnect / 1000000 ))
		      break
		      ;;
		  five-to-two)
		      cpuspeed=$(( 5 * $interconnect / 1000000 ))
		      break
		      ;;
		  *)
		      print
		      ;;
		  esac
	      done

	      ;;

	    *)
	      # invalid entry - go back to the processor speed menu
	      REPLY=
	      print
	      continue
	      ;;

	  esac

	  break

	done	# select procspeed ...

	print
	printf "$(gettext 'Your selections are apparently for a %d MHz processor.')" $cpuspeed | fmt
	print
	if yes_or_no "$(gettext 'Is this correct?')"
	then
	  break
	fi

    done  # while true
    if [[ -n "$1" ]]
    then
        eval "${1}=$interconnect"
    fi
    if [[ -n "$2" ]]
    then
        eval "${2}=$procmultiple"
    fi
}

#############################################################################
#
# save_procspeed - save the processor speeds we've already determined
#
# $1 - interconnect
# $2 - procmultiple
#############################################################################
save_procspeed()
{
    typeset ssp_interconnect
    typeset ssp_procmultiple
    typeset SSPRESOURCE=/var/opt/SUNWssp/.ssp_private/ssp_resource
    ssp_interconnect=${PLATFORM_TYPE}.platformTargetInterconnectClockFreq
    ssp_procmultiple=${PLATFORM_TYPE}.platformTargetProcClockMultiple

    sed -e "s/${ssp_interconnect}:.*\$/${ssp_interconnect}:${1}/" \
        -e "s/${ssp_procmultiple}:.*\$/${ssp_procmultiple}:${2}/" \
	 $SSPRESOURCE > $SSPRESOURCE.$$ && \
 		chown ssp:staff $SSPRESOURCE.$$ && \
		chmod 644 $SSPRESOURCE.$$ && \
		mv $SSPRESOURCE.$$ $SSPRESOURCE
}

#############################################################################
#
# 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 machine to the SSP software.  The platform name occupies a different name space than domain names (hostnames of bootable systems).' | fmt
	print

	if [[ -n "$_default" ]]
	then
	    # TRANSLATION_NOTE - %s is the default platform name
	    _fmt=$(gettext 'What is the name of the platform this SSP will service [%s]? ')
	else
	    _fmt=$(gettext 'What is the name of the platform this SSP 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}\""
	    return 0
	fi
    done
}

#############################################################################
#
# hexip - function to convert a standard IP address into a hexidecimal
# IP address suitable for tftpboot.  This does no error checking so you'd
# better send it a valid IP address.  The result is echo'd so you will
# probably want to use this with back-quotes as in: HIP=`hexip 1.2.3.4`
#
#############################################################################
hexip()
{
    typeset ip=$1
    printf "%02X%02X%02X%02X\n" $(print $ip | tr . ' ')
}


#############################################################################
#
# get_cb_name()
#
# function to get a control board name.
#
# $PLATFORM_NAME	- name of platform (used to build default name)
# $CB0_NAME, $CB1_NAME	- current name of conbrds 0 and 1, set on exit
# $CHANGE		- set to "true" if name was changed
# $1 - control board number, either 0 or 1
# $2 - variable to store result in, defautls to $CB{$1}_NAME, default value
#      is also taken from here.
#
#############################################################################
get_cb_name()
{
    typeset -i _num="$1"
    typeset _prompt
    typeset _fmt
    typeset _name
    typeset _newname
    typeset _oldname
    typeset _var="$2"

    if [[ -z "$_var" ]]
    then
	_var="CB${_num}_NAME"
    fi


    # if no control board, then clear the name
    _prompt=$(printf "$(gettext "Do you have a control board %d?")" "$_num")

    print
    if ! yes_or_no "$_prompt"
    then
	eval $_var=""
	return
    fi

    eval "_newname=\"\$$_var\""
    _oldname="${_newname}"
    if [[ -z "${_newname}" ]]
    then
	_newname=${PLATFORM_NAME}cb${_num}
    fi

    # TRANSLATION_NOTE - %d is either 0 or 1, %s is default conbrd name
    _fmt=$(gettext "Please enter the host name of the control board %d [%s]: ")
    print
    printf "${_fmt}" "${_num}" "${_newname}"
    read _name

    if [[ -n "$_name" ]]
    then
	_newname="$_name"
    fi

    if [[ "${_oldname}" != "${_newname}" ]]
    then
	CHANGE=true
    fi

    eval "$_var=\"$_newname\""
}

#############################################################################
#
# get_cb
#
# Get control board information.
#
# $1 - control board number (0 or 1)
# $2 - variable to store name in - defaults to CB{$1}_NAME
# $3 - variable to store IP addr in - defaults to CB{$1}_ADDR
#
#############################################################################
get_cb()
{
    typeset _cb=$1
    typeset _var1=$2
    typeset _var2=$3
    typeset _cb_name

    if [[ -z "$_var1" ]]
    then
	_var1="CB${_cb}_NAME"
    fi

    if [[ -z "$_var2" ]]
    then
	_var2="CB${_cb}_ADDR"
    fi
    get_cb_name ${_cb} _cb_name
    if [[ -n "${_cb_name}" ]]
    then
	eval "$_var1=\"${_cb_name}\""
	if ! lookup_ip_addr "${_cb_name}" "$_var2"
	then
	    get_ip_addr ${_cb_name} ${_var2}
	fi
    else
	eval "$_var1="
	eval "$_var2="
    fi
}

#############################################################################
#
# get_primary_cb
#
# Identify the primary control board in a two board system.
#
# $P0, $P1 - P{$primary_cb} is set to "P", the other one is cleared
# $1 - cb0's name
# $2 - cb1's name
#
#############################################################################
get_primary_cb()
{
    typeset cb0="$1"
    typeset cb1="$2"
    typeset -i _cb
    typeset _fmt
    typeset _name=
    typeset _prompt

    P0=
    P1=

    if [[ -n "$cb0" && "$cb0" == "$cb1" ]]
    then
	gettext "\nControl Board 0 and Control Board 1 are identical.\n"
	return 1
    elif [[ -z "$cb0" && -z "$cb1" ]]
    then
	gettext "\nNo control board has been identified.\n"
	return 1
    elif [[ -z "$cb1" ]]
    then
	P0=P
	return 0
    elif [[ -z "$cb0" ]]
    then
	P1=P
	return 0
    fi

    prompt=$(gettext "Is Control Board %d [%s] the primary?")
    while true
    do
	gettext "\nPlease identify the primary control board.\n"
	for _cb in 0 1
	do
	    _name=$(eval print \$cb${_cb})
	    _prompt=$(printf "$prompt" "${_cb}" "${_name}")

	    if yes_or_no "$_prompt"
	    then
		eval P${_cb}=P
		return
	    fi
	done

    done
}

#############################################################################
#
# parse_cb_config
#
# Parse the cb_config file
#
# how many entries in file? assuming only a single line...
# this needs to be expanded to handle multiple entries.
#
# $PLATFORM_NAME	- name of the platform
# $CB0_NAME		- name of CB #0
# $CB1_NAME		- name of CB #1
# $CB0_ADDR		- ip address of CB #0
# $CB1_ADDR		- ip address of CB #1
# $P0, $P1		- set to P if either CB0 or CB1 is primary
# $VALID_CONFIG		- "true" if a valid configuration exists
# $PLATFORM_LOCKED	- "true" if the platform is set
#
#############################################################################
parse_cb_config()
{
    VALID_CONFIG=
    PLATFORM_LOCKED=
    if [[ -s "${CBCONFIGFILE}" ]]
    then
	# try and parse current info
	PLATFORM_NAME=$(cut -d: -f1 ${CBCONFIGFILE})
	# we only support Ultra-Enterprise-10000, do not allow this to be
	# set in the file
	PLATFORM_TYPE=$(cut -d: -f2 ${CBCONFIGFILE})
	CB0_NAME=$(cut -d: -f3 ${CBCONFIGFILE})
	P0=$(cut -d: -f4 ${CBCONFIGFILE})
	CB1_NAME=$(cut -d: -f5 ${CBCONFIGFILE})
	P1=$(cut -d: -f6 ${CBCONFIGFILE})
	if [[ -n "$CB0_NAME" ]]
	then
	    lookup_ip_addr "$CB0_NAME" CB0_ADDR
	fi
	if [[ -n "$CB1_NAME" ]]
	then
	    lookup_ip_addr "$CB1_NAME" CB1_ADDR
	fi

	VALID_CONFIG=true

	PLATFORM_LOCKED=true
	# platform name is set?
	if [[ -z "$PLATFORM_NAME" ]]
	then
	    PLATFORM_LOCKED=
	    VALID_CONFIG=
	fi

	# platform type is correct?
	if [[ -z "$PLATFORM_TYPE" ]]
	then
	    PLATFORM_TYPE="Ultra-Enterprise-10000"
	    VALID_CONFIG=
	fi

	if [[ -z "$CB0_NAME" && -z "$CB1_NAME" ]]
	then
	    VALID_CONFIG=
	fi

	# sanity check P0/P1
	if [[ -n "$P1" && -n "$P0" ]]
	then
	    P0=
	    P1=
	    VALID_CONFIG=
	elif [[ -n "$P1" && -z "$CB1_NAME" ]]
	then
	    P1=
	    VALID_CONFIG=
	elif [[ -n "$P0" && -z "$CB0_NAME" ]]
	then
	    P0=
	    VALID_CONFIG=
	fi

    else
	# file not present
	PLATFORM_NAME=
	CB0_NAME=
	CB1_NAME=
	CB0_ADDR=
	CB1_ADDR=
	P0=
	P1=
    fi
}

#############################################################################
#
# set_main_ssp_ip_info
#
# Query the ssp_config user for the hostname associated with the floating
# main ssp.  Save the floating main ssp name in ${MAIN_SSP_NAME_FILE}
#
# Returns:
# 0 => Successfully got and saved main SSP IP info
# 1 => Failed to save main SSP IP info
#############################################################################
set_main_ssp_ip_info()
{
    typeset main_ssp_name
    typeset main_ssp_ip_addr
    typeset name_changed
    typeset result=0

    while true
	do
        query_main_ssp_name main_ssp_name name_changed
        if ! lookup_ip_addr "${main_ssp_name}" main_ssp_ip_addr
        then
            get_ip_addr "${main_ssp_name}" main_ssp_ip_addr
        fi

        write_main_ssp_ip_info ${main_ssp_name} ${main_ssp_ip_addr}
        result=$?

        fmt=$(gettext 'main SSP name = %s')
        printf "\n${fmt}\n" "${main_ssp_name}"
        fmt=$(gettext 'main SSP IP address = %s')
        printf "${fmt}\n" "${main_ssp_ip_addr}"
        print
        if yes_or_no "$(gettext "Is this correct?")"
        then
            break
        fi
    done
    return $result
}


#############################################################################
#
# query_main_ssp_name()
#
# Query the ssp_config user for the name associated with the floating main
# SSP name.
#
# $1 - Varible to hold main SSP name
# $2 - Result parameter that indicates whether the main SSP name has
# changed.
#
#############################################################################
query_main_ssp_name()
{
    typeset main_ssp_name_p=$1
    typeset name_changed_p=$2
    typeset new_main_ssp_name
    typeset old_main_ssp_name
    typeset old_main_ssp_ip_addr
    typeset default_main_ssp_name
    typeset fmt

    #
    # Set the default main SSP name,  If a name exists in the 
    # ${MAIN_SSP_NAME_FILE} the use it as default otherwise the default is
    # ${PLATFORM_NAME}-ssp-main.
    #
    read_main_ssp_ip_info old_main_ssp_name old_main_ssp_ip_addr
    if [[ $? -eq 0 ]]; then
        default_main_ssp_name=${old_main_ssp_name}
    else
        get_platform_name PLATFORM_NAME
        default_main_ssp_name=${PLATFORM_NAME}-ssp-main
        old_main_ssp_name=
    fi

    # TRANSLATION_NOTE - %s is default floating main SSP name
    fmt=$(gettext "Please enter the floating host name of the main SSP [%s]: ")
    print
    printf "${fmt}" "${default_main_ssp_name}"
    read new_main_ssp_name

    if [[ -z "${new_main_ssp_name}" ]]
    then
        #
        # Default main SSP name was selected
        #
        new_main_ssp_name=${default_main_ssp_name}
    fi

    if [[ "${new_main_ssp_name}" != "${old_main_ssp_name}" ]]
    then
        eval ${name_changed_p}=1
    else
        eval ${name_changed_p}=0
    fi

    eval ${main_ssp_name_p}=${new_main_ssp_name}
}


#############################################################################
#
# read_main_ssp_ip_info()
#
# Attempt to read the current floating main SSP IP info from the file,
# ${MAIN_SSP_NAME_FILE}
# 
#
# $1 - Varible to hold main SSP name
# $2 - Varible to hold main SSP IP address
#
# Returns:
# 0 => Successfully read the name and IP address from the file
# 1 => ${MAIN_SSP_NAME_FILE} is not readable
# 2 => the format of ${MAIN_SSP_NAME_FILE} is incorrect
#############################################################################
read_main_ssp_ip_info() {
    typeset main_ssp_name_p=$1
    typeset main_ssp_name
    typeset main_ssp_ip_addr_p=$2
    typeset main_ssp_ip_addr
    typeset result=0

    if [[ -r ${MAIN_SSP_NAME_FILE} ]]; then
        read main_ssp_name main_ssp_ip_addr < ${MAIN_SSP_NAME_FILE}
        if [[ -n ${main_ssp_name} && -n ${main_ssp_ip_addr} ]]; then
            eval ${main_ssp_name_p}=${main_ssp_name}
            eval ${main_ssp_ip_addr_p}=${main_ssp_ip_addr}
            result=0
        else
            eval ${main_ssp_name_p}=
            eval ${main_ssp_ip_addr_p}=
            result=2
        fi
    else
        eval ${main_ssp_name_p}=
        eval ${main_ssp_ip_addr_p}=
        result=1
    fi
    return $result
}


#############################################################################
#
# write_main_ssp_ip_info()
#
# Attempt to write the current floating main SSP IP info to the file,
# ${MAIN_SSP_NAME_FILE}
# 
#
# $1 - main SSP name
# $2 - main SSP IP address
#
# Returns:
# 0 => Successfully wrote main SSP IP info to file
# 1 => Write failed
#############################################################################
write_main_ssp_ip_info() {
    typeset main_ssp_name=$1
    typeset main_ssp_ip_addr=$2
    typeset result

    print -n "${main_ssp_name}\t${main_ssp_ip_addr}" >| ${MAIN_SSP_NAME_FILE}

    if [[ $? -ne 0 ]]; then
        result=1
    else
        result=0
        chown ssp ${MAIN_SSP_NAME_FILE}
        chmod 644 ${MAIN_SSP_NAME_FILE}
    fi
    return $result
}


#############################################################################
#
# remove_ssp_startup_from_rc_init_directories()
#
# Remove the SSP startup scripts /etc/rc?.d/*ssp and /etc/init.d/*ssp.
# Remove a call to ssp_startup, which starts SSP daemons, from /etc/inittab
# Re-read /etc/inittab (historical)
#
# Code based on SUNWsspr/postremove
#
#############################################################################
remove_ssp_startup_from_rc_init_directories()
{
    typeset file=${INITTAB:-/etc/inittab}
    typeset initline

    # First, remove from /etc/inittab, which was used historically:
    if [[ -f ${file} ]]
    then
	initline=$(grep "^sp:234:respawn:.*ssp_startup.sh" ${file} 2>/dev/null)
	# Remove the ssp_startup from the /etc/inittab file.
	if [[ -n "$initline" ]] ; then
	    (echo '/^sp:234:respawn:.*ssp_startup.sh/d';
	    echo 'w';
	    echo 'q' ) | ed -s ${file} >/dev/null
	fi
    fi

    # Have init re-read /etc/inittab:
    init q

    # Pull out rc scripts as well
    if [ -f /etc/init.d/ssp ]
    then
	rm -f /etc/rc?.d/[SK][0-9][0-9]ssp
    fi
}


#############################################################################
#
# add_ssp_startup_to_rc_init_directories()
#
# Add a call to ssp_startup, which starts SSP daemons, to the startup
# scripts /etc/rc?.d/*ssp and /etc/init.d/*ssp
# (instead of inittab, which was used historically).
#
# Code based on SUNWsspr/postinstall
# See man init.d(4) for directory structure.
#
#############################################################################
add_ssp_startup_to_rc_init_directories()
{
	# First remove old versions of the ssp_startup line in the file, if any:
	remove_ssp_startup_from_rc_init_directories

	# configure startup scripts
	ln -sf /etc/init.d/ssp /etc/rc2.d/S99ssp
	ln -sf /etc/init.d/ssp /etc/rc1.d/K20ssp
	ln -sf /etc/init.d/ssp /etc/rc0.d/K20ssp
}

#############################################################################
#
# sighup_inetd()
#
#
# Have inetd re-read /etc/inetd.conf to update with any changes above
# (Note: we have to use ps to get the PID, since it's not saved in a
# .pid file) (Bugid 4069016)
#
#
#############################################################################
sighup_inetd()
{
	# Have inetd re-read /etc/inetd.conf to update with any changes above
	# (Note: we have to use ps to get the PID, since it's not saved in a
	# .pid file) (Bugid 4069016)
	#
	inetd_pid=$(getpid inetd root)

	if [[ -n "$inetd_pid" ]]
	then
	    kill -HUP $inetd_pid
	fi
}
#############################################################################
#
# tftpboot_setup()
# Set up the tftpboot stuff
#
# Move files from /tftpboot.spare to /tftpboot in case this
# system used to be the SSP spare (bugid 4036803).
#
# This routine should be called only for the main SSP, not spare SSP
# (bugids 4112732, 4036803).
#
#############################################################################
tftpboot_setup()
{

    typeset file
    if [[ -d /tftpboot.spare && ! -d /tftpboot ]]
    then
	mv /tftpboot.spare /tftpboot
    elif [[ -d /tftpboot.spare && -d /tftpboot ]]
    then
	# directory already there--move contents conditionally
	for file in /tftpboot.spare/* /tftpboot.spare/.*
	do
	    if [[ -f "${file}" && ! -e /tftpboot/${file##*/} ]]
	    then
		mv -f "${file}" /tftpboot
	    fi
	done
	rm -rf /tftpboot.spare

    elif [[ ! -d /tftpboot ]]
    then
	mkdir -m 755 /tftpboot
    fi

    CBOBJS=${SSPOPT}/cbobjs
    /usr/sbin/install -f /tftpboot -s -m 444 ${CBOBJS}/cbe.ima
    /usr/sbin/install -f /tftpboot -s -m 444 ${SSPVAR}/.ssp_private/cb_port

    if [[ -n "${CB0_ADDR}" ]]
    then
	CB0HEXIP=$(hexip ${CB0_ADDR})
	rm -f /tftpboot/${CB0HEXIP}
	ln -f /tftpboot/cbe.ima /tftpboot/${CB0HEXIP}
	chmod 444 /tftpboot/${CB0HEXIP}
	rm -f /tftpboot/${CB0HEXIP}.cb_port
	ln -f /tftpboot/cb_port /tftpboot/${CB0HEXIP}.cb_port
	chmod 444 /tftpboot/${CB0HEXIP}.cb_port
    fi

    if [[ -n "${CB1_ADDR}" ]]
    then
	CB1HEXIP=$(hexip ${CB1_ADDR})
	rm -f /tftpboot/${CB1HEXIP}
	ln /tftpboot/cbe.ima /tftpboot/${CB1HEXIP}
	chmod 444 /tftpboot/${CB1HEXIP}
	rm -f /tftpboot/${CB1HEXIP}.cb_port
	ln /tftpboot/cb_port /tftpboot/${CB1HEXIP}.cb_port
	chmod 444 /tftpboot/${CB1HEXIP}.cb_port
    fi

    #
    # Uncomment tftp from or add tftp to the inetd.conf file if necessary.
    #
    if grep '^#tftp' /etc/inetd.conf >/dev/null ; then # Uncomment
		ed /etc/inetd.conf << EOF >/dev/null
/^#tftp
s/^#//
.
w
q
EOF
		sighup_inetd
    elif ! grep '^tftp' /etc/inetd.conf >/dev/null ; then # Add
		# Uh-oh!  Where's the tftp line?! Let's add it near the end.
		ed /etc/inetd.conf << EOF >/dev/null
$
i
tftp	dgram	udp	wait	root	/usr/sbin/in.tftpd	in.tftpd -s /tftpboot
.
w
q
EOF
		sighup_inetd
	fi

	#
	# The /tftpboot directory should already exist, start the
	# RARPD daemon (nsf.server does it for us)
	#
	#/usr/sbin/rpc.bootparamd
	# Better to do it right--start and stop nfs.server (bug 4294678):
	/etc/init.d/nfs.server stop
	/etc/init.d/nfs.server start
}


#############################################################################
#
# tftpboot_disable()
# Disable the tftpboot stuff
#
# Move files from /tftpboot to /tftpboot.spare
# This must be done so /etc/init.d/nfs.server won't enable rarpd
# and cause cbs to query the spare SSP for tftp service instead of
# the main SSP (bugid 4036803).  We don't care if tftp is disabled,
# *but* /tftpboot mustn't be there so rarpd isn't enabled at bootup
# by /etc/init.d/nfs.server.
#
# This routine should be called only for the spare SSP, not main SSP
# (bugids 4112732, 4036803).
#
#############################################################################
tftpboot_disable()
{
    # Bug 4876163 - moved changes for bug 4337012 from function sighup_inetd
    # to function tftpboot_disable, added line to while loop to kill tftpd
    # sessions.
    # Original comment for bug 4337012:
    # check for outstanding tftpd sessions. Bug #4337012 has solaris 8
    # not recovering tftpd process if a SIGHUP occurs while it is 
    # outstanding
    tftpd_pid=$(getpid in.tftpd root)
    while [[ -n "$tftpd_pid" ]]
	do
		kill $tftpd_pid
		tftpd_pid=$(getpid in.tftpd root)
	done

    if [[ -d /tftpboot ]]
    then
	if [[ ! -d /tftpboot.spare ]]
	then
	    mv /tftpboot /tftpboot.spare
	else # target directory already there--move contents
	    mv /tftpboot/* /tftpboot/.[^.]* /tftpboot.spare 2>/dev/null
	    rm -rf /tftpboot
	fi
    fi

    # Disable the spare SSPs tftp boot server (bugid 4036803)
    if grep '^tftp' /etc/inetd.conf >/dev/null
    then
		ed /etc/inetd.conf << EOF >/dev/null
/^tftp
s/^tftp/#tftp/
.
w
q
EOF
		sighup_inetd
    fi

    #
    # Kill the RARPD daemon, don't want it active on the spare
    #
    rarpd_pid=$(getpid in.rarpd root)
    if [[ -n "$rarpd_pid" ]]
    then
	kill $rarpd_pid
    fi
}

#############################################################################
#
# show_config
#
# Display the current control board configuration
#
#############################################################################
show_config()
{
    # TRANSLATION_NOTE - make sure the equal signs (=) line up properly
    printf "$(gettext "Platform name     = %s")\n" "${PLATFORM_NAME}"
    if [[ -n "$CB0_NAME" && -n "$CB0_ADDR" ]]
    then
	printf "$(gettext 'Control board %d = %s => %s')\n" 0 "${CB0_NAME}" "${CB0_ADDR}"
    else
	printf "$(gettext 'Control board %d = [empty]')\n" 0
    fi
    if [[ -n "$CB1_NAME" && -n "$CB1_ADDR" ]]
    then
	printf "$(gettext 'Control board %d = %s => %s')\n" 1 "${CB1_NAME}" "${CB1_ADDR}"
    else
	printf "$(gettext 'Control board %d = [empty]')\n" 1
    fi
    if [ "$P0" == "P" ]
    then
	printf "$(gettext 'Primary Control Board = 0')\n"
    else
	printf "$(gettext 'Primary Control Board = 1')\n"
    fi
}

#############################################################################
#
# save_cb_config
#
# Save out changes to the ${CBCONFIGFILE}.
#
#############################################################################
save_cb_config()
{
    # write out the cbconfig file
    print "${PLATFORM_NAME}:${PLATFORM_TYPE}:${CB0_NAME}:${P0}:${CB1_NAME}:${P1}" > /tmp/tmpcb$$
    save_n_copy "${CBCONFIGFILE}" /tmp/tmpcb$$ 644 ssp
    rm -f /tmp/tmpcb$$
}

#############################################################################
#
# get_n_save_cb_config
#
# Get the control board configuration.  This prompts the user for
# data using preloaded defaults from parse_cb_config.  The final results
# are actually saved to the ${CBCONFIGFILE}.
#
#############################################################################
get_n_save_cb_config()
{
    while true
    do
	if [[ "$VALID_CONFIG" == true ]]
	then
	    show_config
	    print

	    # upgrades should be noninteractive if possible
	    if [[ -n "$SSP_UPGRADE" ]]
	    then
		break
	    fi

	    if yes_or_no "$(gettext "Is this correct?")"
	    then
		break
	    fi
	fi

	if [[ -f /.SSP_DEFAULTS ]]
	then
	    # we force the user to enter a new ssp passwd by expiring
	    # the old one.
	    passwd -r files -d -f ssp
	    # unconfigured, so we don't know what kind of procs are out there
	    get_procspeed INTERCONNECT PROCMULTIPLE
	    # write out the ssp resource processor speeds
	    save_procspeed $INTERCONNECT $PROCMULTIPLE
	fi

	if [[ "$PLATFORM_LOCKED" != true ]]
	then
	    get_platform_name PLATFORM_NAME
	fi
	get_cb 0 CB0_NAME CB0_ADDR
	get_cb 1 CB1_NAME CB1_ADDR

	if ! get_primary_cb "$CB0_NAME" "$CB1_NAME"
	then
	    VALID_CONFIG=
	    continue
	fi
	VALID_CONFIG=true
    done

    # write out the cbconfig file
    if [[ ! -s "${CBCONFIGFILE}" || "${CHANGE}" == true ]]
    then
	save_cb_config
    fi

}

#############################################################################
#
# create_platform_link
#
# create the platform specific link in the data directory
#
#############################################################################
create_platform_link()
{
	# create the platform-specific data link
	typeset DATA=${SSPVAR}/data/${PLATFORM_TYPE}
	if [[ ! -d ${DATA} ]]
	then
		fmt=$(gettext "Couldn't find %s!")
		fatal "$(printf "$fmt\n" "${DATA}")"
	fi

	rm -f ${DATA}/${PLATFORM_NAME}
	if ! ln -s ./starfire ${DATA}/${PLATFORM_NAME}; then
		fmt=$(gettext "Couldn't create %s!")
		fatal "$(printf "$fmt\n" "${DATA}/${PLATFORM_NAME}")"
	fi
}

#############################################################################
#
# copy_data_files
#
# Install the various data files and directories needed at runtime.
#
#############################################################################
copy_data_files()
{
    typeset p_etc=${SSPVAR}/etc/${PLATFORM_NAME}
    typeset cbobjs_dir=${p_etc}/cbobjs
    typeset tmpl=${SSPVAR}/.ssp_private/templates/${PLATFORM_TYPE}
    typeset platform_erc=${tmpl}/edd.platform.erc
    typeset domain_erc=${tmpl}/edd.domain.erc
    typeset domaindir=

    if [[ ! -d ${p_etc} ]]
    then
	mkdir -m 755 -p ${p_etc}
	chown ssp ${p_etc}
    fi

    if [[ ! -d ${cbobjs_dir} ]]
    then
	mkdir -m 755 -p ${cbobjs_dir}
	chown ssp ${cbobjs_dir}
    fi

    # if a copy of the platform erc file exists, save it off
    save_n_copy ${p_etc}/${EDD_ERC} ${platform_erc} 640 ssp

    # if a copy of the platform emc file exists, save it off
    save_n_copy ${p_etc}/${EDD_EMC} ${tmpl}/${EDD_EMC} 640 ssp

    # take care of domain files, too
    for domaindir in ${p_etc}/*
    do
	if [[ -f "${domaindir}/${EDD_ERC}" ]]
	then
	    save_n_copy ${domaindir}/${EDD_ERC} ${domain_erc} 640 ssp
	fi
    done

    # remove globalconst.tcl file, to be rebuilt by edd
    rm -f ${cbobjs_dir}/globalconst.tcl

    #
    # Make sure bids.tcl and thermcaldata.tcl are there
    # (bugs 4054660 4067723)
    touch ${cbobjs_dir}/bids.tcl
    chmod 644 ${cbobjs_dir}/bids.tcl
    chown ssp ${cbobjs_dir}/bids.tcl

    touch ${cbobjs_dir}/thermcaldata.tcl
    chmod 644 ${cbobjs_dir}/thermcaldata.tcl
    chown ssp ${cbobjs_dir}/thermcaldata.tcl

    #
    # Remove /etc/opt/SUNWssp/snmp/*.idy and let it be rebuilt by scotty
    #
    rm -f ${SSPETC}/snmp/*.idy
}

#############################################################################
#
# make_platform_config
#
# Install platform config file, we only do this on a first run.
#
#############################################################################
make_platform_config()
{
    typeset platform_name=${1}
    typeset configdir=${SSPVAR}/data/${PLATFORM_TYPE}/config
    typeset platform_config=${configdir}/${platform_name}.config
    typeset starfire_config=${configdir}/starfire.config
    if [[ ! -s "${platform_config}" || "${CHANGE}" == true ]]
    then
	if cp ${starfire_config} ${platform_config}
	then
	    chown ssp ${platform_config}
	    chmod 644 ${platform_config}
	else
	    fatal "$(printf "$(gettext "Could not create %s!")" "${platform_config}!")"
	fi
    fi
}



#####################################################
#
# deconfig_float_ip() 
#
#	This function will remove a float IP address from the public network
#	interface of a SSP if it is assigned. This function should only be
#       executed by the spare SSP. The float IP address information is 
#	retrieved from the ${SSPVAR}/.ssp_private/main_ssp_name file.
#	After the float IP is removed, it will also update the 
#	"ssp_to_domain_hosts" file to replace whatever ssp hostname in that file
#	to the official host name (given by the "uname -n" command) of this SSP.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
#####################################################
deconfig_float_ip()
{
	typeset this_ssp_name=`uname -n`
	typeset ssp_to_domain_file=${SSPVAR}/.ssp_private/ssp_to_domain_hosts
	typeset -r float_ipaddr=$(cat ${SSPVAR}/.ssp_private/main_ssp_name | cut -f2)
	typeset foo=$(egrep -l "^$(uname -n)$" /etc/hostname.*)
	typeset adapt=${foo##*hostname.}
	typeset os_version_major=$(uname -r | cut -d. -f1)
	typeset os_version_minor=$(uname -r | cut -d. -f2)
	integer i
	typeset tmp_file=/var/tmp/deconfig_float_ip.$$
	typeset old_ssp_name
	typeset ret_status

	if [[ -z "${float_ipaddr}" || -z "${foo}" ]]; then
		return 1
	fi

	ret_status=0

	# 
	# First check if the float_ipaddr is assigned
	#
	ifconfig -a | egrep " ${float_ipaddr} " >/dev/null 2>&1
	if [[ $? == 0 ]] 
	then
		#
		# float_ipaddr is assigned
		#
		if [[ $os_version_major > 5 || $os_version_minor > 7 ]]
		then
			#
			# SunOS 5.8 or beyond
			#
			ifconfig $adapt removeif $float_ipaddr >/dev/null 2>&1
			if [[ $? != 0 ]]
			then
				ret_status=1
			fi
		else
			#	
			# SunOS 5.7 or earlier
			# Find the logical interface to which it is assigned
			#
			let i=1
			while (( i <= 100 ))
			do
				su ssp -fc "ifconfig ${adapt}:${i} | egrep ${float_ipaddr}" >/dev/null 2>&1
				if [[ $? == 0 ]]
				then
					break
				fi
				i=$((i + 1))
			done
	
			if [[ i == 101 ]]
			then
				# we give up
				ret_status=1
			else
				ifconfig ${adapt}:${i} 0 down >/dev/null 2>&1
				if [[ $? != 0 ]] 
				then
					ret_status=1
				fi
			fi
		fi
	fi
	
	#
	# We need to update the "ssp_to_domain_hosts" file to change the ssp name
	# to local hostname (given by the "uname -n" command") and we only do so when
	# either the float ip address is not assigned or the above operation succeeded.
	#
	if [[ -f $ssp_to_domain_file && $ret_status == 0 ]]
	then
		old_ssp_name=`cut -d' ' -f2 $ssp_to_domain_file | head -1`
		sed -e "s/ ${old_ssp_name}/ ${this_ssp_name}/g" $ssp_to_domain_file > $tmp_file
		cp $tmp_file $ssp_to_domain_file
		rm -f $tmp_file
	fi
	
	return $ret_status
}


#############################################################################
#
# ssp_terminate()
#
# Terminate the specific SSP process(es) specified on the command line.
# if no SSP process specified, terminate all SSP processes.
#
# First, kill daemons gracefully with SIGTERM,
# then use SIGKILL as a last resort.
# This avoids cleanup problems, such as half-open sockets.
#
# Note: SIGKILL doesn't need any time to complete,
# SIGTERM needs some for cleanup.
#
#############################################################################
ssp_terminate()
{
    #
    # Kill specific ssp processes specified on the command line
    #
    if [[ $# -ne 0 ]]; then
        for proc in $*; do
            for signal in TERM KILL; do
            	pids=$(/usr/bin/ps -ef -o 'pid,fname=VERY_LONG_COMMAND_NAME' | \
			egrep $proc | egrep -v egrep | awk '{print $1}')
	    	if [[ $pids = "" ]]; then
		    break
	        fi
	
		for pid in $pids; do
                    kill -$signal $pid >/dev/null 2>&1
		done

		if [[ $signal = "TERM" ]] ; then
			# wait betwwen TERM and KILL signals
			sleep 1
		fi
            done
	done

	return
    fi
			
    # 
    # kill all SSP processes.
    # killing startup monitoring scripts and hostview
    #
    for signal in TERM KILL; do
	pids=$(/usr/bin/ps -ef | \
		egrep "ssp_startup.sh|ssp_startup.tcl|hostview" | \
		egrep -v egrep | awk '{print $2}')
    	if [ "$pids" = "" ] ; then
	    break
	fi
	for pid in $pids; do
	    kill -$signal $pid >/dev/null 2>&1
    	done

	if [ $signal = "TERM" ] ; then
		# Wait between TERM and KILL signals
		sleep 1
	fi
    done

    #
    # killing client apps (some also serve in a server role)
    #
    for signal in TERM KILL; do
	pids=$(/usr/bin/ps -ef | \
	egrep "bringup|hpost|scotty|netcon$|netcon |netcon_server|obp_helper"| \
		egrep -v "egrep|ps \-ef|rlogin|$XTERMS" | \
		awk '{print $2}')
    	if [ "$pids" = "" ] ; then
		break
	fi
    	for pid in $pids; do
	    kill -$signal $pid >/dev/null 2>&1
    	done

	if [ $signal = "TERM" ] ; then
		# Wait between TERM and KILL signals
		sleep 2
	fi
    done

    #
    # killing the daemons
    #
    for signal in TERM KILL; do
    	for i in codd/ssp edd/ssp snmpd/root straps/root straps/ssp \
			cbs/ssp datasyncd/ssp fod/ssp fad/ssp; do
		daemon=`dirname $i`
		owner=`basename $i`
		pid=$(getpid $daemon $owner)
		if [[ -n "$pid" ]] ; then
		    kill -$signal $pid >/dev/null 2>&1
		fi
    	done

	if [ $signal = "TERM" ] ; then
		# Wait between TERM and KILL signals
		sleep 1
	fi
    done

    #
    # killing ap daemons
    #
    for signal in TERM KILL; do
	pids=$(/usr/bin/ps -ef | egrep "ap_ssp_daemon|ap_startup" | \
		egrep -v "egrep|ps \-ef|rlogin|$XTERMS" | awk '{print $2}')
    	if [ "$pids" = "" ] ; then
		break
	fi
    	for pid in $pids; do
	    kill -$signal $pid >/dev/null 2>&1
    	done
	if [ $signal = "TERM" ] ; then
		# Wait between TERM and KILL signals
		sleep 1
	fi
    done

    #
    # killing machine_server
    #
    for signal in TERM KILL; do
	pids=$(/usr/bin/ps -ef | egrep machine_server | \
		egrep -v "egrep|ps \-ef|rlogin|$XTERMS" | awk '{print $2}')
	if [ "$pids" = "" ] ; then
		break
	fi
	for pid in $pids; do
		kill -$signal $pid >/dev/null 2>&1
	done
	if [ $signal = "TERM" ] ; then
		# Wait between TERM and KILL signals
		sleep 1
	fi
    done

    #
    # Remove the float IP address
    #
    deconfig_float_ip

    # do *not* call exit here, it breaks other things
}


###########################################################################
#
# ssp_pkgrm
#
# Check for package existence before invoking pkgrm.
# argument contains a list of packages to remove
#
###########################################################################
ssp_pkgrm()
{
    while [ $# -gt 0 ]
    do
	pkginfo $1 >/dev/null 2>&1
	if [[ $? -eq 0 ]]
	then
	    print -n "pkgrm $1..."
	    pkgrm -n -a ${adminfile} $1 >> ${log} 2>&1
	    if [[ $? -ne 0 ]]
	    then
		pkg_err=1
		gettext "failed\n"
	    else
		gettext "done\n"
	    fi
	fi
	shift
    done
}

###########################################################################
#
# ssp_pkgadd
#
# Individually perform pkgadd. The advantage of doing it one at a time
# is that we could install even if a package on the list is missing.
# argument contains a list of packages to add.
#
###########################################################################
ssp_pkgadd()
{
    typeset response

    while [[ $# -gt 0 ]]
    do
	if [[ -f "/tmp/${1}.response.${MYPID}" ]]
	then
	    response="-r /tmp/${1}.response.${MYPID}"
	else
	    response=-n
	fi

	print -n "pkgadd $1..."
	pkgadd -d ${package_dir} ${response} -a ${adminfile} $1 >> ${log} 2>&1
	if [[ $? -ne 0 ]]
	then
	    pkg_err=1
	    gettext "failed\n"
	else
	    gettext "done\n"
	fi
	shift
    done
}

###########################################################################
#
# ssp_pkgadd_fp
#
# Install the Flash PROM (SUNWsspfp) if the user need/wants to
#
###########################################################################
ssp_pkgadd_fp()
{
    typeset prompt

    # Get here only if the PROM is not installed and the installed PROM
    # version is out of date; ask the user for direction
    print
    prompt=$(gettext "Do you want to install the SUNWsspfp package?")
    if yes_or_no "$prompt"
    then
	pkgadd -d ${package_dir} SUNWsspfp
	if [[ $? -ne 0 ]]
	then
	    pkg_err=1
	    print "pkgadd SUNWsspfp failed" >> ${log} 2>&1
	    gettext "SUNWsspfp package installation failed.\n"
	    print
	else
	    # pkgadd success
	    return
	fi
    fi

    # Either pkgadd failed or user answered 'n', need to upgrade later
    printf "$(gettext 'You must install the SUNWsspfp package and update the firmware on control board %s. See the Installation Guide for details.')" "$name" \
	| fmt
    print
}


###########################################################################
#
# save_a_copy
#
# Make a backup copy of a file for upgrade purpose.
#
###########################################################################
save_a_copy()
{
    typeset format=$(gettext "Backing up %s as %s")
    while [[ $# -gt 0 ]]
    do
	if [[ -f "$1" ]]
	then
	    printf "$format\n" $1 $1.$UPGRADE_TAG
	    cp $1 $1.$UPGRADE_TAG
	fi
	shift
    done
}

###########################################################################
#
# restore_a_copy
#
# Copy back the file saved by save_a_copy()
#
###########################################################################
restore_a_copy()
{
    typeset format=$(gettext "Restoring %s as %s")
    while [[ $# -gt 0 ]]
    do
	if [[ -f "$1.$UPGRADE_TAG" ]]
	then
	    printf "$format\n" $1.$UPGRADE_TAG $1
	    cp $1.$UPGRADE_TAG $1
	fi
	shift
    done
}

#############################################################################
#
# preupgrade
#
# Perform some basic preupgrade processing.  This determines whether the
# SSP was already a main or spare, and backs up key data files.
#
#############################################################################
preupgrade()
{
	typeset SSPRESOURCE=/var/opt/SUNWssp/.ssp_private/ssp_resource
	typeset -i PROCSPEED

	gettext "Upgrading SSP.\n"

	# If the .ssp_resource file is present, save its value in a
	# pkgask file to stop SUNWsspdf from being interactive
	if [[ -f "$SSPRESOURCE" ]]
	then
	    INTERCONNECT=$(awk -F: '/^Ultra-Enterprise-10000.platformTargetInterconnectClockFreq:/ {print $2}' $SSPRESOURCE)
	    PROCMULTIPLE=$(awk -F: '/^Ultra-Enterprise-10000.platformTargetProcClockMultiple:/ {print $2}' $SSPRESOURCE)
	    case "$PROCMULTIPLE" in
	    three-*)
		# external clock tripler
		PROCSPEED=$((3 * $INTERCONNECT / 1000000 ))
		;;
	    two-*)
		# external clock doubler
		PROCSPEED=$((2 * $INTERCONNECT / 1000000 ))
		;;
	    five-*)
		# External clock doubler
		PROCSPEED=$((5 * $INTERCONNECT / 1000000 ))
		;;

	    esac

	    if [[ "$PROCMULTIPLE" == *-one ]]
	    then
		# assume an internal clock doubler
		PROCSPEED=$(( 2 * $PROCSPEED ))
	    fi
	    printf "$(gettext 'Current SSP is configured for %d MHz processors.')" $PROCSPEED | fmt
	else
	    # can't pick up default values, so ask for them
	    get_procspeed INTERCONNECT PROCMULTIPLE
	fi

	# Backup volatile files
	save_a_copy \
	    /export/home/ssp/.Xdefaults \
	    /export/home/ssp/.openwin-menu \
	    /export/home/ssp/.xinitrc \
	    /export/home/ssp/.drtclrc \
	    /export/home/ssp/.openwin-init \
	    /export/home/ssp/.openwin-menu-ssp \
	    /export/home/ssp/.redxrc \
	    /export/home/ssp/.cshrc \
	    /export/home/ssp/.login \
	    /export/home/ssp/.postrc \
	    /var/opt/SUNWssp/.ssp_private/bringup.lock \
	    /var/opt/SUNWssp/.ssp_private/bringup_dr.lock \
	    /var/opt/SUNWssp/.ssp_private/ssp_resource \
	    /var/opt/SUNWssp/adm/.logger
}

#############################################################################
#
# convert_domain_config
#
# Convert domain_config file to new (3.1) (IDN enhanced) format.
#
# old (3.0) format:  domain : platform : physical : release : boardlist
# new (3.1) format:  domain : platform : physical : release : IDN : boardlist
#
# Also, in SSP3.2, OS releases 2.x are now 5.x.
#
#############################################################################
convert_domain_config()
{
    typeset oldfile=${1}
    typeset newfile=${1}.upgrade$$
    typeset mode=${2}
    typeset owner=${3}
    typeset domain
    typeset platform
    typeset physical
    typeset release
    typeset idn
    typeset boardlist
    typeset ver=

    if [[ ! -f "${oldfile}" ]]
    then
	format=$(gettext "Old domain config file '%s' not found.")
	printf "$format\n" "$oldfile"
	return
    fi

    > ${newfile}

    while IFS=: read domain platform physical release idn boardlist
    do
	if [[ -z "$boardlist" ]]
	then
	    boardlist="$idn"
	    idn="-1.0"
	fi

	# Switch from Solaris to SunOS numbering
	if [[ "${release}" == 2.* ]]
	then
	    release=5.${release#2.}
	fi

	print "${domain}:${platform}:${physical}:${release}:${idn}:${boardlist}" >> ${newfile}
    done < "${oldfile}"

    if cmp -s "${oldfile}" "${newfile}"
    then
	# files are the same, do not do anything
	rm -f ${newfile}
	return
    fi

    chmod ${mode} ${newfile}
    chown ${owner} ${newfile}
    mv ${newfile} ${oldfile}
}

#############################################################################
#
# update_prom
#
# Updates the Control Board PROM to the required version distributed in
# the SUNWsspfp package.
#
#############################################################################
update_prom()
{
    typeset name=$1

    printf "$(gettext 'Upgrading firmware on control board %s to version %s. This may take five or more minutes, please wait...')" "$name" "$PROM_CURRENT" | fmt
    rc=$(cb_prom -p ${FLASH_BOOT_FILE} -h ${name} | cut -d' ' -f3)
    print
    if [[ "${rc}" == "complete." ]]
    then
	# No need to reset the CB to make the new version active
	# This will be done when the SSP daemons are started
	printf "$(gettext 'The firmware version on %s has been successfully upgraded to %s.')" "$name" "$PROM_CURRENT" | fmt
    else
	printf "$(gettext 'The firmware upgrade procedure on %s failed. See the SSP Installation Guide or cb_prom(1M) for details on the procedure to manually upgrade the firmware.')" "$name" \
		| fmt
    fi
}

#############################################################################
#
# check_proms
#
# Check the Control Board PROMs to see if they need to be upgraded. 
#
#############################################################################
check_proms()
{
    typeset revision
    typeset name
    typeset delta

    # First we need to determine the "current" prom revision shipped with
    # this version of the SSP.
    #
    # The check below doesn't work because version 3.46 has 3.44 in the comments
    # area in the image file - must assume current version is 3.46 for SSP3.1.1
    # When we release a new version (say 3.47) in the future, the following
    # line should be uncommented out.
    #PROM_CURRENT=$(strings ${SSPOPT}/cbobjs/flash_boot.ima | grep Version | cut -d' ' -f2)

    #
    # Make sure that the control boards are running before we check firmware
    # version.
    #

    for name in $CB0_NAME $CB1_NAME
    do
	ping $name 3 >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		# control board is hung, reset it
		cb_reset $name
	fi
    done 
	
    print
    gettext 'Checking the firmware version on the control boards...' | fmt
    print

    for name in $CB0_NAME $CB1_NAME
    do
	# Get version from cb_prom; retry on timeouts
	for i in 1 2 3
	do
		cb_prom_message=$(cb_prom -r -h ${name})
		revision=$(echo ${cb_prom_message} | cut -d' ' -f4)
		echo ${revision} | grep '^[0-9]' >/dev/null 2>&1
		status=$?
		if [[ "${status}" -eq 0 ]] ; then	# It's a number
			break
		fi
	   	print "${cb_prom_message}"
		if [[ "${i}" -lt 3 ]] ; then
			gettext 'Retrying . . .\n'
		fi
	done

	if [[ "${status}" -ne 0 ]] ; then	# Error (not a number)
	    print ${cb_prom_message}
	    printf "$(gettext 'The firmware version on %s could not be determined.  Please check this manually.  See cb_prom(1M) for more information.')" "$name" | fmt

	else
	    patch_found=no
	    for patch in a $(showrev -p | egrep 'SUNWsspfp' | awk '{print $2}')
	    do
		if expr "$patch" : '110735-*' >/dev/null
		then
		    patch_found=yes
		fi
	    done

	    delta=$(print "${revision} - ${PROM_REQUIRED}" | bc)

	    if [[ "$delta" == -* ]]
	    then
		# Older than required - automatic upgrade if possible
		printf "$(gettext 'The firmware version on %s (%s) is out of date and must be upgraded.')" "$name" "$revision" | fmt
		print

		if [[ "$patch_found" == no ]]
		then
		    gettext 'Install patch 110735 to upgrade PROMs\n'
		    print
		    continue
		else
		    gettext 'Follow instructions in patch 110735 to upgrade PROMs\n'
		    print
		    continue
		fi

		# Check if the SUNWsspfp package is installed
		pkginfo -q SUNWsspfp
    		if [[ $? -ne 0 ]]
		then
		    # SUNWsspfp not installed
    		    printf "$(gettext 'The SUNWsspfp package is not installed. The ssp_upgrade tool cannot perform an upgrade of the firmware on control board %s. You must install this package so that the firmware on the control board can be updated.')" "$name" | fmt
    		    # Prompt the user if SUNWsspfp should be installed.
    		    ssp_pkgadd_fp
		fi

		# Update the prom if the user had installed SUNWsspfp
		pkginfo -q SUNWsspfp
	        if [[ $? -eq 0 ]]
		then
		    update_prom $name
		fi

	    else
		# current or newer than current - no need to upgrade
		printf "$(gettext 'The firmware version on %s (%s) is current.')" "$name" "$revision" | fmt
	    fi
	fi
    done
    print
}

#############################################################################
#
# update_emc_erc_files
#
# In SSP 3.1.1, obp_reset, cb_power_on, and cb_power_off were added to
# the edd.emc/edd.erc files. When upgrading or restoring from a backup,
# these need to be checked and added if necessary. The files that require
# checking/updating are:
# /var/opt/SUNWssp/.ssp_private/templates/Ultra-Enterprise-10000/edd.emc
#	obp_reset, cb_power_on/off
# /var/opt/SUNWssp/.ssp_private/templates/Ultra-Enterprise-10000/edd.platform.erc
#	cb_power_on/off
# /var/opt/SUNWssp/.ssp_private/templates/Ultra-Enterprise-10000/edd.domain.erc
#	obp_reset
# /var/opt/SUNWssp/etc/<platform>/edd.emc
#	obp_reset, cb_power_on/off
# /var/opt/SUNWssp/etc/<platform>/edd.erc
#	Cb_power_on/off
# /var/opt/SUNWssp/etc/<platform>/<domain>/edd.erc
#	obp_reset
#
#############################################################################
update_emc_erc_files()
{
    typeset tmpl=${SSPVAR}/.ssp_private/templates/${PLATFORM_TYPE}
    typeset edd_emc_file=${tmpl}/${EDD_EMC}
    typeset edd_platform_erc_file=${tmpl}/edd.platform.erc
    typeset domain_erc=${tmpl}/edd.domain.erc
    typeset domaindir=
    typeset p_etc=
    typeset edd_erc_file=
    typeset -i post_31_release=$1

    # Call parse_cb_config to set the PLATFORM_NAME
    parse_cb_config
    p_etc=${SSPVAR}/etc/${PLATFORM_NAME}

    if [[ ${post_31_release} -eq 1 ]]
    then
	# Check the installed edd.emc file
	if (( $(grep obp_reset ${edd_emc_file} | wc -l) < 1 ))
	then
	    ed -s ${edd_emc_file} << EOF >/dev/null
/^obpbooting
i
obp_reset : enabled		#cpu sig states indicate obp reset condition
.
/^bulk_power_norm
i
cb_power_on : enabled		#a control board has been powered on
cb_power_off : enabled		#a control board has been powered off
.
w
q
EOF
	fi

	# Check the installed edd.platform.erc file
	if (( $(grep cb_power_ ${edd_platform_erc_file} | wc -l) < 1 ))
	then
	    ed -s ${edd_platform_erc_file} << EOF >/dev/null
/^bulk_power_norm
i
cb_power_on : enabled : 0 : 1 : PowerOnact  -t %t -b %b
cb_power_off : enabled : 0 : 1 : PowerOffact  -t %t -b %b
.
w
q
EOF
	fi

	# Check the installed edd.domain.erc file
	if (( $(grep obp_reset ${domain_erc} | wc -l) < 1 ))
	then
	    ed -s ${domain_erc} << EOF >/dev/null
/^obpbooting
i
obp_reset : enabled : 300 : 3 : ObpResetact -d %d
.
w
q
EOF
	fi

	# Check the <platform>/edd.emc file
	edd_emc_file=${p_etc}/${EDD_EMC}
	if [[ -f "${edd_emc_file}" ]]
	then
	    if (( $(grep obp_reset ${edd_emc_file} | wc -l) < 1 ))
	    then
	        ed -s ${edd_emc_file} << EOF >/dev/null
/^obpbooting
i
obp_reset : enabled		#cpu sig states indicate obp reset condition
.
/^bulk_power_norm
i
cb_power_on : enabled		#a control board has been powered on
cb_power_off : enabled		#a control board has been powered off
.
w
q
EOF
	    fi
	fi

	# Check the <platform>/edd.erc file
	edd_erc_file=${p_etc}/${EDD_ERC}
	if [[ -f "${edd_erc_file}" ]]
	then
	    if (( $(grep cb_power_ ${edd_erc_file} | wc -l) < 1 ))
	    then
	        ed -s ${edd_erc_file} << EOF >/dev/null
/^bulk_power_norm
i
cb_power_on : enabled : 0 : 1 : PowerOnact  -t %t -b %b
cb_power_off : enabled : 0 : 1 : PowerOffact  -t %t -b %b
.
w
q
EOF
	    fi
        fi

	# Check each <platform>/<domain>/edd.erc file
	for domaindir in ${p_etc}/*
	do
	    domain_erc=${domaindir}/${EDD_ERC}
	    if [[ -f ${domain_erc} ]]
	    then
	        if (( $(grep obp_reset ${domain_erc} | wc -l) < 1 ))
	        then
		    ed -s ${domain_erc} << EOF >/dev/null
/^obpbooting
i
obp_reset : enabled : 300 : 3 : ObpResetact -d %d
.
w
q
EOF
	        fi
	    fi
        done
    else
	# Pre-SSP 3.1.1 - could be in restore or failover process
	# Remove 3.1.1 specific lines from the edd.emc and edd.erc files
	if (( $(grep obp_reset ${edd_emc_file} | wc -l) > 0 ))
	then
	    ed -s ${edd_emc_file} << EOF >/dev/null
/^obp_reset/d
w
q
EOF
	fi
	if (( $(grep cb_power_ ${edd_emc_file} | wc -l) > 0 ))
	then
	    ed -s ${edd_emc_file} << EOF >/dev/null
/^cb_power_on/d
/^cb_power_off/d
w
q
EOF
	fi

	# Check the installed edd.platform.erc file
	if (( $(grep cb_power_ ${edd_platform_erc_file} | wc -l) > 0 ))
	then
	    ed -s ${edd_platform_erc_file} << EOF >/dev/null
/^cb_power_on/d
/^cb_power_off/d
w
q
EOF
	fi

	# Check the edd.domain.erc file
	if (( $(grep obp_reset ${domain_erc} | wc -l) > 0 ))
	then
	    ed -s ${domain_erc} << EOF >/dev/null
/^obp_reset/d
w
q
EOF
	fi

	# Check the <platform>/edd.emc file
	edd_emc_file=${p_etc}/${EDD_EMC}
	if [[ -f "${edd_emc_file}" ]]
	then
	    if (( $(grep obp_reset ${edd_emc_file} | wc -l) > 0 ))
	    then
	        ed -s ${edd_emc_file} << EOF >/dev/null
/^obp_reset/d
/^cb_power_on/d
/^cb_power_off/d
w
q
EOF
	    fi
        fi

	# Check the <platform>/edd.erc file
	edd_erc_file=${p_etc}/${EDD_ERC}
	if [[ -f "${edd_erc_file}" ]]
	then
	    if (( $(grep cb_power_ ${edd_erc_file} | wc -l) > 0 ))
	    then
	        ed -s ${edd_erc_file} << EOF >/dev/null
/^cb_power_on/d
/^cb_power_off/d
w
q
EOF
	    fi
        fi

	# Check each <platform>/<domain>/edd.erc file
	for domaindir in ${p_etc}/*
	do
	    domain_erc=${domaindir}/${EDD_ERC}
	    if [[ -f ${domain_erc} ]]
	    then
	        if (( $(grep obp_reset ${domain_erc} | wc -l) > 0 ))
	        then
		    ed -s ${domain_erc} << EOF >/dev/null
/^obp_reset/d
w
q
EOF
	        fi
	    fi
	done
    fi
}

###########################################################################
#
# update_ssp_to_domain_hosts
#
# Update the file ssp_to_domain_hosts with the current node name 
#
###########################################################################
update_ssp_to_domain_hosts()
{
    typeset this_ssp_name=$(uname -n)
    typeset ssp_to_domain_hosts=${SSPVAR}/.ssp_private/ssp_to_domain_hosts
    typeset tmp_file=/var/tmp/ssp_tmp$$
    typeset old_ssp_name

    if [[ -f ${ssp_to_domain_hosts} ]]
    then
	# Change the SSP name in the $SSPVAR/.ssp_private/ssp_to_domain_hosts
	old_ssp_name=`cut -d' ' -f2 ${ssp_to_domain_hosts} | head -1`
	sed -e "s/ ${old_ssp_name}/ ${this_ssp_name}/g" ${ssp_to_domain_hosts} \
		> ${tmp_file}
	cp ${tmp_file} ${ssp_to_domain_hosts}
	rm -f ${tmp_file}
    fi
}

###########################################################################
#
# ssp_pkgverify
#
# Verify packages $1, $2, ... $n are installed.
# If not, exit 2.
#
# Bugid 4251250
#
###########################################################################
ssp_pkgverify()
{
    typeset missing_package=0

    gettext "Verifying SSP packages are installed"
    for i in `print $*`
    do
        pkginfo -i $i >>${log} 2>&1
        if [[ $? -eq 0 ]] ; then
                printf "."
        else
                gettext "\nPackage $i is not installed\n"
                missing_package=1
        fi
    done

    print
    if [[ "$missing_package" -ne 0 ]] ; then
	format=$(gettext \
		"One or more packages are not installed.  See %s for details.")
	printf "$format\n" "${log}" | fmt
        gettext "ABORTING!\n" >&2
        exit 2
    fi
}


#############################################################################
#
# ssp_version
#
# Get the current version number for SSP software.
# Put the result in environment variables $major.$minor.$patch.
# These strings are empty if the version can't be determined.
# Called by ssp_upgrade and perform_restore (ssp_restore).
#
# Implementation:
# Test package SUNWsspr, as that is the main SSP package.
# The version is extracted with pkginfo, using the "C" locale.
# Example version format is:
#   VERSION:  3.3.0,REV=00.01.06.00.33
#
#############################################################################
ssp_version()
{
    typeset tmp_file=/var/tmp/ssp_tmp$$

    # Run as a sub-shell so the current locale, if any, won't be changed:
    (
	LANG=C; LC_ALL=C; export LANG LC_ALL
	pkginfo -l SUNWsspr 2>/dev/null | grep 'VERSION:' | \
		cut -d':' -f2 | cut -d',' -f1 | sed 's/ //g' >${tmp_file}
    )

    major=`cut -d. -f1 ${tmp_file}`
    minor=`cut -d. -f2 ${tmp_file}`
    patch=`cut -d. -f3 ${tmp_file}`

    # temp file no longer needed
    rm -f ${tmp_file}
}


#############################################################################
#
# ssp_upgrade
#
# Upgrade the SSP software.
# This is done by stopping SSP, removing all the SSP packages, readding them,
# then setting up the configuration files.
# SSP is NOT restarted.
#
#############################################################################
ssp_upgrade()
{
    SSP_UPGRADE=true
    CHANGE=true
    typeset package_dir=${1}
    typeset priv="${SSPVAR}/.ssp_private"
    typeset domain_config="${priv}/domain_config"
    typeset BAD_CF=
    typeset format
    typeset syslog_tmp_file=/var/tmp/ssp_upgrade_syslog_tmp$$
    typeset snmpd_cnf_tmp_file=/var/tmp/ssp_upgrade_snmpd_cnf_tmp$$
    typeset saved_shadow=/var/tmp/shadow$$
    typeset -i post_31_release

    if [[ -z "$package_dir" ]]
    then
	usage
	exit 4
    fi
    if [[ ! -d "$package_dir" ]]
    then
	format=$(gettext "%s is an invalid directory path.")
	printf "$format\n" "${package_dir}"
	exit 4
    fi
    parse_cb_config

    # cb_config file must exist
    if [[ ! -s "${CBCONFIGFILE}" ]]
    then
	printf "$(gettext "Missing %s.")\n" "${CBCONFIGFILE}"
	BAD_CF=1

    elif [[ -z "${PLATFORM_NAME}" ]]
    then
	format=$(gettext "Corrupted %s: Missing platform name.")
	printf "$format\n" "${CBCONFIGFILE}"
	BAD_CF=1

    elif [[ -z "${PLATFORM_TYPE}" ]]
    then
	format=$(gettext "Corrupted %s: Missing platform type.")
	printf "$format\n" "${CBCONFIGFILE}"
	BAD_CF=1
    fi

    # if we don't have a reasonable config, bail out now
    if [[ -n "$BAD_CF" ]]
    then
	gettext "Can not continue. Re-run ssp_config.\n"
	exit 1
    fi

    gettext "Beginning SSP upgrade..."
    print

    #
    # First check if the float main SSP name or IP address info 
    # is available. If not, this is a good place to create this 
    # information.
    #
    if [[ ! -s "${MAIN_SSP_NAME_FILE}" ]]; then
	gettext "\nWARNING! Can't find the float main SSP name or IP address information.\nWithout it, the upgraded SSP software will not work properly. You can\ncreate this information as part of the SSP upgrade process.\n"
	print

	if yes_or_no "$(gettext 'Do you want to continue?')"
	then  
	    set_main_ssp_ip_info
	else 
	    exit 1
	fi
    fi

    # disable daemons from restarting automatically (in case it's 3.0/3.1)
    remove_ssp_startup_from_rc_init_directories
    # shut down SSP software
    ssp_terminate

    # select a log file
    if [[ -d /var/sadm/system/logs ]]
    then
	log=/var/sadm/system/logs/ssp_upgrade_log
    else
	log=/var/tmp/ssp_upgrade_log
    fi
    # clear log file
    pkg_err=0
    > ${log}
    print "SSP software upgrade" >> ${log}
    date >> ${log}
    print >> ${log}

    # Preserve netcon session logging via local1, if enabled:
    grep '^local1\.' /etc/syslog.conf >${syslog_tmp_file} 2>/dev/null

    # Preserve "trap" lines added by SunMC and others, if any:
    egrep 'SUNW|^trap' ${SSPETC}/snmp/agt/${PLATFORM_TYPE}.snmpd.cnf \
	| egrep -v '127.0.0.1.*5051|127.0.0.1.*162' \
    	>${snmpd_cnf_tmp_file} 2>/dev/null

	# Preserve the user_file_list to avoid losing data when the new one
	# is installed by SUNWsspdf
	cp $priv/user_file_list $priv/user_file_list.$UPGRADE_TAG

    # Set up pkgadd/pkgrm admin file
    adminfile=/tmp/ssp_upgrade_adminfile.$$
    cat > ${adminfile} << EOF
mail=
instance=overwrite
partial=nocheck
runlevel=nocheck
idepend=nocheck
rdepend=nocheck
space=quit
setuid=nocheck
conflict=nocheck
action=nocheck
basedir=default
EOF

    # Perform preupgrade if SSP 3.0 packages are installed.
    preupgrade

    # Remove SSP patches, if any
    if [[ -d /var/sadm/patch ]]
    then
	for patchdir in $(showrev -p | egrep 'SUNWssp' | \
		awk '{print $2}')
	do
		rm -fr /var/sadm/patch/$patchdir
	done
    fi


    # Check from what version of SSP we are upgrading.
    # Get $major.$minor.$patch:
    ssp_version

    post_31_release=1
    if [[ ${major} -lt 3 ]]
    then	# Ancient (SSP 2.0 or earlier)
	post_31_release=0
    elif [[ ${major} -eq 3 ]]
    then
	if [[ ${minor} -eq 0 ]]
	then	# SSP 3.0
		post_31_release=0
    	elif [[ ${minor} -eq 1 ]]
	then
		if [[ ${patch} -eq 0 ]]
    		then	# SSP 3.1
			post_31_release=0
		fi
	fi
    fi

    # Remove the rest of the packages
    # SUNWsspid and SUNWsspdo are new to SSP 3.1/3.1.1
    ssp_pkgrm \
	    SUNWsspdr SUNWsspid SUNWssppo SUNWsspob \
	    SUNWsspdo SUNWsspr SUNWsspst SUNWsspdf \
	    SUNWsspmn SUNWsspop

    # If upgrading from 3.0/3.1, need to save the shadow file in order to
    # preserve the ssp passwd because the 3.1 postremove (SUNWsspue)
    # removes the ssp entry in the /etc/shdow file
    if [[ ${post_31_release} -eq 0 ]]
    then
	cp /etc/shadow ${saved_shadow}
    fi

    ssp_pkgrm SUNWsspue

    if [[ ${post_31_release} -eq 0 ]]
    then
	cp ${saved_shadow} /etc/shadow
	rm -f ${saved_shadow}
    fi

    # Now add the new packages
    ssp_pkgadd \
	    SUNWsspue SUNWsspop SUNWsspmn SUNWsspdf \
	    SUNWsspst SUNWsspr SUNWsspdo SUNWsspob \
	    SUNWssppo SUNWsspid SUNWsspdr

    # Verify packages are installed
    ssp_pkgverify \
	    SUNWsspue SUNWsspop SUNWsspmn SUNWsspdf \
	    SUNWsspst SUNWsspr SUNWsspdo SUNWsspob \
	    SUNWssppo SUNWsspid SUNWsspdr

    # Prompt on install error
    if [[ $pkg_err -eq 1 ]]
    then
	format=$(gettext "Error detected. See %s for details.")
	printf "$format\n" "${log}"
	prompt=$(gettext "Do you want to continue?")
	if ! yes_or_no "$prompt"
	then
	    gettext "ABORTING!\n" >&2
	    exit 2
	fi
    fi

    # Update domain_config file
    save_n_copy ${domain_config} "" 640 ssp
    convert_domain_config ${domain_config} 644 ssp

    # Update control board objects
    get_n_save_cb_config

    # create the platform-specific data link
    create_platform_link

    # create the platform configuration file
    make_platform_config

    # save the processor speed information
    save_procspeed $INTERCONNECT $PROCMULTIPLE


    # Restore "trap" lines added to snmpd.cnf by SunMC and others, if any:
    if [ -s "${snmpd_cnf_tmp_file}" ] ; then
		cat ${snmpd_cnf_tmp_file} \
			>> ${SSPETC}/snmp/agt/${PLATFORM_TYPE}.snmpd.cnf
    fi
    rm -f ${snmpd_cnf_tmp_file}


    # Restore netcon session logging via local1, if previously enabled:
    grep '^local1\.' /etc/syslog.conf >/dev/null 2>&1
    if [ $? -ne 0 ] ; then # No local1.* lines present
    	if [ -s "$syslog_tmp_file" ] ; then
		# Restore saved local1.* lines
		local1_lines=`cat $syslog_tmp_file`
		ed /etc/syslog.conf >/dev/null 2>&1 << EOF
			/# SUNWsspr start$/
			/^#local1/
			a
$local1_lines
.
			w
			q
EOF
    	fi
    fi
    rm -f $syslog_tmp_file

    tftpboot_setup
    add_ssp_startup_to_rc_init_directories
    copy_data_files

    # Check and update the edd.emc and edd.erc files if necessary
    update_emc_erc_files 1

    update_ssp_to_domain_hosts

	# Restore the user_file_list to avoid losing data when the new one
	# is installed by SUNWsspdf
	cp $priv/user_file_list.$UPGRADE_TAG $priv/user_file_list
	chown ssp:staff $priv/user_file_list
	chmod 0644 $priv/user_file_list

	# Force the ict and data directories to "ssp staff" ownership.
	# This allows datasync backup/restore to be performed, bug 4344632
	chown -R ssp:staff $SSPVAR/data
 	chown -R ssp:staff $SSPVAR/ict

    # offer to validate the PROM versions
    check_proms
    # cleanup and exit
    rm -f /.SSP_DEFAULTS
    format=$(gettext \
		"\nUpgrade of SSP completed.  See %s for details.\n")
    printf "$format\n" "${log}" | fmt
    print
#   gettext "Run '/etc/init.d/ssp start' to restart SSP software.\n"
#   print
}


#############################################################################
#
# configure_control_boards
#
# Only change the cb_config file
#
#############################################################################
configure_control_boards()
{
    typeset BAD_CF=
    parse_cb_config

    # cb_config file must exist
    if [[ ! -s "${CBCONFIGFILE}" ]]
    then
	printf "$(gettext "Missing %s.")\n" "${CBCONFIGFILE}"
	BAD_CF=1

    elif [[ -z "${PLATFORM_NAME}" ]]
    then
	format=$(gettext "Corrupted %s: Missing platform name.")
	printf "$format\n" "${CBCONFIGFILE}"
	BAD_CF=1

    elif [[ -z "${PLATFORM_TYPE}" ]]
    then
	format=$(gettext "Corrupted %s: Missing platform type.")
	printf "$format\n" "${CBCONFIGFILE}"
	BAD_CF=1
    fi

    # if we don't have a reasonable config, bail out now
    if [[ -n "$BAD_CF" ]]
    then
	gettext "Can not continue. Re-run ssp_config.\n"
	exit 1
    fi

    # bug#4223346: save original primary control board #
    if [ "$P0" = "P" ]
    then
        primary=0
    else
        primary=1
    fi

    get_n_save_cb_config

    # bug#4272751: update the /tftpboot directory, this will ensure any
    # changed CB ip addresses are reset for cbe.ima.
    tftpboot_setup

    # bug#4223346: if control boards were changed, display restart reminder
    if [[ ( (primary -eq 0) && ("$P0" != "P") ) || ( (primary -eq 1) && ("$P1" != "P") ) ]]
    then
         print
         printf "$(gettext "The primary control board has been changed.  The SSP processes")\n"
         printf "$(gettext "must be stopped and restarted.")\n"
         print
         gettext "Use the following command to stop and restart the SSP daemons:\n"
         print
         # DO NOT TRANSLATE -- it is a command line
         print "    # /etc/init.d/ssp [ stop | start ]"
         print
    fi

    check_proms

    exit 0
}

#####################################################
#
# config_float_ip() 
#
#	This function will assign a float IP address to the public network
#	interface of an SSP if it is not assigned. This function should only
#       be executed by the main SSP. The float IP address information is 
#	retrieved from the ${SSPVAR}/.ssp_private/main_ssp_name file.
#       After the float IP address is assigned, it will also update the
#       "ssp_to_domain_hosts" file to replace whatever ssp hostname in that
#	file with the float main ssp hostname associated with the float IP.
#
#	Return:
#		zero		Success
#		non-zero	Failure
#
#####################################################
config_float_ip()
{
	typeset -r ssp_to_domain_file=${SSPVAR}/.ssp_private/ssp_to_domain_hosts
	typeset -r float_ipaddr=$(cat ${SSPVAR}/.ssp_private/main_ssp_name | cut -f2)
	typeset -r float_hname=$(cut -f1 ${SSPVAR}/.ssp_private/main_ssp_name)
	typeset foo=$(egrep -l "^$(uname -n)$" /etc/hostname.*)
	typeset adapt=${foo##*hostname.}
	typeset os_version_major=$(uname -r | cut -d. -f1)
	typeset os_version_minor=$(uname -r | cut -d. -f2)
	integer i
	typeset old_ssp_name
	typeset tmp_file=/var/tmp/config_float_ip.$$
	typeset ret_status

	if [[ -z "${float_ipaddr}" || -z "${foo}" ]] 
	then
		return 1
	fi
	
	ret_status=0

	# 
	# First check if the float_ipaddr is already assigned
	#
	ifconfig -a | egrep " ${float_ipaddr} " >/dev/null 2>&1
	if [[ $? != 0 ]] 
	then
		#
		# float_ipaddr is NOT assigned, do it now.
		#
		if [[ $os_version_major > 5 || $os_version_minor > 7 ]]
		then
			#
			# SunOS 5.8 or beyond
			#
			ifconfig $adapt addif ${float_ipaddr} netmask + broadcast + -trailers up >/dev/null 2>&1
			if [[ $? != 0 ]]
			then 
				ret_status=1 
			fi
		else 
			#	
			# SunOS 5.7 or earlier
			# Find an unused logical interface. 
			#
			let i=1
			while (( i <= 100 ))
			do
				# See if logical interface is being used
				su ssp -fc "ifconfig ${adapt}:${i}" >/dev/null 2>&1
				if [[ $? != 0 ]]
				then
					break
				fi
				i=$((i + 1))
			done
	
			if [[ i == 101 ]]
			then
				# we give up
				ret_status=1
			else 
				ifconfig ${adapt}:${i} ${float_ipaddr} netmask + broadcast + -trailers up >/dev/null 2>&1
				if [[ $? != 0 ]] 
				then
					ret_status=1	
				fi
			fi
		
		fi
	fi

	#
	# We need to update the "ssp_to_domain_hosts" file to change the ssp name
	# to the name that corresponds to the float ip and we only do so if either 
	# the float ip is already assigned or the operation assigning it succeeded. 
	#
	if [[ -f $ssp_to_domain_file && $ret_status == 0 ]]
	then
		old_ssp_name=`cut -d' ' -f2 $ssp_to_domain_file | head -1`
		sed -e "s/ ${old_ssp_name}/ ${float_hname}/g" $ssp_to_domain_file > $tmp_file
		cp $tmp_file $ssp_to_domain_file
		rm -f $tmp_file
	fi

	return $ret_status
}

#############################################################################
#
# configure_main() 
#
# Setup environment so that SSP software can run properly. It should be
# run after ssp_install.  
#
# Note: From SSP3.4 on, this procedure should be run on both SSPs. 
#
#############################################################################
configure_main()
{
	typeset old_main_ssp_name
	typeset old_main_ssp_ip_addr
	typeset prompt

	prompt=$(gettext "Do you wish to configure this system as an SSP for an E10000?")

	if [[ -s "${CBCONFIGFILE}" ]]; then
		parse_cb_config
	fi

	if [[ "$VALID_CONFIG" != true ]]; then
		if [[ ! -s "${MAIN_SSP_NAME_FILE}" ]]; then
			if ! yes_or_no "$prompt"
			then
				exit 2
			fi
		fi
	fi
	#
	# If main SSP IP info is invalid then query the user for this info.  To
	# force the setting of main SSP IP info use the "float" argument.
	#
	if [[ -s "${MAIN_SSP_NAME_FILE}" ]]; then
		read_main_ssp_ip_info old_main_ssp_name old_main_ssp_ip_addr
		if [[ $? -ne 0 ]]; then
			set_main_ssp_ip_info
		fi
	else
		set_main_ssp_ip_info
	fi

	# we only ask for configuration if we don't have one.  if you want to
	# change the configuration anyway, use the "cb" argument.
	if [[ "$VALID_CONFIG" != true ]]
	then
		# no valid configuration, gotta ask for one
		get_n_save_cb_config

		# create the platform-specific data link
		create_platform_link

		# install platform config file, we only do this on a first run
		make_platform_config "${PLATFORM_NAME}"
	fi

	tftpboot_setup
	copy_data_files
	add_ssp_startup_to_rc_init_directories

	# cleanup and exit
	rm -f /.SSP_DEFAULTS
	gettext "\nSSP configuration completed.\n"
	print
}

#############################################################################
#
# 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 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.")" $0)"
    fi
}

#############################################################################
#
# validate_backup_args
#
# Validate that the argument to ssp_backup is a valid directory
#
#############################################################################
validate_backup_args()
{
    typeset filename_cpio=ssp_backup.cpio

    ssp_backup_filename=${1}

    if [[ -d $1 ]]
    then
	# form backup filename: <specified directory>/ssp_backup.cpio
	ssp_backup_filename=$1/${filename_cpio}
    else
	# Not directory, check if tape
	mt -f $1 status >/dev/null 2>&1
	if [[ $? -ne 0 ]]
	then
	    printf "$(gettext 'Invalid backup target specified.\nBackup file will be: /var/tmp/%s.\n')" "${filename_cpio}"
	    print
	    ssp_backup_filename=/var/tmp/${filename_cpio}
	fi
    fi
}

#############################################################################
#
# validate_restore_args
#
# Validate that the argument to ssp_restore is a valid filename
#
#############################################################################
validate_restore_args()
{
    ssp_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 "$(gettext "Invalid restore source specified\n.")"
	    print
	fi
    fi
}

#############################################################################
#
# perform_backup
#
# Generate a file list to send to cpio, which archives the files into
# the specified directory as filename ssp_backup.cpio or to the magnetic
# tape device.
#
#############################################################################
perform_backup()
{
    typeset SSPHOME=/export/home/ssp

    #
    # Set up the log file
    #
    log=${SSPVAR}/ssp_backup.out

    print "SSP files backup" > ${log}
    date >> ${log}
    print >> ${log}

	#
	# RFE 4344560 - insure the autoconfig and ict databases are owned by 
	# ssp:staff
	#
	chown -hR ssp:staff ${SSPVAR}/data
	chown -hR ssp:staff ${SSPVAR}/ict

   find ${SSPHOME}/.ssp_env \
	${SSPHOME}/.Xdefaults \
	${SSPHOME}/.cshrc \
	${SSPHOME}/.dtprofile \
	${SSPHOME}/.login \
	${SSPHOME}/.openwin-init \
	${SSPHOME}/.openwin-menu \
	${SSPHOME}/.openwin-menu-ssp \
	${SSPHOME}/.postrc \
	${SSPHOME}/.redxrc \
	${SSPHOME}/.xinitrc \
	${SSPHOME}/.dt/dtwmrc \
	${SSPHOME}/.dt/user.dtwmrc \
	${SSPVAR}/.ssp_private \
	${SSPVAR}/adm \
	${SSPVAR}/data \
	${SSPVAR}/etc \
	${SSPVAR}/ict \
	/tftpboot \
	-print 2>> ${log} | cpio -ocv > ${ssp_backup_filename} 2>> ${log}
}


###########################################################################
#
# ssp_install
#
# Individually perform pkgadd. The advantage of doing it one at a time
# is that we could install even if a package on the list is missing.
# argument contains a list of packages to add.
#
###########################################################################
ssp_install()
{
    typeset package_dir=${1}

    if [[ -z "$package_dir" ]]
    then
	usage
	exit 4
    fi

    if [[ ! -d "$package_dir" ]]
    then
	format=$(gettext "%s is an invalid directory path.")
	printf "$format\n" "${package_dir}"
	exit 4
    fi

    # select a log file
    if [[ -d /var/sadm/system/logs ]]
    then
	log=/var/sadm/system/logs/ssp_install_log
    else
	log=/var/tmp/ssp_install_log
    fi
    # clear log file
    pkg_err=0
    > ${log}
    print "SSP software install" >> ${log}
    date >> ${log}
    print >> ${log}

    # Set up pkgadd admin file
    adminfile=/tmp/ssp_install_adminfile.$$
    cat > ${adminfile} << EOF
mail=
instance=overwrite
partial=nocheck
runlevel=nocheck
idepend=nocheck
rdepend=nocheck
space=quit
setuid=nocheck
conflict=nocheck
action=nocheck
basedir=default
EOF

    # Now add the new packages
    ssp_pkgadd \
	SUNWsspue SUNWsspop SUNWsspmn SUNWsspdf \
	SUNWsspst SUNWsspr SUNWsspdo SUNWsspob \
	SUNWssppo SUNWsspid SUNWsspdr

    # Verify packages are installed
    ssp_pkgverify \
	SUNWsspue SUNWsspop SUNWsspmn SUNWsspdf \
	SUNWsspst SUNWsspr SUNWsspdo SUNWsspob \
	SUNWssppo SUNWsspid SUNWsspdr


    # Install Flash PROM package. It needs to be interactive.
    ssp_pkgadd_fp

    if [[ $pkg_err -eq 1 ]]
    then
	format=$(gettext "Error detected. See %s for details.")
	printf "$format\n" "${log}"
	exit 2
    fi

    gettext "\nNOTE: Please set a new password for the ssp user account.\n"

    format=$(gettext \
		"\nInstallation SSP completed.  See %s for details.\n")
    printf "$format\n" "${log}" | fmt
}


#############################################################################
#
# convert_domain_os_field
#
# Converts the OS version in the domain_config and domain_history files to
# reflect the format used in the SSP release.
#
# SSP 3.1 os versions are 2.5.1, 2.6, 2.7 etc while
# SSP 3.1.1 and later are 5.5.1, 5.6, 5.7 etc
#
# Parameters:
# $1 = restored_domain_file (config or history)
# $2 = post_31_release (1 if ssp3.1.1 or 3.2, 0 otherwise)
# $3 = major (x in x.y.z)
# $4 = minor (y in x.y.z)
# $5 = patch (z in x.y.z)
#
# Called by perform_restore for ssp_restore.
#
#############################################################################
convert_domain_os_field()
{
    typeset restored_domain_file=${1}
    typeset converted_file=${restored_domain_file}.converted$$
    typeset domain
    typeset platform
    typeset physical
    typeset release
    typeset idn
    typeset boardlist
    typeset -i post_31_release=${2}
    typeset major=${3}
    typeset minor=${4}
    typeset patch=${5}

    if [[ ! -f "${restored_domain_file}" ]]
    then
	# no domain config/history file, do nothing
	return
    fi

    # Empty the file to hold the converted lines
    > ${converted_file}

    while IFS=: read domain platform physical release idn boardlist
    do
	if [[ ${post_31_release} -eq 1 ]]
	then
	    # Switch from Solaris to SunOS numbering
	    if [[ "${release}" == 2.* ]]
	    then
	        release=5.${release#2.}
	    fi
	else
	    # Switch from SunOS to Solaris numbering
	    if [[ "${release}" == 5.* ]]
	    then
	        release=2.${release#5.}
	    fi
	fi
	if (( ($major > 3) || ( ($major == 3) && ($minor > 0) ) ))
	then
	    print "${domain}:${platform}:${physical}:${release}:${idn}:${boardlist}">> ${converted_file}
	else
	    print "${domain}:${platform}:${physical}:${release}:${boardlist}" >> ${converted_file}
	fi
    done < "${restored_domain_file}"

    if cmp -s "${restored_domain_file}" "${converted_file}"
    then
	# Files are the same, no release number changes
	rm -f ${converted_file}
	return
    fi

    cp ${converted_file} ${restored_domain_file}
    # the cp changes the group name to other
    chown ssp:staff ${restored_domain_file}
    rm -f ${converted_file}
}


#############################################################################
#
# convert_MAXcontrolvccfan
#
# Converts the Ultra-Enterprise-10000.MAXcontrolvccfan field
# in $SSPVAR/.ssp_private/ssp_resource from 5.35V (5350) to 5.5V. I.e.,
#	Ultra-Enterprise-10000.MAXcontrolvccfan:5500
#
# NO change is made if the reading isn't the old reading of 5.35V.
# 
# SSP 3.2 and earlier uses 5.35V.
# SSP 3.3 and later   uses 5.5V.
#
# Parameters:
# $1 = restored_ssp_resource_file (config or history)
#
# Called by perform_restore for ssp_restore.
#
#############################################################################
convert_MAXcontrolvccfan()
{
    typeset restored_ssp_resource_file=${1}
    typeset converted_file=${restored_ssp_resource_file}.converted$$
    typeset prefix='Ultra-Enterprise-10000.MAXcontrolvccfan'

    if [[ ! -f "${restored_ssp_resource_file}" ]]
    then
	# No ssp_resource file--do nothing
	return
    fi

    if (( $(grep "^${prefix}:5350$" \
		${restored_ssp_resource_file} | wc -l) < 1 ))
    then
	# No 5.35V line for MAXcontrolvccfan--do nothing
	return
    fi

    # Convert the file
    sed "s/^${prefix}:5350$/${prefix}:5500/" \
		${restored_ssp_resource_file} >${converted_file}
   
    cp -f ${converted_file} ${restored_ssp_resource_file}
    # command cp changes the group name to "other":
    chown ssp:staff ${restored_ssp_resource_file}
    rm -f ${converted_file}
}


#############################################################################
#
# convert_MaxHeartBeats
#
# Converts the Ultra-Enterprise-10000.MaxHeartBeats field
# in $SSPVAR/.ssp_private/ssp_resource from 4 or 10 to 11.  I.e.,
#	Ultra-Enterprise-10000.MaxHeartBeats:11
#
# NO change is made if the reading isn't the old value of 4 or 10.
# SSP 3.2 and earlier (without the patch for 4291084) uses 4.
# SSP 3.3 uses 10.
# SSP 3.4 uses 11.
# Bugid 4291084, RFE 4306874.
#
# Called by perform_restore() for ssp_restore.
#
# Parameters:
# $1 = restored_ssp_resource_file (config or history)
#
#
#############################################################################
convert_MaxHeartBeats()
{
    typeset restored_ssp_resource_file=${1}
    typeset converted_file=${restored_ssp_resource_file}.converted$$
    typeset prefix='Ultra-Enterprise-10000.MaxHeartBeats'
    typeset newMaxHB=11

    if [[ ! -f "${restored_ssp_resource_file}" ]]
    then
	# No ssp_resource file--do nothing
	return
    fi

    for oldMaxHB in 4 10
    do
	if (( $(grep "^${prefix}:${oldMaxHB}$" \
			${restored_ssp_resource_file} | wc -l) >= 1 ))
	then
		# Convert the file
		sed "s/^${prefix}:${oldMaxHB}$/${prefix}:${newMaxHB}/" \
			${restored_ssp_resource_file} >${converted_file}
  	 
		cp -f ${converted_file} ${restored_ssp_resource_file}
		# command cp changes the group name to "other":
		chown ssp:staff ${restored_ssp_resource_file}
		rm -f ${converted_file}
	fi
    done
}

###########################################################################
#
# update_fad_files
#
# Insure fad_files is consistent with SSP 3.4 Failover needs
# Add a new SSP 3.4 entry, if missing, for actionreboot.lock in
# $SSPVAR/.ssp_private/fad_files.
# This is required for restoring from SSP 3.3 and before to SSP 3.4 and
# after.
#
# Called by perform_restore() for ssp_restore.
#
#
###########################################################################
update_fad_files()
{
#
# Some locals we use
#
	typeset restored_fad_files=${SSPVAR}/.ssp_private/fad_files
	typeset converted_fad_files=${restored_fad_files}.converted$$

	if [[ ! -f "${restored_fad_files}" ]]
	then
	# No fad_files file--do nothing
	return
	fi

	cp ${FADCONFIGFILE} ${FADCONFIGFILE}.$UPGRADE_TAG
	#
	# Remove failover.d.config file, not used
	#
	sed '/failover/d' ${FADCONFIGFILE}.$UPGRADE_TAG > ${FADCONFIGFILE}_temp
	#
	# Change cb_config file permissions to read-write
	sed '/cb_config/s/	r	/	rw	/' ${FADCONFIGFILE}_temp > ${FADCONFIGFILE}
	#
	rm ${FADCONFIGFILE}_temp
	#
	# Search for actionreboot.lock entry
	# append if not there
	#
	if (( $(grep "actionreboot.lock" \
		${FADCONFIGFILE} | wc -l) == 0 ))
	then
		echo 'nondomain\tr\tSSPVAR\t.ssp_private\tactionreboot.lock' \
		>>${FADCONFIGFILE}
	fi
	#
	# Search for user_file_list entry
	# append if not there
	#
	if (( $(grep "user_file_list" \
		${FADCONFIGFILE} | wc -l) == 0 ))
	then
		# append to fad_files
		echo 'nondomain\trw\tSSPVAR\t.ssp_private\tuser_file_list' \
		>> ${FADCONFIGFILE}
	fi
	# command cp changes the group name to "other":
	chown ssp:staff ${FADCONFIGFILE}
}

#############################################################################
#
# perform_restore
#
# Restore a backup done using ssp_backup.
#
# Update files for the current release of SSP, if required.
# This is because ssp_backup may have been ran for a previous release of SSP.
#
# Implements command ssp_restore.
#
#############################################################################
perform_restore()
{
    typeset restored_domain_config=${SSPVAR}/.ssp_private/domain_config
    typeset restored_domain_history=${SSPVAR}/.ssp_private/domain_history
    typeset -i post_31_release
	typeset same_release=0

    #
    # Set up the log file
    #
    log=${SSPVAR}/ssp_restore.out

    print "SSP files restore" > ${log}
    date >> ${log}
    print >> ${log}

    # Backup volatile and fad files
    save_a_copy \
	/export/home/ssp/.Xdefaults \
	/export/home/ssp/.cshrc \
	/export/home/ssp/.dtprofile \
	/export/home/ssp/.login \
	/export/home/ssp/.openwin-init \
	/export/home/ssp/.openwin-menu \
	/export/home/ssp/.openwin-menu-ssp \
	/export/home/ssp/.postrc \
	/export/home/ssp/.redxrc \
	/export/home/ssp/.ssp_env \
	/export/home/ssp/.xinitrc \
	/export/home/ssp/.dt/dtwmrc \
	/export/home/ssp/.dt/user.dtwmrc \
	$FADCONFIGFILE

	#
	# extract SSP Release file from backup file
	#
	mv ${SSPVAR}/.ssp_private/ssp_release \
		${SSPVAR}/.ssp_private/ssp_release.orig
	cpio -i ${SSPVAR}/.ssp_private/ssp_release < ${ssp_restore_filename} \
		>> ${log}
	if [[ -f ${SSPVAR}/.ssp_private/ssp_release ]]
	then
		# check if release is the same
		/usr/bin/cmp -s ${SSPVAR}/.ssp_private/ssp_release \
			${SSPVAR}/.ssp_private/ssp_release.orig
                typeset status=$?
		if [[ ${status} -eq 0 ]]
		then
			same_release=1
		fi
	fi


	#
	# restore the cpio file based upon whether or not it is the
	# same release. If different releases, exclude the data & ict
	# hardware configuration databases
	# rfe 4346970
	#
	if [[ ${same_release} -eq 1 ]]
	then
		cpio -icvdum < ${ssp_restore_filename} >>${log}
	else
		cpio -icvdumf "/var/opt/SUNWssp/data*" \
				  "/var/opt/SUNWssp/ict*" \
			< ${ssp_restore_filename} >>${log}
	fi
	mv ${SSPVAR}/.ssp_private/ssp_release.orig \
		${SSPVAR}/.ssp_private/ssp_release

    # Restore the fad file
    restore_a_copy $FADCONFIGFILE

    # Remove /etc/opt/SUNWssp/snmp/*.idy and let it be rebuilt by scotty
    rm -f ${SSPETC}/snmp/*.idy

    #
    # Check what version of SSP we are restoring into
    # Get $major.$minor.$patch:
    # The release categories are post-SSP 3.1 and post-SSP 3.2
    #
    ssp_version

    post_31_release=1
    post_32_release=1
    if [[ ${major} -lt 3 ]]
    then	# Ancient (SSP 2.0 or earlier)
	post_31_release=0
	post_32_release=0
    elif [[ ${major} -eq 3 ]]
    then
	if [[ ${minor} -eq 0 ]]
	then	# SSP 3.0
		post_31_release=0
		post_32_release=0
    	elif [[ ${minor} -eq 1 ]]
	then
		if [[ ${patch} -eq 0 ]]
    		then	# SSP 3.1
			post_31_release=0
			post_32_release=0
		else 	# SSP 3.1.1
			post_31_release=1
			post_32_release=0
		fi
    	elif [[ ${minor} -eq 2 ]]
    	then	# SSP 3.2
		post_31_release=1
		post_32_release=0
	fi
    fi

    #
    # Perform update actions based on the current SSP release.
    #

    # Check and update the edd.emc and edd.erc files if necessary
    update_emc_erc_files ${post_31_release}

    convert_domain_os_field ${restored_domain_config} ${post_31_release} \
		${major} ${minor} ${patch}
    convert_domain_os_field ${restored_domain_history} ${post_31_release} \
		${major} ${minor} ${patch}
    update_fad_files

    if [[ ${post_32_release} -eq 1 ]]
    then	# SSP 3.2 or earlier requires a ssp_resource change 
	convert_MAXcontrolvccfan ${SSPVAR}/.ssp_private/ssp_resource
	convert_MaxHeartBeats ${SSPVAR}/.ssp_private/ssp_resource
    fi

	# Update the fad_files to reflect support SSP Failover (SSP 3.4+)
	update_fad_files

    update_ssp_to_domain_hosts

	# Force the ict and data directories to "ssp staff" ownership.
	# This allows datasync backup/restore to be performed, rfe 4344560
	chown -hR ssp:staff $SSPVAR/data
 	chown -hR ssp:staff $SSPVAR/ict

	if [[ ${same_release} -eq 0 ]]
	then
		print ""
		print "WARNING: Backup release and current release are different."
		print "$SSPVAR/data and $SSPVAR/ict directories were not restored."
		print "You may need to run autoconfig." 
	fi
}


#############################################################################
#
# perform_post_os_upgrade
#
# Sets up necessary files and links to work with
# Solstice Enterprise Agent (SEA or snmpdx).
#
#############################################################################
perform_post_os_upgrade()
{
    #
    # Set up the log file
    #
    log=${SSPVAR}/ssp_post_os_upgrade.out

    print "SSP software post_os_upgrade" > ${log}
    date >> ${log}
    print >> ${log}

    # No need to add the ssp SEA entries to /etc/inet/services
    # --already done when the SUNWsspr package is installed.
    #
    # Create symbolic links for Starfire's Solstice (SEA) configuration files
    #
    pkginfo -q SUNWsacom
    if [ $? -eq 0 ]
    then
	if [[ ! -h ${BASEDIR}/etc/snmp/conf/ssp_snmp.reg ]]
	then
            ln -s ${BASEDIR}/etc/opt/SUNWssp/snmp/sea/ssp_snmp.reg \
		${BASEDIR}/etc/snmp/conf/ssp_snmp.reg
	fi

	if [[ ! -h ${BASEDIR}/etc/snmp/conf/ssp_snmp.rsrc ]]
	then
            ln -s ${BASEDIR}/etc/opt/SUNWssp/snmp/sea/ssp_snmp.rsrc \
		${BASEDIR}/etc/snmp/conf/ssp_snmp.rsrc
	fi

	if [[ ! -h ${BASEDIR}/var/snmp/mib/ssp_snmp.mib ]]
	then
            ln -s ${BASEDIR}/etc/opt/SUNWssp/snmp/${PLATFORM_TYPE}.mib \
		${BASEDIR}/var/snmp/mib/ssp_snmp.mib
	fi
    fi
}


#############################################################################
##
## MAIN CODE STARTS HERE
##
#############################################################################

integer exit_status=0

umask 033

if [[ -f ${ENV} ]]
then
    . ${ENV}
fi


#
# Set up the log file
#
log=${SSPVAR}/ssp_config.out

#
# Rotate the log files, we keep up to ${log}.6 around (actually 7 backups)
#
rotate_file ${log} 6

#
# Guess a subcommand based upon $0
#
subcommand=main

case "$(basename $0)" in
ssp_terminate*)
    subcommand=terminate
    ;;

ssp_configmain*)
    subcommand=main
    ;;

ssp_config?(.*))
    subcommand=main
    if (( $# >= 1 ))
    then
        subcommand=$1
        shift
    fi
    ;;

ssp_upgrade*)
    subcommand=upgrade
    ;;

ssp_install*)
    subcommand=install
    ;;

ssp_backup*)
    subcommand=backup
    ;;

ssp_restore*)
    subcommand=restore
    ;;

ssp_post_os_upgrade*)
    subcommand=post_os_upgrade
    ;;
esac


#
# Check the options
#
case "$subcommand" in

enable_tftp)
    require_args 0 $#
    require_root
    parse_cb_config
    tftpboot_setup
    ;;

disable_tftp)
    require_args 0 $#
    require_root
    tftpboot_disable
    ;;

config_floatip)
    require_args 0 $#
    require_root
    config_float_ip
    ;;

deconfig_floatip)
    require_args 0 $#
    require_root
    deconfig_float_ip
    ;;

cb)
    require_args 0 $#
    require_root
    gettext "Configuring control boards\n"
    configure_control_boards "$@" 2>&1 | tee ${log}
    ;;

float)
    require_args 0 $#
    require_root
    gettext "Configuring floating IP address of main SSP\n"
    # Query user for the name of the floating main SSP and save in file
    set_main_ssp_ip_info 2>&1 | tee ${log}
    ;;

cpu)
    require_args 0 $#
    require_root
    gettext "Configuring processors\n"
    configure_processors "$@" 2>&1 | tee ${log}
    ;;

terminate)
    ssp_terminate "$@"
    ;;

sysidssp)
    require_args 0 $#
    require_root
    configure_main "$@" 2>&1 | tee ${log}
    ;;

main)
    require_args 0 $#
    require_root
    configure_main "$@" 2>&1 | tee ${log}

    # we also should probably start the stuff up
    if (( $(/usr/bin/ps -ef | grep ssp_startup | grep -v grep | wc -l) < 1 ))
    then
        /etc/init.d/ssp start
    fi
    ;;

upgrade)
    require_args 1 $#
    require_root
    ssp_upgrade "$@"
    ;;

prom)
    require_args 0 $#
    require_root
    parse_cb_config
    check_proms
    ;;

install*)
    require_args 1 $#
    require_root
    ssp_install "$@"
    ;;

backup*)
    require_args 1 $#
    require_root
    validate_backup_args "$@"
    perform_backup
    exit 0
    ;;

restore*)
    require_args 1 $#
    require_root
    validate_restore_args "$@"
    perform_restore
    exit 0
    ;;

post_os_upgrade*)
    require_args 0 $#
    require_root
    perform_post_os_upgrade
    ;;

*)
    usage
    exit 4
    ;;
esac

exit ${exit_status}
