#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos720 src/bos/usr/lib/nim/methods/c_getlevel.sh 1.11.1.3 
#  
# Licensed Materials - Property of IBM 
#  
# Restricted Materials of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2011,2014 
# 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 
# @(#)72 1.11.1.3 src/bos/usr/lib/nim/methods/c_getlevel.sh, cmdnim, bos720, 1432A_720 7/29/14 11:39:52
#
#   COMPONENT_NAME: cmdnim
#
#   FUNCTIONS: ck_mksysb
#		ck_source
#		prep_SPOT
#		prep_cd
#		prep_rte
#		prep_tape
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 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     --------------------------------
typeset -i FUDGE_FACTOR=5

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

#---------------------------- module globals    --------------------------------
REQUIRED_ATTRS="source type"
OPTIONAL_ATTRS=""
typeset -i version=0
typeset -i release=0
typeset -i mod=0
oslevel_r=""
oslevel_s=""
source=""
src_access=""
type=""

#---------------------------- prep_tape         --------------------------------
#
# NAME: prep_tape  
#
# FUNCTION:
#		prepares the specified tape device and gets the level of the
#		bos image on the tape.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_tape {

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

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

		src_access=${source}

	else

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

	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, so we need the
	# 		the LPP_NAME file - restore it now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${src_access} ${LPP_NAME} >/dev/NULL 2>${ERR}

	# if the restore succeeded, then get the level from the extracted
	# lpp_name file.  Otherwise, use the level from the currently
	# installed NIM client fileset.
	if [[ $? -eq 0 ]]
	then
		# validate the release level
		ck_rel_level ${TMPDIR}/${LPP_NAME}
	else
		get_fileset_level ${NIM_CLIENT_PACKAGE}
	fi

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

} # end of prep_tape

#---------------------------- prep_cd           --------------------------------
#
# NAME: prep_cd
#
# FUNCTION:
#		prepares a CDROM device and gets the level of the BOS image
#		on the CD.
#
# 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}

	# need to validate the AIX release level of this image, so we need
	# 		the LPP_NAME file - restore it now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${src_access} ${LPP_NAME} >/dev/null 2>${ERR}

	# if the restore succeeded, then get the level from the extracted
	# lpp_name file.  Otherwise, use the level from the currently
	# installed NIM client fileset.
	if [[ $? -eq 0 ]]
	then
		# validate the release level
		ck_rel_level ${TMPDIR}/${LPP_NAME}
	else
		get_fileset_level ${NIM_CLIENT_PACKAGE}
	fi

} # end of prep_cd

#---------------------------- prep_SPOT         --------------------------------
#
# NAME: prep_SPOT
#
# FUNCTION:
#		prepares a SPOT and gets the level of BOS that is installed.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_SPOT {
	typeset old_LANG

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

	# get product data from spots ODM database
	odm_fileset_level=`ODMDIR=${source}/lib/objrepos ${ODMGET} -q "lpp_name=bos.rte" product\
		| ${AWK} '/state =|rel =|mod =|ver =|fix =|lpp_name =/ \
		  {
			if ($1 == "state")  c_state=$3
			if ($1 == "ver")    vrmf[1]=$3
			if ($1 == "rel")    vrmf[2]=$3
			if ($1 == "mod")    vrmf[3]=$3
			if ($1 == "fix") {
				vrmf[4]=$3
				if (c_state == 3 || c_state == 5) {
					bigger=0
					for ( ix=1; ix<=4; ix++ ) {
						if (vrmf[ix] < h_vrmf[ix]) break
						if (vrmf[ix] > h_vrmf[ix]) bigger++
					}
					if (bigger > 0)
					for ( ix=1; ix <= 4; ix++ )
						h_vrmf[ix] = vrmf[ix]
				}
				for ( ix=1; ix <= 4; ix++ ) vrmf[ix] = 9999;
			}
		  }
		  END {

			print h_vrmf[1] "." h_vrmf[2] "." h_vrmf[3] "." h_vrmf[4]
		  }'`


	# parse off the vrmf data into variables.
	vrmf=${odm_fileset_level}
	version=`echo ${vrmf} | ${CUT} -d"." -f1`
	release=`echo ${vrmf} | ${CUT} -d"." -f2`
	mod=`echo ${vrmf} | ${CUT} -d"." -f3`
	fix=`echo ${vrmf} | ${CUT} -d"." -f4`

	# Now run "oslevel -rf; oslevel -s" in the SPOT.
	location=${source}
	setup_chroot_env
	${SET_CHROOT_LIBPATH}

	old_LANG=${LANG}
	export LANG=C
	oslevel_r=$(${chroot} ${OSLEVEL} -rf 2>/dev/null)
	oslevel_s=$(${chroot} ${OSLEVEL} -s 2>/dev/null)
	export LANG=${old_LANG}

        # If oslevel_r is not the form of 5200-1, logical AND the value of
        # oslevel_r with 1100 or ${version}${release}00 to get its base value
        # and not the level of bos.rte.
	if [[ -z ${oslevel_r} ]]
	then
	    oslevel_r=`echo $vrmf | ${SED} 's/\.//g'`
            let oslevel_r="$oslevel_r & ${version}${release}00"
	fi

	[[ -z ${oslevel_s} ]] && oslevel_s=$oslevel_r

	${UNSET_CHROOT_LIBPATH}

	print "oslevel_r=${oslevel_r}"
	print "oslevel_s=${oslevel_s}"

} # end of prep_SPOT

#---------------------------- prep_rte         --------------------------------
#
# NAME: prep_rte 
#
# FUNCTION:
#		prepares environment to check a bos image in a directory to
#		determine its level.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_rte {

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

	# directory where rte exists must be local to the server
	# ${C_STAT} -a location=${dir} 2>${ERR} || err_from_cmd ${C_STAT}

	# need to validate the AIX release level of this image, so we need the
	# 		the LPP_NAME file - restore it now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd

	# If the $source file exists, then restore the lpp_name file from it
	# to get the code level.  If it does not exist, then get the level of
	# the currently installed NIM client fileset.
	if [[ -a ${source} ]]
	then
		${RESTORE} -xqf ${source} ${LPP_NAME} >/dev/null 2>${ERR} || \
			err_from_cmd ${RESTORE}

		# validate the release level
		ck_rel_level ${TMPDIR}/${LPP_NAME}
	else
		get_fileset_level ${NIM_CLIENT_PACKAGE}
	fi

} # end of prep_rte

#---------------------------- ck_mksysb         ------------------------------
#
# NAME: ck_mksysb 
#
# FUNCTION:
#		verifies that the specified mksysb has an acceptable version/release
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#       Mksysbs created on 4.2 and later will contain a line in the form
#       "OSLEVEL= V.R.M.F" in the image.data file that holds the release
#       information.  For mksysbs created on 4.1, the uname information 
#       will continue to be used to retrieve the release information.
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_mksysb {

	typeset -i ok_version=${1:-${DEFAULT_REQUIRED_VERSION}}
	typeset -i ok_release=${2:-${DEFAULT_REQUIRED_RELEASE}}
	typeset filename=${source##*/}
	typeset datafile=${TMPDIR}/${IMAGE_DATA}
        typeset uname_info=""
	typeset oslevel=""

	# mount remote source, if necessary
	nim_mount ${source}

	# filename containing mksysb must exist
	${C_STAT} -a force=yes -a location=${access_pnt} -a mode=0100000 2>${ERR} \
		|| err_from_cmd ${C_STAT}

	# for mksysb images, the version/release info is in the image.data file
	# restore that file now
	cd ${TMPDIR} 2>${ERR} || err_from_cmd cd
	${RESTORE} -xqf ${access_pnt} ${IMAGE_DATA} >/dev/null 2>${ERR} || \
		err_from_cmd ${RESTORE}

	# IMAGE_DATA readable?
	[[ ! -r "${datafile}" ]] && error ${ERR_FILE_ACCESS} ${datafile}

	# OSLEVEL_R specified in IMAGE_DATA?
	oslevel_r=$( ${AWK} '$1=="OSLEVEL_R="{print}' ${datafile} 2>/dev/null )
	if [[ -n "${oslevel_r}" ]]
	then
		# remove OSLEVEL_R= from the string
		oslevel_r=${oslevel_r##*=*( )}
	fi

	# OSLEVEL_S specified in IMAGE_DATA?
	oslevel_s=$( ${AWK} '$1=="OSLEVEL_S="{print}' ${datafile} 2>/dev/null )
	if [[ -n "${oslevel_s}" ]]
	then
		# remove OSLEVEL_S= from the string
		oslevel_s=${oslevel_s##*=*( )}
	fi

	# OSLEVEL specified in IMAGE_DATA?
	# OSLEVEL should be in image.data file for 4.2+ releases
        # It's in the form "OSLEVEL= <version>.<release>.<mod>.<fix>".
	oslevel=$( ${AWK} '$1=="OSLEVEL="{print}' ${datafile} 2>/dev/null )
        if [[ -n "${oslevel}" ]]
	then
		# remove the OSLEVEL string
                oslevel=`echo ${oslevel} | ${CUT} -d"=" -f2`

		# get version level
		version=$( echo ${oslevel} | ${CUT} -d"." -f1 )

		# get release level
		release=$( echo ${oslevel} | ${CUT} -d"." -f2 )

		# get modification level
		mod=$( echo ${oslevel} | ${CUT} -d"." -f3 )
	else
    	# must be 4.1 mksysb - use UNAME_INFO to get version info
	    # UNAME_INFO specified in IMAGE_DATA?
    	uname_info=$(${AWK} '$1=="UNAME_INFO="{print}' ${datafile} 2>/dev/null)
    	[[ -z "${uname_info}" ]] && \
        	error ${ERR_INCOMPLETE} \
            	"UNAME_INFO stanza missing from ${IMAGE_DATA} in ${source}"

    	# what's the version/release?
    	# expecting a string like "UNAME_INFO= AIX <hostname> rel ver cpuid"
    	set -- ${uname_info}
    	[[ $# -lt 5 ]] && error ${ERR_VALUE} "${uname_info}" \
            "UNAME_INFO stanza from the ${IMAGE_DATA} file in ${source}"
    	version=${5}
    	release=${4}

		# if 4.2+ OSLEVEL should have been in image.data file
	if (( (( (( ${version} == 4 )) && (( ${release} >= 2 )) )) || (( ${version} > 4 )) ))
    	then
            error ${ERR_INCOMPLETE} \
                "OSLEVEL stanza missing from ${IMAGE_DATA} in ${source}"
		fi
	fi

	# make sure they're numeric
	[[ "${version}" != +([0-9]) ]] && \
		error ${ERR_RELEASE_LEVEL} "${version}" "${release}" "${source}"
	[[ "${release}" != +([0-9]) ]] && \
		error ${ERR_RELEASE_LEVEL} "${version}" "${release}" "${source}"
	[[ "${mod}" != +([0-9]) ]] && \
		error ${ERR_VER_REL_MOD} "${version}" "${release}" "${mod}" \
            "${source}"

	# now check the values
	if (( ${version} < ${ok_version} ))
	then
		error ${ERR_RELEASE_LEVEL} ${version} ${release} "${source}"
	elif (( ${ok_release} > 0 ))
	then
		if (( ${release} < ${ok_release} ))
		then
			error ${ERR_RELEASE_LEVEL} ${version} ${release} "${source}"
		fi
	fi

 	# If oslevel_r is not the form of 5200-1, logical AND the value of 
	# oslevel_r with 1100 or ${version}${release}00 to get its base value
	# and not the level of bos.rte.
	if [[ -n $oslevel_r ]]
	then
		echo $oslevel_r | ${GREP} "-" >/dev/null 2>&1
		if [[ $? -ne 0 ]]
		then
			let oslevel_r="$oslevel_r & ${version}${release}00"
		fi
		print "oslevel_r=${oslevel_r}"
	fi

	[[ -z ${oslevel_s} ]] && oslevel_s=$oslevel_r
	print "oslevel_s=${oslevel_s}"

} # end of ck_mksysb

#---------------------------- ck_source       --------------------------------
#
# NAME: ck_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 ck_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]* ]]
					then
						prep_cd
					else
						error ${ERR_SOURCE} ${source}
					fi
					;;

		spot)		# source is a SPOT
					prep_SPOT
					;;

		rte)		# source is a BOS rte (runtime) image
					prep_rte
					;;

		mksysb|ios_mksysb)	# source is a mksysb (system backup) image
					ck_mksysb
					;;

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

} # end of ck_source

#---------------------------- c_getlevel     --------------------------------
#
# NAME: c_getlevel
#
# FUNCTION:
#		Examines the AIX version/release level for the specified
#		source.  If the level can not be determined, then the level
#		of the currently installed NIM client fileset will be used.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= version/release ok
#		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
location=
source=

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

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

# check for missing attrs
ck_attrs

# check the specified source
ck_source

# if we get this far, level is ok
# return the version & release on stdout as attr assignments so the calling
#		method will pick them up
print "version=${version}"
print "release=${release}"

# modification level is only on mksysb definitions
# starting with 4.2 and later
if (( (( (( ${version} == 4 )) && (( ${release} >= 2 )) )) || (( ${version} > 4 )) ))
then
	print "mod=${mod}"
fi

# all done
exit 0

