#!/bin/sh

# option variables
DESTDIR=
KERNELDIR=
TARGET=
# Not sure what to put here
# TARGET_ARCH=$(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
TARGET_ARCH=
TARGET_CONFIG=
JOBS=1
CONFIGURE_FLAGS=
TMPDIR=${TMPDIR:-"/var/tmp"}

# commands to run
BUILD_LUSTRE=0
BUILD_KERNEL=0
DEPEND_KERNEL=0
INSTALL_LUSTRE=0
INSTALL_KERNEL=0
SAVE_HEADERS=0
UNPACK_KERNEL=0

# provided by target file
KERNEL=
SERIES=
CONFIG=
VERSION=
EXTRA_VERSION=

BASE_ARCHS=
BIGMEM_ARCHS=
BOOT_ARCHS=
JENSEN_ARCHS=
SMP_ARCHS=
BIGSMP_ARCHS=
PSERIES64_ARCHS=
UP_ARCHS=

RHBUILD=0
SUSEBUILD=0

# flat-out globals
TOPDIR=
TARGET_FILE=
KERNEL_FILE=
SERIES_FILE=
CONFIG_FILE=
RPMBUILD=

canon()
{
    pushd $1 >/dev/null
    echo $PWD
    popd >/dev/null
}
TOPDIR="${0%%${0##*/}}"
if [ "${TOPDIR}" ] ; then
    TOPDIR=$(canon "${TOPDIR}/..")
else
    TOPDIR=$(canon "..")
fi

lbuild_topdir()
{
    retdir=$TOPDIR
    while [ ! -d $retdir/BUILD ] ; do
	retdir=$(canon "$retdir/..")
	if [ "$retdir" = "/" ] ; then
	    break;
	fi
    done
    echo "$retdir"
}

cleanup()
{
    true
}

fatal()
{
    cleanup
    [ "$2" ] && echo
    [ "$2" ] && echo "${0##*/}: $2"
    exit $1
}

list_targets()
{
    echo -n "Available targets:"
    for target in $TOPDIR/lustre/kernel_patches/targets/*.target ; do
	target_file=${target##*/}
	echo -n " ${target_file%%.target}"
    done
    echo
}


usage()
{
    cat <<EOF
Usage: ${0##*/} [OPTION]... [-- <lustre configure options>]

Options:

  --build
    same as --build-kernel --build-lustre --unpack-kernel

  --build-lustre
    configure and compile lustre.  Requires that --build-kernel was
    already run.

  --build-kernel
    configure and compile a kernel.  Implies --depend-kernel.
    Requires that --unpack-kernel was already run.

  --depend-kernel)
    Prepares a kernel tree for building (similar to make mrproper
    oldconfig dep).  Requires that --unpack-kernel was already run.

  --destdir=DESTDIR
    Root directory to install into (like DESTDIR with auto*).

  --extraversion=EXTRAVERSION
    Overrides the target kernel\'s EXTRAVERSION text.

  -h, --help
    Display this message.

  --install
    same as --install-kernel --install-lustre

  --install-lustre
    run make install in the Lustre tree.

  --install-kernel
    install the kernel image and modules.

  -j jobs
    This works just like the -j option to make, and is passed to make
    when building.

  --kerneldir=KERNELDIR
    Directory containing linux source tarballs.

  --target=TARGET
    Name of the configuration to use.  The available targets are
    listed below.

  --target-arch=ARCH
    Specifies an architecture to use when choosing a kernel config
    file.  Default is i386.

  --target-config=CONFIG
    Specifies a special option (such as smp, bigsmp, bigmem, or BOOT)
    to use when choosing a kernel config file.  This also modifies the
    kernel version and modules directory.

  --unpack-kernel
    Untars and patches the kernel source.

  The order that commands (--build-lustre, --unpack-kernel) are
  specified on the command line is ignored; ${0##*/} will always
  execute them in the correct order (unpack, then build, then install
  etc.).

EOF
    list_targets

    fatal "$1" "$2"
}

check_options()
{
    (( $BUILD_LUSTRE || $BUILD_KERNEL || $DEPEND_KERNEL || \
	    $INSTALL_LUSTRE || $INSTALL_KERNEL || $SAVE_HEADERS || \
	    $UNPACK_KERNEL )) || \
		fatal 1 "No commands specified."

    if (( $UNPACK_KERNEL )) ; then
	[ "$KERNELDIR" ] || \
	    fatal 1 "A kernel directory must be specified with --kerneldir."
	[ -d "$KERNELDIR" ] || \
	    fatal 1 "$KERNELDIR is not a directory."
    fi

    if (( $INSTALL_LUSTRE || $INSTALL_KERNEL || $SAVE_HEADERS )) ; then
	[ -z "$DESTDIR" -o -d "$DESTDIR" ] || \
	    fatal 1 "$DESTDIR is not a directory."
    fi

    [ "$TARGET" ] || usage 1 "A target must be specified with --target."
    TARGET_FILE="$TOPDIR/lustre/kernel_patches/targets/$TARGET.target"
    [ -r "$TARGET_FILE" ] || \
	fatal 1 "Target '$TARGET' was not found.  Try --list-targets."

    if [ -z "$JOBS" -o "$JOBS" -lt "1" ] ; then
	JOBS=1
    fi

    RPMBUILD=$(which rpmbuild 2>/dev/null | head -1)
    if [ ! "$RPMBUILD" -o "$RPMBUILD" == "" ]; then
	RPMBUILD=$(which rpm 2>/dev/null | head -1)
	if [ ! "$RPMBUILD" -o "$RPMBUILD" == "" ]; then
	    usage 1 "Could not find binary for making rpms (tried rpmbuild and rpm)."
	fi
    fi
}

get_lustre_version()
{
    for series in $SERIES ; do
	SERIES_FILE="$TOPDIR/lustre/kernel_patches/series/$series"
	lustre_patch=$(grep lustre_version "$SERIES_FILE" 2>/dev/null)
	[ "$lustre_patch" ] && break
    done
    [ "$lustre_patch" ] || \
	fatal 1 "Could not determine Lustre version from $SERIES series."

    awk '/^\+#define LUSTRE_KERNEL_VERSION /{ print $3 }' \
	"$TOPDIR/lustre/kernel_patches/patches/$lustre_patch" 2>/dev/null
}

load_target()
{
    EXTRA_VERSION_save="$EXTRA_VERSION"

    . "$TARGET_FILE"

    [ "$KERNEL" ] || fatal 1 "Target $TARGET did not specify a kernel."
# Suse 2.6 has our patches in already
#    [ "$SERIES" ] || fatal 1 "Target $TARGET did not specify a patch series."
#    [ "$CONFIG" ] || fatal 1 "Target $TARGET did not specify a kernel config."
    [ "$VERSION" ] || fatal 1 "Target $TARGET did not specify the kernel version."
    
    if [ "$KERNELDIR" ] ; then
	KERNEL_FILE="$KERNELDIR/$KERNEL"
	[ -r "$KERNELDIR/$KERNEL" ] || \
	    fatal 1 "Target $TARGET's kernel file $KERNEL not found in kernel directory $KERNELDIR."
    fi

    if [ "$SERIES" ] ; then
	for series in $SERIES ; do
	    SERIES_FILE="$TOPDIR/lustre/kernel_patches/series/$series"
	    [ -r "$SERIES_FILE" ] || \
		fatal 1 "Target $TARGET's series $SERIES missing from $TOPDIR/lustre/kernel_patches/series."
	done
    fi

    TARGET_ARCH=${TARGET_ARCH:-$BASE_ARCHS}
    CONFIG_TARGET="$TARGET-${TARGET_ARCH}${TARGET_CONFIG:+-$TARGET_CONFIG}"
    CONFIG_FILE="$TOPDIR/lustre/kernel_patches/kernel_configs/kernel-$VERSION-$CONFIG_TARGET.config"
    [ -r "$CONFIG_FILE" ] ||
	fatal 1 "Target $TARGET's config file $CONFIG_FILE missing from $TOPDIR/lustre/kernel_patches/configs."

    if [ "$EXTRA_VERSION_save" ] ; then
	EXTRA_VERSION="$EXTRA_VERSION_save"
    else
	EXTRA_VERSION="${EXTRA_VERSION}_lustre.$(get_lustre_version)"
    fi
}

# do these after load_target(), which maybe export CC
setup_ccache_distcc()
{
    # distcc can't handle ".incbin"
    if [ "$TARGET" == "2.6-suse" -o "$TARGET" == "2.6-rhel4" ]; then
        if [ "$TARGET_ARCH" == "x86_64" ]; then
            unset DISTCC
        fi
    fi
    
    CC=${CC:-gcc}
    if [ "$CCACHE" ]; then
        CC="$CCACHE $CC"
        [ "$DISTCC" ] && export CCACHE_PREFIX="$DISTCC"
    else
        [ "$DISTCC" ] && CC="$DISTCC $CC"
    fi
}

tarflags()
{
    case "$1" in
	'')
	    fatal 1 "tarflags(): File name argument missing."
	    ;;
	*.tar.gz | *.tgz)
	    echo 'zxf'
	    ;;
	*.tar.bz2)
	    echo 'jxf'
	    ;;
	*.tar)
	    echo 'xf'
	    ;;
	*)
	    fatal 1 "tarflags(): Unrecognized tar extension in file: $1"
	    ;;
    esac
}

