#!/bin/bash
###############################################################################
# Copyright 2005 Mike Green <mikey at badpenguins dot com>                    #
# Distributed under the terms of the GNU General Public License v2            #
#                                                                             #
# This bootstrap script is a heavily modified version of the old gentoo       #
# stage1 bootstrap.sh script.  An unknown number of unidentified gentoo       #
# developers arbitrarily decided during December 2005 to stop supporting      #
# bootstrapping, apparently users are just too stupid to do it correctly.     #
#                                                                             #
# For those people who happen prefer bootstrapping because they actually      #
# want to build their own systems, with their own choices and optimizations,  #
# I dedicate this bootstrap script.  The reality is that the old gentoo       #
# bootstrap script was buggy as hell, which is not the fault of the users.    #
#                                                                             #
# This bootstrap script supports toolchain upgrades, changes to the           #
# CHOST, and nptl.  It also hard codes options that make the bootstrap        #
# as pristine as possible, disabling options like NLS and enabling            #
# userlocales by default.  It is intended to be as simple as possible,        #
# to allow customization by the users.                                        #
###############################################################################
VER="20051223-01"
#
# First things first, define the bare bones base packages that are included
# in a bootstrap build.  The packages will be installed in the order of this
# list.  All package lists will be generic, I trust portage to install
# whatever version is available.
#
BS_PACKAGES="virtual/baselayout sys-apps/portage sys-devel/binutils-config
sys-devel/binutils sys-devel/gcc-config sys-devel/gcc virtual/os-headers
virtual/libc sys-apps/texinfo sys-libs/ncurses sys-libs/zlib"

#
# Certain packages don't like it when the chost changes or when toolchain
# upgrades produce incompatible binaries against the currently installed
# libs.  Instead of counting on hacks like revdep-rebuild or fix_libtools.sh,
# rebuild the packages against the new toolchain instead.  This list of
# packages that need to be rebuilt before running an emerge -e system is
# defined next.  These packages will only be built if a toolchain upgrade
# or chost change is detected.  They will be installed in the order listed,
# with no dependencies installed.
#
CRANKY_PACKAGES="sys-devel/libperl dev-lang/perl dev-lang/python
dev-python/python-fchksum sys-devel/libtool"

#
# Define the location of progress tracking files.
#
progressfile="/var/run/bootstrap-progress"
envfile="/var/run/bootstrap-env"
logfile="/var/run/bootstrap.log"


###############################################################################
# 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
		:
		#
		# Add custom stuff to do after a failure here.
		#
		eerror
		eerror "Exiting nonzero"
		if [ -f "${logfile}" ]; then
			eerror "Take a gander at ${logfile} if you are wondering why."
		fi
		eerror
		exit ${rc}
	fi
	if [[ -n ${STRAP_RUN} ]] ; then
		:
		#
		# Add custom stuff to do after a successful bootstrap here.
		# One possibility - emerge -e system :)
		#
		# export USE=${ORIGUSE}
		# export FEATURES=${ORIGFEATURES}
		# emerge -e system
	fi
	exit ${rc}
	}

###############################################################################
#
do_pause() {
	einfo "Press any key to continue or control-c to cancel..."
	read -n 1 -s junk
	}

###############################################################################
#
draw_line() {
	echo
	echo -------------------------------------------------------------------------------
	}

###############################################################################
# Determine the current binutils version.  Don't rely on what portage reports.
#
runningBinutilsVersion() {
	as --version | head -n 1 | cut -f3 -d' '
	}

###############################################################################
# Parse the current CHOST from the running binutils version.  Don't rely on
# what portage reports.
#
runningBinutilsTarget() {
	as --version | tail -n1 | cut -f2 -d'`' | cut -f1 -d"'"
	}

###############################################################################
#
set_bootstrap_stage() {
	export BOOTSTRAP_STAGE=$1
	[[ -z ${STRAP_RUN} ]] && return 0
	echo "BOOTSTRAP_STAGE=$1" > ${progressfile}
	}

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

###############################################################################
#
offer_pause() {
	[[ "${DO_PAUSE}" == "0" ]] && return
	echo
	einfo "Press any key within 10 seconds to pause..."
	read -t 10 -n 1 -s junk
	if [ $? -eq 0 ]; then
		do_pause
	fi
	}

