1. 程式人生 > >linux-centos淺談之rpm和rpmbuild

linux-centos淺談之rpm和rpmbuild

一、簡介     

       RPM(Red Hat Package Manager)是用於 Linux 分發版(distribution)的最常見的軟體包管理器。RPM包命名方式:name-version-release.architecture.rpm。RPM有五種基本的操作功能:安裝、解除安裝、升級、查詢和驗證。這五種基本功能的實現僅僅需要用rpm + 選項 + rpm包就能輕易地實現。

       如果想釋出rpm格式的原始碼包或者是二進位制包,就要使用rpmbuild工具(rpm最新打包工具)。rpmbuild根據本地原始碼包的成功編譯安裝而寫了spec檔案(該檔案要以.spec結束)

二、詳解

1、RPM

(1)rpm二進位制包(.rpm檔案)

常用命令組合:

-ivh:安裝顯示安裝進度--install--verbose--hash
-Uvh:升級軟體包--Update;
-qpl:列出RPM軟體包內的檔案資訊[Query Package list];
-qpi:列出RPM軟體包的描述資訊[Query Package install package(s)];
-qf:查詢指定檔案屬於哪個RPM軟體包[Query File];
-Va:校驗所有的RPM軟體包,查詢丟失的檔案[View Lost];
-e:刪除包
rpm2cpio file.rpm |cpio -div    #[抽出檔案] 

1)安裝:

        rpm -i your-package.rpmyour-package.rpm是rpm包的檔名),安裝過程中可能出現下面的警告或者提示:.. conflict with ... ,則可能是要安裝的包裡有一些檔案可能會覆蓋現有的檔案,預設時這樣的情況下是無法正確安裝的可以用rpm-i --force強制安裝即可。若出現... is needed by ...和... is not installed ... 此包需要的一些軟體你沒有安裝可以用rpm-i--nodeps可以忽略所有依賴關係和檔案問題,什麼包都能安裝上,但這種強制安裝的軟體包不能保證完全發揮功能 。


2)查詢:

      rpm -qa 將列出所有安裝過的包 ,rpm -qa | grep httpd  #[搜尋指定rpm包是否安裝]--all搜尋*httpd*
      rpm -ql httpd  #[搜尋rpm包]--list所有檔案安裝目錄

      which httpd    #查詢rpm包可執行檔案安裝到那裡去了

      whereis httpd #查詢rpm包中的檔案安裝到那裡去了
      rpm -qpi Linux-1.4-6.i368.rpm       #[檢視rpm包]--query--package--install package資訊
      rpm -qpf Linux-1.4-6.i368.rpm #[檢視rpm包]--file

      rpm -qpR file.rpm        #[檢視包]依賴關係
查詢rpm中包含哪些檔案:一個沒有安裝過的軟體包,使用rpm -qlp *.rpm;一個已經安裝的軟體包,可以使用rpm -ql 安裝的軟體名稱。
獲取關於一個軟體包的資訊:一個沒有安裝過的軟體包,使用rpm -qip *.rpm ;一個已經安裝過的軟體包,使用rpm -qi安裝的軟體名稱

      rpm -qf `which 程式名` 返回軟體包的全名
      rpm -qif `which 程式名` 返回軟體包的有關資訊
      rpm -qlf `which 程式名` 返回軟體包的檔案列表

      首先獲得這個程式的完整路徑,可以用whereis或者which,然後使用rpm -qf例如:
# whereis ftptop
ftptop: /usr/bin/ftptop /usr/share/man/man1/ftptop.1.gz
# rpm -qf /usr/bin/ftptop
proftpd-1.2.8-1
# rpm -qf /usr/share/doc/proftpd-1.2.8/rfc/rfc0959.txt
proftpd-1.2.8-1
3)刪除:
rpm -e file.rpm      #[刪除一個rpm包]--erase

有時會出現一些錯誤或者警告: ... is needed by ... 這說明這個軟體被其他軟體需要,不能隨便解除安裝 ,可以用rpm -e --nodeps強制解除安裝 。

4)升級

