#!/bin/sh
# @(#) backoutpatch 3.3 93/04/28 SMI
# (internal revision info): $Revision: 1.13 $ $Date: 1993/04/23 21:28:50 $
echo "@(#) backoutpatch 3.3 93/04/28"

# change log (starting from 2/8/93): 
# 
#   2/8/93 - Installpatch and backoutpatch should permit a patch 
#            to be installed which contains only postinstall scripts 
#            and no actual files delivered.
#   2/9/93 - Backoutpatch should resolve macros in the pkgmap.
#   2/9/93 - pkgrm should be executed in such a way that messages
#            are echoed to the screen in addition to the log.
#  4/22/93 - verify that script is being run by root.
#  4/23/93 - change the method for making the database consistent
#	     with restored files.  For each file restored by the cpio
#	     archive, use pkgchk -l to generate the list of packages
#	     that own it.  Do an installf on one of them (doesn't
#	     matter which one, so use first found).  This ensures that
#	     a file is associated with a package that already owns it.
#  4/23/93 - don't do an installf on any file listed in the 
#	     .validation.errors file.  Make sure that any file which
#	     failed validation before the patch was applied will still
#	     fail validation after the patch is backed out.

spoolonly="no"

USAGE="usage: backoutpatch [-s]  <patch number>"

for i in $*
do
	case $i in
	-s)	spoolonly="yes"; shift;;
	-*)	echo $USAGE; exit 2;;
	esac
done

# change directory to location of patch
if [ ! -d /var/sadm/patch/$1 ]; then
	echo "Patch $1 has not been applied to this system."
	exit 1
fi

uid=`id | sed 's/uid=\([0-9]*\)(.*/\1/'`
if [ "$uid" != "0" ] ; then
	echo You must be root to execute this script.
	exit 1
fi

cd /var/sadm/patch/$1

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

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

if [ "$spoolonly" = "yes" ]; then
	if [ -f softinfo_sed ]; then
	    sed -f softinfo_sed /var/sadm/softinfo/$prodver > /tmp/soft.$$
	    mv /var/sadm/softinfo/$prodver /var/sadm/softinfo/sav.$prodver
	    cp /tmp/soft.$$ /var/sadm/softinfo/$prodver
	fi
#
# this code deleted /export/root/templates when called from installpatch
# (bug in installpatch handling  VERSION=11.4.2,PATCH=1)
#	if [ -f spooled_dirs ]; then
#		cat spooled_dirs | xargs rm -fr
#	fi
	exit 0
fi

if [ ! -f /var/sadm/patch/$patchnum/.oldfilessaved -a \
     ! -f /var/sadm/patch/$patchnum/.nofilestosave ]; then
	echo "Patch $1 was installed without backing up the original"
	echo "files.  It cannot be backed out."
	exit 1
fi

#
# generate list of packages to be removed
#

pkglist=
for i in */pkgmap; do
	pkg=`expr $i : '\(.*\)/pkgmap'`
	pkglist="$pkglist $pkg"
done

#
# find the package instances for this patch
#
pkginstlist=
for j in /var/sadm/pkg/*; do
	if grep -s "SUNW_PATCHID *= *$patchnum" $j/pkginfo > \
			/dev/null 2>&1;  then
		pkginst=`basename $j`
		pkginstlist="$pkginstlist $pkginst"
	fi
done

#
# Build admin file for later use by pkgrm
#

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

for i in $pkginstlist; do
	echo "Doing pkgrm of $i package:"
	/usr/sbin/pkgrm -a /tmp/admin.$$ -n $i > /tmp/pkgrmlog.$$ 2>&1
	pkgrmerr=$?
        cat /tmp/pkgrmlog.$$ >> /var/sadm/patch/$patchnum/log
        cat /tmp/pkgrmlog.$$ 
        rm /tmp/pkgrmlog.$$
        if [ $pkgrmerr != 0 -a $pkgrmerr != 2 -a \
	     $pkgrmerr != 10 -a $pkgrmerr != 20 ] ; then
		echo "\npkgrm of $i package failed with return code $pkgrmerr."
		echo "See /var/sadm/patch/$patchnum/log for reason for failure."
		rm -fr /tmp/*.$$
		exit 1
	fi
done

#
# restore old versions of files
#
if [ ! -f /var/sadm/patch/$patchnum/.nofilestosave ]; then
	echo "Restoring previous version of files"
	cd save
	find . -print | cpio -pdumv / 
	if [ $? != 0 ]; then
		echo "Restore of old files failed."
		echo "See README file for instructions."
		rm -f /tmp/*.$$
		exit 1
	fi

	echo "Making the package database consistent with restored files:"
	find . -print | while read file
	do
		rootfile=`expr $file : '\.\(.*\)'`
		if [ ! -f $file -o -h $file -o "$rootfile" = "" ] ; then
			continue
		fi

		# if file failed validation when the patch was installed,
		# don't do an installf on it.  It should continue to fail
		# validation after the patch is backed out.

		srch="^$rootfile\$"
		if [ -f ../.validation.errors ] && \
		    grep "$srch" ../.validation.errors >/dev/null 2>&1 ; then 
			continue
		fi

		# The following commands find the file's entry in the
		# contents file, and return the first field of the entry.
		# If the file is a hard link, the first field will contain
		# an "=".  This will cause the -f test to fail and we won't
		# try to installf the file.

		srch="^$rootfile[ =]"
		cfpath=`grep "$srch" /var/sadm/install/contents | sed 's/ .*//'`
		if [ "$cfpath" = "" -o ! -f $cfpath ] ; then
			continue
		fi
		installfdone=no

		# Parsing the output of pkgchk is complicated by the fact
		# that all of the text in the output may be localized.
		# Currently, the only line in the output which contains
		# a tab is the line of packages owning the file, so we
		# search for lines containing a tab.  This is probably
		# reasonably safe.  If any of the text lines end up with
		# tabs due to localization, the pkginfo check should
		# protect us from calling installf with a bogus package
		# instance argument.

		pkgchk -lp $rootfile | grep '	' | \
		while read instlist ; do
			for i in $instlist ; do
				pkginfo $i >/dev/null 2>&1
				if [ $? = 0 ] ; then
					installf $i $rootfile
					installf -f $i
					installfdone=yes
					break
				fi
			done
			if [ $installfdone = "yes" ] ; then
				break
			fi
		done
	done
	cd ..
fi

if [ -f softinfo_sed ]; then
    sed -f softinfo_sed /var/sadm/softinfo/$prodver > /tmp/soft.$$
    mv /var/sadm/softinfo/$prodver /var/sadm/softinfo/sav.$prodver
    cp /tmp/soft.$$ /var/sadm/softinfo/$prodver
fi
if [ -f spooled_dirs ]; then
	cat spooled_dirs | xargs rm -fr
fi

cd /
rm -fr /var/sadm/patch/$patchnum

rm -f /tmp/*.$$

echo "backoutpatch finished."
exit 0