###############################################################################
#
usage() {
	echo -e "Usage: ${HILITE}${0##*/}${NORMAL} ${GOOD}[options]${NORMAL}"
	echo -e "  ${GOOD}--debug (-d)${NORMAL}      Run with debug information turned on"
	echo -e "  ${GOOD}--fetchonly (-f)${NORMAL}  Just download all the source files"
	echo -e "  ${GOOD}--pretend (-p)${NORMAL}    Display the packages that will be merged"
	echo -e "  ${GOOD}--system (-s)${NORMAL}     After bootstrapping run emerge -e system"
	echo -e "  ${GOOD}--nopause (-np)${NORMAL}   Don't ever pause"
	echo -e "  ${GOOD}--gccpause (-gp)${NORMAL}  Pause after bootstrap of gcc"
	}

###############################################################################
#
v_echo() {
	cmd="$@"
	if [ "${DEBUG}" == "1" -o "${VERBOSE}" == "1" ]; then
		eval ${cmd}
	else
		eval ${cmd} >>${logfile} 2>&1
	fi
	}

###############################################################################
# The most important function - create the envfile that contains the list of  #
# all packages that will be installed, detect chost changes, detect           #
# toolchain upgrades.                                                         #
###############################################################################
generateEnvFile() {
	draw_line
	echo "  [[ Initializing bootstrap environment information ]]"
	echo
	if [ -f "${envfile}" ]; then
		eerror
		eerror "${envfile} already exists and cannot be overwritten."
		eerror "To start over, remove ${envfile} and ${progressfile}."
		eerror
		cleanup 1
	fi
	# run emerge --info to apply updates
	emerge --info >/dev/null 2>&1
	#
	# Locate gcc-config and bintuils-config
	#
	einfo "Locating gcc-config/binutils-config"
	GCC_CONFIG=""
	[[ -x /usr/sbin/gcc-config ]] && GCC_CONFIG="/usr/sbin/gcc-config"
	[[ -x /usr/bin/gcc-config  ]] && GCC_CONFIG="/usr/bin/gcc-config"
	BINUTILS_CONFIG=""
	[[ -x /usr/sbin/binutils-config ]] && BINUTILS_CONFIG="/usr/sbin/binutils-config"
	[[ -x /usr/bin/binutils-config ]]  && BINUTILS_CONFIG="/usr/bin/binutils-config"
	if [ -z "${GCC_CONFIG}" ]; then
		eerror "Cannot locate gcc-config."
		eerror "This script cannot run without it."
		cleanup 1
	fi
	if [ -z "${BINUTILS_CONFIG}" ]; then
		eerror "Cannot locate binutils-config."
		eerror "This script cannot run without it."
		cleanup 1
	fi
	# Parse out properties of binutils and gcc to help detect
	# chost changes or gcc upgrades.  This information will also
	# be used to correctly apply bintils-config/gcc-config later.
	#
	einfo "Querying toolchain information"

	BEG_BINUTILS_VERSION=$(runningBinutilsVersion)
	BEG_BINUTILS_TARGET=$(runningBinutilsTarget)
	BEG_BINUTILS_PROFILE="${BEG_BINUTILS_TARGET}-${BEG_BINUTILS_VERSION}"
	BEG_BINUTILS_PKG="`portageq best_version / binutils`"
	BEG_GCC_VERSION=`gcc -dumpversion`
	BEG_GCC_PROFILE=`${GCC_CONFIG} -c`
	BEG_GCC_TARGET=`echo ${BEG_GCC_PROFILE} | sed s/-${BEG_GCC_VERSION}//g`
	if [ ! "${BEG_BINUTILS_TARGET}" == "${BEG_GCC_TARGET}" ]; then
		eerror "Your toolchain is dorked, fix it and try again."
		eerror "binutils: ${BEG_BINUTILS_TARGET}"
		eerror "gcc:      ${BEG_GCC_TARGET}"
		cleanup 1
	fi
	BEG_CHOST="${BEG_BINUTILS_TARGET}"
	NEW_CHOST="`portageq envvar CHOST`"
	NEW_BINUTILS_PKG="`portageq best_visible / binutils`"
	NEW_BINUTILS_VERSION="$(echo ${NEW_BINUTILS_PKG} | cut -f2 -d/ | cut -f2 -d'-')"
	NEW_BINUTILS_PROFILE="${NEW_CHOST}-${NEW_BINUTILS_VERSION}"
	BEG_GCC_PKG="`portageq best_version / gcc`"
	NEW_GCC_PKG="`portageq best_visible / gcc`"
	NEW_GCC_VERSION="$(echo ${NEW_GCC_PKG} | cut -f2 -d/ | cut -f2 -d'-')"
	NEW_GCC_PROFILE="${NEW_CHOST}-${NEW_GCC_VERSION}"
	CHOST_UPDATE="no"
	TC_UPDATE="no"
	if [ ! "${BEG_CHOST}" == "${NEW_CHOST}" ]; then
		CHOST_UPDATE="yes"
	fi
	if [ ! "${BEG_BINUTILS_PKG}" == "${NEW_BINUTILS_PKG}" ]; then
		TC_UPDATE="yes"
	fi
	if [ ! "${BEG_GCC_PKG}" == "${NEW_GCC_PKG}" ]; then
		TC_UPDATE="yes"
	fi
	#
	# Generate three arrays.  One array containing the names of
	# the packages to install, another containing the beginning
	# version of each package, another containing the upgrade
	# version of each package (if applicable).  These arrays
	# will be used to determine which packages to install and
	# any prunes to perform afterwards.
	#
	NUM_BS_PACKAGES=0
	NUM_CRANKY_PACKAGES=0
	plist="${BS_PACKAGES}"
	junk=(${BS_PACKAGES})
	NUM_BS_PACKAGES=${#junk[@]}
	unset junk
	if [ "${TC_UPDATE}" == "yes" -a -n "${CRANKY_PACKAGES}" ]; then
		plist="${plist} ${CRANKY_PACKAGES}"
		junk=(${CRANKY_PACKAGES})
		NUM_CRANKY_PACKAGES=${#junk[@]}
		unset junk
	fi
	PKGLIST=($plist)
	declare -a BEG_VERSIONS
	declare -a END_VERSIONS
	TOTAL_PACKAGES=${#PKGLIST[@]}
	einfo "Querying package version information for ${TOTAL_PACKAGES} packages"
	ctr=0
	for pkg in ${PKGLIST[@]}
	do
		beg=$(portageq best_version / ${pkg})
		end=$(portageq best_visible / ${pkg})
		if [ -z "${beg}" -a -z "${end}" ]; then
			eerror
			eerror "Cannot query package: $pkg"
			eerror
			cleanup 1
		fi
		# package was not already installed...
		[[ -z "${beg}" ]] && beg=${end}
		BEG_VERSIONS[${ctr}]=${beg}
		END_VERSIONS[${ctr}]=${end}
		ctr=$((ctr+1))
	done
	#
	# Read in some portage environment settings
	#
	ORIGUSE="$(portageq envvar USE)"
	ORIGFEATURES="$(portageq envvar FEATURES)"
	#
	# Seed the envscript with all of these values.
	#
	einfo "Writing ${envfile}"
	L="BEG_BINUTILS_VERSION BEG_BINUTILS_TARGET BEG_BINUTILS_PROFILE
	BEG_GCC_VERSION BEG_GCC_PROFILE BEG_GCC_TARGET BEG_CHOST NEW_CHOST
	BEG_BINUTILS_PKG NEW_BINUTILS_PKG BEG_GCC_PKG NEW_GCC_PKG CHOST_UPDATE
	TC_UPDATE TOTAL_PACKAGES BINUTILS_CONFIG GCC_CONFIG ORIGUSE ORIGFEATURES
	NUM_BS_PACKAGES NUM_CRANKY_PACKAGES NEW_BINUTILS_VERSION
	NEW_BINUTILS_PROFILE NEW_GCC_VERSION NEW_GCC_PROFILE"
	for var in $L
	do
		val=$(eval echo \$$var)
		echo "${var}=\"${val}\"" >>${envfile}
	done
	echo "PKGLIST=\"${PKGLIST[@]}\"" >>${envfile}
	echo "BEG_VERSIONS=\"${BEG_VERSIONS[@]}\"" >>${envfile}
	echo "END_VERSIONS=\"${END_VERSIONS[@]}\"" >>${envfile}
	set_bootstrap_stage 0
	}

###############################################################################
# Handle post-processing of binutils installs.  The goal is to get the system #
# as clean as possible.  Don't trust portage to do everything correctly when  #
# it is this important.  This function will set binutils to the newest        #
# installed version and do everything it can to wipe any remnants of older    #
# versions that might have been left by portage.  Handles changes to CHOST.   #
###############################################################################
process_binutils() {
	draw_line
	echo "  [[ Configuring binutils ]]"
	echo

	cmd="${BINUTILS_CONFIG} ${NEW_BINUTILS_PROFILE}"
	einfo "CMD: ${cmd}"
	v_echo ${cmd}
	CUR="$(${BINUTILS_CONFIG} -c)"
	if [ ! "${CUR}" == "${NEW_BINUTILS_PROFILE}" ]; then
		eerror
		eerror "Failed to set binutils profile"
		eerror
		cleanup 1
	fi
	#
	# Manually remove the remnants, sometimes emerge fails to or refuses.
	#
	if [ ! "${BEG_BINUTILS_PROFILE}" == "${NEW_BINUTILS_PROFILE}" ]; then
		einfo "Cleaning out: ${BEG_BINUTILS_PROFILE}"
		# try to avoid total catastrophes
		if [ -z "${BEG_BINUTILS_PROFILE}" -o -z "${BEG_BINUTILS_TARGET}" \
		     -o -z "${BEG_BINUTILS_VERSION}" ]; then
			error
			eerror "Uh oh, can't remove previous binutils."
			eerror "Some environment information is missing."
			eerror "Check ${toolchainenv} for errors and try again."
			error
			cleanup 1
		fi
		# proceed to tear it up
		rm -f "/etc/env.d/binutils/${BEG_BINUTILS_PROFILE}"
		rm -rf /usr/${BEG_BINUTILS_TARGET}/binutils-bin/${BEG_BINUTILS_VERSION}
		rm -rf /usr/lib/binutils/${BEG_BINUTILS_TARGET}/${BEG_BINUTILS_VERSION}
		rm -f /usr/${BEG_BINUTILS_TARGET}/lib/*${BEG_BINUTILS_VERSION}*
		if [ ! "${BEG_CHOST}" == "${NEW_CHOST}" ]; then
			einfo "Cleaning out old CHOST remnants"
			rm -rf /usr/${BEG_BINUTILS_TARGET}/binutils-bin
			rm -rf /usr/${BEG_BINUTILS_TARGET}/bin
			rm -rf /usr/${BEG_BINUTILS_TARGET}/lib
			rm -rf /usr/lib/binutils/${BEG_BINUTILS_TARGET}
			rm -f /etc/env.d/binutils/config-${BEG_BINUTILS_TARGET}
		fi
	fi
	}

###############################################################################
# Handle post-processing of gcc installs.  The goal is to get the system      #
# as clean as possible.  Don't trust portage to do everything correctly when  #
# it is this important.  This function will set gcc to the newest installed   #
# version, prune out the old version, and do everything it can to wipe any    #
# remnants of older versions that might have been left by portage.  Handles   #
# changes to CHOST.                                                           #
###############################################################################
process_gcc() {
	draw_line
	echo "  [[ Configuring gcc ]]"
	echo

	cmd="${GCC_CONFIG} -f ${NEW_GCC_PROFILE}"
	einfo "CMD: ${cmd}"
	v_echo ${cmd}
	CUR="$(${GCC_CONFIG} -c)"
	if [ ! "${CUR}" == "${NEW_GCC_PROFILE}" ]; then
		eerror
		eerror "Failed to set gcc profile"
		eerror
		eerror "This is possibly a result of inconsistent naming "
		eerror "between the gcc profile and package names."
		eerror
		eerror "Use gcc-config to set the correct gcc profile."
		eerror
		eerror "If everything looks ok, edit ${progressfile},"
		eerror "increment BOOTSTRAP_STAGE to `expr $BOOTSTRAP_STAGE + 1`"
		eerror "and restart the bootstrap."
		eerror
		cleanup 1
	fi
	#
	# Manually remove the remnants, emerge won't do it while it is active
	#
	if [ ! "${BEG_GCC_PROFILE}" == "${NEW_GCC_PROFILE}" ]; then
		# try to avoid total catastrophes
		if [ -z "${BEG_GCC_PROFILE}" -o -z "${BEG_GCC_TARGET}" \
		     -o -z "${BEG_GCC_VERSION}" ]; then
			eerror
			eerror "Uh oh, can't remove previous gcc."
			eerror "Some environment information is missing."
			eerror "Check ${toolchainenv} for errors and try again."
			eerror
			eerror "If everything looks ok, edit ${progressfile},"
			eerror "increment BOOTSTRAP_STAGE to `expr $BOOTSTRAP_STAGE + 1`"
			eerror "and restart the bootstrap."
			eerror
			cleanup 1
		fi
		einfo "Purging: ${BEG_GCC_PROFILE}"
		cmd="emerge -P sys-devel/gcc"
		einfo "CMD: ${cmd}"
		v_echo ${cmd}
		if [ $? -ne 0 ]; then
			eerror
			eerror "Failed to purge the previous gcc (emerge -P sys-devel/gcc)"
			eerror
			eerror "This is not a total showstopper, but some people "
			eerror "might not like old toochain remnants lying around."
			eerror "If everything looks ok, edit ${progressfile},"
			eerror "increment BOOTSTRAP_STAGE to `expr $BOOTSTRAP_STAGE + 1`"
			eerror "and restart the bootstrap."
			eerror
			cleanup 1
		fi
		# manually remove what was not purged
		rm -f /etc/env.d/05gcc-*
		rm -f /etc/env.d/gcc/${BEG_GCC_PROFILE}*
		rm -rf /usr/${BEG_GCC_TARGET}/gcc-bin/${BEG_GCC_VERSION}
		rm -rf /usr/lib/gcc-lib/${BEG_GCC_TARGET}/${BEG_GCC_VERSION}
		rm -rf /usr/lib/gcc/${BEG_GCC_TARGET}/${BEG_GCC_VERSION}
		if [ ! "${BEG_CHOST}" == "${NEW_CHOST}" ]; then
			einfo "Cleaning out old CHOST remnants"
			rm -f /etc/env.d/gcc/${BEG_GCC_PROFILE}*
			rm -rf /usr/${BEG_GCC_TARGET}
			rm -rf /usr/lib/gcc-lib/${BEG_GCC_TARGET}
			rm -rf /usr/lib/gcc/${BEG_GCC_TARGET}
		fi
	fi
	}

###############################################################################
## 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}Gentoo Linux; ${BRACKET}http://www.gentoo.org/${NORMAL}"
echo -e "Copyright 2005 badpenguins.com; Distributed under the GPLv2; Version ${VER}"
echo

#
# Catch major showstoppers early on...
#
MYPROFILEDIR=$(readlink -f /etc/make.profile)
if [[ ! -d ${MYPROFILEDIR} ]] ; then
	eerror "Error:  '${MYPROFILEDIR}' does not exist.  Exiting."
	cleanup 1
fi
[[ -e /etc/profile ]] && source /etc/profile

# Bug #50158 (don't use `which` in a bootstrap).
if ! type -path portageq &>/dev/null ; then
	draw_line
	eerror
	eerror "Your portage version is too old.  Please use a newer stage1 image."
	eerror
	cleanup 1
fi

#
# Initialize settings for current run
#
export BOOTSTRAP_STAGE=${BOOTSTRAP_STAGE:-0}
STRAP_EMERGE_OPTS=""
STRAP_RUN=1
DO_SYSTEM=0
DO_PAUSE=1
GCC_PAUSE=0
DEBUG=0
VERBOSE=0

#
# process command line args
#
for opt in "$@" ; do
	case ${opt} in
		--fetchonly|-f)
			echo "Running in fetch-only mode ..."
			STRAP_EMERGE_OPTS="${STRAP_EMERGE_OPTS} -f"
			unset STRAP_RUN
		;;
		--gccpause|-gp)
			GCC_PAUSE=1
		;;
		--help|-h)
			usage
			exit 0
		;;
		--debug|-d)
			STRAP_EMERGE_OPTS="${STRAP_EMERGE_OPTS} --debug"
			DEBUG=1
		;;
		--nopause|-np)
			DO_PAUSE=0
		;;
		--pretend|-p)
			STRAP_EMERGE_OPTS="${STRAP_EMERGE_OPTS} -p"
			unset STRAP_RUN
		;;
		--system|-s)
			DO_SYSTEM=1
		;;
		--verbose|-v) STRAP_EMERGE_OPTS="${STRAP_EMERGE_OPTS} -v"
			VERBOSE=1
		;;
		--version)
			einfo "Badpenguins.com bootstrap ${VER}"
			exit 0
		;;
		*)
			eerror "Unknown option '${opt}'"
			usage
			exit 1
		;;
	esac
done

#
# Generate a warning if the user has done --nopause and --gccpause
#
if [ "${DO_PAUSE}" == "0" -a "${GCC_PAUSE}" == "1" ]; then
	einfo
	einfo "Warning - you have set --nopause and --gccpause."
	einfo "This script WILL pause after any gcc bootstrap, in spite"
	einfo "of the --nopause argument."
	einfo
	DO_PAUSE=1
	offer_pause
	DO_PAUSE=0
fi

#
# Generate envfile, track progress
#
[[ -e ${envfile} ]] || generateEnvFile
source ${envfile}   || cleanup 1
[[ -e ${progressfile} ]] && source ${progressfile}

#
# What to do if the bootstrap has already happened.
#
if [[ -n ${STRAP_RUN} ]]; then
	if [ ${BOOTSTRAP_STAGE} -ge ${TOTAL_PACKAGES} ] ; then
			einfo
			einfo "System has been bootstrapped already!"
			einfo
			einfo "To start completely over, rm -f /var/run/bootstrap*"
			einfo
			cleanup 0
	fi
fi
if [ ${BOOTSTRAP_STAGE} -gt 0 ] ; then
	einfo "Resuming bootstrap at internal stage #${BOOTSTRAP_STAGE} ..."
else
	einfo "Starting Bootstrap of base system ..."
fi
if [[ ${STRAP_EMERGE_OPTS:0:2} = "-f" ]] ; then
	echo "Fetching all bootstrap-related archives ..."
fi

#
# Take care of environment issues that might cause problems.
#
# This should not be set to get glibc to build properly. See bug #7652.
unset LD_LIBRARY_PATH
# We do not want stray $TMP, $TMPDIR or $TEMP settings
unset TMP TMPDIR TEMP
# Make sure we automatically clean old instances, else we may run
# into issues, bug #32140.
export AUTOCLEAN="yes"
# Allow portage to overwrite stuff
export CONFIG_PROTECT="-*"
# Disable collision-protection and other stuff that add guaranteed
# difficulties debugging problems that can easily be avoided.
export FEATURES="-* noman noinfo nodoc -distcc -ccache -collision-protect"
# Speed things up
export CLEAN_DELAY=0
export EBEEP_IGNORE=0
export EMERGE_WARNING_DELAY=0
export EPAUSE_IGNORE=0

#
# Process the acceptable bootstrap USE flags.
#
STAGE1_USE=""
for opt in ${ORIGUSE} ; do
	case "${opt}" in
		build|bootstrap)
			echo
			eerror "You have 'build' or 'bootstrap' in your USE flags. Please"
			eerror "remove it before trying to continue, since these USE flags"
			eerror "are automatically set as needed by this script."
			echo
			cleanup 1
		;;
		nptl)
			USE_NPTL=1
		;;
		nptlonly)
			USE_NPTLONLY=1
		;;
		multilib)
			STAGE1_USE="${STAGE1_USE} multilib"
		;;
	esac
done

# add userlocales if we find a locales.build
if [ -e "/etc/locales.build" ]; then
	STAGE1_USE="${STAGE1_USE} userlocales"
fi

# Sanity check on nptl
if [ "${USE_NPTL}" = "1" -o "${USE_NPTLONLY}" = "1" ] ; then
	headers="$(portageq best_visible / '>=sys-kernel/linux-headers-2.6.0')"
	if [ -z "${headers}" ]; then
		echo
		eerror "Sorry, the minimum version of kernel headers are not available."
		eerror "NPTL cannot be used.  Fix your USE flags and try again."
		echo
		cleanup 1
	fi
	[ "${USE_NPTL}" = "1" ] && STAGE1_USE="${STAGE1_USE} nptl"
	# Should we build with nptl only?
	[ "${USE_NPTLONLY}" = "1" ] && STAGE1_USE="${STAGE1_USE} nptlonly"
fi

###############################################################################
## Here is where we get down to the real nut cuttin                          ##
###############################################################################
rm -f ${logfile}
PKGLIST=(${PKGLIST})
BEG_VERSIONS=(${BEG_VERSIONS})
END_VERSIONS=(${END_VERSIONS})
#
# draw the menu displaying basic stats
#
draw_line
echo "  [[ Bootstrap Information ]]"
echo
einfo "Bootstrap Packages: ${NUM_BS_PACKAGES}"
einfo "Cranky Packages:    ${NUM_CRANKY_PACKAGES}"
einfo "Total Packages:     ${TOTAL_PACKAGES}"
einfo "Remaining Packages: $(expr ${TOTAL_PACKAGES} - ${BOOTSTRAP_STAGE})"
einfo "CHOST Update?       ${CHOST_UPDATE}"
einfo "Toolchain Update?   ${TC_UPDATE}"
if [ "${DO_PAUSE}" == "1" ]; then
	einfo "Pausing:            On"
else
	einfo "Pausing:            Off"
fi
if [ "${GCC_PAUSE}" == "1" ]; then
	einfo "Pause after GCC?    Yes"
else
	einfo "Pause after GCC?    No"
fi
if [ "${DO_SYSTEM}" == "1" ]; then
	einfo "Emerge System?      Yes"
else
	einfo "Emerge System?      No"
fi
offer_pause

draw_line
echo "  [[ Portage Settings ]]"
echo
PORTAGE_ENV="GENTOO_MIRRORS PORTDIR DISTDIR PKGDIR PORTAGE_TMPDIR
CFLAGS CHOST CXXFLAGS MAKEOPTS ACCEPT_KEYWORDS http_proxy
ftp_proxy"
for var in ${PORTAGE_ENV} ; do
	val=$(portageq envvar "${var}")
	einfo "${var}=\"${val}\""
done
for var in FEATURES AUTOCLEAN CONFIG_PROTECT STAGE1_USE
do
	val=$(eval echo \$$var)
	einfo "${var}=\"${val}\""
done
offer_pause

if [ ${BOOTSTRAP_STAGE} -gt 0 ]; then
	draw_line
	echo "  [[ Installed Packages ]]"
	echo
	ctr=0
	while [ $ctr -lt ${BOOTSTRAP_STAGE} ]; do
		einfo ${PKGLIST[$ctr]}
		ctr=$((ctr+1))
	done
	offer_pause
fi

draw_line
echo "  [[ Remaining Packages ]]"
echo
ctr=${BOOTSTRAP_STAGE}
while [ $ctr -lt ${TOTAL_PACKAGES} ]
do
	einfo ${PKGLIST[$ctr]}
	ctr=$((ctr+1))
done
offer_pause

#
# Handle bootstrap packages first, loop through each package one at a
# time.  Install/fetch it, process any cleanup/prune, continue until they
# are all installed.
#
while [ ${BOOTSTRAP_STAGE} -lt ${NUM_BS_PACKAGES} ]
do
	pkg=${PKGLIST[${BOOTSTRAP_STAGE}]}
	unset cmd
	EXTRA_OPTS="--oneshot --nodeps"
	echo
	# Tell the user whats up
	draw_line
	show_status $(expr ${BOOTSTRAP_STAGE} + 1) Installing ${pkg}
	echo
	#
	# some packages require unique USE flags, account for them here.
	#
	case ${pkg} in
		"sys-apps/portage")
			export USE="-* build bootstrap ${STAGE1_USE}"
			cmd="USE=\"${USE}\" emerge ${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}"
		;;
		"sys-libs/ncurses")
			export USE="-* build bootstrap minimal ${STAGE1_USE}"
			export COMPILE_NCURSES=true
			cmd="USE=\"${USE}\" emerge ${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}"
		;;
		*)
			export USE="-* bootstrap minimal ${STAGE1_USE}"
			cmd="USE=\"${USE}\" emerge ${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}"
		;;
	esac
	#
	# run the command
	#
	if [ -z "${cmd}" ]; then
		eerror
		eerror "Cannot determine how to handle package: ${pkg}"
		eerror
		cleanup 1
	fi
	einfo "USE:    \"${USE}\""
	einfo "EMERGE: \"${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}\""
	einfo "CUR:    ${BEG_VERSIONS[${BOOTSTRAP_STAGE}]}"
	einfo "NEW:    ${END_VERSIONS[${BOOTSTRAP_STAGE}]}"
	if [ "${DEBUG}" == "0" -o "${VERBOSE}" == "0" ]; then
		einfo "LOG:    ${logfile}"
	fi

	v_echo ${cmd}
	if [ $? -ne 0 ]; then
		eerror
		eerror "FAILED: ${cmd}"
		eerror
		cleanup 1
	fi
	#
	# skip post-processing if we are fetching or pretending only.
	#
	if [[ -z "${STRAP_RUN}" ]]; then
		set_bootstrap_stage $((BOOTSTRAP_STAGE+1))
		continue
	fi
	#
	# Handle any special post processing here
	#
	case ${pkg} in
		sys-devel/binutils)
			process_binutils
			if [ $? -ne 0 ]; then
				eerror
				eerror "Configuration of binutils failed, game over"
				eerror
				cleanup 1
			fi
		;;
		sys-devel/gcc)
			process_gcc
			if [ $? -ne 0 ]; then
				eerror
				eerror "Configuration of gcc failed, game over"
				eerror
				cleanup 1
			fi
			if [ "${GCC_PAUSE}" == "1" ]; then
				echo
				einfo "The installation of the gcc compiler has just completed."
				einfo "If you wish to use new CFLAGS, now would be a good time"
				einfo "to pause, exit with control-c, edit your CFLAGS, and"
				einfo "restart the bootstrap script."
				echo
				set_bootstrap_stage $((BOOTSTRAP_STAGE+1))
				do_pause
				continue
			fi
		;;
	esac
	#
	# Everything went ok!  Carry on back at the top of the loop!
	#
	set_bootstrap_stage $((BOOTSTRAP_STAGE+1))
done

#
# Handle remaining (non-bootstrap) packages now, loop through each package
# one at a time.  Install/fetch it, process any cleanup/prune, continue
# until they are all installed.  Unset all USE, FEATURES, etc.. flags, use
# whatever is present in make.conf, the profile, and the portage files.
#
unset USE
unset FEATURES
unset AUTOCLEAN
unset CONFIG_PROTECT
unset STAGE1_USE
while [ ${BOOTSTRAP_STAGE} -lt ${TOTAL_PACKAGES} ]
do
	pkg=${PKGLIST[${BOOTSTRAP_STAGE}]}
	unset cmd
	EXTRA_OPTS="--oneshot"
	echo
	# Tell the user whats up
	draw_line
	show_status $(expr ${BOOTSTRAP_STAGE} + 1) Installing ${pkg}
	echo
	#
	# Some packages require unique USE flags, account for them here.
	#
	case ${pkg} in
		"example-category/example-package")
			cmd="USE=\"whatever flags you want\" emerge ${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}"
		;;
		*)
			cmd="emerge ${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}"
		;;
	esac
	#
	# run the command
	#
	if [ -z "${cmd}" ]; then
		eerror
		eerror "Cannot determine how to handle package: ${pkg}"
		eerror
		cleanup 1
	fi
	einfo "EMERGE: \"${STRAP_EMERGE_OPTS} ${EXTRA_OPTS} ${pkg}\""
	einfo "CUR:    ${BEG_VERSIONS[${BOOTSTRAP_STAGE}]}"
	einfo "NEW:    ${END_VERSIONS[${BOOTSTRAP_STAGE}]}"
	if [ "${DEBUG}" == "0" -o "${VERBOSE}" == "0" ]; then
		einfo "LOG:    ${logfile}"
	fi

	v_echo ${cmd}
	if [ $? -ne 0 ]; then
		eerror
		eerror "FAILED: ${cmd}"
		eerror
		cleanup 1
	fi
	#
	# skip post-processing if we are fetching or pretending only.
	#
	if [[ -z "${STRAP_RUN}" ]]; then
		set_bootstrap_stage $((BOOTSTRAP_STAGE+1))
		continue
	fi
	#
	# Handle any special post processing here
	#
	case ${pkg} in
		dev-lang/perl)
			# Purge old, don't care if it fails
			einfo "purging old versions"
			cmd="emerge -P ${pkg}"
			v_echo ${cmd}
		;;
		dev-lang/python)
			# Purge old, don't care if it fails
			einfo "purging old versions"
			cmd="emerge -P ${pkg}"
			v_echo ${cmd}
		;;
		sys-devel/libperl)
			# Purge old, don't care if it fails
			einfo "purging any old versions"
			cmd="emerge -P ${pkg}"
			v_echo ${cmd}
		;;
	esac
	#
	# Everything went ok!  Carry on back at the top of the loop!
	#
	set_bootstrap_stage $((BOOTSTRAP_STAGE+1))
done

draw_line
if [ "${DO_SYSTEM}" == "1" ] ; then
	einfo
	einfo "Proceeding with system build (emerge ${STRAP_EMERGE_OPTS} -e system)"
	einfo
	offer_pause
	emerge ${STRAP_EMERGE_OPTS} -e system
	if [ $? -eq 0 ]; then
		set_bootstrap_stage $((BOOTSTRAP_STAGE+1))
	fi
	cleanup $?
fi

if [ -n "${STRAP_RUN}" ]; then
	einfo
	einfo "You are now ready for a system build (emerge -e system)"
	einfo
	einfo "To restart a bootstrap, rm /var/run/bootstrap*"
	einfo
fi

cleanup 0
