#!/bin/sh
# is_server feature is disabled for now....
echo "@(#) installpatch 3.2 93/01/06"

validate="yes"
saveold="yes"
is_server="no"

USAGE="usage: installpatch [-u] [-d] <patch directory>"

for i in $*
do
	case $i in
	-u)	validate="no"; shift;;
	-d)	saveold="no"; shift;;
	-*)	echo $USAGE; exit 2;;
	*)	break;;
	esac
done

if [ $# -lt 1 ]; then
    echo "Patch number not specified."
    echo 'See the section on "Instructions for applying the patch" in README file.'
    exit 1
fi

if [ ! -d $1 ]; then
    echo "$1 is not a patch."
    echo 'See the section on "Instructions for applying the patch" in README file.'
    exit 1
fi

if [  `echo $1 | grep -v "^/"` ]; then
    echo "$1 is not a full path name."
    echo 'See the section on "Instructions for applying the patch" in README file.'
    exit 1
fi

# change directory to location of patch
cd $1

thisdir=`pwd`
patchnum=`basename $thisdir`

if [ -f /var/sadm/patch/$patchnum/.applied ]; then
	echo "Patch has already been applied."
	echo "See README file for instructions."
	rm -f /tmp/*.$$
	exit 1
else
	rm -fr /var/sadm/patch/$patchnum
fi

trap 'echo "Interrupt signal detected.  Patch not installed.";
rm -f /tmp/*.$$; rm -fr /var/sadm/patch/$patchnum; exit 1' 1 2 3 15
#
# generate list of packages to be installed
#

pkglist=
for i in */pkginfo; do
	pkg=`expr $i : '\(.*\)/pkginfo'`
	pkglist="$pkglist $pkg"
done
if [ "$pkglist" = "" ]; then
        echo "Unexpected value with pkglist. Exiting."
        exit 1
fi


Product=`sed -n 's/^OS=\(.*\)/\1/p' /var/sadm/softinfo/INST_RELEASE`
Instver=`sed -n 's/^VERSION=\(.*\)/\1/p' /var/sadm/softinfo/INST_RELEASE`
prodver=$Product"_"$Instver

#
#determine whether system beign patched is a server.
#

#if grep -s "SPOOLED_ROOT" /var/sadm/softinfo/$prodver > /dev/null 2>&1
#then
#	is_server="yes"
#fi

# step through each package in pkglist to find
# those packages that are already installed on the system.

finalpkglist=
rootlist=
for i in $pkglist; do
        #
        # find package instance of originally-installed package
        #
        Pkgabbrev=`sed -n 's/^[ 	]*PKG[ 	]*=[ 	]*\([^ 	]*\)[	 ]*$/\1/p' $i/pkginfo`
        Pkgarch=`sed -n 's/^[ 	]*ARCH[ 	]*=[ 	]*\([^ 	]*\)[	 ]*$/\1/p' $i/pkginfo`
        Pkgver=`sed -n \
           -e 's/^[ 	]*VERSION[ 	]*=[ 	]*\([^ 	]*\)\.[0-9][0-9]*[ 	]*$/\1/p' \
           -e 's/^[ 	]*VERSION[ 	]*=[ 	]*\([^ 	]*\),PATCH=.*$/\1/p' $i/pkginfo `
        minver=`expr $Pkgver : '\(.*\)\.0$'`
        while [ "$minver" != "" ] ; do
                Pkgver=$minver
                minver=`expr $Pkgver : '\(.*\)\.0$'`
        done
        Pkgpatchver=`sed -n 's/^[ 	]*VERSION[ 	]*=[ 	]*\([^ 	]*\)[^ 	]*$/\1/p' $i/pkginfo`
        pkginst=
        for j in /var/sadm/pkg/$Pkgabbrev /var/sadm/pkg/$Pkgabbrev.* X; do
		if [ "$j" = "X" ] ; then
			break
		fi
		if [ ! -d $j ] ; then
			continue
		fi
                OrigPkgver=`sed -n 's/^VERSION=\(.*\)$/\1/p' $j/pkginfo`
                minver=`expr $OrigPkgver : '\(.*\)\.0$'`
                while [ "$minver" != "" ] ; do
                        OrigPkgver=$minver
                        minver=`expr $OrigPkgver : '\(.*\)\.0$'`
                done
                if grep -s "^PKG=$Pkgabbrev$" $j/pkginfo > /dev/null 2>&1 \
                   && grep -s "^ARCH=$Pkgarch$" $j/pkginfo > /dev/null 2>&1 \
                   && [ "$OrigPkgver" = "$Pkgver" ] ;
                then
                        pkginst=`basename $j`
                        finalpkglist="$finalpkglist $i,$pkginst"
                        break;
                fi
        done

        if [ "$is_server" = "yes" ]; then
                if [ "$Pkgarch" = "sparc" ]; then
                        Pkgarch="sparc.all"
                fi
                org_template=$Pkgabbrev"_"$Pkgver"_"$Pkgarch
                if grep "SPOOLED_ROOT=$Pkgarch:/export/root/templates/$prodver/$org_template" /var/sadm/softinfo/$prodver > /dev/null 2>&1
                then
                        spoolsize=`/usr/bin/du -ks $i | sed 's/ .*//'`
                        rootlist="$rootlist $i,$Pkgabbrev"_"$Pkgpatchver"_"$Pkgarch",$spoolsize
                fi
        fi
done

pkglist=$finalpkglist

#
# is there any work to do?
#
if [ "$pkglist" = "" -a "$rootlist" = "" ] ; then
	echo "The original software package does not exist, or there are"
	echo "inconsistent pkginfo values between patch and original pkg."
	echo "Compare pkginfo values for PKG, ARCH, or VERSION."
	echo "Installpatch has been terminated."
	exit 1
fi

#
# generate list of files to be installed
#

echo "generating list of files to be patched"
for i in $pkglist; do
	patchpkg=`expr $i : '\(.*\),.*'`
	pkginst=`expr $i : '.*,\(.*\)'`
	basedir=`grep '^BASEDIR' /var/sadm/pkg/$pkginst/pkginfo | sed -e 's@.*=\ *@@' -e 's@/$@@' -e 's@/a$@/@'`
	sed -e '/^:/d' \
	    -e '/^[^ ][^ ]* i/d' \
	    -e 's/^[^ ]* . [^ ]* \([^ ]*\).*$/\/\1/' \
	    -e 's/=.*//' \
	    -e "s,^.,$basedir&," $patchpkg/pkgmap > /tmp/pkgfiles.$$
	if [ "$validate" = "yes" ]; then
		/usr/sbin/pkgchk -i /tmp/pkgfiles.$$ 2>&1 | \
			grep -v '^WARNING' >> /tmp/pkgchk.out.$$ 
	fi

 	cat /tmp/pkgfiles.$$ >> /tmp/patchfiles.$$
done

if [ "$validate" = "yes" ]; then
	if grep ERROR /tmp/pkgchk.out.$$ >/dev/null ; then
		echo "The following validation error was found: \n"
		cat /tmp/pkgchk.out.$$
		echo 
		echo "See the README file for instructions regarding"
		echo "patch validation errors."
		rm -f /tmp/*.$$
		exit 1
	fi
fi

#
# Generate list of files to be patched that already exist.
# Calculate the bytes required to save the files as well.
#

size_total=0
cat /tmp/patchfiles.$$ |
(while read j
do
	if ls -d $j >/dev/null 2>&1
	then
	    echo $j >> /tmp/existfiles.$$
	    size=`wc -c $j`
	    size=`echo $size | sed 's/\ .*//'`
	    [ $size ] && size_total=`expr $size_total + $size`
	fi
done;echo $size_total > /tmp/bytes_required.$$)

