在linux世界裡流行兩種包管理方式,分別是redhat系的rpm和debian系的deb。其中rpm的使用更為廣泛,我打算接下來分多章詳細介紹一下rpm的包管理機制。
包管理是作業系統用來維護各組件版本的一種方式,對於軟體發行者來說,將自己的程式製作成標準的rpm格式也會使得程式的安裝、升級和卸載變得非常容易。因此linux下幾乎所有流行的程式都有rpm格式的包,有些是發行者自己打包,也有些第三方提供rpm包,例如redhat發行版裡的rpm都是redhat自己打包,他們定期打patch,升級並且維護包之間的依賴關係,他們製作的rpm包是最可以信任的。除此之外,http://dag.wieers.com/rpm/這個網站也提供很多較新的rpm包,在redhat官方找不到的包很多在這裡都可以找到。
在網上搜尋rpm包最常用的方式是通過rpmfind.net進行搜尋,它會提供各個發行版下的各個版本的包下載。注意一定要找到正確的發行版下對應的包,由於依賴底層庫和庫版本的不同,不同版本的發行版的包最好不要混裝。
今天先介紹rpm的安裝,基本的安裝命令如下
rpm -ivh xxxxxxx.rpm
i代表安裝,e代表卸載,v代表顯示安裝過程,h代表顯示#號樣式的進度
下面看一個簡單的例子
[leconte@localhost soft]$ sudo rpm -ivh enca-1.9-4.el5.rf.i386.rpmwarning: enca-1.9-4.el5.rf.i386.rpm: Header V3 DSA signature: NOKEY, key ID 6b8d79e6Preparing... ########################################### [100%] 1:enca ########################################### [100%]
rpm包這樣就裝上了,但是很多時候沒有這麼順利,由於rpm包之間可能存在依賴關係,在依賴關係無法滿足的情況下預設是沒法繼續安裝的;再比如某個包已經安裝過,如果想再裝一次,也是無法繼續的。這種情況下可以通過一些參數來強制執行,但是強制執行的後果可能是裝的程式無法正常使用,因為它依賴的包你系統並沒有提供。
安裝時常用的參數如下:
--test 測試安裝,並不真實安裝而僅僅是測試能否安裝。
--nodeps 忽略依賴關係強行安裝
--force 強制替換現有版本
--noscripts 僅安裝檔案不執行附加指令碼
下面示範一個強行安裝的例子
[leconte@localhost soft]$ sudo rpm -ivh awstats-6.9-1.noarch.rpmerror: Failed dependencies: perl(LWP::UserAgent) is needed by awstats-6.9-1.noarch[leconte@localhost soft]$ sudo rpm -ivh awstats-6.9-1.noarch.rpm --nodepsPreparing... ########################################### [100%] 1:awstats ########################################### [100%]
awstats依賴的PERL模組LWP::UserAgent並沒有裝,因此預設是無法安裝的,但是通過nodeps可以強制安裝,而LWP::UserAgent可以通過cpan去後續安裝。也就是說,如果你明白你在做什麼,那麼強制安裝並不可怕。
需要注意的是,rpm包的安裝和卸載都需要在系統的rpm資料庫裡儲存資訊,因此需要root許可權。
本節接著介紹rpm的查詢功能,查詢是我們最常用的功能,例如查詢一個包裡包含哪些檔案、一個檔案屬於哪個包、以及包之間的依賴關係等等。
rpm的-q參數是用來進行查詢的,需要明確的是rpm既可以對安裝在系統上的包進行查詢,也可以對一個未安裝的rpm包進行查詢。當一個rpm包安裝到系統上之後,安裝資訊通常會儲存在本地的/var/lib/rpm/目錄下,資料會以berkeley DB的方式儲存。查看/var/lib/rpm/Packages檔案的類型可以驗證這一點。
[leconte@localhost rpm]$ file /var/lib/rpm/Packages/var/lib/rpm/Packages: Berkeley DB (Hash, version 8, native byte-order)
這種情況下的查詢其實就是對bdb的讀訪問。而對一個未安裝的rpm包進行查詢,則是通過解讀rpm包本身而擷取資訊,這一點是首先需要明確的。
下面我就簡單羅列一下rpm最常用的幾個查詢功能
1.rpm -qa 用來查詢系統安裝的所有包,a代表all
2.rpm -ql [包名] 用來查詢某個包裡的檔案清單,例如查詢包passwd裡包含的內容
[leconte@localhost rpm]$ rpm -ql passwd/etc/pam.d/passwd/usr/bin/passwd/usr/share/man/man1/passwd.1.gz
3.rpm -qi [包名] 用來查詢包資訊,其中包含包的介紹,作者,打包日期等重要訊息。
4.rpm -qf [檔案名稱] 用來查詢一個檔案所屬的rpm包,例如:
[leconte@localhost rpm]$ rpm -qf /etc/passwdsetup-2.5.58-4.el5
系統設定檔/etc/passwd是屬於setup這個包的。
5.rpm -qV [包名] 用來驗證某個包中安裝的各檔案的狀態,如果當前檔案的大小、md5和安裝時資料庫裡儲存的資訊不一致,該命令則會將不一致的檔案列出來。該命令對於系統出問題的情況下的故障排查很有協助。
上面是幾個最常用的查詢命令,都是針對查詢系統rpm包情況的。如果要查詢未安裝的rpm包則只需要加上p參數和包路徑即可。例如查詢包perl-Git-1.5.5.6-4.el5.i386.rpm的資訊:
[leconte@localhost soft]$ rpm -qip perl-Git-1.5.5.6-4.el5.i386.rpmwarning: perl-Git-1.5.5.6-4.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 217521f6Name : perl-Git Relocations: (not relocatable)Version : 1.5.5.6 Vendor: Fedora ProjectRelease : 4.el5 Build Date: 2009年06月19日 星期五 21時28分05秒Install Date: (not installed) Build Host: xenbuilder2.fedora.redhat.comGroup : Development/Libraries Source RPM: git-1.5.5.6-4.el5.src.rpmSize : 24878 License: GPLSignature : DSA/SHA1, 2009年06月20日 星期六 04時07分18秒, Key ID 119cc036217521f6Packager : Fedora ProjectURL : http://kernel.org/pub/software/scm/git/Summary : Perl interface to GitDescription :Perl interface to Git.
rpm包之間會維持依賴關係,這是包管理系統的特色。我們都經曆過安裝一個包而因為依賴缺失而裝不上的情況。後來yum的出現能一定程度解決這個問題,但我們仍然有必要瞭解rpm依賴關係背後的細節。
自己打過rpm包的人都知道,在包的spec設定檔往往要明確寫出此包所依賴的包名或檔案名稱,同時也可能需要明確寫出此包所提供的內容。這個內容可能是動態庫也可能是其他一些名字,並不一定是檔案名稱。各個包之間正是依靠這些內容來建立依賴關係的,每個包都提供一些內容同時依賴一些別的內容,整個系統就在這樣一種相互依賴中形成了。
在看具體的例子之前先介紹幾個指令:
rpm -qR [包名] 可以用來查詢指定包所依賴的內容
rpm -q –provides [包名] 可以用來查詢指定包所提供的內容
rpm -q –whatprovides [內容] 可以用來查詢哪個包提供了指定內容
rpm -q –whatrequires [內容] 可以用來查看哪些包依賴於指定內容
例如我們以time這個包為例進行查詢,結果如下:
[leconte@localhost soft]$ rpm -qR time/bin/sh/bin/sh/sbin/install-infolibc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)libc.so.6(GLIBC_2.3.4)rpmlib(CompressedFileNames) <= 3.0.4-1rpmlib(PayloadFilesHavePrefix) <= 4.0-1rtld(GNU_HASH)
可見,time這個包如果要安裝,上述內容必須已經存在,否則將會提示依賴缺失而無法安裝。我們以列表中的/bin/sh為例進行反查,可以看到系統中哪個包提供了/bin/sh
[leconte@localhost soft]$ rpm -q --whatprovides "/bin/sh"bash-3.2-24.el5
很明顯,bash這個包提供了/bin/sh,正是由於bash的安裝才滿足了time的安裝需求。
time依賴於bash等包,同時它也提供了一些內容,有可能被別的包依賴:
[leconte@localhost soft]$ rpm -q --provides timetime = 1.7-27.2.2[leconte@localhost soft]$ rpm -q --whatrequires 'time'no package requires time
不幸的是系統中並沒有包依賴於time,因為它本身屬於較上層的包。
對於一些底層內容就會有很多包依賴它,例如之前碰到的/bin/sh:
[leconte@localhost soft]$ rpm -q --whatrequires '/bin/sh'bash-3.2-24.el5bash-3.2-24.el5info-4.8-14.el5ncurses-5.5-24.20060715libxml2-2.6.26-2.1.2.7readline-5.1-1.1......................省略n行
由於篇幅所限就不全列舉出來了,這種依賴關係應該可以一目瞭然了。
和上節類似,rpm -qR和rpm -q –provides這兩個查詢指令同樣可以加上-p參數應用到一個未安裝的rpm包,例如
[leconte@localhost soft]$ rpm -qp --provides enca-1.9-4.el5.rf.i386.rpmwarning: enca-1.9-4.el5.rf.i386.rpm: Header V3 DSA signature: NOKEY, key ID 6b8d79e6libenca.so.0enca = 1.9-4.el5.rf
可以看到,enca這個rpm包提供了動態庫libenca.so.0和enca本身。
通過使用本節這四條依賴關係查詢指令基本可以瞭解到系統上眾多rpm包之間的耦合關係,明確了這一點,我們對rpm的理解也就更深了一步。
介紹完了rpm包的安裝和查詢,本節接著來介紹rpm包的卸載和升級,這樣以來rpm包的“增刪改查”就都涉及到了。
rpm包的卸載和升級的指令如下:
rpm -e [包名] 用來卸載一個rpm包
rpm -U [包檔案] 用來升級一個現有的rpm
需要注意的是,如果要卸載的rpm包中的內容被別的rpm包依賴,那麼則無法卸載,例如
[leconte@localhost ~]$ rpm -e php-commonerror: Failed dependencies: php-common = 5.2.9-4 is needed by (installed) php-pdo-5.2.9-4.i386 php-common = 5.2.9-4 is needed by (installed) php-bcmath-5.2.9-4.i386 php-common = 5.2.9-4 is needed by (installed) php-curl-5.2.9-4.i386 php-common = 5.2.9-4 is needed by (installed) php-dba-5.2.9-4.i386
php-common由於被 php-pdo等包依賴而無法單獨卸載,php-pdo和php-common可以利用上節介紹過的依賴關係查詢指令查到:
[leconte@localhost ~]$ rpm -qR php-pdoconfig(php-pdo) = 5.2.9-4libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1.3)libc.so.6(GLIBC_2.3)libc.so.6(GLIBC_2.4)librt.so.1libsqlite3.so.0php-common = 5.2.9-4..............[leconte@localhost ~]$ rpm -q --whatrequires php-commonphp-pdo-5.2.9-4php-bcmath-5.2.9-4php-curl-5.2.9-4php-dba-5.2.9-4php-gd-5.2.9-4...............
這種情況下想要卸載php-common,只能將它依賴的所有包全部卸載掉。更暴力的方式是指定-nodeps忽略依賴關係限制,但是這樣造成的後果就是php-pdo等包將無法正常使用,因此這種方式一般不推薦。
rpm包的升級指的是rpm包的版本升級,這種情況下實際內部執行的動作分兩步,即先安裝新版本然後卸載老版本。此外,rpm也可以進行包的降級,只需要指定–oldpackages參數即可。
值得注意的是在卸載和升級的過程中, 包中的設定檔會被妥善處理,rpm會根據一系列規則決定設定檔是否保留,即使被替換,舊的設定檔也會被重新命名後儲存起來,你之前對設定檔做過的修改不會因為rpm包的升級而丟失。