#!/sbin/sh
# 
# *****************************************************************
# *                                                               *
# *    Copyright Compaq Computer Corporation, 2001                *
# *                                                               *
# *   The software contained on this media  is  proprietary  to   *
# *   and  embodies  the  confidential  technology  of  Compaq    *
# *   Computer Corporation.  Possession, use,  duplication  or    *
# *   dissemination of the software and media is authorized only  *
# *   pursuant to a valid written license from Compaq Computer    *
# *   Corporation.                                                *
# *                                                               *
# *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
# *   by the U.S. Government is subject to restrictions  as  set  *
# *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
# *   or  in  FAR 52.227-19, as applicable.                       *
# *                                                               *
# *****************************************************************
#
# HISTORY
# 
#	setld.sh
#		manage software subset distributions
#
#	setld [-D path] -c subset message		(configure)
#	setld [-D path] -d subset [subset...]		(delete)
#	setld [-D path] -h				(help)
#	setld [-D path] -i [subset...]			(inspect)
#	setld [-D path] -l location			(load)
#	setld [-D path] -v [subset...]			(validate)
#	setld [-D path] -x location			(extract)
#
# @(#)$RCSfile: setld.sh,v $ $Revision: 4.3.134.5 $ (DEC) $Date: 2001/04/04 21:04:45 $
#
#	000	ccb	12-mar-1987
#		Digital Equipment Corporation
#	Many thanks to robin, rnf, and afd
#	new version for 2.2
#
#	001	ccb	02-mar-1988
#		Set UMASK to 22 so that ris can read the images.
#
#	002	06-APR-1988	ccb
#		Fix DEVICE parsing bug.
#
#	003	18-feb-1989	ccb
#		Port to sh5
#		add update (-u) support
#
#	004	07-mar-1989	ccb
#		Add support for new style ris servers.
#
#	005	12-jun-1989	ccb
#		Fix extraneous scp on failed subset problem,
#		clean up entry to -l when subsets specified on command line,
#		clean up exit returns, fix 'D is read-only' problem in trap
#		for keyboard interrupts.
#
#	006	17-jul-1990	ccb
#		Fix problem finding unique client names in risdb.
#
#	007	05-nov-1990	ech
#		Fix path used by setld to exclude current directory,
#		add subset description in the dependency-check error message,
#		change format of messages givien when subset is loaded,
#		change return value such that setld will exit if underlying
#		scp performs an exit 1.
#	   
#	008	16-nov-1990	ech
#		Fix problem in setld -i when .ctrl is empty by resetting 
#		all control variables in ReadCtrlFile(), also mark subset as 
#		incomplete if .ctrl is incomplete.
#		Fix leftover /hosts problem.
#
#	009	17-dec-1990	ech
#		call fverify -yp in Verify(), fix path of .inv fed to tclear 
#		in LoadFromMedia().
#
#       010     29-jan-1991     ech
#               add current directory back to the end of setld PATH.
#               restore /etc/hosts every time LoadFromInet is called.
#
#	011     19-feb-1991     ech
#		clean up usage (no -a, -u, -v w/o specifying subsets).
#		move "Deleting (subset)" to before C_DELETE is called.
#		bug fix in RunScps (no C_INSTALL if POST_L fails).
#
#	012	04-mar-1991	ccb
#		removed reusable code to be placed in SHELL_LIB
#		removed v4.0 setld -u code
#		recoded uses of Add and Subtract calls to use expr(1),
#			the version of expr(1) on OSF/1 correctly handles
#			unary minus.
#
#       013     12-mar-1991     ech
#               add reg expr when 'egrep' ROOT in .image file in Extract().
#               check if RIS server echoes 'hello' in InitDevice().
#
#       014     03-apr-1991     ech
#               take out fverify -yp in Verify().
#
#       014     05-apr-1991     ech
#               bug fix, pass Ferror() the return status of the routine where
#               fatal error occurred.
#
#	015	23-apr-1991 	ech
#		added support for "it" by creating ordered subset list 
#		for C_INSTALL in $_R/sbin/it.d/data/cinst.data.
#
#	016	10-may-1991 	ech
#		added -f (force load) flag to bypass dependency checking.
#		added menu caching.
#
#	017	30-may-1991	ccb
#		add *Proto() and *Config() routines.
#		integrate with TIN isl
#		move usr/opt/data to usr/.smdb.
#		create syslog directory before attempting to open the
#			log file
#		correct sequencing of scp calls for Delete()
#
#	018	21-jun-91	ccb
#		added Basename() and Dirname() replacing calls to the
#		corresponding 'C' programs - done to avoid the overhead
#		of more staically linked binaries
#		fixed an error calling CopyConfig() from Configure()
#		use full path when creating directory for logfiles
#		fix bugs in CopyProto() and CopyConfig()
#
#	019	02-jul-1991	ccb
#		move logging from /var/adm/syslog to /var/adm/smlogs
#
#	020	24-jul-1991	ccb
#		change variable D to _D in DeleteConfig() and DeleteProto()
#
#	021	27-sep-1991	ech
#		no longer direct error message from fitset to /dev/null
#		modify MASK from "OSF" to "^OSF"
#
#	022 	15-oct-1991	ech
#		use "cp -p" in CopyConfig and CopyProto
#		change menu option "None of the Above" to "Mandatory subsets 
#		only", add example in menu prompt, list subsets in basic inst.
#

# QAR29496 - fys
SVR4PATH=${SVR4PATH:=${sp:=/usr/opt/svr4}}

SHELL_LIB=${SHELL_LIB:-/usr/share/lib/shell}
SHELL_LIB2=${SHELL_LIB2:-/usr/share/lib/shell}

# define CAT_MIDFMT
# CAT_MIDFMT="%D\n"
# export CAT_MIDFMT

#
# Load the libinstall library first so that the 
# INST_LoadShellLibrary routine can be used to load all of 
# the other libraries.
#
if [ -f $SHELL_LIB/libinstall ]
then
	. $SHELL_LIB/libinstall
elif [ -f $SHELL_LIB2/libinstall ]
then
	. $SHELL_LIB2/libinstall
else
	2>&1 echo "
Unable to locate the shell library (libinstall) in any of the
following locations:

	$SHELL_LIB/libinstall
	$SHELL_LIB2/libinstall"
	exit 1
fi

#
# Load the necessary shell libraries
#
for LIBRARY in \
	Dialog \
	libswdb \
	Lists \
	Logging \
	Ready \
	Strings \
	Ticker \
	Wait \
; do
	INST_LoadShellLibrary $LIBRARY || exit 1
done

if [ -f /var/adm/dms/bin/libmrg ]; then
	#
	# Force load of the dms version of libmrg
	#
	unset LIBMRG
	. /var/adm/dms/bin/libmrg
else
	[ "$LIBMRG" ] || . $SHELL_LIB/libmrg
fi


#%	DECLARATIONS
#%	SUBROUTINES
#		all subroutines used in setld are defined in alphabetical
#		order here.


:	-AddToRismap
#	given:
#		$1 - name of directory where the .ctrl files are
#		$2 - name of the ris product directory, e.g. "product_1"
#	does:
#	return:
#		Nothing.
#
AddToRismap()
{ (
	cd $1
	find . -name '*.ctrl' \
		| sed -e 's/\.ctrl//g' \
			-e 's@.*/@@g' \
		| fmt -65 \
		| sed "s/^/$2 /" \
		>> $RISMAP
) }


:	-AllSubsetsMustRoll
#		Test if any subset does not belong to a product that
#		must be rolled during a cluster upgrade.
#
#	given:	$* - zero or more subset names
#	does:	check for subsets not from the list of products that
#		have to be rolled.  Note the special case handling
#		for OSFPAT000000* -- any patch tools subset.  These
#		subsets are not required to be rolled, because the
#		patch tools are needed to enable the roll to happen.
#	return:	0 if all named subsets are from products that must roll.
#		1 if any subset is not from a product that must roll.
#	effect:	Sets ROLL_NOT_REQUIRED to the list of subsets that are
#		not from products that must roll.
#
AllSubsetsMustRoll()
{
	ROLL_NOT_REQUIRED=`echo $* \
		| fmt -1 \
		| sed 's/^OSFPAT000000/@@@PAT000000/' \
		| grep -Ev '^('"$MUST_ROLL_GREP_EXP"')' \
		| sed 's/@@@/OSF/'`

	[ "$ROLL_NOT_REQUIRED" ] &&
		return 1
	return 0
}


:	-AnySubsetMustRoll
#		Test if any subset belongs to a product that must
#		be rolled during a cluster upgrade.
#
#	given:	$* - zero or more subset names
#	does:	check for subsets from the list of products that
#		have to be rolled.  Note the special case handling
#		for OSFPAT000000* -- any patch tools subset.  These
#		subsets are not required to be rolled, because the
#		patch tools are needed to enable the roll to happen.
#	return:	0 if any subset is from a product that must roll.
#		1 if all named subsets are from other layered products,
#		which may or may not support roll (or are OSF patch
#		tool subsets).
#	effect:	Sets MUST_ROLL to the list of subsets that are
#		from products that must roll.
#
AnySubsetMustRoll()
{
	MUST_ROLL=`echo $* \
		| fmt -1 \
		| grep -E '^('"$MUST_ROLL_GREP_EXP"')' \
		| grep -v '^OSFPAT000000'`

	[ "$MUST_ROLL" ] &&
		return 0
	return 1
}


:	-Args
#		break up the command args
#
#	given:	the command line
#	does:	break the command line up
#	return:	nothing
#	effect:	$ACT - sets to act value
#		$DEFPATH - set to 0 if root specified, else 1
#		$DEVICE - set to device name for -alux
#		$_R - set to / or new rootpath if specified
#		$ARGV - set to remaining arguments

Args()
{
	IGNORE=0	# ignore current option
	OPT=		# current option value

	# parsing the command line:
	[ $# = 0 ] &&
	{
		# no arguments
		Usage
		return 1
	}

	case "$1" in
	-*)	;;
	*)	# assume old-style optional path prepend -D option switch
		set xx -D $*; shift
	esac


	# QAR29496 - fys
	if [ -x $SVR4PATH/usr/bin/pkginfo ]
	then
		set xx `getopt "cCD:PdfhiIl:m:p:S:s:x:uvZ" $*`; shift 
	else
		set xx `getopt "cCD:dfhiIl:m:p:S:s:x:uvZ" $*`; shift 
	fi
 
	[ $# = 0 ] &&
	{
		Usage
		return 1
	}

	ACT=
	_R=/
	DEFPATH=1
	FORCE_FLAG=	# flag to force operations

	for OPT in $*
	{
		[ "$IGNORE" = 1 ] &&
		{
			# skip already used option
			IGNORE=0
			continue
		}
		#! checks may be desired to guarantee that only one
		#!  action option has been specified
		case "$OPT" in
		-[lpsSx])
			CMDSW=$OPT
			DEVICE=$2
			IGNORE=1	# ignore OPT value on next iteration
			shift 2
			;;

		-[cCdhiIvPuZ])
			CMDSW=$OPT
			shift
			;;
		-[f])
			FORCE_FLAG=yes
			shift
			[ $# = 0 ] &&
			{
				Usage
				return 1
			}
			;;
		-[m])
			MEMBER_ID=$2
			IGNORE=1	# ignore OPT value on next iteration
			shift 2
			[ $# = 0 ] &&
			{
				Usage
				return 1
			}
			;;

		-D)	DEFPATH=0
			_R=$2
			IGNORE=1	# ignore OPT value on next iteration
			shift 2

			# verify that the target directory exists
			[ -d $_R ] ||
			{
				Error "`printf \"$ENOENT\" $_R`"
				Usage
				return 1
			}
			case "$_R" in
			/*)	;;
			*)	_R=`(cd $_R;/bin/pwd)`
			esac
			;;

		--)	# end of options
			shift
			break
			;;

		*)	# bad switches
			DEFMSG="Unreached in Args()"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				ARGS_BAD_SWITCH \
				\"$DEFMSG\"`"
 			return 1
		esac
	}

	CMDSW=`Parse - $CMDSW`
	#(Log "root=$_R -$CMDSW")	# subshell to protect command args
	DEFMSG="root=%1\$s -%2\$s"
	(Log "`message -E -S -V 200 -F installsetld \
		setld.cat -s SETLD3 \
		ROOT_CMDSW_LOG \
		\"$DEFMSG\" \"$_R\" \"$CMDSW\"`")

	ACT=`Ucase $CMDSW`
	case "$WHOAMI,$CMDSW" in
	*,)	# no action switch specified
		Usage
		return 1
		;;
	0,[cCdflmpsvxZ])
		;;
	*,[cCdflmpsvxZ])
		DEFMSG="-%s can be used by super-user only."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			ARGS_ROOT_ONLY \
			\"$DEFMSG\" \"$CMDSW\"`"
		return 1
	esac


	ARGV=$*
	return 0
}

AvailSubInfo()
{
	for _S in $SBS
	{
		#  Will fail if subset does not want to appear on the menu.
		ACT=M $_TDIR/$_S.scp -$CMDSW || continue

		STATUS=

		SWDB_IsInstalled $_S && STATUS="installed"
		SWDB_IsCorrupt $_S && STATUS="corrupt" # ica-12459

		ReadCtrlFile $_TDIR $_S 2> /dev/null ||
		{
			# if .ctrl is incomplete, subset is incomplete
			STATUS="incomplete"
			SDESC=`echo $DESC | sed 's/%.*//'`
		}


		[ "$DEPS" = . ] && DEPS=

		# bit 2 on flags means subset is optional
		case `FlagsAttrCheck SATTR_OPTION $FLAGS` in
		1)      STYPE="optional"
			;;
		*)      STYPE="mandatory"
		esac

		CATAG=`echo $DESC | sed 's/.*%//'`

		echo "{$_S} {$SDESC} {$CATAG} {$DEPS} {$ROOTSIZE} {$USRSIZE} {$VARSIZE} {$STYPE} {$STATUS}" >> $SINFO_WORK
	}

}

:	-AvailSubPostInfo
#	Listing of available products subsets for SUITGUI in a 'tcl like' list
#	
#	given: nothing
#	does: generates a list of all available subsets on the source media
#	returns: nothing
#
AvailSubPostInfo()
{

	rm -rf $SUIT_INFO_MAND
	rm -rf $SUIT_INFO_OPT
	
	for _S in $SBS
	{

		#  Will fail if subset does not want to appear on the menu.
		ACT=M $_TDIR/$_S.scp -$CMDSW || continue

		#
		# We need to check if the subset is installed and if it is 
		# we don't include that subset in this list
		#
		SWDB_IsInstalled $_S &&
		{
			continue
		}

		ReadCtrlFile $_TDIR $_S 2> /dev/null ||
		{
			# if .ctrl is incomplete, subset is incomplete
			STATUS="incomplete"
			SDESC=`echo $DESC | sed 's/%.*//'`
		}

		[ "$DEPS" = . ] && DEPS=

		# bit 2 on flags means subset is optional
		case `FlagsAttrCheck SATTR_OPTION $FLAGS` in
		1)      STYPE="optional"
			;;
		*)      STYPE="mandatory"
		esac

		CATAG=`echo $DESC | sed 's/.*%//'`

		if [ "$STYPE" = "mandatory" ]
		then
			SUITGUI_INFO=$SUIT_INFO_MAND
		else
			SUITGUI_INFO=$SUIT_INFO_OPT
		fi

		echo "{$_S} {$SDESC} {$CATAG} {$DEPS} {$ROOTSIZE} {$USRSIZE} {$VARSIZE} {$STYPE} {$STATUS}" >> $SUITGUI_INFO
	}

}

:	-BackupMergedFiles
#
#	Call routine to analyze which files that will require backing up
#	before it gets merged and then back them up. For update, the analysis 
#	was done prior to setld so only the backup of the files is done.
#
BackupMergedFiles()
{
	[ "$PREMRG_ANALYSIS_DONE" ] || MRG_PreMRGSubsets $*

	[ -f $PREMRG_LIST ] &&
	{
       		cat $PREMRG_LIST | while read FNAME
       		do
			MRG_CreatePreMRG $FNAME
		done

		#
       		# Sort the list of copied PreMRG files.
       		#
       		[ -f $PREMRG_FILE ] &&
       			sort -u -o $PREMRG_FILE $PREMRG_FILE

		#
       		# Remove the PREMRG file. In update, this is done only once 
		# since the list contains all files for all products. 
		# For all other apps, this list will be recreated during the 
		# PreMRGSubsets routine.
       		#
       		rm -f $PREMRG_LIST
	}
}

:	-Basename
#		like the program, just cheaper
#

Basename()
{ (
	[ "$1" ] || return 0
	P=$1
	set xx `Parse / $P`
	shift
	eval echo \$$#
) }


:	-Cleanup
#		cleanup before exiting
#
#	given:	uses global context
#	does:	exit processing, called from Exit

Cleanup()
{
	trap '' 0
	cd $_R

	case "$_MEDIA" in
	tape)	DEFMSG="Rewinding Tape..."
		echo "`message -S setld.cat -s SETLD3 \
			CLEANUP_REWIND_TAPE \
			\"$DEFMSG\"`"
		TickWhile Wait MTPID
		TickWhile mt -f $RAW rew
		;;
	esac

	# The year field descriptor is Y to indicate the full year as
	# a decimal number.  This will resolve the year 2000 issue.
	DATE=`date +%Y.%m.%d.%T`

	Ticker off
	wait
	Log "SETLD $$ $DATE $_R -$CMDSW $STAT $EMESG"
	[ "$UPDFLAG" -o "$ADVFLAG" -o "$CMDSW" = "S" ] || rm -rf $_TDIR
	rm -rf $_TMPDIR

	# Clean up files created for stlmenu.
	rm -f \
		$MAND_FILE \
		$INSTLD_CLI \
		$OPT_FILE
}

:       -ClusterPostDelete
#               process subsets for cluster post
#               deletion
#       given:  The list of subsets that are being deleted.
#		The cluster file, /var/tmp/tmp$pid/mem_status
#		containing member number, name and status must
#		exist.
#       does:   run Configure DELETE on cluster
#		member

ClusterPostDelete()
{
	[ "$TCR_FLAG" ] ||
	{
		DEFMSG="Not a cluster, cannot execute %s option."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			CLUSTER_NOT_CLUSTER \
			\"$DEFMSG\" \"-Z\"`"
		return 1
	}
	SUBLIST=$*
	for SUBSETNAME in $SUBLIST
	{
		CTX=$SMDB/$SUBSETNAME
		# subset is installed, run the configure delete
		Log "$SUBSETNAME SCP C DELETE on $MEMBER_ID"
		ACT=C $CTX.scp DELETE ||
		{
			if [ "$FORCE_FLAG" ]; then
				DEFMSG="\
%1\$s, deletion declined by subset control program,
but subset will be deleted anyway on %2\$s."
				Error "`message -E -S -V 500 \
					-F installsetld \
					setld.cat -s SETLD3 \
					DELETE_FORCE_CONTINUE_MEMBER \
					\"$DEFMSG\" \"$SUBSETNAME\" \
					\"$MEMBER_ID\"`"
			else
				DEFMSG="\
%s, deletion declined by subset control program."
				Error "`message -E -S -V 500 \
					-F installsetld \
					setld.cat -s SETLD3 \
					DELETE_DECLINED_BY_CTRL \
					\"$DEFMSG\" \"$SUBSETNAME\"`"
				ERR=1
				continue
			fi
		}

		#
		# Mark subset as not installed
		#
		SWDB_MarkSubset $SUBSETNAME _not_installed
	}
}

:       -ClusterPostInstall
#               process subsets for cluster post
#               installation
#       given:  The list of subsets that are being installed.
#		The cluster file, /var/tmp/tmp$pid/mem_status
#		containing member number, name and status must
#		exist.
#       does:   run Configure INSTALL on cluster
#		member

ClusterPostInstall()
{
	[ "$TCR_FLAG" ] ||
	{
		DEFMSG="Not a cluster, cannot execute %s option."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			CLUSTER_NOT_CLUSTER \
			\"$DEFMSG\" \"-C\"`"
		return 1
	}
	SUBLIST=$*
	for SUBSETNAME in $SUBLIST
	{
		ReadCtrlFile $_R/$SMDB $SUBSETNAME
		
		# transition to proto state
		CopyProto $SUBSETNAME

		Configure $SUBSETNAME INSTALL
	}
}

:	-Configure
#		configure a subset
#
#	given:	$1 - the name of the subset to configure
#		$2 - the argument to be used in invoking the scp
#	does:	invoke the scp for the named subset with ACT=C and the
#		specified argument on the command line
#	return:	0 is successful, 1 on error

