# This class action script copies the files being replaced
# into a package being constructed in $BUILD_DIR. This class
# action script is only appropriate for regular files that
# are installed by simply copying them into place.
#
# For special package objects such as edittable files, the patch
# producer must supply appropriate class action scripts.
#
# directory format options.
#
#       @(#)i.script 1.15 04/04/08 SMI
#
# Copyright (c) 2004 by Sun Microsystems, Inc.
# All rights reserved
#

add_major()
{
	tmpfile=/tmp/nm.$$.tmp

	if [ -f $BASEDIR/etc/rem_name_to_major ]; then
		rem_file="$BASEDIR/etc/rem_name_to_major"
	fi

	sort +1 -2n $dst $rem_file | nawk '#
BEGIN	{oldmajor = -1}
NR == 1	{n=split(namelist,x)
	 if (n < 1)
	    exit(1)
	 for (i=1; i<=n; i++)
	    chklist[x[i]]++
	}
	{for (name in chklist)
	 {
	    if ($1 == name)
		delete chklist[name]
	 }
	 if (($2 - oldmajor) > 1)
	 {
	    gap++
	    gaplist[gap] = oldmajor " " $2;
	 }
	 oldmajor = $2;
	}
END	{addsize=1
	 for (name in chklist)
	    addlist[addsize++] = name
	
	 addidx = 1
	 for (i=1; i<=gap && addidx < addsize; i++)
	 {
	    split(gaplist[i],x)
	    begmajor = x[1]
	    endmajor = x[2]
	    for (begmajor++;begmajor < endmajor && addidx < addsize;)
	    {
		printf "%s %d\n",addlist[addidx],begmajor
		addidx++
		begmajor++
	    }
	 }
	 for (; addidx < addsize; addidx++)
	 {
	    oldmajor++
	    printf "%s %d\n",addlist[addidx],oldmajor
	 }
	}
' namelist="$*" - > $tmpfile

	if [ -s $tmpfile ]; then
		echo "Adding the following devices to $dst :"
		cat $tmpfile
		sort +1 -2n $dst $tmpfile -o $dst
	fi

	rm -f $tmpfile
}

#
# obsolete_sparc - Filter function to remove obsolete SPARC driver entries.
# We define an associative array of bad driver names, and then nawk out
# lines where the first token is defined in our array.
#
obsolete_sparc()
{
	nawk 'BEGIN {
		obs["rip"] = 1;
		obs["svloop"] = 1;
		obs["tcl"] = 1;
		obs["tco"] = 1;
		obs["tcoo"] = 1;
		obs["sp"] = 1;
		obs["consfb"] = 1;
		obs["XXunusedXX"] = 1;
		obs["sw"] = 1;
		obs["cgtwo"] = 1;
		obs["xy"] = 1;
		obs["xd"] = 1;
		obs["pc"] = 1;
		obs["app"] = 1;
		obs["evq"] = 1;
		obs["win"] = 1;
		obs["svarp"] = 1;
		obs["svip"] = 1;
		obs["svrip"] = 1;
		obs["svicmp"] = 1;
		obs["svudp"] = 1;
		obs["svtcp"] = 1;
		obs["vme"] = 1;
		obs["ie"] = 1;
		obs["ncr"] = 1;
		obs["xt"] = 1;
		obs["id"] = 1;
		obs["vmemem"] = 1;
		obs["pn"] = 1;
		obs["kmac"] = 1;
		obs["ipi3sc"] = 1;
		obs["cgfour"] = 1;
		obs["cgeight-p4"] = 1;
		obs["xdc"] = 1;
		obs["xyc"] = 1;
		obs["mcp"] = 1;
		obs["mcpzsa"] = 1;
		obs["mcpp"] = 1;
		obs["be"] = 1;
		obs["p9000"] = 1;
		obs["p9100"] = 1;
		obs["pci"] = 1;
		obs["profile"] = 1;
		obs["eeprom"] = 1;
	} !($1 in obs) { print $1, $2 }'
}

