歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> 關於Unix

構造Linux的圖形化安裝程序(4)(1)

本文主要包括RPM基本命令介紹,RPM包的定制過程,RPM SPEC文件的主要內容,RPM函數庫簡單參考和安裝程序中關於RPM包管理部分源碼的簡單介紹。通過這部分的介紹,希望讀者能對 Linux 系統下RPM 包的定制過程和RPM包的系統安裝過程有一個基本的了解。 在安裝程

本文主要包括RPM基本命令介紹,RPM包的定制過程,RPM SPEC文件的主要內容,RPM函數庫簡單參考和安裝程序中關於RPM包管理部分源碼的簡單介紹。通過這部分的介紹,希望讀者能對Linux系統下RPM 包的定制過程和RPM包的系統安裝過程有一個基本的了解。

在安裝程序進行了磁盤分區工作之後,安裝程序就可以進行RPM系統包的安裝了。這是整個安裝過程中很重要的一步。在這一環節,安裝程序要讀出所有rpm包的描述信息並根據包之間的依賴關系,構造出正確的包安裝順序。這種構造的機制主要是對包依賴關系的樹形結構進行深度搜索,對於最基本的系統包(比如Glibc和Bash)一定要最先安裝。為了保證在安裝了所有的系統包之後,RPM數據庫運行良好,還要在安裝過程中構造正確的RPM數據庫。最後為了調試的方便,也便於用戶檢查安裝的系統包,還需要對包的安裝過程建立日志。

1 RPM包的基本概念

RPM(Redhat Package Management)是由RedHat開發的,Linux系統下的系統包管理工具。它的目標是:使包的安裝和卸載過程更容易,能夠證實一個包是否已經正確安裝了,簡化包的建立過程,可以從源代碼建立整個包,使它能用於不同的體系結構。RPM系統已經成為現在Linux系統下包管理工具事實上的標准,並且它也移植到很多商業的unix系統之下。

RPM包由包標簽標識,它包含這樣幾個部分,軟件名,軟件版本,包的發行版本。在包的內部還包含如下信息:包的建立時間,包的內容描述,安裝包的所有文件的大小,數字簽名以證實包的完整性。RMP包還包含包內的文件信息,其中包括:每個文件的文件名,每個文件的權限,文件的屬組和擁有者,每個文件的md5校驗和,文件的內容。

RPM的包管理系統提供了下列功能:安裝新的包,除去舊的包,將一個舊包升級為新的包,獲得已經安裝包的信息。

常用的RPM命令:

rpm -i

使用此命令可以安裝一個rpm包。在安裝的過程中,此命令依次要進行包依賴性檢測,包沖突檢測,完成安裝前必須執行的任務,處理相應的配置文件,解開包中的文件並將其拷貝到正確的位置,完成安裝後必須執行的任務,對包進行的處理進行跟蹤記錄。

例如:

rpm -i bzip2-1.0.1-3.i586.rpm

//安裝bzip2包。

rpm -ivh bzip2-1.0.1-3.i586.rpm

//安裝bzip2包的同時,顯示更多的文本提示信息,以及在屏幕上顯示連續的#號來表示的安裝進度。

有時在安裝一個新包時,根據依賴性檢查的結果,需要首先安裝其他的包。但可能這時系統中並沒有安裝所需要包的合適版本,這樣rpm會終止包的安裝。為了直接安裝這個包,您需要加入--nodeps選項。下例表示在安裝bzip2包時,不進行依賴性檢測。

rpm -ivh bzip2-1.0.1-3.i586.rpm --nodeps

rpm -ivh bzip2-1.0.1-3.i586.rpm --force

//強制安裝rpm包。這條命令實際上等價於

rpm -ivh bzip2-1.0.1-3.i586.rpm --replacepkgs --replacefiles

rpm -e

使用此命令可以刪除一個rpm包。刪除rpm包時,此命令要完成如下工作:

檢查rpm數據庫確保沒有其他包依賴將要刪除的包。