untar()
{
    echo "Untarring ${1##*/}..."
    tar $(tarflags $1) $1
}


extract_kernel()
{
    (( $UNPACK_KERNEL )) || return 0
    pushd "$TOPDIR" >/dev/null
    if [ -d linux ] ; then
	[ -L linux ] && rm -rf $(readlink linux)
	rm -rf linux
    fi
    untar "$KERNEL_FILE"
    [ -d linux ] || ln -sf linux* linux
    popd >/dev/null
}

patch_kernel()
{
    (( $UNPACK_KERNEL )) || return 0
    [ "$SERIES" ] || return 0
    pushd "$TOPDIR/linux" >/dev/null
    for series in $SERIES ; do
	echo -n "Applying series $series:"
	SERIES_FILE="$TOPDIR/lustre/kernel_patches/series/$series"
	for patch in $(<"$SERIES_FILE") ; do
	    PATCH_FILE="$TOPDIR/lustre/kernel_patches/patches/$patch"
	    [ -r "$PATCH_FILE" ] || \
		fatal 1 "Patch file not found: $patch"
	    echo -n " $patch"
	    patch -s -p1 < "$PATCH_FILE" || fatal 1 "Error applying patch $patch."
	done
	echo
    done
    popd >/dev/null
}

set_make()
{
    MAKE="make -s"
    [ "$CC" ] && {
        if [ "$TARGET_ARCH" == "ppc64" ] ; then
                MAKE_CC="CC=$CC -m64"
        else 
                MAKE_CC="CC=$CC"
        fi
    }
    if [ "$ARCH" ] ; then
	MAKE_ARCH="$MAKE ARCH=$ARCH"
    else
	case $TARGET_ARCH in
	    i?86)
                ;;
            *)
	        MAKE_ARCH="$MAKE ARCH=$TARGET_ARCH"
		;;
        esac
    fi
    MAKE_J="$MAKE -j $JOBS"
}

timed_run() {
    SLEEP_TIME=$1
    shift

    set -o monitor

    #bash -c "$@" &
    ("$@") &
    child_pid=$!
    
    (sleep $SLEEP_TIME
    kill -TERM -$child_pid 2>/dev/null
    sleep 5
    kill -KILL -$child_pid 2>/dev/null
    echo "$1 was killed due to timeout") &
    dog_pid=$!

    wait $child_pid
    # status will be set to 143 if the process had to be killed due to timeout
    status=${PIPESTATUS[0]}
    kill -KILL -$dog_pid
    return $status
}

depend_kernel()
{
    (( $DEPEND_KERNEL )) || return 0
    # we need to override $CC at make time, since there is no
    # configure
    set_make
    pushd "$TOPDIR/linux" >/dev/null
    echo "Overriding EXTRAVERSION in kernel..."
    local extra_version="${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}"
    if [ -n "${TARGET_CONFIG}" ]; then
	extra_version="${extra_version}${TARGET_DELIMITER}${TARGET_CONFIG}"
    fi
    perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = ${extra_version}/" Makefile
    echo "Making depend in $PWD..."
    $MAKE "$MAKE_CC" mrproper || fatal 1 "Error running make mrproper"
    rm -f rpm-release
    # remove localversion-* files to avoid kernel release string 
    # srewing up by the top-level Makefile
    rm -f localversion-*
    cp "$CONFIG_FILE" .config
    local UPDATE_OLDCONFIG=
    for oc in oldconfig_nonint silentoldconfig oldconfig ; do                   
        if grep -q "$oc" Makefile ; then                                        
            timed_run 300 $MAKE "$MAKE_CC" $oc || UPDATE_OLDCONFIG=1
            break
        fi
    done

    if [ "$UPDATE_OLDCONFIG" ] ; then
        # use the expect script to "make oldconfig" and answer the questions for
        # new items conservatively.  QA will get notified on anything newly added
        # for them to review and adjust accordingly.
        local logfile=$(mktemp /tmp/XXXXXX)
        #timed_run 300 $TOPDIR/build/update_oldconfig $logfile
        #local RC=${PIPESTATUS[0]}
        #local RC=$(strace -f -o update_oldconfig.strace bash -c "$TOPDIR/build/update_oldconfig $logfile; echo \$?")
        $TOPDIR/build/update_oldconfig $logfile
        local RC=${PIPESTATUS[0]}
        #$TOPDIR/build/update_oldconfig $logfile
        #local RC=${PIPESTATUS[0]}
        if [ $RC -eq 143 ]; then
            fatal 1 "update_oldconfig timed out"
        elif [ $RC -ne 0 ]; then
	    # dump the log
            cat $logfile
            rm -f $logfile
	    if [ -f update_oldconfig.strace ]; then
	        cat update_oldconfig.strace
	        rm -f update_oldconfig.strace
            fi
            fatal 1 "update_oldconfig failed: $RC. See log above."
        fi
    fi
    rm -f $logfile
    # now notify if resulting .config is different than $CONFIG_FILE
    local tmpfile=$(mktemp /tmp/XXXXXX)
    diff -I '^#.*' -u "$CONFIG_FILE" .config >$tmpfile
    if [ -s $tmpfile ]; then
        { cat <<EOF
To: lustre-qa-team@sun.com
Subject: kernel_config change 

The result of a make oldconfig on file $CONFIG_FILE resulted in a
difference when compared to .config in the following way:

EOF
        cat $tmpfile
        echo -e "\n\nPlease consider updating $CONFIG_FILE for version: $extra_version."
        # not sure these are entirely useful.  the above and "patch" are good
        #echo -e "\nThe entire new .config file:\n"
        #cat .config
        # sadly, the build roots can't e-mail out, so we can only display this
        # to stderr for an interested party to inspect
        #} | sendmail -flustre-qa-team@sun.com -t
        } >&2
    fi
    rm -f $tmpfile

    case "$VERSION" in
	2.6*)
            $MAKE "$MAKE_CC" include/asm
            ;;
        2.4*)
	    $MAKE "$MAKE_CC" symlinks
	    $MAKE "$MAKE_CC" dep || fatal 1 "Error running make dep"
	    ;;
    esac
    $MAKE "$MAKE_CC" include/linux/version.h || fatal 1 "Error making include/linux/version.h"
}

