#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72L src/bos/usr/lib/nim/methods/c_instspot.sh 1.72.5.4 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1993,2018 
# 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 
# @(#)13 1.72.5.4 src/bos/usr/lib/nim/methods/c_instspot.sh, cmdnim, bos72L, l2018_27A2 6/27/18 17:51:46

#
#   COMPONENT_NAME: CMDNIM
#
#   FUNCTIONS: ./usr/lib/nim/methods/c_instspot.sh
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 1993, 1995, 1996
#   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     --------------------------------
SPOT_INSTALLP_FLAGS="-agqQb"

#---------------------------- module globals    --------------------------------
REQUIRED_ATTRS="location name"
OPTIONAL_ATTRS="lpp_source installp_bundle installp_flags filesets auto_expand fixes fix_bundle show_progress mount_opts force"
location=""
lpp_source=""
src_access=""
ext_access=""
name=""
installp_bundle=""
bundle_access=""
installp_flags=""
filesets=""
spot_fs=""
auto_expand=""
installp_env_variable=""
fileset_list=""
non_41_master=""
check_hooks=""
default_spot_options_set="" 
tape_source=""
geninstall_cmd=""
updts=""
force=""

#---------------------------- undo              --------------------------------
#
# NAME: undo
#
# FUNCTION:
#		backs out changes made by c_instspot
#
# 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

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

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

	# cache the logical device name of the tape drive
	tape_device_name=${lpp_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

	# set a flag to indicate that the image source is a tape
	tape_source="yes"

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


	${CDCHECK} -aq $lpp_source 2>/dev/null 1>&2
	if [[ $? -eq 0 ]]; then
	        export AUTOMOUNT_DISABLE_FLAG="true"
        	${CDCHECK} -mq $lpp_source 2>/dev/null 1>&2
        	if [[ $? -eq 0 ]]; then
			lpp_source=`${CDCHECK} -mq $lpp_source 2>/dev/null`
		fi
	fi

	# mount the CDROM at a specific offset
	nim_mount ${lpp_source} ${new_root}${IMAGES}

	# images are actually at another offset
	[[ ! -d "${new_root}${IMAGES}${OFFSET_FOR_CDROM}" ]] && \
		OFFSET_FOR_CDROM=${OFFSET_FOR_CDROM_OLD}
	src_access=${IMAGES}${OFFSET_FOR_CDROM}
	ext_access=${new_root}${src_access}

} # end of prep_cd

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


	# need to mount lpp_source if it's remote or this is non-/usr SPOT
	if [[ ${lpp_source} = ?*:?* ]] || [[ -n "${new_root}" ]]
	then

		# mount images at a specific offset
		nim_mount ${lpp_source} ${new_root}${IMAGES}
		src_access=${IMAGES}
		ext_access=${new_root}${src_access}

	else

		# use the local directory
		src_access=${lpp_source}

	fi

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


	typeset objrepos=${new_root}/etc/objrepos
	typeset i=""

	# what kind of source?
	if [[ "${lpp_source}" = /dev/* ]] || [[ -f "${lpp_source}" ]]; then
		# non-/usr SPOT?
		if [[ ${location} != /usr ]]
		then
			# we need to use the server's device database in order to
			#		access the specified device once we chroot into the SPOT
			# to do this, we'll copy the server's Cu* database into the
			#		SPOT, then create an undo_on_exit script to clean out
			#		the SPOT's database

			# Save the original CuDvDr in the spot, since it contains
			# default entries that are needed in the network boot image.
			${CP} ${objrepos}/CuDvDr ${objrepos}/CuDvDr.spot 2>${ERR} || err_from_cmd ${CP}

			for i in /etc/objrepos/Cu*
			do

				# copy the object class into the SPOT
				${CP} ${i} ${objrepos} 2>${ERR} || err_from_cmd ${CP}

				# cleanup the SPOT's database when we're done
				[[ ${i} != ?*.vc ]] && \
					print "ODMDIR=${objrepos} ${ODMDELETE} -o ${i} > /dev/null 2>&1" >> \
						${TMPDIR}/undo_on_exit

			done

			# Move the original CuDvDr back.
			print "${MV} ${objrepos}/CuDvDr.spot ${objrepos}/CuDvDr > /dev/null 2>&1" >> ${TMPDIR}/undo_on_exit

		fi

		# tape or CDROM?
		if [[ ${lpp_source} = /dev/rmt[0-9]* ]]
		then
			prep_tape
		elif [[ ${lpp_source} = /dev/cd[0-9]* ]] ||[[ ${lpp_source} = /dev/usbms[0-9]* ]]  ||  [[ -f "${lpp_source}" ]]
		then
			prep_cd
		else
			error ${ERR_SYS} "invalid lpp_source device \"${lpp_source}\""
		fi
	elif [[ -d "${lpp_source}" ]] || [[ "${lpp_source}" = */* ]]; then
		# source is a directory
		prep_dir
	else
		# unknown type
		error ${ERR_SYS} "unknown lpp_source type - \"${lpp_source}\""
	fi

} # end of prep_source

