#!/bin/sh
#
#  Script:		ccm_patch
#  Description:		Apply a patch to an IBM Rational Synergy installation
#			and one or more databases
#  %version:		46 %
#  %date_created:	Thu Nov 20 09:25:44 2008 %

#  CCM_HOME must be set - it does NOT default to /usr/local/ccm
#  for safety reasons.

set -e

VERSION_STRING="%version:        46 %"
CCM_PATCH_VERSION=`echo $VERSION_STRING | sed -e 's;^\%version: *;;' -e 's; .*;;'`

#============================== FUNCTIONS ================================


usage ()
{
	echo "Usage: ccm_patch [-version] [-readme] [-dbonly] [-force]" 1>&2
	echo "         [-p platform] [-d directory] patchfile [database ...]" 1>&2
}


ckuser ()
{
	case	`id` in
	'uid=0('*)	echo root; return;;
	esac

	id | sed -e 's/uid=[0-9]*(//' -e 's/).*//'
}


ckplatform ()
{
	case ${1-`uname -sr`} in
	sun4|sunos|"SunOS 4"*)		PATCH_PLATFORM=sunos ;;
	sol|solaris|"SunOS 5"*)		PATCH_PLATFORM=solaris ;;
	hp*|HP-UX*)			PATCH_PLATFORM=hpux ;;
	ibm|aix|rs6000|AIX*)		PATCH_PLATFORM=aix ;;
	sgi|irix|IRIX*)			PATCH_PLATFORM=irix ;;
	alpha|dec|digital|OSF1*)	PATCH_PLATFORM=osf1 ;;
	siemens|sinix*|SINIX*)		PATCH_PLATFORM=sinix ;;
	linux*|LINUX*|Linux*)		PATCH_PLATFORM=linux ;;
	ReliantUNIX*)			PATCH_PLATFORM=sinix ;;
	*)
		echo "ERROR: unrecognized platform.  Use one of the following:" 1>&2
		echo "	sunos" 1>&2
		echo "	solaris" 1>&2
		echo "	hp" 1>&2
		echo "	ibm" 1>&2
		echo "	sgi" 1>&2
		echo "	alpha" 1>&2
		echo "	siemens" 1>&2
		echo "	linux" 1>&2
		return 1
		;;
	esac

	DBTYPE=`cat $TARGET_CCM_HOME/lib/DEFAULT_DBMS`;
	case $DBTYPE in
	oracle|informix)
		: OK
		;;
	*)
		echo "ERROR: unrecognized database type $DBTYPE!"
		return 1
		;;
	esac

	return 0
}


echon ()
{
	#  Echo parameters with no newline
	case ${PATCH_PLATFORM?} in
	solaris|linux)	echo -n "$*" ;;
	*)	echo "$*\c" ;;
	esac
}


enquire ()
{
	#  Get a yes or no response to a prompt; parameter is the prompt
	echon "${1-Reply yes or no} "
	while	:
	do
		read REPLY
		case $REPLY in
			y*|Y*)	return 0 ;;
			n*|N*)	return 1 ;;
			*)	echon "Reply yes or no (or y or n) " ;;
		esac
	done
}


ckversion ()
{
	#  Parameters are ...
	patch="$1" area="$2" areaversion="$3"

	if	[ -f version ]
	then	pvers="`cat version`"
		if	[ "X$pvers" = "X$areaversion" ]
		then	#  Matching version strings
			return 0
		else
			echo "Patch $patch is for Synergy version $pvers" 1>&2
			echo "$area is Synergy version $areaversion" 1>&2
			echo "Patch not applied." 1>&2
			return 1
		fi
	elif	echo "Patch $patch is for an unknown version of Synergy" 1>&2
		[ -n "$Force" ] ||
		enquire "Are you sure you want to apply it to $area?"
	then	return 0
	else	return 1
	fi
}


