#!/bin/bash #Copyright 2002 William Stearns #Released under the GPL. while [ -n "$1" ]; do case "$1" in [Ss][Tt][Aa][Rr][Tt]) Action=start ;; [Ss][Tt][Oo][Pp]) Action=stop ;; [Ss][Tt][Aa][Tt][Uu][Ss]) Action=status ;; [Rr][Ee][Ss][Tt][Aa][Rr][Tt]) Action=restart ;; [Bb][Aa][Cc][Kk][Uu][Pp]) Backup=backup ;; *) if [ -d "/home/$1/.uml" ]; then Usernames="$Usernames $1" elif [ -d "/home/$1" ]; then Skipping="$Skipping $1" elif [ -f "/home/$1" ]; then Skipping="$Skipping $1" else echo Unknown parameter "$1", exiting. >&2 exit 1 fi ;; esac shift done if [ -z "$Action" ]; then Action="start" fi if [ -z "$Usernames" ]; then echo Missing username, exiting. >&2 exit 1 fi if [ -n "$Skipping" ]; then echo "Skipping: $Skipping" >&2 fi #Show a simple overall system header. By opening with
, this works in a web browser too.
if [ "$Action" = "status" ]; then
	echo \
	echo UML status as of `date`:
	echo `ps ax | grep [S]CREEN | grep -v uml_switch | wc -l` UMLs running
	echo
	if [ -n "`ps ax | grep [u]ml_switch`" ]; then
		echo uml_switch is running
	else
		echo uml_switch is NOT running
	fi
	DefaultGateway=`/sbin/route -n | grep '^0\.0\.0\.0\W' | awk '{print $2}' | uniq | grep -v '^0\.0\.0\.0$'`
	if [ -n "$DefaultGateway" ]; then
		for OneGateway in $DefaultGateway ; do
			if ping -nq -c 3 -w 5 "$OneGateway" >/dev/null 2>&1 ; then
				echo "$OneGateway (default gateway) pings OK"
			else
				echo "no response to pings to $OneGateway (default gateway) !"
			fi
		done
	else
		echo "No default gateway"
	fi
	echo 'Host uptime:' `uptime`
	echo
fi


for OneUser in $Usernames ; do
	#I want to lower the priority of some of the UML's so that other users get first dibs on the CPU.
	case "$OneUser" in
	cache)
		Nice="nice -5 "
		;;
