#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72X src/bos/usr/lib/nim/methods/c_installp.sh 1.33.1.2 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1993,2021 
# 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 
# @(#)46        1.33.1.2  src/bos/usr/lib/nim/methods/c_installp.sh, cmdnim, bos72X, x2021_50A1  8/3/21  10:55:45
#   COMPONENT_NAME: CMDNIM
#
#   FUNCTIONS: ./usr/lib/nim/methods/c_installp.sh
#
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 1993, 1995
#   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     --------------------------------

#---------------------------- module globals    --------------------------------
REQUIRED_ATTRS=""
OPTIONAL_ATTRS="lpp_source installp_flags filesets installp_bundle boot_env fix_bundle fixes async show_progress"
lpp_source=""
installp_flags=""
filesets=""
installp_bundle=""
fileset_list=""
show_progress=""
geninstall_cmd=""

#---------------------------- 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:
#			lpp_source			= source device name
#			src_access			= local access point for the source device
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_tape {

	# tape needs a "no-rewind-on-close" extension
	# was one provided?
	if [[ ${lpp_source} = /dev/rmt[0-9].* ]]
	then

		[[ ${lpp_source} != /dev/rmt[0-9].1 ]] && \
			[[ ${lpp_source} != /dev/rmt[0-9].5 ]] && \
			error ${ERR_SOURCE} ${lpp_source}

		src_access=${lpp_source}

	else

		# append the extension
		src_access="${lpp_source}.5"

	fi

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

} # 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:
#			1						= local mount point
#		global:
#			lpp_source			= source device name
#			src_access			= local access point for the source device
#			access_pnt			= local access point returned from nim_mount
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_cd {

	typeset local_mntpnt=${1}

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

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

} # 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:
#			1						= local mount point
#		global:
#			src_access			= local access point for the source device
#			access_pnt			= local access point returned from nim_mount
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_dir {

	typeset local_mntpnt=${1}
	typeset local_rc=1

	# NOTE: As part of the http availability feature -
	#       the initial call will include a check for
	#       web download service.
	#
	if [[ ${lpp_source} = ?*:/?* ]]
	then
		# c_file_transfer should attempt to locate the file
		# using the nimtthp servicing option
		# Preference for ssl ..

		download_srvr=`echo ${lpp_source} | ${SED} 's/\:.*$//'`
		download_loc=`echo ${lpp_source} | ${SED} 's/.*://'`
		${MKDIR} -p ${TMPDIR}/$download_loc
		${NIMHTTP} -i $download_srvr -f $download_loc -o dest=${TMPDIR} -s >/dev/null 2>&1 ||
		${NIMHTTP} -i $download_srvr -f $download_loc -o dest=${TMPDIR} >/dev/null 2>&1
		local_rc=$?

		if [[ $local_rc -eq 0 ]]; then
			mget_http_content $lpp_source ${TMPDIR} >/dev/null 2>&1
			local_rc=$?

			# set new access point
			if [[ $local_rc -eq 0 ]]; then
				access_pnt="${TMPDIR}/${download_loc}"
			fi
		fi
		# end of HTTP
	fi

	if [[ $local_rc -ne 0 ]]
	then
		# NFS Method

		# mount images at a specific offset
		nim_mount ${lpp_source} ${local_mntpnt}

		# end of NFS
	fi
	src_access=${access_pnt}

} # end of prep_dir

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

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

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

		*/*)		# source is a directory
					prep_dir
					;;

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

} # end of prep_lpp_source

#*---------------------------- c_installp           ----------------------------
#
# NAME: c_installp
#
# FUNCTION:
#		sets up remote access to resources, then calls installp
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= no errors
#		>0							= failure
#
# 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: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}\"
		;;

		f)	# passed to indicate that caller is not a 4.1 master
			# (Info is passed as a flag from m_maint and as a
			# variable if called from nim_script.)
			NIM_NON_41_MASTER=yes
		;;
		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
		;;

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

	esac
done

# The following information is passed as attributes if called from
# m_maint and variables if called from the nim_script.  Need to
# set the variables in the m_maint case.
[[ ${show_progress} = yes ]] && NIM_SHOW_PROGRESS=yes
[[ ${async} = yes ]] && NIM_ASYNC=yes
[[ -n ${NIM_BOSINST_ENV} ]] && UPDT_CL_ERR_INFO=yes

# check for missing attrs
ck_attrs

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

# set geninstall_cmd (if needed)
set_geninst ${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 boot_env specified...
if [[ -n "${boot_env}" ]]
then

	# make sure "-b" is used
	[[ "${installp_flags}" != *b* ]] && installp_flags="-b ${installp_flags}"

fi

# use an lpp_source?
if [[ -n "${lpp_source}" ]]
then

	# setup local access
	prep_lpp_source

	lpp_source="-d ${src_access}"

fi

# use a bundle file?
if [[ -n "${installp_bundle}" ]]
then

	# setup local access
	prep_bundle

	filesets="-f ${bundle_access}"

# use fix_bundle? 
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 "client" "bun" "${bundle_access}" "${lpp_source}"

	filesets="-f ${fileset_list}"

# use fixes? 
elif [[ -n "${fixes}" ]]
then

	# "update_all" keyword specified?
	if [ "${fixes}" = "update_all" ]
	then
		# get list of fileset updates needing installation.
		prep_updt_all_lst "client" "${lpp_source}" 

		if [ ! -s "${fileset_list}" ]
		then
			# print sm_inst error for "nothing to update"
			${INUUMSG} 177 > ${ERR} 2>&1
		 	err_from_cmd "c_installp"
		fi
		filesets="-f ${fileset_list}"
	else
		# convert list of fix keywords to list of filesets
	        prep_instfix_lst "client" "fixes" "${fixes}" "${lpp_source}"

		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
	filesets=${filesets:-${DEFAULT_INSTALLP_OPTIONS}}

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

# doing asynchronous processing?  (ie. master not waiting for script to finish)
if [[  ${NIM_ASYNC} = yes ]] 
then

	# update the state of the client object
	# Only do so if not called from nim_script.  The state is updated
	# there instead.
	[[ ${NIM_SCRIPT} != yes ]] && ${NIMCLIENT} -R success

	# set the following variable so that errors are appended to err_info
	# attribute on the client object.  When c_installp is called from
	# the nim_script, the async flag is not passed to this script so
	# this variable is exported there.
	UPDT_CL_ERR_INFO=yes
fi

# invoke installp
# NOTE that INUSERVERS is an environment variable which effects the behavior
#		of installp.  When set, it causes installp to bypass looking in the
#		/etc/niminfo file for the NIM_USR_SPOT variable, which is used to
#		prevent users from executing installp from the command line on machines
#		whose /usr filesystem has been converted into a SPOT
export INUSERVERS=yes

if [[ -n "$INUBOSTYPE" ]] && [[ ! -r /dev/urandom ]]
then
    /usr/sbin/randomctl -l > /dev/null 2>&1
fi

if [[ -n ${NIM_NON_41_MASTER} ]]
then
	# This script was called from a master at a level greater than 4.1
	# We can show installp output if requested to do so.
	if [[ ${NIM_SHOW_PROGRESS} = yes ]]
	then
		${geninstall_cmd:-$INSTALLP $installp_flags $E_FLAG} \
			${geninstall_cmd:+-I "$installp_flags $E_FLAG"} \
			${lpp_source} ${filesets} 2>&1
		rc=$?
	else
		${geninstall_cmd:-$INSTALLP $installp_flags $E_FLAG} \
			${geninstall_cmd:+-I "$installp_flags $E_FLAG"} \
			${lpp_source} ${filesets} 2>${ERR} 1>&2 
		rc=$?
	fi
else
	# This branch of the else is provided for backwards compatibility 
	# so that 4.2 clients can be controlled by 4.1 NIM masters.
	if [[ ${installp_flags} = *p* ]]
	then
		${geninstall_cmd:-$INSTALLP $installp_flags} \
			${geninstall_cmd:+-I "$installp_flags"} \
			${lpp_source} ${filesets} >${ERR} 2>&1
		rc=$?
 		if [[ $rc -eq 0 ]]
		then
			${CAT} ${ERR} 2>&1   # display the output
			>${ERR}           # wipe out all traces of errors
		fi
	else
		${geninstall_cmd:-$INSTALLP $installp_flags $E_FLAG} \
			${geninstall_cmd:+-I "$installp_flags $E_FLAG"} \
			${lpp_source} ${filesets} 2>${ERR} 1>&2
		rc=$?
	fi
fi

if [[ $rc -ne 0 ]]
then
	# update state on master if it isn't waiting for us to finish
	[[ ${NIM_ASYNC} = yes ]] && [[ ${NIM_SCRIPT} != yes ]] && \
						${NIMCLIENT} -R failure

	# used by error function 
	instp_err_log=${INSTALLP_LOG}
	err_from_cmd ${INSTALLP}	
fi

# update state on master if necessary
[[  ${NIM_ASYNC} = yes ]] && [[ ${NIM_SCRIPT} != yes ]] && \
						${NIMCLIENT} -R success

# success
exit 0