ckprereq ()
{
	#  Parameters are patch name, destination, list of files with patch IDs
	patch=$1; shift
	area=$1; shift

	#  Check Prerequisite patches have been applied
	[ -f prereq ] || return 0
	for pr in `sed -e 's/ .*//' <prereq`
	do
		if	[ "$pr" = none ]
		then	: prerequisite met
		elif	grep "^$pr[\~ ]" "$@" >/dev/null 2>&1
		then	: prerequisite met
		else	echo "This patch ($patch) needs patch $pr" 1>&2
			echo "First apply patch $pr to $area," 1>&2
			echo "then apply $patch to $area" 1>&2
			return 1
		fi
	done
	return 0
}


ckconflicts ()
{
	#  Parameters are patch name, destination, list of files with patch IDs
	patch=$1; shift
	area=$1; shift

	#  Check included patches
	if	[ -f patches.dat ]
	then
		patch_info=`tail -1 patches.dat`
		set +e
		$TARGET_CCM_HOME/bin/ccm_aci -l $TARGET_CCM_HOME/lib/rfclib.a deployment check_installed_patches "$patch_info" $area/etc/patches.dat >/dev/null 2>&1
		exit_code=$?
		set -e
		case $exit_code in
			100)
				# Okay to install the patch
				;;
			101)
				# Patch already installed but can be installed again.
				;;
			102)
				if	[ -z "$Force" ]
				then
					echo "Newer patch already installed."
					echo "  Install this patch may break previously installed patches."
					enquire "  Do you wish to continue?" || return 1
				fi
				;;
			*)
				# Cannot check included patches.
				# Maybe old releases. Skip the check.
				;;
		esac
	fi

	#  Check Conflicting patches have not been applied
	[ -f incompat ] || return 0
	for ip in `sed -e 's/ .*//' <incompat`
	do
		if	[ "$ip" = none ]
		then	: does not conflict
		elif	grep "^$ip[\~ ]" "$@" >/dev/null 2>&1
		then	echo "This patch ($patch) conflicts with patch $ip" 1>&2
			echo "which has already been applied to $area" 1>&2
			echo "Please contact Synergy Support if you need a merged patch" 1>&2
			return 1
		fi
	done
	return 0
}