#--------------------------- ck_mand_updts_in_instp_output ---------------------
#
# NAME: ck_mand_updts_in_instp_output
#
# FUNCTION:
#		greps installp preview output for the existence of
#		specific keywords to indicate that the installp 
#		command is about to be updated.  This functionality
#		acts as a 2ndary check to the ${NIM_INSTP_UPDT_LIST}
#		file which will not be set by installp when older
#		SPOTs are being updated.
#		This routine populates the NIM_INSTP_UPDT_LIST file
#		with bos.rte.install fileset names if found in the
#		grepped output.
#
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#		  ${TMPDIR}/installp.preview =   output file from installp 
#						preview operation as set 
#						in ck_required_space
#
# RETURNS: (int)
#		0 = installp updates found in the preview operation
#				AND
#		    installation of other filesets have been deferred
#		1 = installp updates not found in the preview operation
#
# OUTPUT:
#-------------------------------------------------------------------------------

function ck_mand_updts_in_instp_output {

	INSTP_PREV_OUT=${TMPDIR}/installp.preview

	# Look for all output between the two substrings indicated
	${AWK} '/SUCCESSES/,/End of Success Section/ {print}' \
						${INSTP_PREV_OUT} | \

                # grep the resultant paragraph which should include
                # the installp fileset names
		${GREP} -p "Mandatory Fileset Updates" 2>/dev/null | \

		# grep the installp updates themselves and save in
		# a file that will ultimately be used by the caller
		${GREP} bos.rte.install | ${AWK} -F"#" '{print $1}' | \
			${GREP} bos.rte.install \
			> ${NIM_INSTP_UPDT_LIST} 2>/dev/null

	if [ $? -ne 0 ] 
	then
		${RM} ${NIM_INSTP_UPDT_LIST}
		return 1
	fi

	# Ensure that there are other filesets to install after the
	# installp updates are installed by grepping the installp
	# pre-installation summary to see if any were deferred.
	${GREP} -p "FILESET STATISTICS" ${INSTP_PREV_OUT} 2>/dev/null | \
		${GREP} -q "Deferred"


	if [ $? -ne 0 ] 
	then
		${RM} ${NIM_INSTP_UPDT_LIST}
		return 1
	fi

	return 0
}

