#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72V src/bos/usr/lib/nim/methods/c_mkspot.sh 1.54.4.8 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1993,2020 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)12        1.54.4.8  src/bos/usr/lib/nim/methods/c_mkspot.sh, cmdnim, bos72V, v2020_14B1  3/30/20  18:25:44
#
#   COMPONENT_NAME: CMDNIM
#
#   FUNCTIONS: ./usr/lib/nim/methods/c_mkspot.sh
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 1993
#   All Rights Reserved
#   Licensed Materials - Property of IBM
#   US Government Users Restricted Rights - Use, duplication or
#   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
#

# include common NIM shell defines/functions
NIMPATH=${0%/*}
NIMPATH=${NIMPATH%/*}
[[ ${NIMPATH} = ${0} ]] && NIMPATH=/usr/lpp/bos.sysmgt/nim
NIM_METHODS="${NIMPATH}/methods"
. ${NIM_METHODS}/c_sh_lib

#---------------------------- local defines     --------------------------------
typeset -i FUDGE_FACTOR=5

TAR_CREATE="${TAR} -cdpf - -C"
TAR_EXTRACT="${TAR} -xpf -"

#---------------------------- module globals    --------------------------------
REQUIRED_ATTRS="location name source type st_applied st_committed"
OPTIONAL_ATTRS="arch source_name version release installp_flags auto_expand mount_opts mksysb ios_mksysb nim_sync"
location=""
name=""
source=""
type=""
version=""
release=""
mod=""
src_access=""
src_lic_access=""
refresh=""
source_is_tape=""
tftp_enabled_by_nim=""
mk_usr_spot=""
not_41_master=""
arch=""
source_name=""
bos_license="no"
#lpp_source=""
mspot_list=/usr/lib/bootpkg/bootpkg_list
LSNIM=""
XARGS=/usr/bin/xargs

#---------------------------- undo              --------------------------------
#
# NAME: undo
#
# FUNCTION:
#		backs out changes made by c_mkspot
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1->					= error message stuff
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function undo {

	nim_unmount # umount anything which has been mounted by nim_mount

	[[ $# = 1 ]] && err_from_cmd $1 || error $@

} # end of undo

#---------------------------- ck_size_req       --------------------------------
#
# NAME: ck_size_req
#
# FUNCTION:
#		verifies that the target filesystem (where the SPOT is being created) has
#			enough free space to store the SPOT files (which will come from the
#			source)
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_size_req {
	# don't check if this is for a /usr conversion
	[[ ${location} = /usr ]] && return 0

	typeset spot_fs=""
	typeset first_dir=""
	typeset image_data_file=${1}
	typeset -i size_req=0
	typeset -i free_blocks=0

	# can we read the file?
	[[ ! -r "${image_data_file}" ]] && \
		error ${ERR_FILE_ACCESS} ${image_data_file}

	# parse out the size requirement
	${AWK} '	/^[ 	]*$/ { fs_data = 0; fs_name = 0;};\
				$1 == "fs_data:" {fs_data = 1;};\
				$1 == "FS_NAME=" {if ( $2 == "/usr" ) fs_name = 1;};\
				$1 == "FS_SIZE=" {if (fs_data && fs_name) print "size_req=" $2;};' \
		${image_data_file} >${TMPDIR}/size_req 2>${ERR} || err_from_cmd ${AWK}
	[[ -s ${TMPDIR}/size_req ]] && . ${TMPDIR}/size_req || \
		error ${ERR_SIZE} ${source}

	# find the first directory which currently exists in the pathname of the
	#     target location
	first_dir=${location}
	while [[ -n "${first_dir}" ]]
	do
		[[ -d ${first_dir} ]] && break
		first_dir=${first_dir%/*}
	done

	# is the SPOT being created in a local jfs or jfs2 filesystem?
	${C_STAT} -a location=${first_dir} -a vfstype="0 3" 2>${ERR} || \
	  err_from_cmd ${C_STAT}

	# what filesystem will the SPOT reside in?
	spot_fs=$( ${DF} -P ${first_dir} 2>${ERR} | ${AWK} 'NR==2{print $6}' )
	[[ -z "${spot_fs}" ]] && err_from_cmd ${DF}

	# how much free space in that filesystem?
	free_blocks=$( ${DF} -P ${spot_fs} 2>${ERR} | ${AWK} 'NR==2{print $4}' )
	[[ -z "${free_blocks}" ]] && err_from_cmd ${DF}

	# is there enough space?
	if (( ${size_req} > ${free_blocks} ))
	then

		# should we auto expand the filesystem?
		[[ "${installp_flags}" != *X* ]] && [[ "${auto_expand}" = "no" ]] && \
			error ${ERR_SPACE} ${spot_fs} ${size_req} ${free_blocks}

		# subtract the currently available space
		let "size_req-=free_blocks"

		# expand the filesystem
		${CHFS} -a size=+${size_req} ${spot_fs} 2>${ERR} 1>&2 || \
			err_from_cmd "${CHFS} ${spot_fs}"

	fi

} # end of ck_size_req

#---------------------------- prep_tape         --------------------------------
#
# NAME: prep_tape  
#
# FUNCTION:
#		prepares the specified tape device for use
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_tape {

	typeset bs=""

	source_is_tape=TRUE

	# tape needs a "no-rewind-on-close" extension 
	# remove whatever extension was given and use ".1"
	src_access="${source%.*}.1"

	# cache the logical device name of the tape drive
	tape_device_name=${source##*/}
	tape_device_name=${tape_device_name%.*}

	# get current block_size
	bs=$( ${LSATTR} -El ${tape_device_name} 2>${ERR} | \
			${AWK} '$1=="block_size"{print $2}' )
	[[ -z "${bs}" ]] && err_from_cmd ${LSATTR}

	# block_size needs to be 512: should we change it?
	if [[ ${bs} != 512 ]]
	then

		${CHDEV} -l ${tape_device_name} -a block_size=512 1>/dev/null 2>${ERR} ||\
			err_from_cmd ${CHDEV}

		# by setting the global "tape_block_size" var, the cleanup function will
		#		reset the block_size to the original value
		tape_block_size=${bs}

	fi

	# rewind the tape
	${TCTL} -f ${src_access} rewind 2>${ERR} || err_from_cmd ${TCTL}

	# position to 4th record
	${TCTL} -f ${src_access} fsf 3 2>${ERR} || err_from_cmd ${TCTL}

	# need to validate the AIX release level of this image & determine its
	#		size requirements
	# therefore, restore the LPP_NAME and IMAGE_DATA files now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${src_access} ${LPP_NAME} ${IMAGE_DATA} 2>${ERR} 1>&2 || \
		err_from_cmd "${RESTORE} -xqf ${src_access} ${LPP_NAME} ${IMAGE_DATA}"

	# validate the release level
	ck_rel_level ${TMPDIR}/${LPP_NAME}

	# make sure there's enough space to create the new SPOT
	ck_size_req ${TMPDIR}/${IMAGE_DATA}

	# pop_spot expects tape to be positioned to the BOS image, so reposition 
	#		to 4th record now
	${TCTL} -f ${src_access} rewind 2>${ERR} || err_from_cmd ${TCTL}
	${TCTL} -f ${src_access} fsf 3 2>${ERR} || err_from_cmd ${TCTL}

	# initialize the method to restore the files
	restore_func="${RESTORE} -xqf ${src_access}"

} # end of prep_tape

