#!/bin/sh
# VMWare 2.0.1 New Kernel Modules
# The purpose of this script is to help people install the accompanying
# patch, which corrects for bit rot in some VMware kernel modules,
# allowing them to compile and run on newer versions of the Linux kernel.
# It is only intended for VMware Server version 2.0.1 (but should
# be adaptable to any similar version, just change the MD5SUM variables
# below).
# Josh Lehan (krellan) 7/2009
### TODO handle VMware Server
### TODO handle VMware Player

# Strict error handling
set -e

# Change these if desired
VMWAREVER="2.0.1"
MODSRCDIR="/usr/lib/vmware/modules/source"
#PATCHFILE="vmware-${VMWAREVER}-newkernmods.patch"
PATCHFILE="vmware-2.6.31-vm.patch"
BACKEXT=".backup-${VMWAREVER}"

# Known good MD5SUM values for VMware Server 2.0.1 64-bit
# If you change these, be sure to also change VMWAREVER above
KG64FILE=`mktemp -t`
cat <<-EOF >"$KG64FILE"
	08894c1edd8c7c1c45846768102f3700  vmblock.tar
	ce33586383ef575107fdbf198267db4b  vmci.tar
	c8e574ae63a2d8c84ddbd2dffc6ce212  vmmon.tar
	c4d92fb78ad30950e2b8ae37e39cff44  vmnet.tar
	d70497dbb937e47b978b7af0d86ab1a7  vmppuser.tar
	9e636de7e7bc1116d81492b9f91acd50  vsock.tar
EOF

# Similarly, these are for the 32-bit version
# The patch will still apply cleanly, even though 32 and 64 are slightly different
KG32FILE=`mktemp -t`
cat <<-EOF >"$KG32FILE"
      430f93443d4ca011526a220b2341b67c  vmci.tar
      be97a1dc3d8c91efbc55ab35b2b3938b  vmmon.tar
      b0a60e9556944ccd9e48fb576009aa03  vmnet.tar
      06fbceca3d54a0c7948061a7d13a4ff4  vsock.tar
EOF

# Files contained in patch
# Note: Ignore vmppuser as it is not necessary
#TARS="vmblock vmci vmmon vmnet vsock"
TARS="vmci vmmon vmnet vsock"

# Sanity checks
OLDDIR=`pwd`
PATCHPATH="${OLDDIR}/${PATCHFILE}"
if [ ! -f "$PATCHPATH" ]; then
	echo "Sorry, patch file $PATCHPATH not found."
	exit 2
fi
if [ ! -d "$MODSRCDIR" ]; then
	echo "Sorry, VMware Server directory $MODSRCDIR not found."
	exit 2
fi
USERID=`id -u`
if [ "0" != "$USERID" ]; then
	echo "Sorry, you must be root in order to run this script."
	exit 2
fi
LINUXVER=`uname -r`

cd "$MODSRCDIR"

# Make sure pristine tarballs exist
for TAR in $TARS
do
	TARNAME="${TAR}.tar"
	WORKTAR="${MODSRCDIR}/$TARNAME"
	PRISTINETAR="${WORKTAR}${BACKEXT}"
	if [ -f "$PRISTINETAR" ]; then
		# The MD5 must match, as these are the backup files, we have no recourse if they are wrong
		PRISTINE64MD5=`cat "$KG64FILE" | grep "$TARNAME" | awk '{ print $1 }'`
		PRISTINE32MD5=`cat "$KG32FILE" | grep "$TARNAME" | awk '{ print $1 }'`
		TESTMD5=`md5sum "$PRISTINETAR" | awk '{ print $1 }'`
		GOOD=0
		if [ "$TESTMD5" = "$PRISTINE64MD5" ]; then
			GOOD=1
		fi
		if [ "$TESTMD5" = "$PRISTINE32MD5" ]; then
			GOOD=1
		fi
		if [ "1" != "$GOOD" ]; then
			echo "Sorry, backup file content does not match what was expected"
			echo "for VMware Server $VMWAREVER $PRISTINETAR file."
			echo "             Your checksum: $TESTMD5"
			echo "Expected checksum (64-bit): $PRISTINE64MD5"
			echo "Expected checksum (32-bit): $PRISTINE32MD5"
			exit 3
		fi
	else
		# Script has never been ran yet, existing tarballs installed to work location should be pristine
		PRISTINE64MD5=`cat "$KG64FILE" | grep "$TARNAME" | awk '{ print $1 }'`
		PRISTINE32MD5=`cat "$KG32FILE" | grep "$TARNAME" | awk '{ print $1 }'`
		TESTMD5=`md5sum "$WORKTAR" | awk '{ print $1 }'`
		GOOD=0
		if [ "$TESTMD5" = "$PRISTINE64MD5" ]; then
			GOOD=1
		fi
		if [ "$TESTMD5" = "$PRISTINE32MD5" ]; then
			GOOD=1
		fi
		if [ "1" != "$GOOD" ]; then
			echo "Sorry, installed file content does not match what was expected"
			echo "for VMware Server $VMWAREVER $WORKTAR file."
			echo "             Your checksum: $TESTMD5"
			echo "Expected checksum (64-bit): $PRISTINE64MD5"
			echo "Expected checksum (32-bit): $PRISTINE32MD5"
			exit 3
		fi
		
		# Back up the freshly installed tarball to pristine location
		echo "Found pristine $WORKTAR"
		echo "Backing it up to $PRISTINETAR"
		rm -f "$PRISTINETAR"
		cp -a "$WORKTAR" "$PRISTINETAR"
	fi
