#!/bin/sh
#
# patcher.nt.sh		-delivery system for patches on NT/HPUX/SOLARIS
#
# version: 1.0
# created: 19981028-cfriesen
# updated: 19990208-cfriesen
# 
#
# TODO list:
#	- shutdown nmserver and machd
#	- check if OPENSTEP apps are running
#
#


debug="${DEBUG_PATCHER- > /dev/null}"

if [ "$OS" = "Windows_NT" ]; then
	debug="${DEBUG_PATCHER->> patcherdebug}"
else
    echo "OS environment variable not equal to 'Windows_NT'"
    echo "You probably aren't on a Windows NT system"
    echo "Exiting...."
    exit 1

fi


#eval echo "executing: $0"
backup_suffix=OS
# COMPRESS no used on NT
#COMPRESS=z			# gnutar compress flag: 'Z' or 'z' or ''
NO_ORIGINAL="File/Dir didn't exist before patch."
ORIGINAL_FILE="Existed before patch."

# usage
usage="usage: patcher.sh -install <patch-tarfile> | -remove <patch-tarfile> [-next_root <dir>] [-backup_suffix <string>] -help"

if [ $# -eq 0 ]; then
	echo "$usage"
	exit 0
fi

eval echo  "Processing args." $debug
# process args
while [ $# -gt 0 ]; do
	case $1 in
		-help)
			echo ""
			echo "$usage"
			echo ""
			echo "Arguments \(must have -install or -remove\):"
			echo "	-install <tarfile>		# install patch from tarfile"
			echo "	-remove <tarfile>		# remove files in patch tarfile"
			echo "					#  restoring previous versions"
			echo "	-next_root <dir>		# specify if NEXT_ROOT env not set"
			echo "	-backup_suffix <string>		# used for backed-up files"
			echo "" 
	
			exit 0
			;;
		-install)
			eval echo "-install options entered" $debug
			shift
			if [ "$installPackage" ]; then
				echo "*** ERROR *** -install is multiply defined."
				exit 1
			fi
			
			if [ "$removePackage" ]; then
				echo "*** ERROR *** -install and -remove are exclusive."
				exit 1
			fi

			if [ $# -eq 0 ]; then
				echo "*** ERROR *** no package spefified after -install option."
				exit 1
			fi
			
			if [ -f "$1" ]; then
				installPackage=$1
			fi
			if [ -f "`pwd`/$1" ]; then
				installPackage=`pwd`/$1
			fi

			eval echo "installPackage: $installPackage" $debug
				
			shift
			;;
		-remove)
			eval echo "-remove options entered" $debug
			shift
			if [ "$removePackage" ]; then
                		echo "*** ERROR *** -remove is multiply defined."
                		exit 1
            		fi
            
            		if [ "$installPackage" ]; then
                		echo "*** ERROR *** -install and -remove are exclusive."
                		exit 1
            		fi

            		if [ $# -eq 0 ]; then
                		echo "*** ERROR *** no package spefified after -remove option."
                		exit 1
            		fi

			if [ -f "$1" ]; then
				removePackage=$1
			fi
			if [ -f "`pwd`/$1" ]; then
				removePackage=`pwd`/$1
			fi

			eval echo "-removePackage: $removePackage" $debug
			shift
			;;
		-next_root)
			shift
            		if [ $# -eq 0 ]; then
                		echo "*** ERROR *** no directory spefified after -next_root option."
                		exit 1
            		fi

			next_root=$1
			if [ `echo $next_root | grep  '^.:$'` ]; then
				$next_root=$next_root/
			fi
			if [ ! -d "$next_root" ]; then
				echo "*** ERROR *** NeXT root $next_root not found."
				exit 1
			fi
			if [ "$NEXT_ROOT" ]; then
				echo "*** WARNING *** NEXT_ROOT environment var ingored, using $next_root"
			fi
			shift
			;;
		-backup_suffix)
			shift
			if [ $# -eq 0 ]; then
                		echo "*** ERROR *** no string spefified after -backup_suffix option."
                		exit 1
            		fi

			backup_suffix=$1
			shift
			;;
		*)
			echo "**** ERROR **** Invalid option: $1"
			echo $usage
			exit 1
        		;;
		esac
done

eval echo "Processing args done." $debug
if [ ! "$installPackage" -a ! "$removePackage" ]; then
	echo "*** ERROR *** Failed to specify -install or -remove option."
	exit 1
fi

eval echo "backup_suffix is $backup_suffix" $debug