rpm -Uvh file.rpm    #[升級一個rpm]--upgrade

5)驗證:

rpm –V file.rpm。對已經安裝了的程式進行驗證。

6)--aid:

--aid 解決rpm安裝過程中迴圈依賴

(2)rpm原始碼包(.src.rpm檔案)

.src.rpm結尾的檔案是由軟體的原始碼包裝而成的,使用者要安裝這類RPM軟體包,必須使用命令:

rpmbuild --recompile vim-4.6-4.src.rpm   #這個命令會把原始碼解包並編譯、安裝它,如果使用者使用命令。
rpmbuild --rebuild vim-
4.6-4.src.rpm  #在安裝完成後,還會把編譯生成的可執行檔案重新包裝成i386.rpm的RPM軟體包。

一般會採用的方法:

1.執行rpm -i you-package.src.rpm
2. cd /usr/src/redhat/SPECS
3. rpmbuild -bb your-package.specs 一個和你的軟體包同名的specs檔案,這時在/usr/src/redhat/RPM/i386/ (根據具體包的不同,也可能是i686,noarch等等) 這個目錄下,有一個新的rpm包,這個是編譯好的二進位制檔案。
執行rpm -i new-package.rpm即可安裝完成。

或者:

1.執行rpm -i your-package.src.rpm
2. cd /usr/src/redhat/SPECS
3. rpmbuild -bp your-package.specs 一個和你的軟體包同名的specs檔案
4. cd /usr/src/redhat/BUILD/your-package/ 一個和你的軟體包同名的目錄
5. ./configure 這一步和編譯普通的原始碼軟體一樣,可以加上引數
6. make
7. make install

(3)不安裝獲取rpm包中的檔案

使用工具rpm2cpiocpio命令格式: rpm2cpio file.rpm |cpio -div
rpm2cpio file.rpm | cpio -vi
rpm2cpio file.rpm | cpio -idmv
rpm2cpio file.rpm | cpio --extract --make-directories
      其中引數i和extract相同,表示提取檔案;v表示指示執行程序 ;d和make-directory相同,表示根據包中檔案原來的路徑建立目錄 ;m表示保持檔案的更新時間。

      同樣適用於.src.rpm原始碼包。

(4)rpm的配置檔案

 RPM包管理的配置檔案是 rpmrc ,可以在自己的系統中找到。

[[email protected] RPMS]# locate rpmrc
/usr/lib/rpm/rpmrc
/usr/lib/rpm/redhat/rpmrc

也可以通過 rpm --showrc檢視實現程式碼 。
可以檢視/usr/lib/rpm/macros,/usr/lib/rpm/redhat/macros
另外直接通過 rpm --eval "%{macro}"來檢視具體對應路徑,如rpm --eval "%{?dist}"輸出:.el6

2、RPMBUILD

     它是用來指示轉換的原始碼編譯成二進位制檔案的包,在centos下預設目錄為當前使用者下,如/root。因為系統有預設的rpm構建的目錄,若要重新指定rpm構建的目錄位置,需要在當前使用者目錄下建一個.rpmmacros檔案,通過更改 %_topdir 設定來告訴 RPM 查詢和建立不同目錄集中的檔案,如%_topdir /home/your_userid/rpm,然後手動建立這樣一個完整的目錄樹:~/rpm ~/rpm/SOURCES ~/rpm/SPECS ~/rpm/BUILD ~/rpm/RPMS ~/rpm/RPMS/i386 ~/rpm/SRPMS(也可執行時程式自動建立,比如任意執行個spec檔案,rpmbuild -bp file.spec雖然執行失敗但會建立目錄)。

(1)目錄

       此次在當前root使用者下手動建立目錄,mkdir –p /root/rpmbuild,mkdir -pv ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}。

--BUILD #編譯之前,如解壓包後存放的路徑
--BUILDROOT #編譯後存放的路徑
--RPMS #打包完成後rpm包存放的路徑
--SOURCES #源包所放置的路徑
--SPECS #spec文件放置的路徑
--SPRMS #原始碼rpm包放置的路徑
注:一般我們都把原始碼打包成tar.gz格式然後存放於SOURCES路徑下(rpm -ivh +原始碼包,會自動解壓到SOURCES目錄下),而在SPECS路徑下編寫spec文件,通過命令打包後,預設會把打包後的rpm包放在RPMS下,而原始碼包會被放置在SRPMS下

