#!/sbin/sh
# *****************************************************************
# *                                                               *
# *    Copyright Compaq Computer Corporation, 2002                *
# *                                                               *
# *   The software contained on this media  is  proprietary  to   *
# *   and  embodies  the  confidential  technology  of  Compaq    *
# *   Computer Corporation.  Possession, use,  duplication  or    *
# *   dissemination of the software and media is authorized only  *
# *   pursuant to a valid written license from Compaq Computer    *
# *   Corporation.                                                *
# *                                                               *
# *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
# *   by the U.S. Government is subject to restrictions  as  set  *
# *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
# *   or  in  FAR 52.227-19, as applicable.                       *
# *                                                               *
# *****************************************************************
# @(#)$RCSfile: dupatch.sh,v $ $Revision: 1.1.2.5 $ (DEC) $Date: 2001/09/24 15:33:10 $

. /usr/share/lib/shell/libscp
. /usr/share/lib/shell/Dialog
. /usr/share/lib/shell/Lists
. /usr/share/lib/shell/Strings

[ -f /usr/share/lib/shell/libinstall ] &&
{
	. /usr/share/lib/shell/libinstall
	. /usr/share/lib/shell/libswdb
}


SetUpLogFile ()
{

	local_date=`date +%Y%b%d:%H:%M:%S`
	[ -d $_PATCHDIR/log ] ||
		mkdir -m 755 -p $_PATCHDIR/log
	_EVENT_LOG="$_PATCHDIR/log/Dupatch_load_$local_date.log"
	_SLOG=$_EVENT_LOG

	if [ -f /usr/bin/gawk ]; then
		_AWK=/usr/bin/gawk
	else	
		_AWK=/usr/bin/awk
	fi

	_AWKLOG='
	BEGIN {
		printf("%s", NAME);
	}
	{
		print ">" $0
	}
	'

        [ "$_DPWD" ] ||
        {
                _DPWD=`/bin/pwd`; export _DPWD
        }

	_USERNAME=""
	_USER=""
	_USERNOTES="Loading Patch Tools"
}



Main ()
{
	PATH=/sbin:/usr/lbin:/usr/sbin:/usr/bin

	_ARGS_DONE=

	_DPWD=`/bin/pwd`; export _DPWD
	_PROG=`basename $0`; export _PROG
 
	P_Make_TMP
 
	TRIM=Y

	P_Args $0 $* || P_Exit 1

	P_SetRoot

        SetUpLogFile

        P_LogInit         # standard routine

	echo "" >>$_SLOG



        if [ "$_PVS" -a "$_KIT_TOP" ]; then

		P_UpdateTools || P_Exit $?
	else
	{
		if [ "$_CMDLINE" ]; then
               {
                        echo "
************************************************************************

Warning: To load new tools, you must put the -kit switch on the command line.
                No attempt is being made to load new tools.

************************************************************************
" | tee -a $_SLOG

		}
		else
		{
			P_KitLocGet || P_Exit 1
			P_UpdateTools || P_Exit $?
		}
		fi
	}
	fi



	[ -f $_ROOT/usr/sbin/$_PROG ] ||
	{
		P_Ferror 1 "
	Patch tools need to be installed on your system. As the super-user
	(root), please invoke $_PROG without command line arguments first. 
"
	}

	_DUPATCH_EXEC=Y; export _DUPATCH_EXEC
       [ -x $_ROOT/usr/sbin/$_PROG ] || P_Ferror 1 "ERROR: $_ROOT/usr/sbin/$_PROG is not executable..."

        exec $_ROOT/usr/sbin/$_PROG $*

	P_Exit $?

}


# @(#)$RCSfile: common.sh,v $ $Revision: 1.1.2.26 $ (DEC) $Date: 2002/03/04 20:25:51 $




P_AbsPath ()
{

        case $1 in
        .)      # path is the current directory
                P=$_DPWD
                ;;
        /*)     # absolute path provided
                P=$1
                ;;
        *)      # relative from current directory
                P=$_DPWD/$1
                ;;
        esac

        echo $P | sed -e 's%/\./%/%g' -e 's%/\./%/%g' -e 's%///*%/%g' -e 's%/\.$%%' -e 's%*/$%%'
}



P_Args ()
{

	CMDPATH=$0; shift

	CL=`P_Remove_C_Space $*`

	P_ArgsSub $CL || return 1

	return 0
}



P_ArgsCheck () 
{ 
	P_ArgsMand || return 1 

	[ "$PATCH_DEBUG" ] &&
		echo "\n=== final check stage in P_ArgsCheck ()"

	eval SWLIST=\$_${_TYPE}_SW

	ERROR=0
	for CS in $_ALLSW
	{
		eval SW=\$_SW_$CS
		[ "$SW" ] || continue

		LSW="-`ToLower $CS"	

		Member $CS $SWLIST ||
		{
			P_Error "
\"$LSW\" is not a valid switch with operation \"-`ToLower $_TYPE`\"" 
			ERROR=1
			continue
		}

		eval ARG=\$_ARG_$CS

		case $CS in
		CFGFILE)
			[ "$ARG" ] ||
			{
				P_Error "
The \"$LSW\" switch requires a file name as its argument."
				ERROR=1
				continue
			}
			[ -f $_CONFIGPATH/$ARG ] ||
			{
				P_Error "
The configuration file \"$_CONFIGPATH/$ARG\" does not exist."
				ERROR=1
				continue
			}
			;;

		KIT | \
		ROOT)
			[ "$ARG" ] ||
			{
				P_Error "
The \"$LSW\" switch requires a directory path as its argument." 
				ERROR=1 
				continue
			}

			ARG=`P_AbsPath $ARG`

			[ -d "$ARG" ] ||
			{
				P_Error "
\"$ARG\" does not exist or is not a directory." 
				ERROR=1 
				continue
			} 

			case $CS in
			KIT) 	P_SetRoot
				P_KitLocCheck $ARG || ERROR=1
				;;
			ROOT)	[ -d $ARG/usr/.smdb. ] ||
				{
					P_Error "
\"$ARG\" is not a valid directory for alternate root." 
					ERROR=1 
				}
				;;
			esac
				
			;;
		
		NAME | \
		NOTE)
			[ "$ARG" ] ||
			{
				P_Error "
The \"$LSW\" switch requires a text string as its argument."
				ERROR=1
			}
			;;

		DATA_FILE | \
		NOBACKUP | \
		NOLOG | \
		PATCH_ID | \
		PRECHECK_ONLY | \
		PROCEED | \
		PRODUCT_ID | \
		REV | \
		ROOT_PATH | \
		SINGLE_USER | \
		NOAUTO | \
		NOROLL | \
		PRODUCT_ID)
			[ "$ARG" ] &&
			{
				P_Error "
The \"$LSW\" switch does not require any argument."
				ERROR=1
			}
			;;
 
		TYPE) 
			eval KEYLIST=\$_${CS}_KEY 
			KER=
			if [ ! "$ARG" ]; then 
			{
				KER=1
			} 
			else
			{
				UA=`ToUpper $ARG`				
				eval _ARG_$CS='$UA'		
				Member $UA $KEYLIST || KER=1
			}
			fi

			[ "$KER" ] &&
			{
				KEYLIST=`echo $KEYLIST | sed 's/ / | /g'`		
				P_Error "
The \"$LSW\" switch requires one of the following arguments:
		`ToLower $KEYLIST` "
				ERROR=1
			}
			;;
		PRODUCT)
			P_SetRoot
			P_ValidProd ||
			{
				ERROR=1
				continue
			}	

			[ "$PATCH_DEBUG" ] && 
				echo "\n=== Valid products are: $_VALIDPROD"

			NOT_VALID=

			U_VALIDPROD=`ToUpper $_VALIDPROD`	

			case $_TYPE in
			INSTALL)
				PRODMAP=$_KIT_PRODMAP
				;;
			DELETE)
				PRODMAP=$_SYS_PRODMAP
				;;
			esac

			SEL_LIST=
			for P in $_PRODUCT_LIST
			{
				UA=`ToUpper $P`				

				ALL_VALID="$U_VALIDPROD ALL"
				Member $UA $ALL_VALID ||
				{
					NOT_VALID=1
					P_Error " 
\"$P\" is not a valid product_id specification for this operation."
					continue
				}
				
				SEL=`S_ProdmapGet pvcode $PRODMAP $UA`
				SEL_LIST="$SEL_LIST $SEL"
			}

			[ "$NOT_VALID" ] &&
			{
				ERROR=1 
				P_Error " 
Valid product_id specifications on your system for this operation are:
"
				for V in $_VALIDPROD all
				{
					echo "\t\t$V"
				}

				continue
			}


			Member ALL `ToUpper $_PRODUCT_LIST` ||
			{
				_PVS=$SEL_LIST
			}

			_ARG_PRODUCT=$_PVS
			
			[ "$PATCH_DEBUG" ] &&
			{
				echo "=== _ARG_PRODUCT=$_ARG_PRODUCT"
				echo "=== _PRODUCT_LIST=$_PRODUCT_LIST"
			}
			;;

		esac

		[ "$PATCH_DEBUG" ] &&
		{
			eval SS=\$_SW_$CS
			eval AA=\$_ARG_$CS
			echo "=== _SW_$CS=$SS	_ARG_$CS=$AA"
		}

	}

	case $_TYPE in
	INSTALL | DELETE )
		[ "$_SW_PRODUCT" ] ||
		{
			P_SetRoot
			P_ValidProd
			if [ $? = 0 ]; then 	
			{
				[ `Length $_VALIDPROD` -gt 1 ] &&
				{
					P_Error "
There are more than one products available for this operation.
You must use the \"-product\" switch to specify the product(s).
and the \"-product\" switch must preceed the \"-patch\" switch.

Valid product_id specifications on your system for this operation are:
"
					for V in $_VALIDPROD all
					{
						echo "\t\t$V"
					}
		
					ERROR=1	
				}
			}
			else
				ERROR=1
			fi
		}

		;;
	esac


	return "$ERROR"

}




