选择显示字体大小

构造linux的图形化安装程序(4)(1)

本文主要包括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------------------不进行操作系统兼容性测试




  


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons