#!/bin/bash
###############################################################################
# Copyright 2005 Mike Green <mikey at badpenguins dot com>                    #
# Distributed under the terms of the GNU General Public License v2            #
#                                                                             #
# Test build a stage3 suitable for a LAMP server from a stage3 within a       #
# chroot.  The resulting build will be suitable for a basic                   #
# linux/apache/mysql/php box.  The USE flags are optimized for a lean server: #
# nptlonly, -nls, -pam, userlocales, no X, etc...  The CFLAGS used are        #
# specific to the processor with conservative optimizations.                  #
#                                                                             #
# This script is for testing purposes only, to be used to determine build     #
# times in an automated fashion.  It has only been tested with certain cpus   #
# on the x86 architectures and the resulting code has not been tested in a    #
# production environment.  For amusement purposes only :)                     #
###############################################################################
#
# Parent directory of chroot, i.e. /mnt.  Chroot environment will be created
# in this directory, for example /CHROOT_MOMMA/stage3-lamp-test
#
CHROOT_MOMMA="/mnt"

#
# If this script cannot automatically determine your cpu type, set your
# desired CFLAGS, CHOST, and CPU here.  ONLY set these if the script fails and
# asks you to.  If the autodetection succeeds, it will override what you
# put here. my_CPU matches the cpu type in the stage tarball, i.e. i686,
# pentium3, or pentium4.
#
my_CHOST=""
my_CFLAGS=""
my_CPU=""

#
# Gentoo mirror location, stage1 tarball, portage snapshots, bootstrap patch.
#
GENTOO_MIRROR="http://distfiles.gentoo.org"
SNAP="${GENTOO_MIRROR}/snapshots/portage-20060116.tar.bz2"

#
# Packages needed for a basic lamp server.  Customize and uncomment to
# test build a full "stage4".
#
#LAMP="sysklogd localepurge logrotate vim mailwrapper lilo coldplug hotplug
#sysfsutils reiserfsprogs dcron webapp-config screen mysql apache mod_php"

#
# Don't change this unless you have added extra steps and know
# what you are doing.
#
TOTAL_STEPS=18

#
# Don't change anything below here...
#
VER="20060117.01"
TESTNAME="stage3-lamp-test"
PROGRESSFILE="/var/run/${TESTNAME}-progress"
STATSFILE="/var/run/${TESTNAME}.stats"
LOGFILE="/var/run/${TESTNAME}.log"
CHROOT_DIR="${CHROOT_MOMMA}/${TESTNAME}"

# initialize some of the timer statistics
TOTAL_SECONDS=0
FETCH_SECONDS=0
BUILD_SECONDS=0

[[ -e "${STATSFILE}" ]] && source ${STATSFILE}

###############################################################################
# Load functions from /etc/init.d/functions.sh and set up pretty formatting of
# text.
#
if [ -e /etc/init.d/functions.sh ] ; then
	source /etc/init.d/functions.sh
	esyslog() { echo &> /dev/null; }
else
	eerror() { echo "!!! $*"; }
	einfo() { echo "* $*"; }
fi

###############################################################################
# What to do when we bomb or succeed.  If you have custom stuff you want to
# do after the bootstrap completes, add it here.
#
cleanup() {
	rc=$1
	if [ ! "${rc}" == "0" ]; then
		eerror "Exiting nonzero"
		if [ -f "${LOGFILE}" ]; then
			eerror "Take a gander at ${LOGFILE} if you are wondering why."
		fi
	fi
	umount ${CHROOT_DIR}/proc >/dev/null 2>&1
	umount ${CHROOT_DIR}/dev >/dev/null 2>&1
	exit ${rc}
	}

###############################################################################
#
congrats() {
	einfo
	einfo "Congratulations!  Your test build is complete."
	einfo
	einfo "To run this script again:"
	einfo "rm /var/run/${TESTNAME}*"
	einfo "unmount everything in ${CHROOT_DIR}"
	einfo "rm -rf ${CHROOT_DIR}"
	einfo

	source ${STATSFILE}
	source ${CHROOT_DIR}/etc/make.conf
	BSECS_STR=`time_calc ${BUILD_SECONDS}`
	FSECS_STR=`time_calc ${FETCH_SECONDS}`
	TSECS_STR=`time_calc ${TOTAL_SECONDS}`
	EMERGELOG="${CHROOT_DIR}/var/log/emerge.log"
	TOT_EMERGE=`grep -c "::: completed emerge " ${EMERGELOG}`
	TOT_UNMERGE=`grep -c ">>> unmerge success: " ${EMERGELOG}`

	draw_heading "CPU Information"
	cat /proc/cpuinfo 2>/dev/null

	draw_heading "Memory Information"
	grep 'MemTotal: ' /proc/meminfo 2>/dev/null
	grep 'SwapTotal: ' /proc/meminfo 2>/dev/null

	draw_heading "Load Information"
	cat /proc/loadavg 2>/dev/null

	draw_heading "Disk Usage"
	du -ksh ${CHROOT_DIR}

	draw_heading "Stage make.conf Settings"
	echo "CFLAGS: ${CFLAGS}"
	echo "CHOST:  ${CHOST}"
	echo "USE:"
	echo ${USE}

	draw_heading "Packages Emerged"
	grep '::: completed emerge ' ${EMERGELOG} | cut -f2- -d')' | cut -f2 -d' '

	draw_heading "Packages Unmerged"
	grep '>>> unmerge success: ' ${EMERGELOG}  | cut -f3- -d: | cut -b2-

	draw_heading "Depclean Report"
	cmd="emerge -p --depclean world"
	chroot ${CHROOT_DIR} ${cmd} | grep -v 'WARNING' | grep -v 'Calculating'

	draw_heading "Steps Required"
	grep "TIMER: " ${LOGFILE} | cut -b8- |\
	while read line
	do
		text=`echo $line | cut -f1 -d:`
		rsec=`echo $line | cut -f2 -d: | cut -b2-`
		printf "%-30s `time_calc ${rsec}`\n" "${text}:"
	done

	echo
	printf "%-30s ${FSECS_STR}\n" "Total Fetch Time:"
	printf "%-30s ${BSECS_STR}\n" "Total Build Time:"
	printf "%-30s ${TSECS_STR}\n" "Overall Total Time:"

	echo
	printf "%-32s ${TOT_EMERGE}\n" "Total emerges:"
	printf "%-32s ${TOT_UNMERGE}\n" "Total unmerges:"
	cleanup 0
	}

###############################################################################
#
draw_heading() {
	echo
	echo '--------------------------------------------------------------------'
	echo " [ $@ ]"
	echo '--------------------------------------------------------------------'
	echo
	}

###############################################################################
#
set_run_step() {
	export CURRENT_STEP=$1
	echo "CURRENT_STEP=$1" > ${PROGRESSFILE}
	}

###############################################################################
#
set_stage() {
	cpu=`uname -p`
	myCPU=""
	if [ "${cpu:9:12}" == "Pentium(R) 4" ]; then
		myCPU="pentium4"
	elif [ "${cpu:9:14}" == "Pentium(R) III" ]; then
		myCPU="pentium3"
	elif [ "${cpu:0:11}" == "Pentium III" ]; then
		myCPU="pentium3"
	fi
	if [ -z "${myCPU}" ]; then
		[[ -n "${my_CPU}"  ]] && myCPU="${my_CPU}"
	fi
	if [ -z "${myCPU}" ]; then
		eerror
		eerror "Cannot glean enough information about your cpu to determine"
		eerror "the correct stage3 tarball.  You have to manually set the"
		eerror "desired CPU type by setting my_CPU.  This script has only"
		eerror "been tested with certain autodetected Pentium 3/4's, your"
		eerror "milage may vary, this script might not work at all for you."
		eerror
		cleanup 1
	fi
	STAGE="${GENTOO_MIRROR}/releases/x86/2005.1-r1/stages"
	STAGE="${STAGE}/${myCPU}/stage3-${myCPU}-2005.1-r1.tar.bz2"
	}

###############################################################################
#
show_status() {
	local num=$1
	shift
	echo
	echo "[ Step ${num}/${TOTAL_STEPS}: $* ]"
	echo
	}

