#!/bin/sh
#
# extract D/L patches and check for conflicts
#
:
#set -x
# ver="1.0c"
# 05/12/98 - initial release
# ver="1.1"
# 05/19/98 - added zip logic
# ver="1.2"
# 06/16/98 - added uncompress logic
# ver="1.2.1"
# 06/29/1999 - changed to use Bourne Shell,
#              added patch dependency ordering,
#              added options for verbose, don't unpack and don't installpkg
# ver="1.3"
# 10/01/1999 - use patchadd when installpatch is not available before failing.
ver="1.3.1"

# Variables
master_list=		# list of all patches
patch_list=		# patches to be installed
conflict_list=		# list of conflict patches
patchid=		# conflict patch id
zipprg=			# zip program
verboseflag=0		# verbose debug flag (default=0 silent)
unpackflag=0		# don't unpack flag (default=0 *do* unpack)
installflag=0		# dry run flag meaning do not actually install
			# (default=0 install the package)

# functions

### MAIN ###

# check for args
if [ $# -lt 1 ] ; then
	echo "\nUSAGE: $0 [patch_cluster_filename]\n"
	exit 1
else 
	while getopts "vnd?" c
	do
		case "$c" in
		"v")	verboseflag=1	;;
		"n")	unpackflag=1	;;
		"d")	installflag=1	;;
		"?")     echo "\nUSAGE: $0 [-v|-n|-d] [patch_cluster_filename]\n"
			exit 2;;
		esac
	done
	shift `expr $OPTIND - 1`

	patch_cluster="$1"
fi

# ensure patch cluster file exist
[ $unpackflag -eq 0 ] && [ ! -f $patch_cluster ] && echo "\n!ERROR: Cannot find file -> $patch_cluster\n" && exit 1

# intro
clear
echo ">>> Patch Cluster Extraction Utility v$ver <<<\n"

# --------------------------------------------------------------------------
# determine compression 
# --------------------------------------------------------------------------
if [ -n "`echo $1 | grep \".tar\"`" ] ; then
        ## compressed tar type
        zipprg="/usr/bin/tar -xvf"
else
        ## zipped type

	## check for unix freeware unzip
	if [ "`/bin/which unzip | /bin/cut -f1 -d' '`" != no ] ; then
		zipprg="unzip -o -qq"

	## check for pkware zip
	elif [ "`/bin/which pkzip25 | /bin/cut -f1 -d' '`" != no ] ; then
		zipprg="pkzip25 -extract -overwrite -silent"
	else
		echo "\n!ERROR: Cannot find pkzip25 or unzip in PATH.\n"
		exit 1
	fi
fi

# --------------------------------------------------------------------------
# extract patch cluster
# --------------------------------------------------------------------------
if [ "$unpackflag" -eq "0" ] ; then
	echo "Extracting Patch Cluster..."
	$zipprg $patch_cluster
fi

# uncomment if patch cluster is compressed tar
#(/bin/zcat $patch_cluster | /bin/tar xfp -) >/dev/null 2>&1

# --------------------------------------------------------------------------
# check status
# --------------------------------------------------------------------------
if [ $? -ne 0 ] ; then
	echo "\n!ERROR: Extraction failed, please re-verify patch cluster file.\n"
	exit 1
fi

# --------------------------------------------------------------------------
# extract patches
# --------------------------------------------------------------------------
echo "Extracting Patches..."
for i in `/bin/find 1*.tar.Z -type f -prune`
do
	## extract
	if [ "$unpackflag" -eq "0" ] ; then
		(/bin/zcat $i | /bin/tar xfp -) >/dev/null 2>&1
	fi

	## check status
	if [ $? -ne 0 ] ; then
        	echo "\n!ERROR: Extraction failed, please re-verify patch cluster file.\n"
        	exit 1
	fi
done

# --------------------------------------------------------------------------
# get list of patches to be installed
# --------------------------------------------------------------------------
patch_list="`/bin/find 1* -type d -prune`"

# --------------------------------------------------------------------------
# build master list of existing patches
# --------------------------------------------------------------------------
master_list="`/bin/showrev -p | /bin/awk '{print $2}'`"

# --------------------------------------------------------------------------
# add to master list
# --------------------------------------------------------------------------
master_list="`echo "$master_list\n$patch_list" | /bin/sort -u`"

# --------------------------------------------------------------------------
# loop through patch READMEs
# --------------------------------------------------------------------------
for i in $patch_list
do
    cd $i

    ## check for conflict patches in README
    conflict_list=`/bin/grep "Patches which conflict with this patch:" README* 2>/dev/null | /bin/cut -f2- -d':'`

    ## if so parse patch list
    if [ -n "$conflict_list" ] ; then
        for x in $conflict_list
        do
            ## get patch id
            patchid="`echo $x | /bin/grep '-' | tr -d ','`"
            if [ -n "$patchid" ] ; then
                ## check against master list
                patchid="`echo "$master_list" | /bin/grep $patchid`"
                if [ -n "$patchid" ] ; then
                    echo "!WARNING: Patch $i conflicts with $patchid"
                    echo "Do you still want to install this patch (y/n)? \c"
                    read ans
                    ## if no, remove from list
                    [ $ans == n ] && patch_list="`echo "$patch_list" | /bin/grep -v $i`"
                fi
             fi
        done
    fi
    cd ..