(2)rpmbuild相關命令

基本格式:rpmbuild [options] [spec文件|tarball包|原始碼包],以下依次列出三種不同檔案
1.從spec文件建立有以下選項:
-bp  #只執行spec的%pre 段(解開原始碼包並打補丁,即只做準備)
-bc  #執行spec的%pre和%build 段(準備並編譯)
-bi  #執行spec中%pre,%build與%install(準備,編譯並安裝)
-bl  #檢查spec中的%file段(檢視檔案是否齊全)
-ba  #建立原始碼與二進位制包(常用)
-bb  #只建立二進位制包(常用)
-bs  #只建立原始碼包
2.從tarball包建立,與spec類似
-tp #對應-bp
-tc #對應-bc
-ti #對應-bi
-ta #對應-ba
-tb #對應-bb
-ts #對應-bs
3.從原始碼包建立
--rebuild  #建立二進位制包,通-bb
--recompile  #同-bi
4.其他的一些選項
--buildroot=DIRECTORY  #確定以root目錄建立包
--clean  #完成打包後清除BUILD下的檔案目錄
--nobuild  #不進行%build的階段
--nodeps  #不檢查建立包時的關聯檔案
--nodirtokens
--rmsource  #完成打包後清除SOURCES
--rmspec #完成打包後清除SPEC
--short-cricuit
--target=CPU-VENDOR-OS #確定包的最終使用平臺

 (3) spec文件的編寫

Name:軟體包的名稱,後面可使用%{name}的方式引用,具體命令需跟源包一致
Summary: 軟體包的內容概要
Version: 軟體的實際版本號,具體命令需跟源包一致
Release: 釋出序列號,具體命令需跟源包一致
Group: 軟體分組,建議使用標準分組
-----------------------------------------
軟體包所屬類別,具體類別有:
Amusements/Games (娛樂/遊戲)
Amusements/Graphics(娛樂/圖形)
Applications/Archiving (應用/文件)
Applications/Communications(應用/通訊)
Applications/Databases (應用/資料庫)
Applications/Editors (應用/編輯器)
Applications/Emulators (應用/模擬器)
Applications/Engineering (應用/工程)
Applications/File (應用/檔案)
Applications/Internet (應用/因特網)
Applications/Multimedia(應用/多媒體)
Applications/Productivity (應用/產品)
Applications/Publishing(應用/印刷)
Applications/System(應用/系統)
Applications/Text (應用/文字)
Development/Debuggers (開發/偵錯程式)
Development/Languages (開發/語言)
Development/Libraries (開發/函式庫)
Development/System (開發/系統)
Development/Tools (開發/工具)
Documentation (文件)
System Environment/Base(系統環境/基礎)
System Environment/Daemons (系統環境/守護)
System Environment/Kernel (系統環境/核心)
System Environment/Libraries (系統環境/函式庫)
System Environment/Shells (系統環境/介面)
User Interface/Desktops(使用者介面/桌面)
User Interface/X (使用者介面/X視窗)
User Interface/X Hardware Support (使用者介面/X硬體支援)
----------------------------------------------------
License: 軟體授權方式,通常就是GPL
Source:原始碼包,可以帶多個用Source1、Source2等源,後面也可以用%{source1}、%{source2}引用
BuildRoot: 這個是安裝或編譯時使用的“虛擬目錄”,考慮到多使用者的環境,一般定義為:
%{_tmppath}/%{name}-%{version}-%{release}-root