build_kernel()
{
    (( $BUILD_KERNEL )) || return 0
    set_make
    echo "Building kernel in $PWD..."
    case "$TARGET_ARCH" in
	i386 | i586 | i686 | athlon | x86_64)
	    $MAKE_J "$MAKE_CC" bzImage || fatal 1 "Error making bzImage."
	    ;;
    ia64 | ppc | ppc64)
	    $MAKE_J "$MAKE_CC" vmlinux || fatal 1 "Error making vmlinux."
	    ;;
	*)
	    $MAKE_J "$MAKE_CC" boot || fatal 1 "Error making boot."
	    ;;
    esac
    $MAKE_J "$MAKE_CC" modules || fatal 1 "Error building modules."

    popd >/dev/null
}

build_kernel_ib()
{
    (( $BUILD_KERNEL )) || return 0
    # build kernel-ib{,-devel}
    # some I/B drivers are architecture dependent and kernel-ib's configure
    # does not figure it out for us ~sigh~
    local configure_options=""
    case "$TARGET_ARCH" in
	x86_64 | ia64)
	    configure_options="--with-ipath_inf-mod"
	    ;;
	ppc64)
	    configure_options="--with-ipath_inf-mod --with-ehca-mod"
	    ;;
    esac
    local K_SRC="K_SRC"
    # ofed 1.3 had a bug in the rpm spec
    if [ "$OFED_VERSION" = "1.3" ]; then
        K_SRC="KSRC"
    fi
    $RPMBUILD --rebuild --define 'build_kernel_ib 1' --define 'build_kernel_ib_devel 1' \
	      --define "_topdir $(lbuild_topdir)" --target ${TARGET_ARCH} \
	      --define "KVERSION ${FULL_VERSION}" \
	      --define "$K_SRC ${PWD}/linux" \
	      --define "LIB_MOD_DIR /lib/modules/${FULL_VERSION}" \
	      --define "configure_options --without-quilt --with-core-mod --with-user_mad-mod --with-user_access-mod --with-addr_trans-mod --with-srp-target-mod --with-core-mod --with-mthca-mod --with-mlx4-mod --with-cxgb3-mod --with-nes-mod --with-ipoib-mod --with-sdp-mod --with-srp-mod --without-srp-target-mod --with-rds-mod --with-iser-mod --with-qlgc_vnic-mod --with-madeye-mod $configure_options" $(lbuild_topdir)/OFED/SRPMS/ofa_kernel-${OFED_VERSION}-ofed${OFED_VERSION}.src.rpm

    if [ ${PIPESTATUS[0]} != 0 ]; then
        fatal 1 "Error building kernel-ib"
    fi

    pushd "$TOPDIR" >/dev/null
    rm -rf kernel-ib-devel
    mkdir kernel-ib-devel
    cd kernel-ib-devel
    local rpm=$(ls $(lbuild_topdir)/RPMS/*/kernel-ib-devel-${OFED_VERSION}-${FULL_VERSION//-/_}.*.rpm)
    rpm2cpio -itv < $rpm | cpio -id
    CONFIGURE_FLAGS="--with-o2ib=$(pwd)/usr/src/ofa_kernel ${CONFIGURE_FLAGS}"
    popd >/dev/null
}


configure_lustre()
{
    return 0
    (( $BUILD_LUSTRE )) || return 0
    pushd "$TOPDIR" >/dev/null
    [ -f Makefile ] && make -s clean
    [ -f configure ] || sh ./autogen.sh
    ./configure --with-linux=$PWD/linux $CONFIGURE_FLAGS || \
	fatal 1 "Error configuring Lustre."
    popd >/dev/null
}

build_lustre()
{
    (( $BUILD_LUSTRE )) || return 0
    set_make
    pushd "$TOPDIR" >/dev/null
    sed \
	-e s^@VERSION@^${LUSTRE_VERSION}^g \
	-e s^@LINUXRELEASE@^${FULL_VERSION}^g \
	-e s^@RELEASE@^${FULL_VERSION//-/_}^g \
	-e s^@ac_configure_args@^"--with-linux=${PWD}/linux ${CONFIGURE_FLAGS}"^g \
	< lustre.spec.in \
	> lustre.spec
    $RPMBUILD --target ${TARGET_ARCH} -bb lustre.spec \
        --define "_tmppath $TMPDIR" \
	--define "_topdir $(lbuild_topdir)" || \
	fatal 1 "Error building Lustre rpms."
    # $MAKE_J "$MAKE_CC" || fatal 1 "Error building Lustre."
    popd >/dev/null
}

install_kernel()
{
    (( $INSTALL_KERNEL )) || return 0
    set_make
    pushd "$TOPDIR/linux" >/dev/null
    mkdir -p "$DESTDIR/boot"

    install -m 644 System.map "$DESTDIR/boot/System.map-${FULL_VERSION}"
    # install -m 644 module-info ...
    install -m 644 "$CONFIG_FILE" "$DESTDIR/boot/config-${FULL_VERSION}"

    mkdir -p "$DESTDIR/dev/shm"
    mkdir -p "$DESTDIR/lib/modules/${FULL_VERSION}"

    $MAKE "$MAKE_CC" INSTALL_MOD_PATH="$DESTDIR" KERNELRELEASE="$FULL_VERSION" \
	-s modules_install || \
	fatal 1 "Error installing modules."

    case "$TARGET_ARCH" in
	i386 | i586 | i686 | athlon)
	    cp arch/i386/boot/bzImage "$DESTDIR/boot/vmlinuz-${FULL_VERSION}"
	    cp vmlinux "$DESTDIR/lib/modules/${FULL_VERSION}/"
	    ln -sf "../lib/modules/${FULL_VERSION}/vmlinux" "$DESTDIR/boot/vmlinux-${FULL_VERSION}"
	    ;;
	x86_64)
	    cp arch/x86_64/boot/bzImage "$DESTDIR/boot/vmlinuz-${FULL_VERSION}"
	    cp vmlinux "$DESTDIR/lib/modules/${FULL_VERSION}/"
	    ln -sf "../lib/modules/${FULL_VERSION}/vmlinux" "$DESTDIR/boot/vmlinux-${FULL_VERSION}"
	    ;;
        ppc | ppc64)
	    cp vmlinux "$DESTDIR/boot/vmlinux-${FULL_VERSION}"
	    ln -sf "$DESTDIR/boot/vmlinux-${FULL_VERSION}" "../lib/modules/${FULL_VERSION}/vmlinux" 
	    ;;
	ia64)
	    gzip -cfv vmlinux > vmlinuz
	    mkdir -p "$DESTDIR/boot/efi/redhat"
	    install -m 755 vmlinux "$DESTDIR/lib/modules/${FULL_VERSION}/"
	    install -m 755 vmlinuz "$DESTDIR/boot/efi/redhat/vmlinuz-${FULL_VERSION}"
	    ln -sf "../../../lib/modules/${FULL_VERSION}/vmlinux" "$DESTDIR/boot/efi/redhat/vmlinux-${FULL_VERSION}"
	    ln -sf "efi/redhat/vmlinux-${FULL_VERSION}" "$DESTDIR/boot/vmlinux-${FULL_VERSION}"
	    ln -sf "efi/redhat/vmlinuz-${FULL_VERSION}" "$DESTDIR/boot/vmlinuz-${FULL_VERSION}"
	    ;;
	*)
	    cp vmlinuz "$DESTDIR/boot/vmlinuz-${FULL_VERSION}"
	    cp vmlinux "$DESTDIR/lib/modules/${FULL_VERSION}/vmlinux-${FULL_VERSION}"
	    ln -sf "../lib/modules/${FULL_VERSION}/vmlinux-${FULL_VERSION}" "$DESTDIR/boot/vmlinux-${FULL_VERSION}"

	    ;;
    esac
    if [ -e init/kerntypes.o ] ; then
	cp init/kerntypes.o "$DESTDIR/boot/Kerntypes-${FULL_VERSION}"
    fi

    popd >/dev/null
}

cleanup_libmodules()
{
    (( $INSTALL_LUSTRE )) || return 0

    KVERREL="${VERSION}${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}"
    i="$DESTDIR/lib/modules/${FULL_VERSION}"

    rm -f $i/build
    rm -f $i/source

    if (( $LINUX26 )) ; then
	ln -sf ../../../usr/src/linux-${KVERREL}-obj/${TARGET_ARCH}/${TARGET_CONFIG} $i/build
	ln -sf ../../../usr/src/linux-${KVERREL} $i/source
    else
	ln -sf ../../../usr/src/linux-${KVERREL} $i/build
    fi
}

install_lustre()
{
    (( $INSTALL_LUSTRE )) || return 0
    return 0
    set_make
    pushd "$TOPDIR" >/dev/null
    $MAKE "$MAKE_CC" -s install "DESTDIR=$DESTDIR" KERNELRELEASE="$FULL_VERSION" || fatal 1 "Error installing Lustre."
    popd >/dev/null
}

build_kms()
{
    (( $BUILD_KERNEL )) || return 0
    (( $SUSEBUILD )) || return 0
    set_make
    mkdir -p "${TOPDIR}/modules-${FULL_VERSION}"
    for dir in /usr/src/kernel-modules/* ; do
	# we are replacing lustre-lite, so don't include it
	if [ "${dir##*/}" != "lustre-lite" -a -e $dir/Makefile ]; then
	    build_dir="${TOPDIR}/modules-${FULL_VERSION}/${dir##*/}"
	    cp -a $dir $build_dir
	    # these modules are terrible, and don't all build
	    $MAKE_J "$MAKE_CC" -C $build_dir modules KERNEL_SOURCE="${TOPDIR}/linux"
	fi
    done
}

