162306a36Sopenharmony_ci#! /bin/sh
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci# Script to apply kernel patches.
462306a36Sopenharmony_ci#   usage: patch-kernel [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]
562306a36Sopenharmony_ci#     The source directory defaults to /usr/src/linux, and the patch
662306a36Sopenharmony_ci#     directory defaults to the current directory.
762306a36Sopenharmony_ci# e.g.
862306a36Sopenharmony_ci#   scripts/patch-kernel . ..
962306a36Sopenharmony_ci#      Update the kernel tree in the current directory using patches in the
1062306a36Sopenharmony_ci#      directory above to the latest Linus kernel
1162306a36Sopenharmony_ci#   scripts/patch-kernel . .. -ac
1262306a36Sopenharmony_ci#      Get the latest Linux kernel and patch it with the latest ac patch
1362306a36Sopenharmony_ci#   scripts/patch-kernel . .. 2.4.9
1462306a36Sopenharmony_ci#      Gets standard kernel 2.4.9
1562306a36Sopenharmony_ci#   scripts/patch-kernel . .. 2.4.9 -ac
1662306a36Sopenharmony_ci#      Gets 2.4.9 with latest ac patches
1762306a36Sopenharmony_ci#   scripts/patch-kernel . .. 2.4.9 -ac11
1862306a36Sopenharmony_ci#      Gets 2.4.9 with ac patch ac11
1962306a36Sopenharmony_ci#   Note: It uses the patches relative to the Linus kernels, not the
2062306a36Sopenharmony_ci#   ac to ac relative patches
2162306a36Sopenharmony_ci#
2262306a36Sopenharmony_ci# It determines the current kernel version from the top-level Makefile.
2362306a36Sopenharmony_ci# It then looks for patches for the next sublevel in the patch directory.
2462306a36Sopenharmony_ci# This is applied using "patch -p1 -s" from within the kernel directory.
2562306a36Sopenharmony_ci# A check is then made for "*.rej" files to see if the patch was
2662306a36Sopenharmony_ci# successful.  If it is, then all of the "*.orig" files are removed.
2762306a36Sopenharmony_ci#
2862306a36Sopenharmony_ci#       Nick Holloway <Nick.Holloway@alfie.demon.co.uk>, 2nd January 1995.
2962306a36Sopenharmony_ci#
3062306a36Sopenharmony_ci# Added support for handling multiple types of compression. What includes
3162306a36Sopenharmony_ci# gzip, bzip, bzip2, zip, compress, and plaintext.
3262306a36Sopenharmony_ci#
3362306a36Sopenharmony_ci#       Adam Sulmicki <adam@cfar.umd.edu>, 1st January 1997.
3462306a36Sopenharmony_ci#
3562306a36Sopenharmony_ci# Added ability to stop at a given version number
3662306a36Sopenharmony_ci# Put the full version number (i.e. 2.3.31) as the last parameter
3762306a36Sopenharmony_ci#       Dave Gilbert <linux@treblig.org>, 11th December 1999.
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci# Fixed previous patch so that if we are already at the correct version
4062306a36Sopenharmony_ci# not to patch up.
4162306a36Sopenharmony_ci#
4262306a36Sopenharmony_ci# Added -ac option, use -ac or -ac9 (say) to stop at a particular version
4362306a36Sopenharmony_ci#       Dave Gilbert <linux@treblig.org>, 29th September 2001.
4462306a36Sopenharmony_ci#
4562306a36Sopenharmony_ci# Add support for (use of) EXTRAVERSION (to support 2.6.8.x, e.g.);
4662306a36Sopenharmony_ci# update usage message;
4762306a36Sopenharmony_ci# fix some whitespace damage;
4862306a36Sopenharmony_ci# be smarter about stopping when current version is larger than requested;
4962306a36Sopenharmony_ci#	Randy Dunlap <rdunlap@xenotime.net>, 2004-AUG-18.
5062306a36Sopenharmony_ci#
5162306a36Sopenharmony_ci# Add better support for (non-incremental) 2.6.x.y patches;
5262306a36Sopenharmony_ci# If an ending version number if not specified, the script automatically
5362306a36Sopenharmony_ci# increments the SUBLEVEL (x in 2.6.x.y) until no more patch files are found;
5462306a36Sopenharmony_ci# however, EXTRAVERSION (y in 2.6.x.y) is never automatically incremented
5562306a36Sopenharmony_ci# but must be specified fully.
5662306a36Sopenharmony_ci#
5762306a36Sopenharmony_ci# patch-kernel does not normally support reverse patching, but does so when
5862306a36Sopenharmony_ci# applying EXTRAVERSION (x.y) patches, so that moving from 2.6.11.y to 2.6.11.z
5962306a36Sopenharmony_ci# is easy and handled by the script (reverse 2.6.11.y and apply 2.6.11.z).
6062306a36Sopenharmony_ci#	Randy Dunlap <rdunlap@xenotime.net>, 2005-APR-08.
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciPNAME=patch-kernel
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci# Set directories from arguments, or use defaults.
6562306a36Sopenharmony_cisourcedir=${1-/usr/src/linux}
6662306a36Sopenharmony_cipatchdir=${2-.}
6762306a36Sopenharmony_cistopvers=${3-default}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ciif [ "$1" = -h -o "$1" = --help -o ! -r "$sourcedir/Makefile" ]; then
7062306a36Sopenharmony_cicat << USAGE
7162306a36Sopenharmony_ciusage: $PNAME [-h] [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]
7262306a36Sopenharmony_ci  source directory defaults to /usr/src/linux,
7362306a36Sopenharmony_ci  patch directory defaults to the current directory,
7462306a36Sopenharmony_ci  stopversion defaults to <all in patchdir>.
7562306a36Sopenharmony_ciUSAGE
7662306a36Sopenharmony_ciexit 1
7762306a36Sopenharmony_cifi
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci# See if we have any -ac options
8062306a36Sopenharmony_cifor PARM in $*
8162306a36Sopenharmony_cido
8262306a36Sopenharmony_ci  case $PARM in
8362306a36Sopenharmony_ci	  -ac*)
8462306a36Sopenharmony_ci		  gotac=$PARM;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	esac;
8762306a36Sopenharmony_cidone
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci# ---------------------------------------------------------------------------
9062306a36Sopenharmony_ci# arg1 is filename
9162306a36Sopenharmony_cinoFile () {
9262306a36Sopenharmony_ci	echo "cannot find patch file: ${patch}"
9362306a36Sopenharmony_ci	exit 1
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci# ---------------------------------------------------------------------------
9762306a36Sopenharmony_cibackwards () {
9862306a36Sopenharmony_ci	echo "$PNAME does not support reverse patching"
9962306a36Sopenharmony_ci	exit 1
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci# ---------------------------------------------------------------------------
10362306a36Sopenharmony_ci# Find a file, first parameter is basename of file
10462306a36Sopenharmony_ci# it tries many compression mechanisms and sets variables to say how to get it
10562306a36Sopenharmony_cifindFile () {
10662306a36Sopenharmony_ci  filebase=$1;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci  if [ -r ${filebase}.gz ]; then
10962306a36Sopenharmony_ci		ext=".gz"
11062306a36Sopenharmony_ci		name="gzip"
11162306a36Sopenharmony_ci		uncomp="gunzip -dc"
11262306a36Sopenharmony_ci  elif [ -r ${filebase}.bz  ]; then
11362306a36Sopenharmony_ci		ext=".bz"
11462306a36Sopenharmony_ci		name="bzip"
11562306a36Sopenharmony_ci		uncomp="bunzip -dc"
11662306a36Sopenharmony_ci  elif [ -r ${filebase}.bz2 ]; then
11762306a36Sopenharmony_ci		ext=".bz2"
11862306a36Sopenharmony_ci		name="bzip2"
11962306a36Sopenharmony_ci		uncomp="bunzip2 -dc"
12062306a36Sopenharmony_ci  elif [ -r ${filebase}.xz ]; then
12162306a36Sopenharmony_ci                ext=".xz"
12262306a36Sopenharmony_ci                name="xz"
12362306a36Sopenharmony_ci                uncomp="xz -dc"
12462306a36Sopenharmony_ci  elif [ -r ${filebase}.zip ]; then
12562306a36Sopenharmony_ci		ext=".zip"
12662306a36Sopenharmony_ci		name="zip"
12762306a36Sopenharmony_ci		uncomp="unzip -d"
12862306a36Sopenharmony_ci  elif [ -r ${filebase}.Z ]; then
12962306a36Sopenharmony_ci		ext=".Z"
13062306a36Sopenharmony_ci		name="uncompress"
13162306a36Sopenharmony_ci		uncomp="uncompress -c"
13262306a36Sopenharmony_ci  elif [ -r ${filebase} ]; then
13362306a36Sopenharmony_ci		ext=""
13462306a36Sopenharmony_ci		name="plaintext"
13562306a36Sopenharmony_ci		uncomp="cat"
13662306a36Sopenharmony_ci  else
13762306a36Sopenharmony_ci	return 1;
13862306a36Sopenharmony_ci  fi
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci  return 0;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci# ---------------------------------------------------------------------------
14462306a36Sopenharmony_ci# Apply a patch and check it goes in cleanly
14562306a36Sopenharmony_ci# First param is patch name (e.g. patch-2.4.9-ac5) - without path or extension
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciapplyPatch () {
14862306a36Sopenharmony_ci  echo -n "Applying $1 (${name})... "
14962306a36Sopenharmony_ci  if $uncomp ${patchdir}/$1${ext} | patch -p1 -s -N -E -d $sourcedir
15062306a36Sopenharmony_ci  then
15162306a36Sopenharmony_ci    echo "done."
15262306a36Sopenharmony_ci  else
15362306a36Sopenharmony_ci    echo "failed.  Clean up yourself."
15462306a36Sopenharmony_ci    return 1;
15562306a36Sopenharmony_ci  fi
15662306a36Sopenharmony_ci  if [ "`find $sourcedir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ]
15762306a36Sopenharmony_ci  then
15862306a36Sopenharmony_ci    echo "Aborting.  Reject files found."
15962306a36Sopenharmony_ci    return 1;
16062306a36Sopenharmony_ci  fi
16162306a36Sopenharmony_ci  # Remove backup files
16262306a36Sopenharmony_ci  find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci  return 0;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci# ---------------------------------------------------------------------------
16862306a36Sopenharmony_ci# arg1 is patch filename
16962306a36Sopenharmony_cireversePatch () {
17062306a36Sopenharmony_ci	echo -n "Reversing $1 (${name}) ... "
17162306a36Sopenharmony_ci	if $uncomp ${patchdir}/"$1"${ext} | patch -p1 -Rs -N -E -d $sourcedir
17262306a36Sopenharmony_ci	then
17362306a36Sopenharmony_ci		echo "done."
17462306a36Sopenharmony_ci	else
17562306a36Sopenharmony_ci		echo "failed.  Clean it up."
17662306a36Sopenharmony_ci		exit 1
17762306a36Sopenharmony_ci	fi
17862306a36Sopenharmony_ci	if [ "`find $sourcedir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ]
17962306a36Sopenharmony_ci	then
18062306a36Sopenharmony_ci		echo "Aborting.  Reject files found."
18162306a36Sopenharmony_ci		return 1
18262306a36Sopenharmony_ci	fi
18362306a36Sopenharmony_ci	# Remove backup files
18462306a36Sopenharmony_ci	find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci# set current VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION
19062306a36Sopenharmony_ci# force $TMPFILEs below to be in local directory: a slash character prevents
19162306a36Sopenharmony_ci# the dot command from using the search path.
19262306a36Sopenharmony_ciTMPFILE=`mktemp ./.tmpver.XXXXXX` || { echo "cannot make temp file" ; exit 1; }
19362306a36Sopenharmony_cigrep -E "^(VERSION|PATCHLEVEL|SUBLEVEL|EXTRAVERSION)" $sourcedir/Makefile > $TMPFILE
19462306a36Sopenharmony_citr -d [:blank:] < $TMPFILE > $TMPFILE.1
19562306a36Sopenharmony_ci. $TMPFILE.1
19662306a36Sopenharmony_cirm -f $TMPFILE*
19762306a36Sopenharmony_ciif [ -z "$VERSION" -o -z "$PATCHLEVEL" -o -z "$SUBLEVEL" ]
19862306a36Sopenharmony_cithen
19962306a36Sopenharmony_ci    echo "unable to determine current kernel version" >&2
20062306a36Sopenharmony_ci    exit 1
20162306a36Sopenharmony_cifi
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciNAME=`grep ^NAME $sourcedir/Makefile`
20462306a36Sopenharmony_ciNAME=${NAME##*=}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciecho "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL${EXTRAVERSION} ($NAME)"
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci# strip EXTRAVERSION to just a number (drop leading '.' and trailing additions)
20962306a36Sopenharmony_ciEXTRAVER=
21062306a36Sopenharmony_ciif [ x$EXTRAVERSION != "x" ]
21162306a36Sopenharmony_cithen
21262306a36Sopenharmony_ci	EXTRAVER=${EXTRAVERSION#.}
21362306a36Sopenharmony_ci	EXTRAVER=${EXTRAVER%%[[:punct:]]*}
21462306a36Sopenharmony_ci	#echo "$PNAME: changing EXTRAVERSION from $EXTRAVERSION to $EXTRAVER"
21562306a36Sopenharmony_cifi
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci#echo "stopvers=$stopvers"
21862306a36Sopenharmony_ciif [ $stopvers != "default" ]; then
21962306a36Sopenharmony_ci	STOPSUBLEVEL=`echo $stopvers | cut -d. -f3`
22062306a36Sopenharmony_ci	STOPEXTRA=`echo $stopvers | cut -d. -f4`
22162306a36Sopenharmony_ci	STOPFULLVERSION=${stopvers%%.$STOPEXTRA}
22262306a36Sopenharmony_ci	#echo "#___STOPSUBLEVEL=/$STOPSUBLEVEL/, STOPEXTRA=/$STOPEXTRA/"
22362306a36Sopenharmony_cielse
22462306a36Sopenharmony_ci	STOPSUBLEVEL=9999
22562306a36Sopenharmony_ci	STOPEXTRA=9999
22662306a36Sopenharmony_cifi
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci# This all assumes a 2.6.x[.y] kernel tree.
22962306a36Sopenharmony_ci# Don't allow backwards/reverse patching.
23062306a36Sopenharmony_ciif [ $STOPSUBLEVEL -lt $SUBLEVEL ]; then
23162306a36Sopenharmony_ci	backwards
23262306a36Sopenharmony_cifi
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciif [ x$EXTRAVER != "x" ]; then
23562306a36Sopenharmony_ci	CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL.$EXTRAVER"
23662306a36Sopenharmony_cielse
23762306a36Sopenharmony_ci	CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
23862306a36Sopenharmony_cifi
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ciif [ x$EXTRAVER != "x" ]; then
24162306a36Sopenharmony_ci	echo "backing up to: $VERSION.$PATCHLEVEL.$SUBLEVEL"
24262306a36Sopenharmony_ci	patch="patch-${CURRENTFULLVERSION}"
24362306a36Sopenharmony_ci	findFile $patchdir/${patch} || noFile ${patch}
24462306a36Sopenharmony_ci	reversePatch ${patch} || exit 1
24562306a36Sopenharmony_cifi
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci# now current is 2.6.x, with no EXTRA applied,
24862306a36Sopenharmony_ci# so update to target SUBLEVEL (2.6.SUBLEVEL)
24962306a36Sopenharmony_ci# and then to target EXTRAVER (2.6.SUB.EXTRAVER) if requested.
25062306a36Sopenharmony_ci# If not ending sublevel is specified, it is incremented until
25162306a36Sopenharmony_ci# no further sublevels are found.
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ciif [ $STOPSUBLEVEL -gt $SUBLEVEL ]; then
25462306a36Sopenharmony_ciwhile :				# incrementing SUBLEVEL (s in v.p.s)
25562306a36Sopenharmony_cido
25662306a36Sopenharmony_ci    CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
25762306a36Sopenharmony_ci    EXTRAVER=
25862306a36Sopenharmony_ci    if [ x$STOPFULLVERSION = x$CURRENTFULLVERSION ]; then
25962306a36Sopenharmony_ci        echo "Stopping at $CURRENTFULLVERSION base as requested."
26062306a36Sopenharmony_ci        break
26162306a36Sopenharmony_ci    fi
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci    SUBLEVEL=$(($SUBLEVEL + 1))
26462306a36Sopenharmony_ci    FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
26562306a36Sopenharmony_ci    #echo "#___ trying $FULLVERSION ___"
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci    if [ $(($SUBLEVEL)) -gt $(($STOPSUBLEVEL)) ]; then
26862306a36Sopenharmony_ci	echo "Stopping since sublevel ($SUBLEVEL) is beyond stop-sublevel ($STOPSUBLEVEL)"
26962306a36Sopenharmony_ci	exit 1
27062306a36Sopenharmony_ci    fi
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci    patch=patch-$FULLVERSION
27362306a36Sopenharmony_ci    # See if the file exists and find extension
27462306a36Sopenharmony_ci    findFile $patchdir/${patch} || noFile ${patch}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci    # Apply the patch and check all is OK
27762306a36Sopenharmony_ci    applyPatch $patch || break
27862306a36Sopenharmony_cidone
27962306a36Sopenharmony_ci#echo "#___sublevel all done"
28062306a36Sopenharmony_cifi
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci# There is no incremental searching for extraversion...
28362306a36Sopenharmony_ciif [ "$STOPEXTRA" != "" ]; then
28462306a36Sopenharmony_ciwhile :				# just to allow break
28562306a36Sopenharmony_cido
28662306a36Sopenharmony_ci# apply STOPEXTRA directly (not incrementally) (x in v.p.s.x)
28762306a36Sopenharmony_ci	FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL.$STOPEXTRA"
28862306a36Sopenharmony_ci	#echo "#... trying $FULLVERSION ..."
28962306a36Sopenharmony_ci	patch=patch-$FULLVERSION
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	# See if the file exists and find extension
29262306a36Sopenharmony_ci	findFile $patchdir/${patch} || noFile ${patch}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	# Apply the patch and check all is OK
29562306a36Sopenharmony_ci	applyPatch $patch || break
29662306a36Sopenharmony_ci	#echo "#___extraver all done"
29762306a36Sopenharmony_ci	break
29862306a36Sopenharmony_cidone
29962306a36Sopenharmony_cifi
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciif [ x$gotac != x ]; then
30262306a36Sopenharmony_ci  # Out great user wants the -ac patches
30362306a36Sopenharmony_ci	# They could have done -ac (get latest) or -acxx where xx=version they want
30462306a36Sopenharmony_ci	if [ $gotac = "-ac" ]; then
30562306a36Sopenharmony_ci	  # They want the latest version
30662306a36Sopenharmony_ci		HIGHESTPATCH=0
30762306a36Sopenharmony_ci		for PATCHNAMES in $patchdir/patch-${CURRENTFULLVERSION}-ac*\.*
30862306a36Sopenharmony_ci		do
30962306a36Sopenharmony_ci			ACVALUE=`echo $PATCHNAMES | sed -e 's/^.*patch-[0-9.]*-ac\([0-9]*\).*/\1/'`
31062306a36Sopenharmony_ci			# Check it is actually a recognised patch type
31162306a36Sopenharmony_ci			findFile $patchdir/patch-${CURRENTFULLVERSION}-ac${ACVALUE} || break
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		  if [ $ACVALUE -gt $HIGHESTPATCH ]; then
31462306a36Sopenharmony_ci			  HIGHESTPATCH=$ACVALUE
31562306a36Sopenharmony_ci		  fi
31662306a36Sopenharmony_ci		done
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		if [ $HIGHESTPATCH -ne 0 ]; then
31962306a36Sopenharmony_ci			findFile $patchdir/patch-${CURRENTFULLVERSION}-ac${HIGHESTPATCH} || break
32062306a36Sopenharmony_ci			applyPatch patch-${CURRENTFULLVERSION}-ac${HIGHESTPATCH}
32162306a36Sopenharmony_ci		else
32262306a36Sopenharmony_ci		  echo "No -ac patches found"
32362306a36Sopenharmony_ci		fi
32462306a36Sopenharmony_ci	else
32562306a36Sopenharmony_ci	  # They want an exact version
32662306a36Sopenharmony_ci		findFile $patchdir/patch-${CURRENTFULLVERSION}${gotac} || {
32762306a36Sopenharmony_ci		  echo "Sorry, I couldn't find the $gotac patch for $CURRENTFULLVERSION.  Hohum."
32862306a36Sopenharmony_ci			exit 1
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci		applyPatch patch-${CURRENTFULLVERSION}${gotac}
33162306a36Sopenharmony_ci	fi
33262306a36Sopenharmony_cifi
333