2010年4月23日 星期五

rpm速記

rpm的基本安裝過程:
RPM(Redhat package Manager)是Redhat系的linux最必須要熟知的套件管理程式,許多非Redhat系的linux也沿用這個管理程式,例如SuSE Linux, Mandirva以及其衍生的PCLinuxOS等。rpm的功能非常完備,比起dpkg管理程式更勝一籌。
rpm的所有動作都會與rpmdb進行互動,也就是透過rpm所安裝的程式都能夠被記錄下來;手動安裝的程式則不在db內,因此也無法享受這方面的便利性。安裝、移除、升級rpm時都會更新rpmdb,但是仍然可以手動更新:

rpm --rebuilddb
rpm檔的命名遵循一定的格式:
Filename-version-release.arch.rpm
例如GConf2-2.14.0-9.el5.i386.rpm,其中的GConf2就是檔案名稱,2.14.0為版本號,9為釋出番號,el5.i386表示這是一個適用於RHEL5 x86平台的rpm檔。一個rpm的安裝會有下列過程:
  1. 檢查數位簽章
  2. 進行相依性檢查
  3. 執行pre script
  4. 複製檔案內容至指定位置
  5. 執行post script

GPG(GNU Private Guard) key數位簽章驗證

GPG key(或稱為signature key)是rpm的發行商應該提供的一個數位簽章(也就是一組公開金鑰)在安裝前rpm會進行檢查。如果rpm檔沒有數位簽章,或是rpmdb沒有紀錄該發行商的公鑰,則rpm數位簽章認證則會出錯:

