#!/bin/sh
# $Id: update-kernel,v 1.14 2006/08/20 19:34:51 mikpe Exp $
# usage:
#	cd ${kernelsrcdir}
#	${perfctrsrcdir}/update-kernel

perfctr=
patch=
patchtype=
nopatch=
dryrun=
sym=
backup=
maybe_redhat=
VERSION=
PATCHLEVEL=
SUBLEVEL=
EXTRAVERSION=
kernel=

usage() {
    echo 'Usage: cd ${kernelsrcdir}; ${perfctrsrcdir}/update-kernel [options]'
    echo 'Available options:'
    echo '--patch=version force use of patch for particular kernel version'
    echo '-p version      ditto'
    echo '--nopatch       do not apply patch, only install new files'
    echo '-n              ditto'
    echo '--test          apply the patch but do not change any files'
    echo '-t              ditto'
    exit 1
}

get_perfctr_srcdir() {
    # XXX: use dirname instead?
    perfctr=`echo $0 | sed 's+/update-kernel$++'`
}

get_arch() {
    if [ -z "$ARCH" ]; then
	ARCH=`uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/ppc.*/powerpc/`
    fi
}

get_options() {
    while [ $# -gt 0 ]; do
	case "$1" in
	  --patch=*)
	    patch=`echo "$1" | sed s/--patch=//`
	    ;;
	  -p)
	    shift
	    if [ $# -eq 0 ]; then
		echo Error: option "'-p'" requires an argument
		usage
	    fi
	    patch="$1"
	    ;;
	  --nopatch|-n)
	    nopatch=1
	    ;;
	  --test|-t)
	    dryrun="--dry-run"
	    ;;
	  --sym)
	    # not for general use
	    sym=1
	    ;;
	  --backup)
	    # not for general use
	    backup=1
	    ;;
	  *)
	    echo Error: unknown option "$1"
	    usage
	    ;;
	esac
	shift
    done
}

check_pwd_is_kernel_srcdir() {
    if [ ! -f drivers/Makefile -o ! -f "arch/$ARCH/kernel/Makefile" ]; then
	echo "Error: `pwd` does not appear to be the top-level kernel source directory"
	usage
    fi
}

check_kernel_srcdir_is_clean() {
    if [ -f System.map -o -f .version ]; then
	echo 'Error: kernel source is not clean; please do a "make mrproper"'
	exit 1
    fi
}

get_makefile_variable() {
    eval `grep "^$1 *=" Makefile | head -n 1 | sed 's/ *= */=/'`
}

get_kernel_version() {
    get_makefile_variable VERSION
    get_makefile_variable PATCHLEVEL
    get_makefile_variable SUBLEVEL
    get_makefile_variable EXTRAVERSION
    case "$EXTRAVERSION" in
    *custom)
	maybe_redhat=1
	EXTRAVERSION=`echo $EXTRAVERSION | sed 's/\(.*\)custom/\1/'`
	;;
    esac
    kernel="$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
}

check_given_patch() {
    if [ ! -f "$perfctr/patches/patch-kernel-$patch" ]; then
	alias=`grep ^$patch/ $perfctr/patches/aliases | awk -F/ '{ print $2 }'`
	if [ -n "$alias" -a -f "$perfctr/patches/patch-kernel-$alias" ]; then
	    patch="$alias"
	    echo Using patch "$alias" for kernel "$kernel"
	else
	    echo Error: no patch for user-specified version "$patch" found
	    echo See "$perfctr/patches/" for supported kernel versions
	    exit 1
	fi
    fi
    patchtype="(forced, kernel is $kernel)"
}

try_standard() {
    if [ -f "$perfctr/patches/patch-kernel-$kernel" ]; then
	patch="$kernel"
	echo Found patch for kernel "$kernel"
    else
	alias=`grep ^$kernel/ $perfctr/patches/aliases | awk -F/ '{ print $2 }'`
	if [ -n "$alias" -a -f "$perfctr/patches/patch-kernel-$alias" ]; then
	    patch="$alias"
	    echo Using patch "$alias" for kernel "$kernel"
	fi
    fi
}

try_redhat() {
    if [ -f /etc/redhat-release ]; then
	maybe_redhat=1
    fi
    if [ -n "$EXTRAVERSION" -a -n "$maybe_redhat" ]; then
	if [ -f "$perfctr/patches/patch-kernel-$kernel-redhat" ]; then
	    patch="$kernel-redhat"
	    echo Found patch for RedHat kernel "$kernel"
	else
	    alias=`grep ^$kernel-redhat $perfctr/patches/aliases | awk -F/ '{ print $2 }'`
	    if [ -n "$alias" -a -f "$perfctr/patches/patch-kernel-$alias" ]; then
		patch="$alias"
		echo Using patch "$alias" for RedHat kernel "$kernel"
	    fi
	fi
    fi
}

deduce_patch() {
    try_standard
    if [ -z "$patch" ]; then
	try_redhat
    fi
    if [ -z "$patch" ]; then
	echo Error: no suitable patch found for kernel "$kernel"
	echo See "$perfctr/patches/" for supported kernel versions
	exit 1
    fi
    patchtype="(auto-detected)"
}

identify_patch() {
    if [ -n "$patch" ]; then
	check_given_patch
    else
	deduce_patch
    fi
}

apply_patch() {
    echo
    echo Applying kernel source patch for "$patch" "$patchtype"
    echo
    bVt=
    if [ "$backup" ]; then
	bVt="-bVt"
    fi
    patch $dryrun $bVt -p1 < "$perfctr/patches/patch-kernel-$patch"
}

install_files_by_symlinks() {
    echo ln -sf ${perfctr}/linux/include/asm-i386/perfctr.h include/asm-i386/
    ln -sf ${perfctr}/linux/include/asm-i386/perfctr.h include/asm-i386/
    echo ln -sf ${perfctr}/linux/include/asm-x86_64/perfctr.h include/asm-x86_64/
    ln -sf ${perfctr}/linux/include/asm-x86_64/perfctr.h include/asm-x86_64/
    echo ln -sf ${perfctr}/linux/include/asm-powerpc/perfctr.h include/asm-powerpc/
    ln -sf ${perfctr}/linux/include/asm-powerpc/perfctr.h include/asm-powerpc/
    echo ln -sf ${perfctr}/linux/include/linux/perfctr.h include/linux/
    ln -sf ${perfctr}/linux/include/linux/perfctr.h include/linux/
    echo ln -sf ${perfctr}/linux/drivers/perfctr drivers/
    ln -sf ${perfctr}/linux/drivers/perfctr drivers/
}

install_files_by_tar() {
    tar -C "$perfctr/linux" --exclude CVS -cf - . | tar -xf -
    rm -f include/asm
}

install_files() {
    echo
    echo Installing new kernel source files
    echo
    if [ -n "$sym" ]; then
	install_files_by_symlinks
    else
	install_files_by_tar
    fi
}

get_perfctr_srcdir
get_arch
get_options "$@"
check_pwd_is_kernel_srcdir
check_kernel_srcdir_is_clean
get_kernel_version
if [ -z "$nopatch" ]; then
    identify_patch
    apply_patch
fi
if [ -z "$dryrun" ]; then
    install_files
fi
