#! /bin/bash
#############################################################################
# Copyright (c) 2003-2005,2007-2009 Novell, Inc.
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# 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, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com
#############################################################################
source $(dirname $0)/config.sh
source $(dirname $0)/wd-functions.sh
have_arch_patches=false
have_defconfig_files=false
fuzz="-F0"
case "$DIST_SET" in
sles9 | sles10)
fuzz=
esac
case "$DIST_SET" in
sles9* | sles10* | sle10* | 9.* | 10.* | 11.0)
have_arch_patches=true
have_defconfig_files=true
esac
usage() {
cat <<END
SYNOPSIS: $0 [-qv] [--symbol=...] [--dir=...]
[--combine] [--fast] [last-patch-name] [--vanilla] [--fuzz=NUM]
[--patch-dir=PATH] [--build-dir=PATH] [--config=ARCH-FLAVOR [--kabi]]
[--ctags] [--cscope]
The --build-dir option supports internal shell aliases, like ~, and variable
expansion when the variables are properly escaped. Environment variables
and the following list of internal variables are permitted:
\$PATCH_DIR: The expanded source tree
\$SRCVERSION: The current linux source tarball version
\$TAG: The current tag or branch of this repo
\$EXT: A string expanded from current \$EXTRA_SYMBOLS
With --config=ARCH-FLAVOR, these have values. Otherwise they are empty.
\$CONFIG: The current ARCH-FLAVOR.
\$CONFIG_ARCH: The current ARCH.
\$CONFIG_FLAVOR: The current FLAVOR.
END
exit 1
}
# Allow to pass in default arguments via SEQUENCE_PATCH_ARGS.
set -- $SEQUENCE_PATCH_ARGS "$@"
if $have_arch_patches; then
arch_opt="arch:"
else
arch_opt=""
fi
options=`getopt -o qvd:F: --long quilt,no-quilt,$arch_opt,symbol:,dir:,combine,fast,vanilla,fuzz,patch-dir:,build-dir:,config:,kabi,ctags,cscope -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
QUIET=1
EXTRA_SYMBOLS=
QUILT=true
COMBINE=
FAST=
VANILLA=false
SP_BUILD_DIR=
CONFIG=
CONFIG_ARCH=
CONFIG_FLAVOR=
KABI=false
CTAGS=false
CSCOPE=false
while true; do
case "$1" in
-q)
QUIET=1
;;
-v)
QUIET=
;;
--quilt)
QUILT=true
;;
--no-quilt)
QUILT=false
;;
--combine)
COMBINE=1
FAST=1
;;
--fast)
FAST=1
;;
--arch)
export PATCH_ARCH=$2
shift
;;
--symbol)
EXTRA_SYMBOLS="$EXTRA_SYMBOLS $2"
shift
;;
-d|--dir)
SCRATCH_AREA=$2
shift
;;
--vanilla)
VANILLA=true
;;
-F|--fuzz)
fuzz="-F$2"
shift
;;
--patch-dir)
PATCH_DIR=$2
shift
;;
--build-dir)
SP_BUILD_DIR="$2"
shift
;;
--config)
CONFIG="$2"
shift
;;
--kabi)
KABI=true
;;
--ctags)
CTAGS=true
;;
--cscope)
CSCOPE=true
;;
--)
shift
break ;;
*)
usage ;;
esac
shift
done
unset LIMIT
if [ $# -ge 1 ]; then
LIMIT=$1
shift
fi
if test -n "$CONFIG"; then
CONFIG_ARCH=${CONFIG%%-*}
CONFIG_FLAVOR=${CONFIG##*-}
if [ "$CONFIG" = "$CONFIG_ARCH" -o "$CONFIG" = "$CONFIG_FLAVOR" -o \
-z "$CONFIG_ARCH" -o -z "$CONFIG_FLAVOR" ]; then
echo "Invalid config spec: --config=ARCH-FLAVOR is expected."
usage
fi
fi
if [ $# -ne 0 ]; then
usage
fi
# Some patches require patch 2.5.4. Abort with older versions.
PATCH_VERSION=$(patch -v | sed -e '/^patch/!d' -e 's/patch //')
case $PATCH_VERSION in
([01].*|2.[1-4].*|2.5.[1-3]) # (check if < 2.5.4)
echo "patch version $PATCH_VERSION found; " \
"a version >= 2.5.4 required." >&2
exit 1
;;
esac
# Check SCRATCH_AREA.
if [ -z "$SCRATCH_AREA" ]; then
echo "SCRATCH_AREA not defined (defaulting to \"tmp\")"
SCRATCH_AREA=tmp
fi
if [ ! -d "$SCRATCH_AREA" ]; then
if ! mkdir -p $SCRATCH_AREA; then
echo "creating scratch dir $SCRATCH_AREA failed"
exit 1
fi
fi
[ "${SCRATCH_AREA:0:1}" != "/" ] \
&& SCRATCH_AREA="$PWD/$SCRATCH_AREA"
TMPDIR=$SCRATCH_AREA
export TMPDIR
ORIG_DIR=$SCRATCH_AREA/linux-$SRCVERSION.orig
TAG=$(get_branch_name)
TAG=${TAG//\//_}
if [ "$VANILLA" = "true" ]; then
TAG=${TAG}-vanilla
fi
PATCH_LOG=$SCRATCH_AREA/patch-$SRCVERSION${TAG:+-$TAG}.log
LAST_LOG=$SCRATCH_AREA/last-$SRCVERSION${TAG:+-$TAG}.log
# Check series.conf.
if [ ! -r series.conf ]; then
echo "Configuration file \`series.conf' not found"
exit 1
fi
if [ -e scripts/check-patches ]; then
scripts/check-patches || {
echo "Inconsistencies found."
echo "Please clean up series.conf and/or the patches directories!"
read
}
fi
if $have_arch_patches; then
if [ -z "$ARCH_SYMBOLS" ]; then
if [ -x ./arch-symbols ]; then
ARCH_SYMBOLS=./arch-symbols
elif [ -x scripts/arch-symbols ]; then
ARCH_SYMBOLS=scripts/arch-symbols
else
echo "Cannot locate \`arch-symbols' script (export ARCH_SYMBOLS)"
exit 1
fi
else
if [ ! -x "$ARCH_SYMBOLS" ]; then
echo "Cannot execute \`arch-symbols' script"
exit 1
fi
fi
SYMBOLS=$($ARCH_SYMBOLS)
if [ -z "$SYMBOLS" ]; then
echo "Unsupported architecture \`$ARCH'" >&2
exit 1
fi
echo "Architecture symbol(s): $SYMBOLS"
fi
if [ -s extra-symbols ]; then
EXTRA_SYMBOLS="$EXTRA_SYMBOLS $(cat extra-symbols)"
fi
if [ -n "$EXTRA_SYMBOLS" ]; then
EXTRA_SYMBOLS=${EXTRA_SYMBOLS# }
echo "Extra symbols: $EXTRA_SYMBOLS"
SYMBOLS="$SYMBOLS $EXTRA_SYMBOLS"
fi
EXT=${EXTRA_SYMBOLS// /-}
EXT=${EXT//\//}
if test -z "$PATCH_DIR"; then
PATCH_DIR=$SCRATCH_AREA/linux-$SRCVERSION${TAG:+-$TAG}${EXT:+-}$EXT
fi
if [ -n "$SP_BUILD_DIR" ]; then
# This allows alias (~) and variable expansion
SP_BUILD_DIR=$(eval echo "$SP_BUILD_DIR")
else
SP_BUILD_DIR="$PATCH_DIR"
fi
echo "Creating tree in $PATCH_DIR"
# Clean up from previous run
rm -f "$PATCH_LOG" "$LAST_LOG"
if [ -e $PATCH_DIR ]; then
tmpdir=$(mktemp -d ${PATCH_DIR%/*}/${0##*/}.XXXXXX)
if [ -n "$tmpdir" ]; then
echo "Cleaning up from previous run (background)"
mv $PATCH_DIR $tmpdir
rm -rf $tmpdir &
else
echo "Cleaning up from previous run"
rm -rf $PATCH_DIR
fi
fi
# Create fresh $SCRATCH_AREA/linux-$SRCVERSION.
if ! [ -d $ORIG_DIR ]; then
unpack_tarball "$SRCVERSION" "$ORIG_DIR"
find $ORIG_DIR -type f | xargs chmod a-w,a+r
fi
if $VANILLA; then
PATCHES=( $(scripts/guards $SYMBOLS < series.conf | egrep '^patches\.(kernel\.org|rpmify)/') )
else
PATCHES=( $(scripts/guards $SYMBOLS < series.conf) )
fi
# Check if patch $LIMIT exists
if [ -n "$LIMIT" ]; then
for ((n=0; n<${#PATCHES[@]}; n++)); do
if [ "$LIMIT" = - ]; then
LIMIT=${PATCHES[n]}
break
fi
case "${PATCHES[n]}" in
$LIMIT|*/$LIMIT)
LIMIT=${PATCHES[n]}
break
;;
esac
done
if ((n == ${#PATCHES[@]})); then
echo "No patch \`$LIMIT' found."
exit 1
fi
PATCHES_BEFORE=()
for ((m=0; m<n; m++)); do
PATCHES_BEFORE[m]=${PATCHES[m]}
done
PATCHES_AFTER=()
for ((m=n; m<${#PATCHES[@]}; m++)); do
PATCHES_AFTER[m-n]=${PATCHES[m]}
done
else
PATCHES_BEFORE=( "${PATCHES[@]}" )
PATCHES_AFTER=()
fi
if [ -n "$COMBINE" ]; then
echo "Precomputing combined patches"
(IFS=$'\n'; echo "${PATCHES[*]}") \
| $(dirname $0)/md5fast --source-tree "$ORIG_DIR" \
--temp "$SCRATCH_AREA" \
--cache combined --generate
echo $SRCVERSION > combined/srcversion
fi
if [ -n "$FAST" -a ${#PATCHES_BEFORE[@]} -gt 0 -a \
$SRCVERSION = "$(cat combined/srcversion 2> /dev/null)" ]; then
echo "Checking for precomputed combined patches"
PATCHES=( $(IFS=$'\n'; echo "${PATCHES_BEFORE[*]}" \
| $(dirname $0)/md5fast --cache combined)
"${PATCHES_AFTER[@]}" )
fi
# Helper function to restore files backed up by patch. This is
# faster than doing a --dry-run first.
restore_files() {
local backup_dir=$1 patch_dir=$2 file wd=$PWD
local -a remove restore
if [ -d $backup_dir ]; then
pushd $backup_dir > /dev/null
for file in $(find . -type f) ; do
if [ -s "$file" ]; then
restore[${#restore[@]}]="$file"
else
remove[${#remove[@]}]="$file"
fi
done
#echo "Restore: ${restore[@]}"
[ ${#restore[@]} -ne 0 ] \
&& printf "%s\n" "${restore[@]}" \
| xargs cp -f --parents --target $patch_dir
cd $patch_dir
#echo "Remove: ${remove[@]}"
[ ${#remove[@]} -ne 0 ] \
&& printf "%s\n" "${remove[@]}" | xargs rm -f
popd > /dev/null
fi
}
# Create hardlinked source tree
echo "Linking from $ORIG_DIR"
cp -rld $ORIG_DIR $PATCH_DIR
echo -e "# Symbols: $SYMBOLS\n#" > $PATCH_DIR/series
SERIES_PFX=
if ! $QUILT; then
SERIES_PFX="# "
fi
mkdir $PATCH_DIR/.pc
echo 2 > $PATCH_DIR/.pc/.version
# Patch kernel
set -- "${PATCHES[@]}"
while [ $# -gt 0 ]; do
PATCH="$1"
if ! $QUILT && test "$PATCH" = "$LIMIT"; then
STEP_BY_STEP=1
echo "Stopping before $PATCH"
fi
if [ -n "$STEP_BY_STEP" ]; then
while true; do
echo -n "Continue ([y]es/[n]o/yes to [a]ll)?"
read YESNO
case $YESNO in
([yYjJsS])
break
;;
([nN])
break 2 # break out of outer loop
;;
([aA])
unset STEP_BY_STEP
break
;;
esac
done
fi
if [ ! -r "$PATCH" ]; then
echo "Patch $PATCH not found."
status=1
break
fi
echo "[ $PATCH ]"
echo "[ $PATCH ]" >> $PATCH_LOG
backup_dir=$PATCH_DIR/.pc/$PATCH
exec 5<&1 # duplicate stdin
case $PATCH in
*.gz) exec < <(gzip -cd $PATCH) ;;
*.bz2) exec < <(bzip2 -cd $PATCH) ;;
*) exec < $PATCH ;;
esac
patch -d $PATCH_DIR --backup --prefix=$backup_dir/ -p1 -E $fuzz \
--no-backup-if-mismatch --force > $LAST_LOG 2>&1
STATUS=$?
exec 0<&5 # restore stdin
if [ $STATUS -ne 0 ]; then
restore_files $backup_dir $PATCH_DIR
fi
if ! $QUILT; then
rm -rf $PATCH_DIR/.pc/
fi
cat $LAST_LOG >> $PATCH_LOG
[ -z "$QUIET" ] && cat $LAST_LOG
if [ $STATUS -ne 0 ]; then
[ -n "$QUIET" ] && cat $LAST_LOG
echo "Patch $PATCH failed (rolled back)."
echo "Logfile: $PATCH_LOG"
status=1
break
else
echo "$SERIES_PFX$PATCH" >> $PATCH_DIR/series
if $QUILT; then
echo "$PATCH" >> $PATCH_DIR/.pc/applied-patches
fi
rm -f $LAST_LOG
fi
shift
if $QUILT && test "$PATCH" = "$LIMIT"; then
break
fi
done
if [ -n "$EXTRA_SYMBOLS" ]; then
echo "$EXTRA_SYMBOLS" > $PATCH_DIR/extra-symbols
fi
if ! $QUILT; then
rm $PATCH_DIR/series
fi
ln -s $PWD $PATCH_DIR/patches
ln -s patches/scripts/{refresh_patch,run_oldconfig}.sh $PATCH_DIR/
if $QUILT; then
[ -r $HOME/.quiltrc ] && . $HOME/.quiltrc
[ ${QUILT_PATCHES-patches} != patches ] \
&& ln -s $PWD $PATCH_DIR/${QUILT_PATCHES-patches}
fi
# If there are any remaining patches, add them to the series so
# they can be fixed up with quilt (or similar).
if [ -n "$*" ]; then
( IFS=$'\n' ; echo "$*" ) >> $PATCH_DIR/series
fi
echo "[ Tree: $PATCH_DIR ]"
append=
if test "$SP_BUILD_DIR" != "$PATCH_DIR"; then
mkdir -p "$SP_BUILD_DIR"
echo "[ Build Dir: $SP_BUILD_DIR ]"
rm -f "$SP_BUILD_DIR/source"
rm -f "$SP_BUILD_DIR/patches"
ln -sf "$PATCH_DIR" "$SP_BUILD_DIR/source"
ln -sf "source/patches" "$SP_BUILD_DIR/patches"
fi
if test -e supported.conf; then
echo "[ Generating Module.supported ]"
scripts/guards base external < supported.conf > "$SP_BUILD_DIR/Module.supported"
fi
if test -n "$CONFIG"; then
if test -e "config/$CONFIG_ARCH/$CONFIG_FLAVOR"; then
echo "[ Copying config/$CONFIG_ARCH/$CONFIG ]"
cp -a "config/$CONFIG_ARCH/$CONFIG_FLAVOR" "$SP_BUILD_DIR/.config"
else
echo "[ Config $CONFIG does not exist. ]"
fi
if $KABI; then
if [ ! -x rpm/modversions ]; then
echo "[ This branch does not support the modversions kABI mechanism. Skipping. ]"
elif [ -e "kabi/$CONFIG_ARCH/symtypes-$CONFIG_FLAVOR" ]; then
echo "[ Expanding kABI references for $CONFIG ]"
rpm/modversions --unpack "$SP_BUILD_DIR" < \
"kabi/$CONFIG_ARCH/symtypes-$CONFIG_FLAVOR"
else
echo "[ No kABI references for $CONFIG ]"
fi
fi
fi
if $CTAGS; then
if ctags --version > /dev/null; then
echo "[ Generating ctags (this may take a while)]"
make -s --no-print-directory -C "$PATCH_DIR" O="$SP_BUILD_DIR" tags
else
echo "[ Could not generate ctags: ctags not found ]"
fi
fi
if $CSCOPE; then
if cscope -V 2> /dev/null; then
echo "[ Generating cscope db (this may take a while)]"
make -s --no-print-directory -C "$PATCH_DIR" O="$SP_BUILD_DIR" cscope
else
echo "[ Could not generate cscope db: cscope not found ]"
fi
fi
[ $# -gt 0 ] && exit $status
if ! $have_defconfig_files || test ! -e config.conf; then
exit 0
fi
# Copy the config files that apply for this kernel.
echo "[ Copying config files ]" >> $PATCH_LOG
echo "[ Copying config files ]"
TMPFILE=$(mktemp /tmp/$(basename $0).XXXXXX)
chmod a+r $TMPFILE
CONFIGS=$(scripts/guards --list < config.conf)
for config in $CONFIGS; do
if ! [ -e config/$config ]; then
echo "Configuration file config/$config not found"
fi
name=$(basename $config)
path=arch/$(dirname $config)/defconfig.$name
mkdir -p $(dirname $PATCH_DIR/$path)
chmod +x rpm/config-subst
cat config/$config \
| rpm/config-subst CONFIG_CFGNAME \"$name\" \
| rpm/config-subst CONFIG_RELEASE \"0\" \
| rpm/config-subst CONFIG_SUSE_KERNEL y \
> $TMPFILE
echo $path >> $PATCH_LOG
[ -z "$QUIET" ] && echo $path
# Make sure we don't override a hard-linked file.
rm -f $PATCH_DIR/$path
cp -f $TMPFILE $PATCH_DIR/$path
done
rm -f $TMPFILE