#---------------------------- prep_cd           --------------------------------
#
# NAME: prep_cd
#
# FUNCTION:
#		prepares a CDROM device as the source for a SPOT
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_cd {

	# mount the CDROM
	nim_mount ${source}
	[[ ! -e "${access_pnt}/${BOS_PATH_ON_CDROM}" ]] && \
		BOS_PATH_ON_CDROM=${BOS_PATH_ON_CDROM_OLD}
	src_access=${access_pnt}/${BOS_PATH_ON_CDROM}
	src_lic_access=${access_pnt}/${LIC_PATH_ON_CDROM}

	# need to validate the AIX release level of this image & determine its
	#		size requirements
	# therefore, restore the LPP_NAME and IMAGE_DATA files now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${src_access} ${LPP_NAME} ${IMAGE_DATA} >/dev/null \
		2>${ERR} || err_from_cmd ${RESTORE}

	# validate the release level
	ck_rel_level ${TMPDIR}/${LPP_NAME}

	# make sure there's enough space to create the new SPOT
	ck_size_req ${TMPDIR}/${IMAGE_DATA}

	# initialize the method to restore the files
	restore_func="${RESTORE} -xqf ${src_access}"

} # end of prep_cd

#---------------------------- prep_SPOT         --------------------------------
#
# NAME: prep_SPOT
#
# FUNCTION:
#		prepares an existing SPOT to be used as a source for the creation of the
#			new SPOT
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_SPOT {

	typeset -i spot_version=0
	typeset -i spot_release=0
	typeset -i spot_mod=0

	# make sure source pathname ends with "/usr"
	if [[ "${source##*/}" != usr ]]
	then
		source=${source}/usr
	fi

	# setup local access
	nim_mount ${source}
	src_access=${access_pnt}

	# validate the version/release/mod level by looking in the product 
	#		database of the SPOT
	ODMDIR=${src_access}/lib/objrepos ${ODMGET} -qlpp_name=bos.rte product \
		>${TMPDIR}/spot.product 2>${ERR} || err_from_cmd ${ODMGET}
	let spot_version=$( ${AWK} '$1=="ver"{print $3}' ${TMPDIR}/spot.product \
								2>/dev/null )
	let spot_release=$( ${AWK} '$1=="rel"{print $3}' ${TMPDIR}/spot.product \
								2>/dev/null )
	let spot_mod=$( ${AWK} '$1=="mod"{print $3}' ${TMPDIR}/spot.product \
								2>/dev/null )
	if ((${spot_version}<${version})) ||
		((${spot_release}<${release}))
	then
		error ${ERR_RELEASE} ${spot_version} ${spot_release} ${source}
	fi

    let version=${spot_version}
    let release=${spot_release}
    let mod=${spot_mod}

	# make sure there's enough space to create the new SPOT
	ck_size_req ${src_access}/${IMAGE_DATA_IN_SPOT}

	# append "/usr" to <location> (because "/usr" part will not come from source)
	location=${location}/usr

	# initialize the method to restore the files
	restore_func="copy_SPOT ${src_access} ${location}"

} # end of prep_SPOT

#---------------------------- copy_SPOT         --------------------------------
#
# NAME: copy_SPOT
#
# FUNCTION:
#		copies the specified SPOT to the specified destination
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function copy_SPOT {

	typeset origin=${1}
	typeset dest=${2}

	# cd to original SPOT
	cd ${origin} 2>${ERR} || err_from_cmd cd

	# copy all the files
	${TAR_CREATE} ${origin} . | ( cd ${dest}; ${TAR_EXTRACT} ) || return 1

} # end of copy_SPOT

#----------------------------   get_newest_ver      --------------------------------
#
# NAME: get_newest_ver
#
# FUNCTION:
#		Given a version number in VRMF, and a list of versions in VRMF,
#		output the latest version in the list that is <= the given version
#		number
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters: file with list of VRMFs
#			    a version in VRMF
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT: a VRMF version number
#-------------------------------------------------------------------------------
function get_newest_ver
{
	typeset VERSION_FILE=$1
	typeset MYVER=$2
	typeset -i10 sver=0 srel=0 smod=0 sfix=0
	typeset -i10 this_ver=0 this_rel=0 this_mod=0 this_fix=0
	typeset final LINE

	[[ -f $VERSION_FILE ]] || error $ERR_FILE_MODE "open" $VERSION_FILE

	sver=`echo $MYVER | $CUT -d '.' -f 1` || err_from_cmd cut
	srel=`echo $MYVER | $CUT -d '.' -f 2` || err_from_cmd cut
	smod=`echo $MYVER | $CUT -d '.' -f 3` || err_from_cmd cut
	sfix=`echo $MYVER | $CUT -d '.' -f 4` || err_from_cmd cut

	while read LINE
	do
		if [[ $MYVER = $LINE ]]
		then
			final=$MYVER
			break
		fi

		this_ver=`echo $LINE | $CUT -d '.' -f 1` || err_from_cmd cut
		this_rel=`echo $LINE | $CUT -d '.' -f 2` || err_from_cmd cut
		this_mod=`echo $LINE | $CUT -d '.' -f 3` || err_from_cmd cut
		this_fix=`echo $LINE | $CUT -d '.' -f 4` || err_from_cmd cut
	
		if [[ $sver -gt $this_ver ]]
		then
			final=$LINE
		elif [[ $sver -eq $this_ver && $srel -gt $this_rel ]]
		then
			final=$LINE
		elif [[ $sver -eq $this_ver && $srel -eq $this_rel && $smod -gt $this_mod ]]
		then
			final=$LINE
		elif [[ $sver -eq $this_ver && $srel -eq $this_rel && $smod -eq $this_mod && $sfix -gt $this_fix ]]
		then
			final=$LINE
		fi		

	done <$VERSION_FILE

	echo $final
}

