#!/bin/bash
#
#	VMware Linux Support Script
#	Port from ESX server support script.
#
#	Collects various configuration and log files
#	for use when troubleshooting the VMware on Linux
#
#	PK 10/06/2004
#
#		    - Added UI logs
#		    - Added /etc/services
#
#	PK 07/14/2004
#
#		    - Added /etc/security
#		    - Added ulimit and umask output
#
#	PK 06/09/2004
#                    - Added cron information
#                    - Output of free, uptime and date command
#
#
#	PK 3/18/2004
#		     - 	Changed the vm-support to get input from /etc/vmware/vm-list
#		     -  Replaced an overwrite on ifconfig and added a rpm -qa to the support script
#		     -  DR - Changed $line to use grep instead of sed
#
#	CLI 12/08/2003
#		     - Removed all vmkernel related entries.
#		     - Added new code to parse the vmlist and preference file.
#		     - Allow non-root to run the script.
#
#	JTJ 04/24/2002
#
#	JJ 05/15/2002 - Put all output in a contained subdirectory before 
#			tar'ing
#		      -	only tar new cores
#		      - If tar file is over 10 MB, we print message warning not
#			to mail
#		      - Moved cores to a subdir of ~root after tar'ing so we 
#		      - Added option not to send any cores and and option to
#			send all cores
#		      - Added /proc/cpuinfo
#		      - All proc files tar'ed rather than cat'ed into one file
#
#	JJ 05/22/2002 - Added vmkpcidivy -q commands
#			added all of /proc to tarball except
#				/proc/kcore - too big
#				/proc/kmsg - hangs script
#			made banner take as many args as you want
#			error handling on mv, mkdir, cp, rm, runcmd
#			cleaned up logic for end message
#			
#	JJ 05/29/2002 - removing the --login and sourcing /etc/profile
#			made messages are more support friendly
#


#	Function: usage prints how to use this script

function usage {
	echo ""
	echo "Usage: $0 [-h]"
	echo "	-h prints this usage statement"
	exit
}


TARFILE=vm-$(date -I).$$.tgz
VER=0.86
OUTPUT_DIR=vm-support.$$

#	Function: banner prints any number of strings padded with 
#	newlines before and after.

function banner {
	echo
	for option in "$@"
	do
		echo $option
	done
	echo
}


function UpdateSpinner {
        case $SPINNER in
		"|")
                        SPINNER="/"
                ;;

                "/")
                        SPINNER="-"
                ;;

                "-")
                        SPINNER="\\"
                ;;

                "\\")
                        SPINNER="|"
                ;;

                *)
                        SPINNER="|"
                ;;
        esac
        echo -en "\rPreparing Files: $SPINNER"
}

#	Function: addtar copies whatever files and directories you give it to 
#	a self contained output directory for later tar'ing
#	Working on copies could slow this down with VERY large files but:
#	1) We don't expect VERY large files
#	2) Since /proc files can be copied this preserves the tree without
#	   having to cat them all into a file.
#	3) tar barfs on open files like logs if it changes while it's tar'ing.
#          Copying file first makes sure tar doesn't complain