#---------------------------- ck_required_space --------------------------------
#
# NAME: ck_required_space
#
# FUNCTION:
#		uses the preview option on installp to determine how much space is
#			required for the operation
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= installp flags to use
#			2						= non-NULL if auto expand used
#			3						= d_flag
#			4						= f_flag
#			5						= filesets
#		global:
#			location
#			spot_fs
#
# RETURNS: (int)
#		0							= enough room for operation
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_required_space {


	typeset installp_flags=${1}
	typeset auto_expand=${2}
	typeset d_flag=${3}
	typeset f_flag=${4}
	typeset filesets=${5}

	typeset filesystem=""
	typeset -i required=0
	typeset -i available=0
	typeset -i additional=0

	# check the available space in the SPOT and auto expand if necessary.
	# use the preview option with installp to get the space it needs
	# NOTE that we set the appropriate installp environment variable in order
	#		to make it behave correctly in the NIM environment
	${installp_env_variable}

        # Temporarily set the language variable since we may be grepping
        # installp output for translatable keywords
        OLD_LANG=${LANG}
        export LANG=C
	${chroot} ${geninstall_cmd:-$INSTALLP -pk $installp_flags} \
			${geninstall_cmd:+-p -I "-k $installp_flags"} \
			${d_flag} ${f_flag} ${filesets} </dev/null > \
			${TMPDIR}/installp.preview 2>&1
	export LANG=${OLD_LANG}

	# if installp doesn't return anything, might as well continue
	[[ ! -s ${TMPDIR}/installp.preview ]] && return 0

	# get the size info out of the file
	# NOTE that we have to jump through some hoops here because of the way in
	#		which installp prints this information
	root=$( echo ${location} | ${AWK} -F "/" '{print $2}' )

	# For /usr SPOTs, we need to remember the "/" size requirements to 
	# check against free space in /usr before doing sync_root on 
	# /usr/lpp/bos/inst_root.  Save this information in a file in /tmp.
	[[ ${location} = "/usr" ]] && print 0 > ${INSTROOT_CUST_SZ}

	${CAT} ${TMPDIR}/installp.preview | \
	while read line
	do
		# ASSUMING installp preview info matches the following pattern:
		#		field 1 = "_SIZE_"
		#		field 2 = name of filesystem
		#		field 3 = free space required to install into the filesystem
		#		field 4 = currently available free space in the filesystem

		# does this line match our pattern?
		[[ "${line}" != _SIZE_?* ]] && continue
		set -- ${line}

		# ignore info if this is the "TOTAL"
		[[ "${2}" = TOTAL ]] && continue

		filesystem=${2}
		let "required=${3}"
		let "available=${4}"


		# add in a fudge factor of 10%
		let "required+=(required/10)+1"

		# Save "/" requirement for /usr SPOTs.
		[[ ${location} = "/usr" ]] \
				&& [[ ${filesystem} = "/" ]] \
				&& print ${required} > ${INSTROOT_CUST_SZ}

		# is there enough free space?
		if (( required > available ))
		then

			# auto expand?
			[[ "${auto_expand}" = "no" ]] &&
				error ${ERR_SPACE} ${filesystem} ${required} ${available}

			# calculate additional space needed
			let "additional=required-available"

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

		fi
	done

	# If the preview op above detected an installp update on the media,
	# whether or not it was requested for installation, the preview
	# output only shows us size information for the update of the
	# installp fileset.  Installp will tell us about this condition.
	# If it does we will apply all installp updates on the media before
	# calculating the space needed to install the rest of the filesets
	# that were requested.

	if [[ -s "${NIM_INSTP_UPDT_LIST}" ]] || ck_mand_updts_in_instp_output
	then
		# get the list of filesets printed by the installp command
		# then remove the file we used to communicate this info.
		instp_list=`${CAT} ${NIM_INSTP_UPDT_LIST}`
		${RM} ${NIM_INSTP_UPDT_LIST}

		# expand the fs to help prevent the unarchive failures due to bos.rte
		${CHFS} -a size=+65536 ${filesystem} 2>${ERR} 1>&2

		# install the installp updates
		${chroot} ${geninstall_cmd:-$INSTALLP -e $INSTALLP_LOG $installp_flags} \
			${geninstall_cmd:+-I "-e $INSTALLP_LOG $installp_flags"} \
			${d_flag} ${instp_list} \
			</dev/null 2>${ERR} 1>&2 || err_from_cmd ${INSTALLP}

		# Now see if there's enough space for the original
		# list of filesets.
		# NOTE THE RECURSION HERE!
		ck_required_space "${installp_flags}" \
			"${auto_expand}" "${d_flag}" \
			"${f_flag}" "${filesets}"
	fi

} # end of ck_required_space