###############################################################################
#
time_calc() {
	secs=$1
	if [ -z "${secs}" ]; then
		echo "time_calc(): invalid argument"
		return 1
	fi
	if [ ! "`expr ${secs} / 1 2>/dev/null`" == "${secs}" ]; then
		echo "time_calc(): invalid argument"
		return 1
	fi
	if [ ${secs} -lt 0 ]; then
		echo "time_calc(): invalid argument"
		return 1
	fi
	#DAYS=0
	HOURS=0
	MINUTES=0
	#while [ ${secs} -ge 86400 ]
	#do
	#	secs=$((secs-86400))
	#	DAYS=$((DAYS+1))
	#done
	while [ ${secs} -ge 3600 ]
	do
		secs=$((secs-3600))
		HOURS=$((HOURS+1))
	done
	while [ ${secs} -ge 60 ]
	do
		secs=$((secs-60))
		MINUTES=$((MINUTES+1))
	done
	#echo "${DAYS}d ${HOURS}h ${MINUTES}m ${secs}s"
	printf "%3dh %2dm %2ds" ${HOURS} ${MINUTES} ${secs}
	}

###############################################################################
#
timer_add() {
	timer_type=$1
	num=$2
	[[ -e "${STATSFILE}" ]] && source ${STATSFILE}
	case "${timer_type}" in
		f|fetch)
			tot=`expr ${FETCH_SECONDS} + ${num}`
			if [ $? -eq 0 ]; then
				FETCH_SECONDS=$tot
				tot=`expr ${TOTAL_SECONDS} + ${num}`
				if [ $? -eq 0 ]; then
					TOTAL_SECONDS=${tot}
				fi
			fi
		;;
		*)
			tot=`expr ${BUILD_SECONDS} + ${num}`
			if [ $? -eq 0 ]; then
				BUILD_SECONDS=${tot}
				tot=`expr ${TOTAL_SECONDS} + ${num}`
				if [ $? -eq 0 ]; then
					TOTAL_SECONDS=${tot}
				fi
			fi
		;;
	esac
	echo "FETCH_SECONDS=${FETCH_SECONDS}" >${STATSFILE}
	echo "BUILD_SECONDS=${BUILD_SECONDS}" >>${STATSFILE}
	echo "TOTAL_SECONDS=${TOTAL_SECONDS}" >>${STATSFILE}
	}

###############################################################################
#
timer_entry() {
	num=$1
	shift
	msg="$@"
	echo "TIMER: ${msg}: ${num}" >>${LOGFILE}
	}

###############################################################################
#
v_echo() {
	cmd="$@"
	eval ${cmd} >>${LOGFILE} 2>&1
	}

###############################################################################
## Here is where all of the fun finally starts :)                            ##
###############################################################################
# Trap ctrl-c and stuff.
trap "cleanup" TERM KILL INT QUIT ABRT

#
# display banner
#
echo -e "\n${GOOD}stage3-lamp-test; ${BRACKET}http://badpenguins.com/${NORMAL}"
echo -e "Copyright 2006 badpenguins.com; Distributed under the GPLv2; Version ${VER}"
echo

if [ `id -u` -ne 0 ]; then
	eerror
	eerror "You are not root.  Get root, try again..."
	eerror
	cleanup 1
fi

#
# Initialize settings for current run
#
export CURRENT_STEP=${CURRENT_STEP:-0}

#
# Track progress
#
[[ -e ${PROGRESSFILE} ]] && source ${PROGRESSFILE}

#
# What to do if the test build has already completed.
#
if [ ${CURRENT_STEP} -gt ${TOTAL_STEPS} ] ; then
	congrats
fi

if [ ${CURRENT_STEP} -gt 0 ] ; then
	einfo "Resuming build at internal step #${CURRENT_STEP} ..."
	echo
else
	einfo "Starting build ..."
	echo
fi

# Speed things up, get rid of 5 second delay during package unmerges etc...
export CLEAN_DELAY=0
export EBEEP_IGNORE=0
export EMERGE_WARNING_DELAY=0
export EPAUSE_IGNORE=0