#
# obsolete_i386 - Filter function to remove obsolete i386 driver entries.
# We define an associative array of bad driver names, and then nawk out
# lines where the first token is defined in our array.
#
obsolete_i386()
{
	nawk 'BEGIN {
		obs["aha"] = 1;
		obs["aic"] = 1;
		obs["app"] = 1;
		obs["audiocs"] = 1;
		obs["blogic"] = 1;
		obs["chanmux"] = 1;
		obs["cmtp"] = 1;
		obs["corvette"] = 1;
		obs["csa"] = 1;
		obs["dsa"] = 1;
		obs["eepro"] = 1;
		obs["eha"] = 1;
		obs["el"] = 1;
		obs["elink"] = 1;
		obs["envm"] = 1;
		obs["esa"] = 1;
		obs["esa"] = 1;
		obs["iee"] = 1;
		obs["iss"] = 1;
		obs["kd"] = 1;
		obs["kdmouse"] = 1;
		obs["mc"] = 1;
		obs["mcis"] = 1;
		obs["nee"] = 1;
		obs["nei"] = 1;
		obs["nfe"] = 1;
		obs["p9000"] = 1;
		obs["p9100"] = 1;
		obs["pcaic"] = 1;
		obs["profile"] = 1;
		obs["riles"] = 1;
		obs["rip"] = 1;
		obs["smc"] = 1;
		obs["smce"] = 1;
		obs["smceu"] = 1;
		obs["smcf"] = 1;
		obs["sp"] = 1;
		obs["svarp"] = 1;
		obs["svicmp"] = 1;
		obs["svip"] = 1;
		obs["svloop"] = 1;
		obs["svrip"] = 1;
		obs["svtcp"] = 1;
		obs["svudp"] = 1;
		obs["tcl"] = 1;
		obs["tco"] = 1;
		obs["tcoo"] = 1;
		obs["tiqmouse"] = 1;
		obs["tr"] = 1;
		obs["trantor"] = 1;
	} !($1 in obs) { print $1, $2 }'
}

#
# Useful debugging which is reasonable to include in a production system:
# we copy the salient driver files to the package undo directory before
# doing any work.  This will help diagnose add_drv errors before the system
# becomes an unbootable smoldering ruin.
#
for file in driver_aliases driver_classes minor_perm name_to_major; do
	cp $BASEDIR/etc/$file $PKGSAV/$file.orig >/dev/null 2>&1
done

#
# Add_drv needs /etc/driver_aliases in order to work properly; if for
# some reason it has been removed, create an empty one at this time.
# Recall that in SUNWcsr's pkginfo.tmpl, the driver_aliases class-action
# script is invoked *after* this class-action script.  This is critical
# because if we are going to add_drv a new driver 'foo', and 'foo' has
# an alias 'bar', the add_drv of 'foo' will fail if the alias is already
# present.  Thus new aliases must be added *after* new driver major entries.
# The driver_aliases class-action script will add the complete set of aliases
# if we create an empty file here, so this code allows us to continue and
# get a correct upgrade in the face of a missing driver_aliases file.
#
if [ ! -f $BASEDIR/etc/driver_aliases ]; then
        touch $BASEDIR/etc/driver_aliases
        chmod 0644 $BASEDIR/etc/driver_aliases
	chown root $BASEDIR/etc/driver_aliases
        chgrp sys $BASEDIR/etc/driver_aliases
fi

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

ECHO="/usr/bin/echo"
SED="/usr/bin/sed"
PKGPROTO="/usr/bin/pkgproto"
EXPR="/usr/bin/expr"	# used by dirname
MKDIR="/usr/bin/mkdir"
CP="/usr/bin/cp"
RM="/usr/bin/rm"
MV="/usr/bin/mv"
KSH="/usr/bin/ksh"

recovery="no"
Pn=$$
procIdCtr=0

CMDS_USED="$KSH $ECHO $SED $PKGPROTO $EXPR $MKDIR $CP $RM $MV"
LIBS_USED=""

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=$FILE_DIR/reloc
ROOT_DIR=$FILE_DIR/root
BO_Deletes=$FILE_DIR/deletes
PROGNAME=`basename $0`

if [ "$PATCH_PROGRESSIVE" = "true" ]; then
	PATCH_NO_UNDO="true"
fi

# Since this is generic, figure out the class.
Class=`echo $PROGNAME | nawk ' { print substr($0, 3)  }'`

# Since this is an update, $BASEDIR is guaranteed to be correct
BD=${BASEDIR:-/}

cd $BD

#
# First, figure out the dynamic libraries that can trip us up.
#
if [ -z "$PKG_INSTALL_ROOT" ]; then
	if [ -x /usr/bin/ldd ]; then
		LIB_LIST=`/usr/bin/ldd $CMDS_USED | sort -u | nawk '
			$1 ~ /\// { continue; }
			{ printf "%s ", $3 } '`
	else
		LIB_LIST="/usr/lib/libc.so.1 /usr/lib/libdl.so.1 /usr/lib/libw.so.1 /usr/lib/libintl.so.1 /usr/lib/libgen.so.1 /usr/lib/libadm.so.1 /usr/lib/libelf.so.1"
	fi