Configure()
{
	[ $# != 2 ] &&
	{
		Usage -c
		return 1
	}
	set `Ucase $*`	# coerce subset name and option to upper case
	SUBSET=$1	# subset name to configure
	CONFARG=$2	# command arg for scp

	#% Local Code
	cd $_R

	# Verify that the scp exists.
	[ -f $SMDB/$SUBSET.scp ] ||
	{
		DEFMSG="%s: missing control program, cannot configure."
 		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			CONFIGURE_MISSING_CTRL \
			\"$DEFMSG\" \"$SUBSET\"`"
		return 1
	}

	#
	# Note that we do not check whether a roll is in progress
	# or not.  This is because configuration flows from the
	# Install() and PopulateMember() functions.  If the load or
	# populate is allowed, the configure is allowed without any
	# additional checks.  If the load or populate is declined,
	# Configure() is never invoked.  
	#

	#
	# Make sure the subset is ready for configuration.
	#
	CONFIGURE_FOLLOWS="
		_c_install_completed
		_populate_completed
		_post_load_completed
	"
	SWDB_CheckState $SUBSET $CONFIGURE_FOLLOWS ||
	{
		#
		# Get the current state of the subset.
		#
		CUR_STATE="`SWDB_GetStatusMessage $SUBSET`"

		#
		# Describe the acceptable states for the subset.
		#
		REQ_STATES=
		for STATE_NAME in $CONFIGURE_FOLLOWS
		do
			REQ_STATES="$REQ_STATES\n\t`SWDB_GetStringFromState \
				$STATE_NAME`"
		done

		DEFMSG="\ 
%1\$s is currently in the %2\$s state on %3\$s.  
In order to complete subset configuration it must be in one of the 
following states: 
%4\$s 

Refer to the setld chapter of the Installation Guide for details 
on how to resolve this problem." 

		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			CONFIGURE_CANNOT_CONFIG \
			\"$DEFMSG\" \
			\"$SUBSET\" \
			\"$CUR_STATE\" \
			\"$MEMBER_ID\" \
			\"$REQ_STATES\"`"
		return 1
	}

	# all clear
	ReadCtrlFile $_R/$SMDB $SUBSET 

	# if this is a cluster environment then output
	# the configure message with the member id
	if [ "$TCR_FLAG" ]
	then
		DEFMSG="\nConfiguring \"%1\$s\" (%2\$s) on %3\$s"
			echo "`message -S setld.cat -s SETLD3 \
			CONFIGURE_CONFIGURE_SUBSET_MEMBER \
			\"$DEFMSG\" \"$SDESC\" \"$SUBSET\" \"$MEMBER_ID\"`"
	else
		DEFMSG="\nConfiguring \"%1\$s\" (%2\$s)"
			echo "`message -S setld.cat -s SETLD3 \
			CONFIGURE_CONFIGURE_SUBSET \
			\"$DEFMSG\" \"$SDESC\" \"$SUBSET\"`"
	fi

	# transition .proto.. files to config state
	CopyConfig $SUBSET

	# if in update installation, execute merge files
	[ "$UPDFLAG" -o "$UPD_HWFLAG" ] && UpdMerge $SUBSET ToConfig

	Log "$SUBSET SCP C $CONFARG \c"
	if ACT=C $SMDB/$SUBSET.scp $CONFARG; then
	{
		DEFMSG="SUCCEEDED"
		Log "`message -S setld.cat -s SETLD3 \
			LOG_SUCCEEDED_MSG \
			\"$DEFMSG\"`"

		#
		# Mark the subset as having completed the C INSTALL
		# phase of the .scp.  Since the C INSTALL phase of the
		# .scp is run on every member, do not propagate the 
		# change to the other members.
		#
		SWDB_MarkSubset $SUBSET _c_install_completed

		return 0
	}
	else
	{
		SAVSTAT=$?
		DEFMSG="FAILED: scp status %s"
		Log "`message -E -S -V 400 -F installsetld \
			setld.cat -s SETLD3 \
			CONFIGURE_FAILED_SCP_LOG \
			\"$DEFMSG\" \"$SAVSTAT\"`"

		DEFMSG="SCP C_INSTALL FAILED"
		CORRUPT_REASON=`message -E -S -V 400 -F installsetld \
			setld.cat -s SETLD3 CONFIGURE_C_INSTALL_FAILED \
			"$DEFMSG"`

		#
		# Mark the subset as having failed the C INSTALL
		# phase of the .scp.  Since the C INSTALL phase of the
		# .scp  is run on every member, do not propagate the 
		# change to the other members.
		#
		SWDB_MarkSubset $SUBSET _c_install_failed "$CORRUPT_REASON"

		return 1
	}; fi
}


:	-CopyConfig
#		make state transition to Config state for state files
#
#	given:	$1 - subset name
#	does:	copies all .proto.. files to full config names
#	return:	NIL

CopyConfig()
{ (
	cd $_R

	SUBSET=$1

	ListProtectedSystemFiles $_R/$SMDB/$SUBSET.inv |
		while read FILE
		do
			#
			# Set variables based on $FILE
			#
			#	_D = directory
			#	_F = file
			#	MF = merge file
			#	NF = .new.. file
			#	PF = .proto.. file
			#	CF = configured file
			# _PASSMRG = skip merge due to failure/optimization
			# _FAILMRG = failed results file
			# _KEEPCUS = skip merge due to no new functionality
			#
			MRG_SetFileVariables $SUBSET $FILE

			#
			# Do not execute when rolling additional
			# members when the proto file is shared since
			# the shared file operations were done when
			# the first member rolled. 
			#
			[ "$UPD_MEM_FLAG" ] &&
			{
				MRG_IsMemberSpecific $_D/$CF || continue
			}

			#
			# If the configured file does not exist, copy 
			# the .proto file to the configured file.
			#
			[ ! -f $_D/$CF -o "$ISL_HWFLAG" ] && {
				#
				# Make the parent directory if necessary
				#
				DESTDIRPARENT=`dirname $_D/$CF`
				[ ! -d $DESTDIRPARENT ] && {
					mkdir -p $DESTDIRPARENT
				}

				#
				# Copy the .proto file to the configured
				# file.
				#
				cp -p $_D/$PF $_D/$CF
			}
		done
) }


:	-CopyInstctrl
#		copy instctrl files to SMDB
#	
#	given:	$1 - a list of subsets whose instctrl files are to be copied.
#		$2 - specified only in update installation and contains
#		     subsets to be updated.
#	does:	copy related instctrl files to SMDB. 
#
#		In update installation, clean up outdated instctrl info of
#		subsets available on the media but are not to be updated.
#
#	return: 0


CopyInstctrl()
{ (
	case $# in
	1) 	ALLSUBS=$1
		;;
	2)	# this case only true with update installation.	

		# FIXME - what does this really do?  Shouldn't it
		#	always replace the old information with the
		#	new, regardless of whether or not the subset  
		#	is installed?  For example, in a BL to BL
		#	update shouldn't the new information be loaded
		#	just in case a change has been made (e.g: inv,
		#	scp etc).  In a release to release update the  
		#	old subsets are removed by the
		#	SWDB_RemoveObsolete code. 
		#
		SUBS=$1
		UPD=$2

		# filter through ACT=M first
		ALLSUBS=
		for _S in $SUBS
		{
			ACT=M $_TDIR/$_S.scp -$CMDSW &&
				ALLSUBS="$ALLSUBS $_S"
		}

		# Remove old instctrl info of un-updated subsets now.
		# Outdated instctrl info of updated subsets will be
		# removed later in SWDB_UpdateLockFiles().

		NO_COPY=
		for _S in $ALLSUBS
		{
			Member $_S $UPD ||
			{
				# if subset is installed, then do not replace 
				# its smdb files.
				SWDB_IsInstalled $_S &&
				{
					NO_COPY="$NO_COPY $_S" 
					continue
				}

				NO_VER=`expr "$_S" : '\(.*\)[0-9][0-9][0-9]'`
				rm -f $SMDB/$NO_VER[0-9][0-9][0-9].* #QAR 81107
			}
		}

		# filter out subsets whose smdb files should be kept intact.
		[ "$NO_COPY" ] &&
			ALLSUBS=`ListUniq "$ALLSUBS" "$NO_COPY"`
		;;
	esac

	# If the language variable is set & its subdir exists
	# make a corresponding subdir under /usr/.smdb.
	[ "$LANG" -a -d $_TDIR/$LANG ] &&
	{
		[ -d $SMDB/$LANG ] || mkdir -p $SMDB/$LANG  ||
		{
			Error "$E_MKDIR $SMDB/$LANG"
			return 1
		}
	}

	for _S in $ALLSUBS
	{
		# If the language variable is set & it's subdir
		# contains the subset's ctrl file, copy it to
		# it's corresponding subdir under /usr/.smdb.
		[ "$LANG" -a -f $_TDIR/$LANG/$_S.ctrl ] &&
		{
			cp -p $_TDIR/$LANG/$_S.ctrl $SMDB/$LANG
		}
		cp -p $_TDIR/$_S.ctrl $_TDIR/$_S.inv $_TDIR/$_S.scp $SMDB
	}

	#
        # <QAR #40854> 8/30/96 BF. 
        # It is possible to copy these files directly from the distribution
        # and thereby avoid the permissions change which is made in
        # LoadCtrlInfo, so a copy of that logic has been placed here to 
        # ensure that the file permissions/ownership on the the user's
        # system are set correctly.
	#
        (cd $SMDB
                2>&1 chown -R root:system \
			*.inv \
			*.scp \
			*.sts \
			*.ctrl \
			$LANG/*.ctrl \
			> /dev/null
                2>&1 chmod -R 644 \
			*.inv \
			*.sts \
			*.ctrl \
			$LANG/*.ctrl \
			> /dev/null
                2>&1 chmod -R 755 *.scp > /dev/null
        )

	return 0

) }


:	-CopyProto
#		make state transition to Proto state for state files
#
#	given:	$1 - subset name
#	does:	for all of the .new.. files in the subset inventory,
#		copies them to .proto..
#	return:	NIL

CopyProto()
{ (
	cd $_R

	SUBSET=$1

	ListProtectedSystemFiles $_R/$SMDB/$SUBSET.inv |
		while read FILE
		do
			#
			# Set variables based on $FILE
			#
			#	_D = directory
			#	_F = file
			#	MF = merge file
			#	NF = .new.. file
			#	PF = .proto.. file
			#	CF = configured file
			# _PASSMRG = skip merge due to failure/optimization
			# _FAILMRG = failed results file
			# _KEEPCUS = skip merge due to no new functionality
			#
			MRG_SetFileVariables $SUBSET $FILE

			#
			# Do not execute when rolling additional
			# members when the proto file is shared since
			# the shared file operations were done when
			# the first member rolled. 
			#
			[ "$UPD_MEM_FLAG" ] &&
			{
				MRG_IsMemberSpecific $_D/$PF || continue
			}

			#
			# Check the flag HINSTALL. If it's set then we
			# are doing the initial install of a hardware
			# upgrade, and as a result, it's OK to trash
			# the old .proto file
			#
			if [ ! "$HINSTALL" -a ! "$ISL_HWFLAG" ]
			then
				[ ! -f $_D/$PF ] && 
				{
					cp -p $_D/$NF $_D/$PF
				}
			else
				cp -p $_D/$NF $_D/$PF
			fi
		done
) }



:	-Delete
#		Delete subsets
#
#	given:	$* - a list of subsets to delete
#	does:	delete the subsets
#	return:	0 on success
#		1 on failure

Delete()
{ (
	ERR=0
							
	case "$#" in
	0)	#! menuhook
		Usage -d
		DEFMSG="Delete(): argument error"
		Log "`message -E -S -V 400 -F installsetld \
			setld.cat -s SETLD3 \
			DELETE_ARGS_ERR_LOG \
			\"$DEFMSG\"`"
		return 1
	esac
	set xx `Ucase $*`; shift

	CTX=		# context prefix
	_S=		# current subset

	cd $_R		# assure operation in user specified hierarchy

	SUBS=$*

	DeleteCanProceed $SUBS ||
		return 2

	if [ -f /usr/sbin/clu_get_info ] &&
		clu_get_info -raw > $CLUSTER_INFO 2> /dev/null
	then
		grep "^M:" $CLUSTER_INFO \
			| awk -F: '{print $2,$3,$6}' \
			> $MEMBERS_N_STATUS
	fi

	#
	# Filter out subsets that cannot be deleted.
	#      
	TMP_SUBS=
	for _S in $SUBS
	{
		CTX=$SMDB/$_S

		#
		# If the subset is in the not installed state,
		# the subset cannot be removed.
		#
		SWDB_CheckState $_S _not_installed &&
		{
			DEFMSG="%s: not currently installed, cannot delete."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				DELETE_CANNOT_DELETE \
				\"$DEFMSG\" \"$_S\"`"
			ERR=1
			continue
		}

		#
		# Read in the control file.
		#
		ReadCtrlFile $_R/$SMDB $_S ||
		{
			DEFMSG="\
Error reading control file for %s, cannot delete."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				DELETE_READ_CTRL_ERR \
				\"$DEFMSG\" \"$_S\"`"
			ERR=1
			continue
		}

		#
		# Check the sticky bit in the FLAGS from the
		# control file.
		#
		[ `FlagsAttrCheck SATTR_STICKY $FLAGS` = 1 ] &&
		{
			# sticky flag is set for this subset
			DEFMSG="Sorry, You may not delete \"%1\$s\" (%2\$s)"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				DELETE_SORRY_NODELETE \
				\"$DEFMSG\" \"$SDESC\" \"$_S\"`"
			ERR=1
			continue
		}

		TMP_SUBS="$TMP_SUBS $_S"
	}

	SUBS=$TMP_SUBS
	[ "$SUBS" ] ||
	{
		# no subsets left to delete
		return $ERR
	}

	#
	# Rearrange deletable subsets in reverse depord order.
	# Do not call depord if env variable _DUPATCH_NO_DEPORD
	# is set.
	#
	[ "$_DUPATCH_NO_DEPORD" ] ||
	{
		SUBS=`(cd $SMDB; depord $SUBS)`
		SUBS=`ListReverse $SUBS`
	}

	#
	# Ensure that all the subsets to be deleted are not needed by
	# other installed subsets.  If any are needed, ask the user
	# to confirm that it's nevertheless okay to delete them.
	#
	TMP_SUBS=
	for _S in $SUBS
	{
		CTX=$SMDB/$_S
		Log "$_S"

		#
		# If the subset is not locked (i.e., no other installed
		# subset depends upon it), then add it to the list of
		# those we will delete.
		#
		SWDB_IsLocked $_S ||
		{
			TMP_SUBS="$TMP_SUBS $_S"
			continue
		}

		#
		# The subset is installed and has a non-zero length
		# lock file.  This means that there are subsets that
		# depend on the one that we are trying to remove.
		# This requires that we notify the user and verify
		# that the ramifications of a request to delete are
		# understood.
		#
		# Take out duplicate locks.
		#
		SWDB_Unique $_S

		#
		# If dependency subsets are also specified to be
		# deleted, they need to be filtered out in the msgs.
		# We do this here in case reverse depord order did not 
	        # catch the dependency, which is likely for LPs.
		#
		LOCKS=`SWDB_ListLockingSubsets $_S`
		LOCKS=`ListUniq "$LOCKS" "$SUBS"`
		[ `Length $LOCKS` -le 0 ] &&
		{
			TMP_SUBS="$TMP_SUBS $_S"
			continue
		}

		#
		# Read the control file so we can print its description.
		#
		ReadCtrlFile $_R/$SMDB $_S
		DEL_DESC="$SDESC"
		DEFMSG="
The following subsets need \"%1\$s\" (%2\$s)
to operate correctly:

"
		message -S setld.cat -s SETLD3 \
			DELETE_NEED_SUBSET \
			"$DEFMSG" "$DEL_DESC" "$_S"

		#
		# Print the description of each locking subset (each
		# subset that depends on the one ($_S) that we're
		# trying to delete).
		#
		for K in $LOCKS
		{
			ReadCtrlFile $_R/$SMDB $K 
			echo "	$SDESC ($K)"
		}

		#
		# Ask the user if the subset should be deleted in
		# spite of the others that depend on it.
		#
		DEFMSG="
Are you sure you wish to delete \"%1\$s\" (%2\$s)? (y/n): "
		PROMPT_OVERRIDE_LOCK=`message -S setld.cat -s SETLD3 \
			DELETE_SURE_DELETE "$DEFMSG" \
			"$DEL_DESC" "$_S"`
		DialogYesNo "$PROMPT_OVERRIDE_LOCK" ||
		{
			#
			# The user said NO.  Do not delete the subset.
			#
			DEFMSG=" FAILED: locked"
			Log "`message -E -S -V 400 -F installsetld \
				setld.cat -s SETLD3 \
				DELETE_FAILED_LOG \
				\"$DEFMSG\"`"
			ERR=1
			continue
		}

		#
		# The user said YES.  It's okay to delete the subset.
		#
		DEFMSG=" WARNING: locked"
		Log "`message -E -S -V 300 -F installsetld \
			setld.cat -s SETLD3 \
			DELETE_WARNING_LOG \
			\"$DEFMSG\"`"

		#
		# Now that the user has confirmed the deletion,
		# add this subset to the list to be deleted.
		#
		TMP_SUBS="$TMP_SUBS $_S"
	}
	SUBS=$TMP_SUBS

	DeleteFromSystem $SUBS ||
	{
		# Delete of one of the subsets failed.
		ERR=1
	}
	return $ERR 
) }


:	-DeleteCanProceed
#		Check if it's okay to delete subsets
#
#	given:	$* - subsets we're trying to delete
#	does:	Checks for various conditions when subsets should
#		not be deleted.
#	return:	0 if the subsets can be deleted;
#		1 otherwise.
#

DeleteCanProceed()
{
	_SUBS=$*

	# Deletion is always permitted if we are not on a
	# cluster that is in the process of doing a rolling
	# upgrade.
	#
	INST_CLU_RollIsInProgress ||
		return 0

	if [ "$UPD_MEM_FLAG" ]
	then
		DEFMSG="Subsets cannot be deleted during a cluster
roll additional member operation."
		Error "`message -E -S -V 500 \
			-F installsetld \
			setld.cat -s SETLD5 \
			DELETE_DURING_ROLL_ADDITIONAL \
			\"$DEFMSG\"`"
		return 1
	fi

	# During a cluster roll-first-member operation, it is okay
	# to delete subsets.  The removal is done only on member0
	# and the current member.  The other cluster members are
	# running tagged files and should not remove the product.
	#
	if [ "$UPDFLAG" -o "$UPD_HW_FLAG" ]
	then
		return 0
	fi

	# Otherwise, we know we're not being invoked as part of
	# the roll process because none of the UPD* flag variables
	# are set.  Instead we're being invoked by the user, while
	# the cluster is in a roll state.
	#
	if AnySubsetMustRoll $_SUBS
	then
		# Decline the subset delete.  The reasoning for this
		# is that the rolling upgrade process is responsible
		# for deleting any MUST_ROLL subsets that need to be
		# deleted, and deleting any other such subsets may
		# cause consistency problems in the roll process.
		#
		DEFMSG="The following subsets cannot be deleted
because a rolling upgrade is now in progress on this cluster:\n%1\$s"
		Error "`message -E -S -V 500 \
			-F installsetld \
			setld.cat -s SETLD5 \
			CANNOT_DELETE_MUST_ROLL \
			\"$DEFMSG\" \"$MUST_ROLL\"`"
		return 1
	fi

	# All the subsets requested for deletion are from products
	# that are not required to roll.  That means it is possible
	# for the user to manually delete them, but it might be a
	# really bad idea.  So here we ask for confirmation.
	#
	DEFMSG="

A cluster rolling upgrade operation is in progress.  Please confirm
that removal of these subsets is acceptable for all of the cluster
members.  The removal of a product while the cluster is in the middle
of a roll may adversely affect both the cluster members running the
new O.S. and the cluster members running the old O.S.

Are you sure you wish to continue with the deletion? (y/n)"
	CONFIRM_DELETE=`message -E -S -V 500 \
		-F installsetld \
		setld.cat -s SETLD5 \
		CONFIRM_DELETE_DURING_ROLL \
		"$DEFMSG"`  # QAR 81022
	DialogYesNo "$CONFIRM_DELETE"  # QAR 80590
	return $?
}


:	-DeleteSharedConfig
#		Delete files in Config state
#
#	given:	$1 - subset name
#	does:	deletes all configure state versions of files in subset
#	return:	NIL
#

DeleteSharedConfig()
{ (
	S=$1

	ListProtectedSystemFiles $_R/$SMDB/$S.inv |
	while read FILE
	do
		#
		# Set variables based on $NEW_FILE
		#
		#       _D = directory
		#       _F = file
		#       MF = merge file
		#       NF = .new.. file
		#       PF = .proto.. file
		#       CF = configured file
		#
		MRG_SetFileVariables $S $FILE

		# delete final config version from MEMBER_ID
		echo $_D/$CF

	done | xargs rm -f

) }
	

:       -DeleteFromSingleMember
#               Delete subset from a cluster member, without affecting
#		that same subset on any other member.
#       given:  A subset that is being deleted, and a
#               MEMBER_ID specifying which member is affected.
#       does:   run the Configure DELETE scp phase on the specified
#               cluster member, then remove any member-specific
#               inventory from that member.
#       return: 0 for success, otherwise failure.
#       notes:  This may be called during a rolling upgrade, in which case
#               it affects only the specified member.  It also may be
#               done for post-install delete, in which case this routine
#               will be called for each member except member0.

DeleteFromSingleMember()
{
	[ "$XFLAG" ] && INST_DoTracing begin "DeleteFromSingleMember"

	SS="$*"

	#
	# If we're called without a MEMBER_ID value, we cannot
	# continue.  This routine should not guess which member
	# is intended, and defaulting to the current member is
	# a risky choice.
	#
	[ "$MEMBER_ID" ] ||
	{
		echo "Internal error:  MEMBER_ID not set." >&2
		[ "$XFLAG" ] && INST_DoTracing end "DeleteFromSingleMember"
		return 1
	}

	#
	# This routine only operates on real members, not member0.
	#
	[ "$MEMBER_ID" = "member0" ] &&
	{
		echo "Internal error:  MEMBER_ID=member0 not allowed." >&2
		[ "$XFLAG" ] && INST_DoTracing end "DeleteFromSingleMember"
		return 1
	}

	if SWDB_CheckState $SS _not_installed
	then
		return 0
	fi


	#
	# Run the C DELETE scp phase of the subset.
	#

	ExecuteSCPOnMember $MEMBER_ID $SS C DELETE
	C_DELETE_STATUS=$?
	[ "$C_DELETE_STATUS" = 0 ] ||
	{
		#
		# Return failure unless the "-f" option was given.
		# In case of "-f", ignore the SCP failure and
		# continue with deleting the member-specific files.
		#
		if [ "$FORCE_FLAG" ]
		then
			# Force option set.
			DEFMSG='
%1$s deletion declined by subset control program,
but subset will be deleted anyway on %2$s.'
			Error "`message -E -S -V 400 -F installsetld \
				setld.cat -s SETLD3 \
			DELETE_FORCE_CONTINUE_MEMBER \
			\"$DEFMSG\" \"$SS\" \"$MEMBER_ID\"`"
		else
			# Scp failed.
			DEFMSG='%1$s scp failed on %2$s.'
			Error "`message -E -S -V 400 -F installsetld \
				setld.cat -s SETLD3 \
				DELETE_SUBSET_CTRL_FAIL \
				\"$DEFMSG\" \"$SS\" \"$MEMBER_ID\"`"

			return $C_DELETE_STATUS
		fi
	}

	#
	# Determine the combined member-specific inventory of
	# the subset (on the specified member).  We store the
	# inventory in a temporary file, which we create in the
	# .smdb. directory because we know that's writable.
	#
	MS_INV_FILE=$_R/usr/$CLUSTER/$MEMBER_ID/.smdb./dfsm.$$
	touch $MS_INV_FILE	#  QAR 85615
	INST_DeriveMemberSpecificINV $_R/$SMDB/$SS.inv \
		$MS_INV_FILE $MEMBER_ID

	#
	# Delete the proto and final configured versions of any
	# member-specific protected system files.
	#
	ListProtectedSystemFiles $MS_INV_FILE |
	while read FILE
	do
		#
		# Set variables based on $FILE
		#
		#       _D = directory
		#       _F = file
		#       MF = merge file
		#       NF = .new.. file
		#       PF = .proto.. file
		#       CF = configured file
		#
		# FIXME -- This routine is needed only for protected
		# system files where the .new.. file is shared, but
		# the final configured file is member-specific.  We
		# should identify the limited number of such files,
		# and look for an alternate way to implement each.
		# This will simplify the transition to POSIX.
		#
		MRG_SetFileVariables "ANY" $FILE

		echo $_D/$PF $_D/$CF

	done | xargs rm -f

	#
	# Delete the member-specific inventory.
	#
	frm < $MS_INV_FILE
	rm -f $MS_INV_FILE

	# Remove the link target files still left in member
	# specific areas for the subset.
	awk '$11 ~ /\{memb\}/ {print $10, $11}' $_R/$SMDB/$SS.inv |
	while read MEMBER0_F_OR_D MEMBER0_F_TARGET
	do
		# Get the directory path of the link
		# and cd to that directory because the
		# filename in the inventory is relative
		# to the link directory.
		DNAME=`dirname $MEMBER0_F_OR_D`
		CURRDIR=`pwd`
		cd $DNAME

		# Change file name path to member specific
		# from {memb}.
		MFILE=`MRG_CluTranslate $MEMBER0_F_TARGET`
		[ -f $MFILE ] &&               # is it a file
		{
			# delete MEMBER_ID file
			rm -f $MFILE
		}
		cd $CURRDIR
	done

	# Mark the subset as being deleted on the $MEMBER_ID member.
	# The member-specific files are gone and the C DELETE phase
	# has been run, but the shared files are still present.
	#
	SWDB_MarkSubset $SS _deleting
	
	[ "$XFLAG" ] && INST_DoTracing end "DeleteFromSingleMember"
	return $C_DELETE_STATUS
}
	

:	-DeleteFromSystem
#		Delete subsets from all members of a cluster, or
#		from a single system.
#	given:	The list of subsets that are being deleted.
#	does:	First run C DELETE scp phase on every member, and
#		delete member-specific inventory from every member.
#		Then run C DELETE and PRE_D scp phases on member0,
#		delete the shared and member0-specific inventory.
#		Finish by running the POST_D scp phase on member0.
#	return: 0 for success, otherwise failure.

DeleteFromSystem()
{
	[ "$XFLAG" ] && INST_DoTracing begin "DeleteFromSystem"

	DFS_SUBSETS="$*"

	#
	# Get the list of cluster member numbers, if any.
	#
	MEM_NUM_LIST=`INST_CLU_ListMemberIDs`

	#
	# Delete each subset.
	#
	for SS in $DFS_SUBSETS
	do
		ReadCtrlFile $_R/$SMDB $SS

		DEFMSG="
Deleting \"%1\$s\" (%2\$s)."
		echo `message -S setld.cat -s SETLD3 \
			DELETE_DELETING \
			"$DEFMSG" "$SDESC" "$SS"`

		DELSTAT=0
		rm -f $SS.fail

		#
		# On every member, run C DELETE.  If it succeeds,
		# or if we got the "-f" option on the command line,
		# remove this subset's member-specific inventory
		# and protected system files from that member.
		#
		for MEMBER_ID in $MEM_NUM_LIST
		do
			eval DeleteFromSingleMember $SS ||
			{
				# Terminate deletion for
				# this subset and setup
				# return status.
				DELSTAT=1
			}
		done

		#
		# Run C DELETE as member0.
		#
		MEMBER_ID=member0
		Log "$SS SCP C DELETE on $MEMBER_ID"
		ACT=C $_R/$SMDB/$SS.scp DELETE ||
		{
			if [ "$FORCE_FLAG" ]
			then
				# Force option set.
				DEFMSG='
%s, deletion declined by subset control program,
but subset will be deleted anyway.'
				Error "`message -E -S -V 400 -F installsetld \
					setld.cat -s SETLD3 \
					DELETE_FORCE_CONTINUE \
					\"$DEFMSG\" \"$SS\"`"
			else
				DEFMSG="\
%s, deletion declined by subset control program."
				Error "`message -E -S -V 500 \
					-F installsetld \
					setld.cat -s SETLD3 \
					DELETE_DECLINED_BY_CTRL \
					\"$DEFMSG\" \"$SS\"`"
			fi

			DELSTAT=1
		}

		#
		# Now we've done the C DELETE on every member.  We've
		# also deleted the member-specific files from every
		# real member where C DELETE succeeded (or from all
		# members if the "-f" option was given).  We have not
		# deleted member-specific files from member0 as yet.
		#
		# If C DELETE failed on any member, we won't go any
		# further unless the "-f" option was given.
		#
		[ "$DELSTAT" = 0 ] || [ "$FORCE_FLAG" ] || continue

		#
		# Mark this subset corrupted, on this member.
		#
		SWDB_MarkSubset $SS _deleting

		#
		# Delete final configured version of protected system
		# files from shared space (and from member0's
		# member-specific area).
		#
		DeleteSharedConfig $SS

		#
		# Run PRE_D as member0.
		#
		Log "$SS SCP PRE_D on $MEMBER_ID"
		ACT=PRE_D $_R/$SMDB/$SS.scp

		#
		# Delete proto version of protected system files from
		# shared space (and from member0's member-specific area).
		#
		DeleteSharedProto $SS

		#
		# Delete everything listed in the subset's inventory.
		#
		frm < $_R/$SMDB/$SS.inv

		#
		# Run POST_D as member0.
		#
		Log "$SS SCP POST_D on $MEMBER_ID"
		ACT=POST_D $_R/$SMDB/$SS.scp

		# Clean out dependency info. Check to see if
		# $DEPS  has " " or "."  expr returns 1 if the first
		# character in $DEPS matches any character specified
		# within [].  EDEP is a dummy variable.
		#
		EDEP=`expr match "$DEPS" '[ .]'`   
		if [ "$EDEP" = 0 ]
		then
			#
			# Remove dependency lock file info.
			#
			for K in $DEPS
			do
				SWDB_EraseLocks $K $SS
			done
		fi

		#
		# Mark the subset uninstalled.
		#
		SWDB_MarkSubset $SS _not_installed   # on member0
		SWDB_ClusterPropagate $SS
		rm -f $_R/$SMDB/$SS.lk

		#
		# Remove the deleted subset name from the cinst.data
		# file.
		#
		if [ -s "$_R/$CINSTDATA" ]
		then
			if [ "$TCR_FLAG" ] 
			then
				INST_CLU_OnEachMember INST_UniqueWordList \
					-delete "$SS" $_R/$CINSTDATA
			else
				INST_UniqueWordList -delete "$SS" \
					$_R/$CINSTDATA
			fi
		fi
	done

	[ "$XFLAG" ] && INST_DoTracing end "DeleteFromSystem"
	return $DELSTAT
}


:       -DeleteMemberFiles
#               Delete files in cluster members
#
#       given/Inputs:   subset name
#       does:   deletes all corresponding member0 files in subset
#		by using the member_id
#       return: Nothing
#       effect/Notes:   None
#

DeleteMemberFiles()
{ (
	_S=$1
	CTX=$SMDB/$_S

	# Delete corresponding member files

	# First delete any member specific files
	MEMBER0_LIST=`awk '{print $10}' $CTX.inv | grep -E member0`
	for MEMBER0_F_OR_D in $MEMBER0_LIST
	do
		[ -f $MEMBER0_F_OR_D ] &&               # is it a file
		{
			# change file name to member specific
			# from member0
			MFILE=`MRG_CluTranslate $MEMBER0_F_OR_D`

			# delete MEMBER_ID file
			rm -f $MFILE

			#search if .new.. if yes then .new.. deleted, but not
			# proto or config versions
			FILE=`echo $MEMBER0_F_OR_D | grep -E '\.new\.\.' | \
				sed 's/\.new\.\.//`
			[ "$FILE" ] &&
			{
				#
				# Set variables based on $NEW_FILE
				#
				#       _D = directory
				#       _F = file
				#       MF = merge file
				#       NF = .new.. file
				#       PF = .proto.. file
				#       CF = configured file
				#
				MRG_SetFileVariables $_S $FILE

				# delete proto version and final config
				# version from MEMBER_ID
				rm -f $_D/$PF \
					$_D/$CF
			}
		}
	done

	# Second remove the link target files still left in member
	# specific areas
	awk '$11 ~ /\{memb\}/ {print $10, $11}' $CTX.inv |
	while read MEMBER0_F_OR_D MEMBER0_F_TARGET
	do
		# get the directory path of the link
		DNAME=`dirname $MEMBER0_F_OR_D`
		cd $DNAME

		# change file name to member specific
		# from member0
		MFILE=`MRG_CluTranslate $MEMBER0_F_TARGET`
		[ -f $MFILE ] &&               # is it a file
		{
			# delete MEMBER_ID file
			rm -f $MFILE
		}
	done
)}
		

:	-DeleteSharedProto
#		Delete files in Proto state
#
#	given:	$1 - subset name
#	does:	deletes all proto state versions of files in subset
#	return:	NIL
#

DeleteSharedProto()
{ (
	S=$1

	ListProtectedSystemFiles $_R/$SMDB/$S.inv |
	while read FILE
	do
		#
		# Set variables based on $NEW_FILE
		#
		#       _D = directory
		#       _F = file
		#       MF = merge file
		#       NF = .new.. file
		#       PF = .proto.. file
		#       CF = configured file
		#
		MRG_SetFileVariables $S $FILE

		# delete proto version from MEMBER_ID
		echo $_D/$PF
	done | xargs rm -f
) }


:	-DependencyOrder
#		order a bucketload of subsets
#
#	given:	$* - a list of subsets
#	does:	orders the subset in tape order, writing the ordered list
#		to stdout. It is assumed that the control files for the
#		subsets are in the current directory.
#	return:	nothing

DependencyOrder()
{
	# for disk and ris, use depord 
	[ "$_MEDIA" != tape ] &&
	{
		depord $*
		return 
	}

	case "$#" in
	0)	DEFMSG="DependencyOrder(): no subsets specified"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			DEPENDENCYORDER_NO_SUBSET \
			\"$DEFMSG\"`"
		return 
	esac
	Bu_SUBS=$*

	#% Local Variables
	Bu_ORD=			# ordered subsets
	Bu_LEFT= Bu_RIGHT=	# sort temp variables

	#% Local Code
	# get the PNV for the lead subset in the bucket
	for Bu_SUB in $Bu_SUBS
	{
		NameParse Bu_ $Bu_SUB && break
		Bu_SUBS=`(set $Bu_SUBS;shift;echo $*)`
	}

	for Bu_S in $Bu_SUBS
	{
		# get tape location
		ReadCtrlFile $_TDIR $Bu_S || continue

		set xx `Parse : $MTLOC`; shift
		Bu_VOL=$1 
		Bu_SORD=$2

		# pass tape volume, order on tape, subset name to awk.
		echo "$Bu_VOL $Bu_SORD $Bu_S"

		# arrays in awk are dynamic, so we need to keep track of
                # the bounds ourselves (vmax, lmax, vmin, lmin) */
		#
                # order and inuse are two-dimensional arrays indexed by
                # tape volume ($1) and order on tape ($2).
                # 'order' stores the subset name;
                # 'inuse' stores 'y' to mark the tape location in use. */

	} | awk 'BEGIN {
			vmax=0; vmin=0
			lmax=0; lmin=0
		}
		{       
			order[$1","$2] = $3
			inuse[$1","$2] = "y"
			if( $1 > vmax )	vmax = $1
			if( $2 > lmax )	lmax = $2
			if( $1 < vmin ) vmin = $1
			if( $2 < lmin ) lmin = $2
		}
		END {
			for( j = vmin; j <= vmax; ++j )
			{
				for( i = lmin; i <= lmax; ++i )
				{
					if( inuse[j","i] == "y" )
						print( order[j","i] )
				}
			}
		}'
}