如果包存在卸載前腳本,執行此腳本。

檢測安裝包時是否對包配置文件進行了修改。如果進行了修改,則保存備份。

查找rpm數據庫中此RPM包所包含的文件。如果這些文件不屬於任何其它的包,則刪除它。

如果包存在卸載後腳本,執行此腳本。

從rpm數據庫除去所有包跟蹤記錄。

例如:

rpm -e bzip2

//從系統中除去bzip2包。添加--nodeps選項可以在刪除包時,禁止包的依賴性檢查。

rpm -U

這條命令完成rpm包的升級。它執行的操作包括安裝合意的包,刪除所有存在的老版本的包。例如:

rpm -U bzip2

//升級包bzip2。

rpm -q

這條命令可以獲得rpm包的信息。通過這條命令可以查詢包的文件列表,包的版本,包的描述性信息。同樣的,你也可以通過這條命令查得一個文件屬於哪個rpm包。例如:

rpm -qf `which fdisk`

//檢查fdisk文件屬於哪個系統包。

rpm -qi bzip2

//獲得已安裝包bzip2的描述性信息。

rpm -ql bzip2

//獲得安裝包bzip2的文件列表。

rpm -qa

//獲得系統安裝的所有rpm包的列表。這條命令和grep命令一起使用,可以快速找到系統中包含的某個rpm包,例如:

rpm -qa | grep bzip2

2 RPM包建立過程

為了完成RPM包的建立過程,需要執行以下步驟:

執行Spec文件prep節的命令和宏。

檢查文件列表的內容。

執行Spec文件build節的命令和宏。

執行Spec文件install節的命令和宏,同時也執行文件列表中的宏。

創建二進制包文件。

創建源碼包。

為了執行打包的工作,RPM需要一系列目錄完成建立的工作。正常的目錄結構通常由一個頂級目錄和五個子目錄構成。這五個子目錄分別是:

SOURCES------包含原始的源文件、補丁和像標文件。

SPECS--------包含控制建立過程的spec文件。

BUILD--------包含源碼解包和軟件建立的目錄。

RPMS---------包含建立過程創建的二進制包文件。

SRPMS--------包含建立過程創建的源碼包文件。

除了上述這五個主要的目錄外,在RPMS或SRPMS目錄下通常還會有關於包目標平台的目錄。例如,i386、i586、i686等代表與Intel兼容cpu的平台,noarch目錄下的包代表可以在任何平台下執行。

2.1 SPEC文件

Spec文件是整個RPM包建立過程的中心,它的作用就如同編譯程序時的Makefile文件。Spec文件包含建立一個rpm包必需的信息,包括哪些文件是包的一部分以及它們安裝在哪個目錄下。這個文件一般分為如下的幾節:

Preamle(序言)

序言包含用戶請求包的信息時所顯示的內容。它可以包含包的功能描述,包的軟件版本,版權信息,所屬的包組等。

Prep節 Prep節進行實際的打包准備工作,它是使用節前綴%prep表示的。一般而言,這一節的主要工作是檢查標簽語法是否正確,刪除舊的軟件源程序,對包含源程序的tar文件進行解碼。如果包含補丁(patch)文件,將補丁文件應用到解開的源碼中。它一般包含%setup與%patch兩個命令。% setup用於將軟件包打開,執行%patch可將補丁文件加入解開的源程序中。

%setup

-n newdir---------將壓縮的軟件源程序在newdir目錄下解開。

-c ---------------在解開源程序之前先創建目錄。

-b num------------在包含多個源程序時,將第num個源程序解壓縮。

-T----------------不使用缺省的解壓縮操作。

例如:

%setup -T -b 0

//解開第一個源程序文件。

%setup -c -n newdir

//創建目錄newdir,並在此目錄之下解開源程序。

%patch

%patchN----------這裡N是數字,表示使用第N個補丁文件,等價於%patch -P N

