升級做什麼
RPM的升級功能是它受到用戶好評的原因之一。因為用戶自己將一個軟件包從舊版本升級到新版本,特別是大型軟件,需要有經驗的支持和技術的積累,比較復雜,而用RPM升級軟件,只需一個rpm -U命令就可以了,極大方便了用戶。
軟件升級基本做兩項工作,一是安裝新版本,二是卸載舊版本。RPM還有一項重要的工作要做,這就是妥善處理配置文件(CONFIG FILE)。若直接采用安裝方式,則用戶已配置好的配置文件就會被覆蓋,不符合用戶要求。
配置文件處理
RPM對某個配置文件,通過比較三種不同的MD5檢查和(checksum)來決定如何處理它。這三種不同的MD5檢查和是:
1. 原檢查和。它是舊版本軟件包安裝時配置文件的MD5檢查和。
2. 當前檢查和。它是升級時舊版本配置文件的MD5檢查和。
3. 新檢查和。它是新版本軟件包中配置文件的MD5檢查和。
RPM針對以下幾種情況分別處理:
1. 當原檢查和=X,當前檢查和=X,新檢查和=X時:
這表明配置文件未曾修改過。此時,RPM會將新的配置文件覆蓋掉原文件,而不是對原文件不作處理,原因在於: 雖然文件名和文件內容都沒有變化,但文件別的方面的屬性(如文件的屬主,屬組,權限等)卻可能改變,所以有必要覆蓋一下。
2. 當原檢查和=X,當前檢查和=X,新檢查和=Y時:
這表明原配置文件沒有改動過,但是它與新軟件包中的配置文件卻有所不同。這種情況下,RPM將用新文件覆蓋掉舊文件,並且舊文件不作保存(因為它不曾改動過,沒有必要保存)。
3. 當原檢查和=X,當前檢查和=Y,新檢查和=X時:
這表明新文件與舊文件內容相同,但當前文件已經作過修改,這些修改對於新版本來說應該是合法的,可以使用的。因此,RPM對當前文件予以保留。
4. 當原檢查和=X,當前檢查和=Y,新檢查和=Y時:
這表明原文件經過修改,現在已與新文件相同,這或許是用戶用來修補安全上的漏洞,新版本也作了同樣的修改。這種情況下,RPM將新文件覆蓋當前文件,避免文件屬性方面的不同。
5. 當原檢查和=X,當前檢查和=Y,新檢查和=Z時:
這表明用戶已修改了原文件,並且當前內容與新文件內容不同。這種情況下,RPM無法保證新版本軟件能正常使用當前的配置文件,所以采用了一個比較明智的辦法,既能保護用戶的配置數據,又能保證新版本軟件正常。這種作法就是將當前文件換名保存(給原文件名加個.rpmsave的後綴,如原文件名為ABC,則換名後為ABC.rpmsave),同時安裝新文件,並給出警告信息,如:
warning: /etc/.funkey saved as /etc/.funkey.rpmsave
6. 當沒有原檢查和時:
此種情況下,當前檢查和與新檢查和已無關緊要,這表明沒有安裝過此配置文件。因為沒有安裝過此配置文件,所以RPM無法判斷當前文件是否被用戶修改過。這種情況下,RPM會將當前文件換名保存(原文件名後綴不是加個.rpmsave,而是.rpmorig),同時安裝新文件,並給出警告信息,如:
warning: /etc/.inputdef saved as /etc/.inputdef.rpmsave
升級命令格式
升級RPM包時,請用以下命令格式:
rpm -U [升級選項1 升級選項2...] [軟件包標識1 軟件包標識2...]
其中: 也可使用--upgrade代替-U,效果相同。
軟件包標識
有關軟件包標識的定義,請參見<<精通RPM之三--卸載篇>>。
選項列表
選項說明
因為升級也是一種安裝,所以升級的選項列表與安裝選項列表基本相同,只是升級的選項列表增加了一項--oldpackage。現著重說明一下這個選項,其它選項說明見<<精通RPM之二--安裝篇>>,在此恕不贅述。
--oldpackage選項: 從名字上就可以看出來是老版本軟件包的意思。為什麼要將軟件"升級"到老版本?(這裡的升級其實是降級)這裡面有個原因。用戶一直好好地用著老版本的軟件,當有一天發現有新版本發布時,馬上用rpm -U命令升級到系統中,但因為新版本有"臭蟲",所以這個軟件暫時不能正常工作。而這時,直接用rpm -U命令是升級不到老版本的,因為一般情況的升級是將老版本升級到新版本,RPM默認這一點。若想升級到老版本,則必須用這個特殊的選項。下面舉個例子:
# rpm -U -v lze-6.0-1.i386.rpm
package lze-7.0-1 (which is newer then lze-6.0-1) is already installed
#
注: 本例在升級過程中出現錯誤,RPM提示lze軟件包已安裝,並且現存版本號7.0,高於准備升級的版本號6.0,升級無法繼續。
若在命令行使用--oldpackage,結果會怎麼樣呢?
# rpm -U -v --oldpackage lze-6.0-1.i386.rpm
lze-6.0-1
#
注: 命令執行後輸出了軟件包標識lze-6.0-1,表明升級到老版本成功了。
下面通過輸出調試信息來觀察一下升級軟件包時RPM做的主要工作:
# rpm -U -vv --oldpackage foo-3.0-2.i386.rpm 2>&1 nl
1 D: counting packages to install
2 D: found 1 packages
3 D: looking for packages to download
4 D: retrieved 0 packages
5 D: New Header signature
6 D: Signature size: 68
7 D: Signature pad : 4
8 D: sigsize : 72
9 D: Header + Archive: 1577
10 D: eXPected size : 1577
11 D: opening database mode 0x42 in //var/lib/rpm/
12 D: found 0 source and 1 binary packages
13 D: requires: /bin/sh satisfied by db file lists.
14 D: installing binary packages
15 D: getting list of mounted filesystems
16 D: New Header signature
17 D: Signature size: 68
18 D: Signature pad : 4
19 D: sigsize : 72
20 D: Header + Archive: 1577
21 D: expected size : 1577
22 D: package: foo-3.0-2 files test = 0
23 D:file: /etc/foo.conf action: create
24 D:file: /usr/bin/foo action: create
25 D: running preinstall script (if any)
26 + echo preinstall
27 preinstall
28 foo-3.0-2
29 D: running postinstall scripts (if any)
30 + echo postinstall
31 postinstall
32 + echo triggerinstall
33 triggerinstall
34 + echo triggeruninstall
35 triggeruninstall
36 + echo preuninstall
37 preuninstall
38 D: will remove files test = 0
39 D:file: /usr/bin/foo action: skip
40 D:file: /etc/foo.conf action: skip
41 D: running postuninstall script (if any)
42 + echo postuninstall
43 postuninstall
44 D: removing database entry
45 D: removing name index
46 D: removing group index
47 D: removing requiredby index for /bin/sh
48 D: removing trigger index for file
49 D: removing trigger index for file
50 D: removing trigger index for file
51 D: removing file index for foo.conf
52 D: removing file index for foo
注: 第1-4行: 計算命令行上要升級的包數,並且下載那些需要下載的包裹文件;
第5-10行: 根據包裹文件頭部信息,確定軟件占用空間;
第11,12行: 打開RPM數據庫及包裹文件;
第13行: 檢查依賴是否滿足,本例滿足;
第14行: 安裝執行程序包;
第15行: 取當前已安裝文件系統列表;
第16-21行: 再度檢查包裹頭信息,確定占用系統空間;
第22-24行: 確定包中各個文件的執行操作(action),均為建立(create);
第25行: 執行安裝前腳本程序(如果有的話);
第26-27行: 以+開頭的為腳本程序執行的命令,其後為其輸出結果;
第28行: 安裝foo-3.0-2包;
第29行: 執行安裝後腳本程序(如果有的話);
第30-31行: 以+開頭的為腳本程序執行的命令,其它為執行結果;
第32-33行: 執行安裝時觸發腳本程序;
第34-35行: 執行卸載前觸發腳本程序,自此開始卸載原軟件包;
第36-37行: 執行卸載前腳本程序;
第38-40行: 確定原包中各文件的執行操作,本例均為跳過(skip),即不作處理;
第41-43行: 執行卸載後腳本程序;
第44-52行: 刪除原包在RPM數據庫中的所有信息(數據及索引)。
第5-10行: 根據包裹文件頭部信息,確定軟件占用空間;
第11,12行: 打開RPM數據庫及包裹文件;
第13行: 檢查依賴是否滿足,本例滿足;
第14行: 安裝執行程序包;
第15行: 取當前已安裝文件系統列表;
第16-21行: 再度檢查包裹頭信息,確定占用系統空間;
第22-24行: 確定包中各個文件的執行操作(action),均為建立(create);
第25行: 執行安裝前腳本程序(如果有的話);
第26-27行: 以+開頭的為腳本程序執行的命令,其後為其輸出結果;
第28行: 安裝foo-3.0-2包;
第29行: 執行安裝後腳本程序(如果有的話);
第30-31行: 以+開頭的為腳本程序執行的命令,其它為執行結果;
第32-33行: 執行安裝時觸發腳本程序;
第34-35行: 執行卸載前觸發腳本程序,自此開始卸載原軟件包;
第36-37行: 執行卸載前腳本程序;
第38-40行: 確定原包中各文件的執行操作,本例均為跳過(skip),即不作處理;
第41-43行: 執行卸載後腳本程序;
第44-52行: 刪除原包在RPM數據庫中的所有信息(數據及索引)。