#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72X src/bos/usr/lib/nim/methods/c_sh_lib.sh 1.37.36.3 
#  
# 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 
# @(#)52 1.37.36.3 src/bos/usr/lib/nim/methods/c_sh_lib.sh, cmdnim, bos72X, x2021_23B3 5/27/21 11:22:51
#
#   COMPONENT_NAME: CMDNIM
#
#   FUNCTIONS: ./usr/lib/nim/methods/c_sh_lib.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.
#

# this file contains shell library routines which are included by all NIM
#		shell scripts

#---------------------------- local defines     --------------------------------
PROG=${0}
PROGNAME=${PROG##*/}
[[ ${0} = /SPOT/?* ]] && SPOT=/SPOT || SPOT=""
TMPDIR=/tmp/_nim_dir_$$
ERR=${TMPDIR}/err
OLD_IFS=${IFS}
C_ERRMSG_MSG=0
C_ERRMSG_ERR=1
#---------------------------- include file for NIM error message definitions
. ${NIM_METHODS}/cmdnim_errors.shh

#---------------------------- Export this variable so commands that do RSH can
#---------------------------- utilize it in the Kerberos 5 arena.
export K5MUTE=1

#---------------------------- NIM specific stuff
REQUIRED_TMP_SPACE=2048
NIM_CLIENT_PACKAGE="bos.sysmgt.nim.client"
NIM_SPOT_PACKAGE="bos.sysmgt.nim.spot"
MASTER_UID=root
MSG_MISSING_BOOTI="network boot images"

SPOT_SERVER_OPTIONS="\
	${NIM_CLIENT_PACKAGE} \
	bos.net.tcp.client \
	bos.net.nfs.client"

#--------------------------------- README -------------------------------------
# a SPOT is a very important NIM resource which is used to support all network
#		boot operations
# in order to construct a SPOT, many optional packages are required
# here's why they're needed:
#		bos.sysmgt.nim.client		: required to support NIM operations
#		bos.sysmgt.nim.spot			: required to support network boot
#		bos.net.nfs.client			: required for NFS support
#		bos.net.tcp.client			: network interface support
#		bos.net.tcp.smit				: tcpip SMIT screens
#		bos.diag							: required for diagnostic support
#		bos.sysmgt.serv_aid			: required for diagnostic boot
#		bos.sysmgt.sysbr				: required to support standalone install
#		bos.sysmgt.smit				: required for diskless/dataless clients
#		bos.terminfo					: required for diskless/dataless term support
#		devices.all						: NIM needs all the device support it can get.
#											  this is important because NIM has no
#													knowledge about device support needed by
#													any NIM client and, if a client needs
#													support for a device which the SPOT
#													doesn't have, then the network boot
#													operation being performed MIGHT fail
#											  therefore, all device support is needed
# The following is a list of fileset pairs from which a member from each pair
# should be installed in a SPOT.  The first in the list of pairs that is
# found on the installation media will be appended to the list passed to
# the installp command.
#	bos.rte.up(4.1), bos.up (>=4.2)	: required to support diskless/dataless boot
#	bos.rte.mp(4.1), bos.mp (>=4.2) : required to support standalone install

# The list of filesets to use for DEFAULT_SPOT_OPTIONS may later be
# changed by the routine set_option_lists.

#Common packages found in POWER version/releases
#--------------------------------
DEFAULT_SPOT_COMMON_PPC="\
	${NIM_CLIENT_PACKAGE} \
	${NIM_SPOT_PACKAGE} \
	bos.net.nfs.client \
	bos.net.tcp.client \
	bos.net.tcp.smit \
	bos.diag \
	bos.sysmgt.serv_aid \
	bos.sysmgt.sysbr \
	bos.sysmgt.smit \
	bos.terminfo \
	devices.all"
#--------------------------------

DEFAULT_SPOT_OPTIONS_41="\
	${DEFAULT_SPOT_COMMON_PPC} \
	bos.rte.up \
	bos.rte.mp"

DEFAULT_SPOT_OPTIONS_42="\
	${DEFAULT_SPOT_COMMON_PPC} \
	bos.up \
	bos.mp"

DEFAULT_SPOT_OPTIONS_43="\
	${DEFAULT_SPOT_OPTIONS_42} \
	bos.64bit"

DEFAULT_SPOT_OPTIONS_50="\
	${DEFAULT_SPOT_OPTIONS_43}"

DEFAULT_SPOT_OPTIONS_51="\
	${DEFAULT_SPOT_OPTIONS_43} \
	rpm.rte"

DEFAULT_SPOT_OPTIONS_52="\
	${DEFAULT_SPOT_OPTIONS_43}"

DEFAULT_SPOT_OPTIONS_53="\
	${DEFAULT_SPOT_COMMON_PPC} \
	bos.mp \
	bos.mp64 \
	bos.64bit"

DEFAULT_SPOT_OPTIONS_61="\
	${DEFAULT_SPOT_COMMON_PPC} \
	bos.mp64 \
	bos.64bit \
	bos.wpars \
	mcr.rte"

DEFAULT_SPOT_OPTIONS_71="\
	${DEFAULT_SPOT_COMMON_PPC} \
	bos.mp64 \
	bos.64bit \
	bos.wpars \
	mcr.rte"

DEFAULT_SPOT_OPTIONS="\
	${DEFAULT_SPOT_COMMON_PPC} \
	bos.mp64 \
	bos.64bit \
	bos.wpars \
	mcr.rte"

#--------------------------------- README -------------------------------------
# in order to support install operations, NIM must have access to a directory
#		which contains all the images which will be required for an install
#		operation
# the set of images which NIM requires is called "simages" ("s"upport "images")
# if a NIM lpp_source has the complete set of these images, then it the
#		"simages" attribute will be added to the definition of the lpp_source
# the SIMAGES_OPTIONS list is used when creating an lpp_source
# the REQUIRED_SIMAGES list is used to determine whether an lpp_source gets
#		the "simages" attribute or not
#

# The default list of filesets to use for SIMAGES_OPTIONS and REQUIRED_SIMAGES
# may later be changed by the routine set_option_lists.


###############################################################################
#
# Do not introduce any blank lines during the definition of any of the
# SIMAGES_* variables. When the 'use_source_simages' attribute is set to 'yes'
# during the define operation of an lpp_source, NIM extracts the SIMAGES_*
# variables from this file using grep -p. Please see defect 746878 for more
# details.
#
###############################################################################

#Common packages found in POWER version/releases
#--------------------------------
SIMAGES_COMMON_PPC="\
	bos \
	bos.adt \
	bos.iconv \
	bos.net \
	bos.diag \
	bos.loc.iso \
	bos.msg.en_US \
	bos.sysmgt \
	bos.terminfo.all \
	bos.txt \
	devices.all \
	printers.rte \
	xlC.rte \
	X11.apps \
	X11.base \
	X11.fnt \
	X11.loc.all \
	X11.motif \
	X11.msg.all \
	X11.vsm"
#-------------------------------------------

#Common packages found in POWER 43 &above
#--------------------------------
SIMAGES_COMMON_43_ABOVE="\
	bos.64bit \
	bos.up \
	bos.mp \
	bos.help.msg.en_US \
	ifor_ls.base \
	perl.rte \
	sysmgt.help.msg.en_US \
	sysmgt.sguide \
	sysmgt.websm \
	sysmgt.msg.en_US.websm \
	Tivoli_Management_Agent.client \
	xlC.cpp \
	xlC.msg.en_US.cpp \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"
#-------------------------------------------

SIMAGES_OPTIONS_41="\
	${SIMAGES_COMMON_PPC} \
	bos.rte.up \
	bos.rte.mp \
	bos.ifor_ls \
	bos.info.any \
	bos.powermgt \
	ipx \
	X11.Dt \
	X11.compat"

SIMAGES_OPTIONS_42="\
	${SIMAGES_COMMON_PPC} \
	bos.up \
	bos.mp \
	bos.info.any \
	bos.ifor_ls \
	bos.powermgt \
	xlC.cpp \
	X11.Dt \
	X11.compat \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"

SIMAGES_OPTIONS_43="\
	${SIMAGES_COMMON_PPC} \
	${SIMAGES_COMMON_43_ABOVE} \
	bos.docsearch \
	bos.docregister \
	bos.html.en_US.topnav \
	bos.powermgt \
	ifor_ls.client \
	IMNSearch.rte.httpdlite \
	Java.rte \
	xlC.msg.Ja_JP.cpp \
	xlC.msg.ja_JP.cpp \
	xlC.aix43 \
	X11.Dt \
	X11.compat"

SIMAGES_OPTIONS_50="\
	${SIMAGES_COMMON_PPC} \
	${SIMAGES_COMMON_43_ABOVE} \
	bos.mp64 \
	bos.docsearch \
	bos.docregister \
	bos.html.en_US.topnav \
	bos.man.en_US \
	bos.perf \
	bos.powermgt \
	bos.svprint \
	invscout.ldb \
	invscout.rte \
	rsct.core \
	sysmgt.websm.webaccess \
	IMNSearch.bld \
	IMNSearch.rte \
	IMNSearch.rte.httpdlite \
	Java130.rte \
	xlC.msg.Ja_JP.cpp \
	xlC.msg.ja_JP.cpp \
	xlC.aix50 \
	X11.Dt \
	X11.compat"

SIMAGES_OPTIONS_51="\
	${SIMAGES_COMMON_PPC} \
	${SIMAGES_COMMON_43_ABOVE} \
	bos.mh \
	bos.mp64 \
	bos.acct \
	bos.docsearch \
	bos.docregister \
	bos.html.en_US.topnav \
	bos.man.en_US \
	bos.perf \
	bos.powermgt \
	bos.svprint \
	invscout.com \
	invscout.ldb \
	invscout.rte \
	rpm.rte \
	rsct.core \
	rsct.msg.en_US \
	rsct.msg.EN_US \
	sysmgt.help.en_US \
	IMNSearch.bld \
	IMNSearch.rte \
	IMNSearch.rte.httpdlite \
	Java130.rte \
	xlC.aix50 \
	X11.adt \
	X11.Dt \
	X11.samples \
	csm.core \
	csm.client"

SIMAGES_OPTIONS_52="\
	bos.64bit \
	bos \
	bos.acct \
	bos.adt \
	bos.cdmount \
	bos.diag \
	bos.help.msg.en_US \
	bos.iconv \
	bos.loc.iso \
	bos.man.en_US \
	bos.mh \
	bos.mp \
	bos.mp64 \
	bos.msg.en_US \
	bos.net \
	bos.perf \
	bos.suma \
	bos.sysmgt \
	bos.terminfo.all \
	bos.txt \
	bos.up \
	csm.client \
	csm.core \
	csm.diagnostics \
	csm.dsh \
	csm.msg.en_US \
	csm.msg.EN_US \
	devices.all \
	ifor_ls.base \
	invscout.com \
	invscout.ldb \
	invscout.rte \
	lum.base \
	lum.msg.en_US \
	perl.libext \
	perl.rte \
	printers.rte \
	rpm.rte \
	rsct.core \
	rsct.msg.en_US \
	rsct.msg.EN_US \
	Tivoli_Management_Agent.client \
	xlC.aix50 \
	xlC.cpp \
	xlC.msg.en_US.cpp \
	xlC.rte \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"


SIMAGES_OPTIONS_53="\
	bos.64bit \
	bos \
	bos.acct \
	bos.adt \
	bos.alt_disk_install \
	bos.atm \
	bos.cdmount \
	bos.diag \
	bos.dlc \
	bos.help.msg.en_US \
	bos.iconv \
	bos.loc.iso \
	bos.mh \
	bos.mp \
	bos.mp64 \
	bos.msg.en_US \
	bos.net \
	bos.perf \
	bos.pmapi \
	bos.suma \
	bos.swma \
	bos.sysmgt \
	bos.terminfo.all \
	bos.txt \
	csm.client \
	csm.core \
	csm.deploy \
	csm.diagnostics \
	csm.dsh \
	csm.msg.en_US \
	csm.msg.EN_US \
	devices.all \
	ifor_ls.base \
	ifor_ls.html.en_US \
	infocenter.man.EN_US.commands \
	invscout.com \
	invscout.ldb \
	invscout.rte \
	lum.base \
	lum.msg.en_US \
	perfagent.tools \
	perl.libext \
	perl.rte \
	printers.rte \
	rpm.rte \
	rsct.core \
	rsct.msg.en_US \
	rsct.msg.EN_US \
	Tivoli_Management_Agent.client \
	xlC.aix50 \
	xlC.cpp \
	xlC.rte \
	xlC.msg.en_US.cpp \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"

SIMAGES_OPTIONS_61="\
	bos.64bit \
	bos \
	bos.acct \
	bos.adt \
	bos.ae \
	bos.aixpert.cmds \
	bos.aso \
	bos.cdmount \
	bos.diag \
	bos.help.msg.en_US \
	bos.iconv \
	bos.iocp \
	bos.loc.iso \
	bos.mh \
	bos.mls \
	bos.mp64 \
	bos.msg.en_US \
	bos.net \
	bos.perf \
	bos.perf.pmaix \
	bos.pmapi \
	bos.swma \
	bos.sysmgt \
	bos.terminfo.all \
	bos.txt \
	bos.wpars \
	clic.rte \
	csm.client \
	csm.core \
	csm.deploy \
	csm.diagnostics \
	csm.dsh \
	csm.msg.en_US \
	csm.msg.EN_US \
	devices.all \
	ICU4C.rte \
	ifor_ls.base \
	ifor_ls.html.en_US \
	invscout.com \
	invscout.ldb \
	invscout.rte \
	lum.base \
	lum.msg.en_US \
	mcr.rte \
	perfagent.tools \
	perl.libext \
	perl.rte \
	printers.rte \
	rpm.rte \
	rsct.core \
	rsct.msg.en_US \
	rsct.msg.EN_US \
	security.acf \
	Tivoli_Management_Agent.client \
	wio.common \
	wio.fcp \
	wio.vscsi \
	xlC.aix61 \
	xlC.sup.aix50.rte \
	xlC.cpp \
	xlC.rte \
	xlC.msg.en_US.cpp \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"

SIMAGES_OPTIONS_71="\
	bos.64bit \
	bos \
	bos.acct \
	bos.adt \
	bos.ae \
	bos.aixpert.cmds \
	bos.aso \
	bos.cdmount \
	bos.diag \
	bos.help.msg.en_US \
	bos.iconv \
	bos.iocp \
	bos.loc.iso \
	bos.mh \
	bos.mls \
	bos.mp64 \
	bos.msg.en_US \
	bos.net \
	bos.perf \
	bos.perf.pmaix \
	bos.pmapi \
	bos.swma \
	bos.sysmgt \
	bos.terminfo.all \
	bos.txt \
	bos.wpars \
	cdrtools.base \
	cdrtools.man.en_US \
	clic.rte \
	devices.all \
	ICU4C.rte \
	invscout.com \
	invscout.ldb \
	invscout.rte \
	mcr.rte \
	perfagent.tools \
	perl.libext \
	perl.rte \
	printers.rte \
	rpm.rte \
	rsct.core \
	rsct.msg.en_US \
	rsct.msg.EN_US \
	security.acf \
	Tivoli_Management_Agent.client \
	wio.common \
	wio.fcp \
	wio.vscsi \
	xlC.aix61 \
	xlC.sup.aix50.rte \
	xlC.cpp \
	xlC.rte \
	xlC.msg.en_US.cpp \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"

SIMAGES_OPTIONS="\
	bos.64bit \
	bos \
	bos.acct \
	bos.adt \
	bos.ae \
	bos.aixpert.cmds \
	bos.aso \
	bos.cdmount \
	bos.diag \
	bos.help.msg.en_US \
	bos.iconv \
	bos.iocp \
	bos.liveupdate \
	bos.loc.iso \
	bos.mh \
	bos.mls \
	bos.mp64 \
	bos.msg.en_US \
	bos.net \
	bos.perf \
	bos.perf.pmaix \
	bos.pmapi \
	bos.swma \
	bos.sysmgt \
	bos.terminfo.all \
	bos.txt \
	bos.wpars \
	cdrtools.base \
	cdrtools.man.en_US \
	clic.rte \
	devices.all \
	ICU4C.rte \
	invscout.com \
	invscout.ldb \
	invscout.rte \
	mcr.rte \
	perfagent.tools \
	perl.libext \
	perl.rte \
	printers.rte \
	rpm.rte \
	rsct.core \
	rsct.msg.en_US \
	rsct.msg.EN_US \
	security.acf \
	wio.common \
	wio.fcp \
	wio.vscsi \
	xlC.aix61 \
	xlC.sup.aix50.rte \
	xlC.cpp \
	xlC.rte \
	xlC.msg.en_US.cpp \
	_SPOT._.pre_i.usr.1.0.0.0 \
	_SPOT._.post_i.usr.1.0.0.0"

# RPM packages
#--------------------------------
SIMAGES_COMMON_RPMS="\
	cdrecord* \
	mkisofs*"

SIMAGES_OPTIONS_RPMS_50="\
	${SIMAGES_COMMON_RPMS} \
	mtools*"

SIMAGES_OPTIONS_RPMS_51="\
	${SIMAGES_OPTIONS_RPMS_50}"

SIMAGES_OPTIONS_RPMS_52="\
	${SIMAGES_COMMON_RPMS}"

SIMAGES_OPTIONS_RPMS_53="\
	${SIMAGES_COMMON_RPMS}"

SIMAGES_OPTIONS_RPMS_61="\
	${SIMAGES_COMMON_RPMS} \
	expect* \
	tcl* \
	tk*"

SIMAGES_OPTIONS_RPMS_71="\
	expect* \
	tcl* \
	tk*"

SIMAGES_OPTIONS_RPMS="\
	expect* \
	tcl* \
	tk*"

# Graphics packages
#--------------------------------
SIMAGES_OPTIONS_GRAPHICS_52="\
	bos.docregister \
	bos.docsearch \
	bos.ecc_client \
	csm.gui.dcem \
	Java14.sdk \
	Java14.license \
	X11.adt \
	X11.apps \
	X11.base \
	X11.fnt \
	X11.loc.all \
	X11.motif \
	X11.msg.all \
	X11.samples \
	X11.vsm \
	sysmgt.help.en_US \
	sysmgt.help.msg.en_US \
	sysmgt.sguide \
	sysmgt.websm"

SIMAGES_OPTIONS_GRAPHICS_53="\
	bos.aixpert \
	bos.aixpert.cmds \
	bos.aixpert.websm \
	bos.ecc_client \
	bos.esagent \
	bos.iocp \
	bos.perf.fdpr \
	cas.agent \
	csm.gui.dcem \
	DirectorCommonAgent \
	DirectorPlatformAgent \
	ICU4C.rte \
	infocenter.man.EN_US.files \
	infocenter.man.EN_US.libs \
	Java14.sdk \
	Java14.license \
	Java5.sdk \
	lwi \
	openssl.base \
	openssl.license \
	openssl.man.en_US \
	perfagent.server \
	sysmgt.cim.providers \
	sysmgt.cim.smisproviders \
	sysmgt.cimserver.pegasus \
	tivoli.tivguid \
	X11.adt \
	X11.apps \
	X11.base \
	X11.fnt \
	X11.loc.all \
	X11.motif \
	X11.msg.all \
	X11.samples \
	X11.vsm \
	sysmgt.help.en_US \
	sysmgt.help.msg.en_US \
	sysmgt.sguide \
	sysmgt.websm \
	sysmgtlib.framework \
	sysmgtlib.libraries"

SIMAGES_OPTIONS_GRAPHICS_61="\
	adde.v2.ethernet \
	adde.v2.common \
	adde.v2.diag \
	adde.v2.rdma \
	artex.base \
	bos.ahafs \
	bos.aixpert.websm \
	bos.alt_disk_install \
	bos.cdat \
	bos.clvm \
	bos.cluster \
	bos.dlc \
	bos.ecc_client \
	bos.esagent \
	bos.perf.fdpr \
	bos.suma \
	bos.xerces \
	cache.mgt \
	cas.agent \
	csm.gui.dcem \
	DirectorCommonAgent \
	DirectorPlatformAgent \
	expect.base \
	expect.man.en_US \
	infocenter.man.EN_US.commands \
	infocenter.man.EN_US.files \
	infocenter.man.EN_US.libs \
	Java5.sdk \
	Java5_64.sdk \
	Java6.sdk \
	Java7_64.jre \
	Java7_64.sdk \
	lwi \
	openssl.base \
	openssl.license \
	openssl.man.en_US \
	perfagent.server \
	rsct.basic \
	rsct.compat.basic \
	rsct.compat.clients \
	rsct.opt.stackdump \
	rsct.opt.storagerm \
	sysmgt.cim.providers \
	sysmgt.cim.smisproviders \
	sysmgt.cimserver.pegasus \
	tcl.base \
	tcl.man.en_US \
	tivoli.tivguid \
	tk.base \
	tk.man.en_US \
	X11.adt \
	X11.apps \
	X11.base \
	X11.compat \
	X11.fnt \
	X11.loc.all \
	X11.motif \
	X11.msg.all \
	X11.samples \
	X11.vsm \
	xlsmp.rte \
	xlsmp.aix61.rte \
	sysmgt.help.en_US \
	sysmgt.help.msg.en_US \
	sysmgt.pconsole \
	sysmgt.sguide \
	sysmgt.websm \
	sysmgtlib.framework \
	sysmgtlib.libraries"

SIMAGES_OPTIONS_GRAPHICS_71="\
	adde.v2.ethernet \
	adde.v2.common \
	adde.v2.diag \
	adde.v2.rdma \
	artex.base \
	bos.ahafs \
	bos.alt_disk_install \
	bos.cdat \
	bos.clvm \
	bos.cluster \
	bos.dlc \
	bos.ecc_client \
	bos.esagent \
	bos.perf.fdpr \
	bos.pfcdd \
	bos.suma \
	bos.xerces \
	cache.mgt \
	cas.agent \
	DirectorCommonAgent \
	DirectorPlatformAgent \
	expect.base \
	expect.man.en_US \
	infocenter.man.EN_US.commands \
	infocenter.man.EN_US.files \
	infocenter.man.EN_US.libs \
	Java5.sdk \
	Java5_64.sdk \
	Java6.sdk \
	Java7_64.jre \
	Java7_64.sdk \
	Java8.jre \
	Java8.sdk \
	Java8_64.jre \
	Java8_64.sdk \
	lwi \
	ntp.rte \
	openssl.base \
	openssl.license \
	openssl.man.en_US \
	perfagent.server \
	rsct.basic \
	rsct.compat.basic \
	rsct.compat.clients \
	rsct.opt.stackdump \
	rsct.opt.storagerm \
	sysmgt.cfgassist \
	sysmgt.cim.providers \
	sysmgt.cim.smisproviders \
	sysmgt.cimserver.pegasus \
	tcl.base \
	tcl.man.en_US \
	tivoli.tivguid \
	tk.base \
	tk.man.en_US \
	X11.adt \
	X11.apps \
	X11.base \
	X11.compat \
	X11.fnt \
	X11.loc.all \
	X11.motif \
	X11.msg.all \
	X11.samples \
	X11.vsm \
	xlsmp.rte \
	xlsmp.aix61.rte \
	sysmgt.pconsole \
	sysmgtlib.framework \
	sysmgtlib.libraries"

SIMAGES_OPTIONS_GRAPHICS="\
	adde.v2.ethernet \
	adde.v2.common \
	adde.v2.diag \
	adde.v2.rdma \
	artex.base \
	bos.ahafs \
	bos.alt_disk_install \
	bos.cdat \
	bos.clvm \
	bos.cluster \
	bos.dlc \
	bos.dsc \
	bos.ecc_client \
	bos.esagent \
	bos.hdcrypt \
	bos.kmip_client \
	bos.net.tcp.adt \
	bos.net.tcp.bind \
	bos.net.tcp.bind_utils \
	bos.net.tcp.bootp \
	bos.net.tcp.cdp \
	bos.net.tcp.client \
	bos.net.tcp.client_core \
	bos.net.tcp.dfpd \
	bos.net.tcp.dhcp \
	bos.net.tcp.dhcpd \
	bos.net.tcp.ftp \
	bos.net.tcp.ftpd \
	bos.net.tcp.gated \
	bos.net.tcp.imapd \
	bos.net.tcp.mail_utils \
	bos.net.tcp.ntp \
	bos.net.tcp.ntpd \
	bos.net.tcp.pop3d \
	bos.net.tcp.pxed \
	bos.net.tcp.rcmd \
	bos.net.tcp.rcmd_server \
	bos.net.tcp.sendmail \
	bos.net.tcp.server \
	bos.net.tcp.server_core \
	bos.net.tcp.slip \
	bos.net.tcp.slp \
	bos.net.tcp.smit \
	bos.net.tcp.snmp \
	bos.net.tcp.snmpd \
	bos.net.tcp.syslogd \
	bos.net.tcp.tcpdump \
	bos.net.tcp.telnet \
	bos.net.tcp.telnetd \
	bos.net.tcp.tftp \
	bos.net.tcp.tftpd \
	bos.net.tcp.timed \
	bos.net.tcp.traceroute \
	bos.net.tcp.x500 \
	bos.perf.fdpr \
	bos.pfcdd \
	bos.suma \
	bos.xerces \
	cache.mgt \
	expect.base \
	expect.man.en_US \
	infocenter.man.EN_US.commands \
	infocenter.man.EN_US.files \
	infocenter.man.EN_US.libs \
	ios.vnet \
	Java8_64.jre \
	Java8_64.sdk \
	Java7_64.jre \
	Java7_64.sdk \
	Java6.sdk \
	libc++.rte \
	ntp.rte \
	openssh.base \
	openssh.license \
	openssh.man.en_US \
	openssh.msg.en_US \
	openssl.base \
	openssl.license \
	openssl.man.en_US \
	perfagent.server \
	rsct.basic \
	rsct.compat.basic \
	rsct.compat.clients \
	rsct.opt.stackdump \
	rsct.opt.storagerm \
	sysmgt.cfgassist \
	tcl.base \
	tcl.man.en_US \
	tivoli.tivguid \
	tk.base \
	tk.man.en_US \
	X11.adt \
	X11.apps \
	X11.base \
	X11.compat \
	X11.fnt \
	X11.loc.all \
	X11.motif \
	X11.msg.all \
	X11.samples \
	X11.vsm \
	xlsmp.rte \
	xlsmp.aix61.rte \
	sysmgtlib.framework \
	sysmgtlib.libraries"

#Common packages found in POWER version/releases
#--------------------------------
REQUIRED_COMMON_PPC="\
	bos \
	bos.net \
	bos.diag \
	bos.sysmgt \
	bos.terminfo \
	bos.terminfo.all.data \
	devices.graphics.all \
	devices.scsi.all \
	devices.tty.all \
	xlC.rte"
#-----------------------------------------

REQUIRED_SIMAGES_41="\
	${REQUIRED_COMMON_PPC} \
	devices.buc.all \
	devices.mca.all \
	devices.base.all \
	devices.rs6ksmp.base \
	devices.sio.all \
	devices.sys.all \
	bos.rte.up \
	bos.rte.mp"

REQUIRED_SIMAGES_42="\
	${REQUIRED_COMMON_PPC} \
	devices.buc.all \
	devices.mca.all \
	devices.base.all \
	devices.rs6ksmp.base \
	devices.sio.all \
	devices.sys.all \
	bos.up \
	bos.mp \
	devices.common.all"

REQUIRED_SIMAGES_43="\
	${REQUIRED_SIMAGES_42} \
	bos.64bit"

REQUIRED_SIMAGES_50="\
	${REQUIRED_SIMAGES_43}"

REQUIRED_SIMAGES_51="\
	${REQUIRED_SIMAGES_43}"

REQUIRED_SIMAGES_52="\
	${REQUIRED_COMMON_PPC} \
	bos.up \
	bos.mp \
	devices.common.all \
	bos.64bit"

REQUIRED_SIMAGES_53="\
	${REQUIRED_COMMON_PPC} \
	bos.mp \
	devices.common.all \
	bos.64bit"

REQUIRED_SIMAGES_61="\
	${REQUIRED_COMMON_PPC} \
	bos.mp64 \
	devices.common.all \
	bos.64bit \
	bos.wpars \
	bos.aixpert.cmds \
	ifor_ls.base \
	ICU4C.rte \
	lum.base \
	bos.mls \
	perl.rte \
	xlC.aix61"

REQUIRED_SIMAGES_71="\
	${REQUIRED_COMMON_PPC} \
	bos.mp64 \
	devices.common.all \
	bos.64bit \
	bos.wpars \
	bos.aixpert.cmds \
	ICU4C.rte \
	bos.mls \
	perl.rte \
	xlC.aix61"

REQUIRED_SIMAGES="\
	${REQUIRED_COMMON_PPC} \
	bos.mp64 \
	devices.common.all \
	bos.64bit \
	bos.wpars \
	bos.aixpert.cmds \
	ICU4C.rte \
	bos.mls \
	perl.rte \
	xlC.aix61"

NIMINFO=/etc/niminfo
NIM_AWK="${NIMPATH}/awk"
NIM_CMDS="/usr/sbin"
NIM="${NIM_CMDS}/nim"
NIMCLIENT="${NIM_CMDS}/nimclient"
NIMHTTP="${NIM_CMDS}/nimhttp"
LSNIM="${NIM_CMDS}/lsnim"
NIM_INSTP_UPDT_LIST="/tmp/NIM_instp_updt_list"
MK_NETBOOT="/tmp/mk_netboot"
NIM_STATUS="/tmp/.nim.stat"
C_AT="${NIM_METHODS}/c_at"
C_BOOTDISKHDR="${NIM_METHODS}/c_bootdiskhdr"
C_CH_RHOST="${NIM_METHODS}/c_ch_rhost"
C_CKROS_EMU="${NIM_METHODS}/c_ckros_emu"
C_CKSPOT="${NIM_METHODS}/c_ckspot"
C_CP_RESOLV="${NIM_METHODS}/c_cp_resolv"
C_DUMPCHECK=${NIM_METHODS}/c_dumpcheck
C_ERRMSG=${NIM_METHODS}/c_errmsg
C_FILE_TRANSFER="${NIM_METHODS}/c_file_transfer"
C_FUNCTION="${NIM_METHODS}/c_function"
C_GETLEVEL="${NIM_METHODS}/c_getlevel"
C_INSTALLP="${NIM_METHODS}/c_installp"
C_MK_NIMCLIENT="${NIM_METHODS}/c_mk_nimclient"
C_MKBOOTI="${NIM_METHODS}/c_mkbooti"
C_MKDIR="${NIM_METHODS}/c_mkdir"
C_MKPFILE=${NIM_METHODS}/c_mkpfile
C_NIMINFO="${NIM_METHODS}/c_niminfo"
C_RCP="${NIM_METHODS}/c_rcp"
C_RMDIR=${NIM_METHODS}/c_rmdir
C_RSH="${NIM_METHODS}/c_rsh"
C_SCRIPT=${NIM_METHODS}/c_script
C_STAT=${NIM_METHODS}/c_stat
C_SYNC_ROOT=${NIM_METHODS}/c_sync_root
C_TIME_STAMP=${NIM_METHODS}/c_time_stamp
NIM_CHROOT_LIBS_BASE=/usr/lib/._spot_libs_@_71438
NIM_CHROOT_LIBS1=${NIM_CHROOT_LIBS_BASE}/usr/ccs/lib
NIM_CHROOT_LIBS2=${NIM_CHROOT_LIBS_BASE}/usr/lib
NIM_CHROOT_LIBS_LINKS_BASE=/usr/lib/._spot_libs_links_@_71439
NIM_CHROOT_LIBS_LINKS1=${NIM_CHROOT_LIBS_LINKS_BASE}/usr/ccs/lib
NIM_CHROOT_LIBS_LINKS2=${NIM_CHROOT_LIBS_LINKS_BASE}/usr/lib
SET_CHROOT_LIBPATH="export LIBPATH=${NIM_CHROOT_LIBS_LINKS1}:${NIM_CHROOT_LIBS_LINKS2}:${NIM_CHROOT_LIBS1}:${NIM_CHROOT_LIBS2}:/usr/ccs/lib:/usr/lib"
UNSET_CHROOT_LIBPATH="unset LIBPATH"

M_CHSTATE=${NIM_METHODS}/m_chstate
M_FS=${NIM_METHODS}/m_fs

LPP_NAME="./lpp_name"
IMAGE_DATA="./image.data"
LPP_NAME_IN_SPOT="./lpp/bos/inst_root/lpp_name"
IMAGE_DATA_IN_SPOT="./lpp/bosinst/image.template"
DEFAULT_REQUIRED_VERSION=4
DEFAULT_REQUIRED_RELEASE=0
BOS_PATH_ON_CDROM="installp/ppc/bos"
BOS_PATH_ON_CDROM_OLD="usr/sys/inst.images/bos"
LIC_PATH_ON_CDROM="usr/swlag"
DEFAULT_PERMS="775"
INST_ROOT="./lpp/bos/inst_root"
INST_IMAGES="/usr/sys/inst.images"
DEFAULT_GENCOPY_FLAGS="-bqXS"
DEFAULT_INSTALLP_FLAGS="-agQX"
DEFAULT_INSTALLP_OPTIONS="all"
INSTALLP_LOG=/var/adm/ras/nim.installp
LPPCHK_LOG=/var/adm/ras/nim.lppchk
OFFSET_FOR_CDROM="/installp/ppc"
OFFSET_FOR_CDROM_OLD="/usr/sys/inst.images"
TFTPBOOT="/tftpboot"
NIM_BACKUP_DIR="/export/nim/backups"
SWAPNFS="swapnfs"
INSTROOT_CUST_SZ=/tmp/.installp.root_sz #Used to track root size requirements
					#between c_instspot and c_sync_root
					#for /usr-SPOT inst_root.
SCRIPT_LOG=/var/adm/ras/nim.script
SHROOT_CUSTDIR="etc/.client_data"

STATE_RUNNING=running

PROTECTED_DIRS="/ /usr /var /tmp /home $TFTPBOOT"

# NOTE: The following variable gets used by c_instspot when creating
#       a chroot environment.  The value of IMAGES is the directory
#       over which the lpp_source will be mounted.  This mount point
#       must NOT correspond to any existing filesystem on the server
#       or installp will fail because the stat system call fails
#       because it gets confused.  So, we're using the process ID of
#       c_instspot in the hopes that it will be unique enough that
#       the server will not have a filesystem which uses that name
IMAGES="/$$"

NFS4_MNTDIR="/tmp/_.nim_mounts._"
NFS4_LINKDIR="${NFS4_MNTDIR}/hostlinks"

#---------------------------- AIX command pathnames
INURID=${SPOT}/usr/lib/instl/inurid

RCBOOT=${SPOT}/sbin/rc.boot

BACKUP=${SPOT}/usr/sbin/backup
BFFCREATE=${SPOT}/usr/sbin/bffcreate
BOOTINFO=${SPOT}/usr/sbin/bootinfo
BOOTPTODHCP=${SPOT}/usr/sbin/bootptodhcp
BOSBOOT=${SPOT}/usr/sbin/bosboot
CDCHECK=${SPOT}/usr/sbin/cdcheck
CDEJECT=${SPOT}/usr/sbin/cdeject
CDMOUNT=${SPOT}/usr/sbin/cdmount
CDUMOUNT=${SPOT}/usr/sbin/cdumount
CHDEV=${SPOT}/usr/sbin/chdev
CHFS=${SPOT}/usr/sbin/chfs
CHNFS=${SPOT}/usr/sbin/chnfs
CHNFSEXP=${SPOT}/usr/sbin/chnfsexp
CHROOT=${SPOT}/usr/sbin/chroot
COMPRESS=${SPOT}/usr/bin/compress
DSPMSG=${SPOT}/usr/bin/dspmsg
GENCOPY="${SPOT}/usr/sbin/gencopy"
GENINSTALL="${SPOT}/usr/sbin/geninstall -Z"
INSTALLP="${SPOT}/usr/sbin/installp"
INUTOC="${SPOT}/usr/sbin/inutoc"
LINK=${SPOT}/usr/sbin/link
LOOPMOUNT=${SPOT}/usr/sbin/loopmount
LOOPUMOUNT=${SPOT}/usr/sbin/loopumount
LSATTR=${SPOT}/usr/sbin/lsattr
LSFS=${SPOT}/usr/sbin/lsfs
MKBOOT=${SPOT}/usr/sbin/mkboot 
MKITAB=${SPOT}/usr/sbin/mkitab
MKNFS=${SPOT}/usr/sbin/mknfs
MKNFSEXP=${SPOT}/usr/sbin/mknfsexp
MKTCPIP=${SPOT}/usr/sbin/mktcpip
MOUNT=${SPOT}/usr/sbin/mount
NAMERSLV=${SPOT}/usr/bin/namerslv
REBOOT=${SPOT}/usr/sbin/reboot
RESOLV_CONF="/etc/resolv.conf"
RESTORE=${SPOT}"/usr/sbin/restbyname -Sq"
ROUTE=${SPOT}"/usr/sbin/route"
RSH=${SPOT}"/usr/bin/rsh"
RMNFSEXP=${SPOT}/usr/sbin/rmnfsexp
SAVEBASE=${SPOT}/usr/sbin/savebase
SHUTDOWN=${SPOT}/usr/sbin/shutdown
SM_INST=${SPOT}/usr/lib/instl/sm_inst
UNLINK=${SPOT}/usr/sbin/unlink
UNMOUNT=${SPOT}/usr/sbin/unmount

ALOG=${SPOT}/usr/bin/alog
AT=${SPOT}/usr/bin/at
AWK=${SPOT}/usr/bin/awk
BOOTLIST=${SPOT}/usr/bin/bootlist
BOOTINFO=${SPOT}/usr/sbin/bootinfo
BASENAME=${SPOT}/usr/bin/basename
CAT=${SPOT}/usr/bin/cat
CFGMGR=${SPOT}/usr/sbin/cfgmgr
CHMOD=${SPOT}/usr/bin/chmod
CHOWN=${SPOT}/usr/bin/chown
CHSIGNPOLICY=${SPOT}/usr/sbin/chsignpolicy
CHWPAR=${SPOT}/usr/sbin/chwpar
CP=${SPOT}/usr/bin/cp
CUT=${SPOT}/usr/bin/cut
CPIO=${SPOT}/usr/bin/cpio
DATE=${SPOT}/usr/bin/date
DD=${SPOT}/usr/bin/dd
DF=${SPOT}/usr/bin/df
DIRNAME=${SPOT}/usr/bin/dirname
DU="${SPOT}/usr/bin/du -x"
ECHO=${SPOT}/usr/bin/echo
EGREP=${SPOT}/usr/bin/egrep
EXPR=${SPOT}/usr/bin/expr
FGREP=${SPOT}/usr/bin/fgrep
FILE=${SPOT}/usr/bin/file
FIND=${SPOT}/usr/bin/find
GREP=${SPOT}/usr/bin/grep
HOSTCMD=${SPOT}/usr/bin/host
HOSTNAME=${SPOT}/usr/bin/hostname
INSTFIX=${SPOT}/usr/sbin/instfix
INUUMSG=${SPOT}/usr/sbin/inuumsg
LN=${SPOT}/usr/bin/ln
LPPCHK=${SPOT}/usr/bin/lppchk
LS=${SPOT}/usr/bin/ls
LSDEV=${SPOT}/usr/sbin/lsdev
LSLPP=${SPOT}/usr/bin/lslpp
LSLV=${SPOT}/usr/sbin/lslv
LSMKSYSB=${SPOT}/usr/bin/lsmksysb
LSSAVEVG=${SPOT}/usr/bin/lssavevg
LSSAVEWPAR=${SPOT}/usr/bin/lssavewpar
LSWPAR=${SPOT}/usr/sbin/lswpar
MKDEV=${SPOT}/usr/sbin/mkdev
MKDIR=${SPOT}/usr/bin/mkdir
MKISCSI=${SPOT}/usr/sbin/mkiscsi
MKSSYS=${SPOT}/usr/bin/mkssys
MKWPAR=${SPOT}/usr/sbin/mkwpar
MV=${SPOT}/usr/bin/mv
NM=${SPOT}/usr/bin/nm
OD=${SPOT}/usr/bin/od
ODMADD=${SPOT}/usr/bin/odmadd
ODMCHANGE=${SPOT}/usr/bin/odmchange
ODMDELETE=${SPOT}/usr/bin/odmdelete
ODMGET=${SPOT}/usr/bin/odmget
OSLEVEL=${SPOT}/usr/bin/oslevel
PRTCONF=${SPOT}/usr/sbin/prtconf
PS=${SPOT}/usr/bin/ps
RECFGCT=${SPOT}/usr/sbin/rsct/install/bin/recfgct
REFRESH=${SPOT}/usr/bin/refresh
RESTWPAR=${SPOT}/usr/sbin/restwpar
RM="${SPOT}/usr/bin/rm -f"
RMDEV=${SPOT}/usr/sbin/rmdev
RMDIR=${SPOT}/usr/bin/rmdir
RMISCSI=${SPOT}/usr/sbin/rmiscsi
RMITAB=${SPOT}/usr/sbin/rmitab
RMSSYS=${SPOT}/usr/bin/rmssys
RMWPAR=${SPOT}/usr/sbin/rmwpar
SAVEWPAR=${SPOT}/usr/sbin/savewpar
SED=${SPOT}/usr/bin/sed
SLEEP=${SPOT}/usr/bin/sleep
SLIBCLEAN=${SPOT}/usr/sbin/slibclean
SNAP=${SPOT}/usr/sbin/snap
SORT=${SPOT}/usr/bin/sort
STARTSRC=${SPOT}/usr/bin/startsrc
STARTWPAR=${SPOT}/usr/sbin/startwpar
STOPSRC=${SPOT}/usr/bin/stopsrc
STOPWPAR=${SPOT}/usr/sbin/stopwpar
SYNCWPAR=${SPOT}/usr/sbin/syncwpar
SYSDUMPDEV=${SPOT}/usr/bin/sysdumpdev
SYNC=${SPOT}/usr/sbin/sync
TAIL=${SPOT}/usr/bin/tail
TAR=${SPOT}/usr/bin/tar
TCTL=${SPOT}/usr/bin/tctl
TEE=${SPOT}/usr/bin/tee
TOUCH=${SPOT}/usr/bin/touch
TR=${SPOT}/usr/bin/tr
TUNCHANGE=${SPOT}/usr/sbin/tunchange
UMOUNT=${SPOT}/usr/sbin/umount
UNAME=${SPOT}/usr/bin/uname
VMO=${SPOT}/usr/sbin/vmo
WALL=${SPOT}/usr/sbin/wall
WC=${SPOT}/usr/bin/wc

#---------------------------- AIX file pathnames
BOOTPTAB=/etc/bootptab
DHCPSD=/etc/dhcpsd.cnf
FILESYSTEMS=/etc/filesystems
FIRSTBOOT=/etc/firstboot
HOSTS=/etc/hosts
INETD_CONF=/etc/inetd.conf
INITTAB=/etc/inittab
IPLROM_SETUP=/usr/lib/boot/iplrom.setup
LICENSE_SIG=/var/adm/.license.sig
RHOSTS="/.rhosts"
SWAPSPACES=/etc/swapspaces
TFTPACCESS=/etc/tftpaccess.ctl
LOCAL_DOMAIN=/etc/nfs/local_domain

#---------------------------- module globals    --------------------------------
variable=""
value=""
access_pnt=""
mounts=""
mount_opts=""
tmp_dirs=""
tmp_files=""
unmounts=""
location=""
new_root=""
chroot=""
undo_on_interrupt=""
tape_device_name=""
tape_block_size=""
instp_err_log=""
lppchk_error=""
disable_cdumount=""
typeset -i lvl_a1 lvl_a2 lvl_a3 lvl_a4
typeset -i lvl_b1 lvl_b2 lvl_b3 lvl_b4

#---------------------------- bname 
#
# NAME: bname
#
# FUNCTION: do a basename equiv in ksh
#
# DATA STRUCTURES:
#		parameters:
#			 1		- 	The string to work on... 
#
# RETURNS: (char)
#		The result of the basename function	
#
#-------------------------------------------------------------------------------
function bname {

        S=$1
        S=${S%%+(/)}    # remove rightmost /s if any
        S=${S##*/}      # remove path
        echo $S
}

#---------------------------- DEBUG             --------------------------------
#
# NAME: DEBUG
#
# FUNCTION:
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function DEBUG {
	typeset tmp=""

	[[ $# > 0 ]] && print $*

	read tmp?">>>>>>>>>>>>>>>>>> DEBUG: any key to continue <<<<<<<<<<<<<<<<<<<"

} # end of DEBUG

#---------------------------- unmount_chroot_libs
#
# NAME: unmount_chroot_libs
#
# FUNCTION:
#	Unmounts a SPOT server's libraries from overmounted subdirectories in 
#	the SPOT.
#
#	parameters:
#
#	global:
#		location	= location of SPOT used to support chroot env.
# RETURNS: (int)
#     0              = success
#
#-------------------------------------------------------------------------------

function unmount_chroot_libs {
	
	mnt_pnt=""
	found_mnt=""
	lib=""
	
	# Nothing to do if working with a /usr SPOT since we didn't mount
	# the libraries in the first place.
	[[ ${location} = /usr ]] && return 0

	# Look for the mounted libraries in the mount table.  Then look through
	# the mount list if it appears we need to unmount the libraries.
	${MOUNT} | ${EGREP} -q "(${NIM_CHROOT_LIBS1}|${NIM_CHROOT_LIBS2})"

	if [[ $? -eq 0 ]]
	then
		for i in ${mounts}
		do
			# separate stanza
			mnt_pnt=${i##*:}

			# is this one of the 2 we're looking for?
			if [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS1} ]]
			then

				nim_unmount ${mnt_pnt} force
				found_mnt=${mnt_pnt}
				lib=${NIM_CHROOT_LIBS1}

			elif [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS2} ]]
			then
				nim_unmount ${mnt_pnt} force
				found_mnt=${mnt_pnt}
				lib=${NIM_CHROOT_LIBS2}
			fi
		done
	fi

	# If we found a mount point above, unmount the SPOT from the chroot
	# environment.   This may also need force unmounting because we force 
	# unmounted the libraries which were mounted in the SPOT's subdirs.
	if [[ -n ${found_mnt} ]]
	then
		# Get the SPOT mount point by stripping off the end of the
		# library's mount point (matching the library location in the
		# chroot environment), then adding /usr back on.

		mnt_pnt=${found_mnt%%${lib}}/usr
		nim_unmount ${mnt_pnt} force
	fi
	return 0
}

#---------------------------- cleanup           --------------------------------
#
# NAME: cleanup
#
# FUNCTION:
#		performs cleanup operations on exit
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function cleanup {

	typeset i=""
	typeset dir_name=""

	# anything that needs executing?
	if [[ -s ${TMPDIR}/undo_on_exit ]]
	then

		${CHMOD} +x ${TMPDIR}/undo_on_exit && ${TMPDIR}/undo_on_exit

	fi

	# reset the tape block size if necessary
	if [[ -n "${tape_block_size}" ]] && [[ -n "${tape_device_name}" ]]
	then

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

	fi

	# unmount anything we mounted
	# First, unmount the server's libraries if we mounted them 
	# -- we may need to force unmount them because for some reason,
	# processes are accessing the libraries and causing a non-forced
	# unmount to fail.
	unmount_chroot_libs

	# lets attempt to unmount all the mounts now.  We should keep trying
	# until they are all gone.  If after about 10 tries then we better
	# force unmount them.  There may be situations where the removal of
	# directories later will inadvertently remove the wrong files and
	# directories if this unmount doesn't occur.
	let unmount_retries=10
	while [[ -n ${mounts} ]] && (( unmount_retries > 0 ))
	do
		nim_unmount all 2>/dev/null
		if [[ -n ${mounts} ]] 
		then
			let unmount_retries=unmount_retries-1
			${SLEEP} 1
		fi
	done
	[[ -n ${mounts} ]] && nim_unmount all force

	# do we still require nfs4 mounts?
	if [[ -s ${TMPDIR}/unmount_on_exit ]]
	then
		${CHMOD} +x ${TMPDIR}/unmount_on_exit && ${TMPDIR}/unmount_on_exit
	fi

	# remove tmp files
	for i in ${tmp_files}
	do
		${RM} ${i} 2>/dev/null
	done

	# cd to a neutral directory before removing temporary directories
	cd /tmp 2>/dev/null

	# remove tmp dirs
	for i in ${tmp_dirs}
	do
		dir_name=${i%:*}
		if [[ -d ${dir_name} ]]
		then
			protected_dir ${i} || ${RM} -r ${dir_name} 2>/dev/null
		fi
	done

	# remove tmp stuff
	# for unknown reasons, if "eval" is not used at this point, the shell will
	#		complain about not being able to exeucte "/usr/bin/rm -f" (why?????)
	eval ${RM} /tmp/_nim_$$.err 2>/dev/null
	eval ${RM} -r ${TMPDIR} 2>/dev/null

	unset AUTOMOUNT_DISABLE_FLAG	# set by c_instpot when cdromd is running.


} # end of cleanup

#---------------------------- warning           --------------------------------
#
# NAME: warning
#
# FUNCTION:
#		displays warning messages
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1				= errno
#			2				= str1 of error msg
#			3				= str2 of error msg
#			4				= str3 of error msg
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function warning {

	typeset errno=${1:-${ERR_SYS}}
  
	tmpwarn=${TMPDIR}/$$.tmp_warn

	# display the error msg as a warning
        # prepend a translated "warning" string
        warn_str=`${C_ERRMSG} ${MSG_WARNING} ${C_ERRMSG_MSG} "" "" "" "" 2>&1`
	print -n ${warn_str}": " > ${tmpwarn} 2>&1
	${C_ERRMSG} ${1} ${C_ERRMSG_ERR} ${PROGNAME} "${2}" "${3}" "${4}" \
                                 >> ${tmpwarn} 2>&1

	# do we need to update the err_info field on a client?
	if [ "${UPDT_CL_ERR_INFO}" = "yes" ]
	then
	 	${NIMCLIENT} -o change -aforce=yes -aignore_lock=yes \
						 -aerr_info="$(cat ${tmpwarn})"
	else
		${CAT} ${tmpwarn} 1>&2
	fi
	${RM} ${tmpwarn}

	# check for additional error output from command. 
	if [[ ${errno} = ${ERR_CMD} ]] && [[ -s ${ERR} ]]
	then
		# if updating err_info attribute on client, capture the
		# output and call nimclient to do the update.  
		# otherwise display the output.
		if [[ "${UPDT_CL_ERR_INFO}" = "yes" ]]
		then 
			if [[ -n "${instp_err_log}" ]]
			then
				# Don't want to add installp output to the
				# err_info attribute.  Add a msg about 
				# viewing the log.
				err_txt=`${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
					${C_ERRMSG_MSG} "${instp_err_log}" \
					"" "" "" 2>&1`
			elif [[ -n "${lppchk_error}" ]]
			then
				# Don't want to add lppchk output to the
				# err_info attribute.  Add a msg about 
				# viewing the log.
				err_txt=`${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
					${C_ERRMSG_MSG} "${LPPCHK_LOG}" \
					"" "" "" 2>&1`
			else

				# remove any "rc=" that might exist in 
				# the output
				err_txt=`${AWK} '{gsub(/rc=[0-9]+/,"");print}' \
								${ERR} 2>&1`
			fi
	 		${NIMCLIENT} -o change -aforce=yes -aignore_lock=yes \
					-aerr_info="$( print ${err_txt} )"
		else
			# remove any "rc=" that might exist in the output
			${AWK} '{gsub(/rc=[0-9]+/,"");print}' ${ERR} 1>&2
		fi

	fi

	# In some cases, we show output from the failed cmd and don't
	# capture the err_info in ${ERR}.  Let's print a generic msg
	# about viewing a log. 
	if [[ -n "${lppchk_error}" ]]
	then
		${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
				${C_ERRMSG_MSG} "${LPPCHK_LOG}" "" "" ""

	elif  [[ "${NIM_SHOW_PROGRESS}" = "yes" ]] && [[ -n "${instp_err_log}" ]]
	then
		${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
				${C_ERRMSG_MSG} "${instp_err_log}" "" "" ""
	fi
	instp_err_log=""

} # end of warning

#---------------------------- warning_from_cmd  --------------------------------
#
# NAME: warning_from_cmd
#
# FUNCTION:
#		displays error message from failed commands but does NOT exit
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		ASSUMES error output from failed commad is in the ${ERR} file
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= name of command which failed
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function warning_from_cmd {

	# display the error msg
	warning ${ERR_CMD} "${1}"

} # end of warning_from_cmd

#---------------------------- error             --------------------------------
#
# NAME: error
#
# FUNCTION:
#		displays the specified error message & exits
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		exits with a "1"
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1				= errno
#			2				= str1 of error msg
#			3				= str2 of error msg
#			4				= str3 of error msg
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function error {

	typeset errno=${1:-${ERR_SYS}}

	typeset override_txt=${5}	# used when error msg not in catalogue

	# display the error msg
	if [[ -n "${override_txt}" ]] && [[ -z "${2}" ]]
	then
		err_txt="${override_txt}"
	else
		err_txt=`${C_ERRMSG} ${errno} ${C_ERRMSG_ERR} ${PROGNAME} "${2}" "${3}" "${4}" 2>&1`
	fi

	# do we need to update the err_info field on a client?
	if [ "${UPDT_CL_ERR_INFO}" = "yes" ]
	then
	 	${NIMCLIENT} -o change -aforce=yes -aignore_lock=yes \
				-aerr_info="$( print ${err_txt} )"
	else
		print "rc=${errno}" 1>&2
		print ${err_txt} 1>&2
	fi

	# check for additional error output from command. 
	if [[ ${errno} = ${ERR_CMD} ]] && [[ -s ${ERR} ]]
	then

		# if updating err_info attribute on client, capture the
		# output and call nimclient to do the update.  
		# otherwise display the output.
		if [[ "${UPDT_CL_ERR_INFO}" = "yes" ]]
		then 
			if [[ -n "${instp_err_log}" ]]
			then
				# Don't want to add installp output to the
				# err_info attribute.  Add a msg about 
				# viewing the log.
				err_txt=`${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
					${C_ERRMSG_MSG} "${instp_err_log}" \
					"" "" "" 2>&1`

			elif [[ -n "${lppchk_error}" ]]
			then
				# Don't want to add lppchk output to the
				# err_info attribute.  Add a msg about 
				# viewing the log.
				err_txt=`${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
					${C_ERRMSG_MSG} "${LPPCHK_LOG}" \
					"" "" "" 2>&1`
			else

				# remove any "rc=" that might exist in 
				# the output
				err_txt=`${AWK} '{gsub(/rc=[0-9]+/,"");print}' \
								${ERR} 2>&1`
			fi
	 		${NIMCLIENT} -o change -aforce=yes -aignore_lock=yes \
				-aerr_info="$( print ${err_txt} )"
		else
			# remove any "rc=" that might exist in the output
			${AWK} '{gsub(/rc=[0-9]+/,"");print}' ${ERR} 1>&2
		fi
	fi

	# In some cases, we show output from the failed cmd and don't
	# capture the err_info in ${ERR}.  Let's print a generic msg
	# about viewing a log. 
	if [[ -n "${lppchk_error}" ]]
	then
		${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
				${C_ERRMSG_MSG} "${LPPCHK_LOG}" "" "" ""

	elif  [[ "${NIM_SHOW_PROGRESS}" = "yes" ]] && [[ -n "${instp_err_log}" ]]
	then
		${C_ERRMSG} ${MSG_SEE_LOG_FILE} \
				${C_ERRMSG_MSG} "${instp_err_log}" "" "" ""
	fi
	instp_err_log=""

	# cd to neutral dir
	cd /tmp 2>/dev/null

	# If called from c_cust_lku, then we must
	# manually update the client state since
	# c_script isn't being used.
	if [[ "${CALLED_FROM_NIMCLIENT_LKU}" = "yes" ]]
	then
		${NIMCLIENT} -R failure
	fi

	# exit
	exit ${1}

} # end of error

#---------------------------- err_from_cmd      --------------------------------
#
# NAME: err_from_cmd
#
# FUNCTION:
#		displays error message from failed commands
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		ASSUMES error output from failed commad is in the ${ERR} file
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= name of command which failed
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function err_from_cmd {

	# display the error msg
	error ${ERR_CMD} "${1}"

} # end of err_from_cmd

#---------------------------- err_signal        --------------------------------
#
# NAME: err_signal
#
# FUNCTION:
#		error signal handler
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function err_signal {

	trap "" 1 2 11 15

	[[ -n "${undo_on_interrupt}" ]] && ${undo_on_interrupt}

	error ${ERR_SIGNAL} 1

} # end of err_signal

#---------------------------- mk_tmp_dir        --------------------------------
#
# NAME: mk_tmp_dir
#
# FUNCTION:
#		creates a temporary directory for temp files
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#
# OUTPUT:
#-------------------------------------------------------------------------------
function mk_tmp_dir {

	typeset -i retry_count=0
	typeset -i retry_max=11

	# set umask
	umask 022

	# Note: Process ID's may be re-cycled.  So include the string
	# _nim_dir in the name of the temporary directory.
	# Use the string _nim_ in file names.
	# Also, retry 10 time with a name like _nim_dir<n>_$$ before
	# giving up and re-using _nim_dir_$$.
	while (( $retry_count < $retry_max ))
	do
		if ${MKDIR} ${TMPDIR} 2>/tmp/_nim_$$.err
		then
			break
		else
			(( retry_count = retry_count + 1 ))
			if (( $retry_count < $retry_max - 1 ))
			then
				TMPDIR=/tmp/_nim_dir${retry_count}_$$
			else
				TMPDIR=/tmp/_nim_dir_$$
				${RM} -r ${TMPDIR}
			fi
		fi
	done
}

#---------------------------- nim_init          --------------------------------
#
# NAME: nim_init  
#
# FUNCTION:
#		initializes the NIM environment for a shell script
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function nim_init {

	typeset -i tmp_free=0
	typeset http_avail="no"

	# create a dir for tmp files
	# do this now, before anything else because other functions may be called
	#		which depend on this directory
	mk_tmp_dir

	# NIMINFO file must exist
	# in the network boot environment, /SPOT will always contain the niminfo 
	#		file which was tftp'd from the boot server, so look for this version 
	#		of the file first
	if [[ -s /SPOT/niminfo ]]
	then
		. /SPOT/niminfo
	elif [[ -s ${NIMINFO} ]]
	then
		# we're not currently executing in the network boot environment
		# use the version which is in the traditional place
		. ${NIMINFO}
	else
		print "unable to access the ${NIMINFO} file" 1>&2
		exit 1
	fi

	# must have at least 5 meg of free space in /tmp
	tmp_free="$( ${DF} /tmp | ${AWK} 'NR==2{print $3}' 2>/dev/null )"
	(( ${tmp_free} < ${REQUIRED_TMP_SPACE} )) && \
		error ${ERR_SPACE} /tmp ${REQUIRED_TMP_SPACE} ${tmp_free}


	# check if NFS reserved ports are required for NFS communications
	# set nfso option accordingly.
	if [[ "${NFS_RESERVED_PORT}" = "yes" ]]
	then
		/usr/sbin/nfso -o nfs_use_reserved_ports=1 >/dev/null
	elif [[ "${NFS_RESERVED_PORT}" = "no" ]]
	then
		/usr/sbin/nfso -o nfs_use_reserved_ports=0 >/dev/null
	fi

	# increase ulimit values (reliability enhancement for nim services)
	if [[ -z ${NIM_BOSINST_ENV} ]]
	then
		ulimit -f unlimited >/dev/null 2>&1
		ulimit -n 4000 >/dev/null 2>&1
	fi

	# Check /enable http download attempts
	if [[ "$INUCLIENTS" != yes ]]
	then
		http_avail=$( ${NIMCLIENT} -l -l master 2>/dev/null |${AWK} '/http_support/{print $3}')
	fi
	export HTTP_SUPPORT=$http_avail

	# set strict signature policy - if using medium
	# (unable to process terminal input)
	if [[ "medium" = "$(LANG=C ${CHSIGNPOLICY} -p 2>/dev/null | ${AWK} '(NR==2){print $1}')" ]]
	then
		export INUSIGNPOLICY=high
	fi

	# enable snapshot mksysb failover
	export CALLED_FROM_NIM=y
} # end of nim_init

#---------------------------- nim_mount         --------------------------------
#
# NAME: nim_mount 
#
# FUNCTION:
#		mounts the specified "object" over the specified local mount point; when
#			no local mount points are specified, this function will create one
#		"object"s may be on of the following:
#			1) local directory
#			2) remote directory (in the form of "host:dir")
#			3) local CDROM
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1				= object to mount
#			2				= local mount point (optional)
#		global:
#			access_pnt			= set to local access point
#			mounts				= list of mounts performed by nim_mount
#			disable_cdumount		= if cdrom is already mounted by cdromd, don't cdumount
#
# RETURNS: (int)
#		0					= success; local mount pnt returned via access_pnt
#
# OUTPUT:
#-------------------------------------------------------------------------------

MAX_MNT=8

function nim_mount {

	typeset object=${1}
	typeset -i i=0
	typeset mnt_params=""
	typeset access_pnt_inode=""
	typeset automount_flag=""
	typeset nfs4_access=""
	typeset nfs4_mount=""
	typeset nfs4_link=""
	typeset obj_is_iso=""

	# NOTE that access_pnt is a global, not a local variable
	access_pnt=${2:-""}

	[[ -z "${object}" ]] && return 0

	# determine whether or not we're dealing with an iso image
	if [[ -f "${object}" ]] && \
	   [[ "${object##*.}" = "iso" ]]; then
		obj_is_iso="yes"
	else
		obj_is_iso="no"
	fi

	# check for unnecessary mounts
	if [[ -z "${access_pnt}" ]] && \
		[[ ${object} != /dev/cd[0-9]* ]] && \
		[[ ${object} != /dev/usbms[0-9]* ]] && \
		[[ ${object} != ?*:?* ]] && \
		[[ ${obj_is_iso} = "no" ]]
	then
		# object is local directory and no specific mount point requested
		# therefore, no reason to mount it - return current path
		access_pnt=${object}
		return 0
	fi

	# if nfs4 mount, NIM master will start nfsrgyd 
	# and return mount parms
	if [[ ${object} = ?*:?* ]] 
	then
		if [[ $NIM_SERVER_TYPE != "linux" ]]; then
			nfs4_access=`${NIMCLIENT} -m $object`

		#
		# The following conditional is added for install from NIMoL
		# for NFSv4.  The client will not be able to execute
		# 'nimclient -m' so the following code segment will handle
		# the mount and build up the nfs4_access string.
		#
		elif [[ $NIM_SERVER_TYPE = "linux" ]] && [[ -n $NIM_NFS4_MOUNTS ]]; then

			# example: NIM_NFS4_MOUNTS=" b9rshmc:/:sys:/b9rshmc.sys "
			NIM_NFS4_HOST=`echo $NIM_NFS4_MOUNTS        | $CUT -d: -f1`
			NIM_NFS4_LOCATION=`echo $NIM_NFS4_MOUNTS    | $CUT -d: -f2`
			NIM_NFS4_SECURITY=`echo $NIM_NFS4_MOUNTS    | $CUT -d: -f3`
			NIM_NFS4_DESTINATION=`echo $NIM_NFS4_MOUNTS | $CUT -d: -f4`

			$MKDIR -p ${NFS4_MNTDIR}${NIM_NFS4_DESTINATION}

			${MOUNT} -vnfs -overs=4,sec=${NIM_NFS4_SECURITY} \
				 -ohard,intr ${NIM_NFS4_HOST}:${NIM_NFS4_LOCATION} ${NFS4_MNTDIR}${NIM_NFS4_DESTINATION}

			nfs4_location=`echo $object | $CUT -d: -f2`
			nfs4_access="${NFS4_MNTDIR}${NIM_NFS4_DESTINATION} ${nfs4_location}"
		fi

		if [[ -n "${nfs4_access}" ]]
		then
			nfs4_mount=`${ECHO} ${nfs4_access} | ${AWK} '{print $1}'`
			nfs4_link=`${ECHO} ${nfs4_access} | ${AWK} '{print $2}'`
		fi
	fi

	# Define mount point for nfs3
	if [[ -z ${nfs4_access} ]]
	then
		# need a local mount point?
		if [[ -z "${access_pnt}" ]]
		then
			# going to create a tmp directory in TMPDIR with a prefix of "mnt"
			while (( ${i} < ${MAX_MNT} ))
			do
				access_pnt=${TMPDIR}/mnt${i}
				[[ ! -d ${access_pnt} ]] && break
				let i=i+1
			done
			(( ${i} >= ${MAX_MNT} )) && error ${ERR_GEN_SEQNO} ${TMPDIR}/mnt
		fi

	# Define link for nfs4
	else
		# is there a specified link name?
		if [[ -z "${access_pnt}" ]]
		then
			# create a tmp link
			while (( ${i} < ${MAX_MNT} ))
			do
				# build link using nfs4 vars
				access_pnt="${nfs4_mount}.$$_${i}"
				[[ ! -h ${access_pnt} ]] && break
				let i=i+1
			done
			(( ${i} >= ${MAX_MNT} )) && error ${ERR_GEN_SEQNO} ${access_pnt}
		else
			# nfs4 access point will be defined as a symlink, so delete dir
			# NOTE: nim_mount should never be called with a non-empty mount point
			#       otherwise, data will be lost when handling nfs4 mounts
			${RM} -r "${access_pnt}" 2>/dev/null
		fi
	fi

	# need to create the local access point?
	if [[ ! -r ${access_pnt} ]]
	then

		# yes - doesn't already exist
		if [[ -z ${nfs4_access} ]]
		then
			${MKDIR} ${access_pnt} 2>${ERR} || err_from_cmd ${MKDIR}
			# get the inode of this dir - for adding to remove list.
			access_pnt_inode=`${LS} -i -d ${access_pnt} 2>/dev/null | ${AWK} '{print ":"$1}'`
		else
			${LN} -fs "${nfs4_mount}${nfs4_link}" ${access_pnt} 2>${ERR} || err_from_cmd ${LN}
			# get the inode of this link - for adding to remove list.
			access_pnt_inode=`${LS} -i -N ${access_pnt} 2>/dev/null | ${AWK} '{print ":"$1}'`
		fi

		# if access_pnt ends in "/tftpboot", then don't add it to the list of
		#		dirs to be removed
		# we do this in order to avoid removing the /tftpboot directory in the
		#		inst_root so that clients installed with "source=spot" will get
		#		this directory
		[[ ${access_pnt##*/} != tftpboot ]] && \
			tmp_dirs="${access_pnt}${access_pnt_inode} ${tmp_dirs}"
	fi

	# mount the "object" (either local CDROM, USB, remote dir, or local dir)
	case ${object} in

		/dev/usbms[0-9]*)
			  USBRFS=`${BOOTINFO} -f ${object}`
			  mnt_params=-rv${USBRFS}
			;;
			
		/dev/cd[0-9]*)	# CDROM
                        # check if the device is manage by the cdromd
                        ${CDCHECK} -aq ${object} 2>/dev/null 1>&2

			# If cdromd is running and we chroot to do a spot copy, cdromd will
			# not be detected in the chroot environment.  We use AUTOMOUNT_DISABLE_FLAG to 
			# disable all cd automount calls.
			# AUTOMOUNT_DISABLE_FLAG is set by c_instspot.c
			if [[ $? -eq 0 ]] && [[ $AUTOMOUNT_DISABLE_FLAG != "true" ]]
			then		# cdrom is managed by cdromd
				automount_flag="true"
				${CDCHECK} -mq ${object} 2>/dev/null 1>&2                #check if cdrom is mounted
				
				if [[ $? -eq 0 ]]
				then
					disable_cdumount="true"
					access_pnt=`${CDCHECK} -mq ${object} 2>/dev/null`

				else
					if ${CDMOUNT} -q ${object} 2>${ERR}              #mount the cdrom
					then
						access_pnt=`${CDCHECK} -mq ${object} 2>/dev/null` # get its mount point
					else
						warning_from_cmd ${CDMOUNT}
						err_from_cmd ${CDMOUNT}
					fi
				fi
			
			else
				mnt_params="-r -vcdrfs"
			fi
			;;

		?*:?*)			# remote dir
			mnt_params="-ohard,intr -vnfs"
			;;

		*)	# local dir or iso image file
			if [[ "${obj_is_iso}" = yes ]]; then
				${LOOPMOUNT} -i "${object}" -m "${access_pnt}" -o "-v cdrfs -o ro" 2> ${ERR} 1>&2
				[[ $? -ne 0 ]] && err_from_cmd ${LOOPMOUNT}
				automount_flag="true"
			fi
			;;
	esac

	# nfs4 ? complete : proceed
	if [[ -n ${nfs4_access} ]]
	then
		# define hard link
		# necessary for determining unmount
		# of nimclient mount_pnt
		link_dir="${NFS4_LINKDIR}/${nfs4_mount##*/}"
		link_file="${link_dir}/linkfile"
		${MKDIR} -p ${link_dir}
		${TOUCH} ${link_file}
		${LINK}  ${link_file} "${NFS4_LINKDIR}/${access_pnt##*/}"

		# create exit script for unmount
		[[ $? = 0 ]] && \
			print "\ncount=\`${LS} -e ${link_file} 2>/dev/null | \
			${AWK} '{print \$2}'\`" >> ${TMPDIR}/unmount_on_exit && \
			print "\n(( \$count == 1 )) && ${UNMOUNT} ${nfs4_mount} 2>/dev/null" \
			>> ${TMPDIR}/unmount_on_exit

	elif [[ $automount_flag != "true" ]]; then
	# cdromd is not running, run the mount command

		# if mount_opts is set, lets try them
		# if the mount fails, try removing the mount_opts
		if ${MOUNT} ${mnt_params} ${mount_opts} ${object} ${access_pnt} 2>${ERR}
		then
			:
		else
			warning_from_cmd ${MOUNT}
			${MOUNT} ${mnt_params} ${object} ${access_pnt} 2>${ERR} || \
				err_from_cmd ${MOUNT}
		fi
	fi

	# remember that we've got something mounted
	# NOTE that we're pushing this onto a stack - it is important that we do
	#		the unmounts in reverse order
	mounts="${object}:${access_pnt} ${mounts}"

} # end of nim_mount

#---------------------------- nim_unmount       --------------------------------
#
# NAME: nim_unmount
#
# FUNCTION:
#		unmounts anything which has been mounted by nim_mount
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= either the keyword "all" or local mount pnt
#		global:
#			mounts				= list of mounts performed by nim_mount
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#-------------------------------------------------------------------------------
function nim_unmount {

	typeset dir=${1:-all}
	typeset force=${2}
	typeset i=""
	typeset mnt_pnt=""
	typeset tmp=""

	# cd to neutral dir
	if cd /tmp 2>${ERR}
	then
		:
	else
		warning_from_cmd cd
		return 1
	fi

	# look for the specified <dir>
	for i in ${mounts}
	do
		# separate stanza
		mnt_pnt=${i##*:}

		# this the one we're looking for?
		if [[ ${dir} = ${mnt_pnt} ]] || [[ ${dir} = all ]]
		then

			# unmount it, but first perform a sync and an slibclean to make
			# sure that nothing in the mount is still thought to be busy.
			${SYNC}
			${SLIBCLEAN}
			# If unmounting libraries that we set up for a chroot
			# environment, reset the libpath to make sure that
			# the mount will succeed.
			if [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS1} ]] || 
			   [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS2} ]]
			then
				${UNSET_CHROOT_LIBPATH}
			fi

			# check if the device is manage by the cdromd
			object=${i%%:*}
			${CDCHECK} -aq ${object} 2>/dev/null 1>&2
	
			if [[ $? -eq 0 ]] && [[ $AUTOMOUNT_DISABLE_FLAG != "true" ]]
			then
				# cdrom is managed by cdromd
				${CDCHECK} -mq ${object} 2>/dev/null 1>&2	# check if cdrom is mounted
				if [[ $? -eq 0 ]] && [[ $disable_cdumount != "true" ]]
				then
					if ! ${CDUMOUNT} ${object} 1> /dev/null 2>${ERR}
					then
						warning_from_cmd ${CDUMOUNT}
						tmp="${i} ${tmp}"
					fi
				fi
			
			# nfs4 uses links, let's prevent a bogus unmount
			elif [[ -h ${mnt_pnt} ]]
			then
				if ! ${UNLINK} ${mnt_pnt}
				then
					warning_from_cmd ${UNMOUNT}
					tmp="${i} ${tmp}"
				fi
				# since multiple access points may link
				# to an nfs4 server's root mount we need
				# to check the link count prior to unmount
				${RM} "${NFS4_LINKDIR}/${mnt_pnt##*/}" 2>/dev/null
			
			# assuming that files are iso images
			elif [[ -f "${object}" ]]; then
				if ! ${LOOPUMOUNT} -i "${object}" -m "${mnt_pnt}" 2> ${ERR} 1>&2; then
					warning_from_cmd ${LOOPUMOUNT}
					tmp="${i} ${tmp}"
				fi

			# process mounted dir - force option
			elif [[ -n ${force} ]]
			then
				# We were told to force unmount this directory.
				# Try to unmount without the force first.
				${UNMOUNT} ${mnt_pnt} > /dev/null 2>&1
				if [[ $? -ne 0 ]]
				then
					if ! ${UNMOUNT} -f ${mnt_pnt} 1> /dev/null 2>${ERR}
					then
						warning_from_cmd ${UNMOUNT}
						tmp="${i} ${tmp}"
					fi
				fi
			
			# process mounted dir - normal
			else
				if ! ${UNMOUNT} ${mnt_pnt} 2>${ERR}
				then
					warning_from_cmd ${UNMOUNT}
					tmp="${i} ${tmp}"
				fi
			fi
		
		else
			# not unmounting this dir - add it back to the list
			tmp="${i} ${tmp}"
		fi
	done

	# new list reflects the mounts that are still active
	mounts=${tmp}

} # end of nim_unmount