###############################################################################
## Here is where we get down to the real nut cuttin                          ##
###############################################################################
#
# Step 0 - create chroot directory.
#
if [ ${CURRENT_STEP} -le 0 ]; then
	show_status ${CURRENT_STEP} "Creating chroot directory: ${CHROOT_DIR}"
	if [ -z "${CHROOT_DIR}" -o -d "${CHROOT_DIR}" ]; then
		eerror
		eerror "Problem with CHROOT_DIR.  It has either already been created, "
		eerror "or CHROOT_DIR has been unset.  If you wish to start over, "
		eerror "rm -f /var/run/${TESTNAME}*, unmount everything in ${CHROOT_DIR},"
		eerror "rm -rf everything in ${CHROOT_DIR}, try again."
		eerror
		cleanup 1
	fi
	mkdir -p ${CHROOT_DIR} >/dev/null 2>&1
	if [ $? -ne 0 -o ! -d "${CHROOT_DIR}" ]; then
		eerror "Could not create chroot directory: ${CHROOT_DIR}"
		cleanup 1
	fi
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step 1 - determining which stage3 tarball to use, which is challenging to
# do when attempting to automate a stage3 build :)
#
if [ ${CURRENT_STEP} -le 1 ]; then
	show_status ${CURRENT_STEP} "Retrieving stage3 tarball"
	set_stage
	tb=`basename ${STAGE}`
	einfo "fetching: ${tb}"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	wget -O ${CHROOT_DIR}/${tb} ${STAGE} >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 -o ! -f "${CHROOT_DIR}/${tb}" ]; then
		eerror "Could not retrieve ${STAGE}"
		cleanup 1
	fi
	timer_entry ${secs} "retrieve stage tarball"
	timer_add f ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - Extract stage tarball
#
if [ ${CURRENT_STEP} -le 2 ]; then
	set_stage
	tb=`basename ${STAGE}`
	show_status ${CURRENT_STEP} "Extracting stage tarball: ${tb}"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	tar xjpf ${CHROOT_DIR}/${tb} -C ${CHROOT_DIR} >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "Nonzero return code during extraction."
		cleanup 1
	fi
	rm -f ${CHROOT_DIR}/${tb} >/dev/null 2>&1
	timer_entry ${secs} "extract stage tarball"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - Retrieve snapshot
#
if [ ${CURRENT_STEP} -le 3 ]; then
	tb=`basename ${SNAP}`
	show_status ${CURRENT_STEP} "Retrieving portage snapshot: ${tb}"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	wget -O ${CHROOT_DIR}/${tb} ${SNAP} >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 -o ! -f "${CHROOT_DIR}/${tb}" ]; then
		eerror "Could not retrieve ${SNAP}"
		cleanup 1
	fi
	timer_entry ${secs} "retrieve portage snapshot"
	timer_add f ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - Extract snapshot
#
if [ ${CURRENT_STEP} -le 4 ]; then
	tb=`basename ${SNAP}`
	show_status ${CURRENT_STEP} "Extracting portage snapshot: ${tb}"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	tar xjpf ${CHROOT_DIR}/${tb} -C ${CHROOT_DIR}/usr >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 -o ! -d "${CHROOT_DIR}/usr/portage" ]; then
		eerror "Nonzero return code during extraction."
		cleanup 1
	fi
	rm -f ${CHROOT_DIR}/${tb} >/dev/null 2>&1
	timer_entry ${secs} "extract portage snapshot"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - create make.conf