P_ArgsData ()
{
	if [ "$_ARG_DATA" ]; then
	{
		_ARG_DATA=`P_AbsPath $_ARG_DATA`

		[ -f $_ARG_DATA ] || 
		{
			P_Error "
\"$_ARG_DATA\" does not exist or is not a file." 
			return 1 
		} 
	} 
	else
	{
			P_Error "
The \"-data\" switch requires a file path as its argument." 
			return 1 
	}
	fi

	
	eval SWLIST=\$_${_TYPE}_SW

	TMP=/var/tmp/$_PROG.tmp
	unlink $TMP 2>/dev/null
	> $TMP || exit 1

	[ "$_PRDFLG" ] || _CMD_LINE_ERR=Y

	_PATFLG=Y; _PRDFLG=Y; _PRD1ST=${_PRD1ST:-""}; _WHICHFIRST=${_WHICHFIRST:-""};

	cat $_ARG_DATA | while read LINE
	do

		TMPERR=
		[ "$LINE" ] || continue

		LINE=`echo $LINE`	
		case $LINE in
		\#*)	continue
			;;
		esac
		
		LINE=`echo $LINE | awk -F# '{print $1}'`

		LV=`echo $LINE | awk -F= '{print $1}'`
		LVAL=`ToUpper \`echo $LV\``

		RV=`echo $LINE | awk -F= '{print $2}'`

		if [ $LVAL = "PATCH" ]; then
			RV=`P_Remove_Spaces $RV`
			RVAL=`ToUpper \`echo $RV\``
		else
			RVAL=`echo $RV`
		fi

		[ ! "$LVAL" -a ! "$RVAL" ] && continue


		case "$LVAL" in
		PATCH | PRODUCT)	
			{
				P_SetSwitch $LVAL $RVAL
				P_ArgsPidParse $LVAL $RVAL || continue

				case "$LVAL" in
				PATCH)
					[ -z "$_WHICHFIRST" ] &&
						_WHICHFIRST=1; echo "_WHICHFIRST=1" >> $TMP

					[ "$_PATFLG" ] ||
                                        {
						P_Error "\n\"$LV\" is not a valid data-file switch here;  only one \"-patch\" switch  per product switch allowed "
						TMPERR=Y
						echo "TMPERR=Y" >>$TMP
						continue
					}
					P_ArgsPatchAdd $TMP
					_PATFLG=; _PRDFLG=Y
					echo "_PATFLG=\"\"; _PRDFLG=Y;" >>$TMP
					;;
				PRODUCT)
					[ -z "$_WHICHFIRST" ] &&
					_WHICHFIRST=2; echo "_WHICHFIRST=2" >>$TMP

					[ "$_PRDFLG" ] ||
					{
						P_Error "\n\"$LV\" is not a valid data-file switch here;  was expecting \"-patch\" switch"
						TMPERR=Y
						echo "TMPERR=Y" >>$TMP
						continue
					}
					[ "$_PATFLG" ] &&
					{
						_PRD1ST=Y
						echo "_PRD1ST=Y;" >>$TMP
					}
					_PRODUCT_LIST="$_PRODUCT_LIST $_ARG_PRODUCT"
					echo _PRODUCT_LIST=\"$_PRODUCT_LIST\" >>$TMP
					_PRDFLG=; _PATFLG=Y
					echo "_PRDFLG=\"\"; _PATFLG=Y;" >>$TMP
					;;
				esac

				echo "_SW_$LVAL=$LVAL" >> $TMP
				echo _ARG_$LVAL=\"`echo $RVAL|sed 's/\"//g'`\" >>$TMP
			}
			;;
		*)

			eval SW=\$_SW_$LVAL
			[ "$SW" ] ||
			{
				echo "_SW_$LVAL=$LVAL" >> $TMP
				echo _ARG_$LVAL=\"`echo $RVAL|sed 's/\"//g'`\" >>$TMP
			}
			;;
		esac
	done

	. $TMP

	[ "$TMPERR" ] &&        # any errors from TMP file?
	{
		rm -f $TMP      # yup - bale out...
		return 1
	}

	[ "$PATCH_DEBUG" ] &&
	{
		echo "\n=== After processing data file"
		cat $TMP 
	}

	rm -f $TMP 

	return 0

}



P_ArgsInit ()
{
	_OPS="-install | -delete | -track | -help"

	_DUPATCH_REV=34-02; export _DUPATCH_REV
	_MAX_LOGS=25; export _MAX_LOGS

	_CSPC="C"       # special Customer Specific Patch Character
	export _CSPC

	_N_ALRDY_INS=0
	_N_FAIL=0
	_N_OK=0
	_N_SEL=0

	export _N_ALRDY_INS _N_FAIL _N_OK _N_SEL

	_CMDLINE=

	_ALLARGS=$*

	_PATFLG=
	_PRDFLG=
	_PRD1ST=
	export _PATFLG _PRDFLG _PRD1ST

	_CMD_LINE_ERR=
	_DATA_FILE_ERR=
	export _CMD_LINE_ERR _DATA_FILE_ERR


	_DELETE_SW="CFGFILE \
			DATA \
			KIT \
			NAME \
			NOAUTO \
			NOLOG \
			NOROLL \
			NOTE \
			PATCH \
			PROCEED \
			PRODUCT \
			ROOT"
	_HELP_SW="DATA_FILE \
			KIT \
			PATCH_ID \
			PRODUCT_ID \
			REV \
			ROOT_PATH"
	_INSTALL_SW="CFGFILE \
			DATA \
			KIT \
			NAME \
			NOAUTO \
			NOBACKUP \
			NOLOG \
			NOROLL \
			NOTE \
			PATCH \
			PRECHECK_ONLY \
			PROCEED \
			PRODUCT \
			SINGLE_USER \
			ROOT"
	_TRACK_SW="DATA \
			KIT \
			NOLOG \
			ROOT \
			TYPE"

	_DELETE_MAND="NAME NOTE PATCH"
	_INSTALL_MAND="KIT NAME NOTE PATCH"
	_PRECHECK_ONLY_MAND="KIT PATCH"
	_TRACK_MAND="TYPE" 

	_HISTORY_MAND="PATCH"
	_HISTORY_ALL_MAND="REL CUST ALL"
	_HISTORY_KEY="REL CUST ALL"
	_HISTORY_ALL_KEY="REL CUST ALL"
	_TYPE_KEY="PATCH FILE KIT HISTORY HISTORY_ALL"


	_PRODUCT_LIST=

	_PATCH_LIST=


	_ALLSW="CFGFILE \
		DATA \
		DATA_FILE \
		KIT \
		NAME \
		NOAUTO \
		NOBACKUP \
		NOLOG \
		NOROLL \
		NOTE \
		PATCH \
		PATCH_ID \
		PRECHECK_ONLY \
		PROCEED \
		PRODUCT \
		PRODUCT_ID \
		REV \
		ROOT \
		ROOT_PATCH \
		SINGLE_USER \
		TYPE"

	
	DELETE_USAGE="	$_PROG -delete 	
			 [mandatory switches]:
			 	-name <user_name> 
			 	-note <user_note>
			 	-patch <all | patch_id [patch_id ...]>
	
			 [optional switches]:
				-cfgfile <config_file>  # configuration file
							  for kernel rebuild
				-data <data_file>
				-noauto		# do not perform automatic
						  kernel build and/or reboot
				-nolog		# no session logging
				-noroll		# if patching a cluster, do
				-proceed	# proceed with patches that
						  passed pre-deletion check
			 	-product <all** | product_id > *
		       	   	-root <root_path>		

				*  mandatory when more than one product is
				   available for operation.  PLEASE NOTE that
				   in this case, the \"-product\" and \"-patch\"
			   	   switches MUST be paired together.

                                ** if the -product switch is \"all\", then the
                                        -patch switch MUST ALSO BE \"all\"."	

	HELP_USAGE="	$_PROG -help
			 [optional switches]:
				-data_file	# specifies data_file usage 
				-kit <kit_location>
				-patch_id	# specifies patch_id usage 
				-rev		# lists $_PROG revision
				-product_id     # specifies product_id usage"
		

	INSTALL_USAGE="	$_PROG -install	
			 [mandatory switches]:
			 	-kit <kit_location>
			 	-name <user_name> *
			 	-note <user_note> *
			 	-patch <all | patch_id [patch_id ...]>

				* optional when -precheck_only is specified.

			 [optional switches]:
				-cfgfile <config_file>  # configuration file
							  for kernel rebuild
			   	-data <data_file>
				-noauto		# do not perform automatic
						  kernel build and/or reboot
			   	-nobackup
				-nolog 		# no session logging
				-noroll		# if patching a cluster, do
			   	-precheck_only	# check patch applicability
						  without installing.
				-proceed	# proceed with patches that
						  passed pre-installation check
			 	-product <all** | product_id > *
			   	-root <root_path>
				-single_user	# if in multi-user, bring the
						  system to single-user before
						  installing patches.

				*  mandatory when more than one product is
				   available for operation.  PLEASE NOTE that
				   in this case, the \"-product\" and \"-patch\"
				   switches MUST be paired together.

				** if the -product switch is \"all\", then the
				   -patch switch MUST ALSO BE \"all\"."

	TRACK_USAGE="	$_PROG -track 	
			 [mandatory switches]:
			 	-type <file | kit | patch>  *
				* use \"file\"  to list all patched files.
				* use \"kit\"   to list installed patch kits.
				* use \"patch\" to list installed patches.
				* use \"history\" to list patch installations
				    history.  Requires -product switch when
				    multiple products are on the system
				* use \"history_all\" to list history of
				    all patch installations

				-kit <kit location>     # for loading new tools

			 [optional switches]:
				-data <data_file>
				-nolog		# no session logging
				-root <root_path>"


	ALL_USAGE="When invoked without any arguments, you will be presented with the
interactive menu interface and will be prompted for needed command
arguments.

You can also use the command line interface to make the operations
non-interactive. In this case, all mandatory switches must be specified.

The following is a description of the command line interface:

$DELETE_USAGE

$HELP_USAGE

$INSTALL_USAGE

$TRACK_USAGE"

	DATA_FILE_USAGE="
<data_file usage>:

	When using the \"-data\" switch, you must specify a data_file
	which is a file path and contains specifications with the 
	following format:

		switch1=value	
		switch2=value
			.
  			.
		switch3

	Example:

		kit     = /mnt
		name    = John Doe
		note    = install April patch kit
		product = DIGITAL_UNIX_V4.0D
		patch   = 27.01 63.00 74 83.01
		product = TruCluster_V1.5
		patch   = 21.01 27.01 40

		precheck_only
		nobackup
	- blank lines and comments (preceded with #) are allowed.

	- line continuation (\) is required if a specification spans
	  multiple lines.

	- only one data-file switch is permitted per command-line

	- data-files cannot contain data-files

"

	REV_USAGE="
Tru64 UNIX Patch Utility (Rev. $_DUPATCH_REV)
"
	ROOT_PATH_USAGE="
<root_path usage>:

	- the \"-root\" switch is similar to the \"-D\" switch of setld (8),
	  which specifies an alternative root for the specified operation.
 	
	- root_path must be the root of a complete Tru64 UNIX file system.

	- The default root_path is / for all operations.
"

	export ALL_USAGE DATA_FILE_USAGE ROOT_PATH_USAGE REV_USAGE

	_TOOLSUB=00000; export _TOOLSUB

	_PID=[0-9][0-9][0-9][0-9][0-9]
	_VID=[0-9][0-9]
	
	export _PID _VID

}



P_ArgsMand ()
{
	eval MANDLIST=\$_${_TYPE}_MAND

	[ "$_SW_PRECHECK_ONLY" ] &&
		MANDLIST=$_PRECHECK_ONLY_MAND

	MAND_MISSING=
	for M in $MANDLIST
	{
		eval ARG=\$_ARG_$M
		[ "$ARG" ] ||
			MAND_MISSING="$MAND_MISSING 
		-`ToLower $M`"
		
	}

	[ "$MAND_MISSING" ] &&
	{
		P_Error "
You must specify the following mandatory switch(es):
		$MAND_MISSING" 

		return 1
	}

	return 0 
}



P_ArgsPatchAdd ()
{
	FILE=$1

	[ "$_ARG_PATCH" ] || return 0

	for J in $_ARG_PATCH
	{
		J=`ToUpper $J`			
		if [ "$_ARG_PRODUCT" ]; then
		{
			for P in $_ARG_PRODUCT
			{
				_PATCH_LIST="$_PATCH_LIST $P:$J"
			}
		}
		else
			_PATCH_LIST="$_PATCH_LIST :$J"
		fi

		[ -f $FILE ] &&
			echo _PATCH_LIST=\"$_PATCH_LIST\" >> $FILE
	}

	[ "$PATCH_DEBUG" ] &&
	{
		echo "=== _PATCH_LIST=$_PATCH_LIST"
	}

	return 0
}



P_ArgsPatchMap () 
{ 
	[ "$_PATCH_LIST" ] || 
		return 0 

	WCOUNT=0; 
	RES=0;


	PLIST=
	PSUB_ERROR=
	for J in $_PATCH_LIST
	{
		PROD=`echo $J | awk -F: '{print $1}'`
		PID=`echo $J | awk -F: '{print $2}'`

		if [ "$PROD" ]; then 
		{
			if [ `Ucase $PROD` = ALL ]; then
				if [ `Ucase $PID` = ALL ]; then
					PVS=$_PVS
				else
					P_Error "
If the product switch argument is \"all\" then the patch switch must have \"all\" as its argument"
					return 1
				fi
			else
				PVS=`S_ProdmapGet pvcode $PRODMAP $PROD`	
			fi
		}
		else
		{
			PVS=$_PVS
		}
		fi

		for PV in $PVS
		{

			PCODE=`expr "$PV" : '\(...\)...'`
			VCODE=`expr "$PV" : '...\(...\)'`

			eval PNAME=\$_PNAME$PV	
		
			case "$PID" in 
			ALL)	ID=?????
				RV=??
				;;
	
			*)	# process reserved, patch id, separate patch id and rev number.
				RES="`expr $PID : '^\(.\)'`"
				[ "$RES" = "$_CSPC" ] || {
					RES=0
				}
				if [ "$RES" != "0" ]; then
					ID=`echo $PID | sed 's/^'$_CSPC'//' | awk -F. '{printf "%05d", $1}'`
				else
					ID=`echo $PID | awk -F. '{print $1}'`
				fi

				if [ "$ID" ]; then
					ID=`echo $ID | awk '{printf "%05d", $1}'`
				else
					ID=?????
				fi

				RV=`echo $PID | awk -F. '{print $2}'`
				if [ "$RV" ]; then
					RV=`echo $RV | awk '{printf "%02d", $1}'`
				else
					RV=??
				fi
				[ "$PATCH_DEBUG" ] && echo "$PID->RES=$RES,ID=$ID.RV=$RV"
				;;

			esac
	
	
			case "$_TYPE" in
			INSTALL)
				eval KITDIR=\$_KITDIR$PV
				PSUB=`(cd $KITDIR; ls ${PCODE}PAT?${ID}${RV}${VCODE} 2>/dev/null)`	 
				
				[ "$PSUB" ] ||
				{
					P_Error "
	$PNAME Patch \"$PID\" is not available on the specified patch kit."
					PSUB_ERROR=1
					continue
				}
	
				STL_DepInit
	
				LIST=
				for S in $PSUB
				{
					STL_DepEval $S &&
                        		{
                				case $S in
                				???PAT?$_TOOLSUB*)
                        				continue
                        				;;
                				esac
	
						eval INSTDIR=\$_INSTDIR$PV
						SDESC=`S_ListPatches $S`
						P_Error "$SDESC 
     is already installed and will not be included in this operation."
						continue
                        		}
					LIST="$LIST $S"
				}
	
				PLIST="$PLIST $LIST" 
				;;
	
			DELETE|TRACK) 
				PSUB=`(cd $_SMDB; ls ${PCODE}PAT?${ID}${RV}${VCODE}.lk 2>/dev/null | sed 's/\.lk//')`	 
				[ "$PSUB" ] ||
				{
					STR2="for $PNAME"
	
					case "$PID" in 
					ALL) 
						STR1="No patches"
						STR3=are
						;;
					*)
						STR1="Patch \"$PID\""
						STR3="is not"
						;;
					esac
	
					P_Error " 
$STR1 $STR2 $STR3 installed on your system."
	
					continue
				}
	
				PLIST="$PLIST $PSUB" 
				;;
			esac

		}
	
	}

	_N_ALRDY_INS=$WCOUNT

	[ "$PSUB_ERROR" ] && return 1

	_ARG_PATCH=`echo $PLIST`

	[ "$_TYPE" = DELETE ] &&
	{
		_ARG_PATCH=`P_FilterTools lk $_SMDB $_ARG_PATCH`
	}

	[ "$PATCH_DEBUG" ] && 
		echo "\n=== _ARG_PATCH=$_ARG_PATCH."

	[ "$_ARG_PATCH" ] || 
	{ 
		case "$_TYPE" in
		INSTALL)STR=installable
			;;
		DELETE)	STR=deletable
			;;
		TRACK)  STR=trackable
			;;
		esac

		[ "$_INSTALL_PRECHECK" ] &&
		{

		P_Error "
\007
   **************************************************************

    Pre-Installation Check COMPLETED with the following results:

    $_N_ALRDY_INS patches were already installed


   **************************************************************

\007
"
		}

		P_Error "
There are no $STR patches as specified on the command line.
"

		P_Exit 2
	}

	TMP=./tmp/patchmap.tmp
	unlink $TMP 2>/dev/null
	> $TMP || exit 1

	for P in $_ARG_PATCH
	{
		echo $P >> $TMP
	}
	_ARG_PATCH=`cat $TMP | sort -u`	
	rm -f $TMP

	[ "$PATCH_DEBUG" ] &&
	{
		echo "=== _ARG_PATCH=$_ARG_PATCH"
	}
	return 0
}



P_ArgsPidMsg ()
{(
	PTYPE=$1 	# PATCH or PRODUCT 
	CASE=$2

	SWITCH=`ToLower $PTYPE`
	PTYPE=`ToLower $SWITCH | sed 's/$/_id/'`

	TAB=	
	PREFIX=
	[ "$_TYPE" = HELP ] && 
	{
		PREFIX="\n<$PTYPE usage>:\n"		
		TAB="\t- "
	}


	STR_ALLMIX="\n${TAB}The keyword 'all' can not be combined with other ${PTYPE}s."

	case $PTYPE in
	patch_id)
		STR_ID="\n${TAB}A valid patch_id specification is in the format of:\n\n\t\t'all' <or> [c]xxxxx[.yy]\n\n\t\t\twhere \"xxxxx\" is the patch identifier,\n\t\t\tc is the CSP indicator,\n\t\t\tand \"yy\" is the patch revision.\n\n\t\tExamples:\n\n\t\t\t15\n\t\t\t200.11\n\t\t\tc10.2\n\t\t\t00111.02\n\n\t- Both xxxxx and yy are numeric values; leading zeros can be omitted.\n\n\t- Patch revision (yy), when left unspecified, maps to wildcarded \"??\".\n\n\t- Multiple patch_id specifications are separated by white





 space."
		;;
	product_id)
		STR_ID="\n${TAB}A valid product_id specification is in the format of:\n\n\t\t'all' <or> description_version\n\n\t\t\twhere \"description\" is the product description,\n\t\t\tand \"version\" is the product version.\n\n\t\tExamples:\n\n\t\t\tDIGITAL_UNIX_V4.0B\n\t\t\tTruCluster_V1.4A\n\n\t- product_id specifications are case insensitive.\n\n\t- Wildcards are not allowed in product_id specifications.\n\n\t- Multiple product_id specifications are separated by white space."
		;;
	esac

	STR_ALL="$PREFIX$STR_ID\n$STR_ALLMIX\n"

	eval STR=\$STR_$CASE

	if [ "$_TYPE" = HELP ]; then 
		echo $STR
	else
		P_Error $STR
	fi

	return 0
)}



