#!/bin/bash
# script to get and build a kernel with patches applied
# Exmaples:
# build stock 2.5.59 [opts]
# build cvs user@host.com/var/cvs linux-2.5 [-r REV | -D DATE ] [opts]
# build bk http://linux.bkbits.net/linux-2.5 [-rREV] [opts]
# build url http://system.com/kernel.tgz [opts]
# build url ftp://system.com/kernel.tgz [opts]
# build file /full/path/on/the/local/machine/kernel.tgz [opts]
# build dir /full/path/to/a/kernel/directory/linux/ [opts]
#
# Where opts can be:
#	-C url    Where url is an http or ftp url to a file with the explicit
#		kernel options wanted, or url is just a full path to a file on
#		the current system.
#   -c url    Where url is an http or ftp url to a file with the explicit
#		kernel options wanted, or url is just a full path to a file on
#		the current system.  This file will be applied to the existing
#		config file.  So the
#		specified file should only include lines that the user wants to
#		explicitly set one way or another.  The standard config files
#		can be viewed in the server repository.  However, if the server
#		repository knows nothing about the given machine, i.e. the
#		machine is not in the grid, and the script is being called
#		stand alone, the specified file will end up getting used
#		verbatim.
#
#   -t  dowload ppc64 toolschain
#
#   -p(R)? url  Where url is an http or ftp url to a patch file, or url is 
#               just a full path to a patch file on the current system.  If 
#               the switch is given like -pR, then the given patch will be
#		backed out of the tree
#
#   -m	 all subsequent arguments go to make
#
#  The -c and -p options may be repeated.  The config options, and patch files
#  will be applied in the order specified.  No file specified as the source
#  for the kernel, patch, or config will be modified.  (i.e. get_kernel dir
#  will copy the specified directory)
#

. /etc/autobench.conf || . functions

if [ $# -lt 2 ]; then
  echo "You must specify at least two arguments: type, and source"
  exit 86
fi


CMD_LINE=$@
SRC="$1 $2"
log "using $1 as source argument"
log "using $2 as source argument"
shift 2
while [ $# -gt 0 -a \( "$1" != "-c" -a "$1" != "-p" -a "$1" != "-C" -a "$1" != "-t"  -a "$1" != "-m" \) ]; do
  log "using $1 as source argument"
  SRC="$SRC $1"
  shift
done

KERNDIR=$TMPDIR/build
if [ -e $KERNDIR ]; then
  log "Removing kernel source tree..."
  rm -rf $KERNDIR
fi

# Fetch the kernel source
get_kernel $KERNDIR $SRC
check_status "Getting the kernel"

MAKE_ARGS=""
# Apply any config files or patches
while [ $# -gt 0 ]; do
  case $1 in 
    -p*)
	get_file_as $TMPDIR/patch $2
	check_status "Getting patch $2"
	pushd $KERNDIR > /dev/null
	if [ -n "${1:2}" ]; then
		PATCH_ARGS="-${1:2}";
	fi
	# we don't particularly need to see the output of
	# patch.  Errors will show through
	patch $PATCH_ARGS -p1 -i $TMPDIR/patch > /dev/null
	check_status "Applying patch $2"
	popd > /dev/null
	rm $TMPDIR/patch
	shift 2
	;;
    -C)
	get_file_as $KERNDIR/.config $2
	check_status "Getting config options $2"
	shift 2
	;;
    -t)
    if [ "`uname -m`" == "ppc64" ]; then
    	getcommand ppc_64-bit_userspace
    	ppc_64-bit_userspace;
    	export CROSS_COMPILE=/usr/local/ppc64-3.3/bin/powerpc64-linux-
    fi;
	shift 1
	;;
    -c)
	get_file_as $TMPDIR/config $2
	check_status "Getting config overide options $2"
	apply_config $TMPDIR/config $KERNDIR/.config
	check_status "Applying config options $2"
	rm $TMPDIR/config
	shift 2
	;;
    -m)
	# this just signals the start of arguments for make 
	# it is safe to discard
	shift;
	while [ $# -gt 0 ]; do
		log "argument $1 after -m, forwarding on to make"
		MAKE_ARGS="$MAKE_ARGS $1";
		log "make args -- $MAKE_ARGS"
		shift
	done;
	break;
	;;
    *)
	log "Unknown option to build $1, forwarding on to make"
	MAKE_ARGS="$MAKE_ARGS $1";
	log "make args -- $MAKE_ARGS"
	shift
	;;
  esac
done

# Figure out which build of the kernel in this .dat this is.
IT=1
while [ -d $NONTESTLOGDIR/build$IT ]; do
  IT=$(($IT+1))
done
BUILD_RESULTS=$NONTESTLOGDIR/build$IT


pushd $KERNDIR
# Append -autokern$IT to the extra version in the makefile
# only if it isn't already there
if grep -v 'EXTRAVERSION=.*autokern' Makefile > /dev/null; then
	cat Makefile | sed -e "s/^EXTRAVERSION *= *\(.*\) *$/EXTRAVERSION = \1-autokern$IT/" > Makefile.new
	rm Makefile
	mv Makefile.new Makefile
fi

# instead of showing the whole output of oldconfig, just 
# show a diff
cp .config .config.old
yes '' | make oldconfig > /dev/null
log 'oldconfig diff:'
diff -ur .config.old .config
rm .config.old

log 'Building dependencies'
make dep
check_status "Make dep."

log "Building kernel - make $MAKE_ARGS install"
# the kernel will try to run ~/bin/installkernel
# this ensures that this works
OLDHOME=$HOME
HOME=$AUTODIR/scripts
log "building kernel - make $MAKE_ARGS install"
make -j8 $MAKE_ARGS 
check_status "Build the kernel."
rm -f /boot/*autobench*autokern* 2>/dev/null
make install
check_status "Install the kernel."
HOME=$OLDHOME

if grep -q 'CONFIG_MODULES=y' .config; then
	make $MAKE_ARGS modules
	check_status "Build the modules."
	rm -rf /lib/modules/*autokern* 2> /dev/null
	make modules_install
fi

popd

#
# Save a copy in the logs
#
# the make install script put everything in
# /boot for us
#
#mkdir -p $BUILD_RESULTS
#echo $CMD_LINE > $BUILD_RESULTS/build-command-line
#cp /boot/*$MAJOR.$MINOR.$PATCH${EXTRA}-autokern$IT $BUILD_RESULTS
#tar zcf $BUILD_RESULTS/modules.$IT.tgz /lib/modules/*autokern$IT

log "Build of kernel complete"