#
if [ ${CURRENT_STEP} -le 5 ]; then
	show_status ${CURRENT_STEP} "Setting up chroot environment"
	einfo "set:  CFLAGS/CHOST"
	cpu=`uname -p`
	myCHOST=""
	myCFLAGS=""
	if [ "${cpu:9:12}" == "Pentium(R) 4" ]; then
		myCHOST="i686-pc-linux-gnu"
		myCFLAGS="-O2 -march=pentium4 -pipe -fomit-frame-pointer"
	elif [ "${cpu:9:14}" == "Pentium(R) III" ]; then
		myCHOST="i686-pc-linux-gnu"
		myCFLAGS="-O2 -march=pentium3 -pipe -fomit-frame-pointer"
	elif [ "${cpu:0:11}" == "Pentium III" ]; then
		myCHOST="i686-pc-linux-gnu"
		myCFLAGS="-O2 -march=pentium3 -pipe -fomit-frame-pointer"
	fi
	#
	# Attempt to set via the user provided settings if we
	# failed to detect the cpu information automatically.
	#
	if [ -z "${myCHOST}" -o -z "${myCFLAGS}" ]; then
		[[ -n "${my_CHOST}"  ]] && myCHOST="${my_CHOST}"
		[[ -n "${my_CFLAGS}" ]] && myCFLAGS="${my_CFLAGS}"
	fi
	#
	# Tell the user to set my_CHOST/my_MARCH if we still can't
	# determine cpu information.
	#
	if [ -z "${myCHOST}" -o -z "${myCFLAGS}" ]; then
		eerror
		eerror "Cannot glean enough information about your cpu to determine"
		eerror "the correct settings for your CFLAGS and CHOST."
		eerror "Try manually setting my_CHOST and my_CFLAGS to whatever"
		eerror "CHOST and CFLAGS settings you desire.  This script has only"
		eerror "been tested with certain autodetected Pentium 3/4's, your"
		eerror "milage may vary, this script might not work at all for you."
		eerror
		cleanup 1
	fi
	conf="${CHROOT_DIR}/etc/make.conf"
	echo "# These settings were generated by `basename $0`." >${conf}
	echo "# This make.conf is for testing purposes only, use at your own" >>${conf}
	echo "# risk!" >>${conf}
	echo "CFLAGS=\"${myCFLAGS}\"" >>${conf}
	echo "CXXFLAGS=\"\${CFLAGS}\"" >>${conf}
	echo "CHOST=\"${myCHOST}\"" >>${conf}
	echo "" >>${conf}

	einfo "set:  USE"
	myUSE="-X -alsa -apm -arts -avi -cups -eds -emboss -gnome -gpm -gstreamer -gtk -gtk2
-imlib -ipv6 -kde -mad -mikmod -motif -mp3 -mpeg -nls -ogg -oggvorbis -opengl -oss
-pam -qt -quicktime -sdl -vorbis -xmms -xv
apache2 mysql nptl nptlonly php userlocales"
	echo "USE=\"${myUSE}\"" >>${conf}
	echo "" >>${conf}

	einfo "set:  FEATURES"
	myFEATURES="-ccache -distcc nodoc noman noinfo"
	echo "FEATURES=\"${myFEATURES}\"" >>${conf}
	echo "" >>${conf}

	einfo "set:  GENTOO_MIRRORS"
	echo "GENTOO_MIRRORS=\"${GENTOO_MIRROR}\"" >>${conf}
	echo "" >>${conf}

	einfo "copy: /etc/resolv.conf"
	cp /etc/resolv.conf ${CHROOT_DIR}/etc/resolv.conf >/dev/null 2>&1
	if [ $? -ne 0 -o ! -f "${CHROOT_DIR}/etc/resolv.conf" ]; then
		eerror
		eerror "Could not copy /etc/resolv.conf, fix the problem"
		eerror "and try again."
		eerror
		cleanup 1
	fi

	einfo "copy: /proc/mounts"
	cp /proc/mounts ${CHROOT_DIR}/etc/mtab >/dev/null 2>&1
	if [ $? -ne 0 -o ! -f "${CHROOT_DIR}/etc/mtab" ]; then
		eerror
		eerror "Could not copy /proc/mounts, not a show stopper though."
		eerror
	fi

	einfo "copy: /etc/localtime"
	cp /etc/localtime ${CHROOT_DIR}/etc/localtime >/dev/null 2>&1
	if [ $? -ne 0 -o ! -f "${CHROOT_DIR}/etc/mtab" ]; then
		eerror
		eerror "Could not copy /etc/localtime, not a show stopper though."
		eerror
	fi

	einfo "create: /etc/locales.build"
	echo 'en_US/ISO-8859-1' >${CHROOT_DIR}/etc/locales.build
	echo 'en_US.UTF-8/UTF-8' >>${CHROOT_DIR}/etc/locales.build

	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - fetch system packages
#
if [ ${CURRENT_STEP} -le 6 ]; then
	show_status ${CURRENT_STEP} "Retrieving system distfiles"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -ef system >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "Could not retrieve system distfiles"
		cleanup 1
	fi
	timer_entry ${secs} "retrieve system distfiles"
	timer_add f ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - fetch world packages
#
if [ ${CURRENT_STEP} -le 7 ]; then
	show_status ${CURRENT_STEP} "Retrieving world distfiles"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -ef world >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "Could not retrieve world distfiles"
		cleanup 1
	fi
	timer_entry ${secs} "retrieve world distfiles"
	timer_add f ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - fetch LAMP packages
#
if [ ${CURRENT_STEP} -le 8 ]; then
	if [ -n "${LAMP}" ]; then
		show_status ${CURRENT_STEP} "Retrieving LAMP distfiles"
		einfo "tail -f ${LOGFILE} to watch progress"
		SECONDS=0
		chroot ${CHROOT_DIR} /usr/bin/emerge -ef ${LAMP} >>${LOGFILE} 2>&1
		rc=$?
		secs=${SECONDS}
		if [ $rc -ne 0 ]; then
			eerror "Could not retrieve LAMP distfiles"
			cleanup 1
		fi
		timer_entry ${secs} "retrieve lamp distfiles"
		timer_add f ${secs}
		einfo "seconds: $secs"
	fi
	set_run_step $((CURRENT_STEP+1))
fi

#
# Mount /dev
#
if ! `grep " ${CHROOT_DIR}/dev " /proc/mounts >/dev/null 2>&1`; then
	einfo "mount: ${CHROOT_DIR}/dev"
	mount -o bind /dev ${CHROOT_DIR}/dev >/dev/null 2>&1
	if ! `grep " ${CHROOT_DIR}/dev " /proc/mounts >/dev/null 2>&1`; then
		eerror
		eerror "failed to mount /dev -> ${CHROOT_DIR}/dev"
		eerror
		cleanup 1
	fi
fi

#
# Mount /proc
#
if ! `grep "none ${CHROOT_DIR}/proc " /proc/mounts >/dev/null 2>&1`; then
	einfo "mount: ${CHROOT_DIR}/proc"
	mount -t proc none ${CHROOT_DIR}/proc >/dev/null 2>&1
	if ! `grep "none ${CHROOT_DIR}/proc " /proc/mounts >/dev/null 2>&1`; then
		eerror
		eerror "failed to mount ${CHROOT_DIR}/proc"
		eerror
		cleanup 1
	fi
fi

#
# Step - gcc upgrade
#
if [ ${CURRENT_STEP} -le 9 ]; then
	show_status ${CURRENT_STEP} "gcc upgrade"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -u sys-devel/gcc >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "gcc upgrade failed"
		cleanup 1
	fi
	timer_entry ${secs} "gcc upgrade"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
	einfo
	einfo "The upgrade of gcc just completed.  This pass stops after gcc "
	einfo "is upgraded in order to allow gcc-config to be run."
	einfo "Before continuing, it is necessary to do this manually.  Note"
	einfo "that this script expects the most recent version of gcc to be"
	einfo "used from here on out, any older versions present will be purged."
	einfo "Here are the commands that need to be run:"
	einfo
	einfo "chroot ${CHROOT_DIR} /bin/bash"
	einfo "gcc-config -l"
	einfo "gcc-config xxxxxx (where xxxxxx is the most recent gcc version"
	einfo "exit (to exit the chroot)"
	einfo
	einfo "After completing this step, run `basename $0` again to continue."
	einfo
	cleanup 0
fi

#
# Step - libtool remerge
#
if [ ${CURRENT_STEP} -le 10 ]; then
	show_status ${CURRENT_STEP} "libtool remerge"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge --oneshot sys-devel/libtool >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "libtool remerge failed"
		cleanup 1
	fi
	timer_entry ${secs} "libtool remerge"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - libstdc++-v3 emerge
#
if [ ${CURRENT_STEP} -le 11 ]; then
	show_status ${CURRENT_STEP} "libstdc++-v3 emerge"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge --oneshot sys-libs/libstdc++-v3 >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "libstdc++-v3 emerge failed"
		cleanup 1
	fi
	timer_entry ${secs} "libstdc++-v3 emerge"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - unmerge pam