-p0--------------指定使用第一個補丁文件,-p1指定使用第二個補丁文件。

-s---------------在使用補丁時,不顯示任何信息。

-b name----------在加入補丁文件之前,將源文件名上加入name。若為指定此參數,則缺省源文件加入.orig。

-T---------------將所有打補丁時產生的輸出文件刪除。

Build節

這一節主要用於編譯源碼,它是使用節前綴%build表示的。這一節一般由多個make命令組成。

Install節

這一節主要用於完成實際安裝軟件必須執行的命令,它是使用節前綴%install表示的。這一節一般是由make install指令構成,但是有時也會包含cp、mv、install等指令。

這一節還能指定在用戶安裝的系統上,包安裝時運行的腳本。這樣的腳本稱為安裝(卸載)腳本。它可以指定包安裝前、包安裝後、包除去前、包除去後的系統必須運行的外殼程序段。在用戶安裝的系統上,為了驗證一個包是否已經成功安裝的驗證腳本也可由這一節指定。

Clean節

這一節所描述的內容表示在完成包建立的工作之後,自動執行此節下的腳本進行附加的清除工作,它是使用節前綴%clean表示的。一般而言,這一節的內容是簡單地使用rm -rf $RPM_BUILD_ROOT命令,不需要指定此節的其它內容。

文件列表

這一節指定構成包的文件的列表,它是使用節前綴%files表示的。此外,它還包含一系列宏控制安裝後的文件屬性和配置信息。

改動日志

這一節主要描述軟件的開發記錄,它是使用節前綴%changlog表示的。這個段的內容是為了開發人員能詳細的了解該軟件的開發過程,對於包的維護極有好處。

2.2 建立rpm包

有時您可能只有一個tar.gz格式的源程序包,為了生成正確的rpm包,您可以使用autospec自動創建spec文件。

舉例來說,您有一個源程序文件some.tar.gz。為了定制rpm包,您要進行如下操作:

解壓縮源程序包

tar xvzf some.tar.gz

手動編譯和安裝此源程序包

make; make install

自動生成spec文件

make -n install | autospec -i > some.spec

編譯生成rpm包

rpm -ba some.spec

在創建spec文件之前,必須成功編譯源程序包。否則autospec生成的spec文件將不會包含%build、%install、%file。對於一般的源程序包,您只需到SPEC目錄下,直接執行上面操作的第四步就可以了。

3 定制系統安裝盤

定制系統安裝盤的過程主要是指對於用戶提供的一組RPM包,安裝程序能夠根據用戶提供的描述文件,自動進行包的安裝。這個過程包括對包的依賴性進行檢查、根據類別選擇需要安裝的包。

使用HappyLinux發布盤上附帶的RPM包管理工具可以定制系統發布盤,這些包管理工具保存在安裝盤的/misc目錄下。為了保證安裝程序能夠工作,必須在/HappyLinux/base目錄下提供以下的文件:

compss

在HappyLinux系統下,它是由系統命令gendistrib自動生成的。它可以根據包所屬的包組對包進行分類。compss描述發布盤上所有包的一個列表。這個文件對於安裝過程沒有影響,它的存在只是為了與以前的版本兼容。

compssUsers

此文件的內容是對rpmsrate文件所描述的包類別進行進一步的包裝,以形成更高層的包類表述。

depslist

depslist.ordered

這兩個文件是命令gendistrib生成的,它描述每個包所依賴的系統包。depslist.ordered使安裝程序實際使用的文件,它將依賴包的文本描述轉換為包的編號,這樣可以加快整個安裝的進程。

happyinst_stage2.bz2

這個文件保存的是整個安裝環境(也就是安裝盤上/HappyLinux/happyinst目錄下的所有文件)的壓縮鏡像,它會在啟動過程中由系統加載程序調入內存。這個文件是由命令make_happyinst_stage2生成的。

hdlists