:	-DetermineAvailable
#		Determine which subsets are installable in this environment.
#		Additionally, if this is a post-install of additional base
#		software, ensure that the distribution media revision
#		matches that of the currently installed software.
#
#	given:	global data only
#		contents of $_TDIR
#		$ADVFLAG - specifies installation type
#	does:	uses the temp directory to derive a list of subsets which
#		are available and installable to the system. Installable
#		subsets are those which are not currently installed and
#		are not masked by the subset mask
#	return:	nothing
#	effect:	Sets $SBS.
#		For post-install of base software, this routine will
#		exit 'setld' immediately if the distribution media
#		revision doesn't match the currently installed software.
#

DetermineAvailable()
{
	MASK=".*"		# default, all subsets

	# decode,
	#  bits:
	#	00 - basic base
	#	01 - adv base
	#	10 - basic ws
	#	11 - adv ws

	case "$ADVFLAG" in
	[01])	MASK="$RISC_B|$VAX_B|$WLS_B"
		;;
	[23])	MASK="$RISC_B|$RISC_WS|$VAX_B|$VAX_WS|$WLS_B"
		;;
	esac

	# get list of subsets from temp dir and filter thru the mask
	SBS=`(cd $_TDIR; ls *.ctrl | sed 's/.ctrl//g' | grep -E "$MASK")`
	# verify that there were control files
	[ "$SBS" = '*' ] &&
		SBS=

	# If this a post-initial install of BASE S/W, 
	# and we're not in the process of:
	#   o RIS extract operation
	#   o creating a new DMS area
	#   o an update installation
	# make sure we've got the right distribution.
	#
	[ ! "$ADVFLAG" -a "$OPERATION" != "extract" \
		-a ! "$DMS_NEW_AREA" -a ! "$UPDFLAG" ] &&
	{
		OSFBASE=`(cd $_TDIR; 2>/dev/null ls OSFBASE*.ctrl \
			| sed 's/.ctrl//g')`

		[ "$OSFBASE" ] &&
		{
			#
			# Get the intended version maj/min 
			#
			set -- $OSFBASE
			INTEND_VER=`expr $1 : '.*\(...$\)'`

			#
			# Get currently installed maj/min version 
			# If this system was a HW upgrade, we'll
			# find two versions of OSFBASE
			#
			CURRDIR=`pwd`
			cd $SMDB

			set xx `SWDB_FindInstalledVersions OSFBASE`
			shift 1

			cd $CURRDIR

			case "$#" in
			0)	# Initial alternate root (-D ) install
				return
				;;

			1)	# non HW upgraded system
				CURR_VER=$1
				[ "$INTEND_VER" -ne "$CURR_VER" ] &&
				{
				#
				# Get the current product/revision
				#
				ReadCtrlFile $_R/$SMDB OSFBASE${CURR_VER}
				PROD_REV=$NAME
					DEFMSG="\
\tYou are attempting to install from a distribution media that\n\
\tis a different version than your currently installed system.\n\
\tYou presently have the following operating system version installed:\n\
\n\
\t%s\n\
\n\
\tPlease use a distribution media that matches this version when\n\
\tinstalling base operating system software."
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD3 \
						DETERMINEAVAILABLE_ERR1 \
						\"$DEFMSG\" \"$PROD_REV\"`"
					Exit 1
				}
				;;

			*)	# HW Upgraded system
				CURR_VER1=$1 ; CURR_VER2=$2
				[ "$INTEND_VER" -ne "$CURR_VER1" -a \
				  "$INTEND_VER" -ne "$CURR_VER2" ] &&
				{
				#
				# Get the current products/versions
				#
				ReadCtrlFile $_R/$SMDB OSFBASE${CURR_VER1}
				PROD_REV1=$NAME

				ReadCtrlFile $_R/$SMDB OSFBASE${CURR_VER2}
				PROD_REV2=$NAME

					DEFMSG="\
\tYou are attempting to install from a distribution media that\n\
\tis a different version than your currently installed system.\n\
\tYou currently have the following operating system base and\n\
\thardware upgrade versions installed:\n\
\n\
\t%1\$s\n\
\t%2\$s\n\
\n\
\tPlease use the distribution media that contains these versions when\n\
\tinstalling base operating system software."
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD3 \
						DETERMINEAVAILABLE_ERR2 \
						\"$DEFMSG\" \"$PROD_REV1\" \
						\"$PROD_REV2\"`"
					Exit 1
				}
				;;
			esac

			#
			# Unset positional parameters
			#
			set --
		}
	}

	
}



:	-Dirname
#		get all but the last part of a path
#