#
if [ ${CURRENT_STEP} -le 12 ]; then
	show_status ${CURRENT_STEP} "unmerge pam"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	garbage="pam-login pam"
	chroot ${CHROOT_DIR} /usr/bin/emerge -C ${garbage} >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "unmerge pam failed"
		cleanup 1
	fi
	timer_entry ${secs} "unmerge pam"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - emerge -e system
#
if [ ${CURRENT_STEP} -le 13 ]; then
	show_status ${CURRENT_STEP} "emerge -e system"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -e system >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "emerge -e system failed"
		cleanup 1
	fi
	timer_entry ${secs} "emerge -e system"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - unmerge garbage
#
if [ ${CURRENT_STEP} -le 14 ]; then
	show_status ${CURRENT_STEP} "unmerge garbage"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	garbage="gpm Locale-gettext pkgconfig"
	chroot ${CHROOT_DIR} /usr/bin/emerge -C ${garbage} >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "unmerge garbage failed"
		cleanup 1
	fi
	timer_entry ${secs} "unmerge garbage"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - emerge -e world
#
if [ ${CURRENT_STEP} -le 15 ]; then
	show_status ${CURRENT_STEP} "emerge -e world"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -e world >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "emerge -e world failed"
		cleanup 1
	fi
	timer_entry ${secs} "emerge -e world"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - purge gcc
#
if [ ${CURRENT_STEP} -le 16 ]; then
	show_status ${CURRENT_STEP} "purging gcc"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -C =sys-devel/gcc-3.3* >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "purge of gcc failed"
		cleanup 1
	fi
	timer_entry ${secs} "purge gcc"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - purge old packages
#
if [ ${CURRENT_STEP} -le 17 ]; then
	show_status ${CURRENT_STEP} "purge old python"
	einfo "tail -f ${LOGFILE} to watch progress"
	SECONDS=0
	chroot ${CHROOT_DIR} /usr/bin/emerge -P python >>${LOGFILE} 2>&1
	rc=$?
	secs=${SECONDS}
	if [ $rc -ne 0 ]; then
		eerror "purge failed"
		cleanup 1
	fi
	timer_entry ${secs} "purge old python"
	timer_add b ${secs}
	einfo "seconds: $secs"
	set_run_step $((CURRENT_STEP+1))
fi

#
# Step - build lamp packages
#
if [ ${CURRENT_STEP} -le 18 ]; then
	if [ -n "${LAMP}" ]; then
		show_status ${CURRENT_STEP} "emerging lamp packages"
		einfo "tail -f ${LOGFILE} to watch progress"
		SECONDS=0
		chroot ${CHROOT_DIR} /usr/bin/emerge -n ${LAMP} >>${LOGFILE} 2>&1
		rc=$?
		secs=${SECONDS}
		if [ $rc -ne 0 ]; then
			eerror "emerge failed"
			cleanup 1
		fi
		timer_entry ${secs} "emerge lamp packages"
		timer_add b ${secs}
		einfo "seconds: $secs"
	fi
	set_run_step $((CURRENT_STEP+1))
fi

#
# unmount /dev
#
if `grep " ${CHROOT_DIR}/dev " /proc/mounts >/dev/null 2>&1`; then
	einfo "unmount: ${CHROOT_DIR}/dev"
	umount ${CHROOT_DIR}/dev >/dev/null 2>&1
	if `grep " ${CHROOT_DIR}/dev " /proc/mounts >/dev/null 2>&1`; then
		eerror
		eerror "failed to unmount ${CHROOT_DIR}/dev"
		eerror
	fi
fi

#
# unmount /proc
#
if `grep "none ${CHROOT_DIR}/proc " /proc/mounts >/dev/null 2>&1`; then
	einfo "unmount: ${CHROOT_DIR}/proc"
	umount ${CHROOT_DIR}/proc >/dev/null 2>&1
	if `grep "none ${CHROOT_DIR}/proc " /proc/mounts >/dev/null 2>&1`; then
		eerror
		eerror "failed to unmount ${CHROOT_DIR}/proc"
		eerror
	fi
fi

congrats

