怎样为Linux内核打补丁
?--------------------
? ?? ?? ?? ?? ?? ?? ???作者? ?? ?? ???:Jesper Juhl,2005年8月
? ?? ?? ?? ?? ?? ?? ???最后更新日期 :2006-01-05
? ?? ?? ?? ?? ?? ?? ???譯者? ?? ?? ? :Jeffshia, 2006年8月
? ?? ?? ?? ?? ?? ?? ???email? ?? ? : tshxiayu@126.com
在Linux內核郵件列表中一個經常被問到的問題就是怎樣為Linux內核打一個補丁,或者更具體一點說,
存在這么多的主干/分支,一個補丁到底要打在哪個版本的基礎內核上。希望這篇文檔能夠為你解釋明白這
一點。
除了解釋怎樣應用以及卸載補丁以外,在這里還提供了一個不同內核樹(以及如何為它們打上特
定補丁)的簡要介紹。
什么是補丁?
----------
一個補丁就是一個文本文檔,這個文檔包含了在兩個不同版本的源代碼樹之間的變化。
補丁是通過diff應用程序來創建的。
為了正確地打上一個補丁,你需要知道這個補丁是從哪個基礎版本產生出來的以及這個補丁將要把
目前的源代碼樹變化到什么新的版本。這些信息或者會出現在補丁文件的原數據中,或者可能
從文件名中推斷出來。
怎樣打補丁和卸載補丁
-------------------
可以使用patch程序來打一個補丁。patch程序讀取一個diff(或者patch)文件,然后把文件中
描述的變化內容應用到代碼樹上。
Linux內核中的補丁是相對于保存內核源代碼目錄的父目錄而生成的。
這就意味著:patch文件中的文件路徑包含了它所基于的內核源文件目錄的名字(或者像是"a/"和"b/"
之類的其它名字)。
由于這很可能和你本地機器上的內核源代碼目錄的名字不匹配(但是對于查看一個沒有標簽的補丁所
基于的內核版本是非常有用的)。你應該切換到你的內核源代碼目錄,并且在打補丁的時候去掉patch
中文件名字路徑的第一個分量(patch命令的-p1參數可以完成這個任務)。
為了卸載掉一個以前已經打上的補丁,使用-R參數來打補丁。
??file:///D|/applying-patches.txt(第 1/9 頁)2006-8-15 18:22:12
??file:///D|/applying-patches.txt
于是,如果你使用如下的命令來打補丁:
? ?? ? patch -p1 < ../patch-x.y.z
那么你可以像下面這樣來卸載掉這個補丁:
? ?? ? patch -R -p1 < ../patch-x.y.z
我怎樣把一個patch/diff文件加到一個patch中去?
-------------------------------------------
這個可以通過很多種不同的方法來辦到(像是Linux以及其它的類Unix操作系統一樣)。
在下面所有的例子中,我把這個文件(未壓縮)以下面的語法通過標準輸入加入到patch中:
? ?? ? patch -p1 < path/to/patch-x.y.z
如果你只是想能夠照著下面的例子而并不想知道其它的打補丁的方法的話,那么你就可以
不閱讀這一節余下的內容了。
也可以通過patch的-i參數來獲得文件的名字,就像下面這樣:
? ?? ? patch -p1 -i path/to/patch-x.y.z
如果你的patch文件是使用gzip或者bzip2來壓縮的,那么你在使用之前就不必解壓縮了,你可以
像下面這樣把它加入到patch文件中:
? ?? ? zcat path/to/patch-x.y.z.gz | patch -p1
? ?? ? bzcat path/to/patch-x.y.z.bz2 | patch -p1
如果你想在打補丁之前,手動解壓縮這個patch文件,那么你就可以對這個文件進行gunzip
或者bunzip2操作---就像下面這樣:
? ?? ? gunzip patch-x.y.z.gz
? ?? ? bunzip2 patch-x.y.z.bz2
這個將會給你一個無格式的文本patch-x.y.z文件,這時候你就可以把這個東西以你喜歡的方式通
過標準輸入或者是-i參數來加入到patch中。
一些其它的比較好的參數是-s,這個參數使patch保持無輸出而不是輸出錯誤,這將阻止錯誤在
屏幕上滾動的速度太快。--dry-run參數使得patch命令僅僅打印出來一個將要打的patch的列表
,沒有真正的做任何變動。最后,-verbose告訴patch命令打印出正在進行的工作的更多信息。
打補丁時候的常見錯誤
-------------------
當用patch命令來打一個補丁的時候,它試圖以不同的方法來驗證這個文件的完整性。
檢查這個文件是一個有效的patch文件并且檢查這些被改變周圍的代碼是不是和提供的
??file:///D|/applying-patches.txt(第 2/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
上下文相匹配。這些僅僅是patch所作的兩個最基本的完整性檢查。
如果patch遇到了一些看起來不正確的事情,那么它有兩種選擇。它可以拒絕應用這些改變并且
異常中斷或者它試圖找到一個方法來使patch命令僅僅做一些比較小的改變。
一個patch試圖修正錯誤的例子就是:如果所有的上下文都匹配,被改變的行匹配,但是這些行的
行號不匹配。這是可能發生的,例如,如果patch在一個文件的中間做了一些改變,但是出于一些
原因在文件的開頭處一些行被添加了進來或者被刪除了。在這種情況下,一切看起來都很好,它只
是簡單地上下移動一點,這時候patch通常會修正這些行號并且打上這個補丁。
任何時候,只要patch在打補丁的時候需要改動文件的一些內容,它就會告訴你說:
這個補丁打得有點兒混亂。你應該對這些改變保持一些警惕,因為即使補丁很可能被正確
地打上了,但是情況并不總是這樣,有些情況下結果會是錯誤的。
當patch命令遇到一個變化而不能進行使用一種模糊的方法進行彌補的時候,它就會徹底地
放棄這個動作,并且留下來一個以.rej為擴展名的文件。你可以閱讀這個文件來查看到底是
什么改變不能進行下去,從而在你愿意的情況下來手動修補它。
如果你的內核源代碼上沒有應用任何第三方的補丁,只是一些來自kernel.org的補丁,并且你打這些補丁
的順序是正確的,而且你自己沒有對這些源文件進行改動過,那么你應該就不會看到一個補丁
對這個文件的模糊的改變或者是一些拒絕消息。如果你確實看到了這些消息的話,那么將有非常高的
危險性,這說明或者是你的本地的源代碼書或者是補丁文件在某些方面被玷污了。在這種情況下,你很可能
是應該重新下載這個補丁文件,如果事情仍然還是保持原樣的話,那么我建議你去嘗試從kernel.org上
下載一個完整的新的源代碼樹。
讓我們來看一下補丁可能產生的更多信息。
如果patch命令停下來并且顯示一個“File to patch”的提示符,那么這個時候patch命令找不到
要打補丁的文件。很可能的情況是你忘記指定-p1參數或者你處于一個錯誤的目錄中了。更加不
常見的一種情況是,你會發現一些補丁需要使用-p0參數而不是-p1參數來打補丁(閱讀這個補丁文件
應該能揭示出這些信息--如果是這樣的話,這是一種創建補丁文件的人所犯的錯誤,但是不致命)
如果你得到信息“Hunk #2 succeeded at 1887 with fuzz 2 (offset 7 lines)”,或者是一個類似
的消息,那就意味著patch命令必須調整改變的位置(在這個例子中,它需要在它想打補丁的地方移動7行來
適應這個補丁)。結果得到的文件可能正確也可能不正確,這決定于這個文件與所期望的文件不相同的原因。
這常常發生于你所要打的patch產生于一個另外一個內核版本,這個內核版本和你要打的patch所基于的內核
版本不同。
如果你得到一個類似于“Hunk #3 FAILED at 2387”之類的消息,那么這就意味著不能正確地打上這個
補丁,并且patch程序也不能模糊地通過。這將產生一個導致patch失敗的.rej文件并且產生一個.orig
文件把一些不能改變的原始內容顯示給你。
如果你得到的信息是:“Reversed (or previously applied) patch detected! Assume -R? [n]”,
那么patch檢測到了這個補丁文件中包含的改變已經應用在了目標文件上。如果你確實已經在此之前打了
這個補丁并且重新打補丁遇到了錯誤,那么你可以簡單地選擇[n]o并且終止這次補丁動作。如果你之前
打了補丁并且想得到打補丁以前的版本,但是忘記了指定-R參數,那么你在這里可以回答[y]es來使用patch
file:///D|/applying-patches.txt(第 3/9 頁)2006-8-15 18:22:12
??file:///D|/applying-patches.txt
為你恢復它。這也可能發生在補丁文件的創建者在創建補丁文件的時候倒置了源文件和目標目錄的位置,
在這種情況下從patch中revert實際上是打上了這個補丁。
一個類似于“patch: **** unexpected end of file in patch”或者“patch
unexpectedly ends in middle of line”的消息意味著patch命令對你加入到它之中的
文件覺得沒有意義。或者是你的下載被打斷了,你試圖打上一個沒有壓縮的patch文件,而事前
并沒有解壓縮它,或者是你使用的補丁文件在傳輸的某個地方被一個郵件客戶端或者一個郵件
傳輸代理給損壞了。例如,通過把一個長行分成兩行。通常情況下這些警告可以通過把這兩個
被分開的行合并起來來解決。
就像我上面提到的那樣,如果你打的是從kernel.org得來的補丁到一個正確的版本,
并且你沒有修改過源代碼樹,這些錯誤將從來不會發生。因此如果你從kernel.org來的
補丁上得來了這些錯誤,那么你應該很可能認為或者是你的補丁文件或者是源代碼樹
損壞掉了。我建議你重新開始下載一個完整的內核樹以及你想要打的補丁。
有patch的替代品么?
-----------------
是的,有一些替代品。
你可以使用“interdiff”程序(http://cyberelk.net/tim/patchutils/)來產生一個文件來表示
兩個補丁文件之間之間的不同,然后打上這個文件。這可以使你從一個像2.6.12.2的版本一步
就可以到達版本2.6.12.3。-z標志甚至可以使你送給interdiff一些使用gzip或者bzip2壓縮的
格式文件而不用使用zcat或者bzcat或者手動解壓縮。
下面展示了你可以怎樣一步就可以從2.6.12.2到達2.6.12.3
? ?? ? interdiff -z ../patch-2.6.12.2.bz2 ../patch-2.6.12.3.gz | patch -p1
盡管interdiff可以節省一到兩步,但是我還是建議你通常情況下應該做這些附加的步驟,
這是由于在某些情況下interdiff會把事情弄糟。
另外的一個替代品是“ketchup”,是一個使用python寫的腳本,這個腳本可以自動下載和
打上一些補丁(http://www.selenic.com/ketchup/).
另外一些比較好的工具是diffstat,可以顯示patch所作的所有改變的總結;lsdiff,可以顯示
在一個patch文件中受影響的文件的簡短列表,以及(可選)每一個補丁的行號碼;grepdiff,可
以顯示在補丁包含給定的正則表達式的時候顯示一個被補丁文件修改的文件的列表。
我可以從哪兒下載這些補丁?
-----------------------
??file:///D|/applying-patches.txt(第 4/9 頁)2006-8-15 18:22:12
? ?file:///D|/applying-patches.txt
補丁文件可以從http://kernel.org/來獲得
最近的補丁文件可以從首頁的鏈接中得到,但是他們也有自己的特定的主頁。
2.6.x.y(-穩定)以及2.6.x補丁位于:
??ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
-rc補丁位于:
??ftp://ftp.kernel.org/pub/linux/kernel/v2.6/testing/
-git補丁位于:
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/snapshots/
-mm內核補丁位于:
??ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/
在ftp.kernel.org中,你可以使用ftp.cc.kernel.org,這里cc是一個國家的代碼。這樣你就可以從一個
在地理上離你比較近的位置的鏡像站點下載,從而使你獲得較快的下載速度,全局上更少的帶寬以及
對于kernel.org主服務器的更小的壓力---這是比較好的事情,所以你還是在可能的時候使用這些鏡像
站點。
2.6.x內核
---------
這是Linus發布的基礎穩定版本.發布的最高版本是最新的。
如果發現了沖突或者嚴重的瑕疵,那么在這個基礎上,一個-stable的修正補丁就會被發布
出來(參見下面)。一旦一個新的2.6.x的基礎內核發布出來,就可以得到一個測試版本的補丁
,這個補丁基于先前的2.6.x版本內核和這個新的內核。
為了應用一個從2.6.11到2.6.12的補丁,你最好按照下面來做(注意這些補丁不能應用于2.6.x.y的內核,
而是應用在2.6.x的基礎內核---如果你需要從2.6.x.y到2.6.x+1,那么你首先需要卸載掉2.6.x.y的補丁)
下面是一些例子:
#從2.6.11到2.6.12
$ cd ~/linux-2.6.11? ?? ?? ?? ?? ?? ?? ???# 切換到內核源代碼目錄
$ patch -p1 < ../patch-2.6.12? ?? ?? ?? ?? ?? ?# 應用2.6.12補丁
$ cd ..
$ mv linux-2.6.11 linux-2.6.12? ?? ?? ?? ?? ?? ?# 重命名源代碼目錄
# moving from 2.6.11.1 to 2.6.12
$ cd ~/linux-2.6.11.1? ?? ?? ?? ?? ?? ?? ? # 切換到內核源代碼目錄
$ patch -p1 -R < ../patch-2.6.11.1 # 恢復出來2.6.11.1
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???# 源代碼目錄現在是2.6.11
$ patch -p1 < ../patch-2.6.12? ?? ?? ?? ?? ?? ?# 應用新的2.6.12補丁
? ?file:///D|/applying-patches.txt(第 5/9 頁)2006-8-15 18:22:12
??file:///D|/applying-patches.txt
$ cd ..
$ mv linux-2.6.11.1 linux-2.6.12? ?? ?? ?? ?? ? # 重命名源代碼目錄
2.6.x.y內核
-----------
帶有四位數字版本號的內核是-stable的內核。他們包含了對一個給定的2.6.x內核的一些安全
問題以及發現的重要的退化的修復。
對于那些想要最近的穩定內核并且對于測試開發中的試驗性的版本沒有興趣的
用戶來說,我們推薦這個分支。
如果沒有可用的2.6.x.y內核,那么最高數字的2.6.x內核是目前的穩定內核。
注意:維護穩定內核的團隊通常會做一些增量的補丁,就像是基于最近的主流版本發布
的補丁一樣。但是在下面我僅僅說明了非增量的情況。那些增量式的版本可以在下面的ftp
處找到: ftp://ftp.kernel.org/pub/linux/kernel/v2.6/incr/.
這些補丁不是增量式的,意味著例如對于2.6.12.3補丁不能應用于2.6.12.2的內核源代碼
上去,但是可以應用在2.6.12內核代碼上。
因此,為了為了把2.6.12.3的補丁應用到你使用的2.6.12.2的內核源代碼上,你不得不卸載掉
2.5.12.2補丁(因此你可以得到一個基礎的2.6.12的內核源代碼),并且應用新的2.6.12.3補丁。
下面是一個小例子:
$ cd ~/linux-2.6.12.2? ?? ?? ?? ?? ?? ?? ?# 切換到內核源代碼目錄
$ patch -p1 -R < ../patch-2.6.12.2 # 回歸2.6.12.2補丁
$ patch -p1 < ../patch-2.6.12.3? ?? ?? ?? ?? ? # 應用新的2.6.12.3補丁
$ cd ..
$ mv linux-2.6.12.2 linux-2.6.12.3 # 重新命名內核源代碼目錄
-rc內核
-------
這些是候選的發布內核。當Linus認為目前的git(內核的源代碼管理工具)內核樹處于一個
健全的穩定狀態足以用來測試的時候,而發布的開發內核。
這些內核是不穩定的,如果你試著運行他們應該會想到可能會不時地有問題出現。
但是這是主開發分支上的最穩定的內核,并且最終會變成下一個穩定的內核。因此
讓盡可能多的人來測試它就顯得格外重要。
??file:///D|/applying-patches.txt(第 6/9 頁)2006-8-15 18:22:12
??file:///D|/applying-patches.txt
對于那些想幫忙測試開發中的內核但是又不想跑那些試驗性的東西的人來說,這將是
一個非常好的分支。(這樣的人應該參照下面的關于-git和-mm內核的部分)
-rc補丁是非增量式的,他們應用于2.6.x內核上,就像上面描述的2.6.x.y內核一樣。在-rcN
后綴之前的內核版本號代表了這個-rc的內核最終會變成的內核版本。
因此,2.6.13-rc5意思是這是2.6.13內核的第五個候選的發布版本,并且這個補丁應該打在
2.6.12的內核源代碼上。
下面是3個關于怎樣打這些補丁的例子:
# 首先是一個從2.6.12到2.6.13-rc3的例子
$ cd ~/linux-2.6.12? ?? ?? ?? ?? ?? ?? ? # 切換到2.6.12的源代碼目錄
$ patch -p1 < ../patch-2.6.13-rc3 # 打上2.6.13-rc3的補丁
$ cd ..
$ mv linux-2.6.12 linux-2.6.13-rc3 # 重新命名源代碼目錄
# 現在從2.6.13-rc3遷移到2.6.13-rc5
$ cd ~/linux-2.6.13-rc3? ?? ?? ?? ?? ?? ???# 切換到2.6.12的源代碼目錄
$ patch -p1 -R < ../patch-2.6.13-rc3 # 卸載掉2.6.13-rc3補丁
$ patch -p1 < ../patch-2.6.13-rc5 # 應用新的2.6.13-rc5補丁
$ cd ..
$ mv linux-2.6.13-rc3 linux-2.6.13-rc5 # 重新命名源代碼目錄
# 最后讓我們試著從2.6.12.3到2.6.13-rc5
$ cd ~/linux-2.6.12.3? ?? ?? ?? ?? ?? ?? ?# 切換到內核源代碼目錄
$ patch -p1 -R < ../patch-2.6.12.3 # 回返2.6.12.3補丁
$ patch -p1 < ../patch-2.6.13-rc5 # 應用新的2.6.13-rc5補丁
$ cd ..
$ mv linux-2.6.12.3 linux-2.6.13-rc5 # 重新命名源代碼目錄
-git內核
--------
這些是每天Linus的內核樹的快照(在一個git倉庫中管理著,因此得名)。
這些補丁通常每天都發布而且代表了的Linus的內核樹的當前狀態,由于它們是自動產生的
甚至沒有任何一個光標的騷動來看它們是不是健全的,所以它們比-rc內核更具有試驗性。
-git補丁不是增量的,它們或者是應用在2.6.x內核上或者是應用在一個基礎的
2.6.x-rc內核上---這一點你可以從他們的名字上看出來。一個名字是2.6.12-git1的
補丁應用在2.6.12內核源代碼上,一個名字為2.6.13-rc3-git2的補丁應用在2.6.13-rc3
的內核源代碼上。
??file:///D|/applying-patches.txt(第 7/9 頁)2006-8-15 18:22:12
??file:///D|/applying-patches.txt
這里是一些怎樣打這些補丁的例子:
# 從2.6.12遷移到2.6.12-git1
$ cd ~/linux-2.6.12? ?? ?? ?? ?? ?? ?? ? # 切換到內核源代碼目錄
$ patch -p1 < ../patch-2.6.12-git1 # 應用2.6.12-git1補丁
$ cd ..
$ mv linux-2.6.12 linux-2.6.12-git1 # 重新命名內核源代碼目錄
# 從2.6.12-git1遷移到2.6.13-rc2-git3
$ cd ~/linux-2.6.12-git1? ?? ?? ?? ?? ?? ? # 切換到內核源代碼目錄
$ patch -p1 -R < ../patch-2.6.12-git1 # 回返2.6.12-git1補丁
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 我們現在有了一個2.6.12內核
$ patch -p1 < ../patch-2.6.13-rc2 # 打上2.6.13-rc2補丁
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 內核現在是2.6.13-rc2
$ patch -p1 < ../patch-2.6.13-rc2-git3 # 打上2.6.13-rc2-git3補丁
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 內核現在是2.6.13-rc2-git3
$ cd ..
$ mv linux-2.6.12-git1 linux-2.6.13-rc2-git3 # 重新命名內核源代碼目錄
-mm內核
-------
這是Andrew Morton發布的實驗性的內核
-mm樹作為一個新特性和實驗性的補丁的實驗場。一旦一個補丁在-mm中經過一段時間被證明
有價值,為了使它能包含在主流內核中,Andrew就會把它推給Linus。
盡管鼓勵的方法是通過-mm樹把補丁推給Linus,這個步驟并不是總被實行。子系統的維護者
(或者個人)有些時候直接把補丁推給Linus,盡管(或者之后)它們已經被它并到了-mm中并得
到了測試(或者有些時候并沒有事前在-mm中得到測試)。
通常情況下你應該盡力使你的補丁通過-mm中最大程度測試后再到達主流內核中。
這個分支是一個持續的變化并且包含了一些實驗性的特征,很多正在debug的補丁并不適合于
主流的內核等等。這個分支是這個文檔中描述的最具有試驗性的分支。
這些內核內核不適合于應用在要求穩定的系統上面,并且在運行中比其他任何的分支都可能承擔
更大的風險(確信你有最新的備份---這對于任何實驗性的內核都適用,但是對于-mm更是這樣)。
??file:///D|/applying-patches.txt(第 8/9 頁)2006-8-15 18:22:12
??file:///D|/applying-patches.txt
這些內核除了包含所有的試驗性的補丁以外,它們還包含了在主流-git內核發布的時候任何
可用的改變。
對-mm內核測試會得到極大的賞識,因為這個分支的總的目的就是為了在改變被加到更加穩定的
主流的Linus內核樹之前,消除退化、死機、數據失敗bug、build失敗(以及任何通常意義上的bug)。
但是-mm的測試者應該清醒地認識到這個源代碼樹中的失敗會比其他任何樹中的都要普遍。
-mm內核并不會以一個固定的時間發布,但是通常一些-mm內核會在每一個-rc內核(通常1到3個)
發布的中間。-mm內核或者是應用于一個基礎的2.6.x內核(當還沒有-rc內核發布的時候)或者應用于
一個Linus -rc的內核。
這里有一個打-mm補丁的例子
# 從2.6.12到2.6.12-mm1
$ cd ~/linux-2.6.12? ?? ?? ?? ?? ?? ???# 切換到2.6.12的源文件目錄
$ patch -p1 < ../2.6.12-mm1? ?? ?? ?? ?? ?# 打一個2.6.12-mm1的補丁
$ cd ..
$ mv linux-2.6.12 linux-2.6.12-mm1 # 重新正確命名這個源文件
# 從2.6.12-mm1到2.6.13-rc3-mm3
$ cd ~/linux-2.6.12-mm1
$ patch -p1 -R < ../2.6.12-mm1? ?? ?? ?? ???# 卸載掉2.6.12-mm1補丁
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 現在我們得到了一個2.6.12的源文件
$ patch -p1 < ../patch-2.6.13-rc3 # 打一個2.6.13-rc3的補丁
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 我們現在得到一個2.6.13-rc3的源文件
$ patch -p1 < ../2.6.13-rc3-mm3? ?? ?? ?? ? # 打一個2.6.13-rc3-mm3的補丁
$ cd ..
$ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3 # 重新命名源文件目錄
上面總結了不同內核樹的一些解釋。我希望你已經明白了怎樣打不同的補丁并且對你測
試內核有所幫助。
致謝列表:
Randy Dunlap, Rolf Eike Beer, Linus Torvalds, Bodo Eggert,
Johannes Stezenbach, Grant Coady, Pavel Machek,還有一些人我可能忘記了他們的名字,
但是他們對這篇文檔進行了評論或者貢獻。
轉載于:https://www.cnblogs.com/yinsua/p/3486140.html
總結
以上是生活随笔為你收集整理的怎样为Linux内核打补丁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做爱做的事,做有快感的事
- 下一篇: 高效CSS的一些建议