在 Linux 的世界裡, RPM 指的就是 Red Hat Package Manager, 我們稱之為「包裝檔案管理程式」。 一套良好的管理程式, 能夠成為程式寫作人員與一般使用人員之間的工具橋樑, 有助於 Linux 應用環境的推廣, RPM 能廣被業界與一般使用者接受, 其來有自。 本文的用意, 是希望介紹 RPM 系統內部運作的入門資訊, 有心成為 Linux 玩家者, 應能有所收獲。
令人感到有趣的是, 究竟是什麼關鍵性因素, 促使 Slackware Linux 將散佈套件的市場主導權拱手讓人? 我個人認為 RPM 應該是相當重要的因素之一, 僅管商業套件種類眾多, 但目前大抵是以 RPM 為基礎者, 執市場牛耳, 這樣的現象能說只是個巧合嗎?
我個人是從 Slackware Linux 入門, 自學過程中, 遇到許多不容易解決的問題, 多數與系統函式庫相關。 由於查詢資源不足, 加上對於程式編譯環境還不夠熟悉, 常常只好「望機興嘆」。
是的, 總是會遇到問題, 那時候想要在 Slackware Linux 環境成功編譯一些冷門軟體, 通常需要事先準備好函式庫。 雖然軟體說明檔裡會告訴你該準備好哪些函式庫, 但是說明文件很可能因為過於簡略, 甚至內含過時、錯誤的資訊, 導致整個編譯過程猶如摸石過河, 充滿黑魔術般的驚奇! 面對一串函式庫相依關係連環套, 你若不是得花時間逐一破解、過關斬將, 就是得碰運氣求助於「大師們」(guru)的經驗。 如果你能把這些過程當成修練或遊戲, 那麼倒也樂在其中, 不過, 閉門獨修成師的人總是辛苦, 況且修練也未必僅有此途。
軟體編譯不成功的困擾, 直到我仔細接觸 Red Hat Linux 之後才大獲舒解。 除了因為安裝上所帶來「隨裝即用」的便利外, 前人的心血成果, 諸如設定檔範例、文件資料等, 有機會可以有效地傳承累積, 也是居功厥偉。 將程式寫作、文件寫作、訊息翻譯、檔案包裝、軟體測試, 這些軟體製作流程予以分工, 才容易有機會讓軟體的發展演化加速。
CLE (Chinese Linux Exetension) 當初也是利用 RPM 所帶來的便利性, 為 Red Hat Linux 直接引入中文應用程式及相關修改設定。使得安裝、 設定、使用、修改、重新包裝,也就是整個散佈套件的改進流程加速, 直接造福更多使用者及程式人員。我相信許多以 RPM 為基礎的散佈套件 ,其背後的重要改進力量也在此。
從系統管理員的角度來看,有個統一方式的管理介面, 對於簡化日常工作也有幫助。以 /etc/rc.d/init.d/ 目錄下的系統管理 命令稿為例,常見的伺服程式由 tar ball 製作成 rpm 的過程中, 可以把適用的命令稿檔案也整理進去,讓系統管理員能夠輕易地管控新程式。
為了管理檔案的安裝與移除, 以及各式檔案之間的相依關係 (dependency), 通常包裝系統都會存在一個小型資料庫, 集中管理所有的包裝檔案訊息。 所謂的相依關係, 舉例來說, MS Windows 使用者在安裝特定應用程式時, 遇到需要 Direct X 版本跟著昇級, 就是一個類似的「相依關係滿足」情況。 某一個軟體的正常運作, 需要另一個軟體事先成功安裝, 它們兩者之間就有個相依關係, 而且, 這還包括「軟體之間適當的版本搭配」, 例如「python >= 1.3」這樣的資訊。 隨著在 Linux 環境上開發的應用軟體越來越多, 上述的相依關係肯定會是個越來越複雜而重要的議題。
如果你的 Linux 主機裡頭, 有個運作正常的包裝檔案管理系統, 那麼就可以回答或解決類似下列的問題:
通常這些都是 Linux 初學者有意進階時, 經常會遇到的問題。 從技術層面來看, 答案都是肯定的, 而且, 我樂見同好們一起動手做。 「自己動手做」, 幾乎所有的快樂與痛苦都由此開始, 我寧願相信讀者是為了獲得快樂而來。 不過, 在上路之前, 必須假設讀者已經擁有足夠的先備知識, 它們將是過關斬將時的隨身武器, 要是缺了下列任何一項, 很抱歉, 請務必補齊:
另外,或許有人專精 Perl、Python、Tk/Tcl、Java 之類的語言,這原本也 是好事,特別是在製作這類與「另類語言」相關的包裝檔案時,您應該會 倍感親切 (例如 Perl 程式的編譯流程,通常是 perl Makefile.PL、make、 make install)。不過,再次強調,shell script 是多數包裝檔案管理系統 的基本語言。而 C 則是其常態語言,像 Perl、Python、Tk/Tcl、Java 雖然 也能解決幾乎所有問題,但目前還未全面被應用在系統底層。而且,別小看 grep、sed、awk 這些小型工具,它們與 bash 搭配的威力,應該可以滿足 所有包裝檔案製作時的需要。
取得 RPM 最好的方法,就是安裝 Red Hat Linux,或是任何一個使用 RPM 為 系統基礎的散佈套件。如果你不想要這麼做的話,當然還是可以取得及使用 RPM。請自 ftp://ftp.rpm.org/pub/rpm/dist/ 這個位置取得程式源碼。若是 要從源碼來建立 RPM (例如使用 Slackware Linux 或是 FreeBSD 的朋友), 你還必須準備如 C compiler、make 等編譯環境必備的工具。
最新版的 RPM 系統目前是 4.0.x,不過,一般使用者手邊應該還是可以經常 遇到 3.0.x 的環境。在此我們將僅先討論 3.0.x 環境下的情況,針對 4.0.x 與 3.0.x 不同之處所造成的差異,將盡量予以避免。
在 RPM 的文件方面,網路上已有不少,而且目前也有專書解說,列舉如下:
一篇概況式的中文介紹,不過資料本身已呈老舊,而且本身實用性並不高。
這是在下兩年半前所寫的一篇中文簡介文件,應該還是有些入門參考價值。
這是一本 RPM 專書的內容,由 SAMS 所出版,市面上可以購得。作者 Edward C. Bailey 除了在網站上提供 Postscript 檔案讓讀者下載列印,還有 LaTeX 格式 檔案,實在是太酷了。可惜的是,部份內容已與 4.0.x 版 RPM 有所出入,但 整體來說,絕對還是現存最好的資料管道。
RPM 文件計畫,意圖為 RPM 整理出最新最完整的資訊,且讓我們拭目以待。
RPM 計畫主網站,資訊集中站。
這裡是其中的一個通信論壇資料記錄,最新的 RPM 程式發展,應該考慮在通信 論壇上取得。
包裝檔案的名稱, 通常會盡可能清楚描述檔案本身的功能, 例如 python-devel 指的是 Python 語言的程式開發函式檔案組, python-docs 指的是額外包裝的文件資料。 當然, 任何時候還是可以直接以 rpm -qi pythonlib 這類的指令語法, 取得詳細的包裝檔案資訊。 市面上已經有不少 Linux 入門的書籍, 針對 RPM 於安裝檔案的功能進行解說, 在此我們介紹幾個簡單而重要的命令列指令, 並深入淺出地帶領讀者認識整個 RPM 牽涉及影響的部份。 簡單地看, rpm 程式提供四大基本功能:
example$ rpm -qa | grep -i gtk-qa 表示 query all 之意,經由輸出結果轉給 grep 過濾,最後留下的結果, 有助於讓你初步了解系統裡安裝了哪些與 gtk 相關的包裝檔案。而下列的範例 則可能是更詳細的查詢結果:
example$ rpm -qa --queryformat '%25{NAME} %30{GROUP}\n' | grep -i gtk利用 --queryformat 可以客製化自己需要的查詢格式,我們把想要查詢的線索 擴大至 GROUP 的資訊當中。諸如 %{NAME}、%{GROUP}、%{VERSION} 都是查詢 的標籤範例。
example$ rpm -qf `which startx`-f 可以用來查詢特定檔案所屬的包裝檔案,語法上是接一個檔案名稱,這裡 我們利用「反括號」(`) 的 shell 技巧,先讓 `which startx` 產生 /usr/ X11R6/bin/startx 的輸出結果,再餵給 -qf 參數,善用此技巧,可以省掉 一些打字與尋找檔案的時間。
example$ rpm -q --provides gtk+ example$ rpm -q --provides netscape-navigator--provides 選項可以用來查詢某個包裝檔案所提供的「虛擬包裝名稱」 (virtual package)。例如 gtk+ 提供了 libgdk-1.2.so.0 及 libgtk- 1.2.so.0 這兩個虛擬包裝名稱,在此例中,即是所謂的動態連結函式庫 名稱。而 netscape-navigator 提供的是 webclient、netscape 等虛擬 包裝名稱,如果你查詢 lynx 的話,也會發現它同樣有提供 webclient 虛擬包裝名稱。如果有某個包裝檔案需要相依於 webclient 的話 (例如 urlview),那麼必須至少有一個以上的包裝檔案提供該虛擬包裝名稱, 才能把相依關係滿足。和 --provide 相對的是 --requires 選項,進階 的操作可以類似下列例子:
example$ rpm -q --whatrequires libgtk-1.2.so.0可以查詢出有哪些包裝檔案需要滿足 libgtk-1.2.so.0 的相依關係。
example$ rpm -qip apache-1.3.12-2.i386.rpm這是許多新手容易搞混的地方,-q 所接之查詢參數,通常是 software's name 或是 package label,所以 rpm -q apache-1.3.12-2.i386.rpm 會 出現「package apache-1.3.12-2.i386.rpm is not installed」的錯誤 訊息。想要查詢類似 .i386.rpm 或 .src.rpm 這樣的包裝檔案,記得要 使用 -p 選項。
example$ rpm -ivvh --test \ ftp://linux.sinica.edu.tw/CLE/0.9p1/i386/CLE/RPMS/jmce-0.37-1.i386.rpm
-v 是報告 RPM 「內部運作」詳細資訊 (verbose) 的意思,在 rpm 指令 選項中,幾乎可以隨時任意搭配使用,譬如,此處的兩個 v 就表示「更加 詳細地」顯示資訊。最後,我們指定 --test 選項,表示只打算測試安裝 的狀況,而非真正執行安裝動作。
圖(rpm-i-test.bmp):可以透過FTP模式直接上網安裝包裝檔案
安裝包裝檔案時,可能會遇到「衝突」(conflict) 的情況,例如你想替 系統安裝一套 postfix 郵件伺服程式,卻忘了留意原本留在系統裡的 sendmail 郵件程式,此時 RPM 便會通告發生衝突狀況。由於 sendmail 與 postfix 都提供 smtpdaemon 這個虛擬包裝檔案名稱,在沒有適當做好 設定之前,這樣的衝突狀況會導致安裝或執行的失敗。
圖(rpm-conflict.bmp):RPM偵測到衝突狀況發生
昇級則是以 -U 為指令參數前導子,和「安裝」的差別在於:它會先將 準備要裝進系統的包裝檔案安裝好,然後再執行移除舊版包裝檔案的動作。
想要聰明地讓系統順利昇級, 其實裡頭牽涉到不少複雜的細節, 特別是當你要觸及系統核心及函式庫部份, 或是你已經更動了許多系統裡的設定檔內容。 RPM 採用 MD5 checksum 的檢查機制, 包裝檔案裡若含有設定檔案 (config files), 則在第一次安裝時會記錄其 MD5 值, 日後用以比對設定檔的內容是否已被更動。
假設原始設定檔案的 MD5 值為 X, 而現存設定檔案的 MD5 值為 Y, 如果準備要昇級的包裝檔案裡, 所含的設定檔案 MD5 值為 Z, 則意謂「設定檔案內容已被更動」, 而且「很可能新的設定檔裡已加入新的特色功能」。 此時昇級過程中, RPM 會印出警告訊息, 說明該設定檔已被更名, 通常是檔案後面加上 .rpmsave 之副檔名。
example$ rpm -e --nodeps python由於在真正執行移除動作之前, RPM 會進行相依關係的確認檢查, 如果準備要移除的包裝檔案與其他檔案「緊密糾纏」, 那麼在移除之前請你最好三思再行。 特別是和系統核心或函式庫相關的項目, 若是一場災難於焉發生, 屆時可就呼天不應了。 原則上, 越是屬於系統底層的包裝檔案, 它的相依關係越是複雜, 道理不難體會, 你可以想像整個 Linux 系統如同由許多積木不斷堆疊起來, 地基部份的關鍵積木若是不小心被移除, 則整個系統會有頓時癱瘓的風險。
圖(rpm-e-py.bmp):移除時因相依關係檢查所造成的警告訊息。
雖然存在上述的風險, 我還是非常鼓勵讀者盡量透過 RPM 來測試與探究 Linux 系統。 當然, 千萬不要拿具生產力的線上主機開玩笑, 最好是自己能夠獨力管理, 而且硬碟未存在重要資料的主機。 在認識 Linux 系統的題目上, RPM 可以像是一個貼身而耐心的老師, 隨時等著向你解說系統的許多秘密。
example$ rpm -Va
圖(rpm-va.bmp):RPM正在進行系統檔案的驗證工作
有人在一裝好系統後,就替系統檔案保存一份 MD5 紀錄,以供日後進行 系統安全檢查,而上述這個指令也做了類似的動作。前面提過 RPM 管理著 一個包裝檔案的資料庫,進行驗證動作時,所參考的資訊來源即是此一 資料庫,當然,RPM 資料庫也有錯誤掛點的風險,但是與系統檔案發生狀況 的機會來比,總是小許多。
RPM 進行驗證時,會檢查下列九個屬性資料:
以 S.5....T c /etc/inetd.conf 這樣的結果為例, 它表示 /etc/inetd.conf 這個檔案的 「檔案大小」「MD5 值」「修改時間」 都已經和原始安裝狀態不同, 當然, 如果某個檔案被誤刪了, 那麼它會出現「missing」的訊息。
不過, 倒也不是每一種檔案類型 (file type) 都適用上述的屬性資料, 事實上 RPM 依不同的檔案類型來進行上述的檢查動作。
檔案類型 | 大小 | 存取模式 | MD5 值 | 主號 | 次號 | 連結內容 | 擁有者 | 群組 | 修改時間 |
---|---|---|---|---|---|---|---|---|---|
目錄檔案 | X | X | X | ||||||
連結檔案 | X | X | X | X | |||||
FIFO檔案 | X | X | X | ||||||
設備檔案 | X | X | X | X | X | ||||
一般檔案 | X | X | X | X | X | X |
example$ rpm -Vvv rpm
我們可以使用 -Vvv 參數選項, 在 RPM 進行驗證過程中, 順便得知包裝檔案的詳細相依資訊。
圖(rpm-dbfile.bmp):RPM的資料庫大本營所在
圖(rpm-showrc[1-12].bmp)
example$ rpm2cpio postfix-20000531-7.i386.rpm | cpio -t
cpio 是 rpm 所內附使用的檔案壓縮工具,rpm2cpio 指的就是「從 rpm 包裝檔案中還原解讀出 cpio 格式的檔案」,如上例,我們透過「管道」 過濾 cpio 檔案給 cpio -t 來列出所有的檔案名稱。
有了 cpio 檔案名稱列表,就可以指定解出某個特定的檔案,如下例:
圖(rpm-cpio-ivd.bmp)
由於包裝檔案安裝後,會有所謂「post-install」設定過程,通常應該把 適當的變數或設定值調整好,讓 RPM 於安裝末期執行,顯然,這些苦工夫 還沒全部做完,特別是在中文的應用環境下。解決方法,是將操作流程繼續 以 script 或操作介面包裝,至少應該要提供一般使用者更具意義的錯誤 訊息,或是明載於說明文件中。
有時候,不難想像有人會發出「你憎恨 RPM 嗎」的疑問。如果 RPM 對你 而言,是一個「弊多於利」的工具,那麼可以考慮丟棄它,純粹使用 tar、 install 之類的傳統工具即可。終究對一位習慣或喜歡「不假他人」探索 系統的朋友,單純的環境會覺得更自在些,或者,也可以考慮採用 Debian GNU/Linux,它內附功能強大的 apt 工具程式,其嚴謹的發展架構很可能 會讓你感到喜愛。
「Use the Force, Read the Source!」 rpm (或是類似 dpkg 這樣的包裝系統) 可以是探索 Linux 系統的重要工具, 學習善用之, 相信能讓你進一步窺見 Linux 系統的堂奧, 甚至成為投入「包裝檔案管理系統」專業領域的第一步。 日後自行上網找尋源碼, 便可快樂 DIY。 另外, 「分享」是 Linux 環境上的重要特性, 我們期待 rpm 與 Debian Linux 的 deb, 或是 FreeBSD 的 ports 內容, 也能彼此交互影響, 去蕪存菁, 讓這些自由開放的平台環境獲得更大的進展。
「May the Source be with you!」
[2] Debian GNU/Linux計畫裡的包裝檔案說明文件
http://www.debian.org/doc/packaging-manuals/packaging.html/
[3] vim 教學資源
http://www.study-area.net/tips/vim/index.html
[4] 這裡多的是 Linux 環境上的有趣程式
http://freshmeat.net/
[5] SourceForge 上有許多開放源碼的軟體開發專案
http://www.sourceforge.net/
[6] rpm 包裝檔案大型集散地
http://rpmfind.net/
[7] 建議就近取得各式 rpm 包裝檔案,多加利用諸如中研院等網站鏡射資源。
ftp://linux.sinica.edu.tw/