Linuxのカーネルのパッチ適用

カーネルに対して最新の機能を適用したい場合、カーネルの再構築を行う必要がある。
Linuxはオープンソースでありソースコードは公開されているため、このソースコードを編集し(パッチの作成と適用)、コンパイルを行い、これをカーネル側に反映することにより適用する。

ソースコードは公開されているため、個人利用目的の範囲内であれば、直接ソースコードを編集して目的を実現することが可能だ。
しかし、実際にこれは現実的でないことが多いため、リポジトリ等で公開されているパッチを当てるのが一般的である。

パッチの作成(diffコマンド)

かつて、ネットワーク回線は非常に低速であった。また、記憶装置も高価なものであった。したがって、カーネルプログラムのような大規模なソースコードを更新の都度全てダウンロードするのは、大きな負荷であった。

これを、パッチという仕組みによって解決した。

パッチとは、古いカーネルプログラムと新しいカーネルプログラムの差分データのことである。
patchコマンドによって、これをカーネルのソースコードへ反映する。

パッチに利用するパッチファイルは、diffコマンドによって得られる差分情報の出力結果を利用する。
diffコマンドは、テキストファイルの差分情報を出力するコマンドである。
以下はその例である。

# diff -aNru ./hoge ./fuga | nl
    1  diff -aNru ./hoge/test1.txt ./fuga/test1.txt
    2  --- ./hoge/test1.txt    2009-11-29 19:59:45.000000000 +0900
    3  +++ ./fuga/test1.txt    2009-11-29 20:00:04.000000000 +0900
    4  @@ -1,5 +1,5 @@
    5   a
    6   b
    7  -C
    8  +c
    9   d
   10   e
   11  diff -aNru ./hoge/test2 ./fuga/test2
   12  --- ./hoge/test2.txt    2009-11-29 20:03:18.000000000 +0900
   13  +++ ./fuga/test2.txt    1970-01-01 09:00:00.000000000 +0900
   14  @@ -1 +0,0 @@
   15  -abcde

hogeは旧ディレクトリ、fugaは新ディレクトリであり、この差分情報を標準出力へ出力した。
なお、解説を行うため、nlコマンドにより行番号を与えている。また、C言語のファイルの場合煩雑になるため、簡単な文字列の情報ファイルをサンプルとしている。

diffコマンドへ与えたオプションは以下の通りである。

オプション 内容
a 対象データがテキストファイルであることを明示する。diffはバイナリの認識も可能なので、誤認識を防ぐためである。
N ファイルが存在しない場合、空ファイルとして認識する。ソースコードの追加・削除の可能性があるからである。
r 比較対象がディレクトリであることを表す。パッチの適用対象がディレクトリであるからである。
u ユニファイド形式(最小の情報)で出力する。patchコマンドで利用するフォーマットである。

1行目は、比較の対象となるファイルを表している。
2-3行目にて、タイムスタンプが異なるため、これを更新する情報を与えている。
4-10行目にて、テキストデータの差異を表現している。旧ファイルの3行目が「C」であるのに対し、新ファイルの3行目が「c」であることを表している。

11行目以降も別のファイルに対して同様のことを行っているが、サンプルでは新データにtest2.txtというファイルを作成していない。
しかし、オプションでNを与えたため、新データに空ファイル「test2.txt」が存在しているものとして扱っている。
15行目では、新データには当然情報が存在しないので、旧ファイル側には「abcde」という情報が存在していたことを明示している。

パッチの適用(patchコマンド)

パッチの適用は、patchコマンドを用いる。

下記の図では、現在パッチ対象のディレクトリへ移動しており、そこに3つのファイルが置かれていることを確認した状態である。

# ls
test.diff  test1.txt  test2.txt

ファイル「test.diff」は、パッチファイルである。
これを利用して、patchコマンドを実行する。

まず、パッチファイルの内容を確認して、対象ディレクトリの深さを確認する。

# head -3 ./test.diff
diff -aNru ./hoge/test1.txt ./fuga/test1.txt
--- ./hoge/test1.txt    2009-11-29 20:33:04.000000000 +0900
+++ ./fuga/test1.txt    2009-11-29 20:33:04.000000000 +0900

headコマンドによりパッチファイルの上部を確認したところ、
パッチ対象となるドキュメントが「+++ ./fuga/test1.txt」からディレクトリ「fuga」以下に置かれている事が理解できる。
しかし、実際には更新対象のデータ「test1.txt」はカーレントディレクトリであるため、パッチファイルの内容は階層が1つ浅いということになる。

そこでオプション「-p」を利用して、以下のコマンドを入力する。

# patch -p1 < test.diff
can't find file to patch at input line 4
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff -aNru ./hoge/test1.txt ./fuga/test1.txt
|--- ./hoge/test1.txt   2009-11-29 20:33:04.000000000 +0900
|+++ ./fuga/test1.txt   2009-11-29 20:33:04.000000000 +0900
--------------------------
File to patch: test1.txt
・・・(略)

「-p」に続く数字は、階層の深さを指定する。
旧データと新データのルートとなるディレクトリの名称は、大抵バージョン名が含まれているなどの理由で異なる事が多い。
したがって、patchコマンド実行の際には、パッチ対象データのディレクトリ内に入り、「-p」を指定してパッチを当てることは少なくない。

パッチの適用(patch-kenelスクリプト)

近年更新するソースコードのサイズは増大しており、patchの対象となるデータも比例して多くなっている。
この様な状況下において、上記のpatchコマンドの利用は負荷としてかなり大きいものである。これを解決するのが、patch-kernelスクリプトである。

patch-kernelスクリプトは、カーネルのソースコードが置かれたディレクトリへ一緒に置かれている。
これを、以下の通り実行する。

# (新データ)/scripts/patch-kernel (旧データ)

  • 最終更新:2009-12-06 23:18:53

このWIKIを編集するにはパスワード入力が必要です

認証パスワード