# This script initializes the backout data for a patch package
# directory format options.
# 
#pragma ident	"@(#)preinstall	1.26	11/05/30 SMI"
#
# Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
#

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

# Check if we messaging is ready. Returns 0 on success, 1 on failure
# On successful run it leaves MSG_FILENAME variable defined
# 
# Usage:
#
# check_patch_script_messaging
#
check_patch_script_messaging()
{
	TMP_DIRNAME="/var/run"
	MSG_FILENAME="${TMP_DIRNAME}/patchadd_msg_file_${SUNW_PATCHID}"

	if [ -w "${MSG_FILENAME}" ] ; then
		unset TMP_DIRNAME
		return 0
	else
		unset TMP_DIRNAME
		unset MSG_FILENAME
		return 1
	fi
}

# This function prepares a message to be printed to stdout towards the end
# of postpatch execution. If the message file is not ready, it at least tries
# immediate output to stdout which is currently know to work only in patch
# level scripts.
#
# Usage:
#
# print_patch_message "text_of_message_to_be_printed_out"
#
print_patch_message()
{
	if check_patch_script_messaging; then
		echo "$*" >> "${MSG_FILENAME}"
	else
		echo "$*"
	fi

	return 0
}

# 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

		rm -rf "$BUILD_DIR"
		mkdir -m 700 "$BUILD_DIR"
		if [ $? -ne 0 ]; then
			print_patch_message \
			    "Failed to make directory $BUILD_DIR"
			exit 1
		fi

		mkdir -p "$RELOC_DIR"
		mkdir -p "$ROOT_DIR"

		#
		# 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

		/usr/bin/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

		nawk  ' {
				token = $2;
				ftype = $1;
			}
			$1 ~ /[#\!:]/ { next; }
			$1 ~ /[0123456789]/ {
				if ( NF >= 3) {
					token = $3;
					ftype = $2;
				} else {
					next;
				}
			}
			{ if (ftype == "i" || ftype == "e" || ftype == "f" || ftype == "v" || ftype == "d") { next; } }
			{
				equals=match($4, "=")-1;
				if ( equals == -1 ) { print ftype, $3, $4; }
				else { print ftype, $3, substr($4, 0, equals); }
				print $0
			}
			' < $Our_Pkgmap | while read type class path; do
				# 
				# Read the whole line from pkgmap
				# We may need to propagate it into our 
				# prototype if it is already existing hard link
				#	
				read pline

				#
				# If this isn't replacing something, then it
				# just goes to the deletes list.
				#
				
				# Checking whether path is absolute or relative
				if echo "$path" | grep '^/' 2>&1 1>/dev/null ; then
					# It's an absolute path
					Chk_Path="$PKG_INSTALL_ROOT$path"
					Build_Path="$ROOT_DIR$path"
					Proto_From="$PKG_INSTALL_ROOT"
				else
					Chk_Path="$BASEDIR/$path"
					Build_Path="$RELOC_DIR/$path"
					Proto_From="$BASEDIR"
				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
					# We use ls here because [ -e $dirPath ]
					# is not supported in /bin/sh
					/usr/bin/ls "$dirPath" 1>/dev/null 2>&1
					if [ "$?" != 0 ]; 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
					/usr/bin/rm -f "$dirPath/.testpatchadd.$$"
				fi

				if [ "$type" = 'l' ] ; then
					# If hardlink already exists we put it
					# into proto_file otherwise it goes
					# into deletes
					/usr/bin/ls "$Chk_Path" 1>/dev/null 2>&1
					if [ "$?" != 0 ]; then
						echo "$path" >> $BO_Deletes
					else
						echo "$pline" >> $PROTO_FILE
					fi
				elif [ -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#
#
# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
#
# ident	"@(#)preinstall	1.2	14/03/27 SMI"

# If we are now installing scheduler on this system for the first
# time, we will need to call svcadm to enable the new service. We
# must not do this if scheduler is already installed, as the user may
# have intentionally disabled it. Here we touch scheduler.tmp as a
# way of telling our matching postinstall script that it should
# update /var/svc/profile/upgrade.

rm -f $BASEDIR/var/run/scheduler.tmp
if [ ! -f $BASEDIR/var/svc/manifest/system/scheduler.xml ] ; then
	touch $BASEDIR/var/run/scheduler.tmp
fi
	:
}

# 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