#
# Create patch archive and save area if it does not already exist.
#

if [ ! -d /var/sadm/patch ] ; then
	echo "Create patch archive area"
	mkdir /var/sadm/patch
	chown bin /var/sadm/patch
	chgrp bin /var/sadm/patch
	chmod 555 /var/sadm/patch
fi

if [ ! -d /var/sadm/patch/$patchnum ] ; then
	mkdir /var/sadm/patch/$patchnum
fi

if [ ! -d /var/sadm/patch/$patchnum/save ] ; then
	mkdir /var/sadm/patch/$patchnum/save
fi

# if a server, save the patches in the /export/root/templates
# directory so that future clients will be patched.

trap 'echo "Interrupt signal detected.  Backing out patch:";
./backoutpatch -s $patchnum; rm -fr /var/sadm/patch/$patchnum; 
rm -f /tmp/*.$$; exit 1' 1 2 3 15

if [ "$is_server" = "yes" ]
then
	echo "applying patch package to root templates for future clients"
	echo "(Note that existing clients will need patch applied directly)"
	for i in $rootlist; do
		patchpkg=`expr $i : '\([^,]*\),.*'`
		spoolloc=`expr $i : '[^,]*,\([^,]*\),.*'`
		spoolsize=`expr $i : '[^,]*,[^,]*,\(.*\)'`
		arch=`expr $spoolloc : '[^_]*_[^_]*_\(.*\)'`
		ver=`expr $spoolloc : '[^_]*_\([^_]*\)_.*'`
		abbrev=`expr $spoolloc : '\([^_]*\)_.*'`
		echo  $patchpkg $spoolloc $spoolsize $arch $ver $abbrev

		if [ ! -d /export/root/templates/$prodver/$spoolloc ]; then
			mkdir -p /export/root/templates/$prodver/$spoolloc
		fi
		find $patchpkg -print | cpio -pmdv /export/root/templates/$prodver/$spoolloc
		if [ $? != 0 ]; then
			echo "error while adding patch to root template."
			echo "See README file for instructions."
			rm -fr /export/root/templates/$prodver/$spoolloc
			./backoutpatch -s $patchnum
			rm -fr /var/sadm/patch/$patchnum
			rm -f /tmp/*.$$
			exit 1
		fi
		echo SPOOLED_ROOT=$arch":"/export/root/templates/$prodver/$spoolloc >> /var/sadm/softinfo/$prodver
		echo ROOT=$arch:$abbrev,$spoolsize,$ver >> /var/sadm/softinfo/$prodver
		echo /SPOOLED_ROOT=$arch":".export.root.templates.$prodver.$spoolloc/d >> /var/sadm/patch/$patchnum/softinfo_sed
		echo /ROOT=$arch:$abbrev,$spoolsize,$ver/d >> /var/sadm/patch/$patchnum/softinfo_sed
		echo "/export/root/templates/$prodver/$spoolloc" >> /var/sadm/patch/$patchnum/spooled_dirs
	done
fi

# Save current versions of files to be patched unless user specified
# -d option.
#
if [ "$saveold" = "yes" ]; then
	echo "Save old versions of files to be patched"
	# Is there enough space?
	bytes_avail=`df -b /var/sadm | tail -1`
	bytes_avail=`echo $bytes_avail | sed 's/.*\ //'`
	bytes_avail=`expr $bytes_avail \* 1000`
	bytes_required=`cat /tmp/bytes_required.$$`
	if [ $bytes_required -gt $bytes_avail ]; then
	    echo "Insufficient space in /var/sadm to save old files."
	    echo "Space required in bytes:  $bytes_required"
	    echo "Space available in bytes:  $bytes_avail"
	    ./backoutpatch -s $patchnum
	    rm -f /tmp/*.$$
	    rm -fr /var/sadm/patch/$patchnum
	    exit 1 
	fi
	cd /
	cat /tmp/existfiles.$$ | cpio -pmdv /var/sadm/patch/$patchnum/save
	if [ $? != 0 ]; then
		echo "Save of old files failed."
		echo "See README file for instructions."
	        ./backoutpatch -s $patchnum
		rm -f /tmp/*.$$
		rm -fr /var/sadm/patch/$patchnum
		exit 1
	fi
	touch /var/sadm/patch/$patchnum/.oldfilessaved
	cd $1
fi
 
#
# Build admin file for later use by pkgadd
#

cat > /tmp/admin.tmp.$$ << EOF
mail=
instance=unique
partial=nocheck
runlevel=nocheck
idepend=quit
rdepend=quit
space=quit
setuid=nocheck
conflict=nocheck
action=nocheck
EOF

#
# Install the patch packages
#
echo "Installing patch packages"

trap 'echo "Interrupt signal detected.  Backing out patch:";
./backoutpatch $patchnum; rm -f /tmp/*.$$; exit 1' 1 2 3 15
for ij in $pkglist; do
	i=`expr $ij : '\(.*\),.*'`
	pkginst=`expr $ij : '.*,\(.*\)'`
	basedir=`grep '^BASEDIR' /var/sadm/pkg/$pkginst/pkginfo | sed -e 's@.*=\ *@@' -e 's@/a/@/@' -e 's@/a$@/@'`
	mkdir /var/sadm/patch/$patchnum/$i
	cp $i/pkgmap /var/sadm/patch/$patchnum/$i/pkgmap
	cp $i/pkginfo /var/sadm/patch/$patchnum/$i/pkginfo
 	cp /tmp/admin.tmp.$$ /tmp/admin.$$
	echo basedir=$basedir >> /tmp/admin.$$

	echo "Doing pkgadd of $i package:"
	/usr/sbin/pkgadd -a /tmp/admin.$$ -n -d $1 $i >> /var/sadm/patch/$patchnum/log 2>&1
	if [ $? != 0 ]; then
		echo "Pkgadd of $i package failed.  See"
		echo "/tmp/log.$patchnum for reason for failure."
		cp /var/sadm/patch/$patchnum/log /tmp/log.$patchnum
		echo "Backing out patch:"
		./backoutpatch $patchnum
		rm -fr /tmp/*.$$
		exit 1
	fi
done

# Save ACTION file if exists, README file and backoutpatch script.
mv -f /tmp/ACTION.$patchnum /var/sadm/patch/$patchnum > /dev/null 2>&1
cp -p README.$patchnum backoutpatch /var/sadm/patch/$patchnum > /dev/null 2>&1

touch /var/sadm/patch/$patchnum/.applied
rm -f /tmp/*.$$

echo "Patch installation finished"
exit 0