這個文件是對安裝盤rpm包所在的目錄進行描述。當要進行多盤安裝時,此文件的每一行表示一張發布介質的RPM包所在的目錄。這個文件必須由用戶手動生成。

hdlist.cz2

這是由命令gendistrib生成的,包頭信息的描述文件。安裝程序由此文件讀出每個包的大小、版本等信息。它的名字是由hdlists文件的對應行表示的。

provides

這個文件也是命令gendistrib生成的,它將包沖突檢測的信息保存到此文件中。

rpmsrate

這個文件是由用戶自己定制的。它主要描述同類別包的編組。同時,對包組的文件指定了優先級,使得不同的場景可以自動安裝不同的包組。這些包類別將要寫入compssUsers文件中,構成更大的包邏輯分組。

在發布盤上的任何包的發生改變時,為了使此改變生效,必須運行命令gendistrib,重新生成所有與包描述有關的文件。

gendistrib --distrib /export

根據目錄/export下保存的所有包信息生成相應的描述文件。

在對包的安裝環境進行了任何修改之後,必須重新運行命令make_happyinst_stage2。

make_happyinst_stage2 /export/HappyLinux/happyinst /export/HappyLinux/base/happyinst_stage2.bz2

生成整個安裝程序的壓縮鏡像。

在進行了上述步驟之後,您就可以使用mkisofs創建iso文件,以生成正確的光盤發布了。

4 rpmlib庫函數

rpmlib庫函數是包含在librpm.a庫中的。在c語言中,使用這些函數必須包含頭文件rpmlib.h,對於與header有關的函數還需要包含頭文件header.h。這些函數完成的功能包括從底層的rpm數據庫記錄遍歷到高層的包處理。

在安裝程序中,使用rpmlib中的函數完成包安裝的功能,具有以下的一些優點:

大大減小了整個安裝程序占用的內存。這樣安裝程序就無需提供rpm系統文件了。

直接使用c語言的庫函數提高了包的安裝速度。

通過安裝回調函數,可以在包的安裝過程中,實現一些特殊的效果,比如安裝過程中更換顯示圖片,顯示安裝進度等。

下面包含的函數只是rpmlib中與安裝程序有關的部分函數接口。

4.1 錯誤處理

int rpmErrorCode(void);

這個函數返回最後一個失敗的rpmlib函數返回的錯誤碼。此函數僅用於rpmErrorSetCallBack()定義的錯誤回調函數中。

char *rpmErrorString(void);

這個函數返回最後一個失敗的rpmlib函數返回的錯誤串。此函數僅用於rpmErrorSetCallBack()定義的錯誤回調函數中。

rpmErrorCallBackType rpmErrorSetCallback(rpmErrorCallBackType);

這個函數設置當前錯誤回調函數,它返回以前設置的錯誤回調函數

4.2 獲得包信息

下列函數用於獲得包文件信息。返回的信息以Header結構的形式保存。

int rpmReadPackageInfo(int fd, Header * signatures, Header * hdr);

使用給定fd(表示對應的rpm包)讀入頭信息和標記信息。如果指定signatures或hdr,則其對應的信息不返回。

int rpmReadPackageHeader(int fd, Header * hdr, int * isSource, int * major, int * minor);

使用給定fd(表示對應的rpm包)讀入頭信息,以及此包文件是否是源碼包,包的主、次版本號。

4.3 RPM數據庫處理

這一節的函數完成RPM數據庫的基本操作。這包括打開和關閉數據庫,以及在數據庫損壞時進行重建。每個存取RPM數據庫的函數都要使用rpmdb結構,它是RPM數據庫的句柄。

int rpmdbOpen(char * root, rpmdb * dbp, int mode, int perms);

此過程打開環境變量RPMVAR_DBPATH指定的RPM數據庫,返回rpmdb結構。

void rpmdbClose(rpmdb db);

此過程關閉rpmdb結構指定的RPM數據庫。

int rpmdbInit(char * root, int perms);

