#!/bin/ksh

#
# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

PATH=/usr/bin:/usr/sbin:$PATH; export PATH
ZDIR=/etc/zones
pkg=SUNWopenssl-libraries
rmpkg=SUNWusb
addpkg=SUNWckr
kbtrans=/kernel/misc/sparcv9/kbtrans
PKGCOND=/usr/bin/pkgcond
PKGINFO=/usr/bin/pkginfo


backup_sdconf() {
  if [ -f $ROOTDIR/kernel/drv/sd.conf ]; then
    if [ -f $ROOTDIR/var/sadm/pkg/SUNWckr/save/sd.conf.$PatchNum ]; then
      cp $ROOTDIR/kernel/drv/sd.conf \
       $ROOTDIR/var/sadm/pkg/SUNWckr/save/sd.conf.$PatchNum.$$
      else
        cp $ROOTDIR/kernel/drv/sd.conf \
       $ROOTDIR/var/sadm/pkg/SUNWckr/save/sd.conf.$PatchNum
    fi
  fi
}

update_logindevperm() {
        cp $ROOTDIR/etc/logindevperm $ROOTDIR/etc/logindevperm.before-$PatchNum

}

load_mods() {

	## load modules during patch installation per 6349240
	## to prevent warnings from displaying on the console
	## before the system is rebooted.

	## find all kernel driver modules in patch
	PLATFORM=`uname -i`
	CLASS=`uname -m`
 	ISA_INFO=`/usr/bin/isainfo -b`

	cd  ${patchdir:-$PWD}

		for i in *
		do
		pkginfo `echo $i | cut -f 1 -d '.'` > /dev/null 2>&1
			if [ $? -eq 0 ]; then
				grep " kernel\>" $i/pkgmap | grep -v mpxio | grep -v kmdb
				grep "/kernel\>" $i/pkgmap | grep "${PLATFORM}/" | grep -v "cpu/" | grep -v kmdb
				grep "/kernel\>" $i/pkgmap | grep "$CLASS/" | grep -v "cpu" | grep -v "kmdb/"
			fi

		done 2>/dev/null | nawk '/^1 f/ && ! /\.conf|\/unix|\/genunix/ {print $4}' >/tmp/modules.$$

		if [ "$ROOTDIR" = "/" ] ; then

		##
		## Disable kernel module unloading
		##
		print "Disabling kernel module unloading ... \n"
		if [ -x /usr/bin/mdb ]; then
			if [ $ISA_INFO = 64 ]; then
				SAVED_ADDR=`echo '_kobj_printf/J' | mdb -k | cut -f2 -d ':'` 
				echo '_kobj_printf/Z systrace_stub' | mdb -kw > /dev/null 2>&1
			else
				SAVED_ADDR=`echo '_kobj_printf/X' | mdb -k | cut -f2 -d ':'`
				echo '_kobj_printf/W systrace_stub' | mdb -kw > /dev/null 2>&1
			fi
			echo "moddebug/W20000" | adb -kw /dev/ksyms /dev/mem | grep moddebug > /dev/null 2>&1

		else
			echo "mdb not found: patchadd not safe."
		fi

		while read line; do
		## preload each module
			[ -f /$line ] && {
				## echo "loading module $line"
				modload /$line > /dev/null 2>&1
			}

		done < /tmp/modules.$$

		fi

		if [ $ISA_INFO = 64 ]; then
			echo '_kobj_printf/Z '$SAVED_ADDR | mdb -kw > /dev/null 2>&1
		else
			echo '_kobj_printf/W '$SAVED_ADDR | mdb -kw  > /dev/null 2>&1
		fi

	mv /tmp/modules.$$ /tmp/backoutmods.$PatchNum
}

CheckZones()
{
        if [ "$ROOTDIR" = "/" -a -x /usr/bin/zonename ]; then
                ZONENAME=`/usr/bin/zonename`
                if [ ${ZONENAME} = "global" ]; then
                        GLOBAL_ZONE=true
                else
                        GLOBAL_ZONE=false
                fi
        else
                # Unable to determine zone
                GLOBAL_ZONE=true
        fi
}