done

# Copy pristine tarballs to working location, and extract them
for TAR in $TARS
do
	# Files must now exist, they were validated in previous step
	TARNAME="${TAR}.tar"
	WORKTAR="${MODSRCDIR}/$TARNAME"
	PRISTINETAR="${WORKTAR}${BACKEXT}"
	WORKDIR="${MODSRCDIR}/${TAR}-only"

	# Create working directories from pristine content
	echo "Found backup $PRISTINETAR"
	echo "Restoring it to $WORKTAR"
	rm -f "$WORKTAR"
	cp -a "$PRISTINETAR" "$WORKTAR"

	# Blow away remains of old directory
	echo "Unpacking $WORKDIR"
	rm -rf "$WORKDIR"
	tar -xf "$WORKTAR"
	if [ ! -d "$WORKDIR" ]; then
		echo "Sorry, tarball $TARNAME did not create directory"
		echo "$WORKDIR as expected."
		exit 4
	fi
done

# Test patch first, so we can exit cleanly if any error
echo "Testing patch"
if ! patch --dry-run -N -p1 < "$PATCHPATH" ; then
	echo "Sorry, validation of the patch has failed."
	echo "Check VMware product name: only Server is supported (for now)."
	echo "Check VMware Server version: only $VMWAREVER is supported (for now)."
	exit 5
fi

# Apply patch
echo "Applying patch!"
if ! patch -N -p1 < "$PATCHPATH" ; then
	# This should never happen, as dry run must have succeeded earlier
	echo "Sorry, applying the patch has failed."
	exit 5
fi

# Repack tarballs after applying patch
for TAR in $TARS
do
	# Files must now exist, they were validated in previous steps
	TARNAME="${TAR}.tar"
	WORKTAR="${MODSRCDIR}/$TARNAME"
	WORKBASE="${TAR}-only"

	# Avoid putting absolute paths into the tarball
	echo "Repacking $WORKBASE"
	rm -f "$WORKTAR"
	tar -cf "$WORKTAR" "$WORKBASE"
done

# Make sure it makes
for TAR in $TARS
do
	# Directories must now exist, they were validated in previous steps
	TARNAME="${TAR}.tar"
	WORKBASE="${TAR}-only"

	# Try "make" inside each toplevel module directory
	echo "Testing compilation of $TAR module to see if it works"
	if ! make -C "$WORKBASE" ; then
		echo "Sorry, problem compiling the $TAR module after it was patched."
		echo "Please check that Linux kernel version $LINUXVER is supported."
		exit 6
	fi
done

# Clean up build directories
for TAR in $TARS
do
	# We no longer care if these directories exist or not
	WORKBASE="${TAR}-only"
	
	# Also remove modules that get placed outside the work directories
	rm -f "${TAR}.o"
	rm -rf "$WORKBASE"
done

# Clean up temporary files
rm -f "$KG64FILE"
rm -f "$KG32FILE"

# All appears good, remind user about next step
echo "Done!"
echo
echo "The VMware tar files in here have been changed:"
echo "$MODSRCDIR"
echo
echo "Those files have been backed up therein, with this extension:"
echo "$BACKEXT"
echo
echo "Now run vmware-config.pl"
echo

exit 0