# Locate NeXT root, might be defines in environment as $NEXT_ROOT
#
if [ ! "$next_root" ]; then
	if [ "$NEXT_ROOT" ]; then
		if [ ! -d "$NEXT_ROOT" ]; then
			echo "*** ERROR *** $NEXT_ROOT doesn't exist!"
			exit 1
		fi

		next_root=$NEXT_ROOT
	else
		if [ ! -d /NextLibrary ]; then
			echo "*** ERROR *** can't seem to find NeXT root, please specify using -next_root option."
			exit 1
		fi
		
		next_root=/
	fi
fi

eval echo "NEXT root is $next_root" $debug
# find gnutar, $next_root exists at this point
#
if [ ! "$GNUTAR" ]; then
        for x in $next_root/NextDeveloper/bin/ $next_root/NextDeveloper/Executables/Utilities /usr/bin /usr/local/bin . $SystemDrive/Next/NextDeveloper/Executables/Utilities ; do
                # eval echo 'does $x/gnutar.exe exist?' $debug 
                if [ -f "$x/gnutar.exe" -o -f "$x/gnutar" ]; then
                        GNUTAR=$x/gnutar.exe
                        break 
                fi
        done

# better find it above....
        if [ ! "$GNUTAR" ]; then

                echo "*** ERROR *** gnutar.exe not found in usual places, please put a copy in this directory."
                echo ""
                exit 1
        fi
                
fi

`echo $GNUTAR | grep -s gnutar`
if [ $? -eq 1 ]; then
	echo "*** ERROR *** gnutar not in path"
	exit 1
fi
eval echo "found gnutar at $GNUTAR" $debug

if [ "$installPackage" ]; then
eval echo "entered installPackage" $debug

	for fileEntry in `gunzip -c "$installPackage" | $GNUTAR -t -f - | gawk '{printf "%s ", $0} ` ; do
		eval "echo -n $fileEntry  $debug"
		if [ `echo "$fileEntry" | grep  '/$'` ]; then
			fileEntryType="dir"
		else
			fileEntryType="file"
			# might be a link...
		fi
		eval echo " is a $fileEntryType" $debug

		oldfile=`echo ${next_root}/${fileEntry} | sed 's^/$^^'`
		newfile=${oldfile}.$backup_suffix

		if [ -f "$oldfile" -o -h "$oldfile" ]; then
			eval echo "*** EXISTING FILE ***  $fileEntry" $debug
	
			if [ -f "$newfile" ]; then
				eval echo "*** WARNING *** file: $newfile exists ie already patched" $debug
			else
				mv $oldfile $newfile
			fi

			if [ $? -ne 0 ]; then
				echo "*** ERROR *** couldn't move $oldfile to ${oldfile}.$backup_suffix"
				exit 1
			fi
		elif [ ! -d $oldfile ]; then
			# directory isn't part of original distribution
			# need to make the directory hierarchy so we can make our
			# "back out" file
			if [ "$fileEntryType" = "dir" ]; then
				mkdir -p $oldfile
				eval echo "-making: $oldfile" $debug
			fi
			echo $NO_ORIGINAL > "$newfile" # "backout file"
			eval echo "-making $newfile" $debug
		fi
	done

	echo "No errors, extracting patch"

	
	#COMPRESS=-$COMPRESS

	#eval echo "COMPRESS: $COMPRESS" $debug
	eval echo "extracting patch..." $debug

	eval `(cd "$next_root" ; gunzip -c "$installPackage" | $GNUTAR  -x -f - )`

	if [ $? -ne 0 ]; then
		echo "*** ERROR *** errors while installing patch"
		# restore .$backup_suffix files...
		# by doing uninstall.... just do it or call myself with -remove????
		if [ $? -ne 0 ]; then
			echo "*** WARING *** uninstall failed as well..."
			exit 1
		fi
	else
		echo "Install of $installPackage successful"

		# grok for "special" files that will require a reboot..."
		# and notify.
	fi

	exit 0
fi

if [ "$removePackage" ]; then

	# scan to make sure every file has a backup file
	#
	for fileEntry in `gunzip -c "$removePackage" | $GNUTAR -t -f - | gawk '{printf "%s ", $0 }'`; do
