#!/bin/bash
#
# Create a patch against a kernel tree which adds the DRBD sources.
#
# original script:
# Copyright (C) 2003 Kees Cook, OSDL
# kees@osdl.org, http://developer.osdl.org/kees/
#
# heavily modified:
# Copyright (C) 2003-2008 LINBIT Information Technologies GmbH, Lars Ellenberg
# lars@linbit.com, http://www.linbit.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
#

set -o errexit
fatal() { echo >&2 "$*" ; exit 1; }

KERNEL=$1
  DRBD=$2
    [[ $3 == full ]] && INCREMENT=false || INCREMENT=true

#
# naive sanity checks
#

test -n "$KERNEL" -a -n "$DRBD" ||
	fatal "Usage: kernel-patch KERNEL_SOURCE_DIR DRBD_PACKAGE_DIR"
test -d "$KERNEL/Documentation" ||
	fatal "Please specify the kernel tree to patch"
test -d "$DRBD/documentation"   ||
	fatal "Please specify the drbd tree to use"

# only allow 2.6
KDIR_PATCHLEVEL=$(grep "^PATCHLEVEL = " $KERNEL/Makefile | cut -d " " -f 3)
test "$KDIR_PATCHLEVEL" = 6 ||
	fatal "wrong kernel version patchlevel ($KDIR_PATCHLEVEL), expected 6."

test -e "$KERNEL/drivers/connector/connector.c" ||
	fatal "this won't work: your kernel lacks the connector :("
#
# convert to absolute pathnames
# maybe even do a "test -L $d && readlink $d" first?
# as a side effect this makes sure that KERNEL and DRBD are accessible
# directories, and do not contain whitespace or something...
#
KERNEL=$(cd $KERNEL && pwd)
KERNEL_BASE=$(basename $KERNEL)

DRBD=$(cd $DRBD && pwd)
DRBD_BASE=$KERNEL_BASE-drbd
DRBD_SUB=$DRBD_BASE/drivers/block/drbd

#
# Seems that there are mktemp proggies out there that do not understand
# the -d flag (reportedly Slackware 9.1); We do not need to waste
# entropy anyways.
#
mymktemp() { umask 077 && mkdir "$1" && cd "$1" && pwd; }
TEMPDIR=$(mymktemp /tmp/drbd-patch-$$) ||
	fatal "Could Could not make temp directory"
# cleanup on              0   1   2    3   13   15
trap 'rm -r "$TEMPDIR"' EXIT HUP INT QUIT PIPE TERM

#
# Set up our work area
#

cd $TEMPDIR

# Set up the diff directories
for d in include/linux drivers/block/drbd arch/um ; do
	mkdir -p $KERNEL_BASE/$d
	mkdir -p $DRBD_BASE/$d
done

#
# Pull in the base drbd source
#
include_linux="drbd.h drbd_limits.h drbd_nl.h drbd_tag_magic.h"
drbd_source="drbd_actlog.c drbd_bitmap.c drbd_buildtag.c
	drbd_compat_wrappers.h drbd_int.h drbd_main.c drbd_nl.c drbd_proc.c
	drbd_receiver.c drbd_req.c drbd_req.h drbd_strings.c drbd_worker.c
	lru_cache.c lru_cache.h"

# clean it first
make -s -C $DRBD/drbd clean

# FIXME drbd_config.h probably needs different treatment,
# these should become Kconfig options or go away!
cp -a $DRBD/drbd/linux/drbd_config.h	$DRBD_BASE/include/linux/
for f in $include_linux; do
	cp -a $DRBD/drbd/linux/$f	$DRBD_BASE/include/linux/
done

cp -a $DRBD/drbd/Kconfig		$DRBD_SUB
for f in $drbd_source; do
	cp -a $DRBD/drbd/$f		$DRBD_SUB
done
# we also need the in-kernel-tree Makefile
# remove the trace of the connector backport
sed -e '/^ifndef CONFIG_CONNECTOR/,/^$/d' \
	< $DRBD/drbd/Makefile-2.6 > $DRBD_SUB/Makefile

# disable __arch_um__ to_virt() hack
sed -e 's/^#if defined(__arch_um__).*/#if 0/' \
	< $DRBD/drbd/drbd_receiver.c > $DRBD_SUB/drbd_receiver.c

# and, in case this kernel was already patched:
if test -e $KERNEL/include/linux/drbd.h ; then
	$INCREMENT || fatal "drbd already in $KERNEL"
	cp -a $KERNEL/include/linux/drbd*.h \
	 $KERNEL_BASE/include/linux/
	cp -a $KERNEL/drivers/block/drbd/{*.[ch],Makefile,Kconfig} \
	 $KERNEL_BASE/drivers/block/drbd/
	# remove dangling drbd.mod.c, if it hangs around
	rm -f $KERNEL_BASE/drivers/block/drbd/drbd.mod.c
fi

# Bring over the current kernel Kconfig and Makefile
for f in drivers/block/{Kconfig,Makefile} arch/um/Kconfig_block ; do
	test -e $KERNEL/$f || continue
	cp -a $KERNEL/$f $KERNEL_BASE/$f
	cp -a $KERNEL/$f $DRBD_BASE/$f
done

# Add drbd to the block drivers Makefile and Kconfig if we need to
grep drbd/ $DRBD_BASE/drivers/block/Makefile >/dev/null || \
	echo 'obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/' >> \
		$DRBD_BASE/drivers/block/Makefile \
	|| exit 1

patch_Kconfig() { sed -e '
/^config BLK_DEV_NBD/,/^config /{
	/^config BLK_DEV_NBD/i\
source "drivers/block/drbd/Kconfig"\

}'
}
for f in drivers/block/Kconfig arch/um/Kconfig_block ; do
	test -e $KERNEL_BASE/$f || continue
	grep drbd/ $DRBD_BASE/$f >/dev/null && continue
	patch_Kconfig < $KERNEL_BASE/$f > $DRBD_BASE/$f
done

#
# finally: Create diff!
#
if diff -uNrp $KERNEL_BASE $DRBD_BASE ; then
	echo "$KERNEL already completely patched."
	test /proc/$$/fd/1 -ef /proc/$$/fd/2 ||
		echo >&2 "$KERNEL already completely patched."
fi

cd -
## clean up done by trap on EXIT