P_ArgsPidParse ()
{(

	PTYPE=$1; shift
	VAL=$*

	PID_ERR=
	[ "$VAL" ] ||
	{
		P_ArgsPidMsg $PTYPE NOARG 
		PID_ERR=1
	}

	NUM=`Length $VAL` 

	for P in $VAL
	{
		P=`ToUpper $P`	
		case $P in
		ALL)	[ "$NUM" -eq 1 ] && return 0
			
			P_ArgsPidMsg $PTYPE ALLMIX 
			PID_ERR=1
			continue 
			;; 
		esac

		[ "$PTYPE" = PRODUCT ] && continue 


		ID=`echo $P| awk -F. '{print $1}'`
		RV=`echo $P | awk -F. '{print $2}'`

		[ "$ID" ] ||
		{
			PID_ERR=1
			P_Error "
\"$P\" is not a valid patch_id specification."
			continue 
		}

		case $ID in
		$_CSPC[0-9] | \
		$_CSPC[0-9][0-9] | \
		$_CSPC[0-9][0-9][0-9] | \
		$_CSPC[0-9][0-9][0-9][0-9] | \
		$_CSPC[0-9][0-9][0-9][0-9][0-9])
			;;
		[0-9] | \
		[0-9][0-9] | \
		[0-9][0-9][0-9] | \
		[0-9][0-9][0-9][0-9] | \
		[0-9][0-9][0-9][0-9][0-9]) 	
			;;
		*)
			PID_ERR=1
			P_Error "
\"$P\" is not a valid patch_id specification."
			continue 
			;;
		esac

		[ "$RV" ] && 
		{
			case $RV in
			[0-9] | \
			[0-9][0-9]) 	
				;;
			*) 	
				PID_ERR=1
				P_Error "
\"$P\" is not a valid patch_id specification."
				continue	
				;;
			esac
		}
		
	}

	[ "$PID_ERR" ] &&
	{
		P_ArgsPidMsg $PTYPE ID 
		ERR=1
	}

	return $ERR 
	
)}

P_ArgsSub ()
{
	P_ArgsInit $*
	[ "$_ARGS_DONE" ] && return 0
	ERR=0

	[ $# -eq 0 ] && return 0

	_PATFLG=Y; _PRDFLG=Y; _PRD1ST=${_PRD1ST:-""};

	_WHICHFIRST=${_WHICHFIRST:-""};

	RT_NA_ONLY=1

	while :
	do
		[ $# -eq 0 ] && break

		SW=$1
		USW=`ToUpper $SW`

		S=`echo $SW | sed 's/^-//'`
		S=`ToUpper $S`

		case $USW in
		-DELETE | \
		-HELP   | \
		-INSTALL| \
		-TRACK )
			[ "$_CMDLINE" ] &&
				P_Ferror 1 "
You can only specify ONE of the following operations in one command:
        $_OPS"
			_CMDLINE=$S
			_TYPE=$_CMDLINE
			_CMDLINE_TEXT="$CMDPATH $*"

			export _TYPE _CMDLINE _CMDLINE_TEXT

			case $USW in
			-INSTALL)
				P_CheckEnv Y N || return 1
				;;
			-DELETE)
				P_CheckEnv Y Y || return 1
				;;
			esac

			shift

			RT_NA_ONLY=0
			;;

		-NOBACKUP| \
		-CFGFILE | \
		-DATA    | \
		-DATA_FILE| \
		-HISTORY| \
		-HISTORY_ALL| \
		-KIT     | \
		-NAME    | \
		-NOTE    | \
		-NOLOG   | \
		-PATCH_ID | \
		-PRODUCT_ID | \
		-PRECHECK_ONLY | \
		-PROCEED | \
		-REV     | \
		-ROOT    | \
		-ROOT_PATH | \
		-SINGLE_USER | \
		-NOAUTO | \
		-NOROLL | \
		-TYPE)
			[ $S = ROOT -o $S = NOAUTO ] || RT_NA_ONLY=0
			P_SetSwitch $*
			shift $_SHIFT
			;;

		-PATCH | -PRODUCT)
			P_SetSwitch $*
			shift $_SHIFT


			eval PLIST=\$_ARG_$S
			P_ArgsPidParse $S "$PLIST" ||
			{
				ERR=1
				continue
			}

			case $USW in
			-PATCH)
				if [ -z "$_WHICHFIRST" ]; then
					_WHICHFIRST=1
				fi
				[ "$_PATFLG" ] ||
				{
					P_Error "\n\"$SW\" is not a valid comman
d-line switch here;  only one \"-patch\" switch  per product switch allowed"
					ERR=1
					return 1
				}
				P_ArgsPatchAdd /dev/null
				_PATFLG=; _PRDFLG=Y
				;;

			-PRODUCT)
				if [ -z "$_WHICHFIRST" ]; then
					_WHICHFIRST=2
				fi
				[ "$_PRDFLG" ] ||
				{
					P_Error "\n\"$SW\" is not a valid comman
d-line switch here;  was expecting \"-patch\" switch"
					ERR=1
					return 1
				}
				[ "$_PATFLG" ] && _PRD1ST=Y
				_PRODUCT_LIST="$_PRODUCT_LIST $_ARG_PRODUCT"
				_PRDFLG=; _PATFLG=Y
				;;
			esac

			RT_NA_ONLY=0
			;;

		*)      # bad switches
			P_Error "\n\"$SW\" is not a valid switch"
			P_Usage $_TYPE
			P_Exit 1
			;;

		esac
	done

	[ $RT_NA_ONLY = 1 ] &&
	{
		[ "$_SW_ROOT" ] && { export _SW_ROOT; export _ARG_ROOT; }
		[ "$_SW_NOAUTO" ] && { export _SW_NOAUTO; }
		_ARGS_DONE=1
		export _ARGS_DONE
		return 0
	}

	[ "$_TYPE" ] ||
	{
		P_Usage

		P_Ferror 1 "
For command line interface, you must specify one of the following operations:
        $_OPS
   <OR>
specify no operations on the command line to use the menu interface.
"

	}


	[ "$PATCH_DEBUG" ] &&
		echo "\n=== operation = $_TYPE\n"


	[ "$_SW_DATA" ] &&
	{
		P_ArgsData || ERR=1
	}

	P_ArgsCheck || ERR=1

	[ "$ERR" = 1 ] &&
	{
		P_Usage $_TYPE
		return 1
	}

	[ "$_CMD_LINE_ERR" ] &&
	{
		P_Error "ERROR:  -product / -patch pair mis-match found in comma
nd-line
        - please correct before re-running dupatch..."
		P_Usage $_TYPE
		ERR=1
		return 1
	}

	[ "$_DATA_FILE_ERR" ] &&
	{
		P_Error "ERROR:  product / patch pair mis-match found in data-fi
le
        - please correct before re-running dupatch..."
		P_Usage $_TYPE
		ERR=1
		return 1
	}

	[ "$_TYPE" = HELP ] &&
	{
		P_Usage HELP
		P_Exit 0
	}


	P_ArgsPatchMap ||
	{
		P_Usage $_TYPE
		return 1
	}

	for S in $_ALLSW
	{
		export _SW_$S
		export _ARG_$S
	}
	_ARGS_DONE=1; export _ARGS_DONE

	return 0
}



P_CheckEnv ()
{
	SUPER=$1
	SINGLE=$2


	ERR=0


	[ "$SUPER" = Y ] && 
	{
		[ `id -u` -ne "0" ] &&
		{
			echo "
	This operation can be performed by the super-user (root) only."	
			ERR=1
		}
	
	}



        [ "$SINGLE" = Y -a "$_ROOT" = "/" ] &&
        {
                set -- `who -r`
                while [ "$1" -a "$1" != "run-level" ]
                do
                        shift
                done


                [ "$2" = "S" -o "$2" = "" ] ||
                {
                        echo "
        This operation can be performed in single-user mode only."
                        ERR=1
                }

        }

	return $ERR 
} 




P_Cleanup ()
{
        trap '' 0

	P_Unlock_pat
	
	if [ "$_DUPATCH_TMP" != / ]; then  
		rm -rf $_DUPATCH_TMP

		[ "$PATCH_DEBUG" ] && 
			echo "\n=== $_DUPATCH_TMP removed."
	fi
	
	[ -f /etc/evmlogger.conf.orig ] &&
	{
		mv /etc/evmlogger.conf.orig /etc/evmlogger.conf 2>/dev/null
	}
}




P_Error ()
{
        1>&2 echo "$*"
}



P_Exit ()
{
        STAT=$1

        P_Cleanup

        exit $STAT 
} 



P_Ferror ()
{
        STAT=$1
        P_Error "$_PROG: $2"
        P_Exit $STAT
}



P_FilterTools ()
{(
	TYPE=$1
	LOC=$2; shift 2
	SUBS=$*

	TMP1=$_DUPATCH_TMP/filtertools.tmp1
	if [ "$TYPE" = "lk" ]; then
		(cd $LOC; SWDB_FindInstalledSubsets "OSFPAT?$_TOOLSUB*") >$TMP1
	else
		(cd $LOC; ls OSFPAT?$_TOOLSUB*.$TYPE 2>/dev/null | sed 's/\.'$TYPE'//g' ) >$TMP1
	fi

	[ "$TMP1" ] || 
	{
		echo $SUBS
		rm -f $TMP1
		return 0
	}

	TMP2=$_DUPATCH_TMP/filtertools.tmp2
	> $TMP2
	for S in $SUBS
	{
		echo $S >> $TMP2
	}

	comm -23 $TMP2 $TMP1

	rm -f $TMP1 $TMP2
	return 0
)}



P_GetFirstEntry ()
{
	echo $1
}



P_HighestVerInstalled ()
{ (

	ID=$1	
	[ "$ID" = "OSF" ] &&
		ID=OSFBASE

	cd $_SMDB


	VCODE=`ls -1 ${ID}*.lk 2>/dev/null | \
	       sed 's/\('$ID'\).*\(...\)\(\.lk\)/\2/' | \
	       sed 's/.*[\?\*].*//g' | sort -ru | head -1`

	[ "$VCODE" ] || VCODE=000

	echo $VCODE

	return 0
) }