%{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u}-n}
該引數非常重要,因為在生成rpm的過程中,執行makeinstall時就會把軟體安裝到上述的路徑中,在打包的時候,同樣依賴“虛擬目錄”為“根目錄”進行操作。
後面可使用$RPM_BUILD_ROOT 方式引用。
URL: 軟體的主頁
Vendor: 發行商或打包組織的資訊,例如RedFlag Co,Ltd
Disstribution: 發行版標識
Patch: 補丁原始碼,可使用Patch1、Patch2等標識多個補丁,使用%patch0或%{patch0}引用
Prefix: %{_prefix}這個主要是為了解決今後安裝rpm包時,並不一定把軟體安裝到rpm中打包的目錄的情況。這樣,必須在這裡定義該標識,並在編寫%install指令碼的時候引用,才能實現rpm安裝時重新指定位置的功能
Prefix: %{_sysconfdir}這個原因和上面的一樣,但由於%{_prefix}指/usr,而對於其他的檔案,例如/etc下的配置檔案,則需要用%{_sysconfdir}標識
Build Arch:指編譯的目標處理器架構,noarch標識不指定,但通常都是以/usr/lib/rpm/marcros中的內容為預設值
Requires:該rpm包所依賴的軟體包名稱,可以用>=或<=表示大於或小於某一特定版本,例如:
libpng-devel >= 1.0.20 zlib
※“>=”號兩邊需用空格隔開,而不同軟體名稱也用空格分開
還有例如PreReq、Requires(pre)、Requires(post)、Requires(preun)、Requires(postun)、BuildRequires等都是針對不同階段的依賴指定
Provides: 指明本軟體一些特定的功能,以便其他rpm識別
Packager: 打包者的資訊
%description 軟體的詳細說明
#spec指令碼主體
spec指令碼的主體中也包括了很多關鍵字和描述,下面會一一列舉。我會把一些特別需要留意的地方標註出來。
%prep 預處理指令碼
%setup -n %{name}-%{version} 把原始碼包解壓並放好
注:可根據你的原始碼的名字格式,來確認解壓後名字的格式,否則可能導致install的時候找不到對應的目錄
通常是從/usr/src/redhat/SOURCES裡的包解壓到/usr/src/redhat/BUILD/%{name}-%{version}中。
一般用%setup-c就可以了,但有兩種情況:一就是同時編譯多個原始碼包,二就是原始碼的tar包的名稱與解壓出來的目錄不一致,此時,就需要使用-n引數指定一下了。
%patch 打補丁
通常補丁都會一起在原始碼tar.gz包中,或放到SOURCES目錄下。一般引數為:
%patch -p1 使用前面定義的Patch補丁進行,-p1是忽略patch的第一層目錄
%Patch2 -p1 -b xxx.patch 打上指定的補丁,-b是指生成備份檔案

◎補充一下
%setup 不加任何選項,僅將軟體包開啟。
%setup -n newdir 將軟體包解壓在newdir目錄。
%setup -c 解壓縮之前先產生目錄。
%setup -b num 將第num個source檔案解壓縮。
%setup -T 不使用default的解壓縮操作。
%setup -T -b 0 將第0個原始碼檔案解壓縮。
%setup -c -n newdir 指定目錄名稱newdir,並在此目錄產生rpm套件。
%patch 最簡單的補丁方式,自動指定patch level。
%patch 0 使用第0個補丁檔案,相當於%patch ?p 0。
%patch -s 不顯示打補丁時的資訊。
%patch -T 將所有打補丁時產生的輸出檔案刪除。

%build 開始構建包
在/usr/src/redhat/BUILD/%{name}-%{version}目錄中進行make的工作 ,常見寫法:
make %{?_smp_mflags} OPTIMIZE="%{optflags}"
都是一些優化引數,定義在/usr/lib/rpm/marcros中

%install 開始把軟體安裝到虛擬的根目錄中
在/usr/src/redhat/BUILD/%{name}-%{version}目錄中進行makeinstall的操作。這個很重要,因為如果這裡的路徑不對的話,則下面%file中尋找檔案的時候就會失敗。 常見內容有:
%makeinstall 這不是關鍵字,而是rpm定義的標準巨集命令。也可以使用非標準寫法:
make DESTDIR=$RPM_BUILD_ROOT install

make prefix=$RPM_BUILD_ROOT install

需要說明的是,這裡的%install主要就是為了後面的%file服務的。所以,還可以使用常規的系統命令:

install -d $RPM_BUILD_ROOT/ #建立目錄
cp -a * $RPM_BUILD_ROOT/

%clean 清理臨時檔案
通常內容為:
引用
[ "$RPM_BUILD_ROOT" != "/" ] && rm-rf "$RPM_BUILD_ROOT"
rm -rf $RPM_BUILD_DIR/%{name}-%{version}

※注意區分$RPM_BUILD_ROOT和$RPM_BUILD_DIR:
$RPM_BUILD_ROOT是指開頭定義的BuildRoot,而$RPM_BUILD_DIR通常就是指/usr/src/redhat/BUILD,其中,前面的才是%file需要的。

%pre rpm安裝前執行的指令碼

%post rpm安裝後執行的指令碼

%preun rpm解除安裝前執行的指令碼

%postun rpm解除安裝後執行的指令碼

%preun %postun 的區別是什麼呢?
前者在升級的時候會執行,後者在升級rpm包的時候不會執行

%files 定義那些檔案或目錄會放入rpm中
這裡會在虛擬根目錄下進行,千萬不要寫絕對路徑,而應用巨集或變量表示相對路徑。如果描述為目錄,表示目錄中除%exclude外的所有檔案。
%defattr (-,root,root)指定包裝檔案的屬性,分別是(mode,owner,group),-表示預設值,對文字檔案是0644,可執行檔案是0755

%exclude 列出不想打包到rpm中的檔案
※小心,如果%exclude指定的檔案不存在,也會出錯的。
%changelog 變更日誌

(4) spec文件中常用的幾個巨集(變數)

1.RPM_BUILD_DIR: /usr/src/redhat/BUILD
2. RPM_BUILD_ROOT: 
/usr/src/redhat/BUILDROOT
3. %{_sysconfdir}: 
/etc
4.%{_sbindir}: 
/usr/sbin
5.%{_bindir}: 
/usr/bin
6.%{_datadir}: 
/usr/share
7.%{_mandir}: 
/usr/share/man
8.%{_libdir}: 
/usr/lib64
9.%{_prefix}: 
/usr
10. %{_localstatedir}: 
/usr/var

(5) 建立RPM包的例子

要建立的rpm包為:test-1.0.1-1.el6.i686.rpm,打包的壓縮檔案為:test-1.0.1.tar.gz。

1.把test-1.0.1.tar.gz拷貝到SOURCE目錄底下。

2.轉至SPECS目錄底下,編寫test.spec描述檔案,這個檔案是建立rpm包最重要的部分,它會制定rpm包裡的軟體的安裝目錄,以及安裝軟體前後要注意的問題,軟體的依賴及系統要求。

3.編譯RPM,執行命令:rpmbuild –ba test.spec。這樣以後,就開始建立rpm包。

4.執行rpmbuild –ba test.spec後,會首先把test-1.0.1.tar.gz解壓縮到BUILD目錄,BUILDROOT這個目錄用來存放執行時存放的臨時資料夾,這個目錄也很重要,需要把在此目錄建立相關目錄以及拷貝相關檔案資訊的指令碼寫入test.spec檔案裡,以防編譯出錯,無法生成RPM包。成功執行完成之後,會在RPMS這個目錄生成i686/ test-1.0.1-1.el6.i686.rpm檔案。

如下圖:

(6) 附加SPEC檔案

      檔案是官方釋出的anaconda.spec,Anaconda是RedHat、CentOS、Fedora等Linux的安裝管理程式,以後還有很重要的應用。分析該檔案對系統的定製很有幫助,因檔案內容過長,刪除後面不太重要的日誌部分。

%define livearches %{ix86} x86_64 ppc ppc64
%define _libdir %{_prefix}/lib

Summary: Graphical system installer
Name:    anaconda
Version: 13.21.176
Release: 1%{?dist}
License: GPLv2+
Group:   Applications/System
URL:     http://fedoraproject.org/wiki/Anaconda

# To generate Source0 do:
# git clone http://git.fedorahosted.org/git/anaconda.git
# git checkout -b archive-branch anaconda-%{version}-%{release}
# ./autogen.sh
# ./configure
# make dist
Source0: %{name}-%{version}.tar.bz2
Patch1000: anaconda-centos-installclass.patch
Patch1001: anaconda-centos-upgrade-from-centos.patch
Patch1002: anaconda-centos-droprepos.patch

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

# Versions of required components (done so we make sure the buildrequires
# match the requires versions of things).
%define dmver 1.02.17-6
%define gettextver 0.11
%define genisoimagever 1.1.9-4
%define intltoolver 0.31.2-3
%define libnlver 1.0
%define libselinuxver 1.6
%define pykickstartver 1.74.8
%define rpmpythonver 4.2-0.61
%define slangver 2.0.6-2
%define yumver 2.9.2
%define partedver 1.8.1
%define pypartedver 3.0
%define syscfgdatever 1.9.48
%define pythonpyblockver 0.45-2
%define e2fsver 1.41.0
%define nmver 1:0.7.1-3.git20090414
%define dbusver 1.2.3
%define createrepover 0.4.7
%define yumutilsver 1.1.11-3
%define iscsiver 6.2.0.870-3
%define pythoncryptsetupver 0.0.6
%define mehver 0.8
%define sckeyboardver 1.3.1
%define libblkid 2.17.1-1
%define fcoeutilsver 1.0.12-3.20100323git
%define isomd5sumver 1.0.6

BuildRequires: audit-libs-devel
BuildRequires: bzip2-devel
BuildRequires: device-mapper-devel >= %{dmver}
BuildRequires: e2fsprogs-devel >= %{e2fsver}
BuildRequires: elfutils-devel
BuildRequires: gettext >= %{gettextver}
BuildRequires: gtk2-devel
BuildRequires: intltool >= %{intltoolver}
BuildRequires: isomd5sum-devel >= %{isomd5sumver}
BuildRequires: libarchive-devel
BuildRequires: libX11-devel
BuildRequires: libXt-devel
BuildRequires: libXxf86misc-devel
BuildRequires: libblkid-devel >= %{libblkid}
BuildRequires: libcurl-devel
BuildRequires: libnl-devel >= %{libnlver}
BuildRequires: libselinux-devel >= %{libselinuxver}
BuildRequires: libsepol-devel
BuildRequires: libxml2-python
BuildRequires: newt-devel
BuildRequires: pango-devel
BuildRequires: pykickstart >= %{pykickstartver}
BuildRequires: python-devel
BuildRequires: python-urlgrabber >= 3.9.1-5
BuildRequires: rpm-devel
BuildRequires: rpm-python >= %{rpmpythonver}
BuildRequires: slang-devel >= %{slangver}
BuildRequires: xmlto
BuildRequires: yum >= %{yumver}
BuildRequires: zlib-devel
BuildRequires: NetworkManager-devel >= %{nmver}
BuildRequires: NetworkManager-glib-devel >= %{nmver}
BuildRequires: dbus-devel >= %{dbusver}
BuildRequires: system-config-keyboard >= %{sckeyboardver}
%ifarch %livearches
BuildRequires: desktop-file-utils
%endif
BuildRequires: iscsi-initiator-utils-devel >= %{iscsiver}
%ifarch s390 s390x
BuildRequires: s390utils-devel
%endif

Requires: python-meh >= %{mehver}
Requires: policycoreutils
Requires: rpm-python >= %{rpmpythonver}
Requires: comps-extras
Requires: parted >= %{partedver}
Requires: pyparted >= %{pypartedver}
Requires: yum >= %{yumver}
Requires: libxml2-python
Requires: python-urlgrabber >= 3.9.1-5
Requires: system-logos
Requires: pykickstart >= %{pykickstartver}
Requires: system-config-date >= %{syscfgdatever}
Requires: device-mapper >= %{dmver}
Requires: device-mapper-libs >= %{dmver}
Requires: dosfstools
Requires: e2fsprogs >= %{e2fsver}
Requires: gzip
Requires: xz
Requires: libarchive
%ifarch %{ix86} x86_64 ia64
Requires: dmidecode
%endif
Requires: python-pyblock >= %{pythonpyblockver}
Requires: libuser-python
Requires: newt-python
Requires: authconfig
Requires: system-config-firewall-base
Requires: cryptsetup-luks
Requires: python-cryptsetup >= %{pythoncryptsetupver}
Requires: mdadm
Requires: lvm2
Requires: util-linux-ng >= 2.15.1
Requires: system-config-keyboard >= %{sckeyboardver}
Requires: dbus-python
Requires: cracklib-python
Requires: python-nss
Requires: tigervnc-server
%ifarch %livearches
Requires: usermode
Requires: zenity
%endif
Requires: createrepo >= %{createrepover}
Requires: squashfs-tools
Requires: genisoimage >= %{genisoimagever}
%ifarch %{ix86} x86_64
Requires: syslinux >= 3.73
Requires: makebootfat
Requires: device-mapper
%endif
%ifarch s390 s390x
Requires: openssh
%endif
Requires: isomd5sum
Requires: yum-utils >= %{yumutilsver}
Requires: NetworkManager >= %{nmver}
Requires: dhclient
Requires: anaconda-yum-plugins
Requires: libselinux-python >= %{libselinuxver}
Requires: fcoe-utils >= %{fcoeutilsver}
%ifarch %{sparc}
Requires: elftoaout piggyback
%endif
Obsoletes: anaconda-images <= 10
Provides: anaconda-images = %{version}-%{release}
Obsoletes: anaconda-runtime < %{version}-%{release}
Provides: anaconda-runtime = %{version}-%{release}
Obsoletes: booty

%description
The anaconda package contains the program which was used to install your
system.  These files are of little use on an already installed system.

%prep
%setup -q
%patch1000 -p1
%patch1001 -p1
%patch1002 -p1


%build
%configure --disable-static
%{__make} %{?_smp_mflags}

%install
%{__rm} -rf %{buildroot}
%{__make} install DESTDIR=%{buildroot}
find %{buildroot} -type f -name "*.la" | xargs %{__rm}

%ifarch %livearches
desktop-file-install --vendor="" --dir=%{buildroot}%{_datadir}/applications %{buildroot}%{_datadir}/applications/liveinst.desktop
%else
%{__rm} -rf %{buildroot}%{_bindir}/liveinst %{buildroot}%{_sbindir}/liveinst
%endif

%find_lang %{name}

%clean
%{__rm} -rf %{buildroot}

%ifarch %livearches
%post
update-desktop-database &> /dev/null || :
%endif

%ifarch %livearches
%postun
update-desktop-database &> /dev/null || :
%endif

