scripts: Add a symlink to the most recently expanded source tree
[opensuse:kernel-source.git] / scripts / sequence-patch.sh
1 #! /bin/bash
2
3 #############################################################################
4 # Copyright (c) 2003-2005,2007-2009 Novell, Inc.
5 # All Rights Reserved.
6 #
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of version 2 of the GNU General Public License as
9 # published by the Free Software Foundation.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, contact Novell, Inc.
18 #
19 # To contact Novell about this file by physical or electronic mail,
20 # you may find current contact information at www.novell.com
21 #############################################################################
22
23 source $(dirname $0)/../rpm/config.sh
24 source $(dirname $0)/wd-functions.sh
25
26 set -o pipefail
27
28 have_arch_patches=false
29 fuzz="-F0"
30 case "$IBS_PROJECT" in
31 SUSE:SLE-9*)
32         fuzz=
33         have_arch_patches=true
34 esac
35
36 usage() {
37     cat <<END
38 SYNOPSIS: $0 [-qv] [--symbol=...] [--dir=...]
39           [--fast] [last-patch-name] [--vanilla] [--fuzz=NUM]
40           [--patch-dir=PATH] [--build-dir=PATH] [--config=ARCH-FLAVOR [--kabi]]
41           [--ctags] [--cscope] [--no-xen]
42
43   The --build-dir option supports internal shell aliases, like ~, and variable
44   expansion when the variables are properly escaped.  Environment variables
45   and the following list of internal variables are permitted:
46   \$PATCH_DIR:          The expanded source tree
47   \$SRCVERSION:         The current linux source tarball version
48   \$TAG:                        The current tag or branch of this repo
49   \$EXT:                        A string expanded from current \$EXTRA_SYMBOLS
50   With --config=ARCH-FLAVOR, these have values. Otherwise they are empty.
51   \$CONFIG:             The current ARCH-FLAVOR.
52   \$CONFIG_ARCH:                The current ARCH.
53   \$CONFIG_FLAVOR:      The current FLAVOR.
54
55   The --no-quilt option will still create quilt-style backups for each
56   file that is modified but the backups will be removed if the patch
57   is successful. This can be fast because the new files may be created
58   and removed before writeback occurs so they only exist in memory. A
59   failed patch will be rolled back and the caller will be able to diagnose it.
60
61   The --fast option will concatenate all the patches to be applied and
62   call patch just once. This is even faster than --no-quilt but if any
63   of the component patches fail to apply the tree will not be rolled
64   back.
65
66   When used with last-patch-name or --no-xen, both --fast and --no-quilt
67   will set up a quilt environment for the remaining patches.
68 END
69     exit 1
70 }
71
72 apply_fast_patches() {
73     before=$(echo ${PATCHES_BEFORE[@]}|wc -w)
74     after=$(echo ${PATCHES_AFTER[@]}|wc -w)
75     echo "[ Fast-applying $before patches. $after remain. ]"
76     cat "${PATCHES_BEFORE[@]}" | \
77         patch -d $PATCH_DIR -p1 -E $fuzz --force --no-backup-if-mismatch \
78                 -s > $LAST_LOG 2>&1
79     STATUS=$?
80
81     if [ $STATUS -ne 0 ]; then
82         if [ $STATUS -ne 0 ]; then
83             [ -n "$QUIET" ] && cat $LAST_LOG
84             echo "All-in-one patch failed (not rolled back)."
85             echo "Logfile: $LAST_LOG"
86             status=1
87         fi
88     else
89         rm -f $LAST_LOG
90     fi
91
92     PATCHES=( ${PATCHES_AFTER[@]} )
93 }
94
95 # Patch kernel normally
96 apply_patches() {
97     set -- "${PATCHES[@]}"
98     n=0
99     while [ $# -gt 0 ]; do
100         PATCH="$1"
101         if ! $QUILT && test "$PATCH" = "$LIMIT"; then
102             STEP_BY_STEP=1
103             echo "Stopping before $PATCH"
104         fi
105         if [ -n "$STEP_BY_STEP" ]; then
106             while true; do
107                 echo -n "Continue ([y]es/[n]o/yes to [a]ll)?"
108                 read YESNO
109                 case $YESNO in
110                     ([yYjJsS])
111                         break
112                         ;;
113                     ([nN])
114                         break 2 # break out of outer loop
115                         ;;
116                     ([aA])
117                         unset STEP_BY_STEP
118                         break
119                         ;;
120                 esac
121             done
122         fi
123
124         if [ ! -r "$PATCH" ]; then
125             echo "Patch $PATCH not found."
126             status=1
127             break
128         fi
129         echo "[ $PATCH ]"
130         echo "[ $PATCH ]" >> $PATCH_LOG
131         backup_dir=$PATCH_DIR/.pc/$PATCH
132
133         exec 5<&1  # duplicate stdin
134         case $PATCH in
135         *.gz)   exec < <(gzip -cd $PATCH) ;;
136         *.bz2)  exec < <(bzip2 -cd $PATCH) ;;
137         *)              exec < $PATCH ;;
138         esac
139         patch -d $PATCH_DIR --backup --prefix=$backup_dir/ -p1 -E $fuzz \
140                 --no-backup-if-mismatch --force > $LAST_LOG 2>&1
141         STATUS=$?
142         exec 0<&5  # restore stdin
143
144         if [ $STATUS -ne 0 ]; then
145             restore_files $backup_dir $PATCH_DIR
146         fi
147         if ! $QUILT; then
148             rm -rf $PATCH_DIR/.pc/
149         fi
150         cat $LAST_LOG >> $PATCH_LOG
151         [ -z "$QUIET" ] && cat $LAST_LOG
152         if [ $STATUS -ne 0 ]; then
153             [ -n "$QUIET" ] && cat $LAST_LOG
154             echo "Patch $PATCH failed (rolled back)."
155             echo "Logfile: $PATCH_LOG"
156             status=1
157             break
158         else
159             echo "$SERIES_PFX$PATCH" >> $PATCH_DIR/series
160             if $QUILT; then
161                 echo "$PATCH" >> $PATCH_DIR/.pc/applied-patches
162             fi
163             rm -f $LAST_LOG
164         fi
165
166         shift
167         if $QUILT; then
168                 unset PATCHES[$n]
169         fi
170         let n++
171         if $QUILT && test "$PATCH" = "$LIMIT"; then
172             break
173         fi
174     done
175 }
176
177 # Allow to pass in default arguments via SEQUENCE_PATCH_ARGS.
178 set -- $SEQUENCE_PATCH_ARGS "$@"
179
180 if $have_arch_patches; then
181         arch_opt="arch:"
182 else
183         arch_opt=""
184 fi
185 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,no-xen -- "$@"`
186
187 if [ $? -ne 0 ]
188 then
189     usage
190 fi
191
192 eval set -- "$options"
193
194 QUIET=1
195 EXTRA_SYMBOLS=
196 QUILT=true
197 FAST=
198 VANILLA=false
199 SP_BUILD_DIR=
200 CONFIG=
201 CONFIG_ARCH=
202 CONFIG_FLAVOR=
203 KABI=false
204 CTAGS=false
205 CSCOPE=false
206 SKIP_XEN=false
207
208 while true; do
209     case "$1" in
210         -q)
211             QUIET=1
212             ;;
213         -v)
214             QUIET=
215             ;;
216         --quilt)
217             QUILT=true
218             ;;
219         --no-quilt)
220             QUILT=false
221             ;;
222         --combine)
223             # ignored
224             ;;
225         --fast)
226             FAST=1
227             ;;
228         --arch)
229             export PATCH_ARCH=$2
230             shift
231             ;;
232         --symbol)
233             EXTRA_SYMBOLS="$EXTRA_SYMBOLS $2"
234             shift
235             ;;
236         -d|--dir)
237             SCRATCH_AREA=$2
238             shift
239             ;;
240         --vanilla)
241             VANILLA=true
242             ;;
243         -F|--fuzz)
244             fuzz="-F$2"
245             shift
246             ;;
247         --patch-dir)
248             PATCH_DIR=$2
249             shift
250             ;;
251         --build-dir)
252             SP_BUILD_DIR="$2"
253             shift
254             ;;
255         --config)
256             CONFIG="$2"
257             shift
258             ;;
259         --kabi)
260             KABI=true
261             ;;
262         --ctags)
263             CTAGS=true
264             ;;
265         --cscope)
266             CSCOPE=true
267             ;;
268         --no-xen)
269             SKIP_XEN=true
270             ;;
271         --)
272             shift
273             break ;;
274         *)
275             usage ;;
276     esac
277     shift
278 done
279
280 unset LIMIT
281 if [ $# -ge 1 ]; then
282     LIMIT=$1
283     shift
284 fi
285
286 if test -n "$CONFIG"; then
287     CONFIG_ARCH=${CONFIG%%-*}
288     CONFIG_FLAVOR=${CONFIG##*-}
289     if [ "$CONFIG" = "$CONFIG_ARCH" -o "$CONFIG" = "$CONFIG_FLAVOR" -o \
290          -z "$CONFIG_ARCH" -o -z "$CONFIG_FLAVOR" ]; then
291         echo "Invalid config spec: --config=ARCH-FLAVOR is expected."
292         usage
293     fi
294 fi
295
296 if [ $# -ne 0 ]; then
297     usage
298 fi
299
300 # Some patches require patch 2.5.4. Abort with older versions.
301 PATCH_VERSION=$(patch -v | sed -e '/^patch/!d' -e 's/patch //')
302 case $PATCH_VERSION in
303     ([01].*|2.[1-4].*|2.5.[1-3])  # (check if < 2.5.4)
304         echo "patch version $PATCH_VERSION found; " \
305              "a version >= 2.5.4 required." >&2
306         exit 1
307     ;;
308 esac
309
310 # Check SCRATCH_AREA.
311 if [ -z "$SCRATCH_AREA" ]; then
312     echo "SCRATCH_AREA not defined (defaulting to \"tmp\")"
313     SCRATCH_AREA=tmp
314 fi
315 if [ ! -d "$SCRATCH_AREA" ]; then
316     if ! mkdir -p $SCRATCH_AREA; then
317         echo "creating scratch dir $SCRATCH_AREA failed"
318         exit 1
319     fi
320 fi
321
322 [ "${SCRATCH_AREA:0:1}" != "/" ] \
323     && SCRATCH_AREA="$PWD/$SCRATCH_AREA"
324
325 TMPDIR=$SCRATCH_AREA
326 export TMPDIR
327 ORIG_DIR=$SCRATCH_AREA/linux-$SRCVERSION.orig
328 TAG=$(get_branch_name)
329 TAG=${TAG//\//_}
330 if [ "$VANILLA" = "true" ]; then
331         TAG=${TAG}-vanilla
332 fi
333 PATCH_LOG=$SCRATCH_AREA/patch-$SRCVERSION${TAG:+-$TAG}.log
334 LAST_LOG=$SCRATCH_AREA/last-$SRCVERSION${TAG:+-$TAG}.log
335
336 # Check series.conf.
337 if [ ! -r series.conf ]; then
338     echo "Configuration file \`series.conf' not found"
339     exit 1
340 fi
341 if [ -e scripts/check-patches ]; then
342     scripts/check-patches || {
343         echo "Inconsistencies found."
344         echo "Please clean up series.conf and/or the patches directories!"
345         read
346     }
347 fi
348
349 if $have_arch_patches; then
350     if [ -z "$ARCH_SYMBOLS" ]; then
351         if [ -x ./arch-symbols ]; then
352             ARCH_SYMBOLS=./arch-symbols
353         elif [ -x scripts/arch-symbols ]; then
354             ARCH_SYMBOLS=scripts/arch-symbols
355         else
356             echo "Cannot locate \`arch-symbols' script (export ARCH_SYMBOLS)"
357             exit 1
358         fi
359     else
360         if [ ! -x "$ARCH_SYMBOLS" ]; then
361             echo "Cannot execute \`arch-symbols' script"
362             exit 1
363         fi
364     fi
365     SYMBOLS=$($ARCH_SYMBOLS)
366     if [ -z "$SYMBOLS" ]; then
367         echo "Unsupported architecture \`$ARCH'" >&2
368         exit 1
369     fi
370 echo "Architecture symbol(s): $SYMBOLS"
371 fi
372
373 if [ -s extra-symbols ]; then
374         EXTRA_SYMBOLS="$EXTRA_SYMBOLS $(cat extra-symbols)"
375 fi
376 if [ -n "$EXTRA_SYMBOLS" ]; then
377     EXTRA_SYMBOLS=${EXTRA_SYMBOLS# }
378     echo "Extra symbols: $EXTRA_SYMBOLS"
379     SYMBOLS="$SYMBOLS $EXTRA_SYMBOLS"
380 fi
381
382 EXT=${EXTRA_SYMBOLS// /-}
383 EXT=${EXT//\//}
384
385 if test -z "$PATCH_DIR"; then
386     PATCH_DIR=$SCRATCH_AREA/linux-$SRCVERSION${TAG:+-$TAG}${EXT:+-}$EXT
387 fi
388
389 if [ -n "$SP_BUILD_DIR" ]; then
390     # This allows alias (~) and variable expansion
391     SP_BUILD_DIR=$(eval echo "$SP_BUILD_DIR")
392 else
393     SP_BUILD_DIR="$PATCH_DIR"
394 fi
395
396 echo "Creating tree in $PATCH_DIR"
397
398 # Clean up from previous run
399 rm -f "$PATCH_LOG" "$LAST_LOG"
400 if [ -e $PATCH_DIR ]; then
401     tmpdir=$(mktemp -d ${PATCH_DIR%/*}/${0##*/}.XXXXXX)
402     if [ -n "$tmpdir" ]; then
403         echo "Cleaning up from previous run (background)"
404         mv $PATCH_DIR $tmpdir
405         rm -rf $tmpdir &
406     else
407         echo "Cleaning up from previous run"
408         rm -rf $PATCH_DIR
409     fi
410 fi
411
412 # Create fresh $SCRATCH_AREA/linux-$SRCVERSION.
413 if ! [ -d $ORIG_DIR ]; then
414     unpack_tarball "$SRCVERSION" "$ORIG_DIR"
415     find $ORIG_DIR -type f | xargs chmod a-w,a+r
416 fi
417
418 if $VANILLA; then
419 PATCHES=( $(scripts/guards $SYMBOLS < series.conf | egrep '^patches\.(kernel\.org|rpmify)/') )
420 else
421 PATCHES=( $(scripts/guards $SYMBOLS < series.conf) )
422 fi
423
424 # Check if patch $LIMIT exists
425 if [ -n "$LIMIT" ] || $SKIP_XEN; then
426     for ((n=0; n<${#PATCHES[@]}; n++)); do
427         if [ "$LIMIT" = - ]; then
428             LIMIT=${PATCHES[n]}
429             break
430         fi
431         case "${PATCHES[n]}" in
432         $LIMIT|*/$LIMIT)
433             LIMIT=${PATCHES[n]}
434             break
435             ;;
436         patches.xen/*)
437             if $SKIP_XEN; then
438                 LIMIT=${PATCHES[n-1]}
439                 break
440             fi
441             ;;
442         esac
443     done
444     if ((n == ${#PATCHES[@]})); then
445         echo "No patch \`$LIMIT' found."
446         exit 1
447     fi
448     PATCHES_BEFORE=()
449     for ((m=0; m<n; m++)); do
450         PATCHES_BEFORE[m]=${PATCHES[m]}
451     done
452     PATCHES_AFTER=()
453     for ((m=n; m<${#PATCHES[@]}; m++)); do
454         PATCHES_AFTER[m-n]=${PATCHES[m]}
455     done
456 else
457     PATCHES_BEFORE=( "${PATCHES[@]}" )
458     PATCHES_AFTER=()
459 fi
460
461 # Helper function to restore files backed up by patch. This is
462 # faster than doing a --dry-run first.
463 restore_files() {
464     local backup_dir=$1 patch_dir=$2 file wd=$PWD
465     local -a remove restore
466  
467     if [ -d $backup_dir ]; then
468         pushd $backup_dir > /dev/null
469         for file in $(find . -type f) ; do
470             if [ -s "$file" ]; then
471                 restore[${#restore[@]}]="$file"
472             else
473                 remove[${#remove[@]}]="$file"
474             fi
475         done
476         #echo "Restore: ${restore[@]}"
477         [ ${#restore[@]} -ne 0 ] \
478             && printf "%s\n" "${restore[@]}" \
479                 | xargs cp -f --parents --target $patch_dir
480         cd $patch_dir
481         #echo "Remove: ${remove[@]}"
482         [ ${#remove[@]} -ne 0 ] \
483             && printf "%s\n" "${remove[@]}" | xargs rm -f
484         popd > /dev/null
485     fi
486 }
487
488 # Create hardlinked source tree
489 echo "Linking from $ORIG_DIR"
490 cp -rld $ORIG_DIR $PATCH_DIR
491 # create a relative symlink
492 ln -sf ${PATCH_DIR#${SCRATCH_AREA%%/}/} $SCRATCH_AREA/current
493
494 echo -e "# Symbols: $SYMBOLS\n#" > $PATCH_DIR/series
495 SERIES_PFX=
496 if ! $QUILT; then
497     SERIES_PFX="# "
498 fi
499
500 mkdir $PATCH_DIR/.pc
501 echo 2 > $PATCH_DIR/.pc/.version
502
503 if [ -z "$FAST" ]; then
504     apply_patches
505 else
506     apply_fast_patches
507 fi
508
509 if [ -n "$EXTRA_SYMBOLS" ]; then
510     echo "$EXTRA_SYMBOLS" > $PATCH_DIR/extra-symbols
511 fi
512
513 if ! $QUILT; then
514     rm $PATCH_DIR/series
515 fi
516
517 ln -s $PWD $PATCH_DIR/patches
518 ln -s patches/scripts/{refresh_patch,run_oldconfig}.sh $PATCH_DIR/
519 if $QUILT; then
520     [ -r $HOME/.quiltrc ] && . $HOME/.quiltrc
521     [ ${QUILT_PATCHES-patches} != patches ] \
522         && ln -s $PWD $PATCH_DIR/${QUILT_PATCHES-patches}
523 fi
524 echo "[ Tree: $PATCH_DIR ]"
525
526 if test "$SP_BUILD_DIR" != "$PATCH_DIR"; then
527     mkdir -p "$SP_BUILD_DIR"
528     echo "[ Build Dir: $SP_BUILD_DIR ]"
529     rm -f "$SP_BUILD_DIR/source"
530     rm -f "$SP_BUILD_DIR/patches"
531     ln -sf "$PATCH_DIR" "$SP_BUILD_DIR/source"
532     ln -sf "source/patches" "$SP_BUILD_DIR/patches"
533 fi
534
535 # If there are any remaining patches, add them to the series so
536 # they can be fixed up with quilt (or similar).
537 if [ -n "${PATCHES[*]}" ]; then
538     ( IFS=$'\n' ; echo "${PATCHES[*]}" ) >> $PATCH_DIR/series
539     exit $status
540 fi
541
542 if test -e supported.conf; then
543     echo "[ Generating Module.supported ]"
544     scripts/guards base external < supported.conf > "$SP_BUILD_DIR/Module.supported"
545 fi
546
547 if test -n "$CONFIG"; then
548     if test -e "config/$CONFIG_ARCH/$CONFIG_FLAVOR"; then
549         echo "[ Copying config/$CONFIG_ARCH/$CONFIG ]"
550         cp -a "config/$CONFIG_ARCH/$CONFIG_FLAVOR" "$SP_BUILD_DIR/.config"
551     else
552         echo "[ Config $CONFIG does not exist. ]"
553     fi
554
555     if $KABI; then
556         if [ ! -x rpm/modversions ]; then
557             echo "[ This branch does not support the modversions kABI mechanism. Skipping. ]"
558         elif [ -e "kabi/$CONFIG_ARCH/symtypes-$CONFIG_FLAVOR" ]; then
559             echo "[ Expanding kABI references for $CONFIG ]"
560             rpm/modversions --unpack "$SP_BUILD_DIR" < \
561                 "kabi/$CONFIG_ARCH/symtypes-$CONFIG_FLAVOR"
562         else
563             echo "[ No kABI references for $CONFIG ]"
564         fi
565     fi
566 fi
567
568 if $CTAGS; then
569     if ctags --version > /dev/null; then
570         echo "[ Generating ctags (this may take a while)]"
571         make -s --no-print-directory -C "$PATCH_DIR" O="$SP_BUILD_DIR" tags
572     else
573         echo "[ Could not generate ctags: ctags not found ]"
574     fi
575 fi
576
577 if $CSCOPE; then
578     if cscope -V 2> /dev/null; then
579         echo "[ Generating cscope db (this may take a while)]"
580         make -s --no-print-directory -C "$PATCH_DIR" O="$SP_BUILD_DIR" cscope
581     else
582         echo "[ Could not generate cscope db: cscope not found ]"
583     fi
584 fi
585