P_KitLocCheck ()
{

	P=`P_AbsPath $1`

	[ -d $P ] ||
	{
		P_Error "
	$P does not exist"
		return 1
	}

	[ -d $P/kit ] &&
	{
		[ -d $P/kit/instctrl ] ||
		{
			P_Error "
	$P/kit does not contain a Tru64 UNIX setld format patch kit.
"
			return 1
		}

		[ -d $P/doc ] ||
		{
			P_Error "
	$P/doc does not exist.
	$P does not contain a complete patch kit.
"
			return 1
		}

		P_KitLocSet $P single || return 1

		return 0
	} 

	[ -d $P/*/kit/instctrl ] ||
	{
			P_Error "
	$P 
		does not contain any Tru64 UNIX setld format patch kit.
"
			return 1
	}

	[ -d $P/patch_tools ] ||
	{
		P_Error "
	$P/patch_tools does not exist.
	$P does not contain a complete patch kit.
"
		return 1
	}
	
	[ -f $P/patch_tools/product_map ] ||
	{
		P_Error "
	$P/patch_tools/product_map does not exist.
	$P does not contain a complete patch kit.
"
		return 1
	}
	
	P_KitLocSet $P multi || return 1

	return 0

}



P_KitLocGet ()
{
	[ "$_DUPATCH_EXEC" ] &&
	{
		_DUPATCH_EXEC=
		return 0
	}

	[ "$_ARG_KIT" ] && 
	{
		P_KitLocCheck $_ARG_KIT
		return $?
	}

	STR="get back to the menu"
	[ "$TRIM" ] &&
		STR=quit

	while :
	do
		Dialog "
Enter path to the top of the patch distribution, 
or enter \"q\" to $STR " P $_KIT_TOP

		case $P in
		q|Q)
			return 1
			;;
		*)	P_KitLocCheck $P && return 0
			;;
		esac
	done

	return 0
}



P_KitLocSet ()
{

	_KIT_TOP=$1
	_FORMAT=$2

	[ "$_FORMAT" = single ] &&
	{
                SUB_CTRL=`(cd $_KIT_TOP/kit/instctrl; ls -1 *.ctrl | head -1)`

                [ "$SUB_CTRL" ] ||
                {
                        P_Error "
        No subset control file (.ctrl) in $_KIT_TOP/kit/instctrl.
"
                        return 1
                }

                SUB=`echo $SUB_CTRL | sed 's/\.ctrl//'`

                PRODUCT=`echo $SUB | sed 's/\(...\).*\(...\)$/\1\2/'`
	}

	_PVS=
	_KIT_PRODMAP= 

	[ -f $_KIT_TOP/../patch_tools/product_map ] &&
		_KIT_TOP=$_KIT_TOP/..

	[ -f $_KIT_TOP/patch_tools/product_map ] && 
		_KIT_PRODMAP=$_KIT_TOP/patch_tools/product_map

	if [ "$_KIT_PRODMAP" ]; then
	{
		for PROD in `cat $_KIT_PRODMAP | awk -F% '{print $1"%"$2"%"$3"% "}'`
		{ 
			eval `echo $PROD | \
			     awk -F% '{print "PNAME="$1" PCODE="$2" VCODE="$3}'` 

			SYS_VCODE=`P_HighestVerInstalled $PCODE`

			[ "$VCODE" = "$SYS_VCODE"  ] &&
			{
				_PVS="$_PVS $PCODE$VCODE"
			}
		}

	}
	else
	{

		PCODE=`expr "$PRODUCT" : '\(...\)...'`
		VCODE=`expr "$PRODUCT" : '...\(...\)'`


		SYS_VCODE=`P_HighestVerInstalled $PCODE`

		[ "$VCODE" = "$SYS_VCODE"  ] &&
		{
			_PVS="$_PVS $PCODE$VCODE"
		}
	}
	fi

	
        P_ProdCacheInfo

	[ "$_PVS" ] || 
	{
		P_Error "
	$_KIT_TOP does not contain any patch kit(s) 
	applicable to your system.
"
		return 1
	}	

	[ "$_FORMAT" = single ] &&
                _PVS=$PRODUCT

	export _KIT_TOP _KIT_PRODMAP _PVS _FORMAT

	[ "$PATCH_DEBUG" ] && 
	{ 
		echo "\n=== _KIT_TOP=$_KIT_TOP" 
		echo "\n=== available _PVS=$_PVS" 
	}

	return 0
}


P_Lock_pat()
{
        P_Cklock_pat || return 1
        mknod $_DUPATCH_LK_DIR/patlock p
        echo $_PATCH_TERM > $_DUPATCH_LK_DIR/pat.tty.lock
        echo $_PATCH_TERM > $_DUPATCH_TMP/patchterm
        (
                exec < $_DUPATCH_LK_DIR/patlock
                read X
                rm -f $_DUPATCH_LK_DIR/patlock $_DUPATCH_LK_DIR/pat.tty.lock
        ) &
}




P_Cklock_pat ()
{
        [ -p $_DUPATCH_LK_DIR/patlock ] &&
        {
                [ -f $_DUPATCH_LK_DIR/pat.tty.lock ] ||
                {
                        rm -f $_DUPATCH_LK_DIR/patlock
                        return 0
                }
                TTY=`sed -e "s/\/dev\///" $_DUPATCH_LK_DIR/pat.tty.lock`
                [ "$TTY" ] ||
                {
                        rm -f $_DUPATCH_LK_DIR/patlock \
				 $_DUPATCH_LK_DIR/pat.tty.lock
                        return 0
                }
                set -- `who | grep $TTY`
                PERSON=$1; TTY=$2
                [ "$PERSON" -a "$TTY" ] ||
                {
                        rm -f $_DUPATCH_LK_DIR/patlock \
				$_DUPATCH_LK_DIR/pat.tty.lock
                        return 0
                }
echo "
The dupatch utility is currently locked by $PERSON on /dev/$TTY. If 
it is determined that this person is no longer running dupatch, the
lock files can be removed by issuing the command \"rm $_DUPATCH_LK_DIR/pat*\" ." \
| fmt -78
                return 1
        } 
        return 0
}


P_Unlock_pat()
{
	_TERM=`cat $_DUPATCH_LK_DIR/pat.tty.lock 2>/dev/null`
	_PATCH_TERM=`cat $_DUPATCH_TMP/patchterm 2>/dev/null`
	[ "$_TERM" = "$_PATCH_TERM" ] && 
	{
        	[ -p $_DUPATCH_LK_DIR/patlock ] && 
			echo >$_DUPATCH_LK_DIR/patlock
	}
        trap 1 2 3
}


P_UnlockAndExit()
{
	SetupforReboot	
	
	P_Unlock_pat
	P_Exit 1
}



P_LogInit ()
{

	echo "\n<RECORD>" >> $_EVENT_LOG

	echo "$_DUPATCH_REV" | $_AWK -v NAME=DUPATCH_REV "$_AWKLOG" >> $_EVENT_LOG

	[ "$_CMDLINE" ] &&
	{
		echo "$_DPWD" | $_AWK -v NAME=CUR_DIR "$_AWKLOG" >> $_EVENT_LOG
	
		echo "$_CMDLINE_TEXT" | $_AWK -v NAME=CMDLINE "$_AWKLOG" >> $_EVENT_LOG
		[ "$_ARG_DATA" ] &&
			cat $_ARG_DATA | $_AWK -v NAME=DATAFILE "$_AWKLOG" >> $_EVENT_LOG

	}

	[ "$TRIM" ] ||
	{
	        CheckIfCluster &&
	        {
        	        if [ "$NOROLL_PATCH" ]
                	then
                        	_TYPE2=$_TYPE"_NOROLL_PATCH"
	                else
        	                _TYPE2=$_TYPE"_ROLLING_PATCH"
                	fi
	        }
	}

	ToLower $_TYPE2 | $_AWK -v NAME=TYPE "$_AWKLOG" >> $_EVENT_LOG

	echo "$_USERNAME" | $_AWK -v NAME=NAME "$_AWKLOG" >> $_EVENT_LOG

	echo "$USER" | $_AWK -v NAME=USER "$_AWKLOG" >> $_EVENT_LOG

	echo `date` | $_AWK -v NAME=DATE "$_AWKLOG" >> $_EVENT_LOG

	echo "$_USERNOTES" | $_AWK -v NAME=NOTES "$_AWKLOG" >> $_EVENT_LOG

	set -- `who -r`
	while [ "$1" -a "$1" != "run-level" ]
	do
		shift
	done

	if [ "$2" = "S" -o "$2" = "" ]; then
		_CURRENT_USER_MODE="Single_User"
	else
		_CURRENT_USER_MODE="Multi_User"
	fi
	echo "$_CURRENT_USER_MODE" | $_AWK -v NAME=CURRENT_MODE "$_AWKLOG" >> $_EVENT_LOG

}

P_Make_TMP ()
{
	_DUPATCH_TMP=`P_TransPath ./var/tmp/patch$$`

	if [ "$_DUPATCH_TMP" = / ]; then
		P_Error "Tempfiles directory set to improper value.  dupatch session will terminate."
		P_Exit 1
	fi

	mkdir -m 755 -p $_DUPATCH_TMP ||
	{
		P_Error "Could not create directory $_DUPATCH_TMP. dupatch will terminate."
		P_Exit 1
	}

	if [ ! -d "$_DUPATCH_TMP" -o  ! -w "$_DUPATCH_TMP" ]; then
		P_Error "Tempfiles directory is not writable.  dupatch session will terminate."
		P_Exit 1
	fi
	
	export _DUPATCH_TMP
}


P_PatchesAvailable ()
{
	_FILE_TYPE=$1
	LOC=$2
	VAR=$3
	MSG=$4
	_PR=$5
	TYSTR=$6

	_PR=${_PR:-"?"}

	[ "$PATCH_DEBUG" ] && 
	{
		echo "called P_PatchesAvailable(_FILE_TYPE=$_FILE_TYPE,LOC=$LOC,VAR=$VAR,MSG=$MSG,_PR=$5->$_PR,TYSTR=$TYSTR)"
	}

	SUBLIST=`(cd $LOC; ls ???PAT${_PR}${_PID}${_VID}???.${_FILE_TYPE} 2>/dev/null | sed 's/\.'$_FILE_TYPE'//g' )`

	[ "$PATCH_DEBUG" ] && 
		echo "Found Subset List of $SUBLIST"

	SUBLIST=`P_FilterTools ${_FILE_TYPE} $LOC $SUBLIST`

	[ "$SUBLIST" ] &&
	{
		eval $VAR=\$SUBLIST
		return 0
	}

	[ "$MSG" = MSG ] &&
	{
		STR=
		[ "$_ROOT" != / ] &&
			STR=" (rooted at $_ROOT)"
		P_Error "
	*** There are no $TYSTR patches installed on your system$STR ***"
	}

	eval $VAR=

	return 1
}



P_SCPExtDataEdit ()
{

	if [ -f $SCPEXTDIRBL/*.scp_extension ]; then
	{
		[ "$PATCH_DEBUG" ] && echo "Copying $SCPEXTDIRBL/*.scp_extension to $_SMDB"
		cp -p $SCPEXTDIRBL/*.scp_extension $_SMDB
	}
	fi

	SCP_EXT_DATA_LIST=`(cd $SCPEXTDIRBL; /bin/ls -1 *.scp_extension_data 2>/dev/null)`
	for SCPEXT_DATAFILE in $SCP_EXT_DATA_LIST
	{

		[ -f $_SMDB/$SCPEXT_DATAFILE ] || {
			[ "$PATCH_DEBUG" ] && echo "Copying $SCPEXT_DATAFILE to $_SMDB"
			cp -p $SCPEXTDIRBL/$SCPEXT_DATAFILE $_SMDB
			continue
		}

		sort -u $_SMDB/$SCPEXT_DATAFILE $SCPEXTDIRBL/$SCPEXT_DATAFILE > $PCITMP1

		grep "^#" $PCITMP1  | sed 's/^\#//' > $PCITMP2

		[ -s $PCITMP2 ] || {
			[ "$PATCH_DEBUG" ] && echo "Copying merged $SCPEXT_DATAFILE to $_SMDB"
			cp -p $PCITMP1 $_SMDB/$SCPEXT_DATAFILE
			continue
		}

		comm -23 $PCITMP1 $PCITMP2 > $PCITMP3
		[ "$PATCH_DEBUG" ] && echo "Copying merged and deleted $SCPEXT_DATAFILE to $_SMDB"
		cp -p $PCITMP3 $_SMDB/$SCPEXT_DATAFILE

	}
	return 
}



P_SetUpProductPaths ()
{

	Z1_TMP=$_DUPATCH_TMP/prodpath.tmp
	> $Z1_TMP	# clear the output file

	while read prod_line; do

		N=`echo $prod_line | awk -F% '{print $1}'`
		P=`echo $prod_line | awk -F% '{print $2}'`
		V=`echo $prod_line | awk -F% '{print $3}'`
		PV=`echo $prod_line | awk -F% '{print $2$3}'`


		if [ -d $_KIT_TOP/$N/kit/instctrl ]; then
		{
			echo "_INSTDIR$PV='$_KIT_TOP/$N/kit/instctrl'" >> $Z1_TMP
		}
		fi

	done < $_KIT_PRODMAP

	
	YY=`cat $Z1_TMP`

	for XX in $YY
	{
		ZZ=`echo $XX | awk -F= '{print $1}'`
		eval $XX
		export $ZZ
	}

	rm $Z1_TMP
}



P_ProdCacheInfo ()
{
	FROM_KIT=	
	BAD_KIT=
	BAD_PROD=

	case $_TYPE in
	INSTALL | BASELINE)
		FROM_KIT=Y
		;;
	DOC)
 		[ "$_PAT_REQ" = kit ] && FROM_KIT=Y
		;;
	esac

	[ "$_TYPE" ] || FROM_KIT=Y

	[ "$_KIT_PRODMAP" ] ||
		_KIT_PRODMAP=$_SYS_PRODMAP


        if [ ${_FORMAT} ] ; then
		if [ $_FORMAT = multi ]; then
		{
			P_SetUpProductPaths
		}
		fi
	fi
	
	TMP_OS_NAME="DIGITAL_UNIX"

	PCITMP1=$_DUPATCH_TMP/P_ProdCacheInfo.tmp1
	PCITMP2=$_DUPATCH_TMP/P_ProdCacheInfo.tmp2
	PCITMP3=$_DUPATCH_TMP/P_ProdCacheInfo.tmp3
	>$PCITMP1
	>$PCITMP2
	>$PCITMP3


	if [ "$FROM_KIT" ]; then 
	{
	
		for PV in $_PVS	
		{
			P=`expr $PV : '\(...\)'`
                	V=`expr $PV : '.*\(...\)'`

		    if [ $_FORMAT = multi ]; then
	   	    {	
                	PNAME=`S_ProdmapGet name $_KIT_PRODMAP $P $V`	 
                	PDESC=`S_ProdmapGet desc $_KIT_PRODMAP $P $V`	 
			[ $P = OSF ] &&  TMP_OS_NAME=$PNAME

			if [ -d $_KIT_TOP/$PNAME ]; then
			{
                		eval _PNAME$PV='$PNAME'
                		eval _KITDIR$PV='$_KIT_TOP/$PNAME/kit' 
                		eval _INSTDIR$PV='$_KIT_TOP/$PNAME/kit/instctrl'
				eval _SCPEXT_DIR$PV='$_KIT_TOP/$PNAME/kit/scp_extensions'
				eval _SCPEXT_DIRBL$PV='$_KIT_TOP/$PNAME/kit/scp_extensions/blocking_subsets'

				if [ -d $_KIT_TOP/$PNAME/doc/txt ]; then
                			eval _DOCDIR$PV='$_KIT_TOP/$PNAME/doc/txt' 
				else
                			eval _DOCDIR$PV='$_KIT_TOP/$PNAME/doc' 
				fi
			}
			else
			{
				BAD_PROD=$PV
				if [ $PNAME != "" ]; then
				   BAD_KIT=$PNAME
				else
				   BAD_KIT=$PV
				fi

			}
			fi  #end of kit not found
		    }  # end of multi
		    else
		    {
			if [ $P = "OSF" ]; then
			{
                		eval _PNAME$PV='$_KIT_TOP'
                		eval _KITDIR$PV='$_KIT_TOP/kit' 
                		eval _INSTDIR$PV='$_KIT_TOP/kit/instctrl'
                		eval _DOCDIR$PV='$_KIT_TOP/doc' 
				eval _SCPEXT_DIR$PV='$_KIT_TOP/kit/scp_extensions'
				eval _SCPEXT_DIRBL$PV='$_KIT_TOP/$PNAME/kit/scp_extensions/blocking_subsets'
			}
			else
			{
				echo "ERROR - Single patch kit can only be for the Operating System" | tee -a $_SLOG
			}
			fi
		    }
		    fi # end of single

		eval SCPEXTDIRBL=\$_SCPEXT_DIRBL$PV 

		if [ -d "$SCPEXTDIRBL" ]; then
			P_SCPExtDataEdit
		fi 

		eval _PDESC$PV='$PDESC'

		export _PNAME$PV _KITDIR$PV _INSTDIR$PV _DOCDIR$PV _PDESC$PV  _SCPEXT_DIR$PV _SCPEXT_DIRBL$PV

		}  # end of product loop
	

	if [ "$BAD_PROD" != "" ]; then
	{
		echo "
************************************************************************

Warning: The patch kit does not contain patches for:

         $BAD_KIT

It is recommended that the Tru64 UNIX and TruCluster products
be patched at the same time.  If you choose to 
patch the system, it may cause problems
with your Operating Environment.


************************************************************************
" | tee -a $_SLOG

		if [ "$_CMDLINE" ]; then
		{
		echo "
*** Warning: The patch kit does not contain patches for:

	$BAD_KIT

Automatically Proceeding with patching of the system" >> $_SLOG
		    echo "Automatically Proceeding with patching of the system" 
		}
		else
		{
		    echo "Do you want to proceed with the patching of the system ? [n] \c" | tee -a $_SLOG
		    read X; echo $X >> $_SLOG
		    if [ "$X" != "Y" -a "$X" != "y" ]; then
		    {
			echo "
Terminating this run of Dupatch
" | tee -a $_SLOG
			P_Exit 1
		    }
		    fi
		}
		fi

		YY=""
		for XX in $_PVS	
		{
			if [ "$XX" != "$BAD_PROD" ]; then
			{
				YY="$YY"" $XX"
			}
			fi
		}
		_PVS="$YY"
	}
	fi


		[ "$PATCH_DEBUG" ] &&
		{
			echo "applicable _PVS=$_PVS"
			echo
	
			for PV in $_PVS
			do
				eval echo _PNAME$PV=\$_PNAME$PV
				eval echo _KITDIR$PV=\$_KITDIR$PV
				eval echo _DOCDIR$PV=\$_DOCDIR$PV
				eval echo _INSTDIR$PV=\$_INSTDIR$PV
				eval echo _PDESC$PV=\$_PDESC$PV
				eval echo _SCPEXT_DIR$PV=\$_SCPEXT_DIR$PV
				eval echo _SCPEXT_DIRBL$PV=\$_SCPEXT_DIRBL$PV
			done
	
		}
	}
	else
	{
		for PV in $_PVS
		{
			P=`expr $PV : '\(...\)'`
                	V=`expr $PV : '.*\(...\)'`

                	PNAME=`S_ProdmapGet name $_SYS_PRODMAP $P $V`	 
                	PDESC=`S_ProdmapGet desc $_SYS_PRODMAP $P $V`	 

                	eval _PNAME$PV='$PNAME'
			eval _PDESC$PV='$PDESC'

			export _PNAME$PV _PDESC$PV
		}

		[ "$PATCH_DEBUG" ] &&
		{
			echo "applicable _PVS=$_PVS"
			echo
	
			for PV in $_PVS
			do
				eval echo _PNAME$PV=\$_PNAME$PV
				eval echo _PDESC$PV=\$_PDESC$PV
			done
	
		}
	}
	fi

	return 0
}

P_Remove_C_Space ()
{
	CH=""
	_pat_found=0
	while [ -n "$*" ];do
		next=$1
		shift
		if [ $_pat_found = "1" ]; then
			if [ $next = 'C' -o $next = 'c' ]; then
				next=$next$1
				shift
			fi
		else
			if [ $next = "-patch" ]; then
				_pat_found=1
			else
				X=`echo $next | sed 's/^\(-\).*/\1/'`
				if [ X = "-" ]; then
					_pat_found=0
				fi
			fi
		fi
	
		CH="$CH $next"
	done

	echo $CH
}

P_Remove_Spaces ()
{
	CH=""
	while [ -n "$*" ];do
		next=$1
		shift
		if [ $next = 'C' -o $next = 'c' ]; then
			next=$next$1
			shift
		fi

		CH="$CH $next"
	done

	echo $CH
}



P_SelSysProds ()
{
	TYPE=$1
	SELECT=$2; shift 2	# set to N in command line interface
	SS_SUBS=$*

	case $_TYPE in
	DELETE)
		LOC=$_SMDB
		;;
	DOC)
		LOC=$_ALLDOC
		;;
	esac

	ALL=$_DUPATCH_TMP/allsubs
	for S in $SS_SUBS
	{
		echo $S >> $ALL
	}	

	_PVS=`cat $ALL | sed 's/^\(...\).*\(...\)$/\1\2/' | sort -u`	
	
	[ `Length $_PVS` -gt 1 -a "$SELECT" = Y ] &&
	{
		MenuPost product sys $_PVS || return 1
		
			_PVS=$_MENULIST
	}

	_MENULIST=
	SLIST=$_DUPATCH_TMP/slist
	for PV in $_PVS
	{
		P=`expr "$PV" : '^\(...\)'`
		V=`expr "$PV" : '.*\(...\)$'`

		if [ "$TYPE" = "lk" ]; then
			SWDB_FindInstalledSubsets "${P}PAT?${_PID}${_VID}${V}" >$SLIST
		else
			(cd $LOC; ls ${P}PAT?${_PID}${_VID}${V}.$TYPE 2>/dev/null | sed 's/\.'$TYPE'//g') > $SLIST
		fi
		
		SS_SUBS=`comm -12 $ALL $SLIST`

		eval _SLIST$PV='$SS_SUBS'

		_MENULIST="$_MENULIST $SS_SUBS"
	}

	_MENULIST=`P_FilterTools $TYPE $LOC $_MENULIST`

	rm -f $ALL $SLIST

	export _PVS

       	P_ProdCacheInfo

	return 0
}