#----------------------------    prep_mksysb      --------------------------------
#
# NAME: prep_mksysb
#
# FUNCTION:
#		when the source is a mksysb, mounts resources and prepares variables
#		to later execute mksysb_SPOT
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_mksysb
{
	typeset WORKDIR
	typeset this_list=/tmp/$$.list
	typeset ver_list tar_list ls_list tf

	WORKDIR=$(/usr/lib/instl/libinst_mkworkdir) || err_from_cmd libinst_mkworkdir
	this_list=$WORKDIR/list
	ver_list=$WORKDIR/ver_list
	tar_list=$WORKDIR/tar_list
	ls_list=$WORKDIR/ls_list
	tf=$WORDIR/tmp_file

	$RM -f $this_list $ver_list $tar_list $tf $ls_list
	
	#mount the mksysb resource
	nim_mount ${source}
	mksysb_loc=${access_pnt}

	[[ -z $mksysb_loc ]] && error ${ERR_NFS_MNT} ${mksysb} "a temporary directory"

	(cd $TMPDIR;$RESTORE $mksysb_loc ./image.data 2>&1 >$ERR || err_from_cmd restore)
	mksysb_ver=$($GREP "OSLEVEL=" $TMPDIR/image.data 2>/dev/null | $CUT -d ' ' -f 2)

	# get the right list from the SPOT list file
	$EGREP '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:' $mspot_list >$tf || err_from_cmd egrep
	$SED 's/://g' $tf >$ver_list || err_from_cmd sed
	final=$(get_newest_ver $ver_list $mksysb_ver) || err_from_cmd get_newest_var

	${AWK} -vver=$final 'BEGIN{this=0} /.*:$/ {this=0;if ($1 == ver ":") {this=1;next}} {if (this == 1 && NF > 0) print;}' $mspot_list > $this_list 2> $ERR || err_from_cmd awk

	# now find the right tar file (for the libnim.a.min)
	$LS /usr/lib/bootpkg/*-spotpkg.tar >$ls_list || err_from_cmd ls
	$AWK '{gsub("/usr/lib/bootpkg/", "", $0);gsub("-spotpkg.tar", "", $0); print}' $ls_list >$tar_list || err_from_cmd awk
	final=$(get_newest_ver $tar_list $mksysb_ver) || err_from_cmd get_newest_var
	tar_file=/usr/lib/bootpkg/${final}-spotpkg.tar

	#if the list is empty, error out
	[[ ! -s $this_list ]] && error ${ERR_NO_LIST}

	# initialize the method to restore the files
	restore_func="mksysb_SPOT ${mksysb_loc} ${location} ${this_list}" #${lpp_loc}
}

#----------------------------     restore_symlinks     --------------------------------
#
# NAME: restore_symlinks
#
# FUNCTION:
#		Given a symlink and a backup file, this function will restore the file
#		linked to by the symbolic link and will continually follow successive
#		symlinks restored until a regular file is restored.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		makes recursive calls
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters: relative path of symlink
#			    path to backup file
#			    boolean recursive value
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function restore_symlinks
{
        SYMLINK=$1
        BACKUP_NAME=$2
        ONE_MORE=$3

	#restore the actual file
        $RESTORE $BACKUP_NAME $SYMLINK > /dev/null 2> ${ERR} || err_from_cmd restore

	#base case is that the current file is not a symlink
        if [[ $ONE_MORE = "0" ]]
        then
		#progress is made by following whatever is linked to next
                NEW_LINK=$($LS -l $SYMLINK | $AWK '{print $11}') 

		#stop the recursion if the current file is not a symlink
                [[ -h $SYMLINK ]] || ONE_MORE=1 
                [[ $ONE_MORE = "0" ]] && restore_symlinks ".$NEW_LINK" $BACKUP_NAME $ONE_MORE
        fi
} #end restore_symlinks

#----------------------------     mksysb_SPOT     --------------------------------
#
# NAME: mksysb_SPOT
#
# FUNCTION:
#		Extracts necessary files from the source mksysb based on the SPOT lists and 
#		the .proto files contained on the mksysb
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#	
#
# RECOVERY OPERATION:
#		calls error function
#
# DATA STRUCTURES:
#		parameters: mksysb path, spot path, list file path, lpp_source mount point
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function mksysb_SPOT
{
	MKSYSB=$1
	SPOTDIR=$2
	LISTFILE=$3
	TEMP1=/tmp/$$.ong
	TEMP2=/tmp/$$.tuk
	NEW_ROOT=$SPOTDIR/usr/lpp/bos/inst_root
	no_proto=
	no_file=

	#here, generate list of .proto files to restore using lsnim -a if_supported master
	PROTO_LIST=$(${LSNIM} -a if_defined master | ${AWK} '/.*:/{} /.*=.*/{printf("%s%s%s%s\n", $1, $2, $3, $4)}' | $AWK -F'=' '{print $2}' | $AWK -F'.' '{printf("./usr/lib/boot/network/%s.%s.proto\n", $1, $3)}')
	
	#we'll need the disk proto file for atm boot images
	PROTO_LIST="$PROTO_LIST ./usr/lib/boot/chrp.disk.proto"

	$GREP /usr/lpp/bos/inst_root $LISTFILE | $SED 's/\/usr\/lpp\/bos\/inst_root//' > $TEMP1
	$GREP -v /usr/lpp/bos/inst_root $LISTFILE > $TEMP2

	#first restore all proto files and all protoext files, then restore the /usr file system of the SPOT
	cd $SPOTDIR
	${RESTORE} $MKSYSB ./usr/lib/boot/network/*.proto ./usr/lib/boot/*.proto ./usr/lib/boot/protoext/* ./usr/lib/boot/unix /usr/lib/boot/unix_up ./usr/lpp/bosinst/BosMenus ./usr/bin/tee ./usr/lpp/bos.sysmgt/nim/methods/c_* > /dev/null 2> ${ERR} || err_from_cmd restore
	/usr/sbin/restore -xqdf $MKSYSB ./usr/lib/methods ./usr/lib/drivers ./usr/lib/microcode ./usr/lpp/bosinst/iscsi > /dev/null 2> ${ERR} || err_from_cmd restore
	${XARGS} ${RESTORE} $MKSYSB < $TEMP2 > /dev/null 2> ${ERR} || err_from_cmd xargs

	#restore the files from bos.sysmgt.nim.spot and c_errmsg
	$TAR -xf $tar_file 2>$ERR >/dev/null || err_from_cmd tar

	#restore all boot images from MKSYSB's /tftpboot into TMPDIR/tftpboot
	cd ${TMPDIR} || err_from_cmd cd
	/usr/sbin/restore -xqdf $MKSYSB ./tftpboot >/dev/null 2>&1
	if [[ -s ./tftpboot ]]; then
		cd ./tftpboot || err_from_cmd cd

		#rename boot image files to match the current SPOT name stored in $name
		for file in `${LS} *.*.*`
		do
			# extract the SPOT name from boot images in MKSYSB
			prefix=`echo $file | ${AWK} -F"." '{print $1}'`

			# replace with our SPOT name from $name
			new_booti=`echo $file | ${SED} "s/$prefix/$name/g"`

			# move images to /tftpboot
			${MV} $file $TFTPBOOT/$new_booti > /dev/null 2> ${ERR} || err_from_cmd mv
		done

		cd $SPOTDIR || err_from_cmd cd
		${RM} -rf $TMPDIR/tftpboot > /dev/null 2> ${ERR} || err_from_cmd rm
	fi

	ODMDIR=$SPOTDIR/usr/lib/objrepos
	#see what filesets need to be added to the ODM
	for i in $DEFAULT_SPOT_OPTIONS_43
	do
		#fake out the ODM to make NIM think that required filesets were normally installed 
		echo "product:\nlpp_name=\"$i\"\nstate=5" | $ODMADD >/dev/null 2>${ERR} || err_from_cmd odmadd
	done
	ODMDIR=/etc/objrepos

	#restore the inst_root part of the SPOT
	$MKDIR -p $NEW_ROOT >/dev/null 2>${ERR} || err_from_cmd mkdir
	$LN -fs $SPOTDIR/usr/bin $NEW_ROOT/bin >/dev/null 2>${ERR} || err_from_cmd ln
	$LN -fs $SPOTDIR/usr/lib $NEW_ROOT/lib >/dev/null 2>${ERR} || err_from_cmd ln
	cd $NEW_ROOT >/dev/null 2>${ERR} || err_from_cmd cd
	${RESTORE} $MKSYSB ./etc/objrepos/Cu* ./etc/objrepos/Pd* > /dev/null 2> ${ERR} || err_from_cmd restore
	/usr/sbin/restore -xqdf $MKSYSB ./sbin/helpers > /dev/null 2> ${ERR} || err_from_cmd restore
	${XARGS} ${RESTORE} $MKSYSB < $TEMP1 > /dev/null 2> ${ERR} || err_from_cmd xargs

	$MKDIR -p $NEW_ROOT/var/adm/nim 2>&1 > /dev/null

	$RM $TEMP1 $TEMP2 $LISTFILE 2>&1 > /dev/null

	for i in $PROTO_LIST
	do
		if [[ -f $SPOTDIR/$i ]]
		then
			#get the name of the boot device this proto file is for
			dev=$(echo ${i##*/} | $AWK -F. '{print $2}')
			
			#grab all the files needed in the /usr part of the SPOT
			# (they are the 6th field in the proto file, if we're looking at a regular file)
			$AWK '{if (length($6) > 0 && $2 == "----" && substr($6, 1, 4) == "/usr"){print "."$6}}' $SPOTDIR/$i >$TEMP1 2>${ERR} || err_from_cmd awk

			#grab all the files needed in the root part of the SPOT (same rules as above)
			$AWK '{if (length($6) > 0 && $2 == "----" && substr($6, 1, 4) != "/usr"){print "."$6}}' $SPOTDIR/$i >$TEMP2 2>${ERR} || err_from_cmd awk

			#add all files listed in this device's protoext files (there's only /usr files in there)
			if $LS $SPOTDIR/usr/lib/boot/protoext/${dev}.proto.ext.* > /dev/null 2>&1; then
				$AWK '{if (length($6) > 0){print "."$6}}' $SPOTDIR/usr/lib/boot/protoext/${dev}.proto.ext.* >>$TEMP1 2>${ERR} || err_from_cmd awk
			fi

			#Some protoext files may refer to symbolic links even though it is not noted in the file
			#we still have to track down these links and restore them. This will be done through the 
			#calls to restore_symlinks below.

			#restore /usr part and then / part
			cd $SPOTDIR
			[[ -s $TEMP1 ]] && ${XARGS} ${RESTORE} $MKSYSB < $TEMP1 > /dev/null 2> ${ERR} || err_from_cmd restore
		
			#in /usr part, if a proto file is a symlink, restore the file(s) it links to
			# also, warn if proto files are missing
			for i in $($CAT $TEMP1)
			do
				[[ ! -e $i ]] && no_file=1 #check for missing files
				[[ -h $i ]] && restore_symlinks $i $MKSYSB 0
			done

			#do the same for root part
			cd $NEW_ROOT
			[[ -s $TEMP2 ]] && ${XARGS} ${RESTORE} $MKSYSB < $TEMP2 > /dev/null 2> ${ERR} || err_from_cmd restore

			for i in $($CAT $TEMP2)
			do
				[[ ! -e $i ]] && no_file=1 #check for missing files
				[[ -h $i ]] && restore_symlinks $i $MKSYSB 0
			done

			$RM $TEMP1 $TEMP2 2>&1 > /dev/null
		else
			no_proto=1
		fi
	done

	[[ -n $no_proto ]] && warning ${ERR_MISSING_PROTO_FILES}
	[[ -n $no_file ]] && warning ${ERR_MISSING_FILES}
	[[ ! -f $SPOTDIR/usr/lib/boot/unix_mp ]] && [[ -n `$LSNIM -a if_defined master | ${GREP} mp` ]] && warning ${ERR_MISSING_UNIX_MP}

	#restore the symlinks in inst_root
	$LN -fs /usr/bin $NEW_ROOT/bin >/dev/null 2>${ERR} || err_from_cmd ln
	$LN -fs /usr/lib $NEW_ROOT/lib >/dev/null 2>${ERR} || err_from_cmd ln	

	echo mksysb_source=${mksysb}
}