eval  echo "$fileEntry" $debug
		oldfile=`echo ${next_root}/${fileEntry} | sed 's^/$^^'`
        newfile=${oldfile}.$backup_suffix
		how_many_failed=0
		how_many_not_writable=0
		
		if [ ! -d "$oldfile" ]; then
			if [ ! -f "$newfile" ]; then
				how_many_failed=1
				echo "*** WARNING *** $oldfile doesn't have backup file $newfile"
			elif [ ! -w "$oldfile" ]; then
				how_many_not_writable=1
				echo "*** ERROR *** don't have permission to overwrite $oldfile"
			fi
		fi
		
		
	done
		
		# how_many_failed=`echo $how_many_failed+$how_many_not_writable | bc`

		if [ $how_many_failed -gt 0 -o $how_many_not_writable -gt 0 ]; then
			if [ $how_many_failed -gt 0 ]; then	
				echo "*** ERROR *** file(s) didn't have backups..."
			fi
			if [ $how_many_not_writable -gt 0 ]; then
				echo "*** ERROR *** file(s) weren't writable..."
			fi
			if [ ! "$FORCE_REMOVAL" ]; then
				echo "		... aborting patch removal."
				exit 1
			else
				echo "*** WARNING *** -force option specified, removing patch anyway."
			fi
		fi

	

problem_with_removal=0
	
	# did scan, time to remove patch and restore files
	#
	for fileEntry in `gunzip -c "$removePackage" | $GNUTAR -t -f - | gawk '{printf "%s ", $0 }' ` ; do
			# since there won't be any "system" necessary file like a kernel
			# or some library used by OS, since we are making sure nmserver,
			# machd, or OS/WOF apps we can just remove the files or move the
			# backups.
			#

		#
		eval echo -n "Processing: $fileEntry" $debug
		if [ `echo $fileEntry | grep  '/$'` ]; then
			fileEntryType="dir"
		else
			fileEntryType="file"
		fi
		eval echo " is a $fileEntryType" $debug

		patch_file=`echo ${next_root}/${fileEntry} | sed 's^/$^^'`
		original_file=${patch_file}.${backup_suffix}

		if [ $fileEntryType = "dir" ]; then
			if [ -f "$original_file" ]; then
				eval echo "FILE: $original_file" $debug
				grep -s  "$NO_ORIGINAL" "$original_file"
				if [ $? -ne 0 ]; then
					echo "*** DEBRIS WARNING *** expected file: $original_file doesn't contain string: '$NO_ORIGINAL'"
					problem_with_removal=$problem_with_removal+1
				else
					# try to remove it since the patch put it in...
					#
					eval echo "removing: $original_file" $debug
					\rm -f "$original_file"
					if [ $? -ne 0 ]; then
						echo "*** DEBRIS WARNING *** couldn't remove $file_to_remove"
						problem_with_removal=$problem_with_removal+1
					fi	

					# making a list of dirs to remove later
					#dirsToRemove="$dirsToRemove $patch_file"
					#eval echo "dirs to remove:  $dirsToRemove" $debug
				fi
			
			else
				# it's a dir and has no backup file, so skip it
				continue
			fi
		
			
		elif [ $fileEntryType = "file" ]; then

			if [ ! -f "$original_file" ]; then
				if [ ! -f "$patch_file" -a "$FORCE" ]; then
					break 2
				else
					eval echo "*** ERROR *** backup file doesn't exit, use -force to ignore" $debug
					exit 1
				fi
				exit 1
			fi
				
			echo "-moving: $original_file to: $patch_file"
			\mv -f "$original_file" "$patch_file"
			if [ $? -ne 0 ]; then
				echo "*** REMOVE WARNING *** couldnt' move original file: $original_file to $patch_file"
				echo "*** REMOVE WARNING *** patch file $patch_file not removed!"

				problem_with_removal=$problem_with_removal+1
			fi
			grep -s "$NO_ORIGINAL" "$patch_file"
			if [ $? -eq 0 ]; then
				\rm -f $patch_file
				if [ $? -ne 0 ]; then
					echo "*** DEBRIS WARNING *** couldn't remove file: $patch_file"
				fi
			fi
		fi
	done

	# problem_with_removal=`echo $problem_with_removal | bc`

	if [ "$problem_with_removal" -ne 0 ]; then
		echo ""
		echo "*** ERROR *** TROUBLE REMOVING PATCH! SEE ABOVE FOR *** REMOVE WARNING ***"
		exit 1
	else
		if [ ! "$FORCE_REMOVAL" ]; then
			echo " Removed patch successfully. Start nmserver and machd at your leisure."
			exit 0
		else
			echo "*** WARNING *** -force options specified, see ERROR messages for possible problems."
			exit 1
		fi
	fi

fi

				