function addtar {
	FILE=$1

	DIR=$(dirname "$FILE")
	if [ ! -d "${OUTPUT_DIR}$DIR" ]; then
		mkdir -p "${OUTPUT_DIR}$DIR"

		if [ $? != 0 ]; then
			banner "Could not create ./${OUTPUT_DIR}$DIR... " \
				"Have you run out of disk space?" "Continuing"
			return
		fi
	fi

	# Ignore stdout and handle errors.
	UpdateSpinner
	cp -pr "$FILE" "${OUTPUT_DIR}$DIR" 2>/dev/null

	# We could have failed to copy for several reasons
	# If we path had a shell special character (* ? .)
	# or if the file is in /proc
	if [ $? != 0 ]; then
		FILENAME=${FILE##*/}
		for line in "$DIR"/$FILENAME
		do
			if [ -e "$line" ]; then
				# Ignore stdout and handle errors.
				UpdateSpinner
				cp -pr "$line" "${OUTPUT_DIR}$DIR" 2>/dev/null

				# If a file from /proc does not copy,
				# ignore - they're funny.  
				# Otherwise, exit for failed copy.
				if [ $? != 0 ]; then
					echo "$line" | grep ^/proc > /dev/null

					if [ $? != 0 ]; then
						banner "Could not copy $line \
							to the tar area."
						return
					fi	# Not proc
				fi # is it proc
			fi # does file exist

		done # for each file in the list
	fi # if copy failed

}


#	Function: runcmd executes the command ($1) 
#	redirected to a file ($2) and then adds that 
#	file to the list of files to tar. 
#	It then deletes the temp file since addtar makes a copy in its own
#	selft contained area.

function runcmd {
	$1 > $2 2>/dev/null
	
	if [ $? != 0 ]; then
		banner "Either could not run $1 or could not write to $2" \
"Do you have a full disk?" "Continuing..."
	else
		addtar "$2"
		rm "$2"

		if [ $? != 0 ]; then
			banner "Could not delete $2.  Continuing..." 
		fi
	fi
}

function addteam {
	teamfile=$1

	sed -n -e "s/<URL type=\"string\">//Ip" "$line" | \
		sed -n -e "s/<\/URL>//Ip" | while read vmline
	do
		addvm "$vmline"
	done
}

function addvm {                                                                          
        cfgfile=${1//\"/}                                                              
	# See if this is a team file
	suffix=${cfgfile##*.}
	if [ "$suffix" = "vmtm" ];then

		addteam "$cfgfile"
	fi

        [ -e "$OUTPUT_DIR$cfgfile" ] && return                                            
        addtar "$cfgfile"
        dir=$(dirname "$cfgfile")                                                           
        addtar "$dir/*.log"                                                              
        addtar "$dir/*.vmx"                                                               
        addtar "$dir/*.vmxf"                                                               
        addtar "$dir/*.vmtm"                                                               
        addtar "$dir/*.vmpl"                                                               
        addtar "$dir/vmware-core"                                                         
        addtar "$dir/vmware-core*.gz"                                                     
        addtar "$dir/core"                                                                
        addtar "$dir/core.*"                                                              
}
                                         

# Parse args
for option in $@
do
        case $option in
                "-h")
                        usage
                ;;

                *)
                        usage
                ;;
        esac
done

#	Start message

banner "VMware Linux Support Script $VER"

#	Check for root privledge
        
if [ $(id -u) != "0" ]; then                                                              
        banner "You are not root, some system information can't be collected."
fi

# Source /etc/profile.  If we can't find it, it's the users problem to get
# their paths straight.

if [ -f /etc/profile ]; then
	. /etc/profile
fi

# Protect against non-default values of $IFS (Not all scripts in /etc/profile.d/ 
# are good citizens).
unset IFS

#	make a subdir to put all your files in.  die if it does not create
mkdir $OUTPUT_DIR

if [ $? != 0 ]; then
	banner "Could not create ./${OUTPUT_DIR}... Exiting..." \
"Please cd to a directory to which you can write" # Thanks Adam!
	exit
fi

#	Parse /etc/vmware/vm-list and add the virtual
#	machine configuration and log files to the
#	list of files

if [ -e ~/.vmware/favorites.vmls ]; then
	# This picks up only the user registered VM's
	sed -n -e "s/.*config *= \"//Ip" ~/.vmware/favorites.vmls | \
		sed -n -e "s/\"//Ip" | \
		while read line
	do
		addvm "$line"
	done
fi

#       Pick up the user's vmlist for GSX installs. 

if [ -e ~/.vmware/vmlist ]; then
	# This picks up only the user registered VM's
	sed -n -e "s/.*config *= \"//Ip" ~/.vmware/vmlist | \
		sed -n -e "s/\"//Ip" | \
		while read line
	do
		addvm "$line"
	done
fi

if [ $(id -u) == "0" ] && [ -e "/etc/vmware/vm-list" ]; then                                                              
	# This picks up the VM in /etc/vmware/vm-list
	sed -n -e "s/config \"//Ip" /etc/vmware/vm-list | \
		sed -n -e "s/\"//Ip" | \
		while read line
	do
		addvm "$line"
	done 

fi

sed -n -e "s/.*openedObj.\+\.file *= \"//Ip" ~/.vmware/preferences | \
	sed -n -e "s/\"//Ip" | \
	while read line
do
        addvm "$line"
done

# Try to collect bootloader config
if [ -e /etc/lilo.conf ]; then
	addtar "/etc/lilo.conf"
fi

# And for grub we are not sure about the exact default location so collect them
# all.
if [ -e /boot/grub/grub.conf ]; then
	addtar "/boot/grub/grub.conf"
fi
if [ -e /boot/grub/menu.lst ]; then
        addtar "/boot/grub/menu.lst"
fi
if [ -e /etc/grub.conf ]; then
        addtar "/etc/grub.conf"
fi

addtar "/etc/crontab"
addtar "/etc/cron.daily"
addtar "/etc/cron.hourly"
addtar "/etc/cron.monthly"
addtar "/etc/cron.weekly"
addtar "/etc/modules.conf"
addtar "/etc/vmware/*"
addtar "/etc/security/*"

# Add UI logs
addtar "/tmp/vmware*"

# Add services
addtar "/etc/services"

addtar "~/.vmware/*"
addtar "/var/log/boot*"
addtar "/var/log/secure*"
addtar "/var/log/messages*"
addtar "/etc/xinetd.d/vmware-authd"
addtar "/usr/lib/vmware-mui/apache/conf/httpd.conf"
addtar "/var/log/vmware/vmware-serverd*.log"
addtar "/var/log/vmware/vmware-ccagent*.log"
addtar "/var/log/vmware/core"
addtar "/var/log/vmware-mui/error_log"

# Add /proc with some exceptions.  stdout redirected to /dev/null.  Some files
# come and go and confuse find.  Just send whatever works and don't scare user.

for procfile in `find /proc -type f 2>/dev/null| egrep -v kcore\|kmsg\|acpi\|/proc/$$`
do
	addtar "$procfile"
done

#	Commands to run ($1) and redirect to logs ($2) for 
#	inclusion. 

runcmd "echo vm-support version: $VER" "/tmp/vm-support-version.$$.txt"
runcmd "lspci -H1 -M" "/tmp/lspci1.$$.txt"
runcmd "lspci -H1 -M -vn" "/tmp/lspci2.$$.txt"
runcmd "/sbin/lsmod" "/tmp/modules.$$.txt"
runcmd "uname -a" "/tmp/uname.$$.txt"
runcmd "df" "/tmp/df.$$.txt"
runcmd "cat /etc/issue" "/tmp/issue.$$.txt"
runcmd "ifconfig -a" "/tmp/ifconfig.$$.txt"
runcmd "rpm -qa" "/tmp/rpm-qa.$$.txt"
runcmd "netstat -lan" "/tmp/netstat-lan.$$.txt"
runcmd "route" "/tmp/route.$$.txt"
runcmd "mount" "/tmp/mount.$$.txt"
runcmd "vmware -v" "/tmp/vmware.$$.txt"
runcmd "dmesg" "/tmp/dmesg.$$.txt"
runcmd "free" "/tmp/free.$$.txt"
runcmd "uptime" "/tmp/uptime.$$.txt"
runcmd "date" "/tmp/date.$$.txt"
runcmd "ps auwwx" "/tmp/ps-auwwx.$$.txt"
runcmd "ulimit -a" "/tmp/ulimit-a.$$.txt"
runcmd "umask" "/tmp/umask.$$.txt"


#	Perform the tar ('S' for sparse core files)

tar -czSvf $TARFILE $OUTPUT_DIR

if [ $? != 0 ]; then
	banner "The tar did not successfully complete!" \
"If tar reports that a file changed while reading, please attempt to rerun this script."
else
	size=`stat -t $TARFILE | cut -f2 -d " "`
	if [ $size -gt 10000000 ]; then
		banner "File: $(pwd | sed s/[\/]$//)/$TARFILE" \
"NOTE: $TARFILE is greater than 10 MB." \
"Please do not attach this file when submitting an incident report." \
"Please contact VMware support for an ftp site." \
"To file a support incident, go to http://www.vmware.com/support/sr/sr_login.jsp"
	else
		banner "File: $(pwd | sed s/[\/]$//)/$TARFILE" \
"Please attach this file when submitting an incident report." \
"To file a support incident, go to http://www.vmware.com/support/sr/sr_login.jsp"
	fi
fi


#	Clean up temporary files

rm -rf $OUTPUT_DIR

if [ $? != 0 ]; then
	banner "$OUTPUT_DIR was not successfully removed.  Please remove manually."
fi

#	End