done

# --------------------------------------------------------------------------
# Put the list in dependency order.
# --------------------------------------------------------------------------
echo "Ordering the patch list....."

loop=1
temp_patch_list="${patch_list}"

[ $verboseflag -gt 0 ] && echo "$temp_patch_list\n"

while [ $loop -gt 0 ]
do
    loop=0
    ordered_patch_list=""
    for patchid in ${temp_patch_list}
    do
        [ $verboseflag -gt 0 ] && echo "Processing patchid ${patchid}"
        exist="`echo $ordered_patch_list | grep $patchid`"
        if [ ! -z "$exist" ] ; then
            [ $verboseflag -gt 0 ] && echo "\tDBG: ${patchid}: in list - skipped"
            :
        else
            addtolist="yes"
            req_patchids=`/bin/grep "^Patches required with this patch: " ${patchid}/README* 2>/dev/null | sed "s/^Patches.*patch: //g" | tr -d "A-Za-z()"`
    
            [ $verboseflag -gt 0 ] && echo "\tDBG: req_patchids=(${req_patchids})"
#            req_patchids="`expr "$req_patchids" : '\(.*-.*[0-9]\) .*'`"
	    [ $verboseflag -gt 0 ] && echo "\tDBG: Required Patchids = (${req_patchids})"
            if [ ! -z "${req_patchids}" ] ; then
    
                for req_patchid in ${req_patchids}
                do
                    id="`expr ${req_patchid} : '\(.*\)-.*'`"
                    rev="`expr ${req_patchid} : '.*-\(.*\)'`"
                    [ $verboseflag -gt 0 ] && echo "\tDBG: Processing required patchid ${req_patchid} ${id}, ${rev}...."
                    found="`echo ${ordered_patch_list} | grep "${id}" 2>/dev/null | tr '\012' ' '`"
                    [ $verboseflag -gt 0 ] && echo "\tDBG: looking for ${id} got (${found})..."
        
                    if [ -z "${found}" ] ; then
                        [ $verboseflag -gt 0 ] && echo "\tDBG: Not found..."
                        anypatchdir="`/bin/find $id-* -type d -prune 2>/dev/null`"
                        [ $verboseflag -gt 0 ] && echo "\tDBG: Any same id patch? $anypatchdir"
                        if [ ! -z "${anypatchdir}" -a -d "${anypatchdir}" ] ; then
                            temp="${ordered_patch_list}\n${anypatchdir}"
        	            ordered_patch_list="${temp}"
                            addtolist="no"
                            loop=1
			else
			    addtolist="no"
			    echo "${patchid}:\n\tWARNING: requires patch $req_patchid."
                            echo "\tThe installation might be incomplete due to the missing patch."
                            echo "\tYou might want to remove patch ${patchid} or download the required patch and re-run the cluster install with -n option."
                        fi
                        [ $verboseflag -gt 0 ] && echo "\tDBG: after: ${ordered_patch_list}"
        
                     elif [ ! -z "${found}" ] ; then
        
                        [ $verboseflag -gt 0 ] && echo "\tDBG: Found...-> (${found})"
                        foundrev="`expr ${found} : '.*-\(.*\)'`"
                        if [ ${foundrev} -ge ${rev} ] ; then
                            [ $verboseflag -gt 0 ] && echo "\tDBG: Higher revision ${foundrev} > ${rev}..."
                            addtolist="no"
                            :
                        else
                            [ $verboseflag -gt 0 ] && echo "\tDBG: No higher revision"
                            if [ -d "$req_patchid" ] ; then
                                [ $verboseflag -gt 0 ] && echo "\tDBG: But directory ${req_patchid} exist..."
                                temp="$ordered_patch_list\n${req_patchid}"
                                ordered_patch_list="${temp}"
                                addtolist="no"
                                loop=1
                            fi
                        fi
                    fi
                done
                temp="$ordered_patch_list\n${patchid}"
                ordered_patch_list="${temp}"
                [ $verboseflag -gt 0 ] && echo "\tDBG: after: ${ordered_patch_list}"
            fi
    
            if [ "$addtolist" = "yes" ] ; then
                temp="${ordered_patch_list}\n${patchid}"
                ordered_patch_list="${temp}"
                [ $verboseflag -gt 0 ] && echo "New Order: ${ordered_patch_list}"
            fi
        fi
    done
    temp_patch_list="`echo ${ordered_patch_list} | tr '\012' ' '`"
done

# --------------------------------------------------------------------------
# install patches using patch_list
# --------------------------------------------------------------------------
ordered_patch_list="`echo $temp_patch_list | tr '\012' ' '`"
for i in $ordered_patch_list
do
	cd $i
	echo "Installing Patch -> $i"
	if [ -f ./installpatch ] ; then
		[ "$installflag" -eq "0" ] && ./installpatch .
	elif [ -x "/usr/sbin/patchadd" ] ; then
		[ "$installflag" -eq "0" ] && /usr/sbin/patchadd .
	else
		echo "!WARNING: Neither installpatch nor patchadd is found, patch $i not installed."
	fi
	cd ..
done