P_SetRoot ()
{
	[ "$_ROOT" ] && 
	{

		if [ -z "${_ALTROOT}" ]; then
		{
                	if [ "$_ROOT" = "/" ]; then
				_ALTROOT=
                	else
				_ALTROOT="-D $_ROOT"
				_SW_NOAUTO=NOAUTO
                	fi
		}
		fi

                export _ALTROOT _SW_NOAUTO

		if [ -z "${_PATCHDIR}" ]; then
		{	
			if [ "$_ROOT" = "/" ]; then
				_PATCHDIR=/var/adm/patch
			else
				_PATCHDIR=$_ROOT/var/adm/patch
			fi
	
			[ -d $_PATCHDIR ] ||
				mkdir -p $_PATCHDIR ||
				{
					P_Error "Could not create directory $_PATCHDIR. dupatch will terminate."
					P_Exit 1
				}

		}
		fi

		_SYS_PRODMAP=$_PATCHDIR/product_map

       		export _PATCHDIR _SYS_PRODMAP

		return 0
	}

	if [ "$_ARG_ROOT" ]; then 
	{

		_ROOT=$_ARG_ROOT

                case "$_ROOT" in
                /*)     ;;
                *)      _ROOT=`(cd $_ROOT;Pwd)`
                esac
		_ALTROOT="-D $_ROOT"
		_SW_NOAUTO=NOAUTO
		_R=$_ROOT
        }

	else
	{
		_ROOT=/
		_R=
		_ALTROOT=
	}
	fi

	if [ "$_ROOT" = "/" ]; then
		_PATCHDIR=/var/adm/patch
	else
		_PATCHDIR=$_ROOT/var/adm/patch
	fi
	_SMDB=./usr/.smdb.
	
	[ -d $_PATCHDIR ] ||
		mkdir -p $_PATCHDIR

	_SYS_PRODMAP=$_PATCHDIR/product_map

        export _ROOT _R _SMDB _PATCHDIR _SYS_PRODMAP _ALTROOT _SW_NOAUTO

	cd $_ROOT

	[ "$PATCH_DEBUG" ] &&
	{
		echo "\n=== P_SetRoot has exported these variables:"
		echo "\n=== _ROOT is $_ROOT"
		echo "\n=== _R is $_R"
		echo "\n=== _SMDB is $_SMDB"
		echo "\n=== _PATCHDIR is $_PATCHDIR"
		echo "\n=== _SYS_PRODMAP is $_SYS_PRODMAP"
		echo "\n=== _ALTROOT for setld is '$_ALTROOT'"
		echo "\n=== _SW_NOAUTO is $_SW_NOAUTO"
		echo "\n=== _SW_NOROLL is $_SW_NOROLL"
	}

	return 0
}



P_SetSwitch ()
{

	SW=$1
	S=`echo $SW | sed 's/^-//'`
	S=`ToUpper $S`
	eval _SW_$S='$S'

	ARG_CNT=0
	eval _ARG_$S=

	shift
	ARGS=

	while :
	do
		[ $# -eq 0 ] && break

		case $1 in
		-*)	break
			;;
		*)	ARGS="$ARGS $1"
			ARG_CNT=`expr $ARG_CNT + 1`
			shift	
			;;
		esac
	done
	
	ARGS=`echo $ARGS`
	eval _ARG_$S='$ARGS' 

	[ "$PATCH_DEBUG" ] &&
		eval echo _ARG_$S=\$_ARG_$S
		
	_SHIFT=`expr $ARG_CNT + 1`
} 



P_UpdateTools ()
{
	[ "$_TOOLS_UPDATED" ] && return 0

	_TOOLS_UPDATED=

	SYSVER=`P_HighestVerInstalled OSFBASE`

	case "$_FORMAT" in
	single)
		TOOLDIR=$_KIT_TOP/kit
		[ -d $_KIT_TOP/patch_tools ] &&
			TOOLDIR=$_KIT_TOP/patch_tools
		;;
	multi)
		TOOLDIR=$_KIT_TOP/patch_tools
		;;
	esac

	NEWSUB=`(cd $TOOLDIR; ls OSFPAT?${_TOOLSUB}*${SYSVER} 2>/dev/null)`

	[ "$NEWSUB" ] || 
	{
		P_Error "
	This patch distribution does not contain the required 
	patch tools subset. 
"
		return 1
	}


        CURSUB=`(cd $_SMDB; ls -1 OSFPAT?${_TOOLSUB}*${SYSVER}.lk 2>/dev/null |\
		 tail -1 | sed 's/\.lk//')`

	[ "$CURSUB" ] && 
	{
		NEWREV=`expr "$NEWSUB" : '.*\([0-9][0-9]\)...'`
		CURREV=`expr "$CURSUB" : '.*\([0-9][0-9]\)...'`
		
		[ $CURREV -gt $NEWREV ] && return 0

		[ $CURREV -eq $NEWREV -a ! "$UPDATE_DUPATCH" ] && return 0

     
		[ "$PATCH_DEBUG" ] &&
			echo "\n=== utility update NEW: $NEWREV  CUR: $CURREV"
	}



	[ `id -u` -ne "0" ] &&
	{
		echo "
	Patch tools need to be installed or updated on your system.
	Please invoke the command as the super-user (root) first.
" | tee -a $_SLOG
		return 1	
	}

	STR1="."
 	STR2=""
	[ $_ROOT = / ] || 
	{
		STR1=" relative to $_ROOT."
		STR2="$_ROOT"
	}

        echo "
	* A new version of patch tools required for patch management 
	  is now being installed on your system$STR1" | tee -a $_SLOG

	SETLD_LOC=/usr/sbin
	[ -f $_KIT_TOP/patch_tools/setld ] &&
		SETLD_LOC=$_KIT_TOP/patch_tools


        [ "$PATCH_DEBUG" ] &&
	{
        	$SETLD_LOC/setld $_ALTROOT -l $TOOLDIR $NEWSUB ||
               	 P_Ferror 1 "\nFailed to update patch tools."
	}

        [ "$PATCH_DEBUG" ] ||
	{
        	$SETLD_LOC/setld $_ALTROOT -l $TOOLDIR $NEWSUB > /dev/null || 
               	 P_Ferror 1 "\nFailed to update patch tools."
	}

	echo "
	* Tools updated, invoking the updated Patch Utility...  " | tee -a $_SLOG

	_TOOLS_UPDATED=1; export _TOOLS_UPDATED

	_DUPATCH_EXEC=Y; export _DUPATCH_EXEC
	exec $STR2/usr/sbin/$_PROG $_ALLARGS

	return $?
}



P_Usage ()
{
	case $1 in
	DELETE)
		echo "\nThe following is a description of the command line interface:"
		echo "\n$DELETE_USAGE"
		;;
	HELP)
		[ "$_SW_DATA_FILE" ] &&
			echo "$DATA_FILE_USAGE"

		[ "$_SW_PATCH_ID" ] &&
			P_ArgsPidMsg PATCH ALL

		[ "$_SW_PRODUCT_ID" ] &&
			P_ArgsPidMsg PRODUCT ALL

		[ "$_SW_REV" ] &&
			echo $_DUPATCH_REV

		[ "$_SW_ROOT_PATH" ] && 
			echo "$ROOT_PATH_USAGE"

		[ ! "$_SW_DATA_FILE" -a \
		  ! "$_SW_PATCH_ID" -a \
		  ! "$_SW_PRODUCT_ID" -a \
		  ! "$_SW_REV" -a \
		  ! "$_SW_ROOT_PATH" ] && 
		{

			TMP=/var/tmp/$_PROG.help
			unlink $TMP 2>/dev/null
			> $TMP || exit 1

			echo "$REV_USAGE" >> $TMP
			echo "$ALL_USAGE" >> $TMP
			echo "$DATA_FILE_USAGE" >> $TMP
			P_ArgsPidMsg PATCH ALL >> $TMP
			P_ArgsPidMsg PRODUCT ALL >> $TMP
			echo "$ROOT_PATH_USAGE" >> $TMP

			if [ "$_DISPLAY" ]; then
				$_DISPLAY $TMP
			else
				cat $TMP
			fi

			rm -f $TMP
		}
		;;
	INSTALL)	
		echo "\nThe following is a description of the command line interface:"
		echo "\n$INSTALL_USAGE"
		;;
	TRACK)	
		echo "\nThe following is a description of the command line interface:"
		echo "\n$TRACK_USAGE"
		;;
	*)	echo "\n$ALL_USAGE"	
	esac
	
	return 0
}




P_TransPath ()
{
	RPATH=$1

	STR=`echo $RPATH | sed 's/^\.//'`
	if [ "$_ROOT" = / ]; then
		echo $STR
	else
		echo $_ROOT/$STR
	fi
}



P_ValidProd ()
{
	
	_VALIDPROD=

	[ "$_TYPE" = DELETE ] &&
	{
		P_PatchesAvailable lk $_SMDB VP_SUBS MSG || return 1

		P_SelSysProds lk N $VP_SUBS

	}

	for PV in $_PVS
	{
		eval PROD=\$_PNAME$PV
		_VALIDPROD="$_VALIDPROD $PROD"
	}

	[ "$_VALIDPROD" ] ||
	{
		ERROR=1 
		P_Error " 
There are no patches available for this operation."

		return 1
	}

	return 0
}


# @(#)$RCSfile: share.sh,v $ $Revision: 1.1.2.3 $ (DEC) $Date: 2002/01/15 17:19:19 $
GetSubDesc ()
{

	SDESC=

	case $3 in
	Y)
		SDESC=`S_GetSubDesc $1 $2 STRIP_CAT STRIP_TEXT`
		;;
	*)
		SDESC=`S_GetSubDesc $1 $2 KEEP_CAT KEEP_TEXT`
		;;
	esac

        echo "$SDESC"

	return 0
}


S_ApplicableDeps ()
{
	LIST=$*

	DLIST=
	for K in $LIST
	{
		SUBS=`echo $K | sed 's/:/ /g'`
		for S in $SUBS 
		{
			P=`expr "$S" : '^\(...\).*'`
			V=`expr "$S" : '.*\(...\)$'`
			
			ls ./usr/.smdb./$P*$V.lk > /dev/null 2>&1 &&
			{
				DLIST="$DLIST $S"
				
				break
			}
		}
	}

	echo $DLIST

	return 0
}



S_GetSubDesc ()
{
	SUB=$1
	LOC=$2
	CAT=$3
	TEXT=$4
	HIST=$5

	case $_TYPE in
	INSTALL|BASELINE)	
		PRODMAP=$_KIT_PRODMAP		# install / baseline
		;;
	DOC)	PRODMAP=$_DOC_PRODMAP
		;;
	*)	PRODMAP=$_SYS_PRODMAP		# delete / track
		;;
	esac
  
	if [ ${PRODMAP} ]; then
	ak=1  		# do nothing
	else
	{
		if [ ${_PATCHDIR} ]; then
		{
			PRODMAP="$_PATCHDIR/product_map"
		}
		else
		{
			if [ ${_ROOT} ]; then
				PRODMAP="$_ROOT/var/adm/patch/product_map"
			else
				PRODMAP="/var/adm/patch/product_map"
			fi
		}
		fi
	}
	fi

	SDESC=

	if [ -f $LOC/$SUB.ctrl ]; then
	{ 
		eval `grep DESC= $LOC/$SUB.ctrl`

		SDESC=$DESC
		[ "$CAT" = STRIP_CAT ] && 
			SDESC=`echo "$DESC" | sed 's/%.*//' | sed 's/ $//'`
	}  # new - ask 10/6/98
	else
	{
		TEXT=STRIP_TEXT
	}
	fi   # end new 

	case "$SUB" in
	???PAT?[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])
		PCODE=`expr $SUB : '^\(...\).*$'`	# product code
		VCODE=`expr "$SUB" : '^.*\(...\)$'`	# version code 
		BASE=`expr "$SUB" : '^...\(.*\)...$'`	# w/o p/vcode

		PID=`echo $BASE | cut -b 5-9'`  	# id
		PREV=`echo $BASE | cut -b 10-11'`  	#  rev

		
		case "$SUB" in
		???PAT${_CSPC}[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])
			PID="$_CSPC $PID"
			;;
		*)
			PID="  $PID"
			;;
		esac

		if [ \( "$TEXT" = STRIP_TEXT \) -o \( "$HIST" = hist \) ];  then
			SDESC="Patch $PID.$PREV"
		else
			SDESC=`echo "$SDESC" | sed 's/^Patch:/Patch '"$PID"'.'$PREV' -/'`
		fi

		PNAME=
		[ "$PRODMAP" -a -f $PRODMAP ] &&
			PNAME=`S_ProdmapGet name $PRODMAP $PCODE $VCODE`
	
		[ "$PNAME" ] ||
		{
			[ "$SDESC" ] || SDESC="$SUB"
			echo "$SDESC"
			return 0
		}

		[ "$HIST" = hist ] ||
		{
			if [ "$CAT" = STRIP_CAT ]; then
			{
				SDESC="$PNAME $SDESC"
			}
			else
			{
                        	if `echo $SDESC | egrep -q %`; then
					SDESC=`echo $SDESC | sed "s=%=%$PNAME / ="`
                        	else
					SDESC=`echo $SDESC | sed "s/$/%$PNAME/"`
                        	fi

			}
			fi
		}
		;;

	*)
     		[ "$SDESC" ] || {
			PCODE=`expr $SUB : '^\(...\).*$'`       # product code
                	VCODE=`expr "$SUB" : '^.*\(...\)$'`     # version code
               		PNAME=
                	[ "$PRODMAP" -a -f $PRODMAP ] &&
                        	PNAME=`S_ProdmapGet name $PRODMAP $PCODE $VCODE`
			[ "$PNAME" ] &&
				SDESC="$PNAME"" - subset: $SUB"
		}	
        	;;     
	esac

	[ "$SDESC" ] || SDESC="$SUB"
	echo "$SDESC"

	return 0
}