#---------------------------- inst_spot         --------------------------------
#
# NAME: inst_spot 
#
# FUNCTION:
#		installs the specified SPOT with the specified software
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#			spot_fs				= filesystem where SPOT resides
#			chroot				= command to execute in order to be in correct env
#											for installp
#			new_root				= pathname of new root dir
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function inst_spot {


	typeset d_flag=""
	typeset f_flag=""
	typeset i=""
	typeset auto_expand=""
	typeset MKSPOT_PRE_I="_SPOT._.pre_i.usr.1.0.0.0"
	typeset MKSPOT_POST_I="_SPOT._.post_i.usr.1.0.0.0"

	# prevent savebase from writing to the system's boot disk (d1058970)
	export AIX_NO_SAVEBASE=1

	# which filesystem is SPOT in?
	spot_fs=$( ${DF} -Pk ${location} 2>/dev/null | ${AWK} 'NR==2{print $6}' )

	# setup the chroot environment
	# NOTE that we do this before the preparing the source device because local
	#		access to the source needs to be mounted over the chroot environment
	chroot=""
	setup_chroot_env

	# Now ensure that the server's libraries mounted into the SPOT
	# will be used.
	${SET_CHROOT_LIBPATH}

   # New versions ( > 4.x.x.x ) of bos.sysmgt use the GENINSTALL
   # command as opposed to INSTALLP
   # Get the version of the bos.rte.install  fileset in
   # the SPOT
   lslpp_fileset=`${chroot} ${LSLPP} -lqcOu bos.rte.install` || \
	  err_from_cmd "${LSLPP} -lqcOu bos.rte.install"

   # only update TCB_STATE for non-/usr spots.
   if [[ -n "${new_root}" ]] && [[ $force != "yes" ]]; then

      # force TCB_STATE=tcb_enabled for spot installs with TCB=yes
      # this will make installp update the sysck.cfg from /usr/lib/instl/instal
      cat << END |${chroot} /usr/bin/odmchange -o PdAt -q "attribute like TCB_STATE"
PdAt:
        uniquetype = ""
        attribute = "TCB_STATE"
        deflt = "tcb_enabled"
        values = ""
        width = ""
        type = ""
        generic = ""
        rep = ""
        nls_index = 0
END

   fi # end of TCB enable

   vrmf=`echo $lslpp_fileset | ${CUT} -d":" -f3`
   version=`echo ${vrmf} | ${CUT} -d"." -f1`

   # set geninstall_cmd (if needed)
   # version is obtained from SPOT, set_geninst checks flags
   [[ ${version} > 4 ]] && set_geninst ${installp_flags}

   # if a source was specified, then prepare it for use
   if [[ -n "${lpp_source}" ]]
   then
	prep_source

	# use the "-d" installp option
	d_flag="-d ${src_access}"
   fi

    # Skip all this processing if the installp_flag is "-s" for
    # listing APPLIED software only.
    if [[ ${installp_flags} != "-s" ]]
    then
	# use a bundle file?
	if [[ -n "${installp_bundle}" ]]
	then
		
		prep_bundle

		# use the "-f" installp option
		f_flag="-f ${bundle_access}"
		filesets=""

	#fix_bundle specified? 
	elif [[ -n "${fix_bundle}" ]]
	then
	
		# setup local access (use installp's bundle prep routine)
		installp_bundle=${fix_bundle}
		prep_bundle

		# convert list of fix keywords to list of filesets
		prep_instfix_lst "spot" "bun" "${bundle_access}" "${d_flag}"

		filesets="-f ${fileset_list}"

	# fixes specified? 
	elif [[ -n "${fixes}" ]]
	then
		# "update_all" keyword specified?
	        if [ "${fixes}" = "update_all" ]
		then
			# get list of fileset updates needing installation.
			prep_updt_all_lst "spot" "${d_flag}"
                	if [ ! -s "${fileset_list}" ]
                	then
                        	# print sm_inst error for "nothing to update"
                        	${INUUMSG} 177 > ${ERR} 2>&1
                        	err_from_cmd "c_instspot"
                	fi

			filesets="-f ${fileset_list}"
		else
			# convert list of fix keywords to list of filesets
			prep_instfix_lst "spot" "fixes" "${fixes}" "${d_flag}"

			filesets="-f ${fileset_list}"
		fi

	elif [[ ${installp_flags} = *u* ]] || [[ ${installp_flags} = *r* ]]
	then

		# this is a deinstall operation: filesets must be specified
		[[ -z "${filesets}" ]] && error ${ERR_MISSING_ATTR} filesets

	elif [[ ${installp_flags} != *C* ]]
	then

		# this is an install operation: use default if filesets not specified
		if [ -z "${filesets}" ]
		then

			# Set the "lvl_type" and "lvl_source" variables
			# so they can be used later by the "set_option_lists"
			# routine.  We need the lpp_source for this.
			# Use access_pnt, set up by nim_mount, if the 
			# lpp_source is remote or is a cdrom; else use
			# the values appropriate for a tape source or a
			# local directory.
			# NOTE: don't use src_access because this is the
			# value that's used in the chroot'd env.

			if [[ ${lpp_source} = ?*:?* ]]
			then
				lvl_type="rte"
				[[ -e "${access_pnt}/installp/ppc/bos" ]] && \
					lvl_source="${access_pnt}/installp/ppc/bos" || \
					lvl_source="${access_pnt}/bos"
			elif [[ ${lpp_source} = /dev/cd[0-9]* ]]
			then
				lvl_type="rte"
				[[ ! -e "${access_pnt}${OFFSET_FOR_CDROM}/bos" ]] && \
					OFFSET_FOR_CDROM=${OFFSET_FOR_CDROM_OLD}
				lvl_source="${access_pnt}${OFFSET_FOR_CDROM}/bos"
			elif [[ ${lpp_source} = /dev/rmt[0-9]* ]]
			then
				lvl_type="device"
				lvl_source="${lpp_source}"
			else
				lvl_type="rte"
				[[ -e "${lpp_source}/installp/ppc/bos" ]] && \
					lvl_source="${lpp_source}/installp/ppc/bos" || \
					lvl_source="${lpp_source}/bos"
			fi

			# call set_option_lists to set "DEFAULT_SPOT_OPTIONS" to
			# contain the list appropriate for the level of source.
			set_option_lists ${lvl_type} ${lvl_source}

			filesets="${DEFAULT_SPOT_OPTIONS}"

			default_spot_options_set=1
		fi
	fi
    fi

	if [[ -n "${fixes}" ]] || [[ -n "${fix_bundle}" ]]
	then
        	# if not doing an update_all, add B flag for safety
        	# (so that base levels are not accidently instld via requisites)
        	if [[ "${fixes}" != "update_all" ]] && \
						[[ "${installp_flags}" != *B* ]]
        	then
               	 	installp_flags=${installp_flags}B
        	fi
	fi

	# If the lpp_source is a tape, then do not prompt the user
	# to prepare the device.  Add the q option if it is not
	# already there.
	if [[ -n "${tape_source}" ]]
	then
	  if [[ "${installp_flags}" != *q* ]]
	  then
	    installp_flags="${installp_flags}q"
	  fi
	fi

	# installp cannot expand in a chroot'd env.  We need to do our own
 	# checks and expansion if necessary.  This is really only required 
	# for non-/usr SPOT's, since installp can expand when installing into
	# /usr SPOTs.  However, a sync_root takes place for the 
	# /usr/lpp/bos/inst_root directory for /usr SPOTs.  Therefore, we'll
	# call the space checking routine for either type of SPOT.  

	if [[ ${installp_flags} = *X* ]]
	then

		# intercept the installp "X" flag for non-/usr SPOTs since
		# it won't work correctly and may expand the wrong filesystem.
		#
#  NOTE: installp seems to handle non-/usr SPOTs correctly now 
#        so we will let the -X flag go through.  There seems to 
#        be a difference in the way NIM did space calculations and
#        the way installp does them.  So, we should allow installp
#        the option of expanding also.
#
#		if [[ ${location} != /usr ]]
#		then
#			installp_flags=$( echo ${installp_flags} | \
#								${AWK} '{gsub(/X/,"");print}' )
#		fi
		auto_expand="yes"

	fi

	# check the available space in the SPOT and auto expand if 
	# necessary (only when not doing installp preview)
	[[ "${installp_flags}" != *p* ]] && \
	   ck_required_space "${installp_flags}" "${auto_expand}" "${d_flag}" \
			"${f_flag}" "${filesets}"

	#
	# Check to see if a previous installp flag file exists... 
	#
	[[ -f ${MK_NETBOOT} ]] && ${RM} ${MK_NETBOOT}

	# install into the SPOT
	# NOTE that this may just be maintenance operation where no source or
	#   bundle file is used (ie, this script can be invoked from m_instspot
	#   or m_maintspot)
	# NOTE also that we set the appropriate installp environment variable in 
	#		order to make it behave correctly in the NIM environment
	${installp_env_variable}

	# Disable the loader control controlling loader 
	# handling of unresolved system calls
	export NOFORCE_KIMP_RES=1

	# If there is a pre-installation hook provided in the lpp_source, 
	# invoke it and error off if return code is non-zero
	if [[ -n ${check_hooks} ]]
	then
	   if [[ ${lpp_source} != /dev/rmt[0-9]* ]]
	   then
	      if [[ -f ${ext_access}/${MKSPOT_PRE_I} ]] 
	      then
	          ${ext_access}/${MKSPOT_PRE_I} ${location} ${ext_access} >${ERR} 2>&1
        	  if [ $? -eq 0 ]
        	  then
                	  ${CAT} ${ERR} 2>&1   # display the output
                	  >${ERR}           # wipe out all traces of error
        	  else
                	  err_from_cmd ${MKSPOT_PRE_I}
        	  fi
	      fi
	   fi
	fi

	# if using the default set of filesets to install into the
	# SPOT, then add bos.rte to the list if there is a bos.rte
	# fileset or update found on the install source.
	# (Not all media will contain something called bos.rte.)
	if [[ -n ${default_spot_options_set} ]]
	then
	  ${chroot} ${geninstall_cmd:-$INSTALLP} ${tape_source:+-q} -L ${d_flag} | \
	    ${AWK} 'BEGIN {FS=":"} {print $2}' | \
	    ${GREP} "^bos.rte" > /dev/null 2>&1
	  if [[ $? -eq 0 ]]
	  then
	    updts="yes"
	  fi

	  # prepend I: to default_spot_options list -- for geninstall call
	  if [[ -n ${geninstall_cmd} ]]
	  then
		geninstall_list=""
		for i in `${ECHO} ${filesets}`
		do
			geninstall_list="${geninstall_list} I:${i} "
		done
			filesets="${geninstall_list}"
	  fi
	fi

	# call the installp command differently depending upon the level of 
	# master
	if [[ -z ${non_41_master} ]]
	then
		# Called from a 4.1 master...

		# if doing an installp preview, capture the output in ERR. 
		# Cat the file to stdout if there were no errors, otherwise 
		# do normal error handling.
		if [[ "${installp_flags}" = *p* ]]
		then
			${chroot} ${INSTALLP} ${installp_flags} ${d_flag} \
				${f_flag} ${filesets} </dev/null >${ERR} 2>&1

        		if [ $? -eq 0 ]
        		then
                		${CAT} ${ERR} 2>&1   # display the output
                		>${ERR}           # wipe out all traces of error
        		else
                		err_from_cmd ${INSTALLP}
        		fi
		else
			${chroot} ${INSTALLP} ${E_FLAG} \
				${installp_flags} \
				${d_flag} ${f_flag} \
				${filesets} </dev/null 2>${ERR} 1>&2
		fi
	else
		if [[ ${show_progress} = "no" ]]
		then
			${chroot} ${geninstall_cmd:-$INSTALLP $installp_flags $E_FLAG} \
				${geninstall_cmd:+-I "$installp_flags $E_FLAG"} \
				${d_flag} ${f_flag} ${filesets} </dev/null 2>${ERR} 1>&2
		else
			${chroot} ${geninstall_cmd:-$INSTALLP $installp_flags $E_FLAG} \
				${geninstall_cmd:+-I "$installp_flags $E_FLAG"} \
				${d_flag} ${f_flag} ${filesets} 2>&1
		fi
	fi

	# any updates to pull in?
	if [[ ${updts} = "yes" ]]
	then
	   # get list of fileset updates needing installation.
	   prep_updt_all_lst "spot" "${d_flag}" "${updts}"
       if [ -s "${fileset_list}" ]
       then
	   filesets="-f ${fileset_list}"

	   # check the available space in the SPOT and auto expand if 
	   # necessary (only when not doing installp preview)
	   [[ "${installp_flags}" != *p* ]] && \
		   ck_required_space "${installp_flags}" "${auto_expand}" "${d_flag}" \
		   "${f_flag}" "${filesets}"

	   # install the updates
	   ${chroot} ${geninstall_cmd:-$INSTALLP $installp_flags $E_FLAG} \
		   ${geninstall_cmd:+-I "$installp_flags $E_FLAG"} \
		   ${d_flag} ${f_flag} ${filesets} 2>&1
       fi

	fi

	#
	# Save installp return code for later..
	#
	rc=$?

	#
	# If installp says make boot images, communicate this with mk_netboot
	# attr to the caller (different depending upon level of caller)
	#
	if [[ -n ${non_41_master} ]]
	then
		# save attr assignment in a status file for later processing. 
		[[ -f ${MK_NETBOOT} ]] && echo "mk_netboot=yes" > ${NIM_STATUS}
	else
		# print attr assignment to stdout to be read by caller
		[[ -f ${MK_NETBOOT} ]] && echo "mk_netboot=yes"
	fi

	# If there is a post-installation hook provided in the lpp_source, 
	# invoke it and error off if return code is non-zero
	if [[ -n ${check_hooks} ]]
	then
	   if [[ ${lpp_source} != /dev/rmt[0-9]* ]]
	   then
	      if [[ -f ${ext_access}/${MKSPOT_POST_I} ]] 
	      then
	          ${ext_access}/${MKSPOT_POST_I} ${location} ${ext_access} >${ERR} 2>&1
        	  if [ $? -eq 0 ]
        	  then
                	  ${CAT} ${ERR} 2>&1   # display the output
                	  >${ERR}           # wipe out all traces of error
        	  else
			  # Make sure that any installp failures gets
			  # reported, so only exit from here if installp
			  # was clean...
			  if [[ ${rc} != 0 ]] 
			  then
                	  	warning_from_cmd ${MKSPOT_POST_I}
				>${ERR}
			  else
                	  	err_from_cmd ${MKSPOT_POST_I}
			  fi
        	  fi
	      fi
	   fi
	fi

	#
	# Its later.. Now check the return code from installp. 
	#
	if [[ ${rc} != 0 ]] 
	then
		# Set variables used by error function to print out extra msg
		# about viewing the log.
		# (Only do this if called from a non-41 master)
		if [[ -n ${non_41_master} ]] 
		then
			if [[ ${location} = /usr ]]
			then
				instp_err_log=${INSTALLP_LOG}
			else
				instp_err_log="${location}/lpp/bos/inst_root${INSTALLP_LOG}"
			fi
			export NIM_SHOW_PROGRESS=yes
		fi
		err_from_cmd ${INSTALLP}
		
	fi

} # end of inst_spot