rpm --checksig http://192.168.2.254/RHEL5/Server/GConf2-2.14.0-9.el5.i386.rpm
http://192.168.2.254/RHEL5/Server/GConf2-2.14.0-9.el5.i386.rpm: 
(SHA1) DSA sha1 md5 (GPG) NOT OK (MISSING KEYS: GPG#37017186)
假設我們想匯入GPG key到系統裡,應該用--import:
rpm --import http://192.168.2.254/RHEL5/RPM-GPG-KEY-redhat-release
我再試一次:
rpm --checksig http://192.168.2.254/RHEL5/Server/GConf2-2.14.0-9.el5.i386.rpm
http://192.168.2.254/RHEL5/Server/GConf2-2.14.0-9.el5.i386.rpm: 
(sha1) dsa sha1 md5 gpg OK
其中,--checksig可以用-K來代替。GPG key的簽章校驗失敗並不會讓安裝無法進行,只是rpm被包裹成類似cpio的格式,沒辦法輕易得知裡面的內容是否被有心人士更動過,因此匯入發行商的公開金鑰進行數位簽章的認證其實是常被忽略但極為重要的一個步驟。

安裝:

rpm -ivh foo.rpm
其中,-i表示install, -v為verbose,-h則是用50個#(hash marks)來顯示進度。如果你對debug rpm感興趣,你還可以用-vv顯示更詳盡的內容。
rpm -i --test foo.rpm
非常有趣的一種方式,利用--test測試安裝,過程並不會真的安裝,而是把-i之後的結果先印給使用者。如果結果符合預期,可以把--test拿掉進行真正的安裝。

升級:

rpm的升級可用兩種方式:

rpm -Uvh foo.rpm
-U表示Upgrade and install的意思。如果系統內已經有舊版本的套件,則會移除後再安裝新版本;如果沒有既有套件,則等同於-i全新安裝;這也是很多人常用-Uvh來安裝rpm的原因。
rpm -Fvh foo.rpm
-F為Freshen之意,意思比upgrade更像upgrade。使用-F,系統內必須已經安裝了較舊或相同版本的套件,她並不會像-U自動升級安裝。
需切記核心的升級要使用-i全新安裝,而不要使用-U/-F。原因是rpm -U會移除舊的kernel並安裝新的,但是我們並無法確定新核心是否有問題,甚至不確定能否正常開機。使用-i進行一個新的安裝,一旦新核心有問題,還可以開回舊核心繼續作業。

重新安裝:

rpm -ivh --replacepkgs foo.rpm
雖然名為replace,但是就是reinstall的意思。適用於相同版本號的套件。
rpm -ivh --replacefiles foo.rpm
如果既有檔案與foo.rpm會安裝到系統的檔案有重複或是套件間有conflict,則會覆蓋掉系統的舊檔案,也就是忽略套件間衝突
rpm -ivh --oldpackage foo.rpm
如果為了讓某些程式可以跑,需要舊一點的套件(最常見的就是舊版的gcc),你可能需要downgrade你的套件。利用--oldpackage指定一個比現有套件還舊的package來安裝。強制安裝一個rpm檔,完全忽略相依性未解決的問題。如果你根本不想理會到底是降級到舊版本或是覆蓋舊檔的問題,你可以用--force代替上面三個範例:
rpm -ivh --force foo.rpm
完全等同於
rpm -ivh --replacefiles --replacepkgs --oldpackage foo.rpm
不過這樣硬幹並非好事,而且還是沒辦法解決相依性的問題。如果你只想忽略相依性而強制安裝,應該用--nodeps:
rpm -ivh --nodeps foo.rpm
如果你是x86_64的機器,可是binaries只有for x86且沒有source code可供編譯,可以試試看安裝不同arch的rpm:
rpm -ivh --ignorearch foo.x86.rpm
如果你的硬碟空間非常有限,系統又跑的是你再熟悉不過的服務跟指令,你可以選擇不裝man pages:
rpm -ivh --excludedocs foo.rpm
如此一來雖然你可以執行一個命令,但是沒有他的man page。

移除:

rpm -e foo
不用接版本號就可以移除(erase)該套件。假設該套件同時安裝了x86及x86_64兩種版本,則只好辛苦一點,指定全名:
rpm -e foo-version-arch

查詢已安裝的rpm檔:

印出套件名稱及版本號:

rpm -q foo
如果要列出系統所安裝『所有』套件,則可用
rpm -qa
來觀察。不過-qa列出的資訊太過龐雜,因此較常見的用法是搭配grep搜尋關鍵字:
rpm -qa | egrep "*samba*"
當然,也可以利用-qa來列出系統已安裝的public key:
rpm -qa gpg-pubkey
如果知道套件名稱,想知道他的詳細訊息(info):
rpm -qi foo
如果想知道系統的某個檔案(file)是由哪個套件提供,可以使用-f:
rpm -qf /etc/passwd
反之,如果你想知道這個rpm究竟裝了哪些東西到你的系統(這恰好是windows最不希望使用者知道的...),可以讓rpm列表(list):
rpm -ql foo
不過,列出的訊息實在太多了,應該可以使用grep撈出有用的資訊,看看有哪些是doc,又有哪些是設定檔;你可以用-qd指查詢docs
rpm -qd foo
或是-qc來查看conf檔:
rpm -qc foo
或是進一步查看套件的相依性:
rpm -q --requires foo
這個指令應該反過來理解:foo套件(或指令)需要哪些套件(或檔案)。例如,python指令需要哪些套件或libs:
rpm -q --requires python
/bin/sh  
/usr/bin/env  
libbz2.so.1  
libc.so.6
...以下略  
相反的,查詢某套件提供了哪些指令或libs,例如,python提供了哪些套件跟libs:
rpm -q --provides python
Distutils  
_bisect.so  
_bsddb.so  
_codecs_cn.so
...中間略  
python = 2.4.3-27.el5
顯示python提供了Distutils套件等,也提供了python自己。
rpm -q --provides foo
跟上面相反:foo套件提供了哪些能力。例如:
rpm -q --provides passwd
config(passwd) = 0.73-1
passwd = 0.73-1
與--provides/--requires類似的兩個options分別是--whatprovides與--whatrequires。
rpm -q --whatprovides python
python-2.4.3-27.el5
rpm -q --whatprovides /etc/passwd
setup-2.5.58-7.el5
被查詢的對象可以是一個檔案,也可以是套件本身。python由python-2.4.3-27.el5提供而來,/etc/passwd則由setup-2.5.58-7.el5而來。
rpm -q --whatrequires bash
info-4.8-14.el5
gpm-1.20.1-74.1
initscripts-8.45.30-2.el5
ypbind-1.19-12.el5
sysklogd-1.4.1-46.el5
vixie-cron-4.1-77.el5_4.1
sendmail-8.13.8-8.el5
squid-2.6.STABLE21-6.el5
vnc-server-4.1.2-14.el5_3.1
bash套件被這些套件所依賴。
rpm -q --whatrequires `which bash`
bash-3.2-24.el5
iproute-2.6.18-11.el5
gpm-1.20.1-74.1
groff-1.18.1.1-11.1
iputils-20020927-46.el5
xorg-x11-filesystem-7.1-2.fc6
crontabs-1.10-8
...族繁不及備載
/bin/bash這個檔案被更多的套件所依賴,不難想像linux就是一個大量shell script架構出來的系統。透過--provides/--whatprovides/--requires/--whatrequires這四個參數就可以把rpm的相依性完全釐清,只是在使用--what參數時總是容易令人混淆。 甚至你也可以檢查這個套件在安裝時的狀態(status):
rpm -qs foo

查詢一個rpm檔:

很幸運的,剛剛我們所列出的options都還可以繼續沿用,要查詢一個rpm檔而不是已經安裝的套件名稱,只需要多加一個-p即可。例如查詢一個rpm的info:

rpm -qpi foo.rpm
想知道這個rpm究竟包含哪些binaries以及libraries:
rpm -qp --provides foo.rpm
以及她需要哪些套件或libs:
rpm -qp --requires foo.rpm
甚至你可以清楚的查看安裝這個rpm的blockquote script以及post script:
rpm -qp --script foo.rpm
在安裝前就先看看這個rpm會裝哪些東西到系統裡:
rpm -qpl foo.rpm
當然還是可以搭配--what,只是別忘了記得加-p

patch檔的查詢:

很多時候我們會下載一個小的patch檔而非一整個全新的rpm,要查看這個rpm patch會更新哪些檔案只需要多一個-P:

rpm -qPpl foo.patch.rpm
有了先前的經驗,我們也可以知道某patch套件更新了哪些檔案:
rpm -qPl foo
當然,你更可以查詢整個系統所有被patch過的檔案有哪些:
rpm -qaP

稽核(Verifying)rpm檔;

稽核rpm檔是比較rpm安裝在檔案系統內的檔案與rpmdb所紀錄的檔案資訊做比較。比對的項目有八項:

  1. file size
  2. 檔案大小是否改變 (S)
  3. file type
  4. 檔案狀態(權限、類型)是否被改變 (M)
  5. MD5 checksum
  6. 以md5sum指令進行計算 (5)
  7. device
  8. 裝置檔是否改變 (D)
  9. linkage
  10. 是否指向另一檔案 (L)
  11. owner
  12. user是否改變 (U)
  13. group
  14. group是否改變 (G)
  15. mtime
  16. 修改時間 (T)
例如,檢查vim套件有哪些檔案被修改過:
rpm -V vim-common
S.5....T  c /etc/vimrc
校驗rpm的結果用上述八個欄位表示,上面的結果表示vimrc在安裝之後大小改變,因此md5 checksum也必定改變,修改時間也改變了。"."表示從未改變。假設這個檔案被移除了,則會顯示missing;如果你是用一般使用者的身份查詢系統檔案,很可能因為權限不足而產生"?"的狀態,請切至root執行rpm -V即可正常檢查。

解開rpm:rpm2cpio

rpm2cpio能解一個rpm檔導入cpio解開成檔案。利用上面所學檢查系統是否有rpm2cpio這個程式:

rpm -qf `which rpm2cpio`
可見這個指令就是包含在rpm套件裡面。
rpm2cpio foo.rpm | cpio -idmv
其中,-i表示解開一個cpio檔,-d建立目錄樹(man pages上說cpio只會解檔案不解目錄,但我測試結果,加不加-d是相同效果),-m使還原後能保留mtime,-v為詳細輸出。
如果只是要查看rpm內容,可以不需要輸出:
rpm2cpio foo.rpm | cpio -vt

參考文獻:
1. Redhat Linux網路及系統管理指南(學貫),第26章
2. 鳥哥的私房菜第23章
3. How To Extract an RPM Package Without Installing It.

沒有留言: