#! /bin/bash
set -e

if ! [ -d kernel -a -d Documentation ]
then
    echo >&2 "Not in kernel top level directory. Exiting"
    exit 1
fi
TOPPATCHDIR=/usr/src/kernel-patches
ARCHITECTURE=`dpkg --print-installation-architecture`
DECOMPRESSOR="zcat -f"
PATCH_OPTIONS="--ignore-whitespace --silent"
# This is informational only, used by lskpatches
DHPKPATCHES_VERSION=0.99.36+nmu1

DEPENDS=("" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "")

KVERSIONS=(2.6.14 2.6.15 2.6.16 2.6.17 2.6.18 2.6.19 2.6.20 2.6.21 2.6.22 2.6.23 2.6.24 2.6.25 2.6.26 2.6.28 2.6.29 2.6.30 2.6.31 2.6.32 2.6.33 2.6.34 2.6.35 2.6.36 2.6.37 2.6.39 3.0.1 3.1.5 3.4.7 3.6.0 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.16.6 3.16.7 3.17.0 3.17.1 3.17.2 3.17.3 3.17.4)
PATCHFILES=("/usr/src/kernel-patches/diffs/ptmulti/patch-viewos-2.6.14.diff.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.15-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.16-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.17-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.18-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.19-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.20-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.21-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.22-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.23-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.24-ptmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.25.6-ptrace_multi.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.26-rc6-ptrace_multi.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.28.2-ptrace_multi.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.29-ptrace3_vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.30.5-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.31-rc8-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.32.2-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.33-rc2-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.34-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.35-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.36.2-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.37-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-2.6.39.1-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.0.1-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.1.5-ptrace3-vmmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.4.7-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.6-rc1-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz" "/usr/src/kernel-patches/diffs/ptmulti/patch-linux-3.17.4-ptrace3-vmulti.gz")
DEBPATCHFILES=("" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "")
STRIPLEVELS=(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)

[ -f debian/APPLIED_${ARCHITECTURE}_ptmulti -o \
  -f debian/APPLIED_all_ptmulti ] && exit 0
VERSION=$(grep ^VERSION Makefile 2>/dev/null | \
        sed -e 's/[^0-9]*\([0-9]*\)/\1/')
PATCHLEVEL=$( grep ^PATCHLEVEL Makefile 2>/dev/null | \
        sed -e 's/[^0-9]*\([0-9]*\)/\1/')
SUBLEVEL=$(grep ^SUBLEVEL Makefile 2>/dev/null | \
        sed -e 's/[^0-9]*\([0-9]*\)/\1/')
EXTRAVERSION=$(grep ^EXTRAVERSION Makefile | head -1 2>/dev/null | \
        sed -e 's/EXTRAVERSION =[       ]*\([^  ]*\)$/\1/')
KERNELBRANCHLET=${VERSION}.${PATCHLEVEL}.${SUBLEVEL}
KERNELRELEASE=${KERNELBRANCHLET}${EXTRAVERSION}
IDX=