#---------------------------- c_instspot        --------------------------------
#
# NAME: c_instspot
#
# FUNCTION:
#		installs the specified software into a SPOT
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		this method does NOT create a SPOT - that work is done by c_mkspot
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= SPOT installed
#		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
typeset c=""

# set parameters from command line
while getopts :a:qvfH 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
				;;

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

		f)		# called from non-41 master	
				non_41_master=1
				;;

		H)		# check for the existence of SPOT creation hooks
				check_hooks=1
				;;

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

# check for missing attrs
ck_attrs

# call undo() on interrupt
undo_on_interrupt="undo"

# set defaults
installp_flags=${installp_flags:-${SPOT_INSTALLP_FLAGS}}
installp_flags=$( ck_installp_flags "${installp_flags}" )

# The -e flag (for specifying an alternate log file) will hide output for
# listing operations.  Therefore, we do not want to use the -e flag if we
# are only performing installp listing operations.  We will figure that
# the operation is a listing operation if it isn't an apply (a), commit (c),
# reject (r), or deinstall (u) operation.
# Use sed to remove any "Ou" or "Or" combinations before grepping for
# the action flags (acru).
echo ${installp_flags} | ${SED} 's/Ou//' | ${SED} 's/Or//' | ${GREP} "[acru]" \
  > /dev/null 2>&1