S_ListPatches ()
{(
        SUBS=$*

	LTMP1=$_DUPATCH_TMP/listpatches.tmp1
	LTMP2=$_DUPATCH_TMP/listpatches.tmp2

	>$LTMP1

	S_Order other $SUBS	

	for PV in $PVS
	{
		case "$_TYPE" in
		INSTALL|BASELINE)
                	eval LOC=\$_INSTDIR$PV
			;;
		DOC)	
			LOC=$_DOC_INSTDIR
			;;
		*)				# delete / track
			LOC=$_SMDB
			;;
		esac

		eval SLIST=\$SUBS$PV
		for S in $SLIST
		{
                	DESC=`S_GetSubDesc $S $LOC KEEP_CAT KEEP_TEXT` 	
			echo "$DESC@$S" >> $LTMP1
		}
	}

	if [ `Length $SUBS` = 1 ]; then
	{
		cp $LTMP1 $LTMP2
	}
	else
	{	
		>$LTMP2

        	S_MenuSort $LTMP1 $LTMP2 
		rm -f $LTMP1
	}
	fi

	_EXTRA_OPERATION=list; export _EXTRA_OPERATION

	NO_LINECNT=
	[ "$_CMDLINE" ] &&
		NO_LINECNT="-n"

        if [ -z "${TRIM}" ]; then
        ./usr/lbin/patmenu -l $NO_LINECNT -s display $LTMP2
        else
        {
                echo ""
                AK=`cat $LTMP2 | awk -F@ '{print $1}'`
                AK1=`echo $AK | awk -F% '{print $2}'`
                AK2=`echo $AK | awk -F% '{print $1}'`
                echo " - $AK1"
                echo "        $AK2"
                echo ""
        }
        fi

	rm -f $LTMP1 $LTMP2

        return 0

)}




