189 lines
4.1 KiB
Bash
Executable File
189 lines
4.1 KiB
Bash
Executable File
#! /bin/sh
|
|
# smart patch applier
|
|
# Copyright (C) 1999, 2001 Henry Spencer.
|
|
#
|
|
# 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
#
|
|
# 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.
|
|
#
|
|
# patcher [-v] [-c] targetdir target [ key patchfile ] ...
|
|
# In targetdir, patch target from patchfile unless it already contains
|
|
# key and it appears to have been patched with the same patch. (If the
|
|
# patch has changed, undo the old one and then put the new one in.) Save
|
|
# original as target.preipsec, and patched copy as target.wipsec, with
|
|
# patch md5sum stored as target.ipsecmd5. If the patch doesn't work,
|
|
# put the original back and save the patch attempt as target.mangled.
|
|
# If there are no key+patchfile pairs, undo any old patch and leave it
|
|
# at that.
|
|
# -v means verbose
|
|
# -c means do "patching" by appending rather than by using patch(1)
|
|
#
|
|
# RCSID $Id: patcher,v 1.1 2004/03/15 20:35:27 as Exp $
|
|
|
|
PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
|
|
export PATH
|
|
umask 022
|
|
|
|
verbose=
|
|
modifier=patch
|
|
for dummy
|
|
do
|
|
case "$1" in
|
|
-v) verbose=yes ;;
|
|
-c) modifier=cat ;;
|
|
--) shift ; break ;;
|
|
-*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
|
|
*) break ;;
|
|
esac
|
|
shift
|
|
done
|
|
if test $# -lt 2
|
|
then
|
|
echo "Usage: $0 [-v] [-c] targetdir target [ key patchfile ] ..." >&2
|
|
exit 2
|
|
fi
|
|
|
|
need() {
|
|
if test ! -f $1
|
|
then
|
|
echo "$0: cannot find file \`$1'" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
note() {
|
|
if test "$verbose"
|
|
then
|
|
echo "* $1"
|
|
fi
|
|
}
|
|
|
|
dir="$1"
|
|
target="$2"
|
|
shift ; shift
|
|
it=$dir/$target
|
|
need $it
|
|
|
|
|
|
|
|
patches=
|
|
if test ! -s $it.ipsecmd5
|
|
then
|
|
# no records of patching...
|
|
while test $# -ge 2
|
|
do
|
|
key="$1"
|
|
patchfile="$2"
|
|
shift ; shift
|
|
need $patchfile
|
|
|
|
if egrep -q "$key" $it
|
|
then
|
|
# patched but no record of how
|
|
note "$it no longer needs patch $patchfile"
|
|
else
|
|
patches="$patches $patchfile"
|
|
fi
|
|
done
|
|
elif test ! -f $it.preipsec -o ! -f $it.wipsec
|
|
then
|
|
echo "$0: $it.preipsec or .wipsec is missing!" >&2
|
|
exit 1
|
|
else
|
|
# determine whether patches have changed
|
|
tmp=/tmp/patcher.$$
|
|
>$tmp
|
|
while test $# -ge 2
|
|
do
|
|
key="$1"
|
|
patchfile="$2"
|
|
shift ; shift
|
|
need $patchfile
|
|
md5sum $patchfile | awk '{print $1}' >>$tmp
|
|
|
|
if egrep -q "$key" $it.preipsec
|
|
then
|
|
note "$it no longer needs patch $patchfile"
|
|
else
|
|
patches="$patches $patchfile"
|
|
fi
|
|
done
|
|
if cmp -s $tmp $it.ipsecmd5
|
|
then
|
|
note "$it already fully patched"
|
|
rm -f $tmp
|
|
exit 0
|
|
fi
|
|
rm -f $tmp
|
|
|
|
# must undo old patch(es)
|
|
note "$it old patches must be undone, undoing them..."
|
|
if ! cmp -s $it $it.wipsec
|
|
then
|
|
note "$it has changed, cannot undo old patches!"
|
|
echo "$0: cannot unpatch $it, it has changed since patching" >&2
|
|
exit 1
|
|
fi
|
|
rm $it
|
|
mv $it.preipsec $it
|
|
rm $it.wipsec $it.ipsecmd5
|
|
fi
|
|
|
|
# if no necessary patches, we're done
|
|
if test " $patches" = " "
|
|
then
|
|
note "$it no longer needs patching"
|
|
exit 0
|
|
fi
|
|
|
|
# try to figure out patch options
|
|
if test " $modifier" = " patch"
|
|
then
|
|
if patch --help >/dev/null 2>/dev/null
|
|
then
|
|
# looks like a modern version
|
|
popts='-p1 -b'
|
|
else
|
|
# looks like an old one
|
|
popts='-p1'
|
|
fi
|
|
fi
|
|
|
|
# do it
|
|
>$it.ipsecmd5
|
|
for patchfile in $patches
|
|
do
|
|
note "applying $patchfile to $it..."
|
|
|
|
# make local copy - this defeats hard and soft links
|
|
mv $it $it.preipsec || exit 0
|
|
rm -f $it
|
|
cp -p $it.preipsec $it
|
|
|
|
case "$modifier" in
|
|
patch) ( cd $dir ; patch $popts ) <$patchfile ;;
|
|
cat) cat $patchfile >>$it ;;
|
|
esac
|
|
status=$?
|
|
if test $status -ne 0
|
|
then
|
|
note "$it patch failed, restoring original"
|
|
echo "$0: patch on $it failed!" >&2
|
|
echo "$0: restoring original $it," >&2
|
|
echo "$0: leaving patch attempt in $it.mangled" >&2
|
|
mv $it $it.mangled
|
|
mv $it.preipsec $it
|
|
rm -f $it.ipsecmd5
|
|
exit 1
|
|
fi
|
|
rm -f $it.orig # some patch versions leave debris
|
|
md5sum $patchfile | awk '{print $1}' >>$it.ipsecmd5
|
|
done
|
|
cp -p $it $it.wipsec
|