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.rpm(your-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 ,可以在自己的系统中找到。

[root@localhost 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 <kbsingh@centos.org> - 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 文件路径的形式来添加。

三、总结

(1)IBM官方网站中rpm包的使用讲解的很全面,参看http://www.ibm.com/developerworks/cn/linux/management/package/rpm/part1/和rpmbuild的spec文件的解析参看http://www.ibm.com/developerworks/cn/linux/l-rpm/。也可参考http://blog.chinaunix.net/uid-23069658-id-3944462.html

(2)rpm和rpmbuild内容众多丰富,该博客总结部分内容,以便使用时能快速查找到。

(3)若有读者想沟通交流的,可发信息到邮箱yang.ao@i-soft.com.cn。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦2号

博文不易,支持的请给予小小打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值