symver()
{
    local file=$1 name=${1%.ko}
    nm $file \
    | sed -ne 's,^0*\([0-9a-f]\{8\}\) A __crc_\(.*\),0x\1\t\2\t'"$name"',p'
}

install_kms()
{
    (( $INSTALL_KERNEL )) || return 0
    (( $LINUX26 )) || return 0
    set_make
    for build_dir in "${TOPDIR}/modules-${FULL_VERSION}/*" ; do
	[ -d $build_dir ] || continue
        # these modules are terrible, and don't all build
	$MAKE "$MAKE_CC" -C $build_dir KERNEL_SOURCE="${TOPDIR}/linux" INSTALL_MOD_PATH="$DESTDIR" 
    done
    local symvers_file="${DESTDIR}/boot/symvers-${VERSION}${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}-${TARGET_ARCH}"
    if [ -n "$TARGET_CONFIG" ]; then
	symvers_file="${symvers_file}${TARGET_DELIMITER}${TARGET_CONFIG}"
    fi
    symvers_file="$symvers_file.gz"
    (   symver vmlinux
	moddir="${DESTDIR}/lib/modules/${FULL_VERSION}"
	cd $moddir/kernel
	for module in $(find * -name '*.ko'); do
	    symver $module
	done
	cd $moddir
	for module in $(find * -path 'kernel/*' -prune -o \
			   -name '*.ko' -print); do
	    symver $module
	done
    ) | sort -u -k2 | gzip -c9 > $symvers_file
}

save_headers()
{
    (( $SAVE_HEADERS )) || return 0

    echo "Saving headers for ${TARGET_CONFIG:-up} ${TARGET_ARCH}..."
    pushd linux >/dev/null

    KVERREL="${VERSION}${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}"
    # deal with the kernel headers that are version specific
    
    saveddir="$RPM_BUILD_ROOT/usr/src/linux-${KVERREL}/savedheaders/${TARGET_ARCH}/${TARGET_CONFIG:-up}"
    mkdir -p "$saveddir"
    install -m 644 include/linux/autoconf.h "$saveddir/autoconf.h"
    install -m 644 include/linux/version.h  "$saveddir/version.h"
    mv include/linux/modules "$saveddir/"
    echo ${TARGET_ARCH} ${TARGET_CONFIG} ../../savedheaders/${TARGET_ARCH}/${TARGET_CONFIG:-up}/ \
	>>  "$RPM_BUILD_ROOT/usr/src/linux-${KVERREL}/savedheaders/list"
    popd >/dev/null
}

save_all_headers()
{
    (( $SAVE_HEADERS )) || return 0

    for arch in $BIGMEM_ARCHS ; do
	save_headers bigmem $arch
    done

    for arch in $BOOT_ARCHS ; do
	save_headers BOOT $arch
    done

    for arch in $JENSEN_ARCHS ; do
	save_headers jensen $arch
    done

    for arch in $SMP_ARCHS ; do
	save_headers smp $arch
    done

    for arch in $BIGSMP_ARCHS ; do
	save_headers bigsmp $arch
    done
    for arch in $PSERIES64_ARCHS ; do
	save_headers pseries64 $arch
    done
    for arch in $UP_ARCHS ; do
	save_headers up $arch
    done
}