Dirname()
{ (
	P=$1

	set xx `Parse / $P`
	shift
	OUT=
	case "$P" in
	/*)	SL=/
		;;
	*)	SL=
	esac
	while [ $# -gt 1 ]
	do
		OUT="$OUT$SL$1"
		SL=/
		shift
	done
	echo $OUT
) }


:	-Dirs
#		create all needed directories
#
#	given:	nothing
#	does:	makes sure the directories needed to perform correctly
#		are available
#	return:	0

Dirs()
{
	# check if setld is in use.
	#! a better lock mechanism is needed here
	#
	case $CMDSW in
	[lx])	[ -d $_TDIR ] &&
		{
			DEFMSG="Temp directory %s already in use"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				DIRS_TEMPDIR_ALREADY_USE \
				\"$DEFMSG\" \"$_TDIR\"`"
			return 1
		}
	esac

	rm -rf $_TDIR
	rm -rf $_TMPDIR

	# 
	# Capture current directory, and then change directory to 
	# the defined root (_R) path
	#
	CURDIR=`pwd`

	cd $_R

	#
	# When running on a 4.0* system, do not create
	# the CDSLs, since if the user exits from the 
	# operation, the CDSL will be left on the 4.0*
	# system and CDSLs cannot be resolved on 4.0*
	# systems (QAR 80521).
	#
	case "`uname -r`" in
	*4.0* )
		NOCDSL=1
		;;
	esac

	#
	# Determine whether we are running on a cluster "capable"
	# system, so that we can make the appropriate member-specific
	# directories.
	#
	if [ "$CMDSW" != "s" \
		-a "$CMDSW" != "x" \
		-a ! "$UPDFLAG" \
		-a ! "$NOCDSL" ]
	then
		# (This clause will get executed on all non-'s'
		# execution AND when the "memberid" attribute has
		# been defined in the "generic" subsystem of 
		# ./etc/sysconfigtab)
		#
		# We need to create member specific and shared
		# directories to hold the logfiles.  First, we'll
		# create the member specific (MS) directories and 
		# shared directories.  Then we'll create the CDSLs 
		# that point to them.
		#
		MS_DIRLIST="$U/$V/$CLUSTER/$MEMBER_ID/adm/smlogs \
			$U/$V/$CLUSTER/$MEMBER_ID/tmp \
			$CLUSTER/$MEMBER_ID/sbin/it.d/data"

		for X in $MS_DIRLIST
		{
			[ -d $X ] || mkdir -p $X ||
			{
				Error "$E_MKDIR $X"
				return 1
			}
		}
		
		#
		# Create the shared directories.  If this is
		# a post-initial installation to an alternate 
		# root, we need to create a link from ./var 
		# to ./usr/var.
		#
		if [ "$DEFPATH" = 0 -a ! "$ADVFLAG" ]
		then
			[ -h ./var -o -d ./var ] || ln -s ./usr/var var
		fi

		SHARED_DIRLIST="$S $S/$I $U $V/$A $_TDIR $_TMPDIR \
				$SMDB $CSMDB"

		for X in $SHARED_DIRLIST
		{
			[ -d $X ] || mkdir -p $X ||
			{	
				Error "$E_MKDIR $X"
				return 1
			}
		}

		#
		# Now create the necessary CDSLs
		#
		[ -h $LOGDIR ] ||
			ln -sf ../$CLUSTER/{memb}/adm/smlogs $LOGDIR

		[ -h $V/$T ] ||
			ln -sf ./$CLUSTER/{memb}/tmp $V/$T

		[ -h sbin/it.d/data ] ||
			ln -sf ../../$CLUSTER/{memb}/sbin/it.d/data \
				sbin/it.d/data

		# If we are creating a new dataless area then we
		# need to create a {memb} CDSL so that we can
		# use the CDSL in the case of the pre-V5.0 server.
		[ "$DMS_NEW_AREA" ] &&
		{
			[ -d ./$CLUSTER ] ||
				mkdir -p ./$CLUSTER
			( cd ./$CLUSTER
			ln -fs member0 {memb} )
			(cd ./var/$CLUSTER
			ln -fs member0 {memb} )
		}
	else 
		#
		# Make sure that all required directories exist,
		# when not in a cluster environment.
		#
		DIRLIST="$S $S/$I $SID $U $V $V/$A $LOGDIR $V/$T \
			$_TDIR $_TMPDIR"

		[ "$CMDSW" != "s" ] && DIRLIST="$DIRLIST $SMDB"
		for X in $DIRLIST
		{
			[ -d $X ] || mkdir $X ||
			{
				Error "$E_MKDIR $X"
				return 1
			}
		}
	fi

	cd $CURDIR
	return 0
}


:	-Error
#		Print an error message to stderr, or to 
#		/dev/console if during a graphical full install
#
#	given:	a message to print, $1 may be option '-n'
#	does:	prints the message to stderr, or /dev/console.
#		If -n option is absent,	also logs the message 
#		to the logfile
#	return:	nothing

Error()
{
	case "$1" in
	-n)	shift
		;;
	*)	Log "$1"
	esac
	1>&2 echo "$PROG: $1"

	#
	# If the progress bar is active (STATUSPIPEPATH is a named pipe)
	# and a full installation is in process, we need to echo error
	# messages to /dev/console so they'll appear in the installation
	# information window.
	#
	[ -p "$STATUSPIPEPATH" -a "$ADVFLAG" ] && {
		echo "$PROG: $1" > /dev/console
	}
}


:	-ExecuteSCPOnMember
#		attempt to run a subset's scp on a given member
#	given:	$1 - cluster member name, for example "member7"
#		$2 - subset name
#		$3 - SCP phase, for example "C"
#		$* - optional arguments to the scp, for example "DELETE"
#	does:	runs the subset's SCP script on the named member.
#	return:	the scp's exit status.

ExecuteSCPOnMember()
{
	ESOM_TARGET="$1"
	ESOM_SUBSET="$2"
	ESOM_PHASE="$3"
	shift ; shift ; shift

	if [ "$ESOM_TARGET" = member0 ]
	then
		return 1
	fi

	[ "$ESOM_SELF" ] || ESOM_SELF=`INST_CLU_GetMemberID`

	SCP_FAIL_FILE=$_R/$SMDB/$ESOM_SUBSET.fail.$$
	rm -f $SCP_FAIL_FILE
	CMD=" /bin/ksh ACT=$ESOM_PHASE $_R/$SMDB/$ESOM_SUBSET.scp $@ || touch $SCP_FAIL_FILE"
	Log "$ESOM_SUBSET SCP $ESOM_PHASE $@ on $ESOM_TARGET"
	if [ "$ESOM_TARGET" = "$ESOM_SELF" ]
	then
		eval $CMD
		# check if scp failed
		if [ -f $SCP_FAIL_FILE ]
		then
			SCP_STATUS=2
		else
			SCP_STATUS=0
		fi
	else
		[ "$ESOM_CACHE_MEM_ID" = "$ESOM_TARGET" ] ||
		{
			ESOM_TARGET_NUM=`echo $ESOM_TARGET | sed s/member//`
			set -- `clu_get_info -raw 2> /dev/null \
				| grep '^M:'$ESOM_TARGET_NUM':' \
				| awk -F: '{print $3,$6}'`
			ESOM_CACHE_MEM_ID=$ESOM_TARGET
			ESOM_CACHE_HOSTNAME="$1"
			ESOM_CACHE_STATUS="$2"
		}

		if [ "$ESOM_CACHE_STATUS" = "UP" ]
		then
			rsh $ESOM_CACHE_HOSTNAME "$CMD"
			# check if scp failed
			if [ -f $SCP_FAIL_FILE ]
			then
				SCP_STATUS=2
			else
				SCP_STATUS=0
			fi
		else
			#
			# That member is down -- cannot run anything
			# on it.
			#
			SCP_STATUS=100
		fi
	fi

	rm -f $SCP_FAIL_FILE
	return $SCP_STATUS
}


:	-Exit
#		Leave the program
#
#	given:	$1 - exit status
#	does:	leave program performing any needed cleanup
#	return:	no

Exit()
{
	STAT=$1
	
	# If ADVFLAG or UPDFLAG is defined and we are loading a product
	# other than BASE, then the control file for this product
	# has been mounted on $_TDIR. Since we are leaving, unmount
	# this directory.
	[ "$_MTDIR" ] &&
		umount $_TDIR

	Cleanup
	# restore saved tab settings
	stty $tabsave 2>/dev/null

	#
	# End the automatic ticking which was started to
	# show progress during state transisitons
	# 
	INST_SendStatusBarCommand "tickevery end"

	sync
	exit $STAT
}


:	-Extract
#		extract subsets from media
#
#	given:	$* - names of specific subsets to extract
#	does:	Extract subsets from the media for use by
#		remote installation service.
#	return: 0 if all goes well
#		1 if mandatory/ROOT extraction failure
#		2 if optional extraction failure

Extract()
{
	#% Binding
	SBS=$*		# subsets to be installed

	#% Local Variables
	EISSUB=		# extraction element is a subset {0,1}
	ELOC=		# Extraction element tape location (x:y)
	ENAME=		# Extraction element name
	EOPT=		# extraction element optionality value
	EXTL=		# EXTraction List

	#% Local Code
	[ "$DEFPATH" = 0 ] && cd $_R

	Wait MTPID ||
	{
		DEFMSG="Tape Positioning Error."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			EXTRACT_TAPE_POS_ERR \
			\"$DEFMSG\"`"
		return 1
	}

	# make sure there is an instctrl directory
	[ -d instctrl ] ||
		mkdir instctrl

	# get image and comp file
	cp $_TDIR/*.image $_TDIR/*.comp instctrl 2> /dev/null
	touch instctrl/*.image

	# Establish an extraction list.  This lists each object to be
	# extracted, its media location, whether it is optional, and
	# whether it is an actual subset or a proprietary tape file.
	# At the same time, create a grep -E mask to be used to generate
	# a checksum comparison file.
	# The -h option is added to grep to remove filename prefix of
	# the image files in case there are more than one.  (QAR 74766)
	EXTL=
	ENAME=`grep -h -E '[[:space:]]h?ROOT[[:space:]]*$' instctrl/*.image` &&
	{
		set xx $ENAME; shift
		ENAME=$3
		# dummy out an entry that looks like a subset would
		EXTL="$ENAME:1:-1:0:0:$1"
	}
	# build entries for the rest of the subsets
	for ENAME in $SBS
	{
		ReadCtrlFile $_TDIR $ENAME
		EOPT=`FlagsAttrCheck SATTR_OPTION $FLAGS`
		SUM=`grep -h -E $ENAME instctrl/*.image`
		set xx $SUM; shift
		SUM=$1
		EXTL="$EXTL $ENAME:$MTLOC:$EOPT:1:$SUM"
	}
	OPTERR=0
	# create empty files
	> checksums; > mandatory; > all
	> $TMP1
	for EXTENT in $EXTL
	{
		set xx `Parse : $EXTENT`; shift
		ENAME=$1 EVOL=$2 ELOC=$3 EOPT=$4 EISSUB=$5
		Log "$ENAME \c"
		DEFMSG="Extracting %s..."
		echo "`message -S setld.cat -s SETLD3 \
			EXTRACT_EXTRACTING \
			\"$DEFMSG\" \"$ENAME\"`"

		# read the media.....
		case "$_MEDIA" in
		tape)
			PositionTape $EVOL $ELOC ||
			{
				DEFMSG="Error Extracting %s"
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD3 \
					EXTRACT_EXTRACTING_ERR  \
					\"$DEFMSG\" \"$ENAME\"`"
				rm -f checksums mandatory all
				return 1
			}
			TickWhile "dd if=$RAW of=$ENAME bs=20b 2> /dev/null" ||
			{
				DEFMSG="Error Extracting %s"
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD3 \
					EXTRACT_EXTRACTING_ERR  \
					\"$DEFMSG\" \"$ENAME\"`"
				rm -f checksums mandatory all
				return 1
			}
			_CPOS=`expr $_CPOS + 1`
			;;
		disk)
			if [ -f $_SRC/$ENAME ]
			then
				[ -d ./$CMP_DIR ] ||
					mkdir -p ./$CMP_DIR 2>/dev/null

				TickWhile "cp -p $_SRC/$ENAME ./$CMP_DIR" ||
				{
					DEFMSG="Error Extracting %s"
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD3 \
						EXTRACT_EXTRACTING_ERR  \
						\"$DEFMSG\" \"$ENAME\"`"
					rm -f checksums mandatory all
					return 1
				}
			else
				CURDIR=`pwd`
				cd $_MTPT
				Ticker on
				awk '{print $10}' $_TDIR/$ENAME.inv \
					| pax -r -w -d -p e $CURDIR ||
				{
					DEFMSG="Error Extracting %s"
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD3 \
						EXTRACT_EXTRACTING_ERR  \
						\"$DEFMSG\" \"$ENAME\"`"
					rm -f checksums mandatory all
					Ticker off
					cd $CURDIR
					return 1
				}
				Ticker off
				cd $CURDIR
				EISSUB=1
				DCD=yes
			fi
		esac

		[ $EISSUB = 1 ] &&
		{
			# subset specific operations:
			#  copy .ctrl, .inv, .scp for this subset into instctrl
			#  update mandatory, all
			for X in inv scp ctrl
			{
				cp -p $_TDIR/$ENAME.$X instctrl ||
				{
					DEFMSG="Control Info Error on %s"
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD3 \
						EXTRACT_CTRLINFO_ERR \
						\"$DEFMSG\" \"$ENAME\"`"
					rm -f all checksums mandatory
					return 1
				}
			}
			echo "$ENAME" >> all
			[ $EOPT = 0 ] && echo "$ENAME" >> mandatory
		}

		[ "$DCD" = yes ] && 
		{
			DEFMSG="SUCCEEDED"
			Log "`message -S setld.cat -s SETLD3 \
				LOG_SUCCEEDED_MSG \
				\"$DEFMSG\"`"
			continue
		}
			
		# checksum the image
		#  wait for previous checksum
		Wait SUMPID
		(
			echo "$ENAME	\c" >> $TMP1
			sum $ENAME >> $TMP1
		) &
		SUMPID=$!
		DEFMSG="SUCCEEDED"
		Log "`message -S setld.cat -s SETLD3 \
			LOG_SUCCEEDED_MSG \
			\"$DEFMSG\"`"
	}
	Wait SUMPID
	SUMLIST="$SUMLIST $SUM"

	[ "$DCD" = yes ] && 
	{
		DEFMSG="Media extraction complete."
		echo "`message -S setld.cat -s SETLD3 \
			EXTRACT_MEDIA_EXTRACT \
			\"$DEFMSG\"`"
		return 0
	}
	
	[ "$_MEDIA" = tape ] &&
	{
		mt -f $RAW rew &
		MTPID=$!
		_CPOS=-$T_0
	}

	for EXTENT in $EXTL
	{
		# get subset name
		set xx `Parse : $EXTENT`; shift
		ENAME=$1
		ESUM=$6
		set xx `grep -E $ENAME $TMP1`; shift
		SSUM=$2
		shift
		SUMLIST=$*
		[ "$ESUM" = "$SSUM" ] ||
		{
			DEFMSG="%s: extract checksum error"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				EXTRACT_CHECKSUM_ERR \
				\"$DEFMSG\" \"$ENAME\"`"
		}
	}

	# rm -f mandatory compare checksums csd all &

	DEFMSG="Media extraction complete."
	echo "`message -S setld.cat -s SETLD3 \
		EXTRACT_MEDIA_EXTRACT \
		\"$DEFMSG\"`"
	return 0
}


:	-Ferror
#		Fatal Error
#
#	given:	$1 - Exit status
#		$2 - Error Message
#	does:	print error message and Exit with status

Ferror()
{
	STAT=$1
	Error "$2"
	Exit $STAT
}


:	-FlagsAttrCheck
#		check flags attribute
#
#	given:	$1 - flag attribute to check
#		$2 - word to check in
#	does:	check the value of the $1 flag in $2
#	return:	0 if flag is clear, 1 if set
#
#	note:	FLAGS bitmask is defined as follows:
#		
#		Bit 	Value
#		---	-----
#		 0	set = subset is sticky 
#			clear = subsets removable 
#		 1	set = subset is optional 
#			clear = subset is mandatory 
#		 2	set = subset is in DCD (expanded) format
#			clear = subset is a compressed archive

FlagsAttrCheck()
{ (
	ATTR=$1
	FLAG=$2

	case "$ATTR" in
	SATTR_STICKY)
		VAL=$FLAG
		;;
	SATTR_OPTION)
		VAL=`expr $FLAG / 2`
		;;
	SATTR_DCD_SUBSET)
		VAL=`expr $FLAG / 4`
		;;
	*)	DEFMSG="FlagsAttrCheck: %s: unknown attribute type"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			FLAGSATTRCHECK_UNKNOWN_ATTRTYPE  \
			\"$DEFMSG\" \"$ATTR\"`"
		Exit 1
	esac

	expr $VAL % 2
) }


:	-GetCompAttr
#		determine compression status of a subset
#
#	given:	a subset name
#	does:	determines whether the subset is compressed
#	return:	0 for a compressed subset
#		1 for a non-compressed subset

GetCompAttr()
{ (	S=$1

	cd $_TDIR
	NameParse X_ $S
	[ -f $X_P$X_V.comp ]
) }


:	-InitDevice
#		Initialize the installation device
#
#	given:
#	does:
#	return:
#

InitDevice()
{
        _MEDIA=         # media type - tape, diskette, disk, inet
        _SRC=           # unit - server name, /dev/xxx, install path
        _LOC=           # location where the savesets are stored, can be
                        # path name, host name or tape
	_MTPT=		# mount point for the distribution

	[ -d $DEVICE ] &&
	{
		_MEDIA=disk
		_SRC=$DEVICE
		_LOC=$_SRC

		# stabilize the pathname
		case "$_SRC" in
		/*)	;;
		*)	_SRC=`(cd $_SRC;/bin/pwd)`
		esac

		# Look to see if a file <PRODUCT NAME>.root exists in
		# the instctrl directory. If there is one, then we use this
		# file to determine the root of the kit we are loading.
		#
                if [ -f $_SRC/instctrl/*.root ]; then
			_MTPT=`cd $_SRC/\`cat $_SRC/instctrl/*.root 2>/dev/null\`;/bin/pwd`
		else
			# get the mount point of the disk
			_MTPT=`df $DEVICE | tail -1 | awk '{print $6}'`
		fi

		DEFMSG="Loading from %1\$s (%2\$s)"
 		Log "`message -S setld.cat -s SETLD3 \
			INITDEVICE_LOADING_LOG \
			\"$DEFMSG\" \"$_LOC\" \"$_MEDIA\"`"
		return 0
	}

	# get the media type.
	case "$DEVICE" in
	*::)	#
		DEFMSG="%s - DECnet installation not supported"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			INITDEVICE_DECNET_NOSUPPORT \
			\"$DEFMSG\" \"$DEVICE\"`"
		return 1
		;;
	*:)	# TCP inet installation
		_MEDIA=inet
		# the 'unit-number' is the server hostname
		_SRC=`Parse : $DEVICE`
		_LOC=$_SRC

		#! error case should be handled with retries for goodies like
		#!  no inet ports, login limit reached.
		ERROR=`INST_RIS_ExecuteCommand $_SRC 'echo hello'`
	        [ "$ERROR" = 'hello' ] || 
		{
			DEFMSG="Error contacting server %1\$s: %2\$s"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				INITDEVICE_CONTACT_ERR \
				\"$DEFMSG\" \"$_SRC\" \"$ERROR\"`"
			return 1
		}
		;;

	*mt*[lmh])
		# some sort of tape device, get unit number and verify
		#  access to nrmt?h.
		_MEDIA=tape
		_SRC=`expr $DEVICE : '.*mt\([0-9][0-9]*\).*'`
		_LOC="/dev/nrmt${_SRC}h"
		_TAPE_PATH=nrmt
		_END_TAPE=h
		;;
		
	*mt*)	# tape device naming obsolete - xlate to 2.0
		_MEDIA=tape
		_SRC=`expr $DEVICE : '.*mt\([0-9][0-9]*\).*'`
		_SRC=`expr $_SRC % 4`	# this gets unit plug number.
		_TAPE_PATH=nrmt
		_END_TAPE=h
		;;

	*tape*) # Tape device under V5.0 and later.
		_MEDIA=tape
		_SRC=`echo $DEVICE | sed -e 's?/dev/n*tape/tape??'`
		_LOC="/dev/ntape/tape${_SRC}"
		_TAPE_PATH=/ntape/tape
		_END_TAPE=
		;;

	*ra*)	# ra, diskettes
		# get unit number
		_SRC=`expr $DEVICE : '.*ra\([0-9][0-9]*\).*'`

		_MEDIA=diskette
		_LOC=$_SRC
		ALTOP=+
		ALT=`expr $_SRC $ALTOP 1`
		# validate the existence of device files for
		# both the primary and alternate diskettes
		[ -c $D/rra${_SRC}a -a -c $D/rra${ALT}a ] ||
		{
			Error "`printf \"$E_NODEV\" \
				\"/dev/rra${U}a, /dev/rra${ALT}a\"`"
			return 1
		}
		;;

	*floppy*)	# Floppy diskette in V5.0 and greater
		_SRC=`expr $DEVICE : '.*floppy\([0-9][0-9]*\).*'`
		_MEDIA=diskette
		_LOC=$SRC
		ALTOP=+
		ALT=`expr $_SRC $ALTOP 1`
		_FLOPPY_PATH=disk/floppy
	
	esac

	case "$_MEDIA" in
	"")	# bogus device.
		DEFMSG="Device %s not supported for installations."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			INITDEVICE_NOSUPP_DEVICE \
			\"$DEFMSG\" \"$DEVICE\"`"
		return 1
		;;
	tape)	# do code for old and new style tapes
		RAW=$D/$_TAPE_PATH${_SRC}$_END_TAPE
		[ -c $RAW ] ||
		{
			Error "Cannot access $RAW"
			_MEDIA=
			return 1
		}
		while :
		do
			DEFMSG="\n\
Please make sure your installation tape is mounted and on-line."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				INITDEVICE_MOUNT_TAPE \
				\"$DEFMSG\"`"
			Ready
			mt -f $RAW rew && break
		done
		_CPOS=-$T_0
		;;
	esac
	DEFMSG="Loading from %1\$s (%2\$s)"
	Log "`message -S setld.cat -s SETLD3 \
		INITDEVICE_LOADING_LOG \
		\"$DEFMSG\" \"$_LOC\" \"$_MEDIA\"`"
}


:	-InitializeConstants
#		Initialize all constants to be used in setld
#
#	given:	arglist identical to invocation arglist
#	does:	initialize the constants used thruough the program.
#		all constants should be defined here.
#	return:	nothing

InitializeConstants()
{
	# Message Strings
	DEFMSG="File copy to system disk failed."
	E_FAIL="`message -S setld.cat -s SETLD1 E_FAIL_MSG \"$DEFMSG\"`"
	DEFMSG="Cannot create directory"
	E_MKDIR="`message -S setld.cat -s SETLD1 E_MKDIR_MSG \"$DEFMSG\"`"
	DEF_MSG="These device special files do not exist: %%s"
	E_NODEV="`message -S setld.cat -s SETLD1 E_NODEV_MSG \"$DEFMSG\"`"
	DEFMSG="Cannot recover"
	E_NORECOVER="`message -S setld.cat -s SETLD1 E_NORECOVER_MSG \"$DEFMSG\"`"
	DEFMSG="Attempt to read from your distribution media failed."
	E_READ="`message -S setld.cat -s SETLD1 E_READ_MSG \"$DEFMSG\"`"
	DEFMSG="*** Subset"
	E_STARS="`message -S setld.cat -s SETLD1 E_STARS_MSG \"$DEFMSG\"`"
	DEFMSG="Tape positioning error."
	E_TPOS="`message -S setld.cat -s SETLD1 E_TOPS_MSG \"$DEFMSG\"`"
	DEFMSG="Unknown subset"
	E_UNKNOWN="`message -S setld.cat -s SETLD1 E_UNKNOWN_MSG \"$DEFMSG\"`"
	DEFMSG="%%s: no such file or directory"
	ENOENT="`message -S setld.cat -s SETLD1 ENOENT_MSG \"$DEFMSG\"`"
	DEFMSG="Installation Control"
	IC="`message -S setld.cat -s SETLD1 IC_MSG \"$DEFMSG\"`"

	# the usage messages
	DEFMSG="Send a configuration message to an installed subset: \n\
	setld [-D dir] -c subset message"
	CUSAGE="`message -S setld.cat -s SETLD1 CUSAGE_MSG \"$DEFMSG\"`"
	DEFMSG="Delete subsets: \n\
	setld [-D dir] [-f] -d subset [subset ...]"
	DUSAGE="`message -S setld.cat -s SETLD1 DUSAGE_MSG \"$DEFMSG\"`"

	DEFMSG="\n\
Setld Usage Examples:\n\
\n\
Configure install subsets on a single cluster member:\n\
	setld [-D dir] [-m member-id] -C subset [subset ...]\n\
\n\
%1\$s\n\
\n\
%2\$s\n\
\n\
List all subsets: \n\
	setld [-D dir] -i\n\
\n\
List contents of installed subsets: \n\
	setld [-D dir] -i subset [subset ...]\n\
\n\
Display this message:\n\
	setld [-D dir] -h \n\
\n\
Load layered product from device: \n\
	setld [-D dir] [-m member-id] -l device [subset...]\n\
\n\
Verify integrity of subsets: \n\
	setld [-D dir] -v subset [subset ...]\n\
\n\
Cluster roll additional member:\n\
	setld [-D dir] [-m member-id] -u subset [subset ...]\n\
\n\
Extract media images from device for network distribution:\n\
	setld [-D dir] -x device [subset...]\n\
\n\
Configure delete subsets on a single cluster member:\n\
	setld [-D dir] [-m member-id] -Z subset [subset ...]\n\
\\\n"
	USAGE="`message -S setld.cat -s SETLD1 USAGE_MSG \
		\"$DEFMSG\" \"$CUSAGE\" \"$DUSAGE\" `"

#       The year field descriptor is Y to indicate the full year as a decimal
#       number.  This will resolve the year 2000 issue.
	DATFMT="+%Y.%m.%d.%T"		# format specifier for date command

	PROG=setld			# program name
	T_0=3				# control file tape offset

	#
	# path name constants
	#
	A=adm
	CLUSTER=cluster/members
	D=/dev
	E=etc
	I=it.d
	S=sbin
	SID=$S/$I/data			# location for data file used by "it"
	T=tmp
	U=usr
	SMDB=$U/.smdb.			# _s_oftware _m_anagement _d_b_
	V=var
	_TDIR=/$V/$T/stltmp$$		# Used to point to the instctrl
					# directory of the product to be
					# installed.
	_TMPDIR=/$V/$T/tmp$$		# temporary directory for init. inst.
	RISPATH=/$V/$A/ris		# standard ris home path on ris server
	RISMAP=$_TMPDIR/rismap		# working copy of rismap file
	rm -f $RISMAP
	SINFO_WORK=/$V/$T/workout$$	# temporary output file for setld -s
	BLKBORD=/$V/$T/setld		# block board area for -a, -s, and -p
                                        # NOTE: this area is referred by UIs
	SINFO_UI=$BLKBORD/setld-s.outdone     # output file for user interfaces
	INSTLD_CLI=/$V/$T/instldcli_info$$ #temporary output file for stlmenu installed subsets info
	SUIT_INFO_MAND=/$V/$T/suitgui_mand #temporary output file for setld -S
	SUIT_INFO_OPT=/$V/$T/suitgui_opt #temporary output file for setld -S
	SUIT_INFO_DIR=/$V/$T/suitgui_dir #temporary output file for setld -S
	INSTLD_GUI=/$V/$T/instldgui_info #temporary output file for setld -I

	MAND_FILE=/$V/$T/mandfile$$     # file for mandatory subsets list
	OPT_FILE=/$V/$T/optfile$$       # file for optional subsets list
	PCODES_THAT_MUST_ROLL="
		IOS
		OSF
		OSH
		TCR
	"
	MUST_ROLL_GREP_EXP=`echo $PCODES_THAT_MUST_ROLL \
		| fmt -1000 \
		| tr ' ' '|'`
	PREMRG_FILE=${PREMRG_FILE:-/var/adm/smlogs/upd_PreMRG_files}
	PREMRG_LIST=${PREMRG_LIST:-$_TMPDIR/PreMRG_list}
	PASSMRG_LIST=${PASSMRG_LIST:-$_TMPDIR/PassMRG_list}

	CLUSTER_INFO=$_TMPDIR/clus_info_file	# temp output file 
						# for clu_get_info
	[ -f /usr/sbin/clu_get_info ] &&
		clu_get_info > /dev/null 2>&1 && TCR_FLAG=1
	MEMBERS_N_STATUS=$_TMPDIR/mem_status

	# Define the MEMBER_ID variable to be the numerical identifier
	# returned by the kernel, prefixed by the string "member".  If 
	# the kernel does not return a numerical identifier (pre-Steel 
	# kernel), define the number as "0".  Therefore, the 
	# MEMBER_ID string will always be "memberXXX" where XXX is 
	# either the kernel number or 0.  This variable is also used
	# in the MRG_SetFileVariables routine which is sourced from
	# libmrg.
	#
	[ ! "$MEMBER_ID" ] && MEMBER_ID=`INST_CLU_GetMemberID`

	#
	# log file constants
	#
	CINSTDATA=$SID/cinst.data	# ordered subset list for "it"
	CSETLDCDATA=./$CLUSTER/member0/$SID/setld_C.data	# member-id and 
					# subset list for setld_C "it"
	LOGDIR=$V/$A/smlogs		# location for log file
	FVERIFYLOG=$LOGDIR/fverify.log
	FITSETLOG=$LOGDIR/fitset.log
	DF_LOG=${DF_LOG:-$LOGDIR/df.log}
					# df log during subset load
	LOGFILE=/$LOGDIR/setld.log 	# default logfile
	RETRYFILE=/$V/$T/retrylist      # Successfully installed subset list.
	MENU=$_TMPDIR/menu		# contains user selection from menu.
	UPDMRGLOG=${UPDMRGLOG:-$LOGDIR/upd_mergefail_files}
					# contains files that failed to
					# merge in update installation.
	ZSETLDCDATA=./$CLUSTER/member0/$SID/setld_Z.data	# member-id and 
					# subset list for setld_Z "it"

	[ ! "$CHECK_SYNTAX" ] &&
	{
		# interactive debugging turned off, mark all constants
		#  as read only - please insert here in the order in which
		#  they are defined above

		readonly E_READ E_STARS E_TPOS E_UNKNOWN ENOENT
		readonly E_FAIL E_MKDIR E_NODEV E_NORECOVER
		readonly IC CUSAGE DUSAGE USAGE
		readonly PROG T_0 A D E T U SMDB V
	}

}



:	-InitializeGlobals
#		Initialize default values for all global variables
#
#	given:	nothing
#	does:	sets starting values for the global values used in
#		setld. All global variables should be defined here.
#	return:	nothing

InitializeGlobals()
{
	_CVOL=1				# currently mounted tape volume
	_R=/				# default install root (_R for root)
	export _R
	DATE=				# current date
	DECOMP=cat			# decompression program
	DEFPATH=1			# flag - installing to default root
	MTPID=				# mag tape async op pid
	RISC_B="^OSF"			# RISC base system product definition
	RISC_WS="^OSF"			# RISC UWS product definition
	STAT=1				# default exit status
	TMP1=$_TMPDIR/tmp1$$		# scratch file	
	TMP2=$_TMPDIR/tmp2$$		# scratch file	
	VAX_B="^ULT"			# VAX base system product definition
	VAX_WS="^UWS"			# VAX UWS product definition
	VBSE=				# default tar verbose switch
	WLS_B="^IOS"			# WLS base system product definition
}


:	-Install
#		Install subsets
#
#	given:	$* - list of subsets to be installed
#	does:	calls LoadFromMedia() and PostLoad()/Configure() to install 
#		the software
#	return:	0 if all subsets install correctly
#		1 (immediately) on LoadFromMedia mandatory subset failure
#		2n for n optional failures
#		

Install()
{
	OPTERRS=0		# Initialize subset failure indicator
	SCPLIST=		# subsets that survive LoadFromMedia() 
	RETRYLIST=		# Initialize successfully loaded subsets list
	INSTCNT=1
	CNT=0

	SUBS=$*

	InstallCanProceed $SUBS ||
		return 2

	STOTCNT=$#
	DEFMSG="\n%s subsets will be installed."
	echo "`message -S setld.cat -s SETLD1 \
		SUBSETNUM_MSG \"$DEFMSG\" \"$STOTCNT\" `"

	# load the bits
	for _S
	{
                # Added a counter for each subset in the list so that
                # as each is loaded the number is incremented.  When
                # users see 5 of 20 it means that the 5th subset in
                # the list is being loaded and not that there are 5
                # successfully installed subsets. (QARs #44240 & #47620)
                #
                CNT=`expr $CNT + 1`
		DEFMSG="%1\$s of %2\$s"
		COUNT_MSG="`message -S setld.cat -s SETLD1 \
			COUNT_MSG \"$DEFMSG\" \"$CNT\" \"$STOTCNT\" `"
                DEFMSG="\nLoading subset %s ..."
		echo "`message -S setld.cat -s SETLD1 \
			LOADSUBSET_MSG \"$DEFMSG\" \"$COUNT_MSG\" `"

 		[ "$FITSET_DEBUG" ] && LogDiskspace "Before LoadFromMedia $_S" 

		LoadFromMedia $_S
		LOADMEDIASTATUS="$?"

 		[ "$FITSET_DEBUG" ] && LogDiskspace "After LoadFromMedia $_S" 

		case "$LOADMEDIASTATUS" in
		0)	SCPLIST="$SCPLIST $_S"	# all's OK

			# keep current count of installed subsets
			INSTCNT=`expr $INSTCNT + 1`

			# move .upd.. into real name space and update .inv
			# do it here instead of in PostLoad() to avoid
			# accumulating all the .upd.. and wasting disk space.
			MoveUpd $_S

 			[ "$FITSET_DEBUG" ] && LogDiskspace "After Moveupd $_S" 

			;;
		1)	OPTERRS=1		# MAND (fatal)
			break
			;;
		*)	OPTERRS=`expr $OPTERRS + 2`	# OPT (non-fatal)
		esac

		#
		# Tick the status bar 1 extra tick if the subset load
		# failed.  The reason for this is that the status bar
		# will be expecting a tick for the status transition
		# phase of this subset.  However, since the load failed
		# the state transition phase will not be run and the
		# tick will never be sent.  So, send it now so that
		# the status receives the correct number of ticks.
		#
		[ "$LOADMEDIASTATUS" != 0 ] &&
			INST_SendStatusBarCommand "tick 1"
	}
	INSTCNT=`expr $INSTCNT - 1`
	DEFMSG="\n%1\$s of %2\$s subsets installed successfully.\n"
	echo "`message -S setld.cat -s SETLD1 \
		INSTCNT_MSG \"$DEFMSG\" \"$INSTCNT\" \"$STOTCNT\"`"
   
	#
	# Put out a message for ToProto phase.
	#
	[ "$UPDFLAG" -o "$UPD_HWFLAG" ] && {
		#
		# Get the product name from the .ctrl file
		#
		STARTNAME=`cat $SMDB/$_S.ctrl | grep NAME= | sort -u`
		NAME=`expr "$STARTNAME" : 'NAME=.\(.*\).$'`

		#
		# Output a header so we know that this is the start of
		# the ToProto merge phase during update install.
		#
		DEFMSG="\n\n*** Starting protofile merges for %s ***\\\n"
		echo "`message -S setld.cat -s SETLD1 \
			START_PROTOFILE_MRG_MSG \"$DEFMSG\" \"$NAME\"`"
	}

	# state transitions
	# Note: even with fatal error, we still need to complete state 
	# transitions for subsets previously successfully installed since
	# .lk was already created in LoadFromMedia() (QAR 14757).
	for _S in $SCPLIST
	{
		DEFMSG="Performing state transitions for %1\$s on %2\$s"
		STATUS_OUTPUT="`message -S setld.cat -s SETLD1 \
			INSTALL_STATUS_MSG1 \"$DEFMSG\" \
			\"$_S\" \
			\"$MEMBER_ID\"`"
		INST_SendStatusBarCommand "message $STATUS_OUTPUT"

		# further update installation merge optimization
		[ "$UPDFLAG" ] && {
			UpdMoreOpt $_S
		}

		# transition to proto state and call scp with POST_L
		PostLoad $_S ||
		{
			INST_SendStatusBarCommand "tick 1"
			continue
		}

		#
		# Tick the status bar even though the state transition
		# failed, since the bar is expecting the tick and we
		# do not want to have missing ticks.
		#
		INST_SendStatusBarCommand "tick 1"

		# Add subset to list of successfully loaded subsets.
		RETRYLIST="$RETRYLIST $_S"

		# if installing without specifying -D, configure subset
		# now, i.e., transition to config state. 
		if [ "$DEFPATH" = 1 ] 
		then
			SAVE_MEMBER_ID=$MEMBER_ID
			MEMBER_ID="member0"         # QAR 79604
			Configure $_S INSTALL 
			MEMBER_ID=$SAVE_MEMBER_ID
		else
			# Delay configuration, record subset in $CINSTDATA
			# so it can be configured later with setld -c
			#
			if [ "$TCR_FLAG" ]
			then
				INST_CLU_OnEachMember INST_UniqueWordList \
					-nosort -add "$_S" $_R/$CINSTDATA
			else
				INST_UniqueWordList \
					-nosort -add "$_S" $_R/$CINSTDATA
			fi
		fi
	}

	#
	# Put out the ticks for the proto phase.  The number of
	# ticks assigned to the proto phase is exported from the
	# script calling setld.
	#
	[ "$UPDFLAG" ] && {
		#
		# Output a message so we know that this is the end of
		# the ToProto merge phase during update install.
		#
		DEFMSG="\n\n*** Finished protofile merges for %s ***\\\n"
		echo "`message -S setld.cat -s SETLD1 \
			FINISH_PROTOFILE_MRG_MSG \"$DEFMSG\" \"$NAME\"`"
	}

	#
	# Write list of successfully loaded subsets.
	# Only create file if invoked from full or
	# update installation AND if there were errors.
	#
	if [ "$OPTERRS" -gt 0 ] && [ "$ADVFLAG" -o "$UPDFLAG" ]
	then
		echo "$RETRYLIST" > $RETRYFILE
	fi

	PostClusterCheck && 
	{
		# Copy member-specific files from member0 to other members.
		# Only copy files of subsets that were sucessfully loaded.
		awk '{print $1}' $MEMBERS_N_STATUS |
		while read MEMBER_NUM
		do
			MEMBER_ID="member"$MEMBER_NUM
			# copy member0 files of successfully load subsets
			# to the specific member
			PopulateMember $RETRYLIST || 
				Exit $?
		done

		# When population is done create an it.d script file for
		# each member to do a PostLoad & Configuration at a later
		# time if the member is down now.
		# Remotely execute the setld -C option on all the members.
		#
		RemoteMemberFunction "C" "$RETRYLIST"
	}

	return $OPTERRS
}


:	-InstallCanProceed
#		Determine if it's okay to load the named subsets.
#
#	given:	$* - the subsets we're trying to load
#	does:	Checks for various conditions when subsets should
#		not be loaded.
#	return:	0 if it's okay to load the subsets; otherwise 1.

InstallCanProceed()
{
	_SUBS=$*

	# Installation is always permitted if we are not on a
	# cluster that is in the process of doing a rolling
	# upgrade.
	#
	INST_CLU_RollIsInProgress ||
		return 0

	# Even on a cluster that's rolling, it's okay to install
	# to an alternate root directory.
	#
	if [ "$DEFPATH" = "0" ]
	then
		return 0
	fi

	# During a cluster roll-additional-member operation, no subsets
	# should be loaded.  Instead, subset member-specific files
	# should be propagated to the target member via "setld -u".
	#
	if [ "$UPD_MEM_FLAG" ]
	then
		DEFMSG="Subsets cannot be loaded during a cluster
roll additional member operation.  Instead use \"setld -u\" to
propagate member-specific files."
		Error "`message -E -S -V 500 \
			-F installsetld \
			setld.cat -s SETLD5 \
			INSTALL_DURING_ROLL_ADDITIONAL \
			\"$DEFMSG\"`"
		return 1
	fi

	# During a cluster roll-first-member operation, the only subsets
	# that can be loaded are from the products that must roll.
	#
	if [ "$UPDFLAG" -o "$UPD_HW_FLAG" ]
	then
		AllSubsetsMustRoll $_SUBS &&
			return 0

		# This should never happen in normal operation.  It
		# will be seen if a new product is rolled by update
		# without being added to PCODES_THAT_MUST_ROLL.
		#
		DEFMSG="During a cluster roll-first-member operation,
the only subsets that can be loaded are from these products:\n%1\$s"
		Error "`message -E -S -V 500 \
			-F installsetld \
			setld.cat -s SETLD5 \
			INSTALL_DURING_ROLL_FIRST \
			\"$DEFMSG\" \"$PCODES_THAT_MUST_ROLL\"`"
		return 1
	fi

	# Otherwise, we know we're not being invoked as part of
	# the roll process because none of the UPD* flag variables
	# are set.  Instead we're being invoked by the user, while
	# the cluster is in a roll state.
	#
	if AnySubsetMustRoll $_SUBS
	then
		# Decline the subset load.  The reasoning for this
		# is that the software gets out of sync and the old
		# subsets cannot be loaded on the new OS and the new
		# subsets cannot be loaded on the old OS.
		#
		DEFMSG="The following subsets cannot be installed
because a rolling upgrade is now in progress on this cluster:\n%1\$s"
		Error "`message -E -S -V 500 \
			-F installsetld \
			setld.cat -s SETLD5 \
			CANNOT_INSTALL_MUST_ROLL \
			\"$DEFMSG\" \"$MUST_ROLL\"`"
		return 1
	fi

	# Before interactively asking the user if it's okay to
	# load the $_SUBS subsets during a roll, check if we're
	# loading the patch tools.  If so, don't ask -- just
	# do it.  (QAR #85733)
	#
	echo $_SUBS | grep -q "OSFPAT000000" &&
		return 0

	AllSubsetsMustRoll $_SUBS &&
	 	return 0

	# We know the cluster is in a roll state, and the user is
	# trying to load software from layered products which are
	# not required to roll.  This is not safe unless the layered
	# products have been qualified to work during a roll.  We
	# have to ask the user to check the product documentation
	# to confirm this is okay.  First we determine which of the
	# products being loaded is already present in a different
	# version.
	#
	_LP_ALREADY=
	_LP_LIST=`echo $SUBS \
		| fmt -1 \
		| sed 's/\(...\).*\(...\)/\1\2/' \
		| sort -u`
	for _LP in $_LP_LIST
	do
		set -- `echo $_LP | sed 's/^\(...\)/\1 /'`
		_LP_PCODE=$1
		_LP_PVER=$2

		_LP_HAVE_VER=`SWDB_FindInstalledVersions $_LP_PCODE` ||
			continue

		_LP_HAVE_VER=`echo $_LP_HAVE_VER \
			| fmt -1 \
			| grep -v $_LP_PVER`
		[ "$_LP_HAVE_VER" ] ||
			continue

		_LP_ALREADY="$_LP_ALREADY$_LP_HAVE_VER\n"
	done

	# Construct the menu we'll present to the user.
	#
	DEFMSG="
Because this cluster is partway through a rolling upgrade of the
operating system, it may not be safe to install additional software.
Please consult the product documentation for the software you are
trying to install, to determine if it is known to be safe in a
rolling upgrade environment.  Then select one of these options:

1. Some of the software is not documented as being safe during a
cluster rolling upgrade.

2. All of the software is documented as safe to use on both the
old and new versions of the operating systems.
"
	_LP_MENU="`message -S -s SETLD5 setld.cat \
		ASK_INSTALL_LP_DURING_ROLL \"$DEFMSG\"`"
	_LP_MENU_MAX=2

	# If a previous version of the software is on the system,
	# add a menu entry to confirm that it's okay to have both
	# versions loaded at the same time.
	#
	if [ "$_LP_ALREADY" ]
	then
		DEFMSG="
3. This software is documented as being safe to use at the same
time as this other version that is already installed:\n\t%s
"
		_LP_PRESENT="`message -S -s SETLD5 setld.cat \
			MENU_LP_PREV_VERSION \"$DEFMSG\" $_LP_ALREADY`"

		_LP_MENU="$_LP_MENU\n$_LP_PRESENT"
		_LP_MENU_MAX=3
	fi

	# Append the final prompt for user input.
	#
	DEFMSG="
Enter your selection: "
	_LP_PROMPT="`message -S -s SETLD5 setld.cat \
		MENU_PROMPT \"$DEFMSG\"`"
	_LP_MENU="$_LP_MENU\n$_LP_PROMPT"

	# Loop to ask the user to pick an option for how to handle
	# the LP load.
	#
	_LP_MENU_BAD_INPUT=
	while true
	do
		# If previous iteration got bad input, complain.
		#
		if [ "$_LP_MENU_BAD_INPUT" ]
		then
			_LP_MENU_BAD_INPUT=

			DEFMSG="Please enter a number from 1 to %s."
			Error "`message -E -S -V 300 \
				-F installsetld \
				setld.cat -s SETLD5 \
				BAD_MENU_INPUT \
				\"$DEFMSG\" $_LP_MENU_MAX`"
		fi

		echo "$_LP_MENU\c"

		# If user enters ^D, assume the software should
		# not be loaded.
		#
		read _LP_ANS ||
			_LP_ANS="1"

		case "$_LP_ANS" in

		1)
			# User is unable to confirm that the software
			# is safe to load into a roll environment.  So
			# we won't load it.
			#
			DEFMSG="
This software should not be installed until the cluster rolling upgrade
is finished."
			message -S -s SETLD5 setld.cat \
				WAIT_UNTIL_ROLL_DONE "$DEFMSG"
			exit 1
			;;

		2)
			# User claims the software being loaded should
			# work on both old and new members.
			#
			# If there's no previous version of this software
			# currently installed, then we can load it.
			#
			[ "$_LP_ALREADY" ] ||
				return 0

			# Otherwise, must remove older version before
			# installing the new one.
			#
			DEFMSG="
Before installing this software, you must delete the other version
or versions that are already installed:\n%1\$s"
			Error "`message -E -S -V 400 \
				-F installsetld \
				setld.cat -s SETLD5 \
				DELETE_OLD_LP_FIRST \
				\"$DEFMSG\" $_LP_ALREADY`"
			return 1
			;;

		3)
			# Did user enter "3" when the menu only had
			# two choices?
			#
			if [ $_LP_MENU_MAX -lt 3 ]
			then
				_LP_MENU_ERR=1
				continue
			fi

			# User claims the software being loaded can be
			# used, even when an older version is already
			# present.  Our job now is to ensure the older
			# version's inventory is tagged, so loading
			# the new version does not wipe it out.  Here
			# we test each old product version to confirm
			# it has tagged files.
			#
			_LP_NOT_TAGGED=
			for _LP in $_LP_ALREADY
			do
				INST_CLU_ProductIsTagged $_LP ||
					_LP_NOT_TAGGED="$_LP_NOT_TAGGED $_LP"
			done

			# If any product we're loading has a different
			# version already on the system, and that old
			# version is not tagged, we reject the load.
			#
			if [ "$_LP_NOT_TAGGED" ]
			then
				DEFMSG="
The following software already on your system is not ready for a
different version to be installed: %1\$s
You must use the clu_upgrade utility to create tagged files for
this software, and then reboot the cluster members that are still
running the old version of the operating system.  Once they have
rebooted, you will be able to install the new software.
"
				Error "`message -E -S -V 400 \
					-F installsetld \
					setld.cat -s SETLD5 \
					OLD_LP_NOT_TAGGED \
					\"$DEFMSG\" $_LP_NOT_TAGGED`"
				return 1
			fi

			return 0
			;;

		*)
			_LP_MENU_ERR=1
			;;
		esac
	done

	return 0
}


:	-Inventory
#		product inventory listings
#
#	given:	$* - which subsets to inventory, if empty will provide
#		a list of all known subsets and subset status
#	does:	see given
#	return:	0

Inventory()
{ (
	_S=	# current subset name
	LIST=	# list of all known subsets

	cd $_R/$SMDB

	[ "$*" ] &&
	{
		set `Ucase $*`
		ERR=0
		for _S
		{
			[ -f $_S.inv ] ||
			{
				Error "$_S: $E_UNKNOWN"
				ERR=1
				continue
			}
			awk '{print $10}' $_S.inv
		}
		return $ERR 
	}

	LIST=`echo *.ctrl | sed 's/\.ctrl//g'`

	[ "$LIST" = '*' ] && 
	{
		DEFMSG="No subset information available in %1\$s/%2\$s"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			INVENTORY_NOINFO_MSG \
			\"$DEFMSG\" \"$_R\" \"$SMDB\"`"
		return 1
	}

	#
	# Generate the report header
	#
	DEFMSG="Subset"
	SUBSET_HEADER="`message -S setld.cat -s SETLD1 \
		REPORT_SUBSET_HEADER_MSG \"$DEFMSG\"`"
	DEFMSG="Status"
	STATUS_HEADER="`message -S setld.cat -s SETLD1 \
		REPORT_STATUS_HEADER_MSG \"$DEFMSG\"`"
	DEFMSG="Description"
	DESC_HEADER="`message -S setld.cat -s SETLD1 \
		REPORT_DESC_HEADER_MSG \"$DEFMSG\"`"

	#
	# Determine the number of dashes that fit each of the header
	# strings.
	#
	SUBSET_DASHES=`INST_GetDashes $SUBSET_HEADER`
	STATUS_DASHES=`INST_GetDashes $STATUS_HEADER`
	DESC_DASHES=`INST_GetDashes $DESC_HEADER`

	#
	# This is the default line format used for each 
	# subset in the setld -i output.
	#
	LINE_DEFMSG="%-20s %-22s %s\n"

	#
	# Output the header line
	#
	# FIXME: the message command does not like %-20s, so 
	#	 hardcode the format until it is fixed.
	#
	#	echo "`message -S setld.cat -s SETLD1 \
	#		GENERATE_REPORT_LINE_MSG \
	#		\"$LINE_DEFMSG\" \
	#		\"$SUBSET_HEADER\" \
	#		\"$STATUS_HEADER\" \
	#		\"$DESC_HEADER\"`"
	#
	printf "$LINE_DEFMSG" "$SUBSET_HEADER" "$STATUS_HEADER" "$DESC_HEADER"

	#
	# Output the dashes for the header line
	#
	# FIXME: the message command does not like %-20s, so 
	#	 hardcode the format until it is fixed.
	#
	#	echo "`message -S setld.cat -s SETLD1 \
	#		GENERATE_REPORT_LINE_MSG \
	#		\"$LINE_DEFMSG\" \
	#		\"$SUBSET_DASHES\" \
	#		\"$STATUS_DASHES\" \
	#		\"$DESC_DASHES\"`"
	#
	printf "$LINE_DEFMSG" "$SUBSET_DASHES" "$STATUS_DASHES" "$DESC_DASHES"

	for _S in $LIST
	{
		#
		# Get the status string to display to the user
		#
		STATUS=`SWDB_GetStatusMessage $_S`

		#
		# Get the subset description
		#
		ReadCtrlFile . $_S 2> /dev/null || 
		{
			# if .ctrl is incomplete, subset is incomplete 
			DEFMSG="incomplete"
			STATUS="`message -S setld.cat -s SETLD4 \
				STATUS_INCOMPLETE_MSG \
				\"$DEFMSG\"`"			
		} 
		DESC=`echo $DESC | sed 's/\(.*\)%\(.*\)/\1(\2)/'`

		#
		# Output the line for this subset
		#
		# FIXME: the message command does not like %-20s, so 
		#	 hardcode the format until it is fixed.
		#
		#	echo "`message -S setld.cat -s SETLD1 \
		#		GENERATE_REPORT_LINE_MSG \
		#		\"$LINE_DEFMSG\" \
		#		\"$_S\" \
		#		\"$STATUS\" \
		#		\"$DESC\"`"
		#
		printf "$LINE_DEFMSG" "$_S" "$STATUS" "$DESC"
	} 

	return 0
) }

:       -InventoryCLI
#               product inventory listings for CLI - stlmenu
#
#       does:   Create the $INSTLD_CLI file containing a list of
#		all subsets loaded on the system, including those
#		that have not finished running all the SCP phases
#		for the load.
#
#       return: 0 on success; otherwise 1.

InventoryCLI()
{(
	INSTLIST=`SWDB_FindLoadedSubsets`
	[ "$INSTLIST" ] ||
	{
		DEFMSG="No subset information available in %1\$s/%2\$s"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			INVENTORYCLI_NOINFO_MSG \
			\"$DEFMSG\" \"$_R\" \"$SMDB\"`"
		return 1
	}


	for _S in $INSTLIST
	{
		echo $_S >> $INSTLD_CLI
	}

	return 0
)}

:	-InventoryGUI
#		product inventory listings for SUIT GUI
#
#	does:	Create the $INSTLD_GUI file containing a list of all
#		subsets properly installed, plus information about
#		dependencies and disk space usage.
#
#	return:	0 on success; otherwise 1

InventoryGUI()
{ (
	cd $_R/$SMDB
	LIST=`SWDB_FindLoadedSubsets`
	[ "$LIST" ] ||
	{
		DEFMSG="No subset information available in %1\$s/%2\$s"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			INVENTORYGUI_NOINFO_MSG \
			\"$DEFMSG\" \"$_R\" \"$SMDB\"`"
		return 1
	}

	# Generate report

	for _S in $LIST
	{
		# set STATUS field 
		STATUS=

		# indicate if it installed correctly or damaged
		SWDB_IsInstalled $_S && STATUS="installed"
		SWDB_IsCorrupt $_S && STATUS="corrupt" # ica-12459

		ReadCtrlFile . $_S 2> /dev/null || 
		{
			# if .ctrl is incomplete, subset is incomplete 
			STATUS="incomplete"
		} 

		SDESC=`echo $DESC | sed 's/%.*//'`


		# bit 2 on flags means subset is optional
		case `FlagsAttrCheck SATTR_OPTION $FLAGS` in
		1)      STYPE="optional"
			;;
		*)      STYPE="mandatory"
		esac

		# Get dependent subsets from the .lk file

		DEPEND=
		DEPEND=`SWDB_ListLockingSubsets $_S | tr '\012' " "`

		CATAG=`echo $DESC | sed 's/.*%//'`

		echo {$_S} {$SDESC} {$CATAG} {$DEPEND} {$ROOTSIZE} {$USRSIZE} {$VARSIZE} {$STYPE} {$STATUS} >> $INSTLD_GUI


	} 
	return 0
)}


