# This script creates the backout package for a patch package
#
# directory format options.
#
#pragma ident	"@(#)postinstall	1.26_patchable	09/02/18 SMI"
#
# Copyright 2008 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
postinstall_deflt()
{
# Description:
#       Set the TYPE parameter for the remote file
#
# Parameters:
#       none
#
# Globals set:
#	TYPE
#

set_TYPE_parameter () {
	if [ ${PATCH_UNDO_ARCHIVE:?????} = "/dev" ]; then
		# handle device specific stuff
		TYPE="removable"
	else
		TYPE="filesystem"
	fi
}

#
# Description:
#       Build the remote file that points to the backout data
#
# Parameters:
#       $1:	the un/compressed undo archive
#
# Globals set:
#	UNDO, STATE

build_remote_file () {
	remote_path=$PKGSAV/$SUNW_PATCHID/remote
	set_TYPE_parameter
	STATE="active"

	if [ $1 = "undo" ]; then
		UNDO="undo"
	else
		UNDO="undo.Z"
	fi

	cat > $remote_path << EOF
# Backout data stored remotely
TYPE=$TYPE
FIND_AT=$ARCHIVE_DIR/$UNDO
STATE=$STATE
EOF
}

SED="/usr/bin/sed"
CP="/usr/bin/cp"
MV="/usr/bin/mv"
POSTINSTALL_ERR_LOG="$PKG_INSTALL_ROOT/var/run/$SUNW_PATCHID.postinstall_log.$$"
RET_STATUS=0

PATH=/usr/sadm/bin:$PATH
PATCH_COMMON_LIB="/usr/lib/patch/patch_common_lib"
SAFEMODE_FAILED="Exiting! Patch deferred activation failed"

# Set LC_ALL to avoid risk of undefined behavior
LC_ALL=C
export LC_ALL

if [ "$SAFEMODE_INSTALL" = "true" ] ; then
	if [ ! -s "$PATCH_COMMON_LIB" ]; then
		puttext "$SAFEMODE_FAILED"
		exit 1
	fi
	. $PATCH_COMMON_LIB
	InitSafemode || {
		puttext $SAFEMODE_FAILED
		exit 1
	}
fi

if [ "$PKG_INSTALL_ROOT" = "/" ]; then
	PKG_INSTALL_ROOT=""
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

if [ ! -n "$PATCH_UNDO_ARCHIVE" ]; then
	PATCH_UNDO_ARCHIVE="none"
fi

FILE_DIR=$BUILD_DIR/files
RELOC_DIR=$FILE_DIR/reloc
ROOT_DIR=$FILE_DIR/root
BO_Deletes=$FILE_DIR/deletes
THIS_DIR=`dirname $0`
PROTO_FILE=$BUILD_DIR/prototype
TEMP_REMOTE=$PKGSAV/$SUNW_PATCHID/temp

if [ "$PATCH_PROGRESSIVE" = "true" ]; then
        # remove the scripts that are left behind
        install_scripts=`dirname $0`
        rm $install_scripts/checkinstall $install_scripts/patch_checkinstall $install_scripts/patch_postinstall

	# If this is being used in an old-style patch, insert
	# the old-style script commands here.

	#XXXOld_CommandsXXX#

	exit 0
fi

# If patch includes pkg_* scripts, deliver them into the pspool area
#
PSPOOL_PKG="/var/sadm/pkg/$PKGINST/save/pspool/$PKGINST"

if [ -d "$PKG_INSTALL_ROOT$PSPOOL_PKG/install" ] ; then
	for script in $SCRIPTS_DIR/*; do
		srcscript=`basename $script`
		targscript=`echo $srcscript | nawk '
			{ script=$0; }
			/pkg_/ {
				print "pspool";
				next;
			}
			{ print "dont_use" } '`
		if [ "$targscript" = "dont_use" ]; then
			continue
		fi
		if [ "$targscript" = "pspool" ]; then
			# If the target script is a pspool script, then we need
			# to do the following:
			#	1) If the script is delivered for the first time
			#	   then add it to the deletes file of the undo
			#	   package.
			#	2) Else backup the script in the undo package,
			#	   replace the script and update the undo packag
			#	   prototype file.
			script=`echo $srcscript | $SED 's/pkg_//'`
			[ "$PATCH_NO_UNDO" != "true" ] && {
				if [ -f "$PKG_INSTALL_ROOT$PSPOOL_PKG/install/$script" ]; then
					$MV $PKG_INSTALL_ROOT$PSPOOL_PKG/install/$script $FILE_DIR/$srcscript
					echo "i $srcscript=$FILE_DIR/$srcscript" >> $PROTO_FILE
				else
					echo "$PSPOOL_PKG/install/$script" >> $BO_Deletes
				fi
			}
			$CP $SCRIPTS_DIR/$srcscript $PKG_INSTALL_ROOT$PSPOOL_PKG/install/$script
		fi
	done
fi

#
# At this point we either have a deletes file or we don't. If we do,
# we create a prototype entry.
#
if [ -f $BO_Deletes ]; then
	echo "i deletes=$BO_Deletes" >> $BUILD_DIR/prototype
fi

if [ -f $BUILD_DIR/pkginfo ] ; then
	/usr/bin/grep "^SUNW_PATCH_SAFE_MODE=" $SCRIPTS_DIR/../pkginfo >> \
	    $BUILD_DIR/pkginfo
fi 

#
# Now delete everything in the deletes list after transferring
# the file to the backout package and the entry to the prototype
# file. Remember that the pkgmap will get the CLIENT_BASEDIR path
# but we have to actually get at it using the BASEDIR path. Also
# remember that removef will import our PKG_INSTALL_ROOT
#
# If this is a safemode patch package and it has a deletes file in it
# then handle the deletion of an object for safemode patching.
#
Our_Deletes=$THIS_DIR/deletes
if [ -f $Our_Deletes ]; then
	PSPOOL_DIR="/var/sadm/pkg/$PKGINST/save/pspool/$PKGINST/install"
	UNREGISTER_LIST=/var/run/.$$.unregister.paths.$$
	UNREGISTER_BATCH=/var/run/.$$.unregister.batch.$$
	/usr/bin/rm -f $UNREGISTER_LIST

	cd $BASEDIR
	cat $Our_Deletes | while read path; do
		# If this patch is deleting any pspool script, then the
		# deleted file would have any entry for the script
		# relative to the PKG_INSTALL_ROOT. We have to parse it
		# and process it as follows.
		#	1) build the complete path.
		#	2) move the file to undo package.
		#	3) Add it to the prototype file of undo package.
		Dir=`/usr/bin/dirname $path`
		if [ "$Dir" = "$PSPOOL_DIR" ]; then
			path="${PKG_INSTALL_ROOT:-/}$path"
			if [ -f $path ]; then
				filename=`/usr/bin/basename $path`
				spoolname="pkg_$filename"
				spoolfile="$FILE_DIR/$spoolname"
				mv -f $path $spoolfile
				echo "i $spoolname=$spoolfile" >> $BUILD_DIR/prototype
			fi
			continue;
		fi
		Reg_File=0

		if valpath -l $path; then
			Client_Path="$CLIENT_BASEDIR/$path"
			Build_Path="$RELOC_DIR/$path"
			Proto_Path=$BASEDIR/$path
		else	# It's an absolute path
			Client_Path=$path
			Build_Path="$ROOT_DIR$path"
			Proto_Path=$PKG_INSTALL_ROOT$path
		fi

		# If BASEDIR/CLIENTBASEDIR = "/", then the previous prepends
		# an extra / i.e. //. The sed command later can't find a
		# Proto_Path with // and therefore will not substitute the
		# correct build_Path resulting in the backout pkg not being
		# created.

		if [ "$CLIENT_BASEDIR" = "/" ]; then
			Client_Path=`echo $Client_Path | sed 's|^\/\/|\/|'`
			Proto_Path=`echo $Proto_Path | sed 's|^\/\/|\/|'`
		fi
			
		# Note: If the file isn't really there, pkgproto
		# doesn't write anything but displays an error
		# so check for the file before processing.

		if [ -f "$Proto_Path" ]; then
			LINE=`pkgproto $Proto_Path=$path`
		else
			continue
		fi

		ftype=`echo $LINE | nawk '{ print $1 }'`
		if [ "$ftype" = "f" ]; then
			Reg_File=1
		fi

		if [ $Reg_File = 1 ]; then
			# Add source file to the prototype entry
			if [ "$Proto_Path" = "$path" ]; then
				LINE=`echo $LINE | sed -e "s|$Proto_Path|$Build_Path|2"`
			else
				LINE=`echo $LINE | sed -e "s|$Proto_Path|$Build_Path|"`
			fi

			DirName=`dirname $Build_Path`
			# make room in the build tree
			mkdir -p $DirName
			cp -p $Proto_Path $Build_Path
		fi

		# Insert it into the prototype file
		echo $LINE 1>>$PROTO_FILE 2>/dev/null
		echo "$Client_Path" >> $UNREGISTER_LIST
	done

	# We need to group the deletes entries for performance reasons. Only 100
	# entries are taken in a single batch, since we don't want to exceed the
        # number of arguments passed during removef program invocation, and 
        # 100 seems to a good tradeoff.

	batch_start_line=1
	batch_end_line=100

	if [ -s "$UNREGISTER_LIST" ]; then
		while [ 1 ] ; do
			/usr/bin/sed -n "$batch_start_line,$batch_end_line p" $UNREGISTER_LIST > $UNREGISTER_BATCH
			[ -s $UNREGISTER_BATCH ] || break
			if [ "$SAFEMODE_INSTALL" = "true" ]; then
				# Handle deletion of an object for safemode patching
				HandleSafemodeDeleteObject $PKGINST "`/usr/bin/tr '\n' ' ' < $UNREGISTER_BATCH`"
			else
				# Remove the file only if it's OK'd by removef
				/usr/sbin/removef $PKGINST `/usr/bin/tr '\n' ' ' < $UNREGISTER_BATCH` | while read path; do
					/usr/bin/rm "$path"
				done
			fi
			batch_start_line=`/usr/bin/expr $batch_start_line + 100`
			batch_end_line=`/usr/bin/expr $batch_end_line + 100`
		done
		/usr/sbin/removef -f $PKGINST
	fi
	/usr/bin/rm -f $UNREGISTER_LIST $UNREGISTER_BATCH

	rm $Our_Deletes
fi

#
# Unless specifically denied, make the backout package.
#
if [ "$PATCH_NO_UNDO" != "true" ]; then
	cd $BUILD_DIR	# We have to build from here.

	if [ "$PATCH_UNDO_ARCHIVE" != "none" ]; then
		STAGE_DIR="$PATCH_UNDO_ARCHIVE"
		ARCHIVE_DIR="$PATCH_UNDO_ARCHIVE/$SUNW_PATCHID/$PKGINST"
		mkdir -p $ARCHIVE_DIR
		mkdir -p $PKGSAV/$SUNW_PATCHID
	else
		if [ -d $PKGSAV/$SUNW_PATCHID ]; then
			rm -r $PKGSAV/$SUNW_PATCHID
		fi
		STAGE_DIR=$PKGSAV
		ARCHIVE_DIR=$PKGSAV/$SUNW_PATCHID
		mkdir $ARCHIVE_DIR
	fi

	ERR_LOG_DIR=`dirname $POSTINSTALL_ERR_LOG`
	if [ ! -d $ERR_LOG_DIR ]; then
		mkdir -p $ERR_LOG_DIR
	fi

	/usr/bin/pkgmk -o -d $STAGE_DIR 1>$POSTINSTALL_ERR_LOG 2>&1
	retcode=$?
	if [ "$retcode" != 0 ]; then
		echo "pkgmk(1) failed with error code $retcode" >> $POSTINSTALL_ERR_LOG
		echo "The $PKGINST backout package will not get created" >> $POSTINSTALL_ERR_LOG
		RET_STATUS=1
	else
		/usr/bin/pkgtrans -s $STAGE_DIR $ARCHIVE_DIR/undo $PKG 1>>$POSTINSTALL_ERR_LOG 2>&1
		retcode=$?
		if [ "$retcode" != 0 ]; then
			echo "pkgtrans(1) failed with error code $retcode" >> $POSTINSTALL_ERR_LOG
			echo "The $PKGINST backout package will not get created" >> $POSTINSTALL_ERR_LOG
			RET_STATUS=1
		else
			compress $ARCHIVE_DIR/undo
			retcode=$?
			if [ "$retcode" != 0 ]; then
				echo "compress(1) returned error code $retcode"
				echo "The $PKGINST backout package will not be compressed."
				echo "Continuing to process backout package."
			fi
			if [ "$PATCH_UNDO_ARCHIVE" != "none" ]; then
				if [ $retcode != 0 ]; then
					build_remote_file "undo"
				else
					build_remote_file "undo.Z"
				fi
			fi
		fi
	fi

	rm -r $STAGE_DIR/$PKG

	cd ..
	rm -r $BUILD_DIR
fi

# remove the scripts that are left behind
install_scripts=`dirname $0`
rm -f $install_scripts/checkinstall $install_scripts/patch_checkinstall $install_scripts/patch_postinstall $install_scripts/pkg_*

#
# Since this apparently worked, we'll mark as obsoleted the prior
# versions of this patch - installpatch deals with explicit obsoletions.
#
cd ${PKG_INSTALL_ROOT:-/}
cd var/sadm/pkg

active_base=`echo $SUNW_PATCHID | nawk '
	{ print substr($0, 1, match($0, "-")-1) } '`

List=`ls -d $PKGINST/save/${active_base}* 2>/dev/null`
if [ $? -ne 0 ]; then
	List=""
fi

for savedir in $List; do
        patch=`basename $savedir` 
        if [ $patch = $SUNW_PATCHID ]; then
		break
	fi

        # If we get here then the previous patch gets deleted
	if [ -f $savedir/undo ]; then
		mv $savedir/undo $savedir/obsolete
		echo $SUNW_PATCHID >> $savedir/obsoleted_by
	elif [ -f $savedir/undo.Z ]; then
		mv $savedir/undo.Z $savedir/obsolete.Z
		echo $SUNW_PATCHID >> $savedir/obsoleted_by
        elif  [ -f $savedir/remote ]; then
                `grep . $PKGSAV/$patch/remote | sed 's|STATE=.*|STATE=obsolete|' > $TEMP_REMOTE` 
                rm -f $PKGSAV/$patch/remote 
                mv $TEMP_REMOTE $PKGSAV/$patch/remote  
                rm -f $TEMP_REMOTE 
                echo $SUNW_PATCHID >> $savedir/obsoleted_by
	elif  [ -f $savedir/obsolete -o -f $savedir/obsolete.Z ]; then
		echo $SUNW_PATCHID >> $savedir/obsoleted_by
	fi
done

if [ "$RET_STATUS" != 0 ]; then
	cat $POSTINSTALL_ERR_LOG
	echo "Execution of postinstall encountered problems"
	echo "postinstall exited with 1"
	rm -f $POSTINSTALL_ERR_LOG
	exit $RET_STATUS
else
	rm -f $POSTINSTALL_ERR_LOG
fi
}

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

#XXXSpecial_CommandsXXX#

#!/bin/sh
#
# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# ident	"@(#)postinstall	1.1	08/12/02 SMI"
#

PATH="/usr/bin:/usr/sbin:${PATH}"
export PATH

HERMON_ALIAS="\
	\"pciex15b3,6340\" \
	\"pciex15b3,634a\" \
	\"pciex15b3,6732\" \
	\"pciex15b3,673c\" \
	"
DRVPERM='* 0666 root sys'

check_installed() {
	driver=$1
	grep "^${driver} " $BASEDIR/etc/name_to_major > /dev/null 2>&1
	return $?
}

EXIT=0

check_installed hermon || \
add_drv -b "${BASEDIR}" \
	-m "${DRVPERM}" \
	-i "${HERMON_ALIAS}" \
	hermon || \
EXIT=1

return 0
}

# 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
postinstall_deflt "$@"
postinstall_merge "$@"

exit 0