%files -f %{name}.lang
%defattr(-,root,root)
%doc COPYING
%doc docs/command-line.txt
%doc docs/install-methods.txt
%doc docs/mediacheck.txt
%doc docs/anaconda-release-notes.txt
/lib/udev/rules.d/70-anaconda.rules
%{_sbindir}/anaconda
%ifarch i386 i486 i586 i686 x86_64
%{_sbindir}/gptsync
%{_sbindir}/showpart
%endif
%{_datadir}/anaconda
%{_prefix}/lib/anaconda
%{_prefix}/lib/anaconda-runtime
%ifarch %livearches
%{_bindir}/liveinst
%{_sbindir}/liveinst
%config(noreplace) %{_sysconfdir}/pam.d/*
%config(noreplace) %{_sysconfdir}/security/console.apps/*
%{_sysconfdir}/X11/xinit/xinitrc.d/*
%{_datadir}/applications/*.desktop
%{_datadir}/icons/hicolor/*
%endif

%changelog
* Sat Jun 23 2012 Karanbir Singh <[email protected]> - 13.21.176.1.el6.centos
- Build for CentOS-6.3

(7) 升級RPM包的SPEC檔案修改

當在使用者機器上安裝或解除安裝程式時,能夠執行命令將是很有用的。例如,可能需要編輯一個系統配置檔案以啟用新的服務,或者需要定義一個新使用者以擁有正在安裝的程式的所有權。

安裝和解除安裝指令碼的工作原理看起來很簡單,但它們工作原理中的一些意外可能會引起大問題。這裡是一些基本資訊,可以將下列四節中的任意一個新增到.spec 檔案,它列出了在包安裝期間各個點上執行的shell 指令碼:

%pre 在安裝包之前執行

%post 在安裝包之後執行

%preun 在解除安裝包之前執行

%postun 在解除安裝包之後執行

尤其要注意%install與這些節之間的差異。構建RPM 時,%install 在開發機器上執行;它應該將產品安裝在開發機器上或安裝到一個構建根目錄中。另一方面,這些節指定當使用者正在安裝或解除安裝RPM包時將在使用者的機器上執行什麼。

一種好的技術是使用%pre指令碼來檢查安裝前提條件,它們比RPM可以直接支援的更復雜。 如果不符合前提條件,那麼指令碼以非零狀態退出,而且 RPM 不會繼續安裝。另外請注意,我們必須小心地使用解除安裝指令碼來撤銷安裝指令碼。

然而實際上沒有那麼簡單:升級使每件事情都變得複雜,現在,讓我們著手升級。如果使用者只安裝和刪除自己的包,那麼前面的指令將正常工作;但在升級期間,它們會完全失效。以下是 RPM 如何執行升級:

執行新包的 %pre

安裝新檔案

執行新包的 %post

執行舊包的 %preun

刪除新檔案未覆蓋的所有舊檔案

執行舊包的 %postun

如果我們使用5.3.2系列中現有SPEC檔案中的指令碼來升級,那麼RPM最後將執行 %postun 指令碼,它將除去我們在安裝指令碼中所做的所有工作。

rpm為了解決此問題,在其英文文件中提到了可以向指令碼來傳遞一個引數$1,這個引數傳遞的過程是隱藏的,你只需在%pre,%post,%preun,%postun中使用$1即可($1在shell中就是第一個引數的意思)。這個引數的含義是在執行完此次操作後系統中此軟體包的剩餘數量是多少,就目前我的理解應該只有0,1,2三種可能。

       1.在執行rpm –ivh的安裝過程中,如果有同類包存在,則會報錯提示無法安裝,存在相同的檔案。如果沒有同類包存在則會執行安裝動作,過程如下:

執行新包的%pre $1=1

安裝新檔案

執行新包的%post $1=1

       2.在執行rpm –U的升級過程中,如果沒有同類低階包存在,則過程和傳遞的引數與安裝時完全相同,如果有同類低階包存在則會執行升級操作,過程如下:

執行新包的%pre $1=2

安裝新檔案

執行新包的%post $1=2

執行舊包的%preun $1=1

刪除新檔案未覆蓋的任何舊檔案

執行舊包的%postun $1=1

       3.在執行rpm –e的刪除過程如下:

執行舊包的%preun $1=0

刪除檔案

執行舊包的%postun $1=0

因此我們可以用傳遞的引數來判斷rpm究竟在進行什麼工作,來在指令碼內部通過$1進行判斷來決定進行什麼動作。例如在引數為0的時候才真的執行解除安裝所要進行的動作。

另外在升級的時候,除了注意幾個指令碼的執行順序與結果外,還要注意配置檔案的處理是否正確,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),同時安裝新檔案,並給出警告資訊。

6. 當沒有原檢查和時:

此種情況下,當前檢查和與新檢查和已無關緊要,這表明沒有安裝過此配置檔案。因為沒有安裝過此配置檔案,所以RPM無法判斷當前檔案是否被使用者修改過。這種情況下,RPM會將當前檔案換名儲存(原檔名字尾不是加個.rpmsave,而是.rpmorig),同時安裝新檔案,並給出警告資訊。

因此在%files中可以用%config欄位將配置檔案標識出來,這樣在升級的過程中配置檔案將被按照上面所描述的方法處理。

%config 檔案路徑的形式來新增。

三、總結

(2)rpm和rpmbuild內容眾多豐富,該部落格總結部分內容,以便使用時能快速查詢到。

(3)讀者想溝通交流的,可發信息到郵箱[email protected]