:	-ListProtectedSystemFiles
#               Given a subset inventory file, print on stdout
#               the names of any protected system files.  For
#               example, if an inventory record describes file
#               /usr/.new..spam we print /usr/spam on stdout.
#       given:  Name of inventory file.
#	return: nil

ListProtectedSystemFiles()
{
	[ "$XFLAG" ] && INST_SkipTracing begin

	#
	# If we're called for an empty or non-existent inventory
	# file, do nothing.  (QAR #85615)
	#
	[ -s "$1" ] ||
		return

	#
	# Notice we do the same grep twice.  This is not an error,
	# it is an optimization.  The first grep greatly reduces
	# the amount of input to the much slower awk command.  The
	# second grep eliminates entries where .new.. occurred
	# somewhere other than field 10 of the inventory record
	# (for example, as a link target).
	#
	grep -F /.new.. $1 |
		awk '{print $10}' |
		grep -F /.new.. |
		sed 's!/\.new\.\.!/!g'

	[ "$XFLAG" ] && INST_SkipTracing end
}


:	-LoadCtrlInfo
#		read the installation control information from the media
#	into $_TDIR
#
#	given:	global info
#		$_MEDIA - media type to read
#		$_SRC - unit to read from
#		$_TDIR - target directory
#	does:	read the control information required to perform the task
#		defined in $CMDSW into $_TDIR
#	return:	0 if everything goes well, 1 otherwise
#	effect:	sets SBS to list subsets installable from the media
#	note:	assumes that wd is the desired root