save_files ()
{
	#  Parameters are ...
	patch="$1" source="$2" area="$3"
	[ -d "$area/save" ] || mkdir "$area/save" || return 1

	#  Back up files about to be replaced
	(
		#  Back up files modified by ccm_patch itself (if they exist)

		if	[ "$source" = "ccm_patch" ]
		then
			#  Back up platform files modified by ccm_patch itself
			echo "etc"
			echo "etc/patches.dat"
			echo "etc/patches.txt"
		elif
			[ "$source" = "db_patch" ]
		then
			#  Back up database files modified by ccm_patch itself
			echo "db"
			echo "db/MDL_INFO"
			echo "db/patches.dat"
		elif
			[ -d "$source" ]
		then
			#  Back up the files modified by the patch contents
			cd "$source" && find . -print
		elif
			[ -f "$source" ]
		then
			#  Back up files modified by the patch scripts
			cat "$source"
		else
			: no action
		fi
	) |
	while	read f
	do
		suffix=`echo p$patch | sed -e 's/[-_]/./g'`
		if	[ -d "$area/$f" ]
		then	[ -d "$area/save/$f" ] ||
			mkdir "$area/save/$f" ||
			return 1
		elif	[ -f "$area/$f" ]
		then
			[ -f "$area/save/${f}_orig" ] ||
				ln "$area/$f" "$area/save/${f}_orig" ||
				cp "$area/$f" "$area/save/${f}_orig" ||
				return 1
			[ -f "$area/save/${f}_$suffix" ] ||
				ln "$area/$f" "$area/save/${f}_$suffix" ||
				cp "$area/$f" "$area/save/${f}_$suffix" ||
				return 1
			# Remove original to break link from backup
			rm -f "$area/$f"
			# and copy back, if file does not start "./"
			case "$f" in
			./*)	;;
			*)	cp -p "$area/save/${f}_$suffix" "$area/$f" ||
				return 1
				;;
			esac
		# else it is a new file, or symlink or device ...
		fi
	done
	return 0
}


#================== PARAMETER ANALYSIS AND VALIDATION ====================


#  Analyze flags
PLATFORM_PARAM=
ReadMeOnly=0
DBOnly=0
Root=0
Force=""
while	:
do
	case $1 in
	-version)			echo "ccm_patch $CCM_PATCH_VERSION"; exit 0 ;;
	-readme|-README|-ReadMe)	ReadMeOnly=1; shift ;;
	-dbonly)			DBOnly=1; shift ;;
	-f|-force)			Force=-f; shift ;;
	-d)				TARGET_CCM_HOME="$2"; shift; shift ;;
	-p)				PLATFORM_PARAM="$2"; shift; shift ;;
	--)				shift; break ;;
	-*)				usage; exit 2 ;;
	*)				break ;;
	esac
done

#  Should have at least one parameter (the patch file or directory)
if	[ $# -ge 1 -a -r "$1" ]
then	PATCH_FILE="$1"; shift
else	usage
	exit 2
fi

#  Check and set CCM_HOME and TARGET_CCM_HOME
TARGET_CCM_HOME=${TARGET_CCM_HOME-$CCM_HOME}
if	[ ! -d "$CCM_HOME" -o ! -f "$CCM_HOME/bin/ccm" ]
then	echo "Set CCM_HOME to the installation directory for the machine where you are running ccm_patch" 1>&2
	exit 2
elif	[ ! -d "$TARGET_CCM_HOME" -o ! -f "$TARGET_CCM_HOME/bin/ccm" ]
then	echo "The specified target installation directory, $TARGET_CCM_HOME," 1>&2
	echo "does not exist or is not a Synergy installation directory" 1>&2
	exit 2
elif	[ ! -x $CCM_HOME/bin/ccm_patch ]
then	echo "You must install ccm_patch in $CCM_HOME/bin" 1>&2
	exit 2
else	#  Get real value of CCM_HOME - relative paths & symlinks are problems
	CCM_HOME=`cd $CCM_HOME; /bin/pwd`
	TARGET_CCM_HOME=`cd $TARGET_CCM_HOME; /bin/pwd`
	export CCM_HOME TARGET_CCM_HOME
fi

#  Find the current platform
ckplatform $PLATFORM_PARAM || exit 1

#  Check we are running as root, unless the -dbonly flag is passed
#  (which it is from the internal, recursive call to ccm_patch),
#  in which case we must be running as ccm_root.  If -readme was
#  set, you can be either root or ccm_root.
if	[ $ReadMeOnly = 1 ]
then
	case `ckuser` in
	root)
		#  Turn on Root flag to allow chown/chgrp calls
		Root=1
		;;
	ccm_root)
		Root=0
		;;
	*)	echo "Must be root or ccm_root to run ccm_patch with -readme"
		exit 2
		;;
	esac
elif	[ $DBOnly = 0 ]
then
	case `ckuser` in
	root)
		Root=1
		;;
	ccm_root)
		Root=0
		echo "WARNING: running ccm_patch as ccm_root might leave some files with the wrong" 1>&2
		echo "ownerships and permissions.  Correct this if necessary by running ccm_install" 1>&2
		echo "as user root after ccm_patch has completed." 1>&2
		if	[ -z "$Force" ]
		then	enquire "Do you wish to continue running as ccm_root?" || exit 1
		fi
		;;
	*)	echo "You must be root to run ccm_patch without -dbonly"
		exit 2
		;;
	esac
else
	case `ckuser` in
	ccm_root)
		Root=0
		;;
	*)	echo "You must be ccm_root to run ccm_patch with -dbonly"
		exit 2
		;;
	esac
fi


#============================= SETUP STAGE ===============================

#  Set a good umask
umask 022

#  Find an uncompress/gunzip tool
GUNZIP=
for PDIR in `echo $PATH | tr ':' ' '`
do
	case "$PDIR" in
	/*)	ADIR="$PDIR" ;;
	*)	ADIR=`cd "$PDIR" ; /bin/pwd` || continue ;;
	esac
	if	[ -x "$ADIR/gunzip" ]
	then	GUNZIP="$ADIR/gunzip"
		break
	elif	[ -x "$ADIR/uncompress" ]
	then	GUNZIP="$ADIR/uncompress"
		break
	fi
done
if	[ -z "$GUNZIP" ]
then	echo "No uncompress or gunzip tool found!" 1>&2
	exit 1
fi

#  Ensure the TARGET_CCM_HOME/patches directory exists
CCM_PATCH="$TARGET_CCM_HOME/patches"
[ -d "$CCM_PATCH" ] || mkdir "$CCM_PATCH" || exit 1
if	[ $Root = 1 ]
then
	chown ccm_root $CCM_PATCH
	chgrp ccm_root $CCM_PATCH
	chmod 755 $CCM_PATCH
fi

#  If the input patch is a directory then use it, otherwise unpack it
if	[ -d "$PATCH_FILE" ]
then	PATCH_DIR="$PATCH_FILE"
	PATCH_DIR=`cd "$PATCH_DIR"; /bin/pwd`
else
	#  Construct a temporary directory to hold the patch
	PATCH_DIR="$CCM_PATCH/tmp.$$"
	trap "cd '$TARGET_CCM_HOME'; rm -rf '$PATCH_DIR'; exit" 0 1 2 3 15
	rm -rf "$PATCH_DIR"
	mkdir "$PATCH_DIR" || exit 1

	#  Unpack the patch file into the temp directory
	cat "$PATCH_FILE" | $GUNZIP | ( cd "$PATCH_DIR"; tar xf - ) ||
		{
		echo "Failed to unpack patch file $PATCH_FILE!" 1>&2
		exit 1
		}
fi

#  Check that the input file was a modern patch
if	[ ! -r "$PATCH_DIR/patch_name" ]
then	echo "$PATCH_FILE does not appear to contain a Synergy patch" 1>&2
	exit 1
fi

#  Get the patch name/number
patch=`sed -e 's/ .*//' <"$PATCH_DIR/patch_name"`

# Save the input file, if it is not already in the right place
patch_dirname="`cd \`dirname \"$PATCH_FILE\"\`; /bin/pwd`"
patch_filename="`basename \"$PATCH_FILE\"`"
if	[ -d "$PATCH_FILE" ]
then	: no action if given a directory
elif	[ "$patch_dirname" = "$CCM_PATCH/$patch" -o \
		"$patch_dirname/$patch_filename" = "$CCM_PATCH/$patch" ]
then	: file is in right place, or subdir of it
elif	[ -d "$CCM_PATCH/$patch" -o -f "$CCM_PATCH/$patch" ]
then	echo "$CCM_PATCH/$patch already exists; $PATCH_FILE not moved"
elif	[ "$patch_dirname" != "$CCM_PATCH" ]
then	cp "$PATCH_FILE" "$CCM_PATCH/$patch"
	if	[ $Root = 1 ]
	then
		chown ccm_root "$CCM_PATCH/$patch"
		chgrp ccm_root "$CCM_PATCH/$patch"
		chmod 644 "$CCM_PATCH/$patch"
	fi
	echo "Saved patch file in $CCM_PATCH/$patch"
	echo "(you may remove $PATCH_FILE)"
elif	[ "$patch_filename" != "$patch" ]
then	mv "$PATCH_FILE" "$CCM_PATCH/$patch"
	if	[ $Root = 1 ]
	then
		chown ccm_root "$CCM_PATCH/$patch"
		chgrp ccm_root "$CCM_PATCH/$patch"
		chmod 644 "$CCM_PATCH/$patch"
	fi
	echo "Moved patch file to $CCM_PATCH/$patch"
fi

if	[ $ReadMeOnly = 1 ]
then	cat "$PATCH_DIR/README"
	exit 0
fi


#========================= END OF SETUP STAGE ============================



#======================== PATCH TARGET_CCM_HOME ==========================


# Use a sub-shell so we get back to the current directory afterwards
[ $DBOnly = 0 ] &&
{ (
cd "$PATCH_DIR"
PATCH_LIST="$TARGET_CCM_HOME/etc/patches.txt"
PATCH_DAT="$TARGET_CCM_HOME/etc/patches.dat"

#  Check current architecture
if	[ -n "$Force" -o -d $PATCH_PLATFORM ] ||
	[ ! -d sunos -a ! -d solaris -a ! -d hpux -a ! -d aix \
		-a ! -d irix -a ! -d osf1 -a ! -d sinix -a ! -d linux ]
then
	: No missing platforms
elif
	[ -f missing_platforms ] &&
		grep "^$PATCH_PLATFORM$" missing_platforms >/dev/null
then	: Missing this platform is OK
else	echo "This patch includes platform-specific portions,"
	echo "none of which match your current $PATCH_PLATFORM platform"
	enquire "Are you sure you want to apply this patch?" || exit 1
fi

#  Check current database type
if	[ -n "$Force" -o -d $PATCH_PLATFORM.$DBTYPE ] ||
		[ -z "`ls -d *.informix *.oracle 2>/dev/null; :`" ]
then
	: No missing platforms
elif
	[ -f missing_platforms ] &&
		grep "^$PATCH_PLATFORM.$DBTYPE$" missing_platforms >/dev/null
then	: Missing this platform is OK
else	echo "This patch includes platform and database specific portions,"
	echo "none of which match your current $PATCH_PLATFORM platform"
	echo "and $DBTYPE database type."
	enquire "Are you sure you want to apply this patch?" || exit 1
fi

#  See if this patch has already been applied on this architecture
if	[ -z "$Force" ] &&
	grep "^$patch $PATCH_PLATFORM" "$PATCH_LIST" >/dev/null 2>&1
then	echo "Patch $patch has already been applied to $TARGET_CCM_HOME on $PATCH_PLATFORM"
else
	ckversion "$patch" "$TARGET_CCM_HOME" "`ccm version -ccm`" || exit 1
	ckprereq "$patch" "$TARGET_CCM_HOME" "$PATCH_LIST" "$PATCH_DAT" || exit 1
	ckconflicts "$patch" "$TARGET_CCM_HOME" "$PATCH_LIST" "$PATCH_DAT" || exit 1

	echo "Applying patch $patch to $TARGET_CCM_HOME using ccm_patch version $CCM_PATCH_VERSION ..."
	[ -f prepatch.sh ] && { sh ./prepatch.sh || exit 1; }

	echo "Backing up files to be modified ..."

	save_files "$patch" ccm_patch "$TARGET_CCM_HOME" || exit 1
	if	[ -d ccm ]
	then
		save_files "$patch" ccm "$TARGET_CCM_HOME" || exit 1
	fi

	if	[ -d $PATCH_PLATFORM ]
	then
		save_files "$patch" "$PATCH_PLATFORM" "$TARGET_CCM_HOME" || exit 1
	fi

	if	[ -d $PATCH_PLATFORM.$DBTYPE ]
	then
		save_files "$patch" "$PATCH_PLATFORM.$DBTYPE" "$TARGET_CCM_HOME" || exit 1
	fi

	if	[ -d windows ]
	then
		save_files "$patch" windows "$TARGET_CCM_HOME" || exit 1
	fi

	if	[ -d modelsrc ]
	then
		save_files "$patch" modelsrc "$TARGET_CCM_HOME" || exit 1
	fi

	if	[ -f modified.ccm ]
	then
		save_files "$patch" modified.ccm "$TARGET_CCM_HOME" || exit 1
	fi

	echo "Modifying files ..."

	if	[ -d ccm ]
	then
		echo "Modifying platform-independent files ..."
		cd ccm
		find . -depth -print | cpio -dump "$TARGET_CCM_HOME"  ||
		{
			echo "Failed to copy platform-independent files!" 1>&2
			echo "Failed to apply $patch to $TARGET_CCM_HOME" 1>&2
			exit 1
		}
		cd "$PATCH_DIR"
	fi

	if	[ -d $PATCH_PLATFORM ]
	then
		echo "Modifying platform-specific files ..."
		cd "$PATCH_PLATFORM"
		find . -depth -print | cpio -dump "$TARGET_CCM_HOME"  ||
		{
			echo "Failed to copy platform-specific files!" 1>&2
			echo "Failed to apply $patch to $TARGET_CCM_HOME" 1>&2
			exit 1
		}
		cd "$PATCH_DIR"
	fi

	if	[ -d $PATCH_PLATFORM.$DBTYPE ]
	then
		echo "Modifying platform and database specific files ..."
		cd "$PATCH_PLATFORM.$DBTYPE"
		find . -depth -print | cpio -dump "$TARGET_CCM_HOME"  ||
		{
			echo "Failed to copy database specific files!" 1>&2
			echo "Failed to apply $patch to $TARGET_CCM_HOME" 1>&2
			exit 1
		}
		cd "$PATCH_DIR"
	fi

	if	[ -d windows ]
	then
		WINDOWS="$TARGET_CCM_HOME/windows"
		[ -d "$WINDOWS" ] || mkdir "$WINDOWS"
		cd windows
		find . -depth -print | cpio -dump "$WINDOWS"  ||
		{
			echo "Failed to copy windows files!" 1>&2
			echo "Failed to apply $patch to $TARGET_CCM_HOME" 1>&2
			exit 1
		}

		cd "$PATCH_DIR"
		echo "Modified files for your Windows client are in $WINDOWS"
		echo "You must copy these files to each" \
			"of your Windows installations"
	fi

	if	[ -d modelsrc ]
	then
		MODEL="$CCM_PATCH/modelsrc"
		[ -d "$MODEL" ] || mkdir "$MODEL"
		cd modelsrc
		find . -depth -print | cpio -dump "$MODEL"  ||
		{
			echo "Failed to copy modelsrc files!" 1>&2
			echo "Failed to apply $patch to $TARGET_CCM_HOME" 1>&2
			exit 1
		}

		if	ls *dcm_info.txt >/dev/null 2>&1
		then
			echo "A DCM transfer package for model changes is in $MODEL."
			echo "Copy and receive this transfer package to your model database,"
			echo "then merge the new object versions with your customized versions."
		else
			echo "New CVs for your modsup database are in $MODEL."
			echo "Import these CVs to your modsup database,"
			echo "then merge them with your customized versions."
		fi
		cd "$PATCH_DIR"
	fi

	[ -f postpatch.sh ] && sh ./postpatch.sh

	#  Fix up permissions for patched files
	echo "Fixing ownership and permissions for installed files ..."
	cd "$TARGET_CCM_HOME"
	Inst_Plat=$PATCH_PLATFORM
	[ $Inst_Plat = "osf1" ] && Inst_Plat=dec
	if	[ $Root = 1 ]
	then	$CCM_HOME/bin/ccm_install -d "$TARGET_CCM_HOME" -p $Inst_Plat
	else	$CCM_HOME/bin/ccm_install -v -d "$TARGET_CCM_HOME" -p $Inst_Plat
	fi || :	#  ignore errors from ccm_install

	if	[ $Root = 1 -a -d "$PATCH_DIR/database" ]
	then
		#  In preparation for database patches,
		#  all database files should be owned by ccm_root
		cd "$PATCH_DIR/database"
		find . -exec chown ccm_root '{}' ';'
		find . -exec chgrp ccm_root '{}' ';'
		find . -exec chmod u+w,og-w,og+r '{}' ';'
	fi

	#  Set up audit trail info
	cd "$PATCH_DIR"
	platstr=`echo $PATCH_PLATFORM | awk '{printf "%-8s\n",$0}'`
	applied=`date "+%y/%m/%d %H:%M"`
	[ -f includes ] && sed -e '/none/d' <includes |
	while read incl rest
	do
		grep "^$incl $PATCH_PLATFORM" "$PATCH_LIST" >/dev/null 2>&1 ||
			echo "$incl $platstr $applied $rest" >>"$PATCH_LIST"
	done
	sed -e "s; ; $platstr $applied ;" <patch_name >>"$PATCH_LIST"
	cp "$PATCH_DIR/README" "$CCM_PATCH/README_$patch"
	if	[ $Root = 1 ]
	then
		chown ccm_root $CCM_PATCH/README_$patch $PATCH_LIST
		chgrp ccm_root $CCM_PATCH/README_$patch $PATCH_LIST
		chmod 644 $CCM_PATCH/README_$patch $PATCH_LIST
	fi

	if	[ -f patches.dat ]
	then
		#  6.4 or later patch; update deployment info
		if	[ -f $PATCH_DAT ] &&
			grep "^$patch~" "$PATCH_DAT" > /dev/null 2>&1
		then
			# Current patch already exists. Assume the $CCM_HOME/etc
			# directory is shared between multiple runareas. Since
			# we want to keep the Optional/Required field as it was
			# set on the router, we do not overwrite its value.
			:
		elif	grep "~O~" "patches.dat" > /dev/null 2>&1
			[ $? != 0 ]
		then
			# Patch is new and not optional
			cat patches.dat >> "$PATCH_DAT"
		elif
			# The patch is optional; offer user a choice to make
			# this patch required for all runareas and databases.
			echo "$patch is an optional patch."
			enquire "Do you want to make it required for all runareas and databases?"
		then
			sed -e "s;~O;~R;g" <patches.dat >>"$PATCH_DAT"
		else
			cat patches.dat >> "$PATCH_DAT"
		fi
		if	[ $Root = 1 ]
		then
			chown ccm_root $PATCH_DAT
			chgrp ccm_root $PATCH_DAT
			chmod 644 $PATCH_DAT
		fi

		CLIENTS='Synergy Classic and CLI users'
		UPDATECLIENT="client/Update_$patch.exe"
		if	[ -z "`$CCM_HOME/bin/ccm ps -process router 2>/dev/null; :`" ]
		then	: No router running
		elif	$CCM_HOME/bin/ccm_aci -l $CCM_HOME/lib/rfclib.a -l $CCM_HOME/lib/libAPIac.a deployment refresh_router
		then
			if [ -f $TARGET_CCM_HOME/$UPDATECLIENT ]
			then
					echo "Synergy clients will be given the option to download the new patch"
			fi
		else	echo "Failed to inform router about new patch!"
			CLIENTS='All users'
		fi

		if	[ -f "$TARGET_CCM_HOME/$UPDATECLIENT" ]
		then
			SYSINFO="$TARGET_CCM_HOME/etc/system_info.txt"
			WEBSERVER="$TARGET_CCM_HOME/etc/ccm_websrv.adr"
			URL=''
			if	[ -f "$SYSINFO" ]
			then
				URL=`sed -n -e 's!^HELP_SERVER[ 	][ 	]*!!p' < $SYSINFO`/$UPDATECLIENT
				PROTOCOL=`echo "$URL" | sed -n -e 's!://.*$!!p'`
				if [ "$URL" != "" -a "$PROTOCOL" = "" ]; then
					URL=http://$URL
				fi
			elif	[ -f "$WEBSERVER" ]
			then	URL="http://`cat $WEBSERVER`/$UPDATECLIENT"
			fi
			if	[ -n "$URL" ]
			then
				echo "$CLIENTS should visit the web page $URL to download the patch"
			fi
		fi
	fi

	echo "Patch $patch applied successfully to $TARGET_CCM_HOME"
fi
) || exit 1; }


#===================== END OF PATCH TARGET_CCM_HOME ======================


#=========================== PATCH DATABASES =============================


if	[ ! -d "$PATCH_DIR/database" ]
then	[ $# != 0 ] && echo "Warning: $* not patched"
	if	[ -f "$PATCH_DIR/db.notice" ]
	then
		echo
		cat "$PATCH_DIR/db.notice"
	else	echo "No database components in this patch."
	fi
	exit 0
elif	[ $# = 0 ]
then	echo "Note that this patch contains database components;"
	echo "You must apply this patch to all appropriate databases"
	exit 0
elif	[ $DBOnly = 0 ]
then	su ccm_root -c "$CCM_HOME/bin/ccm_patch -dbonly $Force $PATCH_DIR $*"
else
	#  Check we are now running as ccm_root
	case	`ckuser`  in
	ccm_root)
		;;
	*)	echo "You must be ccm_root to run ccm_patch with -dbonly"
		exit 2
		;;
	esac

	for db
	do
		DB=`echo "$db" | sed -e 's;/db$;;'`
		DB=`cd $DB; /bin/pwd`
		if	[ ! -d $DB -a ! -d $DB/db ]
		then	echo "$db is not a Synergy database" 1>&2
			echo "Skipping attempt to patch $db" 1>&2
			continue
		fi

		(
		cd "$PATCH_DIR"
		PATCH_LIST="$DB/db/MDL_INFO"
		PATCH_DAT="$DB/etc/patches.dat"

		#  See if this patch has already been applied
		if	[ -z "$Force" ] &&
			grep "^$patch " "$PATCH_LIST" >/dev/null 2>&1
		then	echo "Patch $patch has already been applied to $DB"
			continue
		fi

		DBVER=`ccmdb info "$DB" -k version`
		ckversion "$patch" "$DB" "$DBVER" || exit 1
		ckprereq "$patch" "$DB" "$PATCH_LIST" "$PATCH_DAT" || exit 1
		ckconflicts "$patch" "$DB" "$PATCH_LIST" "$PATCH_DAT" || exit 1

		echo "Applying patch $patch to $DB using ccm_patch version $CCM_PATCH_VERSION ..."
		[ -f predb.sh ] && { sh ./predb.sh "$DB" || exit 1; }

		echo "Backing up files to be modified ..."
		cd "$PATCH_DIR/database"
		save_files "$patch" db_patch "$DB" || exit 1
		save_files "$patch" . "$DB" || exit 1

		if	[ -f "$PATCH_DIR/modified.db" ]
		then
			save_files "$patch" "$PATCH_DIR/modified.db" "$DB" || exit 1
		fi

		echo "Modifying files ..."
		find . -depth -print | cpio -dump "$DB"  ||
		{
			echo "Failed to copy files to $DB !" 1>&2
			echo "Failed to apply $patch to $DB" 1>&2
			exit 1
		}
		cd "$PATCH_DIR"
		[ -f postdb.sh ] && sh ./postdb.sh "$DB"

		#  Set up audit trail info
		applied=`date "+%y/%m/%d %H:%M"`
		[ -f includes ] && sed -e '/none/d' <includes |
		while read incl rest
		do
			grep "^$incl " "$PATCH_LIST" >/dev/null 2>&1 ||
				echo "$incl $applied $rest" >>"$PATCH_LIST"
		done
		sed -e "s; ; $applied ;" <patch_name >>"$PATCH_LIST"

		if  [ -f patches.dat ]
		then
			#  6.4 or later patch; update deployment info
			if	grep "^6.4-01" "patches.dat" > /dev/null 2>&1
			then
				DB_PATCH_DAT="$DB/db/patches.dat"
			else
				DB_PATCH_DAT="$DB/etc/patches.dat"
				# Copy the 6.4-01 patch patches.dat file from the
				# old location to the new location if necessary
				if  [ ! -f $DB_PATCH_DAT -a -f "$DB/db/patches.dat" ]
				then
					cp "$DB/db/patches.dat" "$DB_PATCH_DAT"
				fi
			fi
			if  [ -f $DB_PATCH_DAT ]
			then
				sed -e "/^$patch~/d" <$DB_PATCH_DAT >$DB_PATCH_DAT.new
				mv $DB_PATCH_DAT.new $DB_PATCH_DAT
			fi
			cat patches.dat >> "$DB_PATCH_DAT"
			if  [ $Root = 1 ]
			then
				chown ccm_root $DB_PATCH_DAT
				chgrp ccm_root $DB_PATCH_DAT
				chmod 644 $DB_PATCH_DAT
			fi
		fi

		case $DBVER in
		4.[012]*)	touch $DB/_timetag ;;
		esac
		echo "Patch $patch applied successfully to $DB"
		)
	done
fi

#======================= END OF PATCH DATABASES ==========================