if [[ $? -eq 0 ]]
then
  E_FLAG="-e ${INSTALLP_LOG}"
fi

# if auto_expand specified, make sure there's an "X" in the flags
[[ "${auto_expand}" = "yes" ]] && [[ ${installp_flags} != *X* ]] && \
	installp_flags="${installp_flags}X"

# which installp environment variable should be used?
#		INUSERVERS = set for /usr SPOTs so that installp bypasses looking in the
#								/etc/niminfo file for the NIM_USR_SPOT variable
# 		INUCLIENTS = set for non-/usr SPOTs so that installp doesn't create a
#								boot image and to prevent any install scripts from
#								mucking with device configuration ont the server
if [[ ${location} = /usr ]]
then

	installp_env_variable="export INUSERVERS=yes"

	# make sure "b" not passed
	installp_flags=$( echo ${installp_flags} | \
							${AWK} '{gsub(/b/,"");print}' )

else

	installp_env_variable="export INUCLIENTS=yes"

fi

# check for errors
if [[ -n "${installp_bundle}" ]] && [[ -n "${filesets}" ]]
then

	error ${ERR_ATTR_CONFLICT} installp_bundle filesets

elif [[ -n "${fix_bundle}" ]] && [[ -n "${filesets}" ]]
then

	error ${ERR_ATTR_CONFLICT} fix_bundle filesets

elif [[ -n "${fixes}" ]] && [[ -n "${filesets}" ]]
then

	error ${ERR_ATTR_CONFLICT} fixes filesets

elif [[ -n "${fix_bundle}" ]] && [[ -n "${installp_bundle}" ]]
then

	error ${ERR_ATTR_CONFLICT} fix_bundle installp_bundle

elif [[ -n "${fix_bundle}" ]] && [[ -n "${fixes}" ]]
then

	error ${ERR_ATTR_CONFLICT} fix_bundle fixes

elif [[ ${installp_flags} = *a* ]] && [[ -z "${lpp_source}" ]]
then

	error ${ERR_MISSING_ATTR} lpp_source

fi

# perform the install
inst_spot

# all done
exit 0