LoadCtrlInfo()
{
	case "$_MEDIA" in
	diskette)
		[ "$CMDSW" = "x" ] &&
		{
			DEFMSG="diskette media unsupported for -x"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADCTRLINFO_NOOPT_MSG \
				\"$DEFMSG\"`"
			return 1
		}

		DEFMSG=" \n\
Insert the %1\$s diskette for the software \n\
you wish to load on your system in %2\$s unit %3\$s.\\\n"
		echo "`message -S setld.cat -s SETLD1 \
			LOADCTRLINFO_INSERT_DISK_MSG \
			\"$DEFMSG\" \"$IC\" \"$_MEDIA\" \"$_SRC\"`"

		Ready

		(cd $_TDIR;tar xpf $D/$_FLOPPY_PATH${_SRC}a) > $TMP1 ||
		{
			DEFMSG=" \n\
Attempt to read from diskette drive %1\$s failed. \n\
\n\
Remove your diskette from %2\$s unit %3\$s."
			echo "`message -S setld.cat -s SETLD1 \
				LOADCTRLINFO_READ_FAIL_MSG \
				\"$DEFMSG\" \"$_SRC\" \"$_MEDIA\" \"$_SRC\"`"

			# flip unit numbers
			_SRC=`expr $_SRC $ALTOP 1`
			ALTOP=`ChOp $ALTOP`

			DEFMSG=" \n\
Insert the %1\$s diskette for the software \n\
you wish to load in %2\$s unit %3\$s. \n\
NOTE: we are trying the SAME DISKETTE again but in %4\$s unit %5\$s. \\\n"
			echo "`message -S setld.cat -s SETLD1 \
				LOADCTRLINFO_INSERT_DISK_AGAIN_MSG \
				\"$DEFMSG\" \
				\"$IC\" \"$_MEDIA\" \"$_SRC\" \"$_MEDIA\"  \"$_SRC\"`"

			Ready

			(cd $_TDIR;tar xpf $D/$_FLOPPY_PATH${_SRC}a) ||
			{
				DEFMSG="Cannot read control information"
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD1 \
					LOADCTRLINFO_CANNOT_READ_INFO_MSG \
					\"$DEFMSG\"`" 
				return 1
			}
		}
		;;
	disk)	# mounted directory contains subsets
		[ -d $_SRC/instctrl ] ||
		{
			Error "`printf \"$ENOENT\" $_SRC/instctrl`"
			return 1
		}
		[ -h $_SRC/instctrl ] &&
		{
			# If instctrl is a symlink, then this is not
			# the proper location. Fix _SRC so that it's
			# pointing to the right place.
			_SRC=`(cd $_SRC/instctrl; cd ..; pwd)`
		}
		if [ "$UPDFLAG" -o "$ADVFLAG" ]; then
			rm -rf $_TDIR
			_TDIR=$_SRC/instctrl
		else
			(cd $_SRC/instctrl; tar cf - *)|(cd $_TDIR; tar xpf -)
		fi
		;;
	inet)	[ $CMDSW = x ] &&
		{
			DEFMSG="network media not supported for -x"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADCTRLINFO_NONETMEDIA_MSG \
				\"$DEFMSG\"`" 
			return 1
		}

		cd $_R

		#
		# Get the client information from the RIS server.
		#
		IAM=`hostname`
		RISRECORD=`INST_RIS_GetClientInfo $_SRC $IAM`
		[ "$?" != 0 ] && return 1

		# break out the fields, save the sys-type,prod,...,prod
		#  section
		set xx `Parse : $RISRECORD`; shift
		RISDATA=$3

		# break the sys-type,prod,...,prod into parts
		set xx `Parse , $RISDATA`; shift
		_SYSTEM=$1
		shift
		# Products
		PRODUCTS=$*

		# turn on Ticker in case rsh takes a long time due to 
		# network traffic or too many product areas, etc.	
 		Ticker on

		# If UPDFLAG or ADVFLAG is set, read the rp_mapping file
		# from the server. This will tell us the name of the product
		# so that we can reference the correct inventory directory.
		if [ "$UPDFLAG" -o "$ADVFLAG" ]; then 

			rm -rf $_TDIR
			_TDIR=$LOCMNT/instctrl 

			# Read the rp_mapping file from the ris server
			# If one does not exist then just set TDIR to LOCMNT
			#
			FILE_EXIST=`INST_RIS_ExecuteCommand $_SRC \
				'ls $_SYSTEM/rp_mapping'`
			[ "$?" = "0" ] && {
				rcp ris@$_SRC:$_SYSTEM/rp_mapping \
					$_TMPDIR/rp_mapping
			}

			rm -f $RISMAP

			# If the variable SETLD_PROD_NAME is not defined,
			# assign it to BASE	
			#
			[ "$SETLD_PROD_NAME" ] ||
				SETLD_PROD_NAME=BASE

			# Look for an entry for the product in the rp_mapping
			# file. This will allow us to set the _TDIR correctly
			# except in the case of BASE, where we'll do what we
			# always did, because it's faster.
			#
			if [ -f $_TMPDIR/rp_mapping ]; then
				DIR=`grep -E $SETLD_PROD_NAME \
				$_TMPDIR/rp_mapping | awk -F: '{print $1}'`

				if [ "$DIR" ]; then
					# Check to make sure that the
					# client is registered for this product
					REGISTERED=`echo $PRODUCTS | grep -E "$DIR"`
					[ "$REGISTERED" ] ||
					{

						DEFMSG="Client not registered for %1\$s (%2\$s)"
						Ferror 1 "`message -E -S -V 600 -F installsetld \
							setld.cat -s SETLD1 \
							LOADCTRLINFO_CLNT_NOREGIST_MSG \
							\"$DEFMSG\" \
							\"$DIR\" \"$SETLD_PROD_NAME\" `"
					}

					[ "$SETLD_PROD_NAME" = "BASE" ] ||
					{
						# If the product being loaded is
						# not BASE, the product area
						# on the RIS server that
						# contains this product needs
						# to be mounted. We get the
						# mount point for the product
						# from the rp_mapping file.

						_MTDIR=`grep -E $SETLD_PROD_NAME $_TMPDIR/rp_mapping | \
						awk -F: '{print $2}'`
						_MTDIR=$_MTDIR/instctrl

						# Make _TDIR point to the
						# mount point.
						_TDIR=$LOCMNT/ALPHA

						# Mount the product area
						# on $_TDIR.
						mount $_SRC:$_MTDIR $LOCMNT/ALPHA
					}
				else
					DEFMSG="%s not found in rp_mapping"
					Ferror 1 "`message -E -S -V 600 -F installsetld \
						setld.cat -s SETLD1 \
						LOADCTRLINFO_PRODNAME_NOTFOUND_MSG \
						\"$DEFMSG\" \
						\"$SETLD_PROD_NAME\" `"
				fi
			else
				DEFMSG="rp_mapping file not found"
				Ferror 1 "`message message -E -S -V 600 -F installsetld \
					setld.cat -s SETLD1 \
					LOADCTRLINFO_RP_MAP_NOTFOUND_MSG \
					\"$DEFMSG\"`"
			fi

			# create rismap file
			AddToRismap $_TDIR $DIR
		#
		# Post-initial BASE and LP RIS installations
		# execute here.
		#
		else
			for DIR in $PRODUCTS
			{
			#	
			# Read Control Files over one dir at a time, 
			# building rismap from each directory as it comes
			#
				mkdir $_TDIR/$DIR
				rsh $_SRC -l ris \
					-n "cd $_SYSTEM/$DIR/instctrl ; \
					tar cf - ." |
					(cd $_TDIR/$DIR ; tar xpf -)
				AddToRismap $_TDIR/$DIR $DIR
				(cd $_TDIR/$DIR ; find . -type f \
					| sed 's@\./@@' \
					| fmt -1000 \
					| sed 's/\(.*\)/mv \1 ../' \
					| /bin/sh
				)
				rm -rf $_TDIR/$DIR &
			}
		fi

		Ticker off
		;;
	tape)	DEFMSG="Positioning Tape"
		echo "`message -S setld.cat -s SETLD1 \
			LOADCTRLINFO_POSITION_TAPE_MSG \"$DEFMSG\"`"
		PositionTape 1 0 ||
		{
			DEFMSG="Tape Positioning Error"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADCTRLINFO_POSITION_TAPE_ERR \
				\"$DEFMSG\"`"
			mt -f $RAW rew &
			_CPOS=-$T_0
			return 1
		}

		(cd $_TDIR;tar xpbf 20 $RAW && mt -f $RAW fsf) ||
		{
			DEFMSG="Error reading control information"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADCTRLINFO_READ_CTLINFO_TAPE_ERR \"$DEFMSG\"`"
			return 1
		}
		_CPOS=1
		echo
		;;
	*)	DEFMSG="Internal error in LoadCtrlInfo()"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			LOADCTRLINFO_INTERNAL_ERR \
			\"$DEFMSG\"`"
		set | WriteLog
		return 1
	esac
	
	# If we're not in the process of a full or update
	# installation,  set all modes and ownerships of 
	# incoming files.  Else, _TDIR points to a read-only
	# file system.
	#
	[ "$UPDFLAG" -o "$ADVFLAG" ] ||
	{
		(cd $_TDIR
                	2>&1 chown -R root *.inv *.scp *.ctrl $LANG/*.ctrl \
				> /dev/null
                	2>&1 chgrp -R system *.inv *.scp *.ctrl $LANG/*.ctrl \
				> /dev/null
			2>&1 chmod 644 *.inv *.scp *.ctrl $LANG/*.ctrl \
				> /dev/null
			2>&1 chmod 755 *.scp > /dev/null
		)
	}

	# Determine which subsets are available from the media
	#  and are installable in the current context.
	#
	# fix for setld -l loc subset [ subset... ]

	# have DetermineAvailable set up $SBS
	DetermineAvailable

	return 0
}


:	-LoadFromDisk
#		Load a subset from disk
#
#	given:	full GLOBAL context
#	does:	load a subset from disk
#	return:	1 on failure

LoadFromDisk()
{
	# Check the format of the subset.  Is it DCD or compressed
	# archive?
	#
	# DCD_SUBSET=0:  Compressed Archive
	# DCD_SUBSET=1:  DCD (expanded) format
	#
	if [ "$DCD_SUBSET" -eq 0 ]
	then
		#
		# Subset is in compressed archive format
		#
		Ticker on
		$DECOMP < $_SRC/$S | tar xpf -
		RETVAL=$?
		Ticker off
		return $RETVAL
	else
		#
		# Subset is in DCD format (expanded) format
		#
		cd $_MTPT
		Ticker on
		awk '{print $10}' $_R/$SMDB/$S.inv|pax -r -w -d -p e $_R
		RETVAL=$?
		Ticker off
		cd $_R
		return $RETVAL
	fi

}


:	-LoadFromDiskette
#		Load a subset from a diskette
#
#	given:	full GLOBAL context
#	does:	loads a subset from diskettes
#	return:	ignore

LoadFromDiskette()
{
	VOL=1
	set xx `Parse : $NVOLS`

	NVOLS=$2
	VMAX=`expr $2 + 1`
	while [ $VOL -le $NVOLS ]
	do
		DEFMSG=" \n\
Insert diskette %1\$s %2\$s of %3\$s in %4\$s unit %5\$s.\\\n"
		echo "`message -S setld.cat -s SETLD1 \ 
			LOADFROMDISKETTE_INSERT_DISKETTE \
			\"$DEFMSG\" \
			\"$NAME\" \"$VOL\" \"$NVOLS\" \"$_MEDIA\" \"$_SRC\"`"
		Ready

		# check volume number.
		tar tf $D/$_FLOPPY_PATH${_SRC}a > $TMP1 ||
		{
			_SRC=`expr $_SRC $ALTOP 1`
			ALTOP=`ChOp $ALTOP`

			DEFMSG="\n\
%1\$s\n\
Remove diskette %2\$s %3\$s of %4\$s."
			echo "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMDISKETTE_REMOVE_MSG \
				 \"$DEFMSG\" \
				\"$E_FAIL\" \"$NAME\" \"$VOL\" \"$NVOLS\"`"
			DEFMSG="\n\
Insert diskette %1\$s %2\$s of %3\$s in %4\$s unit %5\$s.\n\
NOTE: we are trying the SAME DISKETTE AGAIN but in %6\$s unit %7\$s.\\\n"
			echo "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMDISKETTE_INSERT_MSG \
				\"$DEFMSG\" \
				\"$NAME\" \"$VOL\" \"$NVOLS\" \
				\"$_MEDIA\" \"$_SRC\" \"$_MEDIA\" \"$_SRC\"`"
			Ready

			tar tf $D/$_FLOPPY_PATH${_SRC}a > $TMP1 ||
			{
				DEFMSG=" \n\
Cannot read your diskette, we will continue with the next volume."
				echo "`message -E -S -V 600 -F installsetld \
					setld.cat -s SETLD1 \
					LOADFROMDISKETTE_CANNT_READ_DISKETTE \
					\"$DEFMSG\"`"
				VOL=`expr $VOL + 1`
				continue
			}
		}
		ISVOL=`grep -E "^Volume" $TMP1`
		ISVOL=`expr "$ISVOL" : '.*ume\([0-9][0-9]*\)'`
		case "$ISVOL" in
		$VOL)
			;;
		*)
			DEFMSG=" \n\
You have mistakenly mounted volume %s.\n\
\n\
Please remove the diskette."
			echo "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMDISKETTE_MISS_MOUNT \
				\"$DEFMSG\" \
				 \"$ISVOL\"`"
			sleep 1
			continue
			;;
		esac
		tar xpf $D/$_FLOPPY_PATH${_SRC}a ||
		{
			_SRC=`expr $_SRC $ALTOP 1`
			ALTOP=`ChOp $ALTOP`

			DEFMSG="\n\
%1\$s\n\
Remove diskette %2\$s %3\$s of %4\$s."
			echo "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMDISKETTE_REMOVE_MSG \
				\"$DEFMSG\" \
				\"$E_FAIL\" \"$NAME\" \"$VOL\" \"$NVOLS\"`"

			DEFMSG="\n\
Insert diskette %1\$s %2\$s of %3\$s in %4\$s unit %5\$s.\n\
NOTE: we are trying the SAME DISKETTE AGAIN but in %6\$s unit %7\$s.\\\n"

			echo "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMDISKETTE_INSERT_MSG \
				\"$DEFMSG\" \
				\"$NAME\" \"$VOL\" \"$NVOLS\" \
				\"$_MEDIA\" \"$_SRC\" \"$_MEDIA\" \"$_SRC\"`"

			Ready
			tar xpf $D/$_FLOPPY_PATH${_SRC}a ||
			{
				DEFMSG=" \n\
\n\
%1\$s \n\
Diskette %2\$s: %3\$s of %4\$s may not have been installed \n\
properly on your system but the rest of the installation will continue."
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD1 \
					LOADFROMDISKETTE_NOT_INSTALL \
					\"$DEFMSG\" \
					\"$E_FAIL\" \"$NAME\" \"$VOL\" \"$NVOLS\"`"
			}
			ERR=1
		}
		DEFMSG=" \n\
Remove diskette %1\$s %2\$s of %3\$s."

		echo "`message -S setld.cat -s SETLD1 \
			LOADFROMDISKETTE_REMOVE_DISKETTE \
			\"$DEFMSG\" \"$NAME\" \"$VOL\" \"$NVOLS\"`"
		VOL=`expr $VOL + 1`
	done
}


:	-LoadFromInet
#		read a subset from internet
#
#	given:	full GLOBAL context
#	does:	read a subset from internet onto the system
#	return:	non-zero on failure

LoadFromInet()
{ (
	# Detect Signals when in this subshell

	trap '
		DEFMSG="Setld:LoadFromInet > Non-Standard Exit"
		Log "`message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD1 \
			LOADFROMINET_NON_STD_EXIT_LOG \
			\"$DEFMSG\"`"
		DEFMSG="Setld:LoadFromInet > Exiting"
		Ferror 1 "`message message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD1 \
			LOADFROMINET_EXIT_MSG \
			\"$DEFMSG\"`"
	' 1 2 3 15

	# Read the rismap to determine which directory to search for
	# this subset.
	#
	set xx `grep -E -w $S $RISMAP`; shift

	[ $# = 0 ] && 
	{
		DEFMSG="LoadFromInet(%1\$s): cannot open %2\$s"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			LOADFROMINET_CANNOT_OPEN_RISMAP \
			\"$DEFMSG\" \"$S\" $RISMAP`"
		set | WriteLog
		return 1
	}
	DIR=$1

	Ticker on
	#
	# Check the format of the subset.  Is it DCD or compressed
	# archive?
	#
	# DCD_SUBSET=0:  Compressed Archive
	# DCD_SUBSET=1:  DCD (expanded) format
	#
	if [ "$DCD_SUBSET" -eq 0 ]
	then
		#
		# Non-DCD format.  Unpack the subset from the server 
		# If this is the BASE product, we'll need to search in the
		# ALPHA/BASE directory for any compressed archives.
		#
		if [ `expr $S : '\(...\).*'` = "OSF" ]
		then
			PDIR=/ALPHA/BASE
		else
			unset PDIR
		fi
	
		# Do the load.  The cat after tar is used to clean up
		# so we don't get any extraneous "Broken pipe" messages.
		#
		rsh $_SRC -l ris -n "dd if=$_SYSTEM/$DIR${PDIR}/$S bs=10k" \
			2> /dev/null \
			| $DECOMP \
			| (tar xpbf 20 - ; cat - > /dev/null)
		RETVAL=$?
	else
		#
		# DCD format.  Use "ris_pax" on the server to send us
		# a compressed archive.  First, get ris root path mapping 
		# file from server.
		#
		ERROR=`rcp ris@$_SRC:$_SYSTEM/rp_mapping \
			$_TMPDIR/rp_mapping 2>&1` ||
		{
			DEFMSG="Cannot access server mapping (%s)"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMINET_CANNT_ACCESS_SRVMAP \
				\"$DEFMSG\" \"$ERROR\"`"
			Ticker off
			return 1
		}

		#
		# Scan for product_NNN in the first field of the mapping file
		#
		RISDIR=`grep -E '^'$DIR: $_TMPDIR/rp_mapping` ||
		{
			DEFMSG="%s: not in ris mapping"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMINET_DIR_NOT_IN_RISMAP \
				\"$DEFMSG\" \"$DIR\"`"
			Ticker off
			return 1
		}

		#
		# Get the product's mount point
		#
		RISMNT=`echo $RISDIR | awk -F: '{print $2}'`

		#
		# Use "ris_pax" on the server to send us a compressed
		# archive over the wire.
		#
		# Do the load.  The cat after pax is used to clean up
		# so we don't get any extraneous "Broken pipe" messages.
		#
		rsh $_SRC -l ris -n "/var/adm/ris/bin/ris_pax $RISMNT \
			$_SYSTEM/$DIR $S" \
			| compress -d \
			| (cd $_R; pax -r -p e ; cat - > /dev/null) 
		RETVAL=$?
	fi

	Ticker off
	return $RETVAL
) }


:	-LoadFromMedia
#		load a subset from the installation medium
#
#	given:	$1 - the name of the subset to install
#		$DEVICE - device (location) name to use
#		$_MEDIA - media type
#		$_SRC - media handle to use (named unit, hostname, etc)
#	does:	Load and verify the subset
#	return:	nothing
#	effect: may modify globals ALTOP, _CPOS, _CVOL

LoadFromMedia()
{	S=$1

	ERR=0
	CTX=$SMDB/$S

	cd $_R

	Log "$S LOAD"

	ReadCtrlFile $_R/$SMDB $S ||
	{
		DEFMSG="Error reading control file"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			LOADFROMMEDIA_READ_CTLFILE_ERR \
			\"$DEFMSG\" `"
		return 1
	}

	#
	# Check whether this subset is optional or mandatory
	#
	ISOPT=`FlagsAttrCheck SATTR_OPTION $FLAGS`

	#
	# Check whether this subset is in expanded (DCD) format,
	# or whether it's a compressed archive.
	#
	# DCD_SUBSET=0: Compressed Archive
	# DCD_SUBSET=1: DCD (expanded) format
	#
	DCD_SUBSET=`FlagsAttrCheck SATTR_DCD_SUBSET $FLAGS`

	DECOMP=cat ; NameParse LOC_ $S

	[ -f $_TDIR/$LOC_P$LOC_V.comp ] && DECOMP="gzip -dq"

	# check sizing (only if not in update installation) 
	[ "$UPDFLAG" ] ||
	{
		echo "
SUBSET $S at $_R:" >> $FITSETLOG
			fitset $_R < $SMDB/$S.inv 
		case $? in
		1|2)	# miscellaneous error conditions or no more free space 
			DEFMSG=" \n\
 There is sizing or access problem installing \"%s\"."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMMEDIA_SIZE_ACCESS_ERR \
				\"$DEFMSG\" \"$SDESC\"`"
			return `expr $ISOPT + 1`
			;;
		esac
	}

	# check dependency
	# report missing dependencies all at once + provide subset description
	# wherever possible.

	# check to see if $DEPS has " " or "."
	# If no dependencies, no need for dependency processing.
	EDEP=`expr match "$DEPS" '[ .]'` 
	[ "$EDEP" = 1 ] ||
	{
		DEP_STATUS=0		# count of uninstalled required subsets
		DEP_UINST=""		# list of uninstalled required subsets
		for DEP in $DEPS
		{
		
			# see if required subset is installed
			# if any "?" meta characters resolve them
			# eg. abc40? with abc405 and abc407
			SWDB_IsInstalled $DEP ||
			{
				# save uninstalled required subset in list to
				# use later in output message and their count
				DEP_UINST="$DEP_UINST $DEP"
				DEP_STATUS=`expr $DEP_STATUS + 1`
			}
		}
	
		[ $DEP_STATUS -gt 0 ] &&
		{
			# yes there are uninstalled required subsets
			# report the error and return count

			# General initial error message
			DEFMSG=" Error installing %1\$s (%2\$s) \n\
This subset requires one or more additional subsets to operate correctly."
			Derr_msg="`message -S setld.cat -s SETLD1 \
				LOADFROMMEDIA_DERR_MSG1 \
				\"$DEFMSG\" \"$SDESC\" \"$S\"`"

			ReportDepErr $DEP_UINST
			return `expr $ISOPT + $DEP_STATUS`
		}
	}

 	[ "$FITSET_DEBUG" ] && LogDiskspace "Before scp of $S" 

	Log "$S SCP PRE_$ACT"
	ACT=PRE_$ACT $SMDB/$S.scp ||
	{
		DEFMSG="Installation declined by subset control program \
(PRE_%1\$s).  \"%2\$s\" (%3\$s) will not be loaded."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			LOADFROMMEDIA_SUBSET_NOLOAD \
			\"$DEFMSG\" \"$ACT\" \"$SDESC\" \"$S\"`"

		#
		# The PRE_L .scp phase failed.  We do NOT record
		# this in the .sts file, because this failure
		# means the subset should be left in whatever
		# state it had previously.
		#
		
		return `expr $ISOPT + 1`
	}

 	[ "$FITSET_DEBUG" ] && LogDiskspace "After scp of $S" 

	#
	# Mark the subset as having completed the PRE_L 
	# phase of the .scp.  In a cluster the change is
	# propagated to all members since the PRE_L phase
	# is run once per cluster.
	#
	SWDB_MarkSubset $S _pre_load_completed
	SWDB_ClusterPropagate $S

 	[ "$FITSET_DEBUG" ] && LogDiskspace "After scp ClusterPropogate of $S" 

	echo "
$SDESC"

	DEFMSG="   Copying from %1\$s (%2\$s)"
	echo "`message -S setld.cat -s SETLD1 \
			LOADFROMMEDIA_COPY_FROM_MEDIA \
			\"$DEFMSG\" \"$_LOC\" \"$_MEDIA\"`"

	DEFMSG="Loading %1\$s (%2\$s - subset %3\$s)..." 
	STATUS_OUTPUT="`message -S setld.cat -s SETLD1 \
		LOADFROMMEDIA_STATUS_MSG1 \
		\"$DEFMSG\" \"$SDESC\" \"$S\" \"$COUNT_MSG\"`"
	INST_SendStatusBarCommand "message $STATUS_OUTPUT"

	# run a sweep of the disk clearing away files which cannot
	#  be tarred over.
	[ ! "$ADVFLAG" -o "$RETRY" ] &&
	{
		tclear < $SMDB/$S.inv ||
		{
			DEFMSG="\n\
The installed system contains files which cannot be overwritten\n\
by the load of the files in the software subset %1\$s."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMMEDIA_CANNT_OVERWRITE \
				\"$DEFMSG\" \"$SMDB/$S.inv\"`"
	 		return `expr $ISOPT + 1`
		}

		#
		# In the update case the /dev directory needs to be 
		# re-linked after tclear removes the symlink.
		#
		[ "$UPDFLAG" -a ! -h /dev ] && { 
			ln -s ./$CLUSTER/$MEMBER_ID/dev ./dev
		}
	}

	case $_MEDIA in
	disk)	LoadFromDisk ||
		{	# utter failure
			DEFMSG=" \n\
%1\$s \n\
\n\
Subset %2\$s may not have been installed properly on your system \n\
but the rest of the installation will continue."

			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMMEDIA_NOT_INSTALL \
				\"$DEFMSG\" \"$E_FAIL\" \"$S\"`"
		}
		;;

	diskette)
		LoadFromDiskette
		;;

	inet)	LoadFromInet ||
		{
			DEFMSG="Load from %1\$s failed, subset %2\$s"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMMEDIA_LOAD_FAIL \
				\"$DEFMSG\" \"$_SRC\" \"$S\"`"
		}

		;;

	tape)	LoadFromTape ||
		{
			DEFMSG="%1\$s \n\
\n\
\"%2\$s\" (%3\$s) may not have installed properly on your system (tar error)"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMMEDIA_TAR_ERR \
				\"$DEFMSG\" \"$E_FAIL\" \"$SDESC\" \"$S\"`"
		}
	esac

	sync

 	[ "$FITSET_DEBUG" ] && LogDiskspace "After Load of $S" 

	# Verify the subset
	DEFMSG="VERIFY, \\\c"
	Log "`message -S setld.cat -s SETLD1 \
		LOADFROMMEDIA_VERIFY_LOG \
		\"$DEFMSG\"`"
	DEFMSG="   Verifying" 
	echo "`message -S setld.cat -s SETLD1 \
		LOADFROMMEDIA_VERIFYING \
		\"$DEFMSG\"`"
	echo "
SUBSET $S at $_R:" >> $FVERIFYLOG

	INST_SendStatusBarCommand "tick 1" 
	DEFMSG="Verifying %1\$s (%2\$s - subset %3\$s)..."
	STATUS_OUTPUT="`message -S setld.cat -s SETLD1 \
		LOADFROMMEDIA_STATUS_MSG2 \
		\"$DEFMSG\" \"$SDESC\" \"$S\" \"$COUNT_MSG\"`"
	INST_SendStatusBarCommand "message $STATUS_OUTPUT"

	TickWhile "fverify -y < $CTX.inv > /dev/null 2>&1" &&
	{
		DEFMSG="SUCCEEDED"
		Log "`message -S setld.cat -s SETLD3 \
			LOG_SUCCEEDED_MSG \
			\"$DEFMSG\"`"

		if [ "$UPDFLAG" ] && SWDB_IsLocked $S
		then
			#
			# Strip out the .lk information for the
			# product we are updating.  Leave all other
			# product information alone.  The update
			# install updates several products and as 
			# each product updates the information from
			# the previous version of the product should
			# be removed. 	
			#
			# This works because at the time the new subset is
			# loaded there are no subsets installed from this
			# product that depend on the new version of this
			# subset.  So we clean out all product information 
			# relating to this product and let the subsequent
			# subset loads repopulate the file with the correct
			# information.
			#
			PCODE=`expr "$S" : '^\(...\).*'`
			SWDB_EraseLocks $S "^$PCODE"
		fi

		#
		# Mark the subset as having completed the verify.  In a 
		# cluster the change is propagated to all members since
		# the verify is run once per cluster.
		#
		SWDB_MarkSubset $S _verify_completed
		SWDB_ClusterPropagate $S

		INST_SendStatusBarCommand "tick 1"
		return 0
	}
	# Verify Failed

	INST_SendStatusBarCommand "tick 1"

	DEFMSG=" \n\
There were verification errors for \"%1\$s\" (%2\$s)"
	Error "`message -E -S -V 500 -F installsetld \
		setld.cat -s SETLD1 \
		LOADFROMMEDIA_VERIFY_ERR \
		\"$DEFMSG\" \"$SDESC\" \"$S\"`"

	#
	# Mark the subset as having failed the verify.  In a 
	# cluster the change is propagated to all members since
	# the verify is run once per cluster
	#
	SWDB_MarkSubset $S _verify_failed "$DEFMSG"
	SWDB_ClusterPropagate $S

	case "$ISOPT$CMDSW" in
	0[lp])	return 1
		;;
	*)	return 2
	esac
}



:	-LoadFromTape
#		Load a subset from tape to the system
#
#	given:	full GLOBAL context
#	does:	read the subset from the tape to the system
#	return:	non-zero on failure

LoadFromTape()
{
	set xx `Parse : $MTLOC`; shift
	MTVOL=$1
	MTLOC=$2

	PositionTape $1 $2

	Ticker on
	dd if=$RAW bs=10k 2> /var/tmp/null | $DECOMP | tar x${VBSE}pf -
	RET=$?
	Ticker off
	rm -f /var/tmp/null

	[ $RET = 0 ] && _CPOS=`expr $_CPOS + 1`

	return $RET
}


:	-LogDiskspace
#
#	given:	message to output (e.g. name of routine with current subset)
#	does:	echo diskspace info (df) to log file
#	return:	nothing

LogDiskspace ()
{
	echo "\n******** $1" >>$DF_LOG
	df -k >> $DF_LOG
	echo "\n********" >>$DF_LOG
}


:	-Main
#		This is the main program
#
#	given:	$* from command line
#	does:	parse arguments and all sorts of miscellany
#	return:	does not return

Main()
{
	#
	# Start the trace (if needed)
	# 
	[ "$XFLAG" ] && 
	{
		INST_InitTracing "$XFLAG"

		#
		# Check to see if the ALL or setld keywords were used
		#
		INST_DoTracing begin "ALL"
		INST_DoTracing begin "SETLD"
	}

	CDPATH= ;export CDPATH		# assure no surprises.

	ISL_PATH=${ISL_PATH:-/isl}
	PATH=$ISL_PATH:/sbin:/usr/lbin:/usr/sbin:/usr/bin:.
	export PATH ISL_PATH

	# save tab settings in tabsave




	2>&1 stty -a | grep -E "\-tabs" >/dev/null &&
		{
		  tabsave="-tabs"
        	}

	2>&1 stty -a | grep -E " tabs" >/dev/null &&
        	{
               	  tabsave=" tabs"
        	}
	InitializeConstants
	InitializeGlobals

	trap '
		trap "" 3
		DEFMSG="Non-Standard Exit"
  		Log "`message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD2 \
			MAIN_NON_STD_EXIT_LOG \
				\"$DEFMSG\"`"
		DEFMSG="Exiting"
		Ferror 1 "`message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD2 \
			MAIN_EXIT_MSG \
			\"$DEFMSG\"`"
	' 1 2 3 15

	[ -t 1 ] && stty -tabs 2>/dev/null	# permit tabs use on output if isatty
	DATE=`date $DATFMT`

	# Set tar verbose switch if necessary
	case "$-" in
	*x*)	VBSE=v
		DEFMSG="debug enabled"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			MAIN_DEBUG_ENABLE \
			\"$DEFMSG\" \"$PROG\"`"
	esac

	umask 22

	[ -d /$LOGDIR ] || mkdir -p /$LOGDIR    # needed for logging

	OpenLog					# initialize logging

	ARGV=$*
	Args $ARGV ||
	{
		DEFMSG="error in Args()"
		Ferror 1 "`message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD2 \
			MAIN_ERR_IN_ARGS \
			\"$DEFMSG\"`"
	}

	(Dirs) ||
	{
		DEFMSG="error in Dirs()"
		Ferror 1 "`message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD2 \
			MAIN_ERR_IN_DIRS \
			\"$DEFMSG\"`"
	}
	case $CMDSW in
	c)	cd $_R
		Configure $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	C)	cd $_R
		ClusterPostInstall $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	d)	Delete $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	h)	Usage -h

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit 0
		;;

        I)      InventoryGUI
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	i)	Inventory $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	l)	OPERATION=install
 
		[ "$UPDFLAG" ] || 
		{
			INSTALLED_VERSION=`SWDB_WhatVersion OSF`
			[ "$INSTALLED_VERSION" -ge "505" ] && 
			{
				if [ -f /usr/sbin/clu_get_info ] &&
					clu_get_info -raw > \
						$CLUSTER_INFO \
						2> /dev/null
				then
					grep "^M:" $CLUSTER_INFO \
						| awk -F: '{print $2,$3,$6}' \
						> $MEMBERS_N_STATUS
				fi
			}
		}

                INST_SendStatusBarCommand "tickevery 30"
		DEFMSG="Initializing Software Load..."
		STATUS_OUTPUT="`message -S setld.cat -s SETLD2 \
			MAIN_STATUS_MSG1 \
			\"$DEFMSG\"`"
		INST_SendStatusBarCommand "message $STATUS_OUTPUT"

		InitDevice ||
		{
			DEFMSG="cannot initialize %s"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_INIT_DEV \
				\"$DEFMSG\" \"$DEVICE\"`"
		}
		cd $_R

		# read instctrl info from media to $_TDIR
		TickWhile LoadCtrlInfo ||
		{
			DEFMSG="cannot load control information"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_READ_CTLINFO \
				\"$DEFMSG\"`"
		}
		set xx $ARGV; shift

		# prepare for the installation and set global $SBS:
		#	- present menu,
		#	- copy over instctrl information, etc. 
		# 	- check system space
		#	- order $SBS by dependency 
		#	- prepare/save files for update installation.
		#
		PrepInstall $* ||
		{
			ESTAT="$?"
			[ "$XFLAG" ] && INST_DoTracing end "Main"
			Exit "$ESTAT"
		}

		INST_SendStatusBarCommand "tickevery end"

		Install $SBS 
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;
	p)	set xx $ARGV; shift
		[ `Length $ARGV` = 0 ] &&
		{
			DEFMSG="Playback - ERROR NO subsets"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_PLAYBACK_ERR_NOSUBSET \
				\"$DEFMSG\"`"
			[ "$XFLAG" ] && INST_DoTracing end "Main"
			Exit 1
		}

                INST_SendStatusBarCommand "tickevery 30"
		DEFMSG="Initializing Software Load..."
		STATUS_OUTPUT="`message -S setld.cat -s SETLD2 \
			MAIN_STATUS_MSG1 \
			\"$DEFMSG\"`"
		INST_SendStatusBarCommand "message $STATUS_OUTPUT"

		OPERATION=install
		InitDevice ||
		{
			DEFMSG="cannot initialize %s"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_INIT_DEV \
				\"$DEFMSG\" \"$DEVICE\"`"
		}
		cd $_R

		ACT=L
		[ -d $BLKBORD ] ||
		{
			DEFMSG="Playback - error no temporary initial installation directory"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_NO_TEMP_DIR \
				\"$DEFMSG\"`"
		}
		LoadCtrlInfo ||
		{			
			DEFMSG="cannot load control information"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_READ_CTLINFO \
				\"$DEFMSG\"`"
		}

		# prepare for the installation of specific selected subsets
		# earlier test verified that subset names are provided:
		#       - verify that specified subsets are available on media
		#       - copy over instctrl information from std black board
		#         area to ./usr/.smdb.
		#       - check system space
		#       - order $SBS by dependency
		#       - prepare/save files for update installation.
		#
		PrepInstall $* ||
		{
			ESTAT="$?"
			[ "$XFLAG" ] && INST_DoTracing end "Main"
			Exit "$ESTAT"
		}

		INST_SendStatusBarCommand "tickevery end" 

		Install $SBS
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	# QAR29496 - fys
	P)	#From SVR4 pkginfo PRIVATE FLAG
		Inventory $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

        S)      InitDevice ||
		{
			DEFMSG="cannot initialize %s"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_INIT_DEV \
				\"$DEFMSG\" \"$DEVICE\"`"
		}
		rm -rf $BLKBORD
		mkdir $BLKBORD
		cd $_R

                LoadCtrlInfo ||
		{
			DEFMSG="cannot load control information"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_READ_CTLINFO \
				\"$DEFMSG\"`"
		}
		AvailSubPostInfo

		echo $_TDIR > $SUIT_INFO_DIR

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit 0
		;;

	s)	InitDevice ||
		{
			DEFMSG="cannot initialize %s"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_INIT_DEV \
				\"$DEFMSG\" \"$DEVICE\"`"
		}
		rm -rf $BLKBORD
		mkdir $BLKBORD
		cd $_R
		rm -f $SINFO_UI

		LoadCtrlInfo ||
		{
			DEFMSG="cannot load control information"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_READ_CTLINFO \
				\"$DEFMSG\"`"
		}

		AvailSubInfo

		mv $SINFO_WORK $SINFO_UI

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit 0
		;;

	u)
		[ "$TCR_FLAG" ] ||
		{
			DEFMSG="Not a cluster, cannot execute %s option."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				CLUSTER_NOT_CLUSTER \
				\"$DEFMSG\" \"-u\"`"
			[ "$XFLAG" ] && INST_DoTracing end "Main"
			Exit 1
		}

		set xx $ARGV; shift
		[ `Length $ARGV` = 0 ] &&
		{
			DEFMSG="
setld: empty subset list passed as a command line argument" 
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_ERR_NOSUBSET \
				\"$DEFMSG\"`"
			[ "$XFLAG" ] && INST_DoTracing end "Main"
			Exit 1
		}

		#
		# The _TDIR variable needs to be the system location
		# when invoked during update install, otherwise 
		# any operation using _TDIR will fail because the
		# temporary directory, which contained the temporary
		# copy of the instctrl information, has been removed.
		#
		[ "$UPDFLAG" -o "$UPD_HWFLAG" ] &&
			_TDIR=$SMDB

		#
		# Make sure to save off the files for this specific 
		# member (MEMBER_ID) before starting the merge
		#
		[ "$UPDFLAG" -o "$UPD_HWFLAG" ] &&
		{
			#
			# Prevent the shared files from being merged
			# a second time.  Merging shared files again
			# causes the .PreMRG files from the old
			# version to be over written with the version
			# created by the first roll. 
			#	
			NO_SHARED_PREMRG=1
			BackupMergedFiles
		}

		# copy member0 files to specific member
		PopulateMember $*

		# transition to proto state
		# get subsets
		for _S in $POPULATE_SUCCESS_LIST
		{
			#
			# Message for PostLoad
			#
			DEFMSG="\
Performing state transitions for %1\$s on %2\$s"
			STATUS_OUTPUT="`message -S setld.cat -s SETLD1 \
				INSTALL_STATUS_MSG1 \"$DEFMSG\" \
				\"$_S\" \
				\"$MEMBER_ID\"`"
			INST_SendStatusBarCommand "message $STATUS_OUTPUT"

			PostLoad $_S || 
				continue

			# Delay configuration, record subset in $CINSTDATA
			# so it can be configured later with setld -c
			#
			if [ "$TCR_FLAG" ] 
			then
				INST_CLU_OnEachMember INST_UniqueWordList \
					-nosort -add "$_S" $_R/$CINSTDATA
			else
				INST_UniqueWordList \
					-nosort -add "$_S" $_R/$CINSTDATA
			fi

			INST_SendStatusBarCommand "tick 1"
		}
		;;

	v)	Verify $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;

	x)	OPERATION=extract

		# In the extract case, we want to use the utilities
		# already on the server.
		PATH=/var/adm/ris/bin:/sbin:/usr/lbin:/usr/sbin:/usr/bin:.
		export PATH

		InitDevice ||
		{
			DEFMSG="cannot initialize %s"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_INIT_DEV \
				\"$DEFMSG\" \"$DEVICE\"`"
		}

		LoadCtrlInfo ||
		{
			DEFMSG="cannot load control information"
			Ferror 1 "`message -E -S -V 600 -F installsetld \
				setld.cat -s SETLD2 \
				MAIN_CANNOT_READ_CTLINFO \
				\"$DEFMSG\"`"
		}

		set xx $ARGV; shift
		if [ $# = 0 ] 
		then
			SplitByType || 
			{
				ESTAT="$?"
				[ "$XFLAG" ] && INST_DoTracing end "Main"
				Exit "$ESTAT"
			}

			TickWhile PreSize extract $MAND ||
			{
				DEFMSG=" \n\
There is not enough file system space to extract the mandatory subsets"
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD2 \
					MAIN_NOSPACE_FOR_MANDATORY \
					\"$DEFMSG\"`"
				[ "$XFLAG" ] && INST_DoTracing end "Main"
				Exit 1
			}
			MenuSelect "$MAND" "$OPT" subset || Exit $?
		else
			SBS=$*	
			TickWhile PreSize extract $SBS ||
			{
				DEFMSG=" \n\
There is not enough file system space to extract the specified subsets"
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD2 \
					MAIN_NOSPACE_FOR_SUBSET \
					\"$DEFMSG\"`"
				[ "$XFLAG" ] && INST_DoTracing end "Main"
				Exit 1
			}
		fi

		SBS=`(cd $_TDIR; DependencyOrder $SBS)`

		Extract $SBS
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;
	Z)
		cd $_R
		ClusterPostDelete $ARGV
		ESTAT="$?"

		[ "$XFLAG" ] && INST_DoTracing end "Main"
		Exit "$ESTAT"
		;;
	esac

	EMESG=

	[ "$XFLAG" ] && INST_DoTracing end "Main"
	Exit 0
}


:	-MenuListInit
#		seperate objects into two piles (one with category specified
#		in description and one without) and then sort objects 
#		in each pile.
#	        (category is the first sort key and subset description is the
#		 second sort key)  
#	given:	1) list containing subsets or packages
# 	does:	1) seperate according to existence of category specification. 
#		2) sort the objects according to their descriptions.
#	return: a list of subset ids (subsets with category precede those
#		without category.  
#

MenuListInit()
	 
{	

	# sort objects in the list according to the subset/package description
  	# in ascending alphabetic order 

	LIST=$1
        [ `Length $LIST` -gt 0 ] &&
	{
		> $TMP1
        	for X in $LIST  
        	{
			eval DESC=\$DESC$X
			echo "$DESC%$X" >> $TMP1 
        	}

		# group descriptions with category and echo back subset id 
		grep -E '.+%.+%.+' $TMP1 | sort -t% +1 -2 | awk -F% '{print $3}' 	

		# group descriptions without category and echo back id  
		grep -E -v '.+%.+%.+' $TMP1 | sort | awk -F% '{print $2}' 	
	}
}

:       -MenuSelect
#               select which subsets(packages) are to be installed/extracted
#
#       given:  1) list of mandatory subsets to show before presenting menu.
#               2) list of optional subsets from which to select
#               3) the string 'subset' (or 'package') to make the distinction.
#       does:   display the mandatory. offer selection of the optional.
#               recieve list of selected menu item and confirm selection.
#               set global SBS to reflect the selection.
#       return: 1 if "Nothing from this menu" is selected, else return 0
#       effect: global $SBS or $PKGS - change to list the mandatory
#               prepended to selected optionals.

MenuSelect()
{

        _MAND=$1
        _OPT=$2
        OBJECT=$3

        case "$OBJECT" in
        #package)        OBSW="-p"
        #                ;;
        subset)         OBSW="-s"
                        ;;
        esac

        ISLSW=
        [ "$ADVFLAG" ] &&
                ISLSW="-i"


	# sort subsets according to the subset description
  	# in ascending alphabetic order 
	_MAND=`MenuListInit "$_MAND"`
	_OPT=`MenuListInit "$_OPT"`

	for X in $_MAND
	{
		[ "$OBJECT" = subset ] &&
			ReadCtrlFile $_TDIR $X
		# instead of exporting let's print to files

		# what if there are no mandatory subsets - lets just create a
		# zero length file

		[ "$DEPS" = "." ] && DEPS=

		# Here category is not important and therefore we don't
		# check for format

		echo $X $ROOTSIZE $USRSIZE $VARSIZE "@$DESC" "^$DEPS" >> $MAND_FILE

	}

	for X in $_OPT
	{
		[ "$OBJECT" = subset ] &&
		ReadCtrlFile $_TDIR $X

		[ "$DEPS" = "." ] && DEPS=

		# The subset category is specified as part of the DESC
		# variable in the .ctrl file, delimited by the "%" sign
		# Some .ctrl files do not have a proper category and sometimes
		# not even the delimiter which could cause problems during file
		# parsing by stlmenu.

		# Check for category and provide delimiter if not found

		GDESC=`expr index "$DESC" '\%'` 

		if [ "$GDESC" -le 0 ] 
		then
			DESC="$DESC%"
		fi

		echo $X $ROOTSIZE $USRSIZE $VARSIZE "@$DESC" "^$DEPS" >> $OPT_FILE
	}

	# Populate the installed cli file with installed subsets info.
	# If -x ( extract ) or we are creating a new dataless area then
	# there will be no installed subsets

	if [ "$CMDSW" = "x" -o "$DMS_NEW_AREA" ]
	then
		>>$INSTLD_CLI
	else
		InventoryCLI
	fi


	while :
	do

	# call 'stlmenu' with -a flag for "advanced" which only setld 
	# uses to enable dynamic dependency and space checking

	# This conditional to be revisited when we incorporate code for handling
	# other mounted file systems like i18n. 

	if [ "$CMDSW" = "x"  -o "$DEFPATH" = "0" ]
	then

	# hide free disk space display use -h flag

       	stlmenu -$CMDSW $OBSW $CONTSW $ISLSW -h -a -m $MENU select \
		$MAND_FILE $OPT_FILE $INSTLD_CLI || Exit $?

	else

        stlmenu -$CMDSW $OBSW $CONTSW $ISLSW -a -m $MENU select \
		$MAND_FILE $OPT_FILE $INSTLD_CLI || Exit $?
	
	fi
        	MENULIST=`cat "$MENU"`

        	# nothing was selected from the menu
        	case "$MENULIST" in
        	"")     case "$OBJECT" in
                	subset)         SBS=
                                	;;
                	#package)        PKGS=
                	#                ;;
                	esac
                	return 1
        	esac
	
        	# something gets selected

        	# presize the total selection only if any optional
        	# has been selected. if MENULIST is contained by MAND, since
        	# we've already presized MAND, there's no need to presize
        	# again

		ListContained "$MENULIST" "$MAND"	
		MAND_ONLY=$?
        	if [ $MAND_ONLY -eq 1 ]; then 
			DEFMSG=" \n\
Checking file system space required to %s selected subsets:"
			echo "`message -S setld.cat -s SETLD2 \
				MENUSELECT_CHECK_SPACE \
				\"$DEFMSG\" \"$OPERATION\"`"
                	TickWhile PreSize $OPERATION $MENULIST 
			case $? in
			0) 	DEFMSG=" \n\
File system space checked OK."
				echo "`message -S setld.cat -s SETLD2 \
				MENUSELECT_FILESYSTEM_OK \
				\"$DEFMSG\"`" 
				;;
			1)	case $OPERATION in
				extract )
					DEFMSG=" \n\
There is sizing or access problem extracting the selected subsets.\n\
Please press RETURN to start another selection."
					;;
				install )
					DEFMSG=" \n\
There is sizing or access problem installing the selected subsets.\n\
Please press RETURN to start another selection."
					;;
				esac
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD2 \
					MENUSELECT_SIZE_ACCESS_${OPERATION}_ERR \
					\"$DEFMSG\"`"
				read X
				continue 
				;;
			2)	case $OPERATION in
				extract )
					DEFMSG="\n\
There is not enough file system space to extract all the subsets \n\
you have selected. Please press RETURN to start another selection."
					;;
				install )
					DEFMSG="\n\
There is not enough file system space to install all the subsets \n\
you have selected. Please press RETURN to start another selection."
					;;
				esac
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD2 \
					MENUSELECT_NO_SPACE_$OPERATION \
					\"$DEFMSG\"`"
				read X
                        	continue
				;;
			3)	while :
				do
					case $OPERATION in
					extract )
						DEFMSG="\n\
warning: Extracting all the subsets you have selected will cause\n\
one or more file systems to be over 100%% full. Do you really want\n\
to do this (y/n): \\c"
						;;
					install )
						DEFMSG="\n\
warning: Installing all the subsets you have selected will cause\n\
one or more file systems to be over 100%% full. Do you really want\n\
to do this (y/n): \\c"
						;;
					esac
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD2 \
						MENUSELECT_NO_SPACE_${OPERATION}_WARNING \
						\"$DEFMSG\"`"
					read X
					case "$X" in
					[Yy]*)  break
						;;
					[Nn]*)  continue 2
						;;   
					esac
				done
				;;
			esac
		else
			# Because we already checked the size for
			# the Mandatory subsets, print out a message
			# to assure the user we sized the subsets
			# properly.
			case $OPERATION in
			extract )
				DEFMSG="\n\
Checking file system space required to extract selected subsets:\n\
\n\
File system space checked OK."
				;;
			install )
				DEFMSG="\n\
Checking file system space required to install selected subsets:\n\
\n\
File system space checked OK."
				;;
			esac
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD2 \
				MENUSELECT_CHECK_SPACE_OK_$OPERATION \
				\"$DEFMSG\"`"
		fi

        	case "$OBJECT" in
        	subset)         SBS="$MENULIST"
                        	;;
        	#package)        PKGS="$MENULIST"
        	#                ;;
        	esac
		break
  	
	done

        return 0
}



:	-MoveUpd
#		move .upd..<file> into the real name space and update
#		the inventory entry in .inv.	
#
#	given:	$1 - subset name
#	does:	for all of the .upd.. files in the subset inventory,
#		move them to the real name space and update the inventory.
#	return:	NIL

MoveUpd()
{ (
	SUBSET=$1
	grep -E -s -q '/\.upd\.\.' $SMDB/$SUBSET.inv && 
	{
		awk '{print $10}' $SMDB/$SUBSET.inv | grep -E '/\.upd\.\.' | 
			sed 's/\.upd\.\.//' |
			while read FNAME
			do
				#
				# QAR 71524.  Must move libc_r.so and 
				# libc.so in the same pass, otherwise the
				# hardlink (libc_r.so) and libc.so will 
				# get out of sync. 
				#
				# The result is that libc_r.so has already 
				# been moved into place, so skip the move
				#
				[ "$FNAME" = "./shlib/libc_r.so" ] && continue

				#
				# Set variables based on $FNAME, but
				# only use _D, _F and CF , since the
				# rest of the variables are merge specific
				# and do not apply to .upd.. files.  We
				# are setting these variables so that the
				# cluster member specific information
				# gets set correctly.
				#
				#	_D = directory
				#	_F = file
				#	CF = configured file
				#
				MRG_SetFileVariables $SUBSET $FNAME

				#
				# QAR 71524.  Must move libc_r.so and 
				# libc.so in the same pass, otherwise the
				# hardlink (libc_r.so) and libc.so will 
				# get out of sync. 
				#
				# Make a copy as per Shashi Mangalat's
				# advice.
				#
				[ "$FNAME" = "./shlib/libc.so" -a \
					-f $_R/shlib/libc_r.so ] &&
				{
					cp -p $_R/shlib/libc_r.so \
						$_R/shlib/libc_r.so.OLD
				}

				#
				# Do not move the following files until
				# just before reboot, otherwise the 
				# stat() change will cause these files
				# to fail. Move will be done later in
				# updeng.
				#
				echo $UPD_WAIT_FILES | grep -q $_D/.upd..$_F
				[ $? != 0 ] && {
					mv $_D/.upd..$_F $_D/$CF
				}

				#
				# QAR 71524.  Must move libc_r.so and 
				# libc.so in the same pass, otherwise the
				# hardlink (libc_r.so) and libc.so will 
				# get out of sync. 
				#
				# Relink the libc_r.so file after moving
				# the libc.so file and then remove the 
				# .upd..file for libc_r.so.
				#
				[ "$FNAME" = "./shlib/libc.so" ] &&
				{
					ln -f $_R/shlib/libc.so \
						$_R/shlib/libc_r.so
					rm -f $_R/shlib/.upd..libc_r.so 
				}
			done

		#
		# Update the subset inventory file (.inv) 
		#
		sed 's/\.upd\.\.//g' $SMDB/$SUBSET.inv | \
			sort +9 -10 -o $SMDB/$SUBSET.inv

	}
) }


:	-NameParse
#		parse a subset name into components
#
#	given:	$1 - a variable name prefix to use
#		$2 - a subset name to parse
#	does:	parse the subset name in P (xxx), N (y*), & V (zzz) components
#	return:	nothing
#	effect:	assign the P component to ${1}P
#		assign the N component to ${1}N
#		assign the V component to ${1}V

NameParse()
{
	[ $# -lt 2 ] &&
	{
		DEFMSG="NameParse(): too few arguments (%s)"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			NAMEPARSE_FEW_ARGS \
			\"$DEFMSG\" \"$#\"`"
		return 1
	}
	L_PREFIX=$1	# variable prefix to use
	L_S=$2		# subset name to parse

	#% Local Variables
	L_N=		# temporary subset name
	L_P=		# temporary product code
	L_V=		# temporary version code
	L_X=		# loop control

	#% Local Code
	# check to see if parse information has been cached
	eval NPC=\$Np$L_S
	[ "$NPC" ] &&
	{
		# assign cached values and return
		eval `(
			set $NPC
			shift
			echo "${L_PREFIX}P=$1 ${L_PREFIX}N=$2 ${L_PREFIX}V=$3"
		)`
		return 0
	}

	case "$L_S" in
	.|..|...|....|.....|......|.......)
		DEFMSG="NameParse(): %s: subset names must be at least 8 \
characters long"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			NAMEPARSE_NAME_SHORT \
			\"$DEFMSG\" \"$L_S\"`"
		return 1
	esac
	L_N=`expr $L_S : '^...\(.*\)...$'` ||	# name component
	{
		DEFMSG="NameParse(%s): cannot parse subset name"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			NAMEPARSE_CANNOT_PARSE_NAME \
			\"$DEFMSG\" \"$L_S\"`"
		return 1
	}
	L_P=`expr $L_S : '^\(...\).*$'`	||	# product component
	{
		DEFMSG="NameParse(%s): cannot parse product code"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			NAMEPARSE_CANNOT_PARSE_CODE \
			\"$DEFMSG\" \"$L_S\"`"
		return 1
	}
	L_V=`echo $L_S |  sed 's/^.*\(...\)$/\1/'` ||     # version component
	{
		DEFMSG="NameParse(%s): cannot parse version"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			NAMEPARSE_CANNOT_PARSE_VER \
			\"$DEFMSG\" \"$L_S\"`"
		return 1
	}

	# make the assignments
	for L_X in N P V
	{
		eval $L_PREFIX$L_X=\$L_$L_X
	}
	# cache the resutls
	NPC="$L_S $L_P $L_N $L_V"
	eval Np$L_S='$NPC'
	return 0
}


:	-OpenLog
#		establish logfile
#
#	given:	$LOGFLILE - default logfile
#		$WHOAMI - user name running this process
#		$DATE - invocation time as formatted by $DATFMT
#	does:	establishes a log file for the session and writes initial
#		entry for this invocation
#	return:	0
#	effect:	$LOGFILE - may modify
#		$WHOAMI - will set from output of whoami(1) if not set

OpenLog()
{
	WHOAMI=${WHOAMI:=`id -u`}
	[ "$WHOAMI" != 0 ] && LOGFILE=/dev/null

	# create initial entry for this run
	(Log "SETLD $$ `whoami` $DATE \c")
	return 0
}

:	-PopulateMember
#		copies/creates member specific items for the
#		named subsets from member0 to the specified
#		member
#
#	given:	$* - subsets
#	does:	populates the cluster member $MEMBER_ID
#	return:	0 on success
#		1 on failure
#	effect:	member0 files copied to specific member
#	notes:	MEMBER_ID cannot be set to member0 when calling 
#		this routine
#

PopulateMember()
{
	# get subsets
	SUBSETS=$*
	STOTCNT=$#

	#
	# Cannot copy from member0 to member0, so if MEMBER_ID is
	# set to member0 it is an error.
	#
	[ "$MEMBER_ID" = "member0" ] &&
	{
		DEFMSG="\n\
Unable to execute the PopulateMember routine on member0."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD1 \
			POPULATEMEMBER_CANNOT_EXECUTE \
			\"$DEFMSG\"`"
		return 1
	}

	# loop thru the subsets to copy their files from member 0
	RETURN_VAL=0
	CNT=0
	POPULATE_SUCCESS_LIST=""
	for _S in $SUBSETS
	{
                CNT=`expr $CNT + 1`
		DEFMSG="%1\$s of %2\$s"
		COUNT_MSG="`message -S setld.cat -s SETLD1 \
			COUNT_MSG \"$DEFMSG\" \"$CNT\" \"$STOTCNT\" `"

		ReadCtrlFile $_R/$SMDB $_S

		#
		# Message for the start of the populate phase
		#				
		DEFMSG="Loading %1\$s on (%2\$s - subset %3\$s) on %4\$s..."
		STATUS_MSG="`message -S setld.cat -s SETLD1 \
			POPULATEMEMBER_POPULATE_STATUS_MSG \
			\"$DEFMSG\" \
			\"$SDESC\" \
			\"$_S\" \
			\"$COUNT_MSG\" \
			\"$MEMBER_ID\"`"
		INST_SendStatusBarCommand "message $STATUS_MSG"

		#
		# Create an inventory file that only contains the 
		# entries for member specific files.
		#
		# NOTE: Using the grep before the awk allows the process
		#	to execute in under a second on an MX5.  The 
		#	same command run without the grep produces the
		#	same results but took 13 seconds on an MX5  
		#
		M0_INVFILE=$_TMPDIR/$_S.inv.member0
		grep -E member0 $SMDB/$_S.inv \
			| awk '{if ($10 ~ /.*member0.*/) print $0}' \
			> $M0_INVFILE

		#
		# Translate member0 to the correct ID, but do not 
		# use MRG_CluTranslate because that routine 
		# translates {memb} and the {memb} construct in the 
		# target of the link should not be translated.
		#
		INVFILE=$_TMPDIR/$_S.inv
		cat $M0_INVFILE | sed -e 's/member0/'$MEMBER_ID'/g' > $INVFILE

		#
		# Clear this member's member specific files so
		# that the future operations have no problems.
		#
		# NOTE: Do not clear any files that are in shared space!
		#
		tclear < $INVFILE ||
		{
			ERROR_FILE=/var/adm/smlogs/$_S.overwrite_failure
			mv $INVFILE $ERROR_FILE

			DEFMSG="\n\
The installed system contains files which cannot be overwritten\n\
by the load of the files in %1\$s."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD1 \
				LOADFROMMEDIA_CANNT_OVERWRITE \
				\"$DEFMSG\" \"$ERROR_FILE\"`"

			#
			# Mark the subset as having failed the
			# populate.  Since the populate is done 
			# on a per member basis, do not propagate the
			# changes to other cluster members.
			#
			SWDB_MarkSubset $_S _populate_failed "$DEFMSG"

			RETURN_VAL=1
			continue
		}

		#
		# Temporary file to hold error messages for this subset
		#
		ERROR_MSG_FILE=$_TMPDIR/err.msg.$_S

		#
		# Using the same method we use to drop down DCD subsets
		# create and extract the archive for the subset based
		# upon the member specific inventory.  The benefit
		# to this is that this is the exact same method used 
		# to populate member0, so all of the same behaviors
		# occur as well.  The one difference between this 
		# and the member0 population is the fact that this
		# extract substitutes the member ID in place of member0
		# so that every file name that has member0 in the 10th
		# field will now have $MEMBER_ID instead.  This substitution
		# only occurs for the file name (10th field).
		#
		# NOTE: the M0_INVFILE is used so that the files are
		#	grabbed from member0.
		#
		awk '{print $10}' $M0_INVFILE \
			| pax -r -w -d -p e -s /member0/$MEMBER_ID/ $_R \
			2> $ERROR_MSG_FILE

		#
		# This loop is to handle all of the symbolic links
		# that were not translated in the above extract.  Since
		# the extract above only translated field #10, all of the
		# targets of the links (field 11) still say member0. So
		# for every symbolic link in the INVFILE, redo the link
		# to match the translated inventory.  
		# 
		# NOTE:	INVFILE has all fields translated to $MEMBER_ID,
		#	so this is used to get the correct file name and 
		#	correct target of the link.
		#
		awk '{if ($9 ~ /s/) print $10,$11}' $INVFILE | 
		while read FILE_NAME FILE_TARGET
		do
			(cd $_R ; 
			 ln -sf $FILE_TARGET $FILE_NAME 2> $ERROR_MSG_FILE)
		done

		#
		# Tick once for the completion of the populate phase
		#				
		INST_SendStatusBarCommand "tick 1"

		#
		# Update the smdb files to reflect this member's status
		#
		if [ -s $ERROR_MSG_FILE ]
		then
			#
			# Mark the subset as having failed the
			# populate.  Since the populate is done 
			# on a per member basis, do not propagate the
			# changes to other cluster members.
			#
			ERROR_MSG=`cat $ERROR_MSG_FILE`
			SWDB_MarkSubset $_S _populate_failed "$ERROR_MSG"
		else
			if [ "$UPDFLAG" ] && SWDB_IsLocked $_S
			then
				#
				# Strip out the .lk information for the
				# product we are updating.  Leave all other
				# product information alone.  The update
				# install updates several products and as 
				# each product updates the information from
				# the previous version of the product should
				# be removed. 	
				#
				# This works because at the time the
				# new subset is loaded there are no
				# subsets installed from this 
				# product that depend on the new
				# version of this subset.  So we clean
				# out all product information relating
				# to this product and let the
				# subsequent  subset loads repopulate
				# the file with the correct information.
				#
				PCODE=`expr "$_S" : '^\(...\).*'`
				SWDB_EraseLocks $_S "^$PCODE"
			fi
	
			#
			# Mark the subset as having completed the
			# populate.  Since the populate code is run once
			# per member, do not propagate the change to
			# the other members.
			#
			SWDB_MarkSubset $_S _populate_completed
			POPULATE_SUCCESS_LIST="$POPULATE_SUCCESS_LIST $_S"
		fi

		#
		# Remove the temporary files
		#
		rm -f $ERROR_MSG_FILE \
			$INVFILE \
			$M0_INVFILE

		#
		# Tick once for the completion of the verify stage
		#				
		INST_SendStatusBarCommand "tick 1"
	}

	return $RETURN_VAL
}



