Saturday, August 21, 2010

Working with Linux patches


This topic will use the Linux kernel as an example, but this method can be applied to any source tree. This topic assumes a Linux host or Cygwin installed on a Windows host.
To create a patch one uses the GNU diff command, and to apply a patch one uses the GNU patch command. Both should be available on your Linux system, or in your Cygwin installation.

Creating a patch

You always keep yourself one level up in the directory structure from the directory you want to patch when you execute the diff command. Note that the -u flag is used, which generates unified diff. The -r flag used is to traverse all subdirectories recursively, and the -N flag makes sure files missing in one of the directories still gets added to the patch. And of course you'll want to 'clean' (make distclean) before making the patch:
make distclean
So, let's say you have made changes to a Linux kernel. I keep the original kernel tree I am working from in the linux-2.6.13-orig directory. I keep my changes in a separate tree, linux-2.6.13-mine. To generate a patch file describing my changes with the delta between the two versions I would execute:
diff -uNr linux-2.6.13-orig linux-2.6.13-mine > patch-2.6.13-mytag
This creates a file called patch-2.6.13-mytag, which is an uncompressed patch file. Note that this is readable text, and you should read through it as a sanity check to make sure no dot-files or other junk got in there by mistake.
Also, note the size of the patch file. It should be relatively small. For example, if your source code that has changed consists of a few files that are ~10KB, the patch file should be on the order of 10-20KB.
It is important that the patch file (which again is only a text file) is in UNIX mode and not DOS mode (depending on where you have edited the file). Please run the following command on your patch:
file patch-2.6.13-mytag
If you get: patch-2.6.13-mytag: 'diff' output text then your patch should be in the correct mode. If you get something like patch-2.6.13-mytag: ASCII English text, with CRLF line terminators or similar (note the CRLF which means DOS mode), action is required.
To put the file in UNIX mode (i.e. remove all the CR characters) execute:
tr -d '\r' < patch-2.6.13-mytag.dosmode > patch-2.6.13-mytag.unixmode
Alternatively you can use the dos2unix command, but if only parts of the file is in DOS mode this can yield bad results.
It is also important to make sure that applications do not automatically translate the patch files to DOS mode when transferring the file (i.e. mail clients or web browsers). To prevent this (and of course to reduce the size of the file) you should compress the patch. To compress the patch file using bzip2 execute:
bzip2 -9 patch-2.6.13-mytag
This will create a compressed patch with the name patch-2.6.13-mytag.bz2.
You should replace the mytag part of the filename with something describing the patch. It could be your name, the name of your team, or the ISA the patch is for.
Summary:
  • make distclean
  • diff -uNr linux-2.6.13-orig linux-2.6.13-mine > patch-2.6.13-mytag
  • file patch-2.6.13-mytag optionally followed by:
    • tr -d '\r' < patch-2.6.13-mytag.dosmode > patch-2.6.13-mytag.unixmode
  • bzip2 -9 patch-2.6.13-mytag

Applying a patch

Patches you download are generally compressed. If they end with the .gz extension they are compressed with gzip (patch-2.6.13-sometag.gz). To uncompress this file type:
gunzip patch-2.6.13-sometag.gz
This will create an uncompressed patch file called patch-2.6.13-sometag.
Alternatively the patch ends with the .bz2 extension, in which case you will have to execute the following to uncompress:
bzip2 -d patch-2.6.13-sometag.bz2
This will also create an uncompressed patch file called patch-2.6.13-sometag.
If the file has no ending, it is most probably uncompressed. If you have doubts, execute the following command to get information on the file type:
file patch-2.6.13-sometag
If it's uncompressed it should say that it's a file of type 'diff' output text. To apply the patch, move into the project directory (linux kernel directory in this case, for instance the directory linux-2.6.13) and type:
patch -p1 < ../patch-2.6.13-sometag
This should apply the patch delta to your baseline project directory.
The -p1 option means patchlevel 1. This means that it should skip one level of directories when applying the patch. If you view the patch-2.6.13-mytag file from above, it would read on the first two lines:
--- linux-2.6.13-orig/ Thu Nov 28 23:53:15 2002
+++ linux-2.6.13-mine/ Tue Dec 3 22:54:07 2002
This shows which file to start applying patches to. The -p1 option makes the patch command ignore the first linux-2.6.13-orig and linux-2.6.13-mine directories when applying the patch.
Summary:
  • gunzip patch-2.6.13-sometag.gz or bzip2 -d patch-2.6.13-sometag.bz2.
  • file patch-2.6.13-sometag
  • cd /path/to/kernel
  • patch -p1 < /path/to/patch-2.6.13-sometag

Reverting a patch

Sometimes you want to try out the contents of a patch, but perhaps the patch introduced bugs you currently don't want to deal with. Fortunately, there is a way to revert patches. To revert the patch applied above, execute the following (from the linux-2.6.13 directory):
patch -Rp1 < patch-2.6.13-sometag
This will restore the kernel tree to the state it was before the patch was applied.

How to survive with many patches

If the number of patches you deal with increases, it becomes inconvenient to do this manually. Then you may like to have a look to quilt. See How To Survive With Many Patches for an introduction to quilt.

Sending patches upstream

Handling patch rejects

See handling patch rejects article.

Diff and patch tricks

See (slightly outdated, it mentions BitKeeper) diff and patch tricks article.

For technical support please post your questions at http://e2e.ti.com. Please post only comments about the article Working with Linux patches here.