#FIXME - this doesn't work because it's run once we've left root.
	#dhollis)
	#	Nice="nice --3"
	#	;;
	freenet)
		Nice="nice -15 "
		;;
	jeeves)
		Nice="nice -19 "
		;;
	#whoopis)
	#	Nice="nice --2"
	#	;;
	wstearns-test)
		Nice="nice -15 "
		;;
	*)
		Nice=''
		;;
	esac


	#Check to see if already running.  Thanks to Shane Spencer, Jeff Dike, and David Coulson
	AlreadyRunning='no'
	if [ -r "/home/$OneUser/.uml/$OneUser-id/pid" ]; then
		for OnePID in `cat /home/$OneUser/.uml/$OneUser-id/pid` ; do
			if [ -d "/proc/$OnePID" ]; then
				AlreadyRunning='yes'
			fi				
		done
	fi


	case "$Action" in
	start)
		printf "%-16s" "$OneUser"
		if [ "$AlreadyRunning" = "yes" ]; then
			echo -n "already running, not starting again..."
		else
			if [ "$Backup" = "backup" ]; then
				#Make a dated backups of home and root_fs.cow
				if [ -d "/home/$OneUser/backup" ]; then
					BackupStamp=`date +%Y%m%d`01
					while [ -e "/home/$OneUser/backup/root_fs.cow.$BackupStamp" ] || [ -e "/home/$OneUser/backup/root_fs.cow.$BackupStamp.bz2" ] \
					 || [ -e "/home/$OneUser/backup/home.$BackupStamp" ] || [ -e "/home/$OneUser/backup/home.$BackupStamp.bz2" ]; do
						#echo -n $BackupStamp in use, incrementing...
						BackupStamp=$[ $BackupStamp + 1 ]
					done
					echo -n "Backing up root to ~/backup/root_fs.cow.$BackupStamp..."		
					nice cp -p --sparse=always "/home/$OneUser/.uml/root_fs.cow" "/home/$OneUser/backup/root_fs.cow.$BackupStamp"
					echo -n "Backing up home to ~/backup/home.$BackupStamp..."		
					nice cp -p --sparse=always "/home/$OneUser/.uml/home" "/home/$OneUser/backup/home.$BackupStamp"
				else
					echo -n "No $OneUser backup directory, skipping backup..." >&2
				fi
			fi
	
			#Actually start the UML
			if [ ! -x "/home/$OneUser/.uml/$OneUser" ]; then
				echo -n "Missing or unexecutable binary /home/$OneUser/.uml/$OneUser, not starting..." >&2
			elif [ ! -r "/home/$OneUser/.uml/params" ]; then
				echo -n "Missing or unreadable parameter file /home/$OneUser/.uml/params, not starting..." >&2
			else
				echo -n "Creating fresh swap..."
				rm -f /home/$OneUser/.uml/swap

				#This is 1-50 seconds, but puts 512M in page cache, I think
				#nice cp -p --sparse=always /home/shared/uml/swap.512.pristine /home/$OneUser/.uml/swap

				#This is steadily 10-11 seconds, but uses 1.2 CPU's.
				#nice cp --sparse=always <(cat /home/shared/uml/swap.512.pristine.bz2 | nice bunzip2 -c - ) /home/$OneUser/.uml/swap

				#192 seems like a happy medium
				#And this uses almost no cpu or page cache.  Bingo!
				nice dd if=/dev/zero of="/home/$OneUser/.uml/swap" bs=$((1024 * 1024)) count=0  seek=192 2>/dev/null
				mkswap "/home/$OneUser/.uml/swap" >/dev/null

				chown "$OneUser.$OneUser" /home/$OneUser/.uml/swap 
				chmod 600 /home/$OneUser/.uml/swap 
	
				echo -n "Starting UML..."
				screen -S "$OneUser" -t "$OneUser" -d -m su - "$OneUser" -c "cd /home/$OneUser/.uml ; ulimit -c -H unlimited ; ulimit -c unlimited ; ulimit -c -S unlimited ; ulimit -n -H 16384 ; ulimit -n 16384 ; ulimit -n -S 16384 ; $Nice ./$OneUser `cat /home/$OneUser/.uml/params` ; sleep 36000"
			fi
		fi
		echo 'Done!'
		;;
	stop)
		printf "%-16s" "$OneUser"
		if [ "$AlreadyRunning" = "no" ]; then
			echo -n "not running, skipping stop request..."
		else
			echo -n "Stopping..."
			#Stop "reboot" from finding a new kernel, changing reboot to halt.  :-)
			mv "/home/$OneUser/.uml/$OneUser" "/home/$OneUser/.uml/$OneUser.hold"
			echo -n 'sync...'
			echo -n `uml_mconsole "/home/$OneUser/.uml/$OneUser-id/mconsole" sysrq s 2>/dev/null`...
			sleep 1
			echo -n 'sync...'
			echo -n `uml_mconsole "/home/$OneUser/.uml/$OneUser-id/mconsole" sysrq s 2>/dev/null`...
			sleep 1
			echo -n 'unmount/sync...'
			echo -n `uml_mconsole "/home/$OneUser/.uml/$OneUser-id/mconsole" sysrq u 2>/dev/null`...
			echo -n `uml_mconsole "/home/$OneUser/.uml/$OneUser-id/mconsole" sysrq s 2>/dev/null`...
			sleep 1
			echo -n 'boot...'
			echo -n `uml_mconsole "/home/$OneUser/.uml/$OneUser-id/mconsole" sysrq b 2>/dev/null`...
			sleep 2

			#Do NOT put slashes anywhere in the command to be killed, or all UML's using that kernel die.
			if killall -TERM $OneUser 2>/dev/null || killall -TERM sleep 2>/dev/null ; then
				while killall -TERM $OneUser 2>/dev/null || killall -TERM sleep 2>/dev/null ; do
					echo -n "live..."
					sleep 2
				done
			fi
			echo -n "dead..."

			mv "/home/$OneUser/.uml/$OneUser.hold" "/home/$OneUser/.uml/$OneUser"
		fi
		echo 'Done!'
		;;
	status)
		printf "%-16s" "$OneUser"
		if [ "$AlreadyRunning" = "no" ]; then
			echo "not running"
		else
			if ping -A -nq -c 4 -w 6 "$OneUser.stearns.org" >/dev/null 2>&1 ; then
				echo 'pings OK'
			else
				echo "no response to pings to $OneUser.stearns.org !"
			fi
			echo `uml_mconsole "/home/$OneUser/.uml/$OneUser-id/mconsole" version 2>/dev/null` | sed -e 's/^/    /'
		fi
		;;
	restart)
		$0 $OneUser stop
		$0 $OneUser start $Backup
		;;
	esac
done

if [ "$Action" = "status" ]; then
	echo
	/root/bin/tw_cli info c0 u0
fi