# This script initializes the backout data for a patch package
# directory format options.
# 
#pragma ident	"@(#)preinstall	1.22	09/06/26 SMI"
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

# Definitions for override safety mechanism
PATCH_OVERRIDE_LIB="${PKG_INSTALL_ROOT}/usr/lib/patch/patch_override_lib"

# script in a fucntion so that it can be overridden if needed - generic
preinstall_deflt()
{
	PATH=/usr/sadm/bin:$PATH
	recovery="no"

	if [ "$PKG_INSTALL_ROOT" = "/" ]; then
		PKG_INSTALL_ROOT=""
	fi

	# Check to see if this is a patch installation retry.
	if [ "$INTERRUPTION" = "yes" ]; then
	    if [ -d "$PKG_INSTALL_ROOT/var/tmp/$SUNW_PATCHID.$PKGINST" ] || [ -d "$PATCH_BUILD_DIR/$SUNW_PATCHID.$PKGINST" ]; then
	        recovery="yes"
	    fi
	fi

	if [ -n "$PATCH_BUILD_DIR" -a -d "$PATCH_BUILD_DIR" ]; then
		BUILD_DIR="$PATCH_BUILD_DIR/$SUNW_PATCHID.$PKGINST"
	else
		BUILD_DIR="$PKG_INSTALL_ROOT/var/tmp/$SUNW_PATCHID.$PKGINST"
	fi

	FILE_DIR=$BUILD_DIR/files
	RELOC_DIR=$BUILD_DIR/files/reloc
	ROOT_DIR=$BUILD_DIR/files/root
	PROTO_FILE=$BUILD_DIR/prototype
	ORIGPKGINFO=$PKG_INSTALL_ROOT/var/sadm/pkg/$PKGINST/pkginfo
	PKGINFO_FILE=$BUILD_DIR/pkginfo
	THIS_DIR=`dirname $0`
	INSTALLINGPKGINFO="`dirname $SCRIPTS_DIR`/pkginfo"

	#
	# Unless specifically denied, initialize the backout patch data by
	# creating the build directory and copying over the original pkginfo
	# which pkgadd saved in case it had to be restored.
	#
	if [ "$PATCH_NO_UNDO" != "true" ] && [ "$recovery" = "no" ]; then
		if [ -d $BUILD_DIR ]; then
			rm -r $BUILD_DIR
		fi

		# If this is a retry of the same patch then recovery is set to
		# yes. Which means there is a build directory already in
		# place with the correct backout data.

		if [ "$recovery" = "no" ]; then
			mkdir $BUILD_DIR
			mkdir -p $RELOC_DIR
			mkdir $ROOT_DIR
		fi

		#
		# Here we initialize the backout pkginfo file by first
		# copying over the old pkginfo file and then adding the
		# ACTIVE_PATCH parameter so the backout will know what patch
		# it's backing out.
		#
		# NOTE : Within the installation, pkgparam returns the
		# original data.
		#
		pkgparam -v $PKGINST | nawk '
			$1 ~ /PATCHLIST/	{ next; }
			$1 ~ /CLASSES/		{ next; }
			$1 ~ /PATCH_OBSOLETES/	{ next; }
			$1 ~ /ACTIVE_OBSOLETES/	{ next; }
			$1 ~ /SUNW_OBSOLETES/	{ next; }
			$1 ~ /ACTIVE_PATCH/	{ next; }
			$1 ~ /SUNW_PATCHID/	{ next; }
			$1 ~ /UPDATE/       { next; }
			$1 ~ /SCRIPTS_DIR/	{ next; }
			$1 ~ /PATCH_NO_UNDO/	{ next; }
			$1 ~ /INSTDATE/		{ next; }
			$1 ~ /PKGINST/		{ next; }
			$1 ~ /OAMBASE/		{ next; }
			$1 ~ /PATH/		{ next; }
			{ print; } ' | sed s,\'\"\'\"\',ApOsTrOpHe,g > $PKGINFO_FILE

	        # The previous is needed to workaround pkgparam
	        # inserting '"'"' for every ' it finds in the
	        # pkginfo file. see bugid 4052001.

		# If there is an undo script delivered with this patch pkg
		# there is a possibility that when the patch gets backed out
		# it may not get executed due to the CLASSES macro in the
		# original pkginfo not containing the class
		# identifier. Thus we need to merge the old CLASSES macro and
		# the installing patch pkgs CLASSES macro.

		nawk ' $1 ~ /CLASSES/ {print $0} ' $ORIGPKGINFO \
			| sed s/CLASSES=// > /tmp/installingCLASSES.$$
	 
		classIDs=`nawk ' $1 ~ /CLASSES/ {print $0} ' $INSTALLINGPKGINFO \
			| sed s/CLASSES=//`
	 
		for instClass in $classIDs; do
			notFound=`grep "$instClass" /tmp/installingCLASSES.$$`
			if [ -z "$notFound" ]; then
				newCLASSESlist="$instClass $newCLASSESlist"
			fi
			notFound=""
		done
	 
		classes=`nawk ' $1 ~ /CLASSES/ {print $0} ' $ORIGPKGINFO`  
		newCLASSESlist="$classes $newCLASSESlist"  
		
		echo "$newCLASSESlist" >> $PKGINFO_FILE
		echo "ACTIVE_PATCH=$SUNW_PATCHID" >> $PKGINFO_FILE
		echo "ACTIVE_OBSOLETES=$ACTIVE_OBSOLETES" >> $PKGINFO_FILE

		rm /tmp/installingCLASSES.$$

		# And now initialize the backout prototype file with the
		# pkginfo file just formulated.
		echo "i pkginfo" > $PROTO_FILE

		# Copy over the backout scripts including the undo class
		# action scripts
		for script in $SCRIPTS_DIR/*; do
			srcscript=`basename $script`
			targscript=`echo $srcscript | nawk '
				{ script=$0; }
				/u\./ {
					sub("u.", "i.", script);
					print script;
					next;
				}
				/patch_/ {
					sub("patch_", "", script);
					print script;
					next;
				}
				{ print "dont_use" } '`
			if [ "$targscript" = "dont_use" ]; then
				continue
			fi

			echo "i $targscript=$FILE_DIR/$targscript" >> $PROTO_FILE
			cp $SCRIPTS_DIR/$srcscript $FILE_DIR/$targscript
		done

		#
		# Now add entries to the prototype file that won't be passed to
		# class action scripts. If the entry is brand new, add it to the
		# deletes file for the backout package.
		#
		Our_Pkgmap=`dirname $SCRIPTS_DIR`/pkgmap
		BO_Deletes=$FILE_DIR/deletes

		#
		# Adding hard link entries into the proto file.
		#
		nawk -v basedir=${BASEDIR:-/} '
			{
	                        ftype = $1;
	                }
	                $1 ~ /[0123456789]/ {
	                        if ( NF >= 3) {
	                                ftype = $2;
	                        } else {
	                                next;
	                        }
	                }
			{
				if (ftype == "l") { print $0; }
				else { next; }
			}
			' < $Our_Pkgmap 1>> $PROTO_FILE 2> /dev/null

		nawk -v basedir=${BASEDIR:-/} '
			BEGIN { count=0; }
			{
				token = $2;
				ftype = $1;
			}
			$1 ~ /[#\!:]/ { next; }
			$1 ~ /[0123456789]/ {
				if ( NF >= 3) {
					token = $3;
					ftype = $2;
				} else {
					next;
				}
			}
			{ if (ftype == "l" || ftype == "i" || ftype == "e" || ftype == "f" || ftype == "v" || ftype == "d") { next; } }
			{
				equals=match($4, "=")-1;
				if ( equals == -1 ) { print $3, $4; }
				else { print $3, substr($4, 0, equals); }
			}
			' < $Our_Pkgmap | while read class path; do
				#
				# If this isn't replacing something, then it
				# just goes to the deletes list.
				#
				if valpath -l $path; then
					Chk_Path="$BASEDIR/$path"
					Build_Path="$RELOC_DIR/$path"
					Proto_From="$BASEDIR"
				else	# It's an absolute path
					Chk_Path="$PKG_INSTALL_ROOT$path"
					Build_Path="$ROOT_DIR$path"
					Proto_From="$PKG_INSTALL_ROOT"
				fi

				# If we're up against a file system that can't be
				# written to, skip adding the link to the backout
				# package. Check the links parent directory for
				# writablility. If the parent directory does
				# not exist yet, check its parent directory until
				# the parent directory is $BASEDIR or
				# $PKG_INSTALL_ROOT

				dirPath=`dirname "$Chk_Path"`

				while [ "$dirPath" != "$Proto_From" ]; do
					# If path doesn't exist check parent path
					if valpath -n $dirPath; then
						dirPath=`dirname "$dirPath"`
					else
						break
					fi
				done

				if [ "$dirPath" != "$Proto_From" ]; then
					/usr/bin/touch $dirPath/.testpatchadd.$$ \
						> /dev/null 2>&1
					if [ $? !=  0 ]; then
						continue
					fi
					rm -f $dirPath/.testpatchadd.$$
				fi

				if [ -f "$Chk_Path" -a ! -h "$Chk_Path" ] ; then
					mkdir -p `dirname $Build_Path`
					cp -p $Chk_Path $Build_Path
					cd $Proto_From
					pkgproto -c $class "$Build_Path=$path" 1>> $PROTO_FILE 2> /dev/null
					cd $THIS_DIR
				elif [ -h "$Chk_Path" -o \
				     -c "$Chk_Path" -o \
				     -b "$Chk_Path" -o \
				     -p "$Chk_Path" ]; then
					pkgproto -c $class "$Chk_Path=$path" \
						1>> $PROTO_FILE 2> /dev/null
				else
					echo $path >> $BO_Deletes
				fi
			done
	fi
}

# script in a fucntion so that it can be overridden if needed - particular
preinstall_merge()
{
	# If additional operations are required for this package, place
	# those package-specific commands here.

	#XXXSpecial_CommandsXXX#
	:
}

# load the override lib if it exists
if [ -f "${PATCH_OVERRIDE_LIB}" -a -r "${PATCH_OVERRIDE_LIB}" ] ; then
   . "${PATCH_OVERRIDE_LIB}"
fi

# execute the script functions
preinstall_deflt "$@"
preinstall_merge "$@"

exit 0