declare -i i=${#PATCHFILES[*]}-1
while [ $i -ge 0 ]
do
    v=${KVERSIONS[$i]}
    if [ -n "$KPATCH_ptmulti" -a "$v" = "$KPATCH_ptmulti" \
         -o "$v" = "$KERNELRELEASE" \
         -o "$v" = "$KERNELBRANCHLET" \
         -o "$v" = all ]
    then
        IDX=$i
    fi
    i=i-1
done

if [ -n "$KPATCH_ptmulti" -a ${KVERSIONS[$IDX]} != "$KPATCH_ptmulti" ]
then
    echo >&2 "Requested kernel version \`$KPATCH_ptmulti' not found for patch ptmulti"
    exit 1
elif [ -z "$IDX" ]
then
    echo >&2 "No \"ptrace optimization for UMView et al. (PTRACE_MULTI)\" patch found for kernel version $KERNELRELEASE"
    exit 1
fi
KVERSION=${KVERSIONS[$IDX]}
STRIPLEVEL=${STRIPLEVELS[$IDX]}

if [ "${DEBPATCHFILES[$IDX]}" != '' -a \
    \( -r version.Debian -o -r README.Debian \) ]
then
    PATCHFILE=${DEBPATCHFILES[$IDX]}
else
    PATCHFILE=${PATCHFILES[$IDX]}
fi

echo >&2 "START applying ptmulti patch (ptrace optimization for UMView et al. (PTRACE_MULTI))"

NEEDED_DEPS=
for dep in ${DEPENDS[$IDX]}
do
    if [ -x ${TOPPATCHDIR}/${ARCHITECTURE}/${KERNELBRANCHLET}/apply/$dep ]
    then
        NEEDED_DEPS="${ARCHITECTURE}/${KERNELBRANCHLET}/apply/$dep $NEEDED_DEPS"
    elif [ -x ${TOPPATCHDIR}/all/${KERNELBRANCHLET}/apply/$dep ]
    then
        NEEDED_DEPS="all/${KERNELBRANCHLET}/apply/$dep $NEEDED_DEPS"
    elif [ -x ${TOPPATCHDIR}/${ARCHITECTURE}/apply/$dep ]
    then
        NEEDED_DEPS="${ARCHITECTURE}/apply/$dep $NEEDED_DEPS"
    elif [ -x ${TOPPATCHDIR}/all/apply/$dep ]
    then
        NEEDED_DEPS="all/apply/$dep $NEEDED_DEPS"
    else
        echo >&2 "ERROR: Patch dependency \`$dep' not found - aborting"
        echo >&2 "END applying ptmulti patch"
        exit 1
    fi
done
if [ "$NEEDED_DEPS" ]
then
    echo >&2 "Ensuring the following patches are applied first: $NEEDED_DEPS"
    for apply in ${NEEDED_DEPS}
    do
        dep=$(basename $apply)
        ${TOPPATCHDIR}/$apply

        # check something was applied
        if [ ! -f debian/APPLIED_${ARCHITECTURE}_$dep -a \
             ! -f debian/APPLIED_all_$dep ]
        then
            echo >&2 "ERROR: patch dependency did not left a patch stamp (version mismatch ?) - aborting"
            echo >&2 "END applying ptmulti patch"
            exit 1
        fi
    done
    UNPATCHDEPS=$(echo ${NEEDED_DEPS} | sed s,/apply/,/unpatch/,g)
fi

echo >&2 "Testing whether \"ptrace optimization for UMView et al. (PTRACE_MULTI)\" patch for $KVERSION applies (dry run):"
if ! [ -r $PATCHFILE ]
then
    echo >&2 "\"ptrace optimization for UMView et al. (PTRACE_MULTI)\" patch for $KVERSION not found"
    exit 1
elif ! $DECOMPRESSOR $PATCHFILE |
        patch --force --dry-run $PATCH_OPTIONS -p$STRIPLEVEL
then
    echo >&2 "\"ptrace optimization for UMView et al. (PTRACE_MULTI)\" patch for $KVERSION does not apply cleanly"
    exit 1
fi
if ! $DECOMPRESSOR $PATCHFILE |
        patch $PATCH_OPTIONS -p$STRIPLEVEL
then
    # This should never happen, thanks to the dry-run
    echo >&2 "ASSERTION FAILED - \"ptrace optimization for UMView et al. (PTRACE_MULTI)\" patch for $KVERSION failed"
    echo >&2 "END applying ptmulti patch"
    exit 1
fi
echo >&2 "\"ptrace optimization for UMView et al. (PTRACE_MULTI)\" patch for $KVERSION succeeded"

echo >&2 "Removing empty files:"
# make an exception for ./debian, or else the stamp files will go too.
find . -path ./debian -prune -o \
       -type f -size 0 ! -name 'APPLIED*' -exec rm {} \; -print
echo >&2 "Done."

mkdir -p debian
cat > 'debian/APPLIED_all_ptmulti' <<EOF
PATCHFILE='$PATCHFILE'
STRIPLEVEL='$STRIPLEVEL'
DEPENDS='$UNPATCHDEPS'
EOF
mkdir -p debian/image.d
PKGNAME=`dpkg -S $PATCHFILE | cut -d: -f1`
PKGVERS=`grep-dctrl -n -P $PKGNAME -s Version -X /var/lib/dpkg/status`
cat > 'debian/image.d/register-ptmulti' <<EOF
#!/bin/sh

# This scripts documents the "ptrace optimization for UMView et al. (PTRACE_MULTI)" kernel patch into the
# kernel-image package, as being applied to the kernel.

docdir=\${IMAGE_TOP}/usr/share/doc/kernel-image-\${version}

mkdir -p \${docdir}

(
    printf 'ptrace optimization for UMView et al. (PTRACE_MULTI) (ptmulti)${KPATCH_ptmulti:+ for kernel ${KPATCH_ptmulti}},'
    echo ' from package $PKGNAME, version $PKGVERS'
) >> \${docdir}/applied-patches
EOF
chmod +x 'debian/image.d/register-ptmulti'

echo >&2 "END applying ptmulti patch"