#---------------------------- parse_attr_ass    --------------------------------
#
# NAME: parse_attr_ass
#
# FUNCTION:
#		validates command line attribute assignements
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function parse_attr_ass {

	typeset i=""

	# is it in the correct format (<var>=<value>)?
	if [[ "${1}" != +(?)=+(?) ]]
	then
		error ${ERR_VALUE} "${1}" "valid attribute assignment"
	fi

	# separate variable from value
	# NOTE that we must be careful here as the "value" may have "=" chars in it
	variable=${1%%=*}
	value=${1#*=}

	# make sure its in our list of acceptable attributes
	for i in ${REQUIRED_ATTRS}
	do
		if [[ ${variable} = ${i} ]]
		then
			return 0
		fi
	done
	for i in ${OPTIONAL_ATTRS}
	do
		if [[ ${variable} = ${i} ]]
		then
			return 0
		fi
	done
	
	# not an acceptable attr
	error ${ERR_CONTEXT} "${variable}"

} # end of parse_attr_ass

#---------------------------- ck_attrs          --------------------------------
#
# NAME: ck_attrs  
#
# FUNCTION:
#		checks for missing attributes
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_attrs {

	typeset i=""
	typeset curval=""
	typeset attr_counted=""
	typeset -i attr_count=0

	for i in ${REQUIRED_ATTRS}
	do
		eval curval=\$\{${i}\}
		if [[ -z "${curval}" ]]
		then
			error ${ERR_MISSING_ATTR} ${i}
		fi
	done

	for i in ${EXCLUSIVE_ATTRS}
	do
		eval curval=\$\{${i}\}
		if [[ -n "${curval}" ]] && [[ $attr_count != 0 ]]
		then
			error ${ERR_ATTR_CONFLICT} ${i} ${attr_counted}
		fi
		if [[ -n "${curval}" ]]
		then
			attr_counted=${i}
			attr_count=1
		fi
	done
	if [[ -n "${EXCLUSIVE_ATTRS}" ]] && [[ $attr_count != 1 ]]
	then
		error ${ERR_MISSING_ATTR} ""
	fi

} # end of ck_attrs

#---------------------------- cmd_what          --------------------------------
#
# NAME: cmd_what
#
# FUNCTION:
#		displays the list of required and optional attributes which this method
#			will accept
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#			REQUIRED_ATTRS
#			OPTIONAL_ATTRS
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#		writes info to stdout
#-------------------------------------------------------------------------------
function cmd_what {

	typeset i=""

	if [[ -n "${REQUIRED_ATTRS}" ]]
	then
		print "\nrequired attrs are:"
		for i in ${REQUIRED_ATTRS}
		do
			print "\t${i}"
		done
	else
		print "\nno required attrs"
	fi

	if [[ -n "${OPTIONAL_ATTRS}" ]]
	then
		print "\noptional attrs are:"
		for i in ${OPTIONAL_ATTRS}
		do
			print "\t${i}"
		done
	else
		print "\nno optional attrs"
	fi

	print

} # end of cmd_what

#---------------------------- ck_inst_root_dirs --------------------------------
#
# NAME: ck_inst_root_dirs 
#
# FUNCTION:
#		ensures that the SPOT's inst_root has a directory entry for the filesystem
#			where the SPOT resides
#		this is required by installp because, once we've chroot'd into the
#			inst_root, installp is going to stat "/", which will be the SPOT's
#			inst_root at that point - stat will fail if there's no entry for
#			where we've chroot'd into
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#			location				= SPOT pathname
#			new_root				= pathname of new root (where we'll chroot to)
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_inst_root_dirs {

	typeset fs=""

	# what is the mount point for the filesystem that the SPOT resides in?
	fs=$(${DF} ${location} 2>/dev/null | ${AWK} 'NR==2{print $7}' 2>/dev/null)
	[[ -z "${fs}" ]] && error ${ERR_FS_INFO} ${location}

	# does the directory exist in the new root?
	if [[ ! -d "${new_root}${fs}" ]]
	then

		# create it now
		${MKDIR} ${new_root}${fs} 2>${ERR} || err_from_cmd ${MKDIR}

	fi

} # end of ck_inst_root_dirs

#---------------------------- setup_chroot_env  --------------------------------
#
# NAME: setup_chroot_env
#
# FUNCTION:
#		mounts the appropriate dirs in order to setup a chroot environment
#			within a SPOT
#		this kind of environment is required because we use installp to install
#			software into a SPOT, but it doesn't understand any pathnames other
#			than "/" and "/usr"
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= optional; when present, it is the pathname of the
#											inst_root directory to use
#		global:
#			location				= SPOT pathname
#			new_root				= pathname of new root (where we'll chroot to)
#			chroot				= command to execute in order to chroot
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function setup_chroot_env {

	typeset root_sync=""
	typeset inr=""
	typeset inr_path=""
	typeset inr_ln=""
	typeset spot_fs=""
	typeset spot_fs_path=""
	typeset first_dir=""
	typeset dir_created=""
	typeset first_dir_inode=""

	[[ -s /usr/ios/cli/ios.level ]] && return

	# initialize pathnames for the inst_root directory
	# this directory will become the root ("/") directory after we chroot
	if [[ -n "${1}" ]]
	then

		root_sync=TRUE
		inr=${1}
		inr_path=${inr}${inr%/*}
		inr_ln=${inr}${inr}

	else

		inr="${location}/${INST_ROOT}"
		inr_path=${inr}/lpp/bos
		inr_ln=${inr_path}/inst_root

	fi

	# initialize pathnames for the SPOT's filesystem which will be created in
	#		the inst_root
	spot_fs=${location}
	[[ -n "${spot_fs%/*}" ]] && \
		spot_fs_path=${inr}${spot_fs%/*} || \
		spot_fs_path=""

	# make sure SPOT exists
	[[ ! -d ${location} ]] && error ${ERR_DIR_DNE} spot ${location}
	[[ ! -d ${location}/${INST_ROOT} ]] && \
		error ${ERR_DIR_DNE} inst_root "${location}/${INST_ROOT}"

	# we use the installp command to install optional software
	# it only understands the absolute pathnames of / & /usr, so we might have
	#		to setup a choot environment to support the use of installp

	# is this a non-/usr SPOT or are we going to root-sync a client?
	if [[ ${location} != /usr ]] || [[ -n "${root_sync}" ]]
	then
	
		# not a /usr SPOT (or a root-sync), so we've got some things to do
		# we've got to construct an environment which we can chroot into in before
		#		calling installp because installp only knows how to install into
		#		the /usr filesystem
		new_root=${inr}

		# make sure no previous mounts have been left dangling
		${UNMOUNT} ${new_root}/usr >/dev/null 2>&1
		${UNMOUNT} ${new_root}/tmp >/dev/null 2>&1
		${UNMOUNT} ${new_root}/tftpboot >/dev/null 2>&1
		${UNMOUNT} ${new_root}/images >/dev/null 2>&1
		${UNMOUNT} ${new_root}/opt >/dev/null 2>&1
		${UNMOUNT} ${new_root}/dev >/dev/null 2>&1
		${UNMOUNT} ${new_root}${NIM_CHROOT_LIBS1} >/dev/null 2>&1
		${UNMOUNT} ${new_root}${NIM_CHROOT_LIBS2} >/dev/null 2>&1

		# last chance to unmount - check all mounts under inst_root
		for ir_mount in `${LS} ${new_root}`
		do
			${UNMOUNT} ${new_root}/${ir_mount} >/dev/null 2>&1
		done

		# create subdir in the root which corresponds to the filesystem
		#		where the root resides
		if [[ ! -d ${inr_path} ]]
		then

			first_dir=""
			${C_MKDIR} -a location=${inr_path} >${TMPDIR}/first.dir 2>${ERR} || \
				err_from_cmd ${C_MKDIR}
			. ${TMPDIR}/first.dir

			# get the inode of this directory.  This way when we attempt
			# to remove it later we know we are removing the same directory.
			first_dir_inode=`${LS} -i -d ${first_dir} 2>/dev/null | ${AWK} '{print ":"$1}'`

			tmp_dirs="${first_dir}${first_dir_inode} ${tmp_dirs}"

		fi
		if [[ ${inr_ln} != / ]]
		then

			# make sure no previous links have been left around
			${RM} -r ${inr_ln} >/dev/null 2>&1

			# create sym link (to fake out the filesystem)
			${LN} -s / ${inr_ln} 2>${ERR} || err_from_cmd ${LN}
			tmp_files="${inr_ln} ${tmp_files}"

		fi


		# create subdir in the inst_root which corresponds to the filesystem
		#		where the SPOT resides
		if [[ -n "${spot_fs_path}" ]] && [[ ! -d ${spot_fs_path} ]]
		then

			first_dir=""
			${C_MKDIR} -a location=${spot_fs_path} >${TMPDIR}/first.dir \
				2>${ERR} || err_from_cmd ${C_MKDIR}
			. ${TMPDIR}/first.dir

			# get the inode of this directory.  This way when we attempt
			# to remove it later we know we are removing the same directory.
			first_dir_inode=`${LS} -i -d ${first_dir} 2>/dev/null | ${AWK} '{print ":"$1}'`

			tmp_dirs="${first_dir}${first_dir_inode} ${tmp_dirs}"

		fi
		if [[ ${spot_fs} != /usr ]]
		then

			# make sure no previous links have been left around
			${RM} -r ${inr}${spot_fs} >/dev/null 2>&1

			# create sym links (to fake out the filesystem)
			${LN} -s / ${inr}${spot_fs} 2>${ERR} || err_from_cmd ${LN}
			tmp_files="${inr}${spot_fs} ${tmp_files}"

		fi

		# mount the SPOT over the new_root /usr directory
		nim_mount ${location} ${new_root}/usr

		# mount the server's /tmp over the new_root /tmp directory
		nim_mount /tmp ${new_root}/tmp

		# mount the server's /dev over the new_root /dev directory
		nim_mount /dev ${new_root}/dev

		# mount /opt over new_root /opt when root_syncing /usr SPOTs
		if [[ ${spot_fs} = /usr ]] && [[ -d /opt ]]; then
			nim_mount /opt ${new_root}/opt
		fi

		if [[ -z "${root_sync}" ]]
		then

			# mount the server's /tftpboot over the new_root /tftpboot directory
			nim_mount /tftpboot ${new_root}/tftpboot

		fi

		# initialize the chroot syntax
		chroot="${CHROOT} ${new_root}"

		# For a non-/usr SPOT, always make sure the server's libraries 
		# are available to the chroot'd environment since we'll be 
		# running the server's kernel when processing the SPOT.
		# Create the mount point for SPOTs that were defined prior
		# to 4.2.0
		if [[ ${location} != /usr ]]
		then
			[[ ! -d ${new_root}${NIM_CHROOT_LIBS1} ]] && \
				${MKDIR} -p ${new_root}${NIM_CHROOT_LIBS1}
			nim_mount /usr/ccs/lib ${new_root}${NIM_CHROOT_LIBS1}

			[[ ! -d ${new_root}${NIM_CHROOT_LIBS2} ]] && \
				${MKDIR} -p ${new_root}${NIM_CHROOT_LIBS2}
			nim_mount /usr/lib ${new_root}${NIM_CHROOT_LIBS2}
		fi

	else
	
		# /usr SPOT
		new_root=""
		chroot=""

	fi

} # end of setup_chroot_env


#---------------------------- ck_rel_level       -------------------------------
#
# NAME: ck_rel_level 
#
# FUNCTION:
#		examines the AIX version/release level of the specified LPP_NAME file
#		returns 0 if the levels are acceptable to NIM; errors out otherwise
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function ck_rel_level {

	typeset lpp_name_file=${1}
	typeset -i ok_version=${2:-${DEFAULT_REQUIRED_VERSION}}
	typeset -i ok_release=${3:-${DEFAULT_REQUIRED_RELEASE}}

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

	# parse out the version, release, mod & fix
	${AWK} '	/^. . . bos {$/ {found=1;next};\
				/^bos.rte .*/ {	if (found)\
										{	split($2,info,".");\
											print "version=" info[1];\
											print "release=" info[2];\
											print "mod=" info[3];\
											print "fix=" info[4];\
										}\
									}' \
			${lpp_name_file} >${TMPDIR}/lpp_info 2>${ERR} || err_from_cmd ${AWK}

	# include that info in the current environment
	[[ -s ${TMPDIR}/lpp_info ]] && . ${TMPDIR}/lpp_info

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

	if [[ -n "${mk_usr_spot}" ]]
	then
		# Creating a /usr SPOT so we need to make sure level of bos.rte 
		# on media matches (exactly) that installed in /usr

		# Get level of bos.rte that's installed...
		lslppbos=`${LSLPP} -lcIqOu bos.rte 2>${ERR}` || \
							err_from_cmd ${LSLPP}
		vrmf=`echo ${lslppbos} | ${CUT} -d':' -f3`
		OIFS="$IFS"
		IFS="."
		set -- ${vrmf}
		instver=$1;instrel=$2;instmod=$3;instfix=$4
		IFS="$OIFS"

		if ((	${version} != ${instver} || \
			${release} != ${instrel} || \
			${mod} != ${instmod}     || \
			${fix} != ${instfix} ))
		then
			# get rid of ugly leading zeros from media vrmf
			let version=${version}
			let release=${release}
			let mod=${mod}
			let fix=${fix}

			error ${ERR_USR_SPOT_BOS_MISMATCH} \
				"${instver}.${instrel}.${instmod}.${instfix}" \
				"${version}.${release}.${mod}.${fix}"


		fi
	fi

} # end of ck_rel_level

#---------------------------- ck_spot_options        ---------------------------
#
# NAME: ck_spot_options
#
# FUNCTION:
#		determines whether the specified options are installed into the specified
#			SPOT
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= spot pathname
#			2						= options to check on
#		global:
#			st_applied			= value of ST_APPLIED from /usr/include/swvpd.h file
#			st_committed		= value of ST_COMITTED from /usr/include/swvpd.h file
#
# RETURNS: (int)
#		0							= success
#		1							= something missing
#
# OUTPUT:
#		writes missing options as attr assignments to stdout
#-------------------------------------------------------------------------------
function ck_spot_options {

	# make sure st_applied and st_comitted attrs have been supplied
	[[ -z "${st_applied}" ]] && error $ERR_MISSING_ATTR st_applied
	[[ -z "${st_committed}" ]] && error $ERR_MISSING_ATTR st_committed

	typeset spot=${1}
	typeset optlist=${2}

	typeset rc=0
	typeset i=""
	typeset state=""
	typeset database=""

	# get info out of the /usr product database
	if ODMDIR=${spot}/lib/objrepos ${ODMGET} product \
			>${TMPDIR}/product.usr 2>${ERR}
	then
		:
	else
		warning_from_cmd "ODMDIR=${spot}/lib/objrepos ${ODMGET} product"
		return 1
	fi

	# get info out of the /usr/share product database
	if ODMDIR=${spot}/share/lib/objrepos ${ODMGET} product \
			>${TMPDIR}/product.share 2>${ERR}
	then
		:
	else
		warning_from_cmd "ODMDIR=${spot}/share/lib/objrepos ${ODMGET} product"
		return 1
	fi

	# for each option required by NIM for a valid SPOT...
	for i in ${optlist}
	do

		# *.all and *.any from the list should never exactly match what
		# is installed into a spot, so don't bother to check those

		[[ $i = *.any ]] && continue
		[[ $i = *.all ]] && continue
		
		state=""

		# which database: usr or share?
		[[ ${i} = ?*.data ]] && \
			database=${TMPDIR}/product.share || \
			database=${TMPDIR}/product.usr

		# is the option installed in the SPOT currently?
		state=$(${AWK} -v option=${i} '\
						$1=="product:"{in_stanza=0;};\
						$1=="lpp_name" || $1=="name" {\
							field = "\"" option "\"";\
							if( ($3==field) || (index($3,option) > 0) )\
								in_stanza=1;\
							next};\
					  $1=="state" && in_stanza {print $3; exit}\
							' ${database} 2>/dev/null)

		# is the state acceptable?
		if [[ "${state}" != ${st_applied} ]] && 
			[[ "${state}" != ${st_committed} ]]
		then

			# either totally missing the option or its in a bad state
			print "missing=${i}"

			rc=1
		fi

	done

	return ${rc}

} # end of ck_spot_options

#---------------------------- protected_dir     --------------------------------
#
# NAME: protected_dir
#
# FUNCTION:
#		returns SUCCESS (0) is the specified directory is protected from removal
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= directory to be removed
#		global:
#
# RETURNS: (int)
#		0							= directory is protected and should NOT be removed
#		1							= ok to remove dir
#
# OUTPUT:
#-------------------------------------------------------------------------------
function protected_dir {

	typeset dir=${1}
	typeset i=""
	typeset dir_name=""
	typeset dir_inode=""

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

	dir_name=${dir%:*}
	dir_inode=${dir#*:}
	if [[ -n ${dir_inode} ]] && 
           [[ ${dir_inode} != ${dir_name} ]] &&
	   [[ ${dir_inode} != `${LS} -i -d ${dir_name} | ${AWK} ' {print $1} '` ]]
	then
		return 0
	fi

	for i in ${PROTECTED_DIRS}
	do

		[[ ${dir_name} = ${i} ]] && return 0

	done

	# <dir> is not protected from removal
	return 1

} # end of protected_dir

#---------------------------- prep_bundle      --------------------------------
#
# NAME: prep_bundle    
#
# FUNCTION:
#		prepares environment to use an installp bundle file
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#			installp_bundle	= pathname of bundle file
#			bundle_access		= local access point for the bundle file
#
# RETURNS: (int)
#		0							= success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function prep_bundle {

	[[ -z "${installp_bundle}" ]] && return 0

	bundle_access=${TMPDIR}/bundle
	rc=1

	# local or remote file?
	if [[ ${installp_bundle} = ?*:/* ]]
	then

		# NOTE: As part of the http availability feature -
		#       the initial call will include a check for
		#       web download service.. but not as part of
		#       NIM_BOSINST_ENV condition.
		if [[ -z ${NIM_BOSINST_ENV} ]]
		then
			# Attempt to locate the file
			# using the nimtthp servicing option
			# Preference for ssl ..
			download_srvr=`echo ${installp_bundle} | ${SED} 's/\:.*$//'`
			download_file=`echo ${installp_bundle} | ${SED} 's/.*://'`
			download_loc=`echo ${download_file} | ${SED} 's./[^/]*$..'`
			${MKDIR} -p ${TMPDIR}/$download_loc
			${NIMHTTP} -i $download_srvr -f $download_file -o dest=${TMPDIR} -s >/dev/null 2>&1 ||
			${NIMHTTP} -i $download_srvr -f $download_file -o dest=${TMPDIR} >/dev/null 2>&1
			rc=$?

			if [[ $rc -eq 0 ]]; then
				${MV} ${TMPDIR}/$download_file ${bundle_access} >/dev/null 2>&1
				rc=$?
			fi
			# end of HTTP
		fi

		if [[ $rc -ne 0 ]]
		then
			# NFS Method
			# remote - setup local access
			nim_mount ${installp_bundle}

			# copy the bundle into /tmp so installp will have access to it
			${CP} ${access_pnt} ${bundle_access} 2>${ERR} || \
				err_from_cmd "${CP} ${access_pnt} ${bundle_access}"

			# unmount
			nim_unmount ${access_pnt}
			# end of NFS
		fi

	else

		# already local - just copy it
		${CP} ${installp_bundle} ${bundle_access} 2>${ERR} || \
			err_from_cmd "${CP} ${installp_bundle} ${bundle_access}"

	fi

} # end of prep_bundle

#---------------------------- init_bootlist_attrs ------------------------------
#
# NAME: init_bootlist_attrs
#
# FUNCTION:
#		formats the global variable "boolist_attrs" based on the settings of the
#			parameters which are passed in
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		the formatting of this information is VERY specific and the man page for
#			the bootlist command should be consulted BEFORE changing this function
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= client IP address
#			2						= BOOTP server IP address
#			3						= gateway IP address
#			4 						= boot filename
#		global:
#			bootlist_attrs		= boot device list info
#
# RETURNS: (int)
#		0							= bootlist_attrs set
#
# OUTPUT:
#-------------------------------------------------------------------------------
function init_bootlist_attrs {

	typeset client=${1}
	typeset bserver=${2}
	typeset gateway=${3:-$bserver}
	typeset filename=${4}

	# default is no specific bootlist info
	bootlist_attrs=""

	# the syntax for the bootlist command dictates that we can only combine
	#		certain elements of the boot_info
	# refer to the bootlist man page for futher details
	if [[ -n "${gateway}" ]] && \
		[[ -n "${client}" ]] && \
		[[ -n "${bserver}" ]]
	then

		# we can specify the gateway info
		bootlist_attrs="gateway=${gateway} client=${client} bserver=${bserver}"

	elif	[[ -n "${bserver}" ]]
	then

		# we may pass bserver alone
		bootlist_attrs="bserver=${bserver}"

	fi

	if [[ -n $filename ]]
	then
		bootlist_attrs="$bootlist_attrs filename=$filename"
	fi

} # end of init_bootlist_attrs

#---------------------------- ck_installp_flags --------------------------------
#
# NAME: ck_installp_flags
#
# FUNCTION:
#		makes sure that there is a "-" in front of all installp_flags
#		any missing "-" are added
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= the installp_flags to check
#		global:
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#		writes the installp_flags which should be used to stdout
#-------------------------------------------------------------------------------
function ck_installp_flags {

	typeset flags=${1:-${DEFAULT_INSTALLP_FLAGS}}
	typeset new_flags=""

	# make sure "-" is in front of all installp_flags
	new_flags=$( echo ${flags} | ${AWK} '{	for(i=1;i<=NF;i++) \
														{	if (! match($i,/^-.+/) ) \
																printf( "-" ); \
															print $i \
														} }' 2>/dev/null )

	echo ${new_flags:-${flags}}

} # end of ck_installp_flags

#---------------------------- ck_gencopy_flags --------------------------------
#
# NAME: ck_gencopy_flags
#
# FUNCTION:
#		makes sure that there is a "-" in front of all gencopy_flags
#		any missing "-"'s are added.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#			1						= the gencopy_flags to check
#		global:
#
# RETURNS: (int)
#		0							= success
#		1							= failure
#
# OUTPUT:
#		writes the gencopy_flags which should be used to stdout
#-------------------------------------------------------------------------------
function ck_gencopy_flags {

	typeset flags=${1:-${DEFAULT_GENCOPY_FLAGS}}
	typeset new_flags=""

	# make sure "-" is in front of all gencopy_flags
	new_flags=$( echo ${flags} | ${AWK} '{	for(i=1;i<=NF;i++) \
														{	if (! match($i,/^-.+/) ) \
																printf( "-" ); \
															print $i \
														} }' 2>/dev/null )

	echo ${new_flags:-${flags}}

} # end of ck_gencopy_flags

#---------------------------- prep_updt_all_lst ----------------------------- 
#
# NAME: prep_updt_all_lst
#
# FUNCTION:
#		generates a list of fileset updates on the media which match
#		installed filesets on the target (SPOT or client)
#
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#               calls error on failure
#
#               When the target is either a SPOT that is at a level greater
#               than or equal to 4.3.0 or any client, this function will use 
#               the "sm_inst" command to generate the list of filesets 
#               needing updateing.
#               If the target SPOT is less than 4.3.0 then the following 
#               occurs:
#		uses lslpp to generate list of installed filesets
#		uses "installp -L" to generate media list
#		uses awk to match the two lists -- matches take v.r.m.f of
#			installed filesets into account
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#               parameters:
#			target_type	= type of target "spot" or "client"
#			lpp_source	= installation media 
#                       prep_updts      = flag variable
#               global:
#			fileset_list	= file containing list generated by this routine
#
# RETURNS: (int)
#               0                        = success if no errors, else errors off
#
# OUTPUT:
#		fileset_list contains list of updates to install
#-------------------------------------------------------------------------------
function prep_updt_all_lst {

	target_type=${1}
        lpp_source=${2}
        prep_updts=${3}
	lslpp_cmd=${LSLPP}
	instp_cmd=${INSTALLP}
	fileset_list=${TMPDIR}/updt_all.lst

	#initialize some temp files
	> ${TMPDIR}/up_all.instld
	> ${TMPDIR}/up_all.media

	#initialize global "out-list"
	> ${fileset_list}

        if [[ ${target_type} = "client" ]]
        then
           # target is a client,  so use "sm_inst -L"

           ${SM_INST} installp_cmd -L ${lpp_source} -f _update_all \
                                               1>${fileset_list} 2>${ERR}

	   #outta here if nothing to work with or errors
           [ ! -s ${fileset_list} ] ||  [ -s "${ERR}" ]  && \
                                               err_from_cmd ${SM_INST}
        else 
           # target is a SPOT

	   # augment lslpp cmd 

	   lslpp_cmd="${chroot} ${LSLPP}"

           # Older versions of the "sm_inst" shell script will not have
           # the support for the "-L" option, therefore the level of the
           # bos.sysmgt.smit fileset in the SPOT is checked.
           # If ver.rel >= 4.3 then use "sm_inst -L"

           # Get the version and release of the bos.sysmgt.smit fileset in
           # the SPOT
           vrmf=$( ${lslpp_cmd} -l bos.sysmgt.smit |  ${AWK} '/smit/ {print $2}')
           integer ver=${vrmf%%.*}
           strrel=${vrmf#*.}
           integer rel=${strrel%%.*}

           if  (( (ver > 4) || (ver == 4 && (rel > 2))  ))
           then
              # target is a SPOT that is at a level >= 4.3. Use "sm_inst -L ".

	      sm_inst_cmd="${chroot} ${SM_INST}"
              ${sm_inst_cmd} installp_cmd -L ${lpp_source} -f _update_all \
                                               1>${fileset_list} 2>${ERR}
              if [[ ${prep_updts} = "yes" ]]
              then
			:
              else
	      	#outta here if nothing to work with or errors
              	[ ! -s ${fileset_list} ] && exit 0
				[ -s "${ERR}" ]  && err_from_cmd ${SM_INST}
              fi
           else
              # Use old method 

	      #list the installed filesets capturing name and level
	      ${lslpp_cmd} -qLc | \
		${AWK} 'BEGIN { FS=":" } {printf ("%s %s\n", $2, $3)}' | \
        	${SORT} -A -u 1> ${TMPDIR}/up_all.instld 2>${ERR}

	      #outta here if nothing to work with or errors
              [ ! -s ${TMPDIR}/up_all.instld ] ||  [ -s "${ERR}" ]  && \
                                                        err_from_cmd ${LSLPP}

	      #augment installp cmd depending upon caller
	      instp_cmd="${chroot} ${INSTALLP}"

	      #list the contents of the installation media
	      ${instp_cmd} -qL ${lpp_source} 1>${TMPDIR}/up_all.media 2>${ERR}

	      #outta here if nothing to work with or errors
              [ ! -s ${TMPDIR}/up_all.media ] ||  [ -s "${ERR}" ]  && \
                                                        err_from_cmd ${INSTALLP}

	      #loop on the list of installed filesets
   	      #  -- grep the media listing for matches on that name.
	      #  -- awk the resultant list looking for filesets with 
	      #     greater level than that which is installed.  print them. 
	      #     accumulate output in ${fileset_list} file.
              while read fs_name level
              do
                   ${FGREP} ${fs_name} ${TMPDIR}/up_all.media \
                                        > ${TMPDIR}/up_all.grep 2>&1
                   [ $? -eq 0 ] && \
                           ${AWK} -v name=${fs_name} -v lev=${level} 'BEGIN   {
                           FS=":"
		   	   split(lev, inst_lev, ".")
                           }
                           {
				   # check for exact match for name, since the
				   # grep may have pulled in supersets of the
				   # name being grepped for.
                                   if ($2 == name)
				   {
				      split($3, updt_lev, ".") 
				      v3ptfid=$4

                                      # Compare the VRMF of the installed 
                                      # with the update of each fileset

                                      for  ( i = 1; i < 5 ; i++ )
                                      {
                                          if ( updt_lev[i] > inst_lev[i] )
                                              # Yes this is a newer update
                                              if (v3ptfid != "" )
                                                  printf ( "%s %s.%s\n", $2, $3, v3ptfid)
                                              else
                                                 printf ( "%s %s\n", $2, $3)
                                           else
                                              if ( updt_lev[i] == inst_lev[i] ) {
                                                 # Still need to compare...
                                                 if (( i == 4 ) && (v3ptfid != "" ) )
                                                     printf ( "%s %s.%s\n", $2, $3, v3ptfid)
                                              }
                                              else
                                                 # Not a newer update.
                                                 break
                                        }
				}
                           }' ${TMPDIR}/up_all.grep >> ${fileset_list}

              done < ${TMPDIR}/up_all.instld

              ${RM} ${TMPDIR}/up_all.instld > /dev/null 2>&1
              ${RM} ${TMPDIR}/up_all.media > /dev/null 2>&1
           fi
        fi

} # end of prep_updt_all_lst

#---------------------------- prep_instfix_lst  ---------------------------
#
# NAME: prep_instfix_lst
#
# FUNCTION:
#		generates a list of fileset updates from a list (string)
#		of keywords or file containing keywords.
#
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#               calls error on failure.
#		calls instfix command to generate list of filesets.
#		if non-zero returned from instfix, errors off
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#               parameters:
#			target_type	= type of target ("spot" or "client")
#			fix_type	= type of fixes specified ("fixes" list or "bun"
#			fixes		= list of fixes or bundle name
#               global:
#			fileset_list	= file containing list generated by this routine
#
# RETURNS: (int)
#               0                       = success if ok, else errors off.
#
# OUTPUT:
#		fileset_list contains list of filesets matching fix keys input
#-------------------------------------------------------------------------------
function prep_instfix_lst {
	
	target_type=${1}
	fix_type=${2}
	fixes=${3}
	lpp_src=${4}
	instfix_cmd=${INSTFIX}
	fileset_list=${TMPDIR}/fsets.frm.fixes.lst
	fileset_errs=${TMPDIR}/fsets.frm.fixes.err

	#augment instfix  cmd depending upon caller
	[ ${target_type} = "spot" ] && instfix_cmd="${chroot} ${INSTFIX}"

	#initialize global "out-list"
	> ${fileset_list}

        #generate the list from instfix
        if [ ${fix_type} = "fixes" ]
        then   
		# use string of fix keywords
                ${instfix_cmd} -p -k "${fixes}" ${lpp_src} >${fileset_list} 2>${fileset_errs}
        else
		# use fix bundle
                ${instfix_cmd} -p -f ${fixes} ${lpp_src} >${fileset_list} 2>${fileset_errs}
        fi

	#NOTE:  if instfix encounters errors with *any* of the fixes in
	#	a list, it returns non-zero.
	#	So, we need to re-capture the errors and proceed accordingly.
        if [ -s ${fileset_errs} ]
	then
		${CAT} ${fileset_errs} > ${ERR} 2>&1
		err_from_cmd ${INSTFIX}
	fi

} # end of prep_instfix_lst

#---------------------------- check_access
#
# NAME: check_access
#
# FUNCTION:
# 	Make sure that client allows the server nimsh (or .rhosts) access
#
# RETURNS: (int)
#     0              = success
#     1              = no access
#
#-------------------------------------------------------------------------------
function check_access {

	client=$1

	${C_RSH} ${client} "\"${ECHO} >/dev/null\"" 2>/dev/null
	if [ $? -ne 0 ]
	then
		# which service was used for remote access?
		[[ -z ${nim_name} ]] && connect="shell" ||
		connect=`$LSNIM -a connect ${nim_name} 2>/dev/null | $AWK -F"=" '(NR==2) {print $2}'`
		if [[ ${connect} = *shell* ]]; then
			thishost=`/usr/bin/hostname`
			error ${ERR_NO_RHOST} ${client} ${thishost}
		else
			error ${ERR_NIMSH_CANNOT_CONNECT} ${client}
		fi

	fi
	return 0
}


#---------------------------- check_push_ok
#
# NAME: check_push_ok
#
# FUNCTION:
# 	Make sure that target allows the master to perform push operations
# 	'Target' may not actually be a NIM client.
#
# RETURNS: (int)
#     0              = success
#     1              = no access
#
#-------------------------------------------------------------------------------
function check_push_ok {

	client=$1

	check_access ${client}
	nimpush_ok=`${C_RSH} ${client} "\"/usr/bin/test -f /etc/nimstop && print 0 || print 1\""`
	[ $nimpush_ok -eq 0 ] && {\
		error ${ERR_NO_PUSH} ${client} ${client}
	}

	return 0
}

#---------------------------- check_cpush_ok
#
# NAME: check_cpush_ok
#
# FUNCTION:
# 	Make sure that target allows the master to perform push operations
#       AND that the target appears to have the NIM client fileset installed
#	  	
#
# RETURNS: (int)
#     0              = success
#     1              = no access
#
#-------------------------------------------------------------------------------
function check_cpush_ok {

	client=$1

	check_access ${client}
	nimpush_ok=`${C_RSH} ${client} "\"/usr/bin/test -f /usr/lpp/bos.sysmgt/nim/methods/c_nimpush && print 0 || print 1\""`
	[ $nimpush_ok -ne 0 ] && {\
		error ${ERR_NO_PUSH} ${client} ${client}
	}

	return 0
}


#---------------------------- get_fileset_level
#
# NAME: get_fileset_level
#
# FUNCTION:
#     Gets the level of the fileset indicated by $1
#
#
# RETURNS: (int)
#     0              = success
#     1              = no access
#
#-------------------------------------------------------------------------------
function get_fileset_level {

  lslpp_fileset=`${LSLPP} -lqcOu ${1}` || \
    err_from_cmd "${LSLPP} -lqcOu ${1}"

  vrmf=`echo $lslpp_fileset | ${CUT} -d":" -f3`
  version=`echo ${vrmf} | ${CUT} -d"." -f1`
  release=`echo ${vrmf} | ${CUT} -d"." -f2`
  mod=`echo ${vrmf} | ${CUT} -d"." -f3`
  fix=`echo ${vrmf} | ${CUT} -d"." -f4`

  return 0
}

#---------------------------- set_option_lists --------------------------------
#
# NAME: set_option_lists
#
# FUNCTION: Calls c_getlevel to determine the level of AIX that will
#   supported by the lpp_source.  The "SIMAGES_OPTIONS", "REQUIRED_SIMAGES"
#   and "DEFAULT_SPOT_OPTIONS" variables will be set to include the lists of
#   appropriate filesets for the level determined.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#   parameters:    1 - the type of source containing the bos image
#                  2 - the location of the source for the bos image
#                  3 - the architecture type for support images
#
#   global:        version              - set by c_getlevel
#                  release              - set by c_getlevel
#                  SIMAGES_OPTIONS      - set in this routine
#                  REQUIRED_SIMAGES     - set in this routine
#                  DEFAULT_SPOT_OPTIONS - set in this routine
#
# RETURNS: (int)
#                  0 = success
#                  1 = failure
#
# OUTPUT:
#-------------------------------------------------------------------------------
function set_option_lists {

	typeset arch=${3}

	# Call c_getlevel to get the level of the "source".
	# If the "location" does not contain a bos image, then the
	# level will come from the level of the NIM client fileset that
	# is installed.
	${C_GETLEVEL} -a type=${1} -a source=${2} \
		> ${TMPDIR}/__src_level.$$

	# include the level in the current environment.
	. ${TMPDIR}/__src_level.$$

	LPP_SOURCE_LEVEL=${version}${release}
	
	# what type of images are needed?
	LPP_ARCH_TYPE=${arch:=`get_mac_arch`}

	# Update the default lists to match the level of the install
	# media if necessary.
	# NOTE: SIMAGES_OPTIONS_GRAPHICS needs adding to the list
	# if/when graphics bundles change per release
	if [[ ${LPP_SOURCE_LEVEL} = 41 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_41
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_41
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_41
		SIMAGES_OPTIONS_GRAPHICS=
	elif [[ ${LPP_SOURCE_LEVEL} = 42 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_42
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_42
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_42
		SIMAGES_OPTIONS_GRAPHICS=
	elif [[ ${LPP_SOURCE_LEVEL} = 43 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_43
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_43
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_43
		SIMAGES_OPTIONS_GRAPHICS=
	elif [[ ${LPP_SOURCE_LEVEL} = 50 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_50
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_50
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_50
		SIMAGES_OPTIONS_RPMS=$SIMAGES_OPTIONS_RPMS_50
		SIMAGES_OPTIONS_GRAPHICS=
	elif [[ ${LPP_SOURCE_LEVEL} = 51 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_51
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_51
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_51
		SIMAGES_OPTIONS_RPMS=$SIMAGES_OPTIONS_RPMS_51
		SIMAGES_OPTIONS_GRAPHICS=
	elif [[ ${LPP_SOURCE_LEVEL} = 52 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_52
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_52
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_52
		SIMAGES_OPTIONS_RPMS=$SIMAGES_OPTIONS_RPMS_52
		SIMAGES_OPTIONS_GRAPHICS=$SIMAGES_OPTIONS_GRAPHICS_52
	elif [[ ${LPP_SOURCE_LEVEL} = 53 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_53
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_53
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_53
		SIMAGES_OPTIONS_RPMS=$SIMAGES_OPTIONS_RPMS_53
		SIMAGES_OPTIONS_GRAPHICS=$SIMAGES_OPTIONS_GRAPHICS_53
	elif [[ ${LPP_SOURCE_LEVEL} = 61 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_61
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_61
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_61
		SIMAGES_OPTIONS_RPMS=$SIMAGES_OPTIONS_RPMS_61
		SIMAGES_OPTIONS_GRAPHICS=$SIMAGES_OPTIONS_GRAPHICS_61
	elif [[ ${LPP_SOURCE_LEVEL} = 71 ]]
	then
		SIMAGES_OPTIONS=$SIMAGES_OPTIONS_71
		REQUIRED_SIMAGES=$REQUIRED_SIMAGES_71
		DEFAULT_SPOT_OPTIONS=$DEFAULT_SPOT_OPTIONS_71
		SIMAGES_OPTIONS_RPMS=$SIMAGES_OPTIONS_RPMS_71
		SIMAGES_OPTIONS_GRAPHICS=$SIMAGES_OPTIONS_GRAPHICS_71
	fi
}

#---------------------------- get_oparg_values -------------------------------
#
# NAME: get_oparg_values
#
# FUNCTION: Get the values of the attributes stored in the
#			opargs hidden attribute for a Custom Task.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:  For the resource group below, the following global
#			assignments will be made by this function:
#
#	source=spot filesets="bos.diag"
#
#   The source and filesets variables must be defined in
#	the calling function.
#
#	bos_inst:
#		class     = groups
#		type      = res_group
#		operation = bos_inst
#		opargs    = -a source=spot -a filesets="bos.diag"
# 		member1   = 42Gimages
#		member2   = 42Gspot
#
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#   parameters:
#		1 - The name of the resource group.
#   global:
#		See NOTES.
#
# RETURNS: NONE
#
# OUTPUT:  NONE
#-------------------------------------------------------------------------------

function get_oparg_values
{
RES_GRP_NAME=${1}
OPARGS=""

    # get the opargs hidden attribute
    OPARGS=`/usr/sbin/lsnim -lF ${RES_GRP_NAME} | ${GREP} opargs | \
		${AWK} 'BEGIN { FS="= " } {print $2}'`

    OPARGS="${OPARGS}"

	# Loop through the attributes contained
	# in the opargs attribute. 
    IFS=" "
    for i in ${OPARGS}
    do
		# Skip -a flag preceding each attribute assignment.
        if [[ "${i}" = "-a" ]]
        then
            variable=""
            value=""
            continue
        fi

		# No special processing for this attribute.
		# Just get the attribute type.
        if [[ "${variable}" != "filesets" ]] &&
            [[ "${variable}" != "fixes" ]]
        then
            variable=${i%%=*}
        fi

        # If this is the filesets or fixes attribute
		# be prepared for more than one value.
        if [[ "${variable}" = "filesets" ]] ||
            [[ "${variable}" = "fixes" ]]
        then
            if [[ "${i}" = *=* ]]
            then
                value=`${ECHO} ${i} | ${AWK} 'BEGIN { FS="=" } {print $2}'`
            else
                value="${value} ${i}"
            fi
            eval ${variable}=${value}
            continue
        else
            value=${i#*=}
        fi

		# Assign the attribute value to it's attribute type.
        eval ${variable}=${value}
    done
}

#---------------------------- get_res_values --------------------------------
#
# NAME: get_res_values
#
# FUNCTION: Get the members of a resource group and assign
#			their resource types to their respective values. 
#
# EXECUTION ENVIRONMENT:
#
# NOTES:  For the resource group below, the following global
#			assigments will be made by this function:
#
#         lpp_source=42Gimages spot=42Gspot
#
#   The lpp_source and spot variables must be defined in
#	the calling function.
#
#	bos_inst:
#		class   = groups
#		type    = res_group
# 		member1 = 42Gimages
#		member2 = 42Gspot
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#   parameters:    
#			1 - The name of the resource group.
#   global:      
#		See NOTES.
#
# RETURNS:  NONE 
#
# OUTPUT:	NONE
#-------------------------------------------------------------------------------

function get_res_values
{
RES_GRP_NAME=${1}

	# Loop through the members of this resource group.
    /usr/sbin/lsnim -lF ${RES_GRP_NAME} | ${GREP} member | while read member
    do
        value=${member#*= }

		# Get member's resource type.
        variable=`/usr/sbin/lsnim -l ${value} | ${GREP} type | ${AWK} 'BEGIN { FS="= " } \
			{print $2}'`

		# Assign the resource name to it's type.
        eval ${variable}=\"${value}\"
    done
}

#---------------------------- match_ifs --------------------------------
#
# NAME: match_ifs
#
# FUNCTION:  Prints the hostname associated with an interface on a
#            server that can be reached by a client.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#   parameters:    1 - the name of the client
#                  2 - the name of the server
#
# RETURNS: (int)
#                  0 = success
#
# OUTPUT:  prints the hostname of a machine interface.
#-------------------------------------------------------------------------------
function match_ifs
{
  client_name=$1
  server_name=$2

  # Get the server hostname to use by default if all the checks fail.
  default_server_hostname=`/usr/sbin/lsnim -a if1 $server_name | \
                          ${AWK} '{if (NR!=1) print $4}'`

  #
  # Check 1:  Do the client and server both have an interface on
  #           the same network?
  #

  # Get the network that the client's primary interface is on.
  # The client will mount resources from its primary interface.
  client_network=`/usr/sbin/lsnim -a if1 $client_name | ${AWK} '{if (NR!=1) print $3}'`

  # Check to see if one of the server interfaces is on the
  # same network as the client's primary interface.  If so, print
  # the hostname associated with that server interface.
  if_hostname=`/usr/sbin/lsnim -a if $server_name | ${AWK} '{if (NR!=1) print}' | \
               ${AWK} '{if ($3 == netname) print $4}' netname=$client_network`

  if [[ -n $if_hostname ]]
  then
    print $if_hostname
    return 0
  fi

  #
  # Check 2:  Does the client's network have a default route defined?
  #

  # Get the list of networks that the client can access.
  client_access_nets=`/usr/sbin/lsnim -a routing $client_network | \
                      ${AWK} '{if (NR!=1) print $3}'`

  # If the client's network has a default route, then it should be
  # able to use any interface on the server.
  for access_net in $client_access_nets
  do
    if [[ $access_net = "default" ]]
    then
      print ${default_server_hostname}
      return 0
    fi
  done

  #
  # Check 3:  Does the client's network have a static route set up to
  #           the server's network?
  #

  # Go through the list of server interfaces.  If one of the
  # interfaces is on a network that the client has access to,
  # then print the hostname associated with that interface.
  server_ifs=`/usr/sbin/lsnim -a if $server_name | ${AWK} '{if (NR!=1) print $1}'`

  for check_if in $server_ifs
  do
    if_info=`/usr/sbin/lsnim -a $check_if $server_name | ${AWK} '{if (NR!=1) print }'`
    if_network=`echo $if_info | ${AWK} '{ print $3 }'`
    if_hostname=`echo $if_info | ${AWK} '{ print $4 }'`

    for access_net in $client_access_nets
    do
      if [[ $if_network = $access_net ]]
      then
        print $if_hostname
        return 0
      fi
    done
  done

  #
  #  Check 4:  Nothing left to check.  Just use the hostname of the
  #            server's primary interface.
  #

  # The client does not have a known route to the server.  For NIM
  # operations this could be a problem, but for the purposes of this
  # routine, we will just print the hostname of the server's primary
  # interface.
  print ${default_server_hostname}

  return 0
}

#---------------------------- get_mac_arch
#
# NAME: get_mac_arch
#
# FUNCTION:
# 	Determine the machines architecture from the data returned by the
#       bootinfo command.
#	  	
#
# RETURNS: (int)
#     0		= success
#
# OUTPUT:  prints arch type of the client machine.
#     ia64	= value if bootinfo returns ia64
#     power	= value if bootinfo returns anything other than ia64
#
#-------------------------------------------------------------------------------
function get_mac_arch {

  typeset mac_plat=""

  mac_plat=`${BOOTINFO} -a 2>/dev/null`
  convert_arch_value ${mac_plat}

  return 0
}

#---------------------------- convert_arch_value -------------------------------
#
# NAME: convert_arch_value
#
# FUNCTION:
# 	Converts the value in arch_type to a value that NIM expects
#	  	
#
# RETURNS: (int)
#     0		= success
#
# OUTPUT:  prints arch type of the client machine.
#     ia64	= value if parameter is 4|I|ia64
#     power	= value if parameter is other than 4|I|ia64
#
#-------------------------------------------------------------------------------
function convert_arch_value {

  if [[ $1 = @(4|"I"|"ia64") ]]
  then
		print "ia64"
  else
		print "power"
  fi

  return 0

}

#---------------------------- get_platform_value -------------------------------
#
# NAME: get_platform_value
#
# FUNCTION:
# 	Converts the integer value of arch_type to a string
#	  	
#
# RETURNS: (int)
#     0		= success
#
# OUTPUT:  prints arch type of the client machine.
#     rs6k	= value if parameter is 1
#     rspc	= value if parameter is 2
#     chrp	= value if parameter is 3
#     ia64	= value if parameter is 4
#
#-------------------------------------------------------------------------------
function get_platform_value {

  case $1 in
	1) print "rs6k" ;;
	2) print "rspc" ;;
	3) print "chrp" ;;
	4) print "ia64" ;;
  esac

  return 0

}

#---------------------------- set_geninst -------------------------------
#
# NAME: set_geninst
#
# FUNCTION:
# 	Performs vrmf and flags checks to determine if geninstall command
#	should be set for usage.
#	  	
#
# RETURNS: (int)
#     0		= success
#
# OUTPUT:  returns geninstall or NULL string value
#
#-------------------------------------------------------------------------------
function set_geninst {

  # before anything, see if we want geninstall
  [[ -z ${GENINSTALL} ]] && return 0

  R_FLAG=""
  c_FLAG=""
  a_FLAG=""
  r_FLAG=""
  C_FLAG=""
  s_FLAG=""
  u_FLAG=""
  p_FLAG=""

  U_FLAG=""
  P_FLAG=""

  while getopts :R:acrCsup inst_flags
  do
      case $inst_flags in
          R)      R_FLAG="-R";;
          a)      a_FLAG="-a";;
          c)      c_FLAG="-c";;
          r)      r_FLAG="-r";;
          C)      C_FLAG="-C";;
          s)      s_FLAG="-s";;
          u)      u_FLAG="-u";;
          p)      p_FLAG="-p";;
      esac
  done

  #don't call geninstall for Cleanup, Listing applied s/w updates,
  #commit (c) or reject (r) unless (a) is also there
  if ( [[ ${c_FLAG} != *c* ]] || [[ ${a_FLAG} = *a* ]] ) &&  [[ ${r_FLAG} != *r* ]] \
	&& [[ ${C_FLAG} != *C* ]] && [[ ${s_FLAG} != *s* ]]
  then

	#   get version/release values
	get_fileset_level bos.rte.install

	#   if version > 5.0, call GENINSTALL command
	if (( ${version} > 4 )) 
	then
		# if GENINSTALL is set, and "-u" flag is passed,
		# then pass flag to geninstall command
		[[ -n ${GENINSTALL} ]] && [[ ${u_FLAG} = *u* ]] && \
			U_FLAG="-u"

		# if GENINSTALL is set, and "-p" flag is passed,
		# then pass flag to geninstall command
		[[ -n ${GENINSTALL} ]] && [[ ${p_FLAG} = *p* ]] && \
			P_FLAG="-p"

		# set geninstall/gencopy variables for use
		geninstall_cmd="${GENINSTALL} ${U_FLAG} ${P_FLAG} "
		gencopy_cmd="${GENCOPY} "
	fi

  fi
  return 0

}

#-----------------------------------------------------------------------------
#
#  Name:        get_level
#
#  Function:    Gets the level of the installed NIM master fileset and the
#               level of the backup.  Breaks the levels into integers for
#               comparison.  lvl_a1-lvl_a4 will represent the installed NIM level.
#               lvl_b1-lvl_b4 will represent the level of the backup.
#
#  Parameters:  nim db file
#
#  Returns:     Nothing.
#
#-----------------------------------------------------------------------------
function get_level
{
  typeset nimdbfile=$1
  typeset INST_LEVEL
  typeset BACKUP_LEVEL
  # Problem if INST_LEVEL < BACKUP_LEVEL

  INST_LEVEL=`${LSLPP} -L bos.sysmgt.nim.master | ${GREP} master | ${AWK} '{print $2}'`

  cd /tmp
  ${TAR} -xf $nimdbfile ./etc/NIM.level
  if [[ $? -ne 0 ]]
  then
    ${DSPMSG} -s ${ERR_SET} cmdnim.cat ${ERR_NO_VALID_ENTRIES} '0042-223 %s: Invalid input file: %s\nThe file either cannot be read, is empty, or contains no\nvalid entries.\n' ${PROGRAM_NAME} $nimdbfile
    exit -1
  fi
  BACKUP_LEVEL=`${CAT} /tmp/etc/NIM.level`

  lvl_a1=`${ECHO} $INST_LEVEL | ${AWK} 'BEGIN { FS="." } {print $1}'`
  lvl_a2=`${ECHO} $INST_LEVEL | ${AWK} 'BEGIN { FS="." } {print $2}'`
  lvl_a3=`${ECHO} $INST_LEVEL | ${AWK} 'BEGIN { FS="." } {print $3}'`
  lvl_a4=`${ECHO} $INST_LEVEL | ${AWK} 'BEGIN { FS="." } {print $4}'`
  lvl_b1=`${ECHO} $BACKUP_LEVEL | ${AWK} 'BEGIN { FS="." } {print $1}'`
  lvl_b2=`${ECHO} $BACKUP_LEVEL | ${AWK} 'BEGIN { FS="." } {print $2}'`
  lvl_b3=`${ECHO} $BACKUP_LEVEL | ${AWK} 'BEGIN { FS="." } {print $3}'`
  lvl_b4=`${ECHO} $BACKUP_LEVEL | ${AWK} 'BEGIN { FS="." } {print $4}'`

  return
}

#-----------------------------------------------------------------------------
#
#  Name:        check_level
#
#  Function:    Compares the values set by get_level() to determine whether
#               or not the installed NIM level (lvl_a1-a4) is at the same level
#               or higher as the backup (lvl_b1-lvl_b4).
#
#  Parameters:  None.  Uses the global values lvl_a1-lvl_a4 and lvl_b1-lvl_b4
#
#  Returns:     0 - The installed NIM level is at the same level as the
#                     backup or higher.
#               1 - The backup is at a higher level than the installed
#                     NIM master fileset.
#
#-----------------------------------------------------------------------------
function _check_level
{
#
#  Compare the version.
#  If the master version is less than the backup version, then immediately
#  return failure.  If the master version is greater than the backup version,
#  then immediately return success.  Otherwise, continue checking the other
#  parts of the v.r.m.f.
#
if [[ $lvl_a1 -lt $lvl_b1 ]]
then
  return 1
elif [[ $lvl_a1 -gt $lvl_b1 ]]
then
  return 0
fi

#
#  Compare the release.
#
if [[ $lvl_a2 -lt $lvl_b2 ]]
then
  return 1
elif [[ $lvl_a2 -gt $lvl_b2 ]]
then
  return 0
fi

#
#  Compare the maintenance level.
#
if [[ $lvl_a3 -lt $lvl_b3 ]]
then
  return 1
elif [[ $lvl_a3 -gt $lvl_b3 ]]
then
  return 0
fi

#
#  Compare the fix level.
#
if [[ $lvl_a4 -lt $lvl_b4 ]]
then
  return 1
else
  return 0
fi

}

function check_level
{
	typeset rc=0
	_check_level || rc=$?
	if [[ $rc -ne 0 ]]; then
		# reports levels only if do not match
		print
		${DSPMSG} -s ${MSG_SET} cmdnim.cat ${MSG_MASTER_LEVEL} \
			'The level of the NIM master fileset on this machine is: %s\n' \
			"${lvl_a1}.${lvl_a2}.${lvl_a3}.${lvl_a4}"
		${DSPMSG} -s ${MSG_SET} cmdnim.cat ${MSG_BACKUP_LEVEL} \
			'The level of the NIM database backup is: %s\n' \
			"${lvl_b1}.${lvl_b2}.${lvl_b3}.${lvl_b4}"
		print
	fi
	return $rc
}

#---------------------------- mget_http_content -------------------------------
#
# NAME: mget_http_content
#
# FUNCTION:
# 	Performs an iterative download of http content from nimhttp service.
#	The list of download content is obtained from the CWD/.content file.
#
#
# RETURNS: (int)
#     0		= success
#     1		= failure
#
# OUTPUT:  none (caller must check $?)
#
#-------------------------------------------------------------------------------
function mget_http_content
{
	typeset dir_name=${1%/}
	typeset reloc_name=${2:+"${2%/}/"}
	typeset host=
	typeset fs_name=
	typeset -i space_need=0
	typeset -i free_space=0

	# parse out host:dir_name
	if [[ ${dir_name} = ?*:?* ]]; then
		host=`echo $dir_name | $CUT -d: -f1`
		dir_name=`echo $dir_name | $CUT -d: -f2`
	fi

	# get the actual fs name
	fs_name="$( $DF ${reloc_name}${dir_name} | $AWK 'NR==2{print $7}' 2>/dev/null )"

	# calculate the space needs using the .content file
	if [[ -n "${reloc_name}${dir_name}/.content" ]]
	then
		for i in `$CAT ${reloc_name}${dir_name}/.content | $AWK '{print $5}'`
		do
			let space_need=`expr $space_need + $i 2>/dev/null`
		done
	fi

	# check the fs space
	if (( space_need > 0 ))
	then
		let space_need=`expr $space_need / 512 2>/dev/null`
		free_space="$( $DF ${fs_name} | $AWK 'NR==2{print $3}' 2>/dev/null )"
		# (attempt to) expand filesystem using 512-byte/block
		if (( free_space < space_need )); then
			$CHFS -a size=+$(( space_need - free_space )) ${fs_name} >/dev/null 2>&1
		fi
	fi

	# determine the type of nimhttp service call
	if [[ -z $web_client ]]
	then
		$NIMHTTP -s ${host:+"-i${host}"} -odest="/tmp/._nimhttp_test_$$" >/dev/null 2>&1 \
			&& web_client="$NIMHTTP -s" \
			|| web_client="$NIMHTTP"
		${RM} -r /tmp/._nimhttp_test_$$ >/dev/null 2>&1
	fi
	

	# begin the download attempts - exit on failure
	if [[ -n "${reloc_name}${dir_name}/.content" ]]
	then
		typeset -i bg_job=0
		# first pass - download data
		for entry in `$CAT ${reloc_name}${dir_name}/.content | $AWK '{ if ($1=="DIR:") printf("%s//|%s_%s ",$2,$3,$4); if ($1=="FILE:") printf("%s/|%s_%s ",$2,$3,$4) }'`
		do
			entry_name=
			entry_ownr=
			entry_mode=

			[[ -z $entry ]] && continue
			entry_name=`echo ${entry} | ${SED} 's/\/|.*$//'`
			entry_ownr=`echo ${entry} | ${SED} 's/.*\/|//'`
			entry_mode=`echo ${entry_ownr} | ${SED} 's/.*_//'`
			entry_ownr=`echo ${entry_ownr} | ${SED} 's/\_.*$//'`

			if (( bg_job < 1 ))
			then
				(
				$web_client ${host:+"-i${host}"} -f ${dir_name%/}/${entry_name} \
					${reloc_name:+"-odest=${reloc_name%/}"} 2>/dev/null || \
					return 1
				[[ -n $entry_mode ]] && \
				$CHMOD $entry_mode ${reloc_name}${dir_name%/}/${entry_name} 2>/dev/null
				[[ -n $entry_ownr ]] && \
				$CHOWN $entry_ownr ${reloc_name}${dir_name%/}/${entry_name} 2>/dev/null
				[[ -n "${reloc_name}${dir_name%/}/${entry_name%/}/.content" ]] && \
				mget_http_content ${dir_name%/}/${entry_name} ${reloc_name} >/dev/null 2>&1
				) &

				let bg_job=1
				continue
			fi

			$web_client ${host:+"-i${host}"} -f ${dir_name%/}/${entry_name} \
				${reloc_name:+"-odest=${reloc_name%/}"} 2>/dev/null || \
				return 1

			# output successful - set owner & mode
			[[ -n $entry_mode ]] && \
			$CHMOD $entry_mode ${reloc_name}${dir_name%/}/${entry_name} 2>/dev/null
			[[ -n $entry_ownr ]] && \
			$CHOWN $entry_ownr ${reloc_name}${dir_name%/}/${entry_name} 2>/dev/null

			# recursion - use some form of iteration later
			if [[ -n "${reloc_name}${dir_name%/}/${entry_name%/}/.content" ]]; then
				mget_http_content ${dir_name%/}/${entry_name} ${reloc_name} >/dev/null 2>&1
			fi

			let bg_job=0
			wait $! 

		done
		# wait for any remaining jobs
		wait
	fi

	return 0
}