此過程在環境變量RPMVAR_DBPATH指定的位置創建一個新的RPM數據庫。如果數據庫存在,此函數不做任何操作。

int rpmdbRebuild(char * root);

此過程在環境變量RPMVAR_DBPATH處重建RPM數據庫。

4.4 RPM數據庫遍歷

unsigned int rpmdbFirstRecNum(rpmdb db);

此過程返回db指定的數據庫第一個記錄的記錄編號。

unsigned int rpmdbNextRecNum(rpmdb db, unsigned int lastOffset);

此過程返回緊接著lastOffset的記錄的編號。

Header rpmdbGetRecord(rpmdb db, unsigned int offset);

此過程返回指定偏移處的記錄。

4.5 RPM數據庫查詢

這一節的函數查詢RPM數據庫,並且返回dbiIndexSet結構。在不使用此返回值的時候,使用dbiFreeIndexRecord()函數釋放。

typedef struct {

dbiIndexRecord * recs;

int count;

} dbiIndexSet;

typedef struct {

unsigned int recOffset;

unsigned int fileNumber;

} dbiIndexRecord;

recOffset是記錄在數據庫中的偏移,fileNumber僅用於rpmdbFindByFile()。

int rpmdbFindByFile(rpmdb db, char * filespec, dbiIndexSet * matches);

此過程搜索db指定的RPM數據庫,找到擁有filespec指定文件的記錄,並保存在matches中。

int rpmdbFindByGroup(rpmdb db, char * group, dbiIndexSet * matches);

此過程搜索db指定的RPM數據庫,查找是group組指定的成員的包,返回值保存在matches中。

int rpmdbFindPackage(rpmdb db, char * name, dbiIndexSet * matches);

此過程搜索db指定的RPM數據庫,查找包名是name的包,返回值保存在matches中。

int rpmdbFindByProvides(rpmdb db, char * provides, dbiIndexSet * matches);

此過程搜索db指定的RPM數據庫,查找包的provides信息和指定的provides信息一致的包,返回值保存在matches中。

int rpmdbFindByRequiredBy(rpmdb db, char * requires, dbiIndexSet * matches);

此過程搜索db指定的RPM數據庫,查找包的requires信息和指定的requires信息一致的包,返回值保存在matches中。

int rpmdbFindByConflicts(rpmdb db, char * conflicts, dbiIndexSet * matches);

此過程搜索db指定的RPM數據庫,查找包的conflicts信息和指定的conflicts信息一致的包,返回值保存在matches中。

4.6 包處理

int rpmInstallSourcePackage(char * root, int fd, char ** specFile, rpmNotifyFunction notify, char * labelFormat);

此函數安裝fd指定的源碼包。如果指定了root字段則將包安裝到此目錄下。notify指定安裝過程中調用的進程跟蹤過程。labelformat指定包標簽的打印格式。

int rpmInstallPackage(char * rootdir,rpmdb db, int fd, char * prefix, int flags, rpmNotifyFunction notify, char * labelFormat, char *.netsharedPath);

此過程安裝db指定的二進制包,如果指定了rootdir,包安裝到此目錄下。flags參數控制包的安裝行為。

RPMINSTALL_REPLACEPKG------------即使包已經安裝,仍繼續安裝。

RPMINSTALL_REPLACEFILES----------即使會替換另外一個包的文件也安裝此包。

RPMINSTALL_TEST------------------只進行安裝時檢測,不安裝包。

RPMINSTALL_UPGRADE---------------安裝包並除去包的老版本。

RPMINSTALL_UPGRADETOOLD----------即使此包是老版本,仍進行安裝。

RPMINSTALL_NODOCS----------------不安裝包的文檔文件。

RPMINSTALL_NOSCRIPTS-------------不執行包的安裝和刪除腳本。

RPMINSTALL_NOARCH----------------不完成結構兼容性測試

RPMINSTALL_NOOS------------------不進行>操作系統兼容性測試

Copyright © Linux教程網 All Rights Reserved