#---------------------------- prep_file         --------------------------------
#
# NAME: prep_file       
#
# FUNCTION:
#		prepares environment to use a file as the source
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_file {

	typeset dir=${source%/*}
	typeset filename=${source##*/}

	# setup local access to source
	nim_mount ${dir}
	src_access=${access_pnt}/${filename}

	# need to validate the AIX release level of this image & determine its
	#		size requirements
	# therefore, restore the LPP_NAME and IMAGE_DATA files now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${src_access} ${LPP_NAME} ${IMAGE_DATA} >/dev/null \
		2>${ERR} || err_from_cmd ${RESTORE}

	# validate the release level
	ck_rel_level ${TMPDIR}/${LPP_NAME}

	# make sure there's enough space to create the new SPOT
	ck_size_req ${TMPDIR}/${IMAGE_DATA}

	# initialize the method to restore the files
	restore_func="${RESTORE} -xqf ${src_access}"

} # end of prep_file

#---------------------------- prep_dir          --------------------------------
#
# NAME: prep_dir        
#
# FUNCTION:
#		prepares environment to access a directory containing a BOS image
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_dir {

	# setup local access to BOS image
	nim_mount ${source}
	# check for installp/ppc path location
	[[ -e "${access_pnt}/installp/ppc/bos" ]] && \
		src_access=${access_pnt}/installp/ppc/bos || \
		src_access=${access_pnt}/bos

	src_lic_access=${access_pnt}/${LIC_PATH_ON_CDROM}

	# need to validate the AIX release level of this image & determine its
	#		size requirements
	# therefore, restore the LPP_NAME and IMAGE_DATA files now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${src_access} ${LPP_NAME} ${IMAGE_DATA} >/dev/null \
		2>${ERR} || err_from_cmd ${RESTORE}

	# validate the release level
	ck_rel_level ${TMPDIR}/${LPP_NAME}

	# make sure there's enough space to create the new SPOT
	ck_size_req ${TMPDIR}/${IMAGE_DATA}

	# initialize the method to restore the files
	restore_func="${RESTORE} -xqf ${src_access}"

} # end of prep_dir

#---------------------------- prep_source       --------------------------------
#
# NAME: prep_source
#
# FUNCTION:
#		prepares the specified source device for use
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_source {

	# what kind of source?
	case ${type} in

		device)	# tape or CDROM?
					if [[ ${source} = /dev/rmt[0-9]* ]]
					then
						prep_tape
					elif [[ ${source} = /dev/cd[0-9]* ]] || [[ -f "${source}" ]] || [[ ${source} = /dev/usbms[0-9]* ]]
					then
						prep_cd
					else
						error ${ERR_SOURCE} ${source}
					fi
					;;

		spot)		# source is another SPOT
					prep_SPOT
					;;

		lpp_source) # source is directory containing a BOS image
					prep_dir
					;;

		mksysb|ios_mksysb)	# source is a mksysb of a system
					prep_mksysb
					;;

		*)			# unknown type
					error ${ERR_SYS} "unknown source type - \"${type}\""
					;;
	esac

} # end of prep_source

#---------------------------- pop_spot          --------------------------------
#
# NAME: pop_spot  
#
# FUNCTION:
#		creates a new SPOT by creating the directory and filling it files from
#			the specified source
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function pop_spot {

	# does location exist?
	if [[ ! -d ${location} ]]
	then

		# create the new directory & include the first_dir info
		${C_MKDIR} -alocation=${location} -aperms=${DEFAULT_PERMS} \
			>${TMPDIR}/tmp 2>${ERR} || err_from_cmd ${C_MKDIR}
		[[ -s ${TMPDIR}/tmp ]] && . ${TMPDIR}/tmp
		first_dir=${first_dir:-${location}}

	fi

	# let's get into the new directory
	cd ${location} 2>${ERR} || err_from_cmd cd

	# restore the source files
	[[ -z "${restore_func}" ]] && error ${ERR_SOURCE} ${source}
	if ${restore_func} >/dev/null 2>${ERR}
	then

		# keep what we've got so far
		# copy licensing data
		[[ -n $src_lic_access ]] && [[ -d $src_lic_access ]] &&
			${MKDIR} -p ${location}/${LIC_PATH_ON_CDROM} 2>/dev/null &&
			if ${CP} -R $src_lic_access/* ${location}/${LIC_PATH_ON_CDROM} 2>/dev/null
			then
				print "bos_license=yes"
			fi

	else

		# SPOT creation failed - remove the directory
		${RM} -r ${first_dir} 1>/dev/null 2>&1

		# display error msg
		err_from_cmd "${restore_func}"

	fi

	# When performing a spot-copy, we can skip the rest of
	# the file hierarchy processing. No reason to duplicate linkage
	[[ ${type} = "spot" ]] && return 0

	# Create directories in the SPOT where the server's
	# libraries will be mounted for the chroot environment
	${MKDIR} -p ${location}${NIM_CHROOT_LIBS1}
	${MKDIR} -p ${location}${NIM_CHROOT_LIBS2}

	nim_mount /usr/ccs/lib ${location}${NIM_CHROOT_LIBS1}
	nim_mount /usr/lib ${location}${NIM_CHROOT_LIBS2}

	# We now have our system's /usr/ccs/lib and /usr/lib mounted within
	# our spot which we'll use in our LIBPATH instead of the spot's
	# /usr/ccs/lib and /usr/lib in the chroot environment. However,
	# these mounted directories still contain symbolic links to
	# /usr/ccs/lib and /usr/lib which resolve to the spot's
	# /usr/ccs/lib and /usr/lib in the chroot environment. Therefore we
	# need to create two new directories which contain these same links
	# except have them point to our mounted directories and also have
	# them take precedence in our LIBPATH.

	# iterate through the two library directories we've overmounted
	for lib in /usr/ccs/lib /usr/lib
	do
		# create directory hierarchy to hold symbolic links
		for dir in `$FIND $lib -type d`; do
			[[ ! -d ${location}${NIM_CHROOT_LIBS_LINKS_BASE}${dir} ]] && \
				$MKDIR -p ${location}${NIM_CHROOT_LIBS_LINKS_BASE}${dir}
		done

		# create symbolic links
		#   'linkFrom' is the pathname to an existing symbolic link
		#   'linkTo' is the pathname 'linkFrom' points to
		for linkFrom in `$FIND $lib -type l`; do

			# need to locate the end of a potential chain of symbolic links
			linkTo=$linkFrom;

			while true; do
				# extract the path where the symbolc link points to
				linkTo=`$LS -l $linkTo 2>/dev/null | $AWK '{print $11}'`

				# no need to process any further if its a relative link
				if echo $linkTo | $EGREP -v '^/' > /dev/null 2>&1; then break; fi

				# finish looping when theres no more links to follow
				if [[ `$LS -l $linkTo 2>/dev/null | $AWK '{print $10}'` != '->' ]]; then break; fi
			done

			# create the link
			echo $linkTo | $EGREP '^(/usr/ccs/lib|/usr/lib)' > /dev/null 2>&1 && \
				[[ ! -e ${location}${NIM_CHROOT_LIBS_LINKS_BASE}${linkFrom} ]] && \
				$LN -s ${NIM_CHROOT_LIBS_BASE}${linkTo} ${location}${NIM_CHROOT_LIBS_LINKS_BASE}${linkFrom}

		done
	done

	nim_unmount ${location}${NIM_CHROOT_LIBS1}
	nim_unmount ${location}${NIM_CHROOT_LIBS2}

} # end of pop_spot

#---------------------------- ck_this_machine -------------------------------
#
# NAME: ck_this_machine 
#
# FUNCTION:
#		checks to make sure that the machine we're currently running on is at
#			version 4 or later
#		this is important because when we build a SPOT, we need to use version 4
#			commands/libs to do it correctly
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_this_machine {

	typeset msg=""
	typeset i=""
	typeset -i bos_version=0
	typeset -i bos_release=0

	# get the current version & release
	let bos_version=$(${UNAME} -v 2>/dev/null)
	let bos_release=$(${UNAME} -r 2>/dev/null)

	# check version/release
	if ((${bos_version}<${version})) || ((${bos_release}<${release}))
	then

		error ${ERR_RELEASE} ${bos_version} ${bos_release} server

	fi

	# check for options required to be a SPOT server
	if ck_spot_options /usr "${SPOT_SERVER_OPTIONS}" >${TMPDIR}/missing
	then

		# nothing else to do - server has all the required options
		return 0

	fi

	# missing some stuff - format the error message
	if [[ -s ${TMPDIR}/missing ]]
	then

		# missing some stuff - format the error message
		error ${ERR_MISSING_OPTIONS_OLD} server \
			"$( ${AWK} -F "=" '$1=="missing"{print "\t" $2}' ${TMPDIR}/missing)"

	else

		# missing some stuff - format the error message
		for i in ${SPOT_SERVER_OPTIONS}
		do

			msg="${msg}\t${i}\n"

		done
		error ${ERR_MISSING_OPTIONS_OLD} server "${msg}"

	fi

} # end of ck_this_machine

#---------------------------- secure_tftp_access ----------------------------
#
# NAME: secure_tftp_access 
#
# FUNCTION:
#		Modifies or creates /etc/tftpaccess.ctl to ensure tftp access 
#		is not granted to more than /tftpboot as a result of SPOT
#		creation on a machine in the NIM env.
#		
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		-- uncomments #allow:/tftpboot
#		-- comments out deny:/tftpboot
#		-- when looking for the above, assumes that whitespace may 
#		   have been inserted anywhere in the line (even though this
#		   is illegal).
#		-- creates file if does not exist
#		-- changes/sets permissions on /etc/tftpaccess.ctl
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#			tftp_enabled_by_nim     = tells if NIM uncommented the
#						  tftp entry in /etc/inetd.conf
#
# RETURNS: (int)
#		0				= success
#
# OUTPUT:
#-------------------------------------------------------------------------------

function secure_tftp_access {

	# if file already exists...
	if [ -s ${TFTPACCESS} ]
	then
		# is there a "deny" for /tftpboot that needs commenting out?
		DENY="^[ 	]*deny:[ 	]*\/tftpboot[ 	]*$"
		${GREP} -qE "${DENY}" ${TFTPACCESS}
		if [[ $? -eq 0 ]]
		then
			# comment it out
			${SED} "s/${DENY}/#deny:\/tftpboot/g" ${TFTPACCESS} \
					> ${TMPDIR}/.tftpaccess.ctl.$$
			[ $? -eq 0 ] && \
				${MV} ${TMPDIR}/.tftpaccess.ctl.$$ ${TFTPACCESS}
		fi

		# is there an "allow" for /tftpboot that needs uncommenting?
		ALLOW="^[ 	]*#[ 	]*allow:[ 	]*\/tftpboot[ 	]*$"
		${GREP} -qE "${ALLOW}" ${TFTPACCESS} 
		if [[ $? -eq 0 ]]
		then
			# uncomment the allow
			${SED} "s/${ALLOW}/allow:\/tftpboot/g" ${TFTPACCESS} \
					> ${TMPDIR}/.tftpaccess.ctl.$$
			[ $? -eq 0 ] && \
				${MV} ${TMPDIR}/.tftpaccess.ctl.$$ ${TFTPACCESS}
			has_access=1
		else
			# is there already access to /tftpboot?
			${GREP} -E "^allow:\/tftpboot$" ${TFTPACCESS} >/dev/null 2>&1
			[[ $? -eq 0 ]] && has_access=1
		fi
	else
		# File doesn't exist.  Leave it that way (unrestricted) if
		# NIM didn't just grant tftp access to this machine
		[[ -z "${tftp_enabled_by_nim}" ]] && return 0
	fi

	# append to file if necessary (or create if not there)
	if [[ -z "${has_access}" ]]
	then
		# add access for /tftpboot
		echo "# NIM access for network boot" >> ${TFTPACCESS}
		echo "allow:/tftpboot" >> ${TFTPACCESS}
	fi
	
	# make sure permissions and owner are correct
	${CHMOD} 644 ${TFTPACCESS}	
	${CHOWN} root.system ${TFTPACCESS}
	return 0
}

#---------------------------- usr_spot       --------------------------------
#
# NAME: usr_spot
#
# FUNCTION:
#		converts a /usr filesystem into a SPOT
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function usr_spot {

	typeset inst_root="${location}/${INST_ROOT}"

	# first, check to make sure that inst_roots haven't been removed
	${INURID} -q >/dev/null 2>${ERR}  
	if [[ $? -ne 0 ]] 
	then
		# let's display the output as a warning if it produced any
		# (inurid normally doesn't return any output from this test.)
		[[ -s ${ERR} ]] && warning_from_cmd ${INURID}

		# print our own error msg
		error ${ERR_NO_INST_ROOTS}
	fi
	

	# remove any INST_ROOT remaining around
	# we do this to ensure we're not left with a partial INST_ROOT
	protected_dir ${inst_root} || ${RM} -r ${inst_root} 2>/dev/null

	# generate the list of inst_root files to be restored
     ${RESTORE} -Tvqf${src_access} 2>/dev/null | \
        ${GREP} inst_root | ${AWK} '{print $2}' \
        >${TMPDIR}/inst_root.files 2>${ERR} || err_from_cmd ${AWK}
	[[ ! -s ${TMPDIR}/inst_root.files ]] && \
		error ${ERR_SYS} "unable to determine the list of inst_root files"

	# "cd" to "/"
	cd / 2>${ERR} || err_from_cmd cd

	# if source is a tape...
	if [[ -n "${source_is_tape}" ]]
	then

		# rewind the tape
		${TCTL} -f ${src_access} rewind 2>${ERR} || err_from_cmd ${TCTL}

		# position to 4th record
		${TCTL} -f ${src_access} fsf 3 2>${ERR} || err_from_cmd ${TCTL}

	fi

	# restore the BOS inst_root files from the source
	${restore_func} $(${CAT} ${TMPDIR}/inst_root.files) \
		>/dev/null 2>${ERR} || err_from_cmd ${restore_func}

	# add variable to NIMINFO file
	${C_NIMINFO} -alocation=${NIMINFO} NIM_USR_SPOT=${name} 2>${ERR} || \
		err_from_cmd ${C_NIMINFO}

} # end of usr_spot

#---------------------------- up_inetd_conf      -------------------------------
#
# NAME: up_inetd_conf
#
# FUNCTION:
#		updates the inetd.conf file in leu of an AIX command to do so (inetserv
#			has been withdrawn)
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= name of daemon to uncomment
#		global:
#			refresh				= non-NULL if inetd daemon needs to be refreshed
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#-------------------------------------------------------------------------------
function up_inetd_conf {

	typeset daemon=${1}
	typeset line=""
	typeset first_field=""

	[[ -z "${daemon}" ]] && return 1

	# make sure /etc/inetd.conf file is writable
	if [[ ! -w ${INETD_CONF} ]]
	then
		warning ${ERR_FILE_ACCESS} ${INETD_CONF}
		return 1
	fi

	# is there a line referencing <daemon> already?
	line=$(${GREP} -E "^${daemon}|^#${daemon}" ${INETD_CONF} 2>/dev/null)
	if [[ -z "${line}" ]]
	then
		warning ${ERR_FILE_MOD} ${INETD_CONF}
		return 1
	fi

	# is it active?
	if [[ ${line} = ${daemon}?* ]]
	then
		# already uncommented - nothing else to do
		return 0
	fi

	if [[ ${daemon} = "tftp" ]]
	then
		tftp_enabled_by_nim=1
	fi

	# uncomment the entry
	first_field=${line%%[ 	]*}
	line=${line#\#}
	if ${AWK} -v ff="${first_field}" -v new="${line}" \
		'{if ($1==ff) $0=new; print}' ${INETD_CONF} \
		>${TMPDIR}/$$.inetd_conf 2>${ERR}
	then

		if ${CAT} ${TMPDIR}/$$.inetd_conf >${INETD_CONF} 2>${ERR}
		then
			refresh=yes
		else
			warning ${ERR_FILE_MOD} ${INETD_CONF}
		fi

	else

		warning ${ERR_FILE_MOD} ${INETD_CONF}
		return 1

	fi

} # end of up_inetd_conf

#---------------------------- start_daemons     --------------------------------
#
# NAME: start_daemons
#
# FUNCTION:
#		starts the daemons required in order to access a SPOT (boopd & tftp)
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#-------------------------------------------------------------------------------
function start_daemons {

	# NOTE that the inetserv command is no longer available and, currently, there
	#		is no analogous command available
	# therefore, we'll update the inetd info ourselves

	refresh=""

	# for bootpd
	up_inetd_conf bootps

	# for tftp
	up_inetd_conf tftp

	# refresh the inetd daemon?
	if [[ -n "${refresh}" ]]
	then

		${REFRESH} -s inetd 2>${ERR} 1>&2 || \
			warning_from_cmd "${REFRESH} -s inetd"

	fi

} # end of start_daemons

#---------------------------- get_boot_images  --------------------------------
#
# NAME: get_boot_images
#
# FUNCTION:
#		gets the boot images from a source spot which was determined to be
#		cross platform
#
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#-------------------------------------------------------------------------------
function get_boot_images {

	host=${source%%:*}
	list_cmd=""
	tftpboot_fs=""
	tftpboot_available=0
	tftpboot_needed=0
	DEFAULT_TFTPBOOT_SPACE=8000

	# set a command for use as "lsnim" or "nimclient -l"
	${CAT} /etc/niminfo | ${GREP} "NIM_NAME=master" >/dev/null
	if [[ $? -eq 0 ]]
	then
		list_cmd="/usr/sbin/lsnim"
	else
		list_cmd="${NIMCLIENT} -l"
	fi
	
	# create list of if_supported image files
	if_list=`${list_cmd} -a if_supported ${source_name} | ${AWK} '(NR>1){print $3"."$4}'`

	# determine available space (exand if allowed)
	# which filesystem does tftpboot reside
	tftpboot_fs=$( ${DF} -Pk ${TFTPBOOT} 2>/dev/null | \
									${AWK} 'NR==2{print $6}' )
	tftpboot_available=$( ${DF} -Pk ${TFTPBOOT} 2>/dev/null | \
									${AWK} 'NR==2{print $4}' )
	for i in ${if_list}
	do
		let tftpboot_needed=tftpboot_needed+${DEFAULT_TFTPBOOT_SPACE}
	done

	# is there enough free space in /tftpboot?
	if (( tftpboot_needed > tftpboot_available ))
	then

		if [[ "${auto_expand}" = "no" ]]
		then
			error ${ERR_SPACE} /tftpboot "${tftpboot_needed}" "${tftpboot_available}"
		fi

		# subtract the currently available space
		let "tftpboot_needed-=tftpboot_available"

		# chfs needs a block size of 512
		let "tftpboot_needed*=2"
	
		#expand to fil requirements
		if ${CHFS} -a size=+${tftpboot_needed} ${tftpboot_fs} 2>${ERR} 1>&2
		then
			:
		else
			err_from_cmd "${CHFS} /tftpboot"
		fi
	fi

	# if source is local, host variable will be same as source
	if [[ "${source}" = "${host}" ]]
	then

		for if_def in ${if_list}
		do
			${CP} ${TFTPBOOT}/${source_name}.${if_def} ${TFTPBOOT}/${name}.${if_def}
		done

	elif [[ -n ${host} ]]
	then

		for if_def in ${if_list}
		do
			# usage - `tftp -o localfile host remotefile image` 
			/bin/tftp -o ${TFTPBOOT}/${name}.${if_def} ${host} ${TFTPBOOT}/${source_name}.${if_def} >/dev/null 2>&1
		done

	else
		error ${ERR_SYS} "null host assignment"
	fi

} # end of get_boot_images

#---------------------------- c_mkspot          --------------------------------
#
# NAME: c_mkspot
#
# FUNCTION:
#		creates a SPOT by populating the specified directory with the bos.rte
#			files from the specified source
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		this method does NOT install packages into the SPOT - that work is done
#			by c_instspot
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= SPOT created
#		1							= error encountered - message on stderr
#
# OUTPUT:
#-------------------------------------------------------------------------------

# signal processing
trap cleanup 0
trap err_signal 1 2 11 15

# NIM initialization
nim_init

# initialize local variables

# set parameters from command line
while getopts :a:qvf c
do
	case ${c} in

		a)		# validate the attr ass
				parse_attr_ass "${OPTARG}"

				# include the assignment for use in this environment
				eval ${variable}=\"${value}\"
				;;

		q)		# show attr info
				cmd_what
				exit 0
				;;

		f)		# not a 4.1 NIM master
				not_41_master=1
				;;

		v)		# verbose mode (for debugging)
				set -x
				for i in $(typeset +f)
				do
					typeset -ft $i
				done
				;;

		\?)	# unknown option
				error ${ERR_BAD_OPT} ${OPTARG}
				;;
	esac
done

# check for missing attrs
ck_attrs

[[ -n $ios_mksysb ]] && mksysb=$ios_mksysb

# set defaults
let version=${version:-4}
let release=${release:-0}
installp_flags=$( ck_installp_flags "${installp_flags}" )

# check this machine's version  - it must be at version 4 or greater
ck_this_machine

# Perform some SPOT location-specific tasks before calling prep_source...
if [[ ${location} != /usr ]]
then
	# Need to append the SPOTname to <location>
	if [[ -n ${nim_sync} ]]
	then
		# When a spot is renamed, the location directory is unchanged
		# and uses the original name. In the case of nim sync, we must
		# use the location of the source spot. We can do that by appending
		# the original name of the spot to the location variable.
		typeset orignametmp=${source%/usr}
		typeset origname=`/usr/bin/basename $orignametmp`
		location=${location}/${origname}
	else
		location=${location}/${name}
	fi
else
	# global variable to be used in ck_rel_level
	mk_usr_spot=yes
fi

#make an LSNIM variable and make it point to either lsnim or to nimclient -l depending on whether 
#this is on a NIM master
if [[ $NIM_CONFIGURATION = "master" ]]
then
	LSNIM="/usr/sbin/lsnim"
else
	LSNIM="/usr/sbin/nimclient -l"
fi

[[ -n $mksysb ]] && RESTORE="$RESTORE -xqf"

undo_on_interrupt="undo"

# prepare the source device for use
prep_source

# /usr SPOT or new location?
if [[ ${location} = /usr ]]
then

	# converting a /usr filesystem is relatively easy, but does require some
	#		checking
	# do so now
	usr_spot

else

	# need to create a directory and populate it
	pop_spot

fi

# if we get this far, we've got something worth keeping
# return the version, release and modification level on stdout
# as attr assignments so the calling method will pick them up
let version=${version}
let release=${release}
print "version=${version}"
print "release=${release}"

# modification level is only applicable for SPOT
# definitions starting with 4.2 and later and when
# the NIM master is running 4.2 or greater
if (( (( (( ${version} == 4 )) && (( ${release} >= 2 )) )) || (( ${version} > 4 )) )) &&
	[[ -n "${not_41_master}" ]]
then
	let mod=${mod}
	print "mod=${mod}"
fi

# start the daemons
start_daemons

# set up tftp permissions for /tftpboot
secure_tftp_access

# if different arch, we need to get boot images for new spot
if [[ -n ${arch} ]]
then
	get_boot_images
fi

# all done
exit 0

