#!/bin/ksh

# $Id: checkpatches.sh 229 2009-06-07 11:27:10Z elkner $
# (C) 2008 by Jens Elkner jel+lu@cs.uni-magdeburg.de
# Licence: CDDL - see http://opensource.org/licenses/cddl1.php


usage() {
	printf 'Usage: %s [-d] [-h] [-R root_path] [-a] [-f file] patch_number ...

Check, whether the given patch with at least the given revision is installed
on the system and print out the latest one to stdout.
Inofficial Patches (IR, T, etc.) are not covered by this simple script.

  patch_number .. Patch number to lookup - non-numeric characters except the
                  dash (-) are ignored, the part before the dash is called
                  patch, the part after the dash the revision of the patch.
                  (e.g. 119703-07 or 119703 or 119703-07, or 119703-07a ). 
  -R root_path .. Define the full path name of a directory to use as the
                  root_path (same as in showrev(1M)). Default: /
  -a           .. Show all installed revisions of the given patch.
  -h           .. Print this help text and exit.
  -f file      .. Use the given file produced by  showrev -p  instead of
                  using showrev internally.
  -l           .. just create a patch revision list from installed packages
  -p           .. use pkginfo files instead of "showrev -p"
  -d           .. enable debug
' $0
}

cleanup() {
	[ -z "$NORM" ] && rm $TF
}

createPkgObsoleteList() {
	find $RPATH/var/sadm/pkg -type f -name pkginfo | grep -v /save/ | \
	while read PF ; do
		PI=`fgrep PATCH_INFO_ $PF | sed -e 's/PATCH_INFO_/Patch: /' \
			-e 's/=Installed:.*Obsoletes:/ Obsoletes:/' \
			-e 's/\([0-9]\) \([0-9]\)/\1, \2/g'`
		[ -n "$PI" ] && echo "$PI" >>$TF
	done
}

getObsoletingPatch() {
	PB="$1"
	PR="$2"
	OB=""
	XOB=""
	REM=""
	cut -f2,3 -d: $TF | /usr/xpg4/bin/fgrep "${PB}-" | while read P T O ; do
		if [ -n "$XOB" ]; then
			# exact match found - chomp the rest
			continue
		fi
		# if has no Obsoletes: patches or the line is for the patch itself cont.
		[ "$O" = "Requires" -o "$P" != "${P#${PB}}" ] && continue
		if [ -n "$PR" ]; then
			# on exact match stop
			# grr - no ksh93  //
			X=`echo $O | sed -e "s,${PB}-${PR},,"`
			if [ "$X" != "$O" ]; then
				XOB="$P"
			else
				OR=${O##*${PB}-}
				OR=${OR%% *}
				OR=${OR%%,}
				if [ $OR -gt $PR ]; then
					OB="${OB} $P"
				fi
			fi
		else
			OB="${OB} $P"
		fi
	done
	if [ -n "$XOB" ]; then
		echo $XOB
	else
		echo ${OB## }
	fi
}

ALL=""
RPATH=""
TF=""
NORM=""
PKGPL=""
LISTONLY=""

while getopts "dhalpR:f:" option ; do
	case "$option" in
		"h") usage; exit 1;;
		"a") ALL="true";;
		"R") RPATH="$OPTARG";;
		"f") TF="$OPTARG"; NORM="true";;
		"l") LISTONLY="true";;
		"p") PKGPL="true";;
		"d") typeset -ft $(typeset +f);;
	esac
done
shift $((OPTIND-1))
if [ -z "$1" -a -z "$LISTONLY" ]; then
	usage
	exit 1
fi

export PATH="/usr/bin:/usr/sbin"
if [ -n "$TF" ]; then
	if [ ! -r "$TF" ]; then
		echo "Unable to read patch file $TF"
		exit 1
	fi
	RPATH=""
elif [ -x /usr/bin/mktemp ]; then
	TF=`mktemp -t patches.XXXXXX`
else
	TF="/tmp/patches.$$"
	cp /dev/null $TF
fi

ARGS="-p"
if [ -n "$RPATH" ]; then
	if [ ! -d "$RPATH" ]; then
		echo "Invalid root_path $RPATH"
		cleanup
		exit 2
	else
		ARGS="-p -R \"$RPATH\""
	fi
fi

if [ "$PKGPL" = "true" ]; then
	createPkgObsoleteList
	sort -u -o $TF $TF
else
	showrev ${ARGS} | sort -k2 1>$TF
fi

if [ "$LISTONLY" = "true" ]; then
	ls -al $TF
	exit 0
fi

PATCHES=""
while [ -n "$1" ]; do
	PATCHNO=`echo $1 | tr -dc -- -0123456789`
	PATCH=${PATCHNO%%-*}
	REV=${PATCHNO#$PATCH}
	REV=${REV#-}
	REV=${REV%%-*}
	if [ -z "$PATCH" ]; then
		print -u2 "Invalid  patch number \"$PATCHNO\" ignored"
	else
		PATCHES="${PATCHES} ${PATCH}-${REV}"
	fi
	shift
done

for p in $PATCHES ; do
	PATCH=${p%-*}
	REV=${p#*-}
	if [ -z "$REV" ]; then
		PN="$PATCH   "
	else
		PN="${PATCH}-$REV"
	fi
	if [ -z "$ALL" ]; then
		INFO=`/usr/xpg4/bin/egrep "^Patch: ${PATCH}-" $TF | tail -1 | cut -f2 -d:`
		if [ -z "$INFO" ]; then
			# not installed - might be obsoleted by another one
			X=`getObsoletingPatch $PATCH "$REV"`
			if [ -n "$X" ]; then
				echo "${PN}: ok - obsoleted by: $X"
			else
				echo "${PN}: MISSING"
			fi
		else
			# installed: check revisions
			if [ -n "$REV" ]; then
				FPR=${INFO#*-}
				FPR=${FPR% *}
				if [ $REV -gt $FPR ]; then
					X=`getObsoletingPatch $PATCH $REV`
					if [ -z "$X" ]; then
						echo "${PN}: MISSING - latest revison found: $FPR"
					else
						echo "${PN}: probably obsoleted by: $X"
					fi
				else
					echo "${PN}: ok - found: ${INFO%Obsoletes}"
				fi
			else
				echo "${PN}: ok - found: ${INFO%Obsoletes}"
			fi
		fi
	else
		echo "### PATCH $PATCH ###"
		/usr/xpg4/bin/egrep "^Patch: ${PATCH}-" $TF | awk '{ print $2 }'
	fi
done
cleanup