longopts="build,build-lustre,build-kernel,depend-kernel,destdir:,extraversion:"
longopts="$longopts,help,install,install-lustre,install-kernel,kerneldir:"
longopts="$longopts,save-headers,target:,target-arch:,target-config:,unpack-kernel"

options=$(getopt -o hj: -l "$longopts" -- "$@")

eval set -- "$options"
    
while [ "$1" ] ; do
    case "$1" in
	'')
	    usage 1
	    ;;
	--build)
	    BUILD_LUSTRE=1
	    BUILD_KERNEL=1
	    DEPEND_KERNEL=1
	    UNPACK_KERNEL=1
	    shift
	    ;;
	--build-lustre)
	    BUILD_LUSTRE=1
	    shift
	    ;;
	--build-kernel)
	    BUILD_KERNEL=1
	    DEPEND_KERNEL=1
	    shift
	    ;;
	--depend-kernel)
	    DEPEND_KERNEL=1
	    shift
	    ;;
	--destdir)
	    DESTDIR=$2
	    shift 2
	    ;;
	--extraversion)
	    EXTRA_VERSION=$2
	    shift 2
	    ;;
	--help | -h)
	    usage 0
	    ;;
	--install)
	    INSTALL_LUSTRE=1
	    INSTALL_KERNEL=1
	    shift
	    ;;
	--install-lustre)
	    INSTALL_LUSTRE=1
	    shift
	    ;;
	--install-kernel)
	    INSTALL_KERNEL=1
	    shift
	    ;;
	-j)
	    JOBS=$2
	    shift 2
	    ;;
	--kerneldir)
	    KERNELDIR=$2
	    shift 2
	    ;;
	--save-headers)
	    SAVE_HEADERS=1
	    shift
	    ;;
	--target)
	    TARGET=$2
	    shift 2
	    ;;
	--target-arch)
	    TARGET_ARCH=$2
	    shift 2
	    ;;
	--target-config)
	    TARGET_CONFIG=$2
	    shift 2
	    ;;
	--unpack-kernel)
	    UNPACK_KERNEL=1
	    shift
	    ;;
	--)
	    shift
	    CONFIGURE_FLAGS=$@
	    break
	    ;; 
	*)
	    usage 1 "Unrecognized option: $1"
	    ;;
    esac
done

check_options
load_target
EXTRA_VERSION_DELIMITER=${EXTRA_VERSION_DELIMITER:-"-"}
FULL_VERSION="${VERSION}${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}"
if [ -n "$TARGET_CONFIG" ]; then
    FULL_VERSION="${FULL_VERSION}${TARGET_DELIMITER}${TARGET_CONFIG}"
fi
setup_ccache_distcc

extract_kernel
patch_kernel

depend_kernel
build_kernel

if [ -n "$OFED_VERSION" ]; then
    build_kernel_ib
fi

configure_lustre
build_lustre

build_kms

install_kernel
install_lustre

install_kms

cleanup_libmodules

save_headers

exit 0