LocalZones()
{
# Any local zone stuff here,
# typically this fuction is not used
        return 0
}

ExecuteALLCmds()
{
 load_mods
 update_logindevperm
 backup_sdconf
 relocate_kbtrans
}


determine_pkgcond () {

  if $PKGCOND  is_whole_root_nonglobal_zone > /dev/null 2>&1 ; then
      # Execute non-global whole root zone commands.
      update_logindevperm
      return 0
  fi

  if $PKGCOND  is_nonglobal_zone > /dev/null 2>&1 ; then 
      # Execute non-global zone commands. Should be no action here
      update_logindevperm
      return 0
  fi

  if $PKGCOND is_netinstall_image > /dev/null 2>&1 ; then
      # Execute commands applicable to patching the mini-root.
      # There are usually no actions to take here since your patching
      # the mini-root on an install server.
      update_logindevperm
      relocate_kbtrans
      return 0
  fi

  if $PKGCOND is_mounted_miniroot > /dev/null 2>&1 ; then
      # Execute commands specific to the mini-root
      update_logindevperm
      relocate_kbtrans
      return 0
  fi

  if $PKGCOND is_diskless_client > /dev/null 2>&1 ; then
      # Execute commands specific to diskless client
      update_logindevperm
      return 0
  fi

  if $PKGCOND is_alternative_root > /dev/null 2>&1 ; then
      # Execute commands specific to an alternate root
      ExecuteALLCmds
      return 0
  fi

  if $PKGCOND is_global_zone > /dev/null 2>&1 ; then
      # In a global zone and system is mounted on /.
      # Execute all commands.
      ExecuteALLCmds
      return 0
  fi

}

relocate_kbtrans() {


        if [ ! -f $ROOTDIR/$kbtrans ] ; then
                return
        fi

	## This patch will add kbtrans to SUNWckr.  Manually remove it from SUNWusb
	## if it exists
	##
	Pgk=`pkgchk -R $ROOTDIR -l -p $kbtrans | grep $rmpkg`
	if [ "$?" =  "0" ] ; then
		removef -R $ROOTDIR $rmpkg $ROOTDIR/$kbtrans 1>/dev/null 2>&1
		removef -R $ROOTDIR -f $rmpkg
		installf -R $ROOTDIR $addpkg $ROOTDIR/$kbtrans
		installf -R $ROOTDIR -f $addpkg
		save_kbtrans_pkgmap
	fi
}


##
## Save kbtrans entry
##
## Address 6343544 by using workaround 6312956 - removef doesn't update zones
## saved pkgmap files. We'll use cp -p to preserve permissions on the pkgmap
## file. Even though kbtrans may have moved from SUNWusb to SUNWckr, the
## pkgmap still needs to be cleaned up after the package switch is complete.
##

save_kbtrans_pkgmap () {

        rmpkg=SUNWusb
	kbtrans_entry=kernel/misc/sparcv9/kbtrans
        mypatchid=${PatchNum}

        cd $ROOTDIR/var/sadm/pkg/$rmpkg/save/pspool/$rmpkg
        ## Until removef/installf is fixed, we'll check if the entry is
        ## still in the origin package's pkgmap

        if grep "$kbtrans_entry" pkgmap >/dev/null
        then
            ## Save kbtrans entry in backoutpkgmap for postbackout restore
            ## backoutpkgmap=$ROOTDIR/var/sadm/patch/$mypatchid.savekbtrans.$rmpkg.undo.pkgmap
	    backoutpkgmap=/tmp/$rmpkg.pkgmap.$mypatchid
            cp -p pkgmap $backoutpkgmap
            grep "$kbtrans_entry" pkgmap > $backoutpkgmap

            ## Remove kbtrans entry in present SUNWusb pkgmap to clean up
            cp -p pkgmap pkgmap.tmp
            grep -v "$kbtrans_entry" pkgmap > pkgmap.tmp
            mv pkgmap.tmp pkgmap

        fi

}

AlternateRoot()
# returns 0 if $PKG_INSTALL_ROOT -
{
	if [ -n "$ROOTDIR" ]; then
		if  [ "/" = "`echo $ROOTDIR |nawk '{gsub(/\/+/,"/"); print}'`" ]; then
			return 1
		else
			return 0
		fi
	else
		return 1
	fi
}

Check_miniroot()
{
	if [ ! -z "$PKGDBARG" ]; then
		echo $PKGDBARG | grep "^\-C" > /dev/null 2>&1
		if [ $? -eq 0 ] ; then
				if [ X"$PKG_NONABI_SYMLINKS" != X"true" ]; then
				return 1
			fi
		fi
	fi
	return 0
}

CheckLOFI()
{
	LOFITESTF1=/tmp/.lofitestf1.$$.$PatchNum
	LOFITESTF2=/tmp/.lofitestf2.$$.$PatchNum
	mkdir -p /tmp
	echo "1" >$LOFITESTF1
	echo "2" >$LOFITESTF2
	if  mount -F lofs $LOFITESTF1 $LOFITESTF2 >/dev/null 2>&1; then
		if [ X"`cat $LOFITESTF2`" = X"1" ]; then
			# well lofs mount does work
			_LOFI=0
		else
			#It does not work :(
			_LOFI=1
		fi
	else
		_LOFI=1
	fi
	umount $LOFITESTF2 >/dev/null 2>&1
	rm -f $LOFITESTF2 $LOFITESTF1
	return $_LOFI
}

zfs_zones_check()
{
	if [ ! -x "/usr/sbin/zoneadm" ]; then
		# zoneadm does not exist, so we have no problem here
		return 0
	fi
	zone_list=""
	
	#
	# Look at all zones for the "dataset" keyword.
	# We look at all installed zones.
	#
	for zone in $(zoneadm -R ${ROOTDIR:-/} list -i)
	do
		if [[ ${zone} == "global" ]]; then
			continue
		fi
		grep "<dataset name=" ${ROOTDIR}/${ZDIR}/${zone}.xml > \
		    /dev/null 2>&1
		if [ $? -eq 0 ]; then
			zone_list="${zone} ${zone_list}"
		fi
	done
	
	if [ -z ${zone_list} ]; then
		return 0
	else
		echo "The following zones contain datasets:"
		echo "\t${zone_list}"
		return 1
	fi
}

# Main

ZONENAME=global

[ -x /sbin/zonename ] && ZONENAME=`/sbin/zonename`

if AlternateRoot; then
	: # well no lofs mounts are needed
else
	if CheckLOFI; then
		: # we are ok to proceed
	else
		cat <<EOM
ERROR: lofs mount test failed. It can be caused by "exclude: lofs" entry in /etc/system.
       Please be sure that lofs mount is working before applying this patch.
EOM
		exit 1
	fi
fi

if Check_miniroot; then
	: # we are ok, PKG_NONABI_SYMLINKS is set up
else
	echo "ERROR: PKG_NONABI_SYMLINKS must be set to true for patchadd -C"
	exit 1
fi

{ pkgparam -R $ROOTDIR SUNWsndmu > /dev/null 2>&1 || pkgparam -R $ROOTDIR SUNWsndmr > /dev/null 2>&1; } \
&& {
	pkgparam -R $ROOTDIR SUNWopenssl-libraries > /dev/null 2>&1 \
	|| {
		cat <<EOM
Package SUNWopenssl-libraries must be installed before applying this patch.
This is required to satisfy a new dependency relationship packages SUNWsndmu and SUNWsndmr
have on package SUNWopenssl-libraries.
EOM
		exit 1
	}
}

##
## Disabled, because fix for CR# 6500872 is available now
##
## if zfs_zones_check; then
## 	:
## else
## 	cat <<EOM
## This patch cannot be installed without first performing some additional steps due to the
## presence of datasets in zones.  Please read the Special Install Instructions in the patch
## README for information on how to proceed.
## EOM
## 	exit 1
## fi
##

if [ -x "$PKGCOND" ] ; then
  determine_pkgcond || exit 1
else
  CheckZones
  if [ "${GLOBAL_ZONE}" = "true" ]; then
       ExecuteALLCmds
  else
   LocalZones
  fi
fi

exit 0