:	-PositionTape
#		position tape to a specified location
#
#	given:	$1 - volume number to position to
#		$2 - setld readable file position on the tape to go to
#		global $_CPOS - current tape position
#	does:	position the tape to be able to read the specified volume
#		and file
#	return:	0 if all's well.
#		1 on failure.
#	effect:	global $_CVOL - may change to reflect new position
#		global $_CPOS - may change to reflect new position

PositionTape()
{
	NEWVOL=$1		# desired volume
	NEWPOS=$2		# desired position

	case "$NEWPOS" in
	-[123])	;;
	-*)	DEFMSG="Unaccessible tape position %s"
		Ferror 1 "`message -E -S -V 600 -F installsetld \
			setld.cat -s SETLD2 \
			POSITIONTAPE_UNACCESS_TAPE_POS \
			\"$DEFMSG\" \"$NEWPOS\"`"
	esac

	# make sure the tape drive isn't being used...
	Wait MTPID

	#  1. get the correct volume mounted
	[ "$NEWVOL" != "$_CVOL" ] &&
	{
		# volume change logic
		DEFMSG=" \n\
Volume change. Rewinding tape...\\\c"
		echo "`message -S setld.cat -s SETLD2 \
			POSITIONTAPE_VOL_CHANGE \
			\"$DEFMSG\"`"

		TickWhile "mt -f $RAW rew && mt -f $RAW offl" ||
		{
			DEFMSG="\n\
Unable to dismount your tape.  Please take the tape drive\n\
off line manually."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD2 \
				POSITIONTAPE_CANNOT_DISMOUNT \
				\"$DEFMSG\"`"
		}
		DEFMSG=" \n\
Please remove tape volume %1\$s and replace it with volume %2\$s."
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			POSITIONTAPE_TAPE_REPLACE \
			\"$DEFMSG\" \"$_CVOL\" \"$NEWVOL\"`"

		while :
		do
			Ready
			mt -f $RAW rew && break
		done
		_CVOL=$NEWVOL
		_CPOS=-$T_0
	}

	#  2. get the correct position in the volume
	MOVE=`expr $_CPOS - $NEWPOS`
	_CPOS=$NEWPOS

	case "$MOVE" in
	0)	# we're at it.
		;;
	-*)	# forward X files.
		MOVE=`Parse - $MOVE`
		TickWhile "mt -f $RAW fsf $MOVE"
		;;
	*)	MOVE=`expr $MOVE + 1`
		TickWhile "mt -f $RAW bsf $MOVE && mt -f $RAW fsf"
		;;
	esac
	return $?	# returns value of last exec in case
}


:	-PostClusterCheck
#		Check to see if processing post installation/deletion
#		on a cluster system
# 
#	given:	nothing
#	does:	Conditional returns 0 if yes it is a post operation
#		on a cluster and 1 if it is not.
#	return:	0 is it is a post operation on a cluster.
#		1 is it is not a post operation on a cluster.
#
PostClusterCheck()
{
	if [ -s "$MEMBERS_N_STATUS" -a ! "$ADVFLAG" \
	     -a ! "$UPDFLAG" -a ! "$UPD_HWFLAG" ]
	then
		return 0
	else
		return 1
	fi
}


:	-PostLoad 
#		transition to proto state and call scp with POST_L 
# 
#	given:	a subset id	
#	does:	1) transition files to proto state 	
#		2) if in update installation, execute merge files
#		3) run scp POST_L
#	return:	0 is successful, 1 on error
#

PostLoad()
{
	SUBSET=$1

	ReadCtrlFile $_R/$SMDB $SUBSET

	# transition to proto state
	CopyProto $SUBSET

	# if in update installation, execute merge files
	[ "$UPDFLAG" -o "$UPD_HWFLAG" ] && UpdMerge $SUBSET ToProto

	#
	# Do not invoke the POST_L phase of the .scp file when
	# running setld -u, since the POST_L phase should only be
	# executed once per cluster and -u runs once per member.
	#
	[ "$CMDSW" = "u" ] && 
		return 0

	[ -f $SMDB/$SUBSET.scp ] ||
		return 1

	Log "$SUBSET SCP POST_L \c"
	if ACT=POST_L $SMDB/$SUBSET.scp; then 
	{
		DEFMSG="SUCCEEDED"
		Log "`message -S setld.cat -s SETLD3 \
			LOG_SUCCEEDED_MSG \
			\"$DEFMSG\"`"

		#
		# Make sure the subset is in the correct state
		#
		SWDB_MarkSubset $SUBSET _post_load_completed
		SWDB_ClusterPropagate $SUBSET

		# if in update installation:
		# transfer subset dependency locks and remove predecessors' 
		# smdb files
		[ "$UPDFLAG" -o "$UPD_HWFLAG" ] &&
			SWDB_UpdateLockFiles $SUBSET

		# create subset locks in .lk of subsets depended upon.

		# check to see if K is " " or "."
		# using expr which returns 1 if the first
		# character in K matches any character within [].
		# If K is " " or "." then no dependencies to add to
		# the .lk file

		for K in $DEPS
		{
			EDEP=`expr match "$K" '[ .]'` 

			[ "$EDEP" = 1 ] && break

			#resolve any "?" meta characters
			#and replace with installed version
			#eg. abc40? with abc405 and abc407

			for J in `SWDB_FindLoadedSubsets $K`
			{
				SWDB_AddLock $J $SUBSET

				# take out duplicates
				SWDB_Unique $J
			}
		}	

		# If this is a post-initial installation, re-create 
		# any dependencies on this subset as necessary.
		#
		# Get list of subsets that are dependent ON THIS SUBSET
		# being installed.  Do not execute this segment for full,
		# update, or dataless client installations.
		#
		[ ! "$ADVFLAG" -a ! "$UPDFLAG" -a ! "$DMS_NEW_AREA" ] &&
		{
			#
			# The grep -l returns the names of the files and
			# the sed operation strips off the .ctrl and any
			# path information so that all that is left is
			# the subset name for each subset.
			#
			DEP_SUBS=`grep -l "DEPS=.*$SUBSET.*" $SMDB/*.ctrl \
				| sed -e 's/\.ctrl//' -e 's!.*/!!'`

			# We should now have a list of subsets that depend
			# on "$SUBSET" being installed.  If no dep's exist
			# then just return.
			#
			[ "$DEP_SUBS" ] || return 0
		
			# Create a new subset lock file and populate it
			# with any installed subsets that are dependent
			# upon this one.
			#
			for HAS_THIS_DEP in $DEP_SUBS
			do
				SWDB_IsInstalled $HAS_THIS_DEP && \
					SWDB_AddLock $SUBSET $HAS_THIS_DEP
			done
		}	
		return 0
	}
	else
	{
		DEFMSG=" \n\
\"%1\$s\" (%2\$s) failed in subset control program (POST_L)." 
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD2 \
			POSTLOAD_FAIL_IN_POSTL \
			\"$DEFMSG\" \"$SDESC\" \"$SUBSET\"`"
		SWDB_IsLocked $SUBSET &&
		{
			DEFMSG2=" \n\
This failure may adversely affect the operation of the following subsets:\\\n"
			echo "`message -S setld.cat -s SETLD2 \
				POSTLOAD_AFFECT_SUBSET \
				\"$DEFMSG2\"`"
			SWDB_ListLockingSubsets $SUBSET
		}

		SWDB_MarkSubset $SUBSET _post_load_failed "$DEFMSG$DEFMSG2"
		SWDB_ClusterPropagate $SUBSET
		return 1
	}; fi

}


:	-PrepInstall
#		prepare for subset installation.
#	given:	subset list specified on setld -l command line (may be empty)
#	does:	1) presents setld menu (if no subsets specified)
#		2) copy instctrl info to SMDB
#		3) check disk space
#		4) dependency ordering
#		5) prepare/save files for update installation.
#	effect:	modify (order) global $SBS
#	return: 0 if success
#		non-0 if failure
# 

PrepInstall() 
{
	ARGS=$*
	NOT_DEPSORT=0	# not sorted by dependency yet

	if [ `Length $ARGS` = 0 ] 
	then
		# no subsets specified on command line

		[ `Length $SBS` -gt 200 ] && echo "
Processing user responses and selections may take up to several minutes."
	
		SplitByType || return $?


		# copy over instctrl info 
		CopyInstctrl "$MAND $OPT" 

		TickWhile PreSize install $MAND 
		case $? in
		1)	DEFMSG="\n\
There is sizing or access problem installing the mandatory subsets."  
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				PREPINSTALL_SIZE_ACCESS_ERR_MANDATORY \
				\"$DEFMSG\"`"
			return 1
			;;
		2)	DEFMSG=" \n\
There is not enough file system space to install the mandatory subsets."
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				PREPINSTALL_NOSPACE_FOR_MANDATORY \
				\"$DEFMSG\"`"
			return 1
			;;
		3)	DEFMSG=" \n\
<warning> Installing the mandatory subsets will cause file systems \n\
to be (over) 100%% full." 
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				PREPINSTALL_SYSTEM_FULL_MANDATORY \
				\"$DEFMSG\"`"
			;;
		esac

		case "$ADVFLAG" in
		0|2)	# basic installation
			SBS=$MAND

                        [ `Length $SBS` -gt 0 ] &&
                        {
                        	for X in $SBS
                                {
                                	ReadCtrlFile $_TDIR $X
                                        export DESC$X
                                }

				SBS=`(cd $_TDIR; DependencyOrder $SBS)`
				NOT_DEPSORT=1

                                export SBS

				DEFMSG=" \n\
The following subsets will be installed:"
				echo "`message -S setld.cat -s SETLD3 \
				PREPINSTALL_INSTALLING_SUBSET \
				\"$DEFMSG\"`"

				stlmenu -$CMDSW -s -i display SBS || 
					return $?
			}
			;;
		*)	# present menu	
			MenuSelect "$MAND" "$OPT" subset || return $?
		esac
	else
		# subsets specified on command line, stored in $ARGS

		ARGS=`ListNoDup $ARGS`
		MISSING_SUBSETS=`ListContained -s "$ARGS" "$SBS"` ||
		{
			MISSING_SUBSETS=`echo $MISSING_SUBSETS`
			DEFMSG="\
The following specified subsets are not available on the\n\
distribution media:\n\
\n\
\t%s\n"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				PREPINSTALL_MISSING_SUBSET \
				\"$DEFMSG\" \"$MISSING_SUBSETS\"`"
			Exit 1
		}

		if [ "$UPDFLAG" ] 
		then
			# in update installation, we copy instctrl info of all 
			# available subsets on the kit to SMDB 
			CopyInstctrl "$SBS" "$ARGS"

			# in update installation, updeng calls fitset
			# directly before invoking setld. So there's no
			# need to call PreSize again here.
 
		else
			if [ "$CMDSW" = "p" ]
			then
				#copy instctrl info of all subsets on the kit
				CopyInstctrl "$SBS"
			else
				# copy instctrl info of specified subsets only.
				CopyInstctrl "$ARGS"
			fi

			#if post installation with arguments then invoke
			#depord to do dependency inclusion and ordering
			[ "$ADVFLAG" ] ||       #not initial installation
			{
				ALL_SBS=`(cd $_TDIR; depord -i $ARGS)`
				#remove the original subset arguments from the
				#list returned from depord to get the included
				#subsets
				INC_SBS=`ListUniq "$ALL_SBS" "$ARGS"`
	
				#if subsets are to be included tell the user
				[ -n "$INC_SBS" ] &&
				{
					DEFMSG="\n\
The chosen subsets require one or more additional subsets\n\
which will be loaded automatically:"
					Error "`message -E -S -V 500 \
						-F installsetld \
						setld.cat -s SETLD3 \
						PREPINSTALL_REQUIRE_SUBSET \
						\"$DEFMSG\"`"

 					for X in $INC_SBS
					{
						#display the description of each
						#subset
						ReadCtrlFile $_TDIR $X
						echo "* $SDESC  ($X)"
					}
				}

				# copy instctrl info of required subsets only.
				CopyInstctrl "$INC_SBS"

				# set the original subset argument list to
				# the new subset list resulting from depord

				ARGS=$ALL_SBS

			}
			DEFMSG="\n\
Checking file system space required to install specified subsets:"
			echo "`message -S setld.cat -s SETLD3 \
				PREPINSTALL_CHECK_SPACE \
				\"$DEFMSG\"`"

			TickWhile PreSize install $ARGS
			case $? in
			0) 	DEFMSG="\n\
File system space checked OK." 
				echo "`message -S setld.cat -s SETLD3 \
					PREPINSTALL_CHECK_SPACE_OK \
					\"$DEFMSG\"`"
				;;
			1)	DEFMSG="\n\
There is sizing or access problem installing the specified subsets." 
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD3 \
					PREPINSTALL_SIZE_ACCESS_ERR_SPECIFIED \
					\"$DEFMSG\"`"
				return 1
				;;
			2)	DEFMSG="\n\
There is not enough file system space to install the specified subsets."
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD3 \
					PREPINSTALL_NOSPACE_FOR_SPECIFIED \
					\"$DEFMSG\"`"
				return 1
				;;
			3)	DEFMSG="\n\
<warning> Installing the specified subsets will cause file systems \n\
to be (over) 100%% full."
				Error "`message -E -S -V 500 -F installsetld \
					setld.cat -s SETLD3 \
					PREPINSTALL_SYSTEM_FULL_SPECIFIED  \
					\"$DEFMSG\"`"
				;;
			esac
		fi

		SBS=$ARGS	

	fi

	#
	#       This code looks for scp_extensions dropped by other installations
	#       to see whether there are new restrictions on the installation
	#       of this subset.
	#       In general the scp_extension is an extension of the .scp and contains
	#       knowledge that wasn't know at the time of the subset
	#       Manufacturing.
	#
	#       For each subset in list, check for an existence of a scp_extension,
	#       If it exists, execute it and if the status is a failure,
	#       remove the subset from the subset list.
	NEW_SUBSET_LIST=
	for CURRENT_SUBSET in $SBS
	{
		TOADD=$CURRENT_SUBSET
		[ -x $SMDB/$CURRENT_SUBSET.scp_extension ] &&
		{
			ACT=POST_M $SMDB/$CURRENT_SUBSET.scp_extension || TOADD=
		}
		NEW_SUBSET_LIST="$NEW_SUBSET_LIST $TOADD"
	}
	SBS=$NEW_SUBSET_LIST

	# order $SBS according to dependency.
	[ "$NOT_DEPSORT" = 0 ] &&
		SBS=`(cd $_TDIR; DependencyOrder $SBS)`

	# if update installation, save current copies (.new../.proto../conf) 
	# of protected files that need to be updated. 

	[ "$UPDFLAG" -o "$UPD_HWFLAG" ] && BackupMergedFiles

	#
	# Specific directories are created by setld with owner, group,
	# and permission values that differ from the OSFBASE500 subset
	# definitions. For full installs, modify these attributes now
	# to avoid subsequent fverify corrections and messages.
	#
	if [ "$ADVFLAG" ]
	then
		chown adm:adm $U/$V/$CLUSTER/$MEMBER_ID/$A > $D/null 2>&1
		chown adm:adm $U/$V/$A > $D/null 2>&1
		chmod ugo=rwxrwxrwt $U/$V/$CLUSTER/$MEMBER_ID/$T > $D/null 2>&1
	fi

	return 0
}