fi

#
# Now read the list of files in this class to be replaced. If the file
# is already in place, then this is a change and we need to copy it
# over to the build directory if undo is allowed. If it's a new entry
# (No $dst), then it goes in the deletes file for the backout package.
#

LD_LIB_DIR=$PKG_INSTALL_ROOT/var/tmp/LDLIB.$$

procIdCtr=0
while read src dst; do
	if [ "${PATCH_NO_UNDO}" != "true" ]; then
		#
		# Here we construct the path to the appropriate source
		# tree for the build. First we try to strip BASEDIR. If
		# there's no BASEDIR in the path, we presume that it is
		# absolute and construct the target as an absolute path
		# by stripping PKG_INSTALL_ROOT. FS_Path is the path to
		# the file on the file system (for deletion purposes).
		# Build_Path is the path to the object in the build
		# environment.
		#
		# The following rootPath variable accounts for a BASEDIR
		# that is used as a regular variable within the path and
		# not as a variable that a path needs to be relocated to.

		rootPath=`$ECHO $src | $SED s@"$INST_DATADIR/$PKGINST"@@ | \
			nawk -F/ '{print $2}'`
		if [ "$rootPath" = "root" ]; then
			FS_Path=$dst
		elif [ "$BD" = "/" ]; then
			FS_Path=`$ECHO $dst | $SED s@"$BD"@@`
		else
			FS_Path=`$ECHO $dst | $SED "s|^$BD/||"`
		fi

		# If it's an absolute path the attempt to strip the
		# BASEDIR will have failed.
		if [ "$dst" = "$FS_Path" ]; then
			if [ -z "$PKG_INSTALL_ROOT" ]; then
				FS_Path=$dst
				Build_Path="$ROOT_DIR$dst"
			else
				Build_Path="$ROOT_DIR"`echo $dst | \
				    $SED "s|$PKG_INSTALL_ROOT||"`
				FS_Path=`echo $dst | \
				    $SED "s|$PKG_INSTALL_ROOT||"`
			fi
		else
			Build_Path="$RELOC_DIR/$FS_Path"
		fi

		if [ -f "$dst" ]; then	# If this is replacing something
			cd $FILE_DIR
			#
			# Construct the prototype file entry. We replace
			# the pointer to the filesystem object with the
			# build directory object.
			#
			echo "e nametomajor $FS_Path=$Build_Path ? ? ?" >> \
			    $BUILD_DIR/prototype

			# Now copy over the file
			if [ "$recovery" = "no" ]; then
				DirName=`dirname $Build_Path`
				$MKDIR -p $DirName
				$CP -p $dst $Build_Path
			else
				# If this file is already in the build area skip it
				if [ -f "$Build_Path" ]; then
					cd $BD
					continue
				else
					DirName=`dirname $Build_Path`
					if [ ! -d "$DirName" ]; then
						$MKDIR -p $DirName
					fi
					$CP -p $dst $Build_Path
				fi
			fi

			cd $BD
		else	# It's brand new
			$ECHO $FS_Path >> $BO_Deletes
		fi
	fi

	# If special processing is required for each src/dst pair,
	# add that here.
	#
	#XXXSpecial_CommandsXXX#
	#

	if [ ! -f $dst ] ; then
		cp $src $dst
	else
		#
		# Strip obsolete entries from the existing name_to_major
		#
		if [ $ARCH = sparc ]; then
			obsolete_sparc < $dst > /tmp/onm.$$.tmp
		else
			obsolete_i386  < $dst > /tmp/onm.$$.tmp
		fi

		cp /tmp/onm.$$.tmp $dst
		rm -f /tmp/onm.$$.tmp
		os_rev=`uname -r`

		while read name major; do
			#
			# If the driver is already present in name_to_major,
			# leave the existing number and continue
			#
			grep -w $name $dst >/dev/null 2>&1 && continue

			#
			# Otherwise add the driver to name_to_major using
			# add_major or add_drv:
			#
				#
				# add_drv produces spurious output even on
				# success, so save its output in a temporary
				# file in case an error occurs.
				#
				if add_drv -b $BASEDIR $name \
				    >/tmp/ad.$$.tmp 2>&1; then
					echo "added $name to $dst"
				else
					echo "$PKG: failed to add $name to " \
					    "$dst:" >& 2
					cat /tmp/ad.$$.tmp >& 2
				fi
		done < $src
		rm -f /tmp/ad.$$.tmp
	fi
done 
# If additional operations are required for this package, place
# those package-specific commands here.

#XXXSpecial_CommandsXXX#

exit 0