S_MenuSort ()

{(
	IN=$1
	OUT=$2

	>$OUT	# make sure OUT is empty...

	[ -s $IN ] || return 0


        grep % $IN | sort -t% +1 -2 > $OUT

        grep -v % $IN | sort >> $OUT

	return 0
)}




S_Order ()
{
	OP=$1; shift
	O_SUBS=$*

	[ `Length $O_SUBS` = 1 ] &&
	{
		PV=`echo $O_SUBS | sed 's/^\(...\).*\(...\)$/\1\2/'`

		case $OP in
		install | delete)
			_PVS=$PV
			eval _SLIST$PV='$O_SUBS'
			;;
		other)
			PVS=$PV
			eval SUBS$PV='$O_SUBS'
			;;
		esac 

		return 0 
	} 

	LTMP1=$_DUPATCH_TMP/order.tmp1

	>$LTMP1
	for S in $O_SUBS
	{
		echo $S >> $LTMP1
	}	

	PVS=`cat $LTMP1 | sed 's/^\(...\).*\(...\)$/\1\2/' | sort -u`	

	for PV in $PVS
	{

		[ `Length $PVS` -eq 0 ] ||
		{
			P=`expr "$PV" : '^\(...\)'`
			V=`expr "$PV" : '.*\(...\)$'`
			O_SUBS=`egrep '^'$P'.+'$V'$' $LTMP1`
		}

		case $OP in
		install) 
			eval INSTCTRL=\$_INSTDIR$PV
                        O_SUBS=`(cd $INSTCTRL; $_ROOT/usr/lbin/depord $O_SUBS)`
			eval _SLIST$PV='$O_SUBS'
			;;

		delete)	 
			O_SUBS=`GetDeleteOrder $O_SUBS`
	                RC=$?

                        [ $RC != 0 ] &&
                        {
				echo "An error occurred in examining patches for deletion.  Please contact your Customer"
				echo "Service Representative for assistance."
				echo "Patches will not be removed.  dupatch terminating."
				P_Exit 1
			}

			eval _SLIST$PV='$O_SUBS'
			;;
		other)
			eval SUBS$PV='$O_SUBS'
			;;
		esac

	}

	rm -f $LTMP1

	[ "$OP" = other ] && return 0


	_PVS=$PVS

	return 0
}


S_ProdmapGet ()
{(
	TYPE=$1
	PRODMAP=$2

	[ -s "$PRODMAP" ] ||
	{
		echo "product_map does not exist or is empty, can not continue."
		exit 1
	}

	case $TYPE in
	whole | name | desc)
		P=$3
		V=$4

		ENTRY=`egrep "%$P%$V%" $PRODMAP| head -1`
		;;
	pvcode)
		NAME=$3
		ENTRY=`egrep -i "^$NAME%" $PRODMAP| head -1`
		;;
	esac

	case $TYPE in
	whole)
		echo $ENTRY
		;;
	name)
		echo $ENTRY | awk -F% '{print $1}'
		;;
	desc)
		echo $ENTRY | awk -F% '{print $4}' | sed 's/\"//g'
		;;
	pvcode)	
		echo $ENTRY | awk -F% '{print $2$3}'
	esac

	case $TYPE in
	vname)
		echo $ENTRY | awk -F% '{print $5}'
		;;
	svname)
		echo $ENTRY | awk -F% '{print $6}'
		;;
	kitpre)
		echo $ENTRY | awk -F% '{print $7}'
		;;
	esac

	return 0
)}
[ "$CHECK_SYNTAX" ] || Main $@