:	-PreSize
#		determine is space is available to -l/-x a subset to
#	the system.
#
#	given:	$1 - operation description in {install,extract}
#		$2... - names of objects to be operated upon
#	does:	permit space to be measured before reading software
#		onto the system
#	return:	0 is operation can be performed in the available space,
#		1 if not.
#	effect:	none, closed context
#

PreSize()
{ (
	OPCODE=$1
	shift
	SUBSETS=$*

	[ "$SUBSETS" ] || return 0	# no subsets.

	case "$OPCODE" in
	extract)
		
		# use the size variables in the .ctrl file and
		# the sizes of the .ctrl, .inv, and .scp files
		# to determine the total size of extraction
		CSIZE=0
		TSIZE=0
		>$TMP1
		for S in $SUBSETS
		{
			if [ -f $_SRC/$S ]; then
				grep -E $S $_TDIR/*.image >> $TMP1
				SIZE=`ls -s $_TDIR/$S.* | awk '{print $1}'`
				SIZES="$SIZES $SIZE"
			else
				CSIZE=`ls -l $_TDIR/$S.* | awk '
					{ sum += $5 }
					END { print sum }'`
				ReadCtrlFile $_TDIR $S 2>/dev/null
				TSIZE=`expr $TSIZE + $CSIZE + $ROOTSIZE + $USRSIZE + $VARSIZE`
			fi
		}
		BLKSIZE=`expr \( $TSIZE + 511 \) / 1024`

		# RISADDSIZE is a global enviroment variable which is 
		# created by the routine CalcAddSize in /isl/OSFBASE.ris.
		# This routine is called by RIS to calcuate the 
		# additional file system space that is needed for 
		# the RIS extract to take place. If this
		# variable is not set, then don't do anything.

		[ "$RISADDSIZE" ] &&
			BLKSIZE=`expr $BLKSIZE + $RISADDSIZE`

		# add up the sizes of all of the images
		ISIZE=`awk '
			BEGIN	{size=0}
				{size += $2}
			END	{print size}' < $TMP1`
	
	
		# add up image size and all individual file sizes
		SIZE=0
		for X in $SIZES $ISIZE
		{
			SIZE=`expr $SIZE + $X`
		}

		# Add the size of the compressed subsets and 
		# control files (SIZE) to the size of the expanded
		# subsets and control files (BLKSIZE). Note that
		# units are in 1024 byte blocks.
		SIZE=`expr $SIZE + $BLKSIZE`

		# get freespace from system
		if [ "$DEFPATH" = 0 ]
		then
			FREESPACE=`df -k $_R | awk 'NR == 2 {print $4}'`
		else
			FREESPACE=`df -k . | awk 'NR == 2 {print $4}'`
		fi

		# If there's enough space return 0, otherwise 1
		[ "$SIZE" -lt "$FREESPACE" ] && return 0
		return 1
		;;

	install)
		echo "
SUBSET $SUBSETS at $_R:" >> $FITSETLOG
		SUBSETS=`(cd $_TDIR;DependencyOrder $*)`
		#
		# cram all of the specified inventory files thru fitset
		#
		> $_R/$V/$T/allinv 

		for S in $SUBSETS
		{
				cat $_TDIR/$S.inv >> $_R/$V/$T/allinv 
		}

		#
		# Create an stl_inv(4) style inventory entry for
		# the "allinv" file, so that 'fitset' can credit
		# us back the space that we're using to temporarily
		# store this file.
		#
		ils ./$V/$T/allinv > $_TMPDIR/temp.inv

		fitset -c $_TMPDIR/temp.inv $_R < $_R/$V/$T/allinv
		FITSTAT=$?

		rm $_R/$V/$T/allinv 2>/dev/null
		return $FITSTAT 
		;;
	*)	DEFMSG="PreSize(): %s: unknown opcode"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			PRESIZE_UNKNOWN_OPCODE \
			\"$DEFMSG\" \"$OPCODE\"`"
	esac
) }


:	-ReadCtrlFile
#		Initialize control file values
#
#	given:	$1 - pathname for directory to search for control file
#		$2 - name of subset
#	does:	read the file and verify it's contents
#		saves the control attributes
#	return:	1 on error
#	effect:	sets DESC, SDESC, NVOLS, MTLOC, DEPS, FLAGS
#			sets \$DESC$2....
#

ReadCtrlFile()
{
	# initialize, clean up residual values
	DESC=
	NVOLS=
	MTLOC=
	DEPS=
	FLAGS=
	ROOTSIZE=
	USRSIZE=
	VARSIZE=

	# this variable stores the subset description without the category
	SDESC=

	[ $# = 2 ] ||
	{
		DEFMSG="ReadCtrlFile(%1\$s): expected 2 args, received %2\$s"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			READCTRLFILE_ARGS_CHECK \
			\"$DEFMSG\" \"$*\" \"$#\"`"
		return 1
	}
	L_DIR=$1	# directory to search
	L_SUB=$2	# subset name

	# check to see if the information is already cached 
	eval SET=\$SET$L_SUB
	[ "$SET" = 1 ] &&	# retrieve the info
	{
		eval DESC=\$DESC$L_SUB
		eval SDESC=\$SDESC$L_SUB
		eval NVOLS=\$NVOLS$L_SUB
		eval MTLOC=\$MTLOC$L_SUB
		eval DEPS=\$DEPS$L_SUB
		eval FLAGS=\$FLAGS$L_SUB
		eval ROOTSIZE=\$ROOTSIZE$L_SUB
		eval USRSIZE=\$USRSIZE$L_SUB
		eval VARSIZE=\$VARSIZE$L_SUB
		return 0
	}

	# info not cached, read and cache
	if [ "$LANG" -a -f $L_DIR/$LANG/$L_SUB.ctrl ]
	then
		ABS_CTRL_DIR=$L_DIR/$LANG
	elif [ -f $L_DIR/$L_SUB.ctrl ]
	then
		ABS_CTRL_DIR=$L_DIR
	else
		DEFMSG="ReadCtrlFile(): cannot find %1\$s/%2\$s.ctrl"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			READCTRLFILE_NO_EXIST_CTRL \
			\"$DEFMSG\" \"$L_DIR\" \"$L_SUB\"`"
		return 1
	fi
	. $ABS_CTRL_DIR/$L_SUB.ctrl ||
	{
		DEFMSG="ReadCtrlFile(): error reading %1\$s/%2\$s.ctrl"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			READCTRLFILE_CANNOT_READ_CTRL \
			\"$DEFMSG\" \"$ABS_CTRL_DIR\" \"$L_SUB\"`"
		return 1
	}

	# did we get it all?
	case "~$DESC~$NVOLS~$MTLOC~$DEPS~$FLAGS~" in
	*~~*)	# Control File appears to be incomplete
		DEFMSG="ReadCtrlFile(): %1\$s/%2\$s.ctrl is incomplete"
		Error "`message -E -S -V 500 -F installsetld \
			setld.cat -s SETLD3 \
			READCTRLFILE_INCOMPLETE_CTRL \
			\"$DEFMSG\" \"$ABS_CTRL_DIR\" \"$L_SUB\"`"
		return 1
	esac

	# Get root, usr and var sizes.

	# Inventory file will be used only if all the sizes turn out to
	# be zero  - if there are no *SIZE fields in the .ctrl file initialize
	# those variables to zero and force reading of .inv files
	# using the kits (/usr/bin/kits) algorithm

	grep "ROOTSIZE" $ABS_CTRL_DIR/$L_SUB.ctrl > /dev/null || ROOTSIZE=0
	grep "USRSIZE" $ABS_CTRL_DIR/$L_SUB.ctrl  > /dev/null || USRSIZE=0
	grep "VARSIZE" $ABS_CTRL_DIR/$L_SUB.ctrl > /dev/null || VARSIZE=0

	if [ "$ROOTSIZE" = 0 -a "$USRSIZE" = 0 -a "$VARSIZE" = 0 ]
	then

		[ -f $ABS_CTRL_DIR/$L_SUB.inv ] ||
		{
			DEFMSG="ReadCtrlFile(): cannot find %1\$s/%2\$s.inv"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				READCTRLFILE_NO_EXIST_INV \
				\"$DEFMSG\" \"$ABS_CTRL_DIR\" \"$L_SUB\"`"
			return 1
		}
	
		INV_SIZE=`awk 'BEGIN { root=0; usr =0; var =0;}
			{
				if ( substr ($10, 1, 6) == "./var/" )
					var +=$2
				else
					if ( substr ( $10, 1, 10 ) == "./usr/var/" )
						var +=$2
					else
						if ( substr  ($10, 1, 6) == "./usr/" )
							usr += $2
						else
							root +=$2

			}
		END { printf "%d\t%d\t%d", root, usr, var }' $ABS_CTRL_DIR/$L_SUB.inv`

		ROOTSIZE=`echo "$INV_SIZE" | cut -f1`
		USRSIZE=`echo "$INV_SIZE" | cut -f2`
		VARSIZE=`echo "$INV_SIZE" | cut -f3`

	fi
				 
	# filter out category in the subset description
	# then filter trailing space
	SDESC=`echo $DESC | sed 's/ *%.*//'`

	# preserve the information
	eval DESC$L_SUB='$DESC'
	eval SDESC$L_SUB='$SDESC'
	eval NVOLS$L_SUB='$NVOLS'
	eval MTLOC$L_SUB='$MTLOC'
	eval DEPS$L_SUB='$DEPS'
	eval FLAGS$L_SUB='$FLAGS'
	eval ROOTSIZE$L_SUB='$ROOTSIZE'
	eval USRSIZE$L_SUB='$USRSIZE'
	eval VARSIZE$L_SUB='$VARSIZE'

	# mark the subset as 'set'
	eval SET$L_SUB=1
	return 0
}


:	-RemoteMemberFunction
#		Run a setld command remotely on each cluster member
#
#	given/Inputs:
#		$1 - command line option letter ("C" or "Z")
#		$* - subsets to process on each member
#	Outputs: None
#	does:	Attempts to rsh to each cluster member to run setld
#		with the given command line option.  For each member
#		that fails, create an "it" job to retry the task
#		the next time that member boots.#		
#	return:	Nothing
#	effect/Notes:	None
#

RemoteMemberFunction()
{ (
	FUNC="$1"
	shift
	SUBSET_LIST=$*

	# If we're not running in a cluster, then there are no
	# other members.  We're done.
	#
	PostClusterCheck ||
		return

	MY_MEMBER_ID=`INST_CLU_GetMemberID`

	awk '{print $1, $2, $3}' $MEMBERS_N_STATUS |
	while read MEMBER_NUM MEMBER_NAME MEMBER_STATUS
	do
		MEMBER_ID="member"$MEMBER_NUM
		export MEMBER_ID

		# Determine the name of the it job data file for this
		# function.
		#
		M0_DATA="$FUNC"SETLDCDATA
		POSTDATA=`eval echo "$"$M0_DATA \
			| sed 's/member0/'$MEMBER_ID'/'`

		# Create "it" job and its data file ($POSTDATA) for the
		# function, listing all subsets to be processed.
		#
		itruns setld_$FUNC in 23
		echo "$SUBSET_LIST" | fmt -1 | tr -d ' ' | grep . \
			>> $_R/$POSTDATA
		sort -u -o $_R/$POSTDATA $_R/$POSTDATA

		# If the member is down, we're done.  The it job is
		# ready to run when the system comes back up.
		#
		[ "$MEMBER_STATUS" = "UP" ] ||
			continue

		# Initialize success/failure lists.
		#
		RSHLIST=
		RSHFAIL=

		# Attempt to perform the function remotely on the
		# requested machine.  Keep track of which subsets
		# succeed and which fail.
		#
		for SUBSET in $SUBSET_LIST
		{
			if [ "$MEMBER_ID" = "$MY_MEMBER_ID" ]
			then
				/usr/sbin/setld \
					-m $MEMBER_ID -$FUNC $SUBSET \
					< /dev/null
				FUNC_STATUS=$?
			else
				rsh -l root $MEMBER_NAME \
					/usr/sbin/setld \
					-m $MEMBER_ID -$FUNC $SUBSET \
					< /dev/null
				FUNC_STATUS=$?
			fi

			if [ "$FUNC_STATUS" = 0 ]
			then
				RSHLIST="$RSHLIST $SUBSET"
			else
				RSHFAIL="$RSHFAIL $SUBSET"
			fi
		}

		# If we couldn't rsh to the member for
		# any subset, report it.
		#
		if [ "$RSHFAIL" ]
		then
			DEFMSG="\
Could not remotely run setld -%1\$s on %2\$s for %3\$s"
			Error "`message -E -S -V 500 \
				-F installsetld \
				setld.cat -s SETLD5 \
				INSTALL_NO_SETLD_FUNC \
				\"$DEFMSG\" \"$FUNC\" \"$MEMBER_NAME\" \
				\"$RSHFAIL\"`"
		fi

		# Remove the RSHLIST subsets from the it job data file,
		# because those subsets have just had the function
		# performed.
		#
		sort -u $_R/$POSTDATA > $_TMPDIR/$MEMBER_ID.cp
		echo $RSHLIST | fmt -1 | tr -d ' ' | grep . | sort -u \
			> $_TMPDIR/$MEMBER_ID.ok
		comm -23 $_TMPDIR/$MEMBER_ID.cp $_TMPDIR/$MEMBER_ID.ok \
			> $_R/$POSTDATA
		rm -f $_TMPDIR/$MEMBER_ID.cp \
			$_TMPDIR/$MEMBER_ID.ok

		# If the it job data file is now empty,
		# there's no need to run the it job.
		#
		[ -s $_R/$POSTDATA ] ||
		{
			rm -f /$CLUSTER/$MEMBER_ID/sbin/it.d/23.d/setld_$FUNC \
				$_R/$POSTDATA
		}
	done
) }


:	-ReportDepErr
#		Output warning message with a list of uninstalled required subsets
#
#	given/Inputs:	$* - list of uninstalled required subsets
#	Outputs: warning message with a list of uninstalled required subsets
#	does:	separates list of subsetnames with meta characters from regular
#		subsetnames and outputs the appropriate warning message
#	return:	Nothing
#	effect/Notes:	None
#

ReportDepErr()
{

	REGLIST=		# list of regular subsetnames
	METALIST=		# list of subsetnames with meta characters

	for SUBNAME in $*
	{
		if expr match $SUBNAME '^[A-Z0-9]*$' > /dev/null
		then
			# subsetname is regular
			REGLIST="$REGLIST $SUBNAME"
		else
			# subsetname has a meta character
			METALIST="$METALIST $SUBNAME"
		fi
	}

	[ "$REGLIST" ] &&
	{
		# Add specific regular subsetnames error msg
		DEFMSG=" %s \n\
The following subsets are required:"
		Derr_msg="`message -S setld.cat -s SETLD3 \
		REPORTDEPERR_DERR_MSG1 \
		\"$DEFMSG\" \"$Derr_msg\"`"

		for REG in $REGLIST
		{
			ReadCtrlFile $_R/$SMDB $REG 2>/dev/null 
			# Add each regular description and subsetname 
	Derr_msg=" $Derr_msg
	\"$SDESC\" ($REG)"
		}

	}

	[ "$METALIST" ] &&
	{
		# Add specific meta character subsetnames error msg
		DEFMSG=" %s \n\
Versions of subsets matching the following patterns are required:"
		Derr_msg="`message -S setld.cat -s SETLD3 \
		REPORTDEPERR_DERR_MSG2 \
		\"$DEFMSG\" \"$Derr_msg\"`"

		for META in $METALIST
		{
			# Add each meta character subsetname
			Derr_msg=" $Derr_msg
		$META"
		}
	}

		# Output dependency error message.
	DEFMSG="%s \n\
Please install required subsets first." 
	Error "`message -E -S -V 500 -F installsetld \
		setld.cat -s SETLD3 \
		REPORTDEPERR_REQUIRED_SUBSET \
		\"$DEFMSG\" \"$Derr_msg\"`"
	return
}	


:	-SplitByType
#		split subset list into optional and mandatory
#
#	given:
#	does:
#	return:

SplitByType()
{
	MAND="" # list of mandatory subsets
	OPT=""  # list of optional subsets

	# scan control files, differentiate OPT & MAND subsets
	INSTALLED=		# smu-2290
	for _S in $SBS
	{
		case "$CMDSW" in
		l)
			# make sure subset is not installed.
			SWDB_IsInstalled $_S &&
			{
				INSTALLED=1
				continue
			}
			;;
		x)	# Make sure subset is not already on server
			[ -f $_S ] &&
			{
				INSTALLED=1
				continue
			}
		esac

		ReadCtrlFile $_TDIR $_S

		# if STL_NOACTM is not set, run scp with M action.
		#  Will fail if subset does not want to appear on the menu.

		[ "$STL_NOACTM" ] ||
		{
			# If the operation is an extract, then we
			# need to run the scp based off /. Otherwise,
			# the scp may fail.
			if [ "$OPERATION" = "extract" ]; then
				(cd $_R; ACT=M $_TDIR/$_S.scp -$CMDSW) || continue
			else
				ACT=M $_TDIR/$_S.scp -$CMDSW || continue
			fi
		}

		# bit 2 on flags means subset is optional
		case `FlagsAttrCheck SATTR_OPTION $FLAGS` in
		1)	OPT="$OPT $_S"
			;;
		*)	MAND="$MAND $_S"
		esac
	}
	case "$MAND$OPT$INSTALLED" in
	"")
		case $OPERATION in
		extract)
			DEFMSG="No extractable subsets on your kit"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				SPLITBYTYPE_NONE_TO_EXTRACT \
				\"$DEFMSG\"`"
			;;
		install)
			DEFMSG="No installable subsets on your kit"
			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				SPLITBYTYPE_NONE_TO_INSTALL \
				\"$DEFMSG\"`"
			;;
		esac
		return 1
		;;
	1)
		case $OPERATION in
		extract)
			DEFMSG="All subsets on the kit are already extracted"
			Error "`message -E -S -V 500 -F installsetld\
				setld.cat -s SETLD3 \
				SPLITBYTYPE_ALREADY_EXTRACTED \
				\"$DEFMSG\"`"
			;;
		install)
			DEFMSG="All subsets on the kit are already installed"
			Error "`message -E -S -V 500 -F installsetld\
				setld.cat -s SETLD3 \
				SPLITBYTYPE_ALREADY_INSTALLED \
				\"$DEFMSG\"`"
			;;
		esac
		return 1
	esac
}



:	-UpdMerge
#		execute the merge files in the specified subset
#	given: 	1) a subset id
#		2) merge option to pass to the merge file, i.e., ToProto or
#		   ToConfig.
#	does:	For each .mrg..filename listed in the .inv, execute 
#		the merge with specified option.
#
#	return: 0 

UpdMerge()
{ (
	SUBSET=$1
	OPTION=$2

	MRGFILES=`grep -E '/\.mrg\.\.' $SMDB/$SUBSET.inv | awk '{print $10}'`

	for K in $MRGFILES
        {
                FNAME=`echo $K | sed 's/\.mrg\.\.//'`
		MRG_PerformMerge $OPTION $SUBSET $FNAME
        }

	return 0
) }



:	-UpdMoreOpt
#		more optimization for update installation merges.
#
#	given:	a subset
#	does:	Goes through newly delivered merge scripts in a subset,
#		if the target file was customized (indicated by the
#		absence of .passMRG), check if the new .new.. is the
#		same as the old one (.new..file.PreMRG). If they are the
#		same, leave a mark for UpdMerge() to pick up.
#	return:	0	
#

UpdMoreOpt()
{
	SUBSET=$1

	MRGFILES=`grep -E '/\.mrg\.\.' $SMDB/$SUBSET.inv | awk '{print $10}'`

	for K in $MRGFILES
        {
		#
		# Strip off the .mrg..
		#
                FNAME=`echo $K | sed 's/\.mrg\.\.//'`

		#
		# Set variables based on FNAME
		#
		#	_D = directory
		#	_F = file
		#	MF = merge file
		#	NF = .new.. file
		#	PF = .proto.. file
		#	CF = configured file
		# _PASSMRG = skip merge due to failure/optimization
		# _FAILMRG = failed results file
		# _KEEPCUS = skip merge due to no new functionality
		#
		MRG_SetFileVariables $SUBSET $FNAME

		[ -f $_D/$_PASSMRG ] &&
		{
			# there was no customization (no merge necessary)
			continue
		}
 
		[ -f $_D/$NF.PreMRG ] || 
		{
			# no previous version of .new.. saved (can't optimize
			# further)
			continue
		}

		# further optimization: check if newly delivered
		# .new.. is the same as the old one or not.
                # Note: works with ASCII files only.

		# first filter out RCS strings and Copyright strings
		grep -E -v '^# @\(#\)\$RCSfile|^#.*Copyright \(c\) Digital Equipment' $_D/$NF 	   > $TMP1  2>/dev/null
		grep -E -v '^# @\(#\)\$RCSfile|^#.*Copyright \(c\) Digital Equipment' $_D/$NF.PreMRG > $TMP2  2>/dev/null

		# then diff the real contents of the files
                diff $TMP1 $TMP2 >/dev/null 2>&1
		[ $? = 0 ] && 
		{
			# drop a mark to bypass merge process and
			# keep the customization.
			DNAME=`dirname $_D/$_KEEPCUS`
			[ -d $DNAME ] || mkdir -p $DNAME
			> $_D/$_KEEPCUS
		
			# remove backups since $PF and $CF
			# will remain unchanged (customized).
			rm -f $_D/.*..$_F.PreMRG $_D/$CF.PreMRG
		}
	}

	return 0
}



:	-Usage
#		print usage messages
#
#	given:	$1 - switch for which message to print
#	does:	prints a particular usage message
#	return:	nothing

Usage()
{
	case "$1" in
	"")	Error -n "$USAGE"
		;;
	-c)	DEFMSG="\n\
Usage:\n\
%s"
		Error -n "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				USAGE_CUSAGE_MSG \
				\"$DEFMSG\" \"$CUSAGE\"`" 
		;;
	-d)	DEFMSG="\n\
Usage: %s"
		Error -n "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				USAGE_DUSAGE_MSG \
				\"$DEFMSG\" \"$DUSAGE\"`" 
		;;
	-h)	echo "$USAGE"
		;;
	esac
	return 0
}


:	-Verify
#		verify the integrity of the installation subsystem
#
#	given:	$* - list of subsets to be verified 
#	does:   For each subset specified:
#		1) check if subset is installed.
#		2) read control file to get subset description 
#		3) test ivp
#	return: nothing

Verify()
{
	cd $_R
	ERR=0
	for _S in $*
	{
		SWDB_IsInstalled $_S ||
		{
			DEFMSG="%s: not currently loaded"
			Error "`message -E -S -V 400 -F installsetld \
				setld.cat -s SETLD1 \
				E_NOLOAD_MSG \
				\"$DEFMSG\" "$_S"`"
			ERR=1
			continue
		}

                # read .ctrl to get subset description ($SDESC), 
                # ReadCtrlFile() will provide proper error msg when needed.
		ReadCtrlFile $_R/$SMDB $_S  

		Log "$_S SCP V \c"
		echo "
$SDESC ($_S)"

		ACT=V $SMDB/$_S.scp ||
		{
			DEFMSG="ivp failed."
 			Error "`message -E -S -V 500 -F installsetld \
				setld.cat -s SETLD3 \
				VERIFY_IVP_FAIL \
				\"$DEFMSG\"`"
			ERR=1
			continue
		}

		DEFMSG="SUCCEEDED"
		Log "`message -S setld.cat -s SETLD3 \
			LOG_SUCCEEDED_MSG \
			\"$DEFMSG\"`"
	}
	return $ERR
}



:	-VerifySuccessful
#		update smdb files to reflect successful verify
#
#	given:	$1 - subset which succeeded
#	does:	updates the smdb files
#	return:	nothing

VerifySuccessful()
{
	S=$1


}



#% CODE
#	actual code begins here. This is structured this way to
#	enable interactive debugging of the independent subroutines
#	by setting CHECK_SYNTAX to something and running '. setld'

[ "$CHECK_SYNTAX" ] || Main "$@"
