2006年01月13日

一种新的应用程序形式。他的特点:



  • 保证最新,每次启动时检查新版本;

  • 可以脱机工作;

  • 安全,访问本地资源会有提示;

我现在正在学习。

2006年01月12日

看了看,从3月份开始,就一直没有斗牛。


其间,我更多的时间在设计一个个人Blog程序,调试Linux,处理蒙古文。就是这些,累得实在是懒得说话,更别提写博了。


从现在开始,年底考核结束,快过年了,我也放松放松。


这片是我用爱搞搞客户端写的一个博,算作测试吧。

2005年03月11日

装载了j2sdk后,swing窗口不能显示汉字,网上查询了2天!!!,也没有找到合适的解决方法。后来,就在刹那间,swing突然显示出汉字了!
总结了一下:
1.到Windows系统下font文件夹找到simsun.ttc拷贝到/usr/share/fonts/zh_CN/TrueType/目录;
2.找到JAVA_HOME/jre/lib/font.properties.zh_CN.Redhat,打开,找到最后一行
filename.-misc-zysong18030-medium-r-normal–*-%d-*-*-c-*-iso10646-1=/usr/share/fonts/zh_CN/TrueType/gbsn00lp.ttf
改成
filename.-misc-zysong18030-medium-r-normal–*-%d-*-*-c-*-iso10646-1=/usr/share/fonts/zh_CN/TrueType/simsun.ttc
另存为font.properties.zh_CN;保存退出。
3.起动Mozilla浏览器,找到工具栏“工具”──》“Web开发”──》“Java控制台”;看到汉字了吧!

2005年03月02日

CNET科技资讯网3月2日国际报道 一年多前,许多人认为Eclipse 开放源代码计划不过是IBM 用来销售自家软件的手段之一。但现在,这个计划已经成了Java工具产业的创
新源头。

本周一开罗的EclipseCon大会门票全数销售一空,跟去年不同的是,在开幕大会上,IBM 的技术大师们将不再是主角。取而代之的,这种
开源码基金会将会亮出最新加入的董事成员,包括IBM 对手BEA 、Sybase与Borland,并详细说明Eclipse 手头上越来越多的开发专案细
节。

“Eclipse 绝对是当今主流的Java工具平台。”Meta集团分析师Thomas Murphy。“未来Eclipse 组织也会不断大力倡导这种通用型的平台。”

IBM 是在2001年以4000万美元种子基金成立Eclipse 联盟,并且捐赠了不少源代码。如今,该组织有91个会员,包含许多全球最大的软件
商。根据Evans Data公司的信息,Eclipse 是目前最受欢迎的Java开发工具。

Eclipse 是在一年前从IBM 分出,独立成非盈利组织。独立之后它反而增长得更好,以往不愿入会的厂商,比如BEA ,都纷纷加入。

实际上,Eclipse 几乎统合了绝大部分的Java供应商,唯一比较明显的例外是Sun 没加入,而甲骨文的参与度则不太高。但这样的成就已
经足以让先前多年的产业标准化作为大大汗颜。

“大势底定。”开放源代码Java厂商JBoss 策略副总裁Bob Bickel表示,他所指的正式Java工具产业的竞争已经结束了。

“Eclipse 刚刚好过了关键多数(critical mass)的阶段,厂商们乐于不用背负开发新工具的成本。”他表示。

详细内容见http://www.zdnet.com.cn/news/softwares/story/0,3800055189,39352020,00.htm

2004年12月30日
作者:未知 来源:未知 加入时间:2004-8-24 天新软件园
一、安装篇

  jspSmartUpload是由www.jspsmart.com网站开发的一个可免费使用的全功能的文件上传下载组件,适于嵌入执行上传下载操作的JSP文件中。该组件有以下几个特点:

1、使用简单。在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载,方便。

2、能全程控制上传。利用jspSmartUpload组件提供的对象及其操作方法,可以获得全部上传文件的信息(包括文件名,大小,类型,扩展名,文件数据等),方便存取。

3、能对上传的文件在大小、类型等方面做出限制。如此可以滤掉不符合要求的文件。

4、下载灵活。仅写两行代码,就能把Web服务器变成文件服务器。不管文件在Web服务器的目录下或在其它任何目录下,都可以利用jspSmartUpload进行下载。

5、能将文件上传到数据库中,也能将数据库中的数据下载下来。这种功能针对的是MYSQL数据库,因为不具有通用性,所以本文不准备举例介绍这种用法。

  jspSmartUpload组件可以从www.jspsmart.com网站上自由下载,压缩包的名字是jspSmartUpload.zip。下载后,用WinZip或WinRAR将其解压到Tomcat的webapps目录下(本文以Tomcat服务器为例进行介绍)。解压后,将webapps/jspsmartupload目录下的子目录Web-inf名字改为全大写的WEB-INF,这样一改jspSmartUpload类才能使用。因为Tomcat对文件名大小写敏感,它要求Web应用程序相关的类所在目录为WEB-INF,且必须是大写。接着重新启动Tomcat,这样就可以在JSP文件中使用jspSmartUpload组件了。

  注意,按上述方法安装后,只有webapps/jspsmartupload目录下的程序可以使用jspSmartUpload组件,如果想让Tomcat服务器的所有Web应用程序都能用它,必须做如下工作:

1.进入命令行状态,将目录切换到Tomcat的webapps/jspsmartupload/WEB-INF目录下。

2.运行JAR打包命令:jar cvf jspSmartUpload.jar com

(也可以打开资源管理器,切换到当前目录,用WinZip将com目录下的所有文件压缩成jspSmartUpload.zip,然后将jspSmartUpload.zip换名为jspSmartUpload.jar文件即可。)

3.将jspSmartUpload.jar拷贝到Tomcat的shared/lib目录下。

二、相关类说明篇

㈠ File类

  这个类包装了一个上传文件的所有信息。通过它,可以得到上传文件的文件名、文件大小、扩展名、文件数据等信息。

  File类主要提供以下方法:

1、saveAs作用:将文件换名另存。

原型:

public void saveAs(java.lang.String destFilePathName)



public void saveAs(java.lang.String destFilePathName, int optionSaveAs)

其中,destFilePathName是另存的文件名,optionSaveAs是另存的选项,该选项有三个值,分别是SAVEAS_PHYSICAL,SAVEAS_VIRTUAL,SAVEAS_AUTO。SAVEAS_PHYSICAL表明以操作系统的根目录为文件根目录另存文件,SAVEAS_VIRTUAL表明以Web应用程序的根目录为文件根目录另存文件,SAVEAS_AUTO则表示让组件决定,当Web应用程序的根目录存在另存文件的目录时,它会选择SAVEAS_VIRTUAL,否则会选择SAVEAS_PHYSICAL。

例如,saveAs(“/upload/sample.zip”,SAVEAS_PHYSICAL)执行后若Web服务器安装在C盘,则另存的文件名实际是c:\upload\sample.zip。而saveAs(“/upload/sample.zip”,SAVEAS_VIRTUAL)执行后若Web应用程序的根目录是webapps/jspsmartupload,则另存的文件名实际是webapps/jspsmartupload/upload/sample.zip。saveAs(“/upload/sample.zip”,SAVEAS_AUTO)执行时若Web应用程序根目录下存在upload目录,则其效果同saveAs(“/upload/sample.zip”,SAVEAS_VIRTUAL),否则同saveAs(“/upload/sample.zip”,SAVEAS_PHYSICAL)。

建议:对于Web程序的开发来说,最好使用SAVEAS_VIRTUAL,以便移植。

2、isMissing

作用:这个方法用于判断用户是否选择了文件,也即对应的表单项是否有值。选择了文件时,它返回false。未选文件时,它返回true。

原型:public boolean isMissing()

3、getFieldName

作用:取HTML表单中对应于此上传文件的表单项的名字。

原型:public String getFieldName()

4、getFileName

作用:取文件名(不含目录信息)

原型:public String getFileName()

5、getFilePathName

作用:取文件全名(带目录)

原型:public String getFilePathName

6、getFileExt

作用:取文件扩展名(后缀)

原型:public String getFileExt()

7、getSize

作用:取文件长度(以字节计)

原型:public int getSize()

8、getBinaryData

作用:取文件数据中指定位移处的一个字节,用于检测文件等处理。

原型:public byte getBinaryData(int index)。其中,index表示位移,其值在0到getSize()-1之间。

㈡ Files类

  这个类表示所有上传文件的集合,通过它可以得到上传文件的数目、大小等信息。有以下方法:

1、getCount

作用:取得上传文件的数目。

原型:public int getCount()

2、getFile

作用:取得指定位移处的文件对象File(这是com.jspsmart.upload.File,不是java.io.File,注意区分)。

原型:public File getFile(int index)。其中,index为指定位移,其值在0到getCount()-1之间。

3、getSize

作用:取得上传文件的总长度,可用于限制一次性上传的数据量大小。

原型:public long getSize()

4、getCollection

作用:将所有上传文件对象以Collection的形式返回,以便其它应用程序引用,浏览上传文件信息。

原型:public Collection getCollection()

5、getEnumeration

作用:将所有上传文件对象以Enumeration(枚举)的形式返回,以便其它应用程序浏览上传文件信息。

原型:public Enumeration getEnumeration()

㈢ Request类

  这个类的功能等同于JSP内置的对象request。只所以提供这个类,是因为对于文件上传表单,通过request对象无法获得表单项的值,必须通过jspSmartUpload组件提供的Request对象来获取。该类提供如下方法:

1、getParameter

作用:获取指定参数之值。当参数不存在时,返回值为null。

原型:public String getParameter(String name)。其中,name为参数的名字。

2、getParameterValues

作用:当一个参数可以有多个值时,用此方法来取其值。它返回的是一个字符串数组。当参数不存在时,返回值为null。

原型:public String[] getParameterValues(String name)。其中,name为参数的名字。

3、getParameterNames

作用:取得Request对象中所有参数的名字,用于遍历所有参数。它返回的是一个枚举型的对象。

原型:public Enumeration getParameterNames()

㈣ SmartUpload类这个类完成上传下载工作。

A.上传与下载共用的方法:

只有一个:initialize。

作用:执行上传下载的初始化工作,必须第一个执行。

原型:有多个,主要使用下面这个:

public final void initialize(javax.servlet.jsp.PageContext pageContext)

其中,pageContext为JSP页面内置对象(页面上下文)。

B.上传文件使用的方法:

1、upload

作用:上传文件数据。对于上传操作,第一步执行initialize方法,第二步就要执行这个方法。

原型:public void upload()

2、save

作用:将全部上传文件保存到指定目录下,并返回保存的文件个数。

原型:public int save(String destPathName)

和public int save(String destPathName,int option)

其中,destPathName为文件保存目录,option为保存选项,它有三个值,分别是SAVE_PHYSICAL,SAVE_VIRTUAL和SAVE_AUTO。(同File类的saveAs方法的选项之值类似)SAVE_PHYSICAL指示组件将文件保存到以操作系统根目录为文件根目录的目录下,SAVE_VIRTUAL指示组件将文件保存到以Web应用程序根目录为文件根目录的目录下,而SAVE_AUTO则表示由组件自动选择。

注:save(destPathName)作用等同于save(destPathName,SAVE_AUTO)。

3、getSize

作用:取上传文件数据的总长度

原型:public int getSize()

4、getFiles

作用:取全部上传文件,以Files对象形式返回,可以利用Files类的操作方法来获得上传文件的数目等信息。

原型:public Files getFiles()

5、getRequest

作用:取得Request对象,以便由此对象获得上传表单参数之值。

原型:public Request getRequest()

6、setAllowedFilesList

作用:设定允许上传带有指定扩展名的文件,当上传过程中有文件名不允许时,组件将抛出异常。

原型:public void setAllowedFilesList(String allowedFilesList)

其中,allowedFilesList为允许上传的文件扩展名列表,各个扩展名之间以逗号分隔。如果想允许上传那些没有扩展名的文件,可以用两个逗号表示。例如:setAllowedFilesList(“doc,txt,,”)将允许上传带doc和txt扩展名的文件以及没有扩展名的文件。

7、setDeniedFilesList

作用:用于限制上传那些带有指定扩展名的文件。若有文件扩展名被限制,则上传时组件将抛出异常。

原型:public void setDeniedFilesList(String deniedFilesList)

其中,deniedFilesList为禁止上传的文件扩展名列表,各个扩展名之间以逗号分隔。如果想禁止上传那些没有扩展名的文件,可以用两个逗号来表示。例如:setDeniedFilesList(“exe,bat,,”)将禁止上传带exe和bat扩展名的文件以及没有扩展名的文件。

8、setMaxFileSize

作用:设定每个文件允许上传的最大长度。

原型:public void setMaxFileSize(long maxFileSize)

其中,maxFileSize为为每个文件允许上传的最大长度,当文件超出此长度时,将不被上传。

9、setTotalMaxFileSize

作用:设定允许上传的文件的总长度,用于限制一次性上传的数据量大小。

原型:public void setTotalMaxFileSize(long totalMaxFileSize)

其中,totalMaxFileSize为允许上传的文件的总长度。

C.下载文件常用的方法

1、setContentDisposition

作用:将数据追加到MIME文件头的CONTENT-DISPOSITION域。jspSmartUpload组件会在返回下载的信息时自动填写MIME文件头的CONTENT-DISPOSITION域,如果用户需要添加额外信息,请用此方法。

原型:public void setContentDisposition(String contentDisposition)

其中,contentDisposition为要添加的数据。如果contentDisposition为null,则组件将自动添加”attachment;”,以表明将下载的文件作为附件,结果是IE浏览器将会提示另存文件,而不是自动打开这个文件(IE浏览器一般根据下载的文件扩展名决定执行什么操作,扩展名为doc的将用word程序打开,扩展名为pdf的将用acrobat程序打开,等等)。

2、downloadFile

作用:下载文件。

原型:共有以下三个原型可用,第一个最常用,后两个用于特殊情况下的文件下载(如更改内容类型,更改另存的文件名)。

① public void downloadFile(String sourceFilePathName)

其中,sourceFilePathName为要下载的文件名(带目录的文件全名)

② public void downloadFile(String sourceFilePathName,String contentType)

其中,sourceFilePathName为要下载的文件名(带目录的文件全名),contentType为内容类型(MIME格式的文件类型信息,可被浏览器识别)。

③ public void downloadFile(String sourceFilePathName,String contentType,String destFileName)

其中,sourceFilePathName为要下载的文件名(带目录的文件全名),contentType为内容类型(MIME格式的文件类型信息,可被浏览器识别),destFileName为下载后默认的另存文件名。

三、文件上传篇

㈠ 表单要求

对于上传文件的FORM表单,有两个要求:

1、METHOD应用POST,即METHOD=”POST”。

2、增加属性:ENCTYPE=”multipart/form-data”

下面是一个用于上传文件的FORM表单的例子:

<FORM METHOD=”POST” ENCTYPE=”multipart/form-data”
ACTION=”/jspSmartUpload/upload.jsp”>
<INPUT TYPE=”FILE” NAME=”MYFILE”>
<INPUT TYPE=”SUBMIT”>
</FORM>



㈡ 上传的例子

1、上传页面upload.html

本页面提供表单,让用户选择要上传的文件,点击”上传”按钮执行上传操作。

页面源码如下:

<!–
    文件名:upload.html
作  者:纵横软件制作中心雨亦奇(zhsoft88@sohu.com)
–>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>
<head>
<title>文件上传</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″>
</head>

<body>
<p>&nbsp;</p>
<p align=”center”>上传文件选择</p>
<FORM METHOD=”POST” ACTION=”jsp/do_upload.jsp”
ENCTYPE=”multipart/form-data”>
<input type=”hidden” name=”TEST” value=”good”>
  <table width=”75%” border=”1″ align=”center”>
    <tr>
      <td><div align=”center”>1、
          <input type=”FILE” name=”FILE1″ size=”30″>
        </div></td>
    </tr>
    <tr>
      <td><div align=”center”>2、
          <input type=”FILE” name=”FILE2″ size=”30″>
        </div></td>
    </tr>
    <tr>
      <td><div align=”center”>3、
          <input type=”FILE” name=”FILE3″ size=”30″>
        </div></td>
    </tr>
    <tr>
      <td><div align=”center”>4、
          <input type=”FILE” name=”FILE4″ size=”30″>
        </div></td>
    </tr>
    <tr>
      <td><div align=”center”>
          <input type=”submit” name=”Submit” value=”上传它!”>
        </div></td>
    </tr>
  </table>
</FORM>
</body>
</html>



2、上传处理页面do_upload.jsp

本页面执行文件上传操作。页面源码中详细介绍了上传方法的用法,在此不赘述了。

页面源码如下:

<%–
文件名:do_upload.jsp
作  者:纵横软件制作中心雨亦奇(zhsoft88@sohu.com)
–%>
<%@ page contentType=”text/html; charset=gb2312″ language=”java”
import=”java.util.*,com.jspsmart.upload.*” errorPage=”" %>
<html>
<head>
<title>文件上传处理页面</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″>
</head>

<body>
<%
// 新建一个SmartUpload对象
SmartUpload su = new SmartUpload();
// 上传初始化
su.initialize(pageContext);
// 设定上传限制
// 1.限制每个上传文件的最大长度。
// su.setMaxFileSize(10000);
// 2.限制总上传数据的长度。
// su.setTotalMaxFileSize(20000);
// 3.设定允许上传的文件(通过扩展名限制),仅允许doc,txt文件。
// su.setAllowedFilesList(“doc,txt”);
// 4.设定禁止上传的文件(通过扩展名限制),禁止上传带有exe,bat,
jsp,htm,html扩展名的文件和没有扩展名的文件。
// su.setDeniedFilesList(“exe,bat,jsp,htm,html,,”);
// 上传文件
su.upload();
// 将上传文件全部保存到指定目录
int count = su.save(“/upload”);
out.println(count+”个文件上传成功!<br>”);

// 利用Request对象获取参数之值
out.println(“TEST=”+su.getRequest().getParameter(“TEST”)
+”<BR><BR>”);

// 逐一提取上传文件信息,同时可保存文件。
for (int i=0;i<su.getFiles().getCount();i++)
{
com.jspsmart.upload.File file = su.getFiles().getFile(i);

// 若文件不存在则继续
if (file.isMissing()) continue;

// 显示当前文件信息
out.println(“<TABLE BORDER=1>”);
out.println(“<TR><TD>表单项名(FieldName)</TD><TD>”
+ file.getFieldName() + “</TD></TR>”);
out.println(“<TR><TD>文件长度(Size)</TD><TD>” +
file.getSize() + “</TD></TR>”);
out.println(“<TR><TD>文件名(FileName)</TD><TD>”
+ file.getFileName() + “</TD></TR>”);
out.println(“<TR><TD>文件扩展名(FileExt)</TD><TD>”
+ file.getFileExt() + “</TD></TR>”);
out.println(“<TR><TD>文件全名(FilePathName)</TD><TD>”
+ file.getFilePathName() + “</TD></TR>”);
out.println(“</TABLE><BR>”);

// 将文件另存
// file.saveAs(“/upload/” + myFile.getFileName());
// 另存到以WEB应用程序的根目录为文件根目录的目录下
// file.saveAs(“/upload/” + myFile.getFileName(),
su.SAVE_VIRTUAL);
// 另存到操作系统的根目录为文件根目录的目录下
// file.saveAs(“c:\\temp\\” + myFile.getFileName(),
su.SAVE_PHYSICAL);

}
%>
</body>
</html>



四、文件下载篇

1、下载链接页面download.html

页面源码如下:

<!–
文件名:download.html
作  者:纵横软件制作中心雨亦奇(zhsoft88@sohu.com)
–>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>
<head>
<title>下载</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″>
</head>
<body>
<a href=”jsp/do_download.jsp”>点击下载</a>
</body>
</html>



2、下载处理页面do_download.jsp do_download.jsp展示了如何利用jspSmartUpload组件来下载文件,从下面的源码中就可以看到,下载何其简单。

源码如下:

<%@ page contentType=”text/html;charset=gb2312″
import=”com.jspsmart.upload.*” %><%
// 新建一个SmartUpload对象
SmartUpload su = new SmartUpload();
// 初始化
su.initialize(pageContext);
// 设定contentDisposition为null以禁止浏览器自动打开文件,
//保证点击链接后是下载文件。若不设定,则下载的文件扩展名为
//doc时,浏览器将自动用word打开它。扩展名为pdf时,
//浏览器将用acrobat打开。
su.setContentDisposition(null);
// 下载文件
su.downloadFile(“/upload/如何赚取我的第一桶金.doc”);
%>



注意,执行下载的页面,在Java脚本范围外(即<% … %>之外),不要包含HTML代码、空格、回车或换行等字符,有的话将不能正确下载。不信的话,可以在上述源码中%><%之间加入一个换行符,再下载一下,保证出错。因为它影响了返回给浏览器的数据流,导致解析出错。

3、如何下载中文文件

jspSmartUpload虽然能下载文件,但对中文支持不足。若下载的文件名中有汉字,则浏览器在提示另存的文件名时,显示的是一堆乱码,很扫人兴。上面的例子就是这样。(这个问题也是众多下载组件所存在的问题,很少有人解决,搜索不到相关资料,可叹!)

为了给jspSmartUpload组件增加下载中文文件的支持,我对该组件进行了研究,发现对返回给浏览器的另存文件名进行UTF-8编码后,浏览器便能正确显示中文名字了。这是一个令人高兴的发现。于是我对jspSmartUpload组件的SmartUpload类做了升级处理,增加了toUtf8String这个方法,改动部分源码如下:

public void downloadFile(String s, String s1, String s2, int i)
throws ServletException, IOException, SmartUploadException
    {
if(s == null)
    throw new IllegalArgumentException(“File ‘” + s +
    ”‘ not found (1040).”);
if(s.equals(“”))
    throw new IllegalArgumentException(“File ‘” + s +
    ”‘ not found (1040).”);
if(!isVirtual(s) && m_denyPhysicalPath)
    throw new SecurityException(“Physical path is
    denied (1035).”);
if(isVirtual(s))
    s = m_application.getRealPath(s);
java.io.File file = new java.io.File(s);
FileInputStream fileinputstream = new FileInputStream(file);
long l = file.length();
boolean flag = false;
int k = 0;
byte abyte0[] = new byte[i];
if(s1 == null)
    m_response.setContentType(“application/x-msdownload”);
else
if(s1.length() == 0)
    m_response.setContentType(“application/x-msdownload”);
else
    m_response.setContentType(s1);
m_response.setContentLength((int)l);
m_contentDisposition = m_contentDisposition != null ?
m_contentDisposition : “attachment;”;
if(s2 == null)
    m_response.setHeader(“Content-Disposition”,
    m_contentDisposition + ” filename=” +
    toUtf8String(getFileName(s)));
else
if(s2.length() == 0)
    m_response.setHeader(“Content-Disposition”,
    m_contentDisposition);
else
    m_response.setHeader(“Content-Disposition”,
    m_contentDisposition + ” filename=” + toUtf8String(s2));
while((long)k < l)
{
    int j = fileinputstream.read(abyte0, 0, i);
    k += j;
    m_response.getOutputStream().write(abyte0, 0, j);
}
fileinputstream.close();
    }

    /**
     * 将文件名中的汉字转为UTF8编码的串,以便下载时能正确显示另存的文件名.
     * 纵横软件制作中心雨亦奇2003.08.01
     * @param s 原文件名
     * @return 重新编码后的文件名
     */
    public static String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i=0;i<s.length();i++) {
    char c = s.charAt(i);
    if (c >= 0 && c <= 255) {
sb.append(c);
    } else {
byte[] b;
try {
    b = Character.toString(c).getBytes(“utf-8″);
} catch (Exception ex) {
    System.out.println(ex);
    b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
    int k = b[j];
    if (k < 0) k += 256;
    sb.append(“%” + Integer.toHexString(k).
    toUpperCase());
}
    }
}
return sb.toString();
    }



注意源码中粗体部分,原jspSmartUpload组件对返回的文件未作任何处理,现在做了编码的转换工作,将文件名转换为UTF-8形式的编码形式。UTF-8编码对英文未作任何处理,对中文则需要转换为%XX的形式。toUtf8String方法中,直接利用Java语言提供的编码转换方法获得汉字字符的UTF-8编码,之后将其转换为%XX的形式。

将源码编译后打包成jspSmartUpload.jar,拷贝到Tomcat的shared/lib目录下(可为所有WEB应用程序所共享),然后重启Tomcat服务器就可以正常下载含有中文名字的文件了。另,toUtf8String方法也可用于转换含有中文的超级链接,以保证链接的有效,因为有的WEB服务器不支持中文链接。

小结:jspSmartUpload组件是应用JSP进行B/S程序开发过程中经常使用的上传下载组件,它使用简单,方便。现在我又为其加上了下载中文名字的文件的支持,真个是如虎添翼,必将赢得更多开发者的青睐。

2004年12月28日

中午,阿姨说上午一个不认识女人打电话找我,她告诉她中午打电话过来。

中午,果然,有电话来,电话号码同上午的一样。一个细声细气的家伙,在电话那头自称是lenovo的电话调查工作人员,要对我电话调查,考虑到我的lenovo的印象还不错,我就爽快地答应了。

我一开始抱着儿子,我打电话,儿子玩久违了的电话线。儿子玩腻了,电话还在进行中,阿姨抱过去,逗儿子玩,电话还在继续,儿子困了,阿姨哄儿子睡觉,儿子睡着了,电话还没完,我也火了,发了两次火,调查仍然在延续……

我的天啊,这就是我一向敬重的lenovo的电话调查!

而且还找了个分不清“二”“爱”、“十”“四”的大舌头!

简直是没法忍受!

2004年11月25日

该死的jive,整整折腾了我一个星期。最后,总算搞定。
下面,我对jive配置做一个详细地说明:
1.安装Jdk.
到Java老家Sun取下载一份Jdk,现在最高版本是j2sdk1.5,下载一份j2sdk1.4.2即可。如果下载的是Windows下的安装程序。就更省事了,双击,一路Next,直至安装完毕。
然后,设置环境变量Path=[Java_Home]/bin;
相关资料网上很多,不熟悉就到网上找一份。
2.安装resin。
resin是一款简单易用的Java服务器,现在最高版本是3.09,高版本对Jdk的要求也很高,下载个一般版本即可,如resin2.1.13。原程序是一个压缩文件,解压即可。假如解压到C:/resin2.1.13,进入resin/bin,会发现有一个httpd.exe文件,图标看起来像一只蜻蜓,就是他了。双击,会启动两个Dos窗口,一个上面标有“启动”和“关闭”,另一个显示的是Resin的启动信息。
不出意外的话,Resin将正常运行,端口是8080,也就是说,在地址栏内键入:
http://localhost:8080/
将显示默认的index.xtp页面,那么,恭喜你了,你的Java服务器正常运行了。
3.Jive就不多说了,他是现在互联网上比较成熟的一个商用Jsp论坛应用程序。可以的话,当然鼓励你付费使用Jive了,这样,也就不会像我似的,为找到一个适合的版本,累死累活,网上狂搜,找到之后,安装又不顺利,不敢奢想售后,只能自己瞎捉摸了。
言归正传。在resin目录下有一个webapps目录,这个目录就是Caucho公司设计专门用来发布war应用程序的。我们就用这个目录。
我用的jive是jive_forums_ent_3_1_3,目录结构如下
jive_forums_ent_3_1_3
———————database[数据库文件]
———————documentation[安装帮助说明]
———————jive3[jive应用程序]
———————jiveHome[jive配置文件]
———————resources[其他一些skin等可选资源]
另外,这里还有changelog,issues,readme,MakeWAR.jar文件。


第一步,你可以把整个jive3目录拷贝到webapps中,或者,使用上面的MakeWAR.jar工具把jive3打包jive3.war,然后拷贝jive3.war到webapps下,其效果同上。。
第二步,启动resin,resin会自动发布jive3,然后提示你没有设置jiveHome。既然没有设置jiveHome,我们接下来就设置他。
第三步,拷贝jiveHome目录到任何你想放的地方,但通常不放到能够通过http访问到的地方,因为这是jive的秘密,也是你的秘密。如果你愿意,当然也可以。我放到jive3/web-inf里,因为web-inf是禁止访问的。记下jiveHome的绝对路径(如:C:/resin/webapps/jive3/web-inf/jiveHome),找到jive3/web-inf/classes/jive_init.xml,编辑他,找到<jiveHome></jiveHome>,中间加上jiveHome的路径,如:<jiveHome>C:/resin/webapps/jive3/web-inf/jiveHome</jiveHome>,jiveHome设置完毕。
第四步,关闭resin。
4.安装数据库。我以MySQL为例。
www.mysql.com下载一份新的MySQL软件,安装。
安装成功后,到mysql/bin目录下有一个mysqladmin工具,运行,如果绿灯亮了,说明mysql安装成功。
MySQL的管理操作界面不是太友好,你可以下在一个辅助工具,我下了一个mysql-Front,打开,建立jive数据库,到database中找到对应的数据库数据文件,导入。
最新的MySQL的JDBC驱动是mysql-connector-java-3.0.15-ga-bin,找到,复制到jive/web-inf/lib下,待用。
5.破解license。
启动resin。键入http://localhost:8080/jive3/admin/setup/
如果一切正常,将出现jive的安装界面,在第一个安装界面的最下面一项是license,要求你输入license,随便输入几个字,然后保存。
//一定要注意:破解须在服务器关闭时,否则,因为,服务器正在使用jivebase.jar,破解无效。
关闭服务器。
这里有一个破解软件包crack,内有patcher.jar,拷贝到jive3/web-inf/lib下。
开始-运行-cmd
将出现Dos窗口。切换到jive/web-inf/lib下,执行
java -jar patcher.jar
……jivebase.jar;
Done.
破解完毕。
重新启动resin。如果还要license,进入jive/web-inf/work目录,删除所有文件。重新启动resin。
试吧。
终会成功的。
6.相关配置。
数据库配置,mysql的数据库配置是http://localhost:3806/jive
邮件服务器没有则Skip,管理员密码Skip。
最后进入adminstrator tool。
7.汉文配置。
管理员工具中local setting中local选择中国,市区选Asia ShangHai,语言编码选择UTF-8;退出管理员。
拷贝jive_forums_i18n_zh.properties文件到jive/web-inf/classes下。
进入jiveHome目录,找到jive_config.xml,编辑。
找到
<database>
<defaultProvider>
<driver>com.mysql.jdbc.Driver</driver>
<serverURL>jdbc:mysql://localhost:3306/jive</serverURL>
<username>root</username>
<password>hfl</password>
<minConnections>5</minConnections>
<maxConnections>15</maxConnections>
<connectionTimeout>1.0</connectionTimeout>
</defaultProvider>
</database>
变成
<database>
<defaultProvider>
<driver>com.mysql.jdbc.Driver</driver>
<serverURL>jdbc:mysql://localhost:3306/jive</serverURL>
<username>root</username>
<password>hfl</password>
<minConnections>5</minConnections>
<maxConnections>15</maxConnections>
<connectionTimeout>1.0</connectionTimeout>
</defaultProvider>
//加上如下代码
<mysql>
<useUnicode>true</useUnicode>
</mysql>
</database>
重新启动Resin。
it is OK.

2004年11月23日

vi 编辑器


一、Unix编辑器概述


编辑器是使用计算机的重要工具之一,在各种操作系统中,编辑器都是必不可少的部件。Unix及其相似的ix


操作系统系列中,为方便各种用户在各个不同的环境中使用,提供了一系列的ex编辑器,包括 ex, edit,ed 和


vi.其中ex,edit,ed都是行编辑器,现在已很少有人使用,Unix提供他们的原因是考虑到满足各种用户特别


是某些终端用户的需要。


值得庆幸的是,Unix提供了全屏幕的Vi编辑器,这使我们的工作轻松不少。不少DOS用户抱怨Vi编辑器不象


DOS下的编辑器如edit那么好用,这是因为Vi考虑到各种用户的需要,没有使用某些通用的编辑键(在各个


不同的终端机上他们的定义是不同的,在某些终端机上甚至没有这些键)。而是采用状态切换的方法,但这


只是习惯的问题,一旦你熟练的使用上了vi你就会觉得它其实也很好用。


虽然 Vi采用了状态切换的方法,但电脑的硬件及操作系统多种多样,某些电脑的键盘上没有特定的几个功


能键!那麽不就有某些功能不能用了?这个问题在 Unix 系统上也一样,几乎各大电脑厂商都有自己的


Unix 系统,而 vi 的操作方法也会随之有点出入。这里我们采用 PC 的键盘来说明 vi 的操作,但在具体


的环境中还要参考相应的资料,这一点是值得注意的。


二、Vi入门


(一)、进入vi


在系统提示字符(如$、#)下敲入vi <档案名称>,vi 可以自动帮你载入所要编辑的文件或是开启一个新


文件(如果该文件不存在或缺少文件名)。进入 vi 后萤幕左方会出现波浪符号,凡是列首有该符号就代


表此列目前是空的。


(二)、两种模式


如上所述,vi存在两种模式:指令模式和输入模式。在指令模式下输入的按键将做为指令来处理:如输入


a,vi即认为是在当前位置插入字符。而在输入模式下,vi则把输入的按键当作插入的字符来处理。指令


模式切换到输入模式只需键入相应的输入命令即可(如a,A),而要从输入模式切换到指令模式,则需在


输入模式下键入ESC键,如果不晓得现在是处於什麽模式,可以多按几次 [ESC],系统如发出哔哔声就表


示已处于指令模式下了。


付:有指令模式进入输入模式的指令:


新增 (append)


a :从光标所在位置後面开始新增资料,光标後的资料随新增资料向後移动。


A: 从光标所在列最後面的地方开始新增资料。


插入 (insert)


i: 从光标所在位置前面开始插入资料,光标後的资料随新增资料向後移动。


I :从光标所在列的第一个非空白字元前面开始插入资料。


开始 (open)


o :在光标所在列下新增一列并进入输入模式。


O: 在光标所在列上方新增一列并进入输入模式。


(三)、退出vi


在指令模式下键入:q,:q!,:wq或:x(注意:号),就会退出vi。其中:wq和:x是存盘退出,而:q是直接退出,


如果文件已有新的变化,vi会提示你保存文件而:q命令也会失效,这时你可以用:w命令保存文件后再用:q


退出,或用:wq或:x命令退出,如果你不想保存改变后的文件,你就需要用:q!命令,这个命令将不保存文件


而直接退出vi。


(四)、基本编辑


配合一般键盘上的功能键,像是方向键、[Insert] 、[Delete] 等等,


现在你应该已经可以利用 vi 来编辑文件


了。当然 vi 还提供其他许许多多功能让文字的处理更为方便。


何谓编辑?一般认为是文字的新增、修改以及删除,甚至包括文字区块的搬移、复制等等。先这里介绍 vi


的如何做删除与修改。(注意:在 vi 的原始观念里,输入跟编辑是两码子事。编辑是在指令模式下操作


的,先利用指令移动光标来定位要进行编辑的地方,然後才下指令做编辑。)


删除与修改文件的命令:


x: 删除光标所在字符。


dd :删除光标所在的列。


r :修改光标所在字元,r 後接著要修正的字符。


R: 进入取替换状态,新增文字会覆盖原先文字,直到按 [ESC] 回到指令模式下为止。


s: 删除光标所在字元,并进入输入模式。


S: 删除光标所在的列,并进入输入模式。


其实呢,在PC上根本没有这麽麻烦!输入跟编辑都可以在输入模式下完成。例如要删除字元,直接按

[Delete] 不就得了。而插入状态与取代状态可以直接用 [Insert] 切换,犯不著用什麽指令模式的编

辑指令。不过就如前面所提到的,这些指令几乎是每台终端机都能用,而不是仅仅在 PC 上。

在指令模式下移动光标的基本指令是 h, j, k, l 。想来各位现在也应该能猜到只要直接用 PC 的方向

键就可以了,而且无论在指令模式或输入模式下都可以。多容易不是。

当然 PC 键盘也有不足之处。有个很好用的指令 u 可以恢复被删除的文字,而 U 指令则可以恢复光标所

在列的所有改变。这与某些电脑上的 [Undo] 按键功能相同。

三、附件:vi详细指令表

(一)、基本编辑指令:

新增 (append)


a :从光标所在位置後面开始新增资料,光标後的资料随新增资料向後移动。


A: 从光标所在列最後面的地方开始新增资料。


插入 (insert)


i: 从光标所在位置前面开始插入资料,光标後的资料随新增资料向後移动。


I :从光标所在列的第一个非空白字元前面开始插入资料。


开始 (open)


o :在光标所在列下新增一列并进入输入模式。


O: 在光标所在列上方新增一列并进入输入模式。


x: 删除光标所在字符。


dd :删除光标所在的列。


r :修改光标所在字元,r 後接著要修正的字符。


R: 进入取替换状态,新增文字会覆盖原先文字,直到按 [ESC] 回到指令模式下为止。


s: 删除光标所在字元,并进入输入模式。


S: 删除光标所在的列,并进入输入模式。


(二)、光标移动指令:

由於许多编辑工作是藉由光标来定位,所以 vi 提供许多移动光标的方式,这个我们列

几张简表来说明(这些当然是指令模式下的指令):


指令? ?说明 ?????? 功能键

0 移动到光标所在列的最前面 [Home]?

$ ? 移动到光标所在列的最後面 [End]

[CTRL][d] 向下半页 ? [PageDown]

[CTRL][f] 向下一页

[CTRL][u] 向上半页?

[CTRL][b] 向上一页 [PageUp]



指令 说明

H 移动到视窗的第一列

M 移动到视窗的中间列

L 移动到视窗的最後列

b 移动到下个字的第一个字母

w 移动到上个字的第一个字母 ??

e 移动到下个字的最後一个字母

^ 移动到光标所在列的第一个非空白字元




指令 说明 ???

n- 减号移动到上一列的第一个非空白字元前面加上数字可以指定移动到以上 n 列

n+ 加号移动到下一列的第一个非空白字元前面加上数字可以指定移动到以下 n 列

nG 直接用数字 n 加上大写 G 移动到第 n 列

指令 说明

fx

往右移动到 x 字元上

Fx 往左移动到 x 字元上 ?

tx 往右移动到 x 字元前???

Tx 往左移动到 x 字元前

; 配合 f&t 使用,重复一次??

,?? 配合 f&t 使用,反方向重复一次

/string 往右移动到有 string 的地方

?string 往左移动到有 string 的地方

n ? 配合 /&? 使用,重复一次

N ? 配合 /&? 使用,反方向重复一次


指令 说明 ?备注

n(

左括号移动到句子的最前面句子是以前面加上数字可以指定往前移动 n 个句子 ! . ? 三种符号来界定

n)? 右括号移动到下个句子的最前面前面加上数字可以指定往後移动 n 个句子 ! . ? 三种符号来界定

n{ ?? 左括弧移动到段落的最前面 段落是以段落间的空白列界定

n} 前面加上数字可以指定往前移动 n 个段落右括弧移动到下个段落的最前面前面加上数字可以指定往後移动 n 个段落 段落是以段落间的空白列界定



(三)、更多的编辑指令

这些编辑指令非常有弹性,基本上可以说是由指令与范围所构成。例如 dw 是由删除指令 d 与范围 w 所

组成,代表删除一个字 d(elete) w(ord) 。

指令列表如下:

d 删除(delete)

y 复制(yank)

p 放置(put)

c 修改(change)

范围可以是下列几个:

e 光标所在位置到该字的最後一个字母

w 光标所在位置到下个字的第一个字母

b 光标所在位置到上个字的第一个字母

$ 光标所在位置到该列的最後一个字母

0 光标所在位置到该列的第一个字母

) 光标所在位置到下个句子的第一个字母

( 光标所在位置到该句子的第一个字母

} 光标所在位置到该段落的最後一个字母

{ 光标所在位置到该段落的第一个字母

说实在的,组合这些指令来编辑文件有一点点艺术气息。不管怎麽样,它们提供更多编辑文字的能力。值得

注意的一点是删除与复制都会将指定范围的内容放到暂存区里,然後就可以用指令 p 贴到其它地方去,这

是 vi 用来处理区段拷贝与搬移的办法。

某些 vi 版本,例如 linux 所用的 elvis 可以大幅简化这一坨指令。如果稍微观察一下这些编辑指令

就会发现问题其实是定范围的方式有点杂,实际上只有四个指令罢了。指令 v 非常好用,只要按下 v 键,

光标所在的位置就会反白,然後就可以移动光标来设定范围,接著再直接下指令进行编辑即可。

对於整列操作, vi 另外提供了更方便的编辑指令。前面曾经提到过删除整列文字的指令 dd 就是其中一个

;cc 可以修改整列文字;而 yy 则是复制整列文字;指令 D 则可以删除光标到该列结束为止所有的文字。

(四)、文件操作指令

文件操作指令多以 : 开头,这跟编辑指令有点区别。

:q 结束编辑(quit)

:q! 不存档而要放弃编辑过的文件。

:w 保存文件(write)其後可加所要存档的档名。

:wq 即存档後离开。

zz 功能与 :wq 相同。

:x 与:wq相同



mastering regular expressions http://www.wellho.net/book/1-56592-257-3.html Learning the vi Editor, 6th Edition http://www.ora.com/catalog/vi6/ VI命令可以说是Unix/linux世界里最常用的编辑文件的命令了,但是因为它的命令集众多,很多人都不习惯使用它,其实您只需要掌握基本命令,然后加以灵活运用,就会发现它的优势,并会逐渐喜欢使用这种方法。本文旨在介绍VI的一些最常用命令和高级应用技巧。


一、基本命令介绍


—- 1.光标命令


k、j、h、l——上、下、左、右光标移动命令。虽然您可以在linux中使用键盘右边的4个光标键,但是记住这4个命令还是非常有用的。这4个键正是右手在键盘上放置的基本位置。

nG——跳转命令。n为行数,该命令立即使光标跳到指定行。

Ctrl+G——光标所在位置的行数和列数报告。

w、b——使光标向前或向后跳过一个单词。


—- 2.编辑命令


i、a、r——在光标的前、后以及所在处插入字符命令(i=insert、a=append、r=replace)。

cw、dw——改变(置换)/删除光标所在处的单词的命令 (c=change、d=delete)。

x、d$、dd——删除一个字符、删除光标所在处到行尾的所有字符以及删除整行的命令。


—- 3.查找命令


—- /string、?string——从光标所在处向后或向前查找相应的字符串的命令。

—- 4.拷贝复制命令


—- yy、p——拷贝一行到剪贴板或取出剪贴板中内容的命令。


二、常见问题及应用技巧


—- 1.在一个新文件中读/etc/passwd中的内容,取出用户名部分。


—- vi file

—- :r /etc/passwd 在打开的文件file中光标所在处读入/etc/passwd

—- :%s/:.*//g 删除/etc/passwd中用户名后面的从冒号开始直到行尾的所有部分。

—- 您也可以在指定的行号后读入文件内容,例如使用命令“:3r /etc/passwd”从新文件的第3行开始读入 /etc/passwd的所有内容。

—- 我们还可以使用以下方法删掉文件中所有的空行及以#开始的注释行。

—- #cat squid.conf.default | grep -v ‘^$’ | grep -v ‘^#’


—- 2.在打开一个文件编辑后才知道登录的用户对该文件没有写的权限,不能存盘,需要将所做修改存入临时文件。


—- vi file

—- :w /tmp/1 保存所做的所有修改,也可以将其中的某一部分修改保存到临时文件,例如仅仅把第20~59行之间的内容存盘成文件/tmp/1,我们可以键入如下命令。

—- vi file

—- :20,59w /tmp/1


—- 3.用VI编辑一个文件,但需要删除大段的内容。


—- 首先利用编辑命令“vi file”打开文件,然后将光标移到需要删除的行处按Ctrl+G显示行号,再到结尾处再按Ctrl+G,显示文件结尾的行号。

—- :23,1045d 假定2次得到的行号为23和1045,则把这期间的内容全删除,也可以在要删除的开始行和结束行中用ma、mb命令标记,然后利用“:’a,’bd”命令删除。


—- 4.在整个文件的各行或某几行的行首或行尾加一些字符串。


—- vi file

—- :3,$s/^/some string / 在文件的第一行至最后一行的行首插入“some string”。

—- :%s/$/some string/g 在整个文件每一行的行尾添加“some string”。

—- :%s/string1/string2/g 在整个文件中替换“string1”成“string2”。

—- :3,7s/string1/string2/ 仅替换文件中的第3行到第7行中的“string1”成“string2”。

—- 注意: 其中s为substitute,%表示所有行,g表示global。


—- 5.同时编辑2个文件,拷贝一个文件中的文本并粘贴到另一个文件中。


—- vi file1 file2

—- yy 在文件1的光标处拷贝所在行

—- :n 切换到文件2 (n=next)

—- p 在文件2的光标所在处粘贴所拷贝的行

—- :n 切换回文件1


—- 6.替换文件中的路径。


—- 使用命令“:%s#/usr/bin#/bin#g”可以把文件中所有路径/usr/bin换成/bin。也可以使用命令“:%s/\/usr\/bin/\/bin/g”实现,其中“\”是转义字符,表明其后的“/”字符是具有实际意义的字符,不是分隔符。

一、安装


命令格式:

rpm -i ( or –install) options file1.rpm … fileN.rpm


参数:

file1.rpm … fileN.rpm 将要安装的RPM包的文件名


详细选项:

-h (or –hash) 安装时输出hash记号 (“#”)

–test 只对安装进行测试,并不实际安装。

–percent 以百分比的形式输出安装的进度。

–excludedocs 不安装软件包中的文档文件

–includedocs 安装文档

–replacepkgs 强制重新安装已经安装的软件包

–replacefiles 替换属于其它软件包的文件

–force 忽略软件包及文件的冲突

–noscripts 不运行预安装和后安装脚本

–prefix 将软件包安装到由 指定的路径下

–ignorearch 不校验软件包的结构

–ignoreos 不检查软件包运行的操作系统

–nodeps 不检查依赖性关系

–ftpproxy 用 作为 FTP代理

–ftpport 指定FTP的端口号为


通用选项


-v 显示附加信息

-vv 显示调试信息

–root 让RPM将指定的路径做为”根目录”,这样预安装程序和后安装程序都会安装到这个目录下

–rcfile 设置rpmrc文件为

–dbpath 设置RPM 资料库存所在的路径为


二、删除


命令格式:


rpm -e ( or –erase) options pkg1 … pkgN


参数


pkg1 … pkgN :要删除的软件包


详细选项


–test 只执行删除的测试

–noscripts 不运行预安装和后安装脚本程序

–nodeps 不检查依赖性


通用选项


-vv 显示调试信息

–root 让RPM将指定的路径做为”根目录”,这样预安装程序和后安装程序都会安装到这个目录下

–rcfile 设置rpmrc文件为

–dbpath 设置RPM 资料库存所在的路径为


三、升级


命令格式


rpm -U ( or –upgrade) options file1.rpm … fileN.rpm


参数


file1.rpm … fileN.rpm 软件包的名字


详细选项


-h (or –hash) 安装时输出hash记号 (“#”)

–oldpackage 允许”升级”到一个老版本

–test 只进行升级测试

–excludedocs 不安装软件包中的文档文件

–includedocs 安装文档

–replacepkgs 强制重新安装已经安装的软件包

–replacefiles 替换属于其它软件包的文件

–force 忽略软件包及文件的冲突

–percent 以百分比的形式输出安装的进度。

–noscripts 不运行预安装和后安装脚本

–prefix 将软件包安装到由 指定的路径下

–ignorearch 不校验软件包的结构

–ignoreos 不检查软件包运行的操作系统

–nodeps 不检查依赖性关系

–ftpproxy 用 作为 FTP代理

–ftpport 指定FTP的端口号为


通用选项


-v 显示附加信息

-vv 显示调试信息

–root 让RPM将指定的路径做为”根目录”,这样预安装程序和后安装程序都会安装到这个目录下

–rcfile 设置rpmrc文件为

–dbpath 设置RPM 资料库存所在的路径为


四、查询


命令格式:


rpm -q ( or –query) options


参数:


pkg1 … pkgN :查询已安装的软件包


详细选项


-p (or “-”) 查询软件包的文件

-f 查询属于哪个软件包

-a 查询所有安装的软件包

–whatprovides 查询提供了 功能的软件包

-g 查询属于 组的软件包

–whatrequires 查询所有需要 功能的软件包


信息选项


显示软件包的全部标识

-i 显示软件包的概要信息

-l 显示软件包中的文件列表

-c 显示配置文件列表

-d 显示文档文件列表

-s 显示软件包中文件列表并显示每个文件的状态

–scripts 显示安装、卸载、校验脚本

–queryformat (or –qf) 以用户指定的方式显示查询信息

–dump 显示每个文件的所有已校验信息

–provides 显示软件包提供的功能

–requires (or -R) 显示软件包所需的功能


通用选项


-v 显示附加信息

-vv 显示调试信息

–root 让RPM将指定的路径做为”根目录”,这样预安装程序和后安装程序都会安装到这个目录下

–rcfile 设置rpmrc文件为

–dbpath 设置RPM 资料库存所在的路径为


五、校验已安装的软件包


命令格式:


rpm -V ( or –verify, or -y) options


参数


pkg1 … pkgN 将要校验的软件包名


软件包选项


-p Verify against package file

-f 校验所属的软件包

-a Verify 校验所有的软件包

-g 校验所有属于组 的软件包


详细选项


–noscripts 不运行校验脚本

–nodeps 不校验依赖性

–nofiles 不校验文件属性


通用选项


-v 显示附加信息

-vv 显示调试信息

–root 让RPM将指定的路径做为”根目录”,这样预安装程序和后安装程序都会安装到这个目录下

–rcfile 设置rpmrc文件为

–dbpath 设置RPM 资料库存所在的路径为


六、校验软件包中的文件


语法:


rpm -K ( or –checksig) options file1.rpm … fileN.rpm


参数:


file1.rpm … fileN.rpm 软件包的文件名


Checksig–详细选项


–nopgp 不校验PGP签名


通用选项


-v 显示附加信息

-vv 显示调试信息

–rcfile 设置rpmrc文件为


七、其它RPM选项


–rebuilddb 重建RPM资料库

–initdb 创建一个新的RPM资料库

–quiet 尽可能的减少输出

–help 显示帮助文件

–version 显示RPM的当前版本


制作篇(上)


要想制作一个RPM格式的软件包,需要编写软件包描述文件。其标准命名格式为:软件名-版

本号-释出号.spec,这个文件,详细描述了有关该软件包的诸多信息,如软件名,版本,类别, 说

明摘要,创建时要执行什么指令,安装时要执行什么操作,以及软件包所要包含的文件等等。 有

了这个文件,RPM就可以制作出相应的包裹文件来。


下面以我制作小赵编辑器LZE的软件包(lze-6.0-2.i386.rpm)为例,详细说明一下软件包描

述文件的书写。其描述文件为lze-6.0-2.spec,该文件内容如下:(用nl -ba命令列出,每行开头

的数字为所在行在文件中的行号)


1 # 文件名称: lze-6.0-2.spec

2 # 文件功能: lze软件包描述信息

3 # 文件作者: 纵横软件制作中心雨亦奇 国防大学研究生二队赵建利

4 # 修改时间: 2001.10.19

5

6 Name: lze

7 Version: 6.0

8 Release: 2

9 Summary: 小赵全屏幕中英文多窗口多功能编辑器(LINUX/UNIX系统适用)

10 Group: Applications/Editors

11 License: Share

12 Vendor: 纵横软件制作中心

13 Packager: 雨亦奇(zhsoft@371.net)

14 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz

15 Prefix: /usr

16 Requires: /bin/sh

17 Provides: lze-edit

18

19 %description

20 小赵编辑器,是为使用SCO UNIX,LINUX多用户系统的广大用户专门设计的全屏幕多窗

21 口中英文多功能编辑器。

22 它主要有以下十大特点:1.全屏幕菜单操作。2.显示方式多样。3.块操作丰富。4.十

23 字制表功能强大。5.多窗口操作灵活自如。6.文件操作功能齐全。7.解释输出功能独具特

24 色。8.自带中文输入法(增强五笔和增强拼音),实用方便。9.十六进制编辑功能,如虎

25 添翼。10.即时翻译,按到即译。

26 总之,小赵编辑器会成为您在UNIX,LINUX系统上编制程序和书写一般性文稿的好帮手。

27 它将在工作中助您一臂之力,轻松上阵,游刃有余!

28

29 %prep

30 echo “预处理脚本程序(prep)开始执行”

31 %setup

32

33 %build

34 echo “编译连接脚本程序(build)开始执行”

35 make

36

37 %install

38 echo “安装脚本程序(install)开始执行”

39 make install

40

41 %clean

42 echo “建包结束后清理脚本程序(clean)开始执行”

43

44 %pre

45 echo “安装前执行脚本程序(pre)开始执行”

46

47 %post

48 echo “安装后执行脚本程序(post)开始执行”

49

50 %preun

51 echo “卸载前执行脚本程序(preun)开始执行”

52

53 %postun

54 echo “卸载后执行脚本程序(postun)开始执行”

55

56 %veryfiscript

57 echo “软件包校验脚本程序(verifyscript)开始执行”

58

59 %triggerin — xiuwu

60 echo “软件包安装时触发脚本程序(triggerin)开始执行”

61

62 %triggerun — yuntaishan < 2.0

63 echo “软件包卸载前触发脚本程序(triggerun)开始执行”

64

65 %triggerpostun — dapubu

66 echo “软件包卸载后触发脚本程序(triggerpostun)开始执行”

67

68 %files

69 %defattr (-,root,root)

70 %config /etc/funkey.def

71 %config /etc/inputme.def

72 %doc /usr/doc/lze-6.0/README

73 %doc /usr/doc/lze-6.0/LICENSE

74 /usr/bin/lze

75 /usr/bin/lzeime.py

76 /usr/bin/lzeime.wb

77 /etc/wbzc.dat

78

79 %changelog

80 * Tue Aug 18 1998 雨亦奇

81 – 内置拼音,五笔输入法

82 * Fri May 01 1998 雨亦奇

83 – 增加多窗口操作

84 * Mon Mar 24 1997 雨亦奇

85 – 增加块操作命令

86


该描述文件包括以下几方面的内容:


一、注释行

见第1-4行。

它以#号开头,起注解作用,可帮助用户理解所写的内容,但对软件包的生成不起任何作用。

此文件中,注释行集中在文件首部。实际上,它可位于描述文件的任何位置。


二、文件头

见第6-17行。

文件头描述软件包的基本信息,它包含若干个域,其中有必选的域,也有可选的域。一个域占用一行,其描述格式为:

域名 : 域值

注意: 域名不分大小写,并且域值不能为空。

文件头必选域有以下六个:


1. Name :

此域定义软件名。


2. Version :

此域定义版本号。仅当软件较以前有较大改变时才增加版本号。注: 版本号中不能含减号(-)字符。


3. Release :

此域定义释出号。若软件较以前改变较小,则仅增加释出号,不改变版本号。注: 释出号中亦不能含减号(-)字符。

RPM利用上述的Name(软件名),Version(版本号),Release(释出号)及体系号来命名软件包,如本例输出的包裹文件名为lze-6.0-2.i386.rpm。


4. Summary :

此域定义软件包简介,为一句话说明。


5. Group :

此域定义软件所属类别,详见<<精通RPM之五–查询篇>>,本例的Applications/Editors表示本软件属”应用/编辑器”类。


6. License :

此域定义软件适用的许可证或版权规则。该域也可用Copyright(版权)来定义,二者同意。许可证具体有: GPL(通用公共许可证,自由软件适用),BSD,MIT,Public Domain(公共域),Distributable(贡献),Commercial(商业),Share(共享)等。


文件头可选的域包括如下几类:

1. 基本信息


1.1 Vendor :

此域定义软件的供应商(销售商)。


1.2 Distribution :

此域定义软件所属的发行版,这是软件包制作者自己的分类。通常,一个发行版由若干个软件包构成。如我想做一个名为“熊猫’95”的发行版,则其中每个软件包(如竹叶95)的描述文件都应有这么一行:

Distribution : 熊猫’95


1.3 Icon :

此域指定软件包所用的图标文件名。此文件为GIF或XPM格式,必须存放在RPM的%_sourcedir

(源码目录)宏所指示目录下,默认为/usr/src/dist/SOURCES。RPM本身并不使用图标,但它

将图标文件内容存贮到包裹文件中,安装时亦存贮到RPM数据库中。此图标可被图形界面的

RPM包管理工具使用,用以改善界面效果,增加可视性。如下例指示软件包使用panda.xpm作

为图标:

Icon : panda.xpm


1.4 Packager :

此域定义打包者,亦即建立此软件包的人或公司。书写格式是:

打包者的名字 <电子信箱或相关网页>

请参考描述文件第13行。


1.5 Serial :

此域定义软件序列号,也可使用域名Epoch。软件序列号为一整数,由打包者指定,它应随着版本号的增加而不断增加,并且始终保持数值的唯一。软件序列号可被用来说明软件包之间的依赖关系。下例指定软件包序列号为4:

Serial : 4

或用:

Epoch : 4


1.6 URL :

此域定义包含打包软件有关信息的网页地址。如:

URL : http://devplanet.fastethernet.net/gxedit.html


2. 依赖相关

依赖是RPM用来描述软件包之间关系的。一个软件包依赖的东西RPM称作功能,它可以是真实存在的软件包,也可以是虚拟的软件包(虚包)。虚包没有版本号。

依赖相关的域有:


2.1 Provides :

此域定义软件包提供的功能,可重复多行。其描述格式为:

Provides : 功能1 [,功能2] …


注: []所括为可选项,多个功能之间以逗号或空格分隔。

软件包所提供的功能一般是以虚包形式存在的共享库。当有多个软件包均提供相同的服务时,常用虚包来表示其服务。如,一个邮件客户端软件允许用户使用不同的看信方式(文本形式,HTML形式等),可以要求任何一个看信程序必须提供mail-reader虚包。这样,看信程序的描述文件应有这么一行:

Provides : mail-reader

如此它才能被邮件客户端使用。


2.2 Requires :

此域定义软件包所需的功能,可重复多行。其描述格式为:

Requires : 功能1 [比较符1 [序列号1:]版本号1[-释出号1]] [,功能2 [比较符2 [序列号2:]版本号2[-释出号2]]] …


其中: * []所括为可选项;

* 比较符可使用<(小于),>(大于),=(等于),>=(大于等于)或<=(小于等于);

* 序列号不选时,RPM默认为0;

* 功能之间的逗号可选,也可使用空格进行分隔。

例子:Requires: aaa, bbb >= 3.0, ccc < 2:5.0-1

注: 本例定义生成的包在安装时需要系统有如下功能:

(1) aaa(系统中已安装aaa包,或者已安装软件包中有软件包提供aaa虚包);

(2) bbb包已安装且版本要求大于等于3.0;

(3) ccc包已安装且版本要求小于序列号为2,版本号为5.0且释出号为1。

RPM在进行版本比较时,执行比较的顺序是; 先版本号,再释出号,最后比较序列号。通过比较,确定哪个版本较新,哪个版本较老。


2.3 Conflicts :

此域定义有哪些功能与本软件包相冲突(不能共存)。此域亦可在描述文件中书写多次。其描述格式形同Requires域,为:

Conflicts : 功能1 [比较符1 [序列号1:]版本号1[-释出号1]] [,功能2 [比较符2 [序列号2:]版本号2[-释出号2]]] …


其中: * []所括为可选项;

* 比较符可使用<(小于),>(大于),=(等于),>=(大于等于)或<=(小于等于);

* 序列号不选时,RPM默认为0;

* 功能之间的逗号可选,也可使用空格进行分隔。

举个例子:

Conflicts : xxx=1:2.0 yyy>=3.0

注: 本例阐明生成的包冲突的功能有:

(1) 当系统中xxx包版本等于序列号为1且版本号为2.0时;(2) 当系统中yyy包版本大于等于3.0时。

*** 依赖关系的自动实现 ***

一般情况下,当RPM建立一个软件包时,它要执行/usr/lib/rpm目录下的两个小程序。一个是find-requires,用于查找软件包所需的共享库,这些库将以虚包的形式加入到该软件包所需的功能(Requires)之中。另一个是find-provides,它用于查找软件包所提供的共享库,这些库将以虚包的形式加入到该软件包所提供的功能(Provides)之中。这两个程序都是SHELL程序,代码量虽小,但确实帮了软件包制作者一个大忙–不必劳心费神地自己写这样的依赖关系了,因为程序均自动完成了。

下面三个域用于指示RPM是否执行这两个程序。


2.4 Autoreq :

此域用于指示RPM是否自动查找软件所需的共享库。仅当域值为no或0时,RPM不执行find-requires程序,否则均执行该程序。


2.5 Autoprov :

此域用于指示RPM是否自动查找软件提供的共享库。仅当域值为no或0时,RPM不执行find-provides程序,否则均执行该程序。


2.6 Autoreqprov :

此域用于指示RPM是否自动查找软件所需的共享库与其提供的共享库。仅当域值为no

或0时,RPM不执行find-requires与find-provides两个程序。此域相当于同时设定Autoreq

与Autoprov域值为指定之值。

注: 上述三个域在描述文件中,它们之间因为顺序的不同而结果会有所不同,一般以最后一个为准。如:

Autoreq : yes

Autoreqprov : no

Autoprov : yes


注: 本例虽然第一行允许执行find-requires,但第二行又不允许find-requires与find-provides两个程序运行,而第三行允许find-provides运行,所以依照执行顺序,结果为不允许执行find-requires,而允许执行find-provides。

又如:

Autoreq : no

Autoreqprov : yes

Autoprov : no


注: 本例的结果为允许执行find-requires,而不允许执行find-provides。


3. 系统相关

RPM制作软件包时,可以为其指定适用的CPU体系或操作系统,也可为其指定不适用的CPU体系或操作系统,这样,当RPM发现当前的CPU体系或操作系统与软件包要求的不兼容时,将中止软件包的制作。RPM默认的当前CPU体系由宏%_arch定义,一般为i386。RPM默认的当前操作系统由宏%_os定义,一般为linux。读者可以通过查看/usr/lib/rpm/macros宏定义文件得到。

下面四个域说明软件包的适用范围:


3.1 Excludearch :

此域定义软件包不适用的体系。RPM可选的体系名请参见/usr/lib/rpm/rpmrc文件中的arch_canon项目。

软件包不适用于某个体系,可能有两方面的原因。一是该软件还没有移植到所定义的体系上;二是该软件含有特定的机器码(汇编语言),它与别的体系不兼容。

此域描述格式为:

Excludearch : 体系1 [体系2] …


注: []所括为可选项,各体系之间以空格分隔。

如果当前体系在此域值之中,则RPM制作软件包时将报错退出,请看下面的例子。

在lze-6.0-2.spec文件头部分加入一行:

Excludearch : i386

再运行建包命令rpm -bb(<<精通RPM之七–制作篇(下)>>将讲到):

# rpm -bb lze-6.0-2.spec

Architecture is excluded: i386

#


由上看出,RPM提示了“体系不适用: i386”的错误。


3.2 Exclusivearch :

此域定义软件包适用的体系。其描述格式与Excludearch类似:

Exclusivearch : 体系1 [体系2] …


注: []所括为可选项,各体系之间以空格分隔。

假如在lze-6.0-2.spec文件头加入一行:

Exclusivearch : i386 sparc

再运行建包命令将会怎么样:

# rpm -bb lze-6.0-2.spec

Executing: %prep

预处理脚本程序(prep)开始执行

Executing: %build

编译连接脚本程序(build)开始执行

Executing: %install

安装脚本程序(install)开始执行

Processing files: lze

Finding Provides: (using /usr/lib/rpm/find-provides)…

Finding Requires: (using /usr/lib/rpm/find-requires)…

Provides: lze-edit

PreReq: /bin/sh

Requires: /bin/sh ld-linux.so.2 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1)

Wrote: /usr/src/dist/RPMS/i386/lze-6.0-2.i386.rpm

#


看,此次建包(lze-6.0-2.i386.rpm)成功了,因为当前的体系(i386)正好适用。


3.3 Excludeos :

此域定义软件包不适用的操作系统。RPM可选的操作系统请参考文件/usr/lib/rpm/rpmrc中的os_canon项目。

其描述格式为:

Excludeos : 操作系统1 [操作系统2] …


注: []为可选项,操作系统之间以空格分隔。例如:

Excludeos : irix aix solaris

注: 如将此行加入到lze的描述文件中,则它会指示RPM不在irix,aix,solaris这三个操作系统上建立lze软件包。如果当前操作系统是三者之一,则RPM会报错并中止软件包的制作。

如:

# rpm -bb lze-6.0-2.spec

OS is excluded: Solaris

#


3.4 Exclusiveos :

此域定义软件包适用的操作系统。其描述格式为:

Exclusiveos : 操作系统1 [操作系统2] …

注: []为可选项,操作系统之间以空格分隔。例如:

Exclusiveos : linux solaris


4. 目录相关

4.1 Prefix :

此域定义可重定位的目录前缀,可在描述文件中书写多次。其描述格式为:

Prefix : 目录前缀1 [目录前缀2] …


注: []为可选项,各目录前缀之间均以空格分隔。例如:

Prefix : /usr /etc

它也可写作:

Prefix : /usr

Prefix : /etc

RPM利用可重定位的目录前缀,实现了软件包的重定位安装, 使软件中的文件不必固定在某

个绝对位置,这种做法很好。LZE软件包描术文件lze-6.0-2.spec中就定义了一个可重定位

的前缀/usr(见第15行),这样,安装时就可将该包中在/usr目录下的文件重定位到用户指定

的目录,如:

# rpm -i –prefix /tmp lze-6.0-2.i386.rpm

#

或者:

# rpm -i –relocate /usr=/tmp lze-6.0-2.i386.rpm

#

注: 此命令安装lze包,将其中含/usr重定位目录前缀的文件定位到/tmp目录。如包中

的/usr/bin/lze文件安装后,因重定位而成了/tmp/bin/lze。(RPM安装命令使用方法请参考<<精通RPM之二–安装篇>>)


4.2 Buildroot :

此域定义的是软件包所包含的文件共有的根目录,此根目录仅供RPM建立软件包时使用。即当RPM建立软件包时,将设定此目录为根(调用chroot函数),提取所需文件,生成软件包。

例如: 当Buildroot设定为/tmp时,对于LZE包描述文件中所包含的/usr/bin/lze文件,RPM实际打包的则是/tmp/usr/bin/lze,但对生成的包查询后可以发现:原文件名并未改变,还是/usr/bin/lze。

如此说来,这就很有意思了。一般用户通过设定Buildroot,也可以象超级用户(root)那样自由地建立各种各样的软件包了,即使包中有那些唯有超级用户才可以操作的目录或文件。安装这样的包与安装由超级用户建立的包,是没有什么分别的。

此域的描述格式很简单:

Buildroot : 目录

如,上例可定义为:

Buildroot : /tmp


5. 源码相关

下列四个域均是为制作源码包而设计的。源码包里有什么?用户可以通过查询包的文件列表得到,命令是“rpm -qpl 源码包文件”(请参阅<<精通RPM之五–查询篇>>有关内容)。一般情况下,源码包里有这么四类文件: 一是程序源码(SOURCE),二是源码补丁(PATCH),三是软件包描述文件,四是图标文件(ICON)。通过安装源码包,用户可以轻松地实现现场编译、连接和应用,同时更方便了软件开发者与软件包制作者:他们维护程序容易了,并且维护过后可以很快地生成执行代码包与源码包。这,也是所有人钟爱RPM的重要原因之一。


5.1 Source :

此域定义RPM打包时要包含的程序源码文件。这些文件一般先用tar命令打包,然后再用gzip压缩。一个描述文件中可包含多个Source域,当有多个这样的域时,需要进行编号:第1个编为Source0(也可直接用Source),第2个编为Source1,第3个编为Source2等等。此域的描述格式为:

Source[编号] : 源码文件


注: []所括为可选项。具体用法如:

Source0 : lze-6.0-2.tar.gz

Source1 : lzeime-wb-6.0-2.tar.gz

Source2 : lzeime-py-6.0-2.tar.gz

Source3 : lze-lib-6.0-2.tar.gz

注: 此域域值可以采用URL(统一资源定位)的形式,如LZE描述文件第14行。采用这种形式,主要是给其它用户提供该源码的位置信息。在RPM制作源包时,它提取的是最后的文件名lze-6.0-2.tar.gz,而不是http://zhsoft.myetang.com/lze-6.0-2.tar.gz(URL前面的内容被RPM忽略了)。


5.2 NoSource :

在上例中,假如在打包时不想包含Source1与Source2定义的文件,那该怎么办?

办法之一是将其所在行删除掉;

办法之二是将其所在行注释掉(即所在行前面加#号);

办法之三就是定义Nosource域,此域可重复。其描述格式为:

NoSource : 源码域编号


本例可写作:

NoSource : 1

NoSource : 2

注: 其中的1与2为编号,表示Source1和Source2。

注意: 如果软件包描述文件中没有NoSource域,则RPM生成的源码包名字格式为”软件名-版本号-释出号.src.rpm”。如果使用了NoSource域,则RPM生成的源码包名字格式为”软件名-版本号-释出号.nosrc.rpm”(单从名字就可看出源码包包含的文件不完整)。


5.3 Patch :

Patch的本义是补丁,用在这里指的是源程序的补丁,它是用diff命令比较新老源程序所产生的输出(命令为“diff -Nur 旧文件 新文件 >补丁文件”),而系统中的patch命令又可利用此输出将老版本的源程序升级为新版本。

此域定义RPM制作源码包时所要包含的补丁文件,该文件的命名建议用”软件名-版本号.补丁功能.patch”的格式。一个软件包描述文件中可有多个Patch域,当有多个这样的域时,也需要象Source域那样进行编号(注:第1个域编为Patch0,也可省略0,用Patch)。

此域的描述格式为:

Patch[编号] : 源码补丁文件


注: []所括为可选项。具体用法如:

Patch0 : blather-4.5-bugfix.patch

Patch1 : blather-4.5-config.patch

Patch2 : blather-4.5-somethingelse.patch

注: 此域的域值也可以象Source域一样,采用URL的形式,RPM仅提取其中的文件名供其使用。


5.4 NoPatch :

此域的功能类似NoSource,其定义的编号对应的补丁文件RPM不作打包处理。此域在描述文件中可重复出现。如上例,若不想让源码包包含Patch0与Patch2域所指示的补丁文件,则可在描述文件写上这么两行:

NoPatch : 0

NoPatch : 2

注意: 如果软件包描述文件中没有NoPatch域,则RPM生成的源码包名字格式为”软件名-版本号-释出号.src.rpm”。如果使用了NoPatch域,则RPM生成的源码包名字格式为”软件名-版本号-释出号.nosrc.rpm”(单从名字就可看出源码包包含的文件不完整)。


三、功能段

见第19-86(即文件头以下的部分)。

何谓功能段?可以这么说,功能段是描述软件包的重要数据和操作指令的段落,它包括段名与段内容两部分。没有功能段,RPM便制作不出任何包裹文件。功能段的段名都是以百分号(%)开始的,占用一行。功能段的段内容范围是这样界定的:它从该功能段段名下一行开始到下一个功能段段名的前一行或到描述文件结束。如LZE描述文件,%description段是从第19行到第28行(%prep段从第29行开始),第19行为段名,第20-28行为段内容。而%prep段是从第29行到第32行(第33行%build段开始),其段名在第29行,段内容在第30-32行。另外要注意的是,各个功能段的位置是自由的,可放在文件头以下的任何位置,不必拘泥某一固定位置。

必选的功能段

描述文件中,必选的功能段有:


1. %description

本段是描述段,段的内容是对软件包进行较为详细的介绍,不象文件头的Summary域仅用一句话说明。介绍的文本形式自由,可任意换行,不受限制。具体请参见LZE描述文件第20-27行。

本段段名描述格式是:

%description [子包选项]


其中,子包选项的格式为:[-n] 子包名

注: []所括为可选项。


三种形式的描述段段名:

(1) 段名格式为“%description”时:

本功能段描述的内容是关于父包的。父包也可叫作主软件包,它用软件名来命令,其名字格式是:软件名-版本号-释出号.体系.rpm。如:lze-6.0-2.i386.rpm。

(2) 段名格式为“%description 子包名”时:

本功能段描述的内容是关于子包的。子包选项中没有-n选项时,子包是用软件名加子包名的形式命名,格式为: 软件名-子包名-版本号-释出号.体系.rpm。如分成两个子包的LZE软件:lze-bin-6.0-2.i386.rpm(执行程序包),lze-config-6.0-2.i386.rpm(配置文件包)。

(3) 段名格式为“%description -n 子包名”时:

本功能段描述的内容也是关于子包的。当子包选项中有-n选项时,子包直接采用子包名的形式命名。它不包含软件名,命名格式为: 子包名-版本号-释出号.体系.rpm。如分成两个子包的LZE软件: bin-6.0-2.i386.rpm(执行程序包),config-6.0-2.i386.rpm(配置文件包)。注意:这种类型的子包内容通常是可被其它软件包共用的函数库,如果专用,则尽量不要采用这样形式来定义子包。


2. %files

本段是文件段,它定义的是软件包需要包含哪些文件。本段通常放在描述文件尾部,以便于添加文件名,便于编辑。

本段段名描述格式为:

%files [子包选项] [-f 文件名]


注: []所括为可选项。

当没有任何选项时,本段内容定义的是父包要打包的文件列表;

当有子包选项时,本段内容定义的则是子包要打包的文件列表;

当选择-f选项时,RPM除了从文件段读取打包文件列表外,还将从指定的文件中读取要打包的文件列表。指定的文件中,一个文件名占用一行。此选项方便了软件包制作者,他们可以通过程序自动产生有关软件的文件列表,并将其写入到一个特定的文件中,这样制作软件包时,只需引用一下这个文件,RPM就会自动从这个文件中读取文件名并将其加入包中。如果没有此选项,软件包制作者只能在文件段里,将要打包的文件名一个一个写进去,有点麻烦。


文件段的内容格式为:

[修饰符1 [修饰符2] …] 文件名

其中:修饰符是可选的,一个文件可以有多个修饰符,文件名必须以/开头(绝对路径形式)。

修饰符有以下几类:


(1) 文件相关

* %doc :

此修饰符设定文件类型为说明文档(参见LZE描述文件第72,73行);

* %config :

此修饰符设定文件类型为配置文件(参见LZE描述文件第70,71行);

* %config(missingok) :

此修饰符设定文件类型为配置文件,且此文件可丢失。即使丢失了,RPM在卸载软件包时并不认为这是个错误,并不报错。

此修饰符通常用于那些软件包安装后建立的符号连接文件,如/etc/rc.d/rc2.d/S55named等。此类文件在软件包卸载后可能需要删除,所以丢失了也不要紧。

* %config(noreplace) :

此修饰符设定文件类型为配置文件,且如果安装时系统中有同名的文件,则软件包中的这个文件将换个名字安装,其文件名后缀加个.rpmnew。(如果不用此修饰符,则安装时RPM若发现有同名文件,则RPM会将系统中的这个文件换个名字,其后缀加上.rpmorig,而软件包中的文件则还用原来的名字。)在软件包卸载时,系统中的同名文件被RPM换个名字保存起来,其后缀加上了.rpmsave。

如描述文件的文件段中定义了这么一行:

%config(noreplace) /etc/hello

则制成的包在安装时,若系统中已有此文件/etc/hello,则RPM会提示:

warning: /etc/hello created as /etc/hello.rpmnew

这表明包中的/etc/hello文件被创建为/etc/hello.rpmnew文件了。

如果卸载这个软件包,则系统中的/etc/hello将会改名为/etc/hello.rpmsave。

* %ghost :

此修饰符所修饰的文件,其内容不被包含到软件包中。这样的文件一般是日志文件(log file)一类的文件,其文件属性(文件名,属主,属组等)很重要,但是文件内容并不重要。用此修饰符后,RPM仅将其文件属性加入包中。

* %attr :

此修饰符设定文件的属性信息,使用格式为:

%attr(权限,属主,属组)

注: 权限常用数字形式(八进制),属主和属组可以是数字,也可以是字符串。如果文件的权限,属主和属组想使用系统默认值,则可用减号(-)表示它。

如下例采用两个修饰符,定义/etc/funkey.def文件的权限为755,属主默认,属组为root,类型为配置文件:

%attr(755,-,root) %config /etc/funkey.def

* %verify :

此修饰符设定文件需要校验的那些属性。这些属性有:owner(属主),group(属组),mode(权限),md5(MD5检查和),size(大小),maj(主设备号),min(从设备号),symlink(符号连接),mtime(最后修改时间)。

此修饰符使用格式为:

%verify([not] owner group mode md5 size maj min symlink mtime)

注: not可眩当选用not时,表明需要校验除选定属性以外的那些属性。

如下例指示RPM校验/dev/ttyS0文件时,要校验其权限,MD5检查和,大小,主设备号,从设备号,符号连接和最后修改时间共七项属性信息:

%verify(mode md5 size maj min symlink mtime) /dev/ttyS0

这也可以采用not选项来实现,因为除去属主owner和属组group两项属性,剩下的就是需要校验的属性了:

%verify(not owner group) /dev/ttyS0


(2) 目录相关

* %docdir :


此修饰符定义说明文档前缀,这样,后面所有含指定文件名作为前缀的文件,RPM打包时会将其类型统一设定为说明文档。

例如某描述文件的文件段中有这么三行:

/root/readme

%docdir /root

/root/mydoc.txt


此例指明/root为说明文档的前缀,因为/root/mydoc.txt在%docdir的下一行,所以RPM打包时会设定此文件的类型为说明文档。而/root/readme文件则不做此设定,因为它在%docdir定义之前。

通过此修饰符,用户可以很方便地设定说明文档一类的文件,因为它们通常固定在某个目录下面,有着共同的前缀。

* %dir :

RPM在制作软件包时,如果要打包的文件是个目录,那么RPM会将该目录下面的所有文件包含到软件包中。(注意:如果要打包的文件是个符号连接,此符号连接又指向一个目录,则RPM并不会将其视作目录,只会把它当为普通文件处理。)如果仅想将这个目录名包含到软件包中,制作者用此修饰符修饰一下这个目录名就行了。

如: /etc是个系统目录,其下有多个文件,如果想将其均加入包中,描述文件的文件段里可写上这么一行:

/etc

如果仅想包含此目录,则可用:

%dir /etc



(3) 另类修饰符

此类只有一个%defattr。说它是另类修饰符,是由于它设定的是默认的文件属性,而非特定的某个文件。它一般放在文件段内容的第一行。

其使用格式为:

%defattr(权限,属主,属组)


其中: 权限,属主和属组都可以使用减号(-)。使用减号的属性将由系统设定。

例如: %defattr(022,zzz,zhsoft) 设定其后的所有文件权限为022,属主为zzz,属组为zhsoft;又如: %defattr(-,zzz,-) 则是设定其后的所有文件属主为zzz,权限与属组由系统设置。

可选的功能段

描述文件中,可选功能段的内容都是些脚本程序。(LZE描述文件中多个脚本程序中仅含一个echo命令)

可选的功能段的描述格式为:

功能段名 [子包选项]


注: 子包选项为”[-n] 子包名”。当无子包选项时,段内容描述的是父包的脚本程序。当有子包选项时,段内容则是描述子包的脚本程序。


可选的功能段可分为如下三类:

1. 建包用功能段:

RPM通过源程序来建立一个软件包时,要执行预处理,编译,安装和清理四项操作,分别对应于%prep,%build,%install和%clean四个段。

下面按其执行顺序逐段进行说明:

1.1 %prep :

此为预处理段,其内容为预处理脚本程序。该程序完成以下任务:

* 建立软件编译用目录;

* 将源程序解压缩;

* 通过打补丁,升级源程序;

* 执行其它一些操作,使源程序随时可进行编译。

在此脚本程序中,可使用如下两个宏命令:

1.1.1 %setup

这个宏利用系统中的gzip与tar等命令,来解压源程序包。RPM会自动探测源程序包是否压缩,如果压缩,它会用gzip将其解压缩,否则直接用tar命令展开包中文件。其使用格式为:

%setup [-n name] [-c] [-D] [-T] [-b N] [-a N]


注: []所括为可选项。

(1) 当没有任何选项时:

这个宏用来解压默认的源程序包(由文件头Source或Source0域指定)。注意:源程序包中的文件应用”软件名-版本号”作为其上层目录,这样%setup宏就可以正常工作。如果不以”软件名-版本号”作为其上层目录,则%setup宏工作时有一个指令”cd 软件名-版本号”(转目录)会因为系统中没有此目录而出错退出(除非在此宏上面加上建立此目录的命令)。如LZE软件源程序所在的目录为lze-6.0,我需要用命令”tar cvzf lze-6.0-2.src.tgz lze-6.0″将源程序打包并压缩,这样的包就可以被%setup宏正确使用了。

下面是%setup宏命令所执行的一系列命令: (指令前面为行号)

1 cd /usr/src/dist/BUILD

2 echo “预处理脚本程序(prep)开始执行”

3 cd /usr/src/dist/BUILD

4 rm -rf lze-6.0

5 /bin/gzip -dc /usr/src/dist/SOURCES/lze-6.0-2.src.tgz | tar -xvvf –

6 STATUS=$?

7 if [ $STATUS -ne 0 ]; then

8exit $STATUS

9 fi

10 cd lze-6.0

11 [ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root .

12 [ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root .

13 /bin/chmod -Rf a+rX,g-w,o-w .

14 exit 1


看,第10行就有一个转到lze-6.0目录的命令,如果没有这个目录,程序就会出错退出了。也许你要问:这些指令你是怎么知道的?其实这很简单,只要在%setup宏下面加上一句”exit 1″命令,让预处理脚本程序非正常退出即可。这样RPM所执行的预处理脚本程序作为临时文件在其退出时并未删除,只要看一下这个文件(在/var/tmp目录下以rpm-tmp开头)就知道%setup宏命令做什么了。


(2) -n name :

上面已经谈到,源程序包中的文件应采用”软件名-版本号”作为上层目录。如果用了别的什么目录(如name),%setup宏无法正常工作,那该怎么办?没关系,可以用-n选项,引用一下这个目录(name)就行了。假如我的LZE源程序包中的文件是以lze为上层目录,那么我就可以用”%setup -n lze”宏命令来解压缩该包。


(3) -c :

此选项的作用是创建上层目录(“软件名-版本号”目录)并转到这个目录。对于LZE软件,其效果相当于在上例的第4行与第5行之间加上这么两行命令:

mkdir -p lze-6.0

cd lze-6.0

它适用的情况是:有的源程序包是在源程序所在目录下打的包,所以其中的文件都没有上层目录。这样的话,要想正确解压,必须创建上层目录。


(4) -D :

本选项的作用是在解压源程序包之前不要删除软件的上层目录(软件名-版本号)。在上例中,其效果是不执行第4行的命令(rm -rf lze-6.0)。


(5) -T :

本选项的作用是不解压默认的源程序包(由文件头的Source或Source0域所定义)。在上例中,其效果是不执行第5-9行的命令:第5行是解压源程序包(用gzip -dc将包的内容解压缩到管道中,再由tar -xvvf -从管道中读取数据并展开),第6-9行是检查解压命令的返回值,非0时执行非正常退出。


(6) -b N :

本选项指示RPM在转到上层目录前解压第N个源程序包(由文件头SourceN域定义)。这适用于含上层目录的源程序包。注意:如果使用此选项时不同时使用-T选项,则RPM解压的是两个源程序包,一个是默认的包(由Source或Source0域定义),一个是-b选项指定的包(由SourceN域定义)。这样,当N等于0时,默认的源程序包将被解压两次。所以,如果想仅解压指定源程序包,请同时使用-T选项,以禁止解压默认的源程序包。

下面的宏命令仅解压第1个源程序包,然后转到上层目录:

%setup -b 1 -T


(7) -a N :本选项指示RPM在转到上层目录后再解压第N个源程序包(由文件头SourceN域定义)。这适用于不含上层目录的源程序包。使用本选项时,一般加上-c选项,以创建上层目录并转到此目录。注意:如果使用此选项时不同时使用-T选项,则RPM解压的是两个源程序包,一个是默认的包(由Source或Source0域定义),一个是-a选项指定的包(由SourceN域定义)。这样,当N等于0时,默认的源程序包将被解压两次。所以,如果想仅解压指定源程序包,请同时使用-T选项,以禁止解压默认的源程序包。


下面的宏命令让RPM先转到上层目录,再仅解压第2个源程序包:

%setup -T -a 2

1.1.2 %patch

此宏利用系统中的patch命令,来给指定的源程序包打补丁,从而将程序升级。其使用格式为:

%patch [-P N] [-p N] [-b name] [-E]

注: []所括为可选项。

为了说明下列选项的作用,我们为LZE软件包描述文件中定义三个补丁文件:

Patch0 : lze-patch.zero

Patch1 : lze-patch.one

Patch2 : lze-patch.three


(1) 当没有任何选项时:

没有任何选项时,该宏使用的是默认的补丁文件(第0个补丁文件),即由文件头Patch或Patch0域所定义的文件(LZE包使用lze-patch.zero)。

该宏在执行时,扩展为以下指令:

echo “Patch #0:”

patch -p0 -s < /usr/src/dist/SOURCES/lze-patch.zero

注: 第一行指令是利用echo命令向屏幕输出字符串“Patch #0:”。第二行指令则是利用patch命令读取补丁文件lze-patch.zero升级源程序。

patch命令用了两个选项:(有关patch命令用法,详见其用户手册)

* -p : 这个选项用于确定patch所要操作的文件。它针对补丁文件头部的文件名,删除名字中指定数目个斜杠(/)前面的所有字符,从而得到要操作的文件名。如补丁文件里有个文件名/usr/zzz/src/lze.c,则用-p0时patch操作的文件名不变,用-p1时则变为usr/zzz/src/lze.c,用-p2时则变为zzz/src/lze.c,如用-p4则操作的文件名变为lze.c。

* -s : 这个选项指示patch在打补丁过程中不输出任何信息,即使有错误发生。


(2) -P N :

使用此选项以指示RPM使用第N个补丁文件(由文件头PatchN域定义)。如想让RPM使用LZE的第2个补丁文件Patch2(lze-patch.three)时,可使用”-P 2″来指定。


(3) -p N :

此选项与其参数是由%patch宏直接传给patch命令的。请参见上面patch命令所用的-p选项的介绍。


(4) -b name :

当有多个patch命令操作同一个文件时,patch会将原文件换名保存(其后缀变作.orig),如lze.c会变作lze.orig。如果想用别的名字作后缀,则可用-b设置一下,这样原文件会换名为”原文件名+后缀”,如用-b ZZZ时,lze.c会换名保存为lze.cZZZ。

此选项在执行时,实际上是给patch命令传递了一个选项及参数,即–suffix name。


(5) -E :

此选项直接传给patch命令,其作用是:如果一个文件打完补丁后内容为空(字节数为0),则删除这个文件。


1.2 %build :

此为编译段,其内容为编译脚本程序。该程序完成源程序的编译和连接。一个最简单的例子就是程序中仅有一个make命令。这适用于大部分情况,因为多数软件均有自己的makefile,这样通过make命令就可实现编译与连接。如果没有makefile的话,需要软件包制作者自己在编译段书写上一系列的编译连接命令。


1.3 %install :

此为安装段,其内容是安装脚本程序。该程序将已编译连接好的执行程序或其它文件存放到指定目录下,这些程序或文件供RPM打包时使用。一个最简单的例子就是程序中仅用一个make install命令,从而完成安装。这也需要相应的软件有makefile维护文件。没有的话,软件包制作者也得自己写指令。


1.4 %clean :

此为清理段,其内容是清理脚本程序。此程序在RPM制作好软件包后才执行,它通常是删除那些编译连接时产生的临时文件或目录,完成缮后工作。


2. 管理用功能段:

此类段用于软件包自身的管理(安装,卸载和校验),包括%pre,%post,%preun,%postun,和%verifyscript五个功能段。

2.1 %pre :


该段内容为安装前脚本程序。它在软件包安装之前执行,通常是检测操作环境,建立有关目录,清理多余文件等等,为软件包的顺利安装做准备。本段很少使用。

其段名格式为: %pre [子包选项]


2.2 %post :

该段内容为安装后脚本程序。它在软件包安装完成之后执行,常用来建立符号连接,修改系统配置文件,运行ldconfig程序等,以利软件的正常运行。

其段名格式为: %post [子包选项]


2.3 %preun :

该段内容为卸载前脚本程序。它在软件包卸载之前执行,主要为卸载做准备。具体如,要卸载的软件包中某个程序当前正在运行时,此脚本程序必须杀掉它,否则无法正确卸载。

其段名格式为: %preun [子包选项]


2.4 %postun :

该段内容为卸载后脚本程序。它在软件包卸载后执行,完成卸载的缮后工作,如将系统配置文件inetd.conf改回原来的样子,重新运行一下ldconfig命令,将已卸载的共享库从缓冲文件ld.so.cache中删除等等。

其段名格式为: %postun [子包选项]


2.5 %verifyscript :

该段内容为校验脚本程序。RPM校验软件包时,除了执行标准的校验外,如果软件包制作者设定有此校验脚本程序,还将执行之。


其段名格式为: %verifyscript [子包选项]

下面是XFree86-libs-3.3.6-6.i386.rpm软件包中的校验脚本程序,它校验的是动态链接库目录/usr/X11R6/lib。校验时,在/etc/ld.so.cache文件中查找/usr/X11R6/lib,如果找不到,则显示”missing”,找到则显示”found”。

# verifyscript

echo -n “Looking for /usr/X11R6/lib in /etc/ld.so.conf… ”

if ! grep “^/usr/X11R6/lib$” /etc/ld.so.conf > /dev/null

then

echo “missing”

echo “/usr/X11R6/lib missing from /etc/ld.so.conf” >&2

else

echo “found”

fi


3. 交互用功能段:

这类功能段有%triggerin,%triggerun,%triggerpostun,它们的内容都是RPM用于软件包之间交互控制的脚本程序。这些脚本程序都是在系统满足指定的条件下才触发执行的:


1) %triggerin : 段内为安装时触发脚本程序,当其所在软件包与指定软件包仅有一方已安装时,安装另一方将触发此程序执行;


2) %triggerun : 段内为卸载时触发脚本程序,当其所在软件包与指定软件包都已安装时,卸载二者中的任一个将触发此程序执行;


3) %triggerpostun : 段内为卸载后触发脚本程序,只有指定软件包卸载后才触发此程序执行。


3.1 段名格式

它们的段名描述格式均为:

交互段名 [子包选项] [-p 解释程序] — 触发条件1 [,触发条件2] …


注: []所括为可选项。子包选项见前面介绍,不赘述。


3.1.1 -p选项:

此选项用于指定一个解释程序,来解释执行交互功能段的脚本程序。默认情况下,RPM使

用/bin/sh来执行脚本(此类脚本用SHELL语言编写,也叫SHELL程序)。有的RPM包则是使用/usr/bin/perl

来执行脚本(此类脚本是用PERL这种解释性语言写的),这就需要用-p选项来指定解释程序为

/usr/bin/perl,如:

%triggerin — sendmail

ln -sf /usr/bin/sendmail /etc/mymailer/mailer

%triggerin — vmail

ln -sf /usr/bin/vmail /etc/mymailer/mailer


注: 此例中定义package子软件包安装时触发脚本程序:当触发条件(fileutils>3.0,perl<1.2)满足时,用/usr/bin/perl执行脚本,即用print命令输出字符串”I’m in my trigger!”。


3.1.2 触发条件:

交互功能段的触发条件格式是:

功能名 [比较符 版本号]


其中:比较符与版本号可眩仅有一个功能名时,表明该功能存在时触发程序执行。比较符可用大于(>),等于(=),小于(<),大于等于(>=)和小于等于(<=)。

如触发条件bash,又如触发条件fileutils>3.0,这种使用均合法。

交互功能段最少有一个触发条件。当有多个触发条件时,这些条件间均以逗号(,)分隔,它们之间是”或”的关系,即只要其中有一个条件系统满足,RPM就将执行触发脚本程序。如上面介绍-p选项时举的例子:例子中有两个触发条件fileutils>3.0和perl<1.2,在安装软件包时,只要有一个条件满足,RPM就会执行触发脚本,即输出”I’m in my trigger!”。


3.2 交互用功能段的使用

为什么要使用交互用功能段?下面的例子很能说明问题。

假定mymailer软件包需要/etc/mymailer/mailer这个符号连接文件指向当前使用的邮件发送代理程序。如果sendmail包安装了,那么这个符号连接文件应指向/usr/bin/sendmail程序。如果vmail包安装了,那么它应当指向/usr/bin/vmail程序。如果这两个软件包都安装了(实际上,sendmail与vmail彼此是冲突的),那么我们也无需考虑符号连接指向哪个文件了。当然,如果这两个包都未安装,那么/etc/mymailer/mailer符号连接文件也没有理由存在了。


上述要求,我们通过为mymailer软件包编写触发脚本程序来实现,这些脚本程序在下列事件发生时,将改变/etc/mymailer/mailer符号连接的内容:

1) sendmail已安装;

2) vmail已安装;

3) sendmail卸载时;

4) vmail卸载时。


前两个事件触发的脚本程序可以这样写:

%triggerin — sendmail

ln -sf /usr/bin/sendmail /etc/mymailer/mailer

%triggerin — vmail

ln -sf /usr/bin/vmail /etc/mymailer/mailer


这是两个安装时被sendmail或vmail所触发脚本程序。它们将在下列情况下执行:

1) 在mymailer包已安装的情况下,安装或升级sendmail包;

2) 在mymailer包已安装的情况下,安装或升级vmail包;

3) 在sendmail包已安装的情况下,安装或升级mymailer包;

4) 在vmail包已安装的情况下,安装或升级mymailer包。

后两个事件触发的脚本程序可以这么写:

%triggerun — sendmail

[ $2 = 0 ] || exit 0

if [ -f /usr/bin/vmail ]

then

ln -sf /usr/bin/vmail /etc/mymailer/mailer

else

rm -f /etc/mymailer/mailer

fi

%triggerun — vmail

[ $2 = 0 ] || exit 0

if [ -f /usr/bin/sendmail ]

then

ln -sf /usr/bin/sendmail /etc/mymailer/mailer

else

rm -f /etc/mymailer/mailer

fi


这两个脚本程序在下列情况下触发执行:

1) 在sendmail包已安装的情况下,卸载mymailer包;

2) 在vmail包已安装的情况下,卸载mymailer包;

3) 在mymailer包已安装的情况下,卸载sendmail包;

4) 在mymailer包已安装的情况下,卸载vmail包。

为了确保在mymailer包卸载后符号连接文件/etc/mymailer/mailer也被删除,可以在

mymailer软件包描述文件的%postun功能段内,加上删除该文件的命令:

%postun

[ $1 = 0 ] && rm -f /etc/mymailer/mailer


注: %postun段内为卸载后执行脚本程序,在mymailer包卸载后执行。

由上看出,当一个软件包与另一个软件包存在密切关系时,我们可以通过交互用功能段实现某些文件的管理,这不仅扩展了RPM软件包管理的功能,又有助于软件包的正常运行。


4. 其它功能段

其它功能段只有一个,即%changelog。这个段的内容是软件维护记录,它记录每次软件维护的时间,维护人及其EMAIL,维护的项目等。

%changelog段内容格式为:

* 星期 月份 日子 年份 维护内容

注: 每个维护记录均以*开头,星期,月份均须为英文缩写。维护内容多时可分行编写,

每行开头最好以减号(-)开头。可以采用类似LZE方式的维护记录写作格式:(见LZE描述文件第80-85行)


一个RPM的软件包描述文件,可以仅生成一个父包或一个子包,也可以生成一个父包和多个子包。通过设定子包选项,可以使生成的子包采用”软件名-子包名”的标准命名,也可使生成的子包采用自己的名字。一个子包,通常是按照其包含的文件的用途或类型来归并文件进而打成包裹的。象前面的LZE描述文件很简单,它将所有文件都包含进了父包中。我们也可以将文件分类作成子软件包,如可分成执行程序子包(lze-bin),配置文件子包(lze-config)和说明文档包(lze-doc)。我们还可以只分出一个配置文件子包(lze-config),其余文件均打入父包中(lze)。通过这样详细地分类,有助于用户管理软件包,避免安装多余的东西,同时也有助于升级。


要想创建子软件包,必须描述以下内容:


1. %package :

用此段创建一个子包。其名字由子包选项控制。子包选项为”[-n] 子包名”,不选-n时,生成的子包文件为”软件名-子包名-版本号-释出号.体系.rpm”;选-n时,生成的子包文件为”子包名-版本号-释出号.体系.rpm”。其应用格式为:


%package 子包选项


2. Summary


此域必须在%package下面,它定义子包功能简介(一句话说明)。格式为:


Summary : 子包简介


3. Group


此域必须在%package下面,其定义子包所属软件类别(软件类别请参见<<精通RPM之五–查询篇>>)。格式为:


Group : 软件类别


4. %description :


此描述段的内容是较为详细的子包功能介绍,介绍为文本形式,格式不作要求,可任意换行或分段。格式为:

%description 子包选项

…介绍子包功能的内容…


5. %files :

此文件段的内容是子包所要包含的文件列表。文件列表中,一个文件占用一行,还可使用多种文件修饰符。(详见<<精通RPM之七–制作篇(上)>>)


段名应用格式为:


%files 子包选项 [-f 文件名]


注意: 上述%description与%files段所用的子包选项形式,必须与%package所用的子包选项形式一致,否则的话,它们定义的不是同一个子包,RPM检查时将报错退出。如定义过%package name后,描述段名须用%description name,文件段名须用%files name方可。而用%description -n name则不行,%files -n name也不行。


子软件包也可使用%pre,%post,%preun,%postun,%triggerin,%triggerun和%triggerpostun等七个可选的功能段,因为它们都可使用子包选项。当使用子包选项时,它们的段内容就是用来管理子软件包的脚本程序。要注意的是,这些段使用的子包选项形式也必须与%package段使用的子包选项形式一致。


条件语句的使用


在软件包描述文件中,可以灵活地使用条件语句,位置不限制。这些语句,用于当前体系与操作系统的判断,当条件为真或为假时,RPM均会引用其相应的描述内容。


条件语句有两种格式:


1. {%ifarch,%ifnarch,%ifos,%ifnos} 值1 [值2] …

描述内容

%endif


注: {}所括内容必选其中之一,[]所括为可选项,各个值之间以空格分隔,%endif表示条件语句结束。


此语句的含义是:

1) 使用%ifarch时,表示如果当前体系为值1或值2…,则引用描述内容。

2) 使用%ifnarch时,表示如果当前体系不为值1或值2…,则引用描述内容。

3) 使用%ifos时,表示如果当前操作系统为值1或值2…,则引用描述内容。

4) 使用%ifnos时,表示如果当前操作系统不为值1或值2…,则引用描述内容。


如果想在LZE包描述文件的文件段增加只适用于sparc体系的文件/etc/sparc.lze和 /etc/sparc.ime,则可在文件段内加入如下语句:

%ifarch sparc

/etc/sparc.lze

/etc/sparc.ime

%endif


这样做以后,如果当前体系为sparc,则RPM在打包时会加入这两个文件。


2. {%ifarch,%ifnarch,%ifos,%ifnos} 值1 [值2] …

描述内容1

%else

描述内容2

%endif


注: {}所括内容必选其中之一,[]所括为可选项,各个值之间以空格分隔,%else表示另外一种情况,%endif表示条件语句结束。


此语句的含义是:

1) 使用%ifarch时,表示如果当前体系为值1或值2…,则引用描述内容1,否则引用描述 内容2。

2) 使用%ifnarch时,表示如果当前体系不为值1或值2…,则引用描述内容1,否则引用描述内容2。

3) 使用%ifos时,表示如果当前操作系统为值1或值2…,则引用描述内容1,否则引用描述内容2。

4) 使用%ifnos时,表示如果当前操作系统不为值1或值2…,则引用描述内容1,否则引用描述内容2。


如果想根据当前操作系统来确定LZE包的名字,则可在描述文件头使用如下语句定义Name域:

%ifos linux

Name : lzeforlinux

%else


%ifos aix

Name : lzeforaix

%else

Name : lzeforothersys

%endif


%endif


本例中使用了嵌套的条件语句,它说明的情况是:如果操作系统为linux,则软件名定为lzeforlinux,如果操作系统为aix,则软件名定为lzeforaix,如果不是上述两个操作系统,则将软件名定为lzeforothersys。


如何在描述文件中使用宏(macros)


1. 宏是什么?

学过C语言的人都知道,宏是用来实现文本替换的,即定义了宏名与宏体后,文件中所有有宏名的地方在预处理时将被宏体替换掉。使用宏可以减少文字的录入量,方便了编程人员。在软件包描述文件中使用宏,也是基于这个目的,只不过这个宏与C语言的宏定义格式不同而已。


2. 宏的定义


描述文件中宏的定义格式为:


%define [(opts)]


注: []所括为可选项。为宏名,宏名可用字母,数字和下划线(_),并且其长度最小为3。opts为一个或多个选项,各选项之间无分隔,选项采用getopt函数要求的形式,即选项为单个字符,如果某个选项需要参数,则需要在这个选项后加个冒号(:)。为宏体,它周围的空字符将被删掉。宏体的内容须在一行上。


如没有选项的宏定义:


%define aaa “This is my software”



如仅有一个选项的宏定义:


%define xxx(p:Z) echo %{-p:%{-p*}} %{-Z}


3. 宏的使用


宏的使用格式为:

% [opt1] [opt2]… [arg1] [arg2]…



%{} [opt1] [opt2]… [arg1] [arg2]…



注: []所括为可选项;为所应用的宏名,宏名可以用{}括住;opt1,opt2…为选项,均须以减号(-)开头,并且如果选项需要参数,则必须提供一个选项参数;arg1,arg2…则为宏的参数。


如上面定义的xxx宏,可这样使用:


%xxx -p zhsoft hello world<

br>

例子中,xxx宏使用一个选项-p,zhsoft为-p选项的参数,还有两个宏的参数hello和world。


注意: 宏使用时最好多换一行(即宏下面空一行),因为宏在扩展后并不换行,这样如果不多换行,则下面一行若有内容的话,宏扩展后的内容将和下面一行的内容合并在一起,极容易出现错误。这也是笔者发现RPM宏的问题之一。还有一个问题,如果注释行上存在宏,则这个宏也将扩展,错矣!因为注释本来就是要忽略掉的,有宏也不必再扩展了。这两个问题都需要引起RPM开发者的注意,并切实加以解决。


4. 宏体专用的宏

宏体中可使用如下专用的宏:(类似SHELL形式的宏)


1) %0 : 表示所在宏的宏名;

2) %* : 表示宏的所有参数;

3) %# : 表示宏的参数个数;

4) %{-f} : 表示如果宏使用了-f选项,则它表示-f及其选项参数;

5) %{-f*} : 表示如果宏使用了-f选项,则它表示-f所带的参数;

6) %{-f:X} : 表示如果宏使用了-f选项,则它表示X;

7) %{!-f:Y} : 表示如果宏没有使用-f选项,则它表示Y;

8) %1,%2,… : 表示宏的参数1,参数2…


如,上例中xxx宏执行时,若宏体中有上述专用的宏,则专用宏将会扩展为:


1) %0扩展为xxx;

2) %*扩展为hello world;

3) %#扩展为2;

4) %{-p}扩展为-p zhsoft;

5) %{-p*}扩展为zhsoft;

6) %{-p:good}扩展为good;

7) %{!-Z:bad}扩展为bad; (因为xxx宏未使用-Z选项)

8) %1为hello,%2为world,没有其它参数。


5. 系统内置的宏


系统内置的宏可分如下三类:


5.1 定义类

1) %define … : 定义一个宏;(原来,%define也是一个宏啊)

2) %undefine … : 取消一个宏;(宏取消后,此语句下面的描述文件就不能再使用这个宏了,即使使用,该宏也不会被扩展了)


5.2 调试类

1) %trace : 打印宏扩展前后的调试信息;

2) %dump : 打印活动的宏(宏名及宏体);

3) %{echo:…} : 打印…到标准错误设备;

4) %{warn:…} : 打印…到标准错误设备;

5) %{error:…} : 打印…到标准错误设备,并且返回BADSPEC值;


5.3 特殊类

这类宏的默认值通常放在/usr/lib/rpm/macros文件中,用户通过编辑自己主目录(HOME)下的.rpmmacros文件(~/.rpmmacros),可重定义这类宏,改变其默认值,以供RPM在软件包制作,安装及查询时使用自己的定义。


这类宏的定义格式为:


%



注: 为宏名,为宏体。


1) %packager,%vendor,%distribution :


这三个宏用于定义描述文件中Packager,Vendor,Distribution三个可选域的默认的域值,即如果这三个域中有哪个未在描述文件中定义,且其相对应的宏有定义,则RPM会采用其对应的宏的宏体。


如我的~/.rpmmacros文件中有这样三行:


%vendor 纵横软件制作中心

%packager 雨亦奇

%distribution 小赵’2001


这样,软件包描述文件中再也不用定义那三个域了,由此制作出来的软件包在查询时,其打包者(Packager),销售商(Vendor)及发行版(Distribution)均自动搞定了,一劳永逸。


2) %buildroot,%_provides :


这两个宏定义软件包建包时用的根目录及软件包所提供的功能。它们在打包时不会象 上面那三个宏一样主动被RPM采用,而是必须在描述文件中写那么几行。即:


%vendor 纵横软件制作中心

%packager 雨亦奇

%distribution 小赵’2001

Buildroot : %buildroot

Provides : %_provides


3) %_topdir,%_builddir,%_rpmdir,%_sourcedir,%_specdir,%_srcrpmdir :


这六个宏都是RPM制作软件包时要用的,它们在/usr/lib/rpm/macros文件中的默认值为:


%_topdir %{_usrsrc}/dist

%_builddir %{_topdir}/BUILD

%_rpmdir %{_topdir}/RPMS

%_sourcedir %{_topdir}/SOURCES

%_specdir %{_topdir}/SPECS

%_srcrpmdir %{_topdir}/SRPMS


%_topdir宏定义的是RPM制作软件包时所用目录的顶层目录,一般为/usr/src/dist(%{_usrsrc} 宏的值为/usr/src)。在顶层目录下面,又有五个子目录:


* 编译连接源程序时用的目录,由%_builddir宏定义,常用BUILD;

* 生成的RPM执行程序包存放的目录,由%_rpmdir宏定义,常用RPMS;

* 软件源程序存放的目录,由%_sourcedir宏定义,常用SOURCES;

* 软件包描述文件存放的目录,由%_specdir宏定义,常用SPECS;

* 生成的RPM源程序包存放的目录,由%_srcrpmdir宏定义,常用SRPMS。


由于宏的递归特性,我们可以通过只定义%_topdir宏来达到改变%_builddir等五个宏的目的。(注意:%_builddir等五个宏的宏体如无特殊要求,尽量不要改变,它们是标准的定义,应该采用)这对于普通用户来说,意义非常重大。因为RPM默认的顶层目录/usr/src/dist并不是每个用户都可以随便使用的,普通用户更想在自己所有的目录下用RPM来制作些软件包。我也有这种想法,所以在~/.rpmmacros文件里加上这么一行:


%_topdir /usr/zzz/rpm



同时,在此宏定义的目录下面建立了RPM所需的子目录,使用命令为:


$ cd /usr/zzz

$ mkdir -p rpm/{BUILD,RPMS/i386,SOURCES,SPECS,SRPMS}

$


命令中的i386是RPM默认的体系名,RPM生成的执行程序包是存放在“RPMS/体系名”目录下面的。这么做以后,我就可以在自己的目录下制作RPM软件包了,象超级用户一样自由。


4)%_excludedocs,%_ftpport,%_ftpproxy,%_httpport,%_httpproxy,%_netsharepath :


这六个宏对RPM软件包的安装和查询起作用。


* %_excludedocs : 如果其值定义为1,则RPM安装软件包时,对说明文档的默认作法是不安装;

* %_ftpport : 此宏用于定义RPM默认的FTP端口;

* %_ftpproxy : 此宏用于定义RPM默认的FTP代理服务器;

* %_httpport : 此宏用于定义RPM默认的HTTP端口;

* %_httpproxy : 此宏用于定义RPM默认的HTTP代理服务器;

* %_netsharepath : 此宏用于定义RPM默认的网络共享目录,适用于网络文件系统(NFS)。


6. 一种特殊的宏

这种宏的用法是:


%(SHELL命令及其参数)


它的结果是取指定的SHELL命令的标准输出的结果作为描述文件内容的一部分。如软件包描述文件的某个部分需要加上当前日期,则可以用:


%(date +%Y-%m-%d)



执行后,该宏将扩展为类似2001-10-31的日期数据。用户不妨在自己的描述文件的预处理段(%prep)内加上这么两行试试:


%(date +%Y-%m-%d)

exit 1


注: exit 1用于中止RPM的执行。


描述文件模板

以下所有描述文件模板均以LZE软件包制作为例,以源程序现场编译后产生的文件为准生成软件包。描述文件中一般只描述必要的部分。另外,如果文件段的所有文件已存在于系统中,并且想直接利用打包,则可以去掉Source域,去掉RPM建包用功能段(%prep,%build,%install,%clean)。


1. 只有父包,没有任何子包:

此描述文件见<<精通RPM之七–制作篇(上)>>。此文件中还可以去掉几个可选的功能段, 如%pre,%post,%preun,%postun,%triggerin,%triggerun,%triggerpostun。这几个段在此文件中无实质用途,执行时仅显示RPM开始执行某个脚本程序的信息。此描述文件仅生成软件包lze-6.0-2.i386.rpm(父包)。


2. 有父包,也有子包:


描述文件如下:


1 # 文件名称: lze-6.0-2.spec1

2 # 文件功能: lze软件包描述信息

3 # 文件作者: 纵横软件制作中心雨亦奇 国防大学研究生二队赵建利

4 # 修改时间: 2001.10.31

5

6 Name: lze

7 Version: 6.0

8 Release: 2

9 Summary: 小赵全屏幕中英文多窗口多功能编辑器(LINUX/UNIX系统适用)

10 Group: Applications/Editors

11 License: Share

12 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz

13

14 %description

15 小赵编辑器,是为使用SCO UNIX,LINUX多用户系统的广大用户专门设计的全屏幕多窗

16 口中英文多功能编辑器。

17 它主要有以下十大特点:1.全屏幕菜单操作。2.显示方式多样。3.块操作丰富。4.十

18 字制表功能强大。5.多窗口操作灵活自如。6.文件操作功能齐全。7.解释输出功能独具特

19 色。8.自带中文输入法(增强五笔和增强拼音),实用方便。9.十六进制编辑功能,如虎

20 添翼。10.即时翻译,按到即译。

21 总之,小赵编辑器会成为您在UNIX,LINUX系统上编制程序和书写一般性文稿的好帮手。

22 它将在工作中助您一臂之力,轻松上阵,游刃有余!

23

24 %prep

25 echo “预处理脚本程序(prep)开始执行”

26 %setup

27

28 %build

29 echo “编译连接脚本程序(build)开始执行”

30 make

31

32 %install

33 echo “安装脚本程序(install)开始执行”

34 make install

35

36 # 配置文件子包

37 %package config

38 summary : 小赵编辑器LZE的配置文件

39 group : Applications/Editors

40

41 %description config

42 小赵编辑器用配置文件包括功能键定义文件与

43 输入法控制文件,用户可根据实际情况加以修改。

44

45 %files config

46 %config /etc/funkey.def

47 %config /etc/inputme.def

48

49 # 说明文档子包

50 %package doc

51 summary : 小赵编辑器LZE的说明文档

52 group : Applications/Editors

53

54 %description doc

55 小赵编辑器说明文档,详细介绍了该编辑器的

56 命令行用法及内置的各项菜单的功能与操作,对用

57 户熟悉小赵编辑器有很大作用。

58

59 %files doc

60 %doc /usr/doc/lze-6.0/README

61 %doc /usr/doc/lze-6.0/LICENSE

62

63 # 父包文件段

64 %files

65 %defattr (-,root,root)

66 /usr/bin/lze

67 /usr/bin/lzeime.py

68 /usr/bin/lzeime.wb

69 /etc/wbzc.dat

70

此描述文件生成软件包有:lze-6.0-2.i386.rpm(父包),lze-config-6.0-2.i386.rpm(配置文件子包)和lze-doc-6.0-2.i386.rpm(说明文档子包)。


3. 没有父包,只有子包:

没有父包,意味着描述文件中可以没有父包的文件段(%files),请看下面的描述文件:


1 # 文件名称: lze-6.0-2.spec2

2 # 文件功能: lze软件包描述信息

3 # 文件作者: 纵横软件制作中心雨亦奇 国防大学研究生二队赵建利

4 # 修改时间: 2001.10.31

5

6 Name: lze

7 Version: 6.0

8 Release: 2

9 Summary: 小赵全屏幕中英文多窗口多功能编辑器(LINUX/UNIX系统适用)

10 Group: Applications/Editors

11 License: Share

12 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz

13

14 %description

15 小赵编辑器,是为使用SCO UNIX,LINUX多用户系统的广大用户专门设计的全屏幕多窗

16 口中英文多功能编辑器。

17 它主要有以下十大特点:1.全屏幕菜单操作。2.显示方式多样。3.块操作丰富。4.十

18 字制表功能强大。5.多窗口操作灵活自如。6.文件操作功能齐全。7.解释输出功能独具特

19 色。8.自带中文输入法(增强五笔和增强拼音),实用方便。9.十六进制编辑功能,如虎

20 添翼。10.即时翻译,按到即译。

21 总之,小赵编辑器会成为您在UNIX,LINUX系统上编制程序和书写一般性文稿的好帮手。

22 它将在工作中助您一臂之力,轻松上阵,游刃有余!

23

24 %prep

25 echo “预处理脚本程序(prep)开始执行”

26 %setup

27

28 %build

29 echo “编译连接脚本程序(build)开始执行”

30 make

31

32 %install

33 echo “安装脚本程序(install)开始执行”

34 make install

35

36 # 配置文件子包

37 %package config

38 summary : 小赵编辑器LZE的配置文件

39 group : Applications/Editors

40

41 %description config

42 小赵编辑器用配置文件包括功能键定义文件与

43 输入法控制文件,用户可根据实际情况加以修改。

44

45 %files config

46 %config /etc/funkey.def

47 %config /etc/inputme.def

48

49 # 说明文档子包

50 %package doc

51 summary : 小赵编辑器LZE的说明文档

52 group : Applications/Editors

53

54 %description doc

55 小赵编辑器说明文档,详细介绍了该编辑器的

56 命令行用法及内置的各项菜单的功能与操作,对用

57 户熟悉小赵编辑器有很大作用。

58

59 %files doc

60 %doc /usr/doc/lze-6.0/README

61 %doc /usr/doc/lze-6.0/LICENSE

62

63 # 执行程序子包

64 %package bin

65 summary : 小赵编辑器LZE的执行程序

66 group : Applications/Editors

67

68 %description bin

69 小赵编辑器执行程序为lze,五笔输入法服务器执行程序

70 为lzeime.wb,拼音输入法服务器执行程序为lzeime.py。

71

72 %files bin

73 %defattr (-,root,root)

74 /usr/bin/lze

75 /usr/bin/lzeime.py

76 /usr/bin/lzeime.wb

77 /etc/wbzc.dat

78


此描述文件生成三个软件包:lze-config-6.0-2.i386.rpm(配置文件子包),lze-doc-6.0-2.i386.rpm(说明文档子包),lze-bin-6.0-2.i386.rpm(执行程序子包)。


制作篇(下)

(雨亦奇 赵建利2001年12月10日 09:38)


要想制作RPM格式的软件包,需使用如下命令格式:


rpm-bX[制作选项1制作选项2...]描述文件1描述文件2…


注:-bX可用-tX替换,效果有所不同:使用-b时,需要在命令行上指定软件包描述文件;而使用-t时,在命令行上需要指定的不是软件包描述文件,而是含有此描述文件的TAR格式的包裹文件(必须用gzip压缩),RPM在准备制作软件包时,会自动从此包裹文件中提取描述文件,根据其中的建包指令,生成RPM格式的软件包。注意:此描述文件必须以.spec为后缀,其中必须有Source域,并且此域定义的源程序包必须存放在当前目录下,否则的话,RPM将报错退出。

注意,-bX与-tX当中的X,取不同的值时,RPM将执行不同的操作:(下面各个例子均对LZE的描述文件lze-6.0-2.spec进行操作,有的则通过管道技术,用nl命令给输出加上行号,以便解释)


1)X=p时,指示RPM执行描述文件中的预处理段(%prep)的脚本程序。该脚本程序一般用来解压源程序包,并且为源程序打补丁,升级源程序。

#rpm-bplze-6.0-2.spec2>&1|nl

1Executing:%prep

2+umask022

3+cd/usr/src/dist/BUILD

4+echo’预处理脚本程序(prep)开始执行’

5预处理脚本程序(prep)开始执行

6+cd/usr/src/dist/BUILD

7+rm-rflze-6.0

8+/bin/gzip-dc/usr/src/dist/SOURCES/lze-6.0-2.src.tgz

9+tar-xvvf-

10drwxr-xr-xroot/root02001-11-0216:02lze-6.0/

11-rw——-root/root2462262001-11-0216:00lze-6.0/lze.c

12-rw——-root/root982492001-11-0216:00lze-6.0/lzeime.wb.c

13-rw——-root/root3399022001-11-0216:00lze-6.0/lzeime.py.c

14-rw-r–r–root/root12832001-11-0216:00lze-6.0/funkey.def

15-rwxr–r–root/root2502001-11-0216:00lze-6.0/inputme.def

16-rw-r–r–root/root8132742001-11-0216:00lze-6.0/wbzc.dat

17-rw——-root/root4742001-11-0216:02lze-6.0/makefile

18+STATUS=0

19+’['0-ne0']‘

20+cdlze-6.0

21++/usr/bin/id-u

22+’['0=0']‘

23+/bin/chown-Rhfroot.

24++/usr/bin/id-u

25+’['0=0']‘

26+/bin/chgrp-Rhfroot.

27+/bin/chmod-Rfa+rX,g-w,o-w.

28+exit0

#


注:本例中第1行显示的”Executing:%prep”表明RPM开始执行预处理段的脚本程序。例中行号后那些以加号(+)开始的行均为预处理段脚本程序的指令,其它内容则为指令执行所输出的结果。从预处理段脚本程序所执行的指令,我们就可以看出RPM正在做什么:

第2行:设置文件创建掩码;

第3行:转到RPM默认的编译目录;

第4行:回显字符串,这才是用户所写的预处理段脚本程序的开始,第2,3行均是RPM增加的指令;

第6-27行:为%setup所扩展出来的指令及其执行结果,其中可以看到RPM用gzip命令解压LZE的源程序包(第8行),而后用tar命令展开源程序包(第9行)。

第28行:正常退出,返回值为0。


2)X=l时,指示RPM检查文件段(%files),看其中的文件是否存在。如果不存在,则RPM会报错退出。

#rpm-bl-vvlze-6.0-2.spec|nl

1Processingfiles:lze

2D:File0:0100644root.root/etc/funkey.def

3D:File1:0100644root.root/etc/inputme.def

4D:File2:0100644root.root/usr/doc/lze-6.0-2/README

5Filenotfound:/usr/doc/lze-6.0-2/LICENSE

6D:File3:0100555root.root/usr/bin/lze

7D:File4:0100511root.root/usr/bin/lzeime.py

8D:File5:0100511root.root/usr/bin/lzeime.wb

9D:File6:0100644root.root/etc/wbzc.dat

10Provides:lze-edit

11PreReq:/bin/sh

12Requires:/bin/sh

#


注:本例命令中使用了通用选项-vv,以输出RPM检查时的调试信息(以行号和D:开始的行)。

由上看出,RPM对文件段的所有文件逐一进行检查,找到的文件显示其权限,属主和属组信息,结果发现/usr/doc/lze-6.0-2.LICENSE文件不存在,于是报出错误(File not found)(见第5行)。RPM在检查过文件后,还显示出描述文件要求LZE提供的功能(Provides)和所需的功能(Requires)。


3)当X=c时,指示RPM依次执行预处理段(%prep),编译段(%build)的脚本程序。编译段的脚本程序用来编译连接软件的源程序,生成可执行程序,通常一个make命令足够。因为一个有良好习惯的程序员会把Makefile(程序维护文件)写好,以便其它程序员编译该软件。如果某个软件没有维护文件的话,用户要么自己写个Makefile,要么在编译段里写上软件编译与连接的各项命令。


4)当X=i时,指示RPM依次执行预处理段(%prep),编译段(%build)和安装段(%install)的脚本程序。安装段的脚本程序的任务是将编译连接好的执行程序拷贝到适当的目录(如/bin,/usr/bin等公共执行目录),以便打包或执行。它通常执行的指令是make install。


5)当X=b时,指示RPM依次执行预处理段(%prep),编译段(%build),安装段(%install)的脚本程序,之后根据文件段(%files)的文件列表,将文件打包,生成RPM执行程序包,最后执行清理段(%clean)。

#rpm-bblze-6.0-2.spec2>&1|nl

1Executing:%prep

2+umask022

3+cd/usr/src/dist/BUILD

4+echo’预处理脚本程序(prep)开始执行’

5预处理脚本程序(prep)开始执行

6+cd/usr/src/dist/BUILD

7+rm-rflze-6.0

8+tar-xvvf-

9+/bin/gzip-dc/usr/src/dist/SOURCES/lze-6.0-2.src.tgz

10drwxr-xr-xroot/root02001-11-0217:04lze-6.0/

11-rw——-root/root2462262001-11-0216:00lze-6.0/lze.c

12-rw——-root/root982492001-11-0216:00lze-6.0/lzeime.wb.c

13-rw——-root/root3399022001-11-0216:00lze-6.0/lzeime.py.c

14-rw-r–r–root/root12832001-11-0216:00lze-6.0/funkey.def

15-rwxr–r–root/root2502001-11-0216:00lze-6.0/inputme.def

16-rw-r–r–root/root8132742001-11-0216:00lze-6.0/wbzc.dat

17-rw——-root/root4742001-11-0216:02lze-6.0/makefile

18-rw-r–r–root/root12552001-11-0217:04lze-6.0/getinputme.c

19+STATUS=0

20+’['0-ne0']‘

21+cdlze-6.0

22++/usr/bin/id-u

23+’['0=0']‘

24+/bin/chown-Rhfroot.

25++/usr/bin/id-u

26+’['0=0']‘

27+/bin/chgrp-Rhfroot.

28+/bin/chmod-Rfa+rX,g-w,o-w.

29+exit0

30Executing:%build

31+umask022

32+cd/usr/src/dist/BUILD

33+cdlze-6.0

34+echo’编译连接脚本程序(build)开始执行’

35编译连接脚本程序(build)开始执行

36+make

37cc-fwritable-strings-DUSE_AS_LZE-DFOR_LINUX-s-I/usr/zzz/src/include-DFOR_LZE_INPUTME-olze/usr/zzz/src/li-

38bsrc/mycurses.clze.cgetinputme.c/usr/zzz/src/my.a

39cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.wbgetinputme.clzeime.wb.c/usr/zzz/src/my.a

40lzeime.wb.c:Infunction`do_service’:

41lzeime.wb.c:1409:warning:passingarg5of`bsearch’fromincompatiblepointertype

42cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.pygetinputme.clzeime.py.c/usr/zzz/src/my.a

43+exit0

44Executing:%install

45+umask022

46+cd/usr/src/dist/BUILD

47+cdlze-6.0

48+echo’安装脚本程序(install)开始执行’

49安装脚本程序(install)开始执行

50+makeinstall

51installing…

52done

53+exit0

54Processingfiles:lze

55FindingProvides:(using/usr/lib/rpm/find-provides)…

56FindingRequires:(using/usr/lib/rpm/find-requires)…

57Provides:lze-edit

58PreReq:/bin/sh

59Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

60Wrote:/usr/src/dist/RPMS/i386/lze-6.0-2.i386.rpm

61Executing:%clean

62+umask022

63+cd/usr/src/dist/BUILD

64+cdlze-6.0

65+echo’建包结束后清理脚本程序(clean)开始执行’

66建包结束后清理脚本程序(clean)开始执行

67+exit0

#


注:本例中,各行解释如下:

第1行:显示RPM开始执行预处理段(%prep);

第2-29行:为预处理段(%prep)脚本程序执行的命令与结果,命令前有加号(+),结果前面则没有。预处理完成了LZE源程序包的解压缩(gzip-dc)与包的展开(tar-xvvf),从而为源程序的编译打下了基础;

第30行:RPM表示开始执行编译段(%build);

第31-43行:为编译段(%build)脚本程序执行的命令与结果。脚本程序执行的make维护命令,该命令执行了cc编译程序,以编译与连接LZE软件;

第44行:RPM表示开始执行安装段(%install);

第45-53行:为安装段(%install)脚本程序执行的命令与结果。本段程序执行了makeinstall命令,将LZE的执行程序等文件拷贝到系统目录下;

第54行:RPM显示:开始处理LZE的文件(为%files文件段的内容);

第55-59行:RPM利用/usr/lib/rpm/find-provides程序查找LZE提供的功能,又利用/usr/lib/rpm/find-requires查找LZE所依赖的功能,以设定LZE的依赖关系;

第60行:制作完成LZE执行程序包,文件名为lze-6.0-2.i386.rpm,在/usr/src/dist/RPMS/i386目录下;

第61行:RPM显示:开始执行清理段(%clean)脚本程序,本段程序用于清理临时文件;

第62-67行:为清理段(%clean)脚本程序执行的命令与结果。


从上我们可以清楚看出RPM制作软件包的工作流程:预处理段,编译段,安装段,软件包制作,清理段。


6)当X=s时,指示RPM建立源码包。RPM源码包的内容包括软件包描述文件(SPEC),软件源程序,软件补丁程序,图标文件等几项。建立源码包不需要执行软件包描述文件中的各个功能段,仅需将所需文件包含到包中即可。


#rpm-bslze-6.0-2.spec

Wrote:/usr/src/dist/SRPMS/lze-6.0-2.src.rpm

#rpm-qplv/usr/src/dist/SRPMS/lze-6.0-2.src.rpm

-rw——-rootroot206711月215:44lze-6.0-2.spec

-rw-r–r–rootroot53870611月217:05lze-6.0-2.src.tgz

#


注:本例中,使用rpm-bs命令生成了LZE源码包lze-6.0-2.src.rpm(在RPM标准源码目录/usr/src/dist/SRPMS下),然后用rpm -qplv命令查询源码包中所含的文件信息,从中可以看到LZE源码包中有两个文件:一个是软件包描述文件lze-6.0-2.spec,一个是LZE源代码包lze-6.0-2.src.tgz(TAR打包再用gzip压缩),此文件由描述文件中的Source域确定。


7)当X=a时,指示RPM依次执行预处理段(%prep),编译段(%build),安装段(%install)脚本程序,之后先生成RPM源码包,再根据文件段(%files)的文件列表,将文件打包,生成RPM执行程序包,最后执行清理段(%clean)脚本程序,清除中间文件。此命令执行的结果相当于先执行rpm-bs命令生成源码包,再执行rpm-bb命令生成执行码包。


选项列表



选项详解


通用选项的解释见<<精通RPM之二–安装篇>>,本文不再赘述。


1.–short-circuit:单步执行

此选项的目的在于单步执行功能段,仅适用命令为RPM-bc(或-tc)和-bi(或-ti)时。当用rpm-bc–short-circuit命令时,RPM将不再执行预处理段(%prep)的脚本程序,直接执行编译段(%build)的脚本程序。当用rpm-bi–short-circuit命令时,RPM将不再执行预处理段(%prep)和编译段(%build)的脚本程序,仅执行安装段(%install)的脚本程序。


为什么要使用这个选项?其原因可能是源程序包中的文件有问题,导致RPM在编译或安装过程中出现了这样或那样的错误,如不能单步执行,则无法排除这些错误。单步执行后,用户可以进入源程序所在的目录,查看源程序,修改错误,然后再用tar命令生成一个正确的源程序包,覆盖掉原包即可。这样,RPM再制作时就不会有问题了。


2.–timecheck:设置时间检查值

该选项的用法是:–timecheck

注:为检查的时间段,单位是秒,如–timecheck600设置检查的时间段为600秒,即10分钟。


设置时间检查值的目的,在于检验打包文件是否是指定时间段内产生的新文件,如果不是,则RPM会产生警告信息,提醒用户某个文件不是新文件,而是老文件,可能是某种错误导致的。这种错误,可能是由于makefile(维护文件)或描述文件中的安装段脚本程序书写不正确,从而使某个程序不能正确安装到指定目录,因而RPM打包时总是引用老的程序文件。如下面的例子:

#rpm-bl–timecheck600lze-6.0-2.spec

Processingfiles:lze

warning:TIMECHECKfailure:/usr/bin/lze

FindingProvides:(using/usr/lib/rpm/find-provides)…

FindingRequires:(using/usr/lib/rpm/find-requires)…

Provides:lze-edit

PreReq:/bin/sh

Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

#


注:本例中利用RPM检查文件列表,看哪个文件是在10分钟以前产生的老文件,结果RPM发出警告信息:“warning:TIMECHECKfailure:/usr/bin/lze”,这说明文件/usr/bin/lze时间检查出现错误,这是个老文件。经查,是makefile的问题,里面少了一句“cplze/usr/bin”。修正后,再次编译连接程序,再进行时间检查就没有这个问题了。


3.–buildroot:设定建包用根目录

该选项的用法是:

–buildroot



注:

为用户指定的建包用的根目录。

此选项相当于在软件包描述文件的文件头加上一行:

Buildroot:



只不过在命令行上设定比较自由罢了。


通过设定建包用根目录,一般用户也可以建立那些只有超级用户(root)才能建立的RPM包了。下面以普通用户zzz建立LZE软件包为例,说明一下这种形式的包的建立过程。


1)在用户zzz的HOME目录(/usr/zzz)下,建立RPM建包所用的目录:

$cd/usr/zzz

$mkdir-prpm/{BUILD,RPMS/i386,SOURCES,SPECS,SRPMS}

$


2)拷贝描述文件lze-6.0-2.spec到rpm/SPECS目录,拷贝源程序包lze-6.0-2.src.tgz到rpm/SOURCES目录。


$cd/usr/zzz

$cp/root/lze-6.0-2.specrpm/SPECS

$cp/root/lze-6.0-2.src.tgzrpm/SOURCES

$


3)建立.rpmmacros文件,编辑它:

$cd/usr/zzz

$vi.rpmmacros

在此文件中增加一行:

%_topdir/usr/zzz/rpm


用于确定RPM建包用的顶层目录为/usr/zzz/rpm。


4)转到描述文件目录,编辑修改lze-6.0-2.spec安装段的脚本程序:

$cd/usr/zzz/rpm/SPECS

$vilze-6.0-2.spec

$


用于确定RPM建包用的顶层目录为/usr/zzz/rpm。


安装段脚本程序修改为:(原make命令被注释掉)


%install

echo”安装脚本程序(install)开始执行”

#makeinstall

mkdir-p$RPM_BUILD_ROOT/usr/bin

mkdir-p$RPM_BUILD_ROOT/etc

mkdir-p$RPM_BUILD_ROOT/usr/doc/lze-6.0

cplzelzeime.wblzeime.py$RPM_BUILD_ROOT/usr/bin

cpinputme.deffunkey.defwbzc.dat$RPM_BUILD_ROOT/etc

cp/usr/doc/lze-6.0/*$RPM_BUILD_ROOT/usr/doc/lze-6.0



注:脚本程序中,使用建包用根目录的环境变量RPM_BUILD_ROOT,相继在建包用根目录下创建若干子目录(usr/bin,etc,usr/doc/lze-6.0),然后拷贝程序或文件到相应的子目录中,从而完成完装。 5)选用–buildroot选项,执行RPM建包命令:

$cd/usr/zzz/rpm/SPECS

$rpm-bb–buildroot/usr/zzz/tmplze-6.0-2.spec

Executing:%prep

+umask022

+cd/usr/zzz/rpm/BUILD

+echo’预处理脚本程序(prep)开始执行’

预处理脚本程序(prep)开始执行

+cd/usr/zzz/rpm/BUILD

+rm-rflze-6.0

+/bin/gzip-dc/usr/zzz/rpm/SOURCES/lze-6.0-2.src.tgz

+tar-xvvf-

drwxr-xr-xroot/root02001-11-0217:04lze-6.0/

-rw——-root/root2462262001-11-0216:00lze-6.0/lze.c

-rw——-root/root982492001-11-0216:00lze-6.0/lzeime.wb.c

-rw——-root/root3399022001-11-0216:00lze-6.0/lzeime.py.c

-rw-r–r–root/root12832001-11-0216:00lze-6.0/funkey.def

-rwxr–r–root/root2502001-11-0216:00lze-6.0/inputme.def

-rw-r–r–root/root8132742001-11-0216:00lze-6.0/wbzc.dat

-rw——-root/root4742001-11-0216:02lze-6.0/makefile

-rw-r–r–root/root12552001-11-0217:04lze-6.0/getinputme.c

+STATUS=0

+’['0-ne0']‘

+cdlze-6.0

++/usr/bin/id-u

+’['500=0']‘

++/usr/bin/id-u

+’['500=0']‘

+/bin/chmod-Rfa+rX,g-w,o-w.

+exit0

Executing:%build

+umask022

+cd/usr/zzz/rpm/BUILD

+cdlze-6.0

+echo’编译连接脚本程序(build)开始执行’

编译连接脚本程序(build)开始执行

+make

cc-fwritable-strings-DUSE_AS_LZE-DFOR_LINUX-s-I/usr/zzz/src/include-DFOR_LZE_INPUTME-olze/usr/zzz/src/libsrc/mycurses.clze.cgetinputme.c/usr/zzz/src/my.a

cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.wbgetinputme.clzeime.wb.c/usr/zzz/src/my.a

lzeime.wb.c:Infunction`do_service’:

lzeime.wb.c:1409:warning:passingarg5of`bsearch’fromincompatiblepointertype

cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.pygetinputme.clzeime.py.c/usr/zzz/src/my.a

+exit0

Executing:%install

+umask022

+cd/usr/zzz/rpm/BUILD

+cdlze-6.0

+echo’安装脚本程序(install)开始执行’

安装脚本程序(install)开始执行

+mkdir-p/usr/zzz/tmp/usr/bin

+mkdir-p/usr/zzz/tmp/etc

+mkdir-p/usr/zzz/tmp/usr/doc/lze-6.0

+cplzelzeime.wblzeime.py/usr/zzz/tmp/usr/bin

+cpinputme.deffunkey.defwbzc.dat/usr/zzz/tmp/etc

+cp/usr/doc/lze-6.0/LICENSE/usr/doc/lze-6.0/README/usr/zzz/tmp/usr/doc/lze-6.0

+exit0

Processingfiles:lze

FindingProvides:(using/usr/lib/rpm/find-provides)…

FindingRequires:(using/usr/lib/rpm/find-requires)…

Provides:lze-edit

PreReq:/bin/sh

Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

Wrote:/usr/zzz/rpm/RPMS/i386/lze-6.0-2.i386.rpm

Executing:%clean

+umask022

+cd/usr/zzz/rpm/BUILD

+cdlze-6.0

+echo’建包结束后清理脚本程序(clean)开始执行’

建包结束后清理脚本程序(clean)开始执行

+exit0

$

注:RPM建包成功后,生成了/usr/zzz/rpm/RPMS/i386/lze-6.0-2.i386.rpm包裹文件,

通过RPM的查询命令,我们就可以知道该包与由超级用户建成的包内容毫无二致:

$rpm-qplv/usr/zzz/rpm/RPMS/i386/lze-6.0-2.i386.rpm

-rw-r–r–rootroot128311月609:24/etc/funkey.def

-rwxr-xr-xrootroot25011月609:24/etc/inputme.def

-rw-r–r–rootroot81327411月609:24/etc/wbzc.dat

-rwxr-xr-xrootroot40863211月609:24/usr/bin/lze

-rwxr-xr-xrootroot8292011月609:24/usr/bin/lzeime.py

-rwxr-xr-xrootroot3856811月609:24/usr/bin/lzeime.wb

-rw-r–r–rootroot121511月609:24/usr/doc/lze-6.0/LICENSE

-rw-r–r–rootroot369011月609:24/usr/doc/lze-6.0/README

$


现在我们可以说,普通用户也可以自由地建立各种形式的RPM软件包了!


4.–target:设定目标平台

该选项的用法为:–target体系-平台-操作系统

注:RPM制作出来的软件包默认的体系为i386,平台为pc,操作系统为linux。如果用户想加以改变,就需要使用此选项来确定一下,如下例:

#rpm-bb–targeti686-pc-solaris–quietlze-6.0-2.spec

创建目标平台:i686-pc-solaris

正在创建目标:i686-pc-solaris

#


本例设定生成的RPM包适用的目标平台为:i686-pc-solaris(即体系为i686,平台为pc,操作系统为solaris)。注意:必须在/usr/src/dist/RPMS目录下创建一个i686的子目录,没有指定体系的子目录,RPM将无法生成软件包。我们可以查询一下生成的软件包,看其适用的体系与操作系统是什么:


#rpm-qp–qf”archis%{arch}nosis%{os}n”/usr/src/dist/RPMS/i686/lze-6.0-2.i686.rpm

archisi686

osissolaris

#


从输出上可以看到,其体系与操作系统正是我们所设定的。


5.–quiet:尽量减少信息输出

此选项的目的,是让RPM减少信息的输出。使用此选项后,如果没有错误发生,RPM就不会输出多余的信息,这时的RPM也显得比较“安静”(quiet)了。

$rpm-bl–quietlze-6.0-2.spec

$


6.–clean:执行文件清理

如果软件包描述文件的清理段(%clean)没有删除临时文件的命令,那么RPM建包结束后那些临时文件还是存在的,占用了一定的空间。如果想让RPM自动删除那些临时文件,可以在建包时使用–clean选项。此选项执行一条命令,即:

rm-rf软件名-版本号


用它来删除”软件名-版本号”目录及该目录下的所有文件。这个”软件名-版本号”目录,也即RPM默认的存放解压后的源程序的目录。

#rpm-bl–cleanlze-6.0-2.spec

Processingfiles:lze

FindingProvides:(using/usr/lib/rpm/find-provides)…

FindingRequires:(using/usr/lib/rpm/find-requires)…

Provides:lze-edit

PreReq:/bin/sh

Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

Executing:–clean

+umask022

+cd/usr/src/dist/BUILD

+rm-rflze-6.0

+exit0


注:例中的“Executing:–clean”表示RPM开始执行自己的文件清理操作。


7.–rmsource:删除源程序及描述文件


此选项用于指示RPM在建包后删除软件源程序和包描述文件,软件源程序由包描述文件中的Source域定义。此选项也可单独使用,如:

#rpm–rmsourcelze-6.0-2.spec

#lslze-6.0-2.spec../SOURCES/lze-6.0-2.src.tgz

ls:lze-6.0-2.spec:文件或目录不存在

ls:../SOURCES/lze-6.0-2.src.tgz:文件或目录不存在

#


8.–sign:软件包内置数字签名

此选项用于在软件包内添加PGP数字签名,通过数字签名,用户可以校验软件包是否原装,是否修改过。要使用PGP数字签名,必须先安装好PGP应用程序及产生自己的密钥对。(有关数字签名的内容,详见<<精通RPM之八–签名篇>>)


使用此选项建包时,RPM会要求输入密码,验证正确后开始执行建包的系列操作,在建包前会产生数字签名,以便写入包中。请看下例:(省略不少输出,……表示)

#rpm-bb–signlze-6.0-2.spec

Enterpassphrase:mypass

Passphraseisgood.

Executing:%prep

……

Executing:%build

……

Executing:%install

……

Processingfiles:lze

……

Requires:/bin/shld-linux.so.2libc.so.6

Generatingsignature:1002

GeneratingsignatureusingPGP.

PrettyGoodPrivacy(tm)Version6.5.8

(c)1999NetworkAssociatesInc.

UsestheRSAREF(tm)Toolkit,whichiscopyrightRSADataSecurity,Inc.

ExportofthissoftwaremayberestrictedbytheU.S.government. Wrote:/root/test/RPMS/i386/lze-6.0-2.i386.rpm

Executing:%clean

……

#


注:例中要求输入密码,输入mypass后校验成功,之后RPM开始建包操作。(实际上,mypass在屏幕上并不显示出来)例中的Generatingsignature之下的几行就是产生数字签名时输出的东西。


其它建包相关的命令


其它建包相关的命令有两个,它们都是针对RPM格式的源码包进行操作的,执行时先安装源码包,然后再根据软件包描述文件进行下一步的工作。 1.重编译命令:

用法为:rpm–recompileRPM源码包1RPM源码包2…

如:

rpm–recompilelze-6.0-2.src.rpm


此命令执行时,首先安装此源码包,然后依次执行源码包内软件包描述文件的预处理段(%prep),编译段(%build),安装段(%install)的脚本程序。此命令相当于以下两条命令:


1)rpm-ilze-6.0-2.src.rpm

2)rpm-bilze-6.0-2.spec


2.重建立命令:

用法为:rpm–rebuildRPM源码包1RPM源码包2…

如:

rpm–rebuildlze-6.0-2.src.rpm


重编译命令执行后并不建立新的RPM软件包,而此重建立命令执行后则会制作出一个新的RPM软件包。重建立命令执行时,首先安装RPM源码包,然后依次执行源码包内软件包描述文件的预处理段(%prep),编译段(%build),安装段(%install),清理段(%clean)的脚本程序,生成一个新的RPM执行包,最后删除源程序包,描述文件及其它临时文件。此命令相当于以下两条命令:

1)rpm-ilze-6.0-2.src.rpm

2)rpm-bb–clean–resourcelze-6.0-2.spec


------------

RPM的另类用法


RPM不仅在安装,升级,卸载方面工作出色,而且在查询方面比其它软件包管理工具更胜一筹。这从以下几种情况可以看出:


* 当你在浏览系统文件时,发现一个文件,想知道它来自哪个软件包时,可以用RPM来查询得知;


* 当你的朋友给你发送来一个软件包,但你不知道这是个什么样的软件包,不知道它做些什么,安装些什么,来源是哪里。这时,你可以用RPM查询搞定;


* 几个月前你安装了XFree86窗口软件,但现在你忘了它的版本号,也不知它的说明文档在哪里。这时,你可以用RPM查询一下这个软件包,得到这方面的信息。


RPM的查询还有一个高级功能,即定制输出功能。你可用–queryformat(或-qf)来定制一下输出格式,这样,RPM查询得到的信息将以你定制的格式输出,这样很是方便,尤适合于程序的自动处理。


命令格式


查询RPM格式的软件包,可使用如下命令格式:


rpm -q [查询选项1 查询选项2...]


注: 也可使用–query代替-q,效果相同。


选项列表


选项详解


指定用选项中ftp与http相关的四个选项(–ftpproxy,–ftpport,–httpproxy,–httpport)和通用选项的解释,请参见<<精通RPM之二–安装篇>>,本文不再赘述。下面对指定用选项做些解释:


指定用选项可分为如下几类:


一、软件包选择类


此类选项在一次只能选择一个,选择多个时RPM将提示错误:


rpm: one type of query/verify may be performed at a time


从查询方面看,一个是查询那些已安装的软件包,一个是查询未安装的软件包。


1. 查询已安装的软件包,使用下列选项:


(1) -a (或–all) : 查询所有已安装的软件包


# rpm -q -a


setup-2.0.2-1


filesystem-1.3.4-5


basesystem-6.0-5


agrep-2.04-5


aktion-0.3.6-2


amor-0.5-1


dhcpcd-1.3.17pl2-1


ldconfig-1.9.5-15


glibc-2.1.2-12


chkconfig-1.0.6-2


……


#


注: 本例查找当前系统中安装的所有软件包,输出很多,仅列出几个,剩下的省略掉了(以……表示)。


(2) -g (或–group) : 查询有哪些软件包属于指定类别


RPM根据软件功用的不同,将软件分为以下若干类:(括号内为注释)


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硬件支持)


Other (其它)


注意: 类别是大小写敏感的,这一点输入时要小心。如果用户想要查询当前系统安装了哪些游戏类的软件包,可这样做:


# rpm -q -g Amusements/Games


clanbomber-1.01-1


kdegames-1.1.2-1


xbill-2.0-6


xboard-4.0.0-3


xboing-2.4-7


xgammon-0.98-14


xjewel-1.6-11


xpat2-1.04-10


xpilot-3.6.2-6


xpuzzles-5.4.1-7


xtrojka-1.2.3-6


#


如果用户想查询若干类别的软件包时,可以把类别都列出来,一起查询,如:


# rpm -q -g Applications/Editors Applications/File


emacs-20.3-15


emacs-nox-20.3-15


emacs-X11-20.3-15


vim-common-5.6-12


vim-minimal-5.6-12


vim-X11-5.6-12


fileutils-4.0-3


bzip2-0.9.5d-1


findutils-4.1-32


git-4.3.17-6


gzip-1.2.4-15


slocate-1.4-7


stat-1.5-12


file-3.26-6


#


注: 本例查询结果中前6个为”应用/编辑器”类别,后8个为”应用/文件”类别。


(3) -f (或–file) : 查询有哪些软件包拥有指定文件这个选项非常有用。当用户不清楚某个文件属于哪个软件包时,可试试这个选项。假如我记不清/usr/sbin/ftpd这个文件在哪个包中,现在用RPM查询:


# rpm -qf /usr/sbin/ftpd


inet6-apps-0.36-3


#


现在知道了,它在inet6-apps-0.36-3包中。命令中-qf是-q -f的缩写,当选项仅带一个减号时,多个选项可以合并在一起,如-a -b -c三个选项可写作-abc,执行效果相同。


(4) –whatrequires : 查询有哪些包需要指定功能


本选项指示RPM从所有已安装的软件包中,查询有哪些软件包提供了用户指定的功能,命令行上可输入一个或多个功能。


# rpm -q –whatrequires /bin/ps libc.so.6 | head


autofs-3.1.3-2


agrep-2.04-5


aktion-0.3.6-2


amor-0.5-1


chkconfig-1.0.6-2


libtermcap-2.0.8-16


bash-2.03-10


ncurses-4.2-18


info-3.12f-4


fileutils-4.0-3


#


注: 本例从系统中查询哪些软件包需要/bin/ps和libc.so.6功能,通过管道输出前10行内容。


(5) –whatprovides : 查询有哪些包提供指定功能


本选项指示RPM从所有已安装的软件包中,查询有哪些软件包提供了用户指定的功能。命令行上可输入一个或多个功能。


# rpm -q –whatprovides libc.so.6 /bin/ps


glibc-2.1.2-12


no package provides /bin/ps


#


注: 本例从系统中查询有哪些软件包提供libc.so.6与/bin/ps功能,结果是glibc-2.1.2-12包提供了libc.so.6,而没有包提供/bin/ps功能。


(6) –triggeredby : 查询有哪些包被指定的包触发本选项指示RPM从所有已安装的软件包中,查询有哪些包可被用户指定的包触发。指定的包可输入一个或多个。


# rpm -q –triggeredby file


foo-8.0-1


#


注: 本例查询后得知,安装或卸载foo-8.0-1包,将会触发与file包相关的脚本程序执行。


2. 查询未安装的软件包: (仅有一个选项可用)


(1) -p : 查询指定包裹文件的信息


使用本选项,通过指定一个或多个包裹文件名,RPM就可以获取相应包裹的有关信息。包裹文件可以是一般形式,也可是ftp/http形式。


# rpm -qp -l –ftpport 2121 ftp://zzz:pass@linux/zhsoft/file-3.26-6.i386.rpm


/usr/bin/file


/usr/man/man1/file.1


/usr/man/man4/magic.4


/usr/share/magic


#


注: 本例查询ftp形式的包裹,显示其文件列表(-l选项使然,下面要讲到)。ftp用户名zzz,密码为pass,远程机为linux,文件名为/zhsoft/file-3.26-6.i386.rpm,ftp使用2121端口。


二、信息显示类


本类选项可同时选择多个,以显示多种信息。


1. -i : 显示软件包信息


当用户需要了解软件包的头部信息时,要使用该选项。


# rpm -qi file


Name: file Relocations: /usr


Version : 3.26 Vendor: Red Hat Software


Release : 6 Build Date: 1999年03月23日 星期二 05时32分29秒


Install date: 2001年10月14日 星期日 21时18分25秒 Build Host: porky.devel.redhat.com


Group : Applications/File Source RPM: file-3.26-6.src.rpm


Size: 211946 License: distributable


Packager: Red Hat Software


Summary : A utility for determining file types.


Description :


The file command is used to identify a particular file according to the


type of data contained by the file. File can identify many different


file types, including ELF binaries, system libraries, RPM packages, and


different graphics formats.


You should install the file package, since the file command is such a


useful utility.


#


上述输出中,包含多个域,各个域的含义为:


Name : 软件名;Relocations : 重定位目录前缀(一个或多个);


Version : 版本号;Vendor : 开发商;


Release : 释出号;Build Date : 包建立时间;


Install date : 安装时间; Build host : 包建立主机;


Group: 类别; Source RPM : 源代码包;


Size : 大小; License : 许可证;


Packager : 打包者;


Summary : 软件简介;


Description : 详细描述。


2. -l (或–list) : 显示软件包文件列表


当用户想知道软件包包含哪些文件时,要使用该选项。输出时,一行一个文件名,形成文


件列表。下例列出file包中文件:


# rpm -qlv file


-rwxr-xr-x root root23948 3月 23 1999 /usr/bin/file


-rwxr-xr-x root root12023 3月 23 1999 /usr/man/man1/file.1


-rwxr-xr-x root root 6625 3月 23 1999 /usr/man/man4/magic.4


-rwxr-xr-x root root 169350 3月 23 1999 /usr/share/magic


#




注: 本例列文件时选用了通用选项-v,这样列出的格式同ls命令列出的格式,从中可以看到各个文件的权限,属主,属组,大小,最后修改时间及文件名等信息。


3. -d (或–docfiles) : 显示软件包说明文档RPM将软件包中的文件分为三类,一是配置文件,一是说明文档,再一是其它文件(包括可执行程序及数据文件等)。通过-d选项,可列出包中所有说明文档。下例列出file包中说明文档:


# rpm -qd file


/usr/man/man1/file.1


/usr/man/man4/magic.4


#


4. -c (或–configfiles) : 显示软件包配置文件使用本选项可列出包中所有配置文件。下例列出lze包中的配置文件:


# rpm -qc lze


/etc/funkey.def


/etc/inputme.def


#


5. -s (或–state) : 显示软件包文件状态RPM已安装的软件包中各个文件可拥有如下4种状态:


* normal(正常): 这表明文件未被其它软件包修改过。


* replaced(已替换): 这表明文件已被其它软件包修改替换过了,不再是原先的文件了。* not installed(未安装): 这表明文件未安装。有一种原因可导致这种情况发生,这就是当安装软件包时使用了–excludedocs选项(或是通过设置%_excludedocs宏为1),说明文档未被安装到系统中。当用RPM查询此软件包状态时,所有说明文档均显示此状态。


* net shared(网络共享): 这表明文件处于网络共享状态。这一状态是RPM用来支持NFS(网络文件系统)的,用于避免一个NFS客户端系统删除一个正在共享的文件时,另一NFS客户端系统无法正常使用含此文件的软件包。有两种情况可使文件在此状态,一是文件安装在真实网络共享的目录里,二是文件安装在RPM资源配置文件中%_netsharedpath宏所确定的目录里。


# rpm -i –excludedocs file-3.26-6.i386.rpm


# rpm -qs file


normal/usr/bin/file


not installed /usr/man/man1/file.1


not installed /usr/man/man4/magic.4


normal/usr/share/magic


#


注: 本例先安装file包裹文件,选用–excludedocs表明不安装说明文档。而后再查询file包文件的状态,可以看到其说明文档均为not installed(未安装),其它文件为normal(正常)状态。


6. -R (或–requires) : 显示软件包所需的功能


所谓功能,可以是软件包标识,可以是文件(如共享库libc.so.6等),也可以是虚拟的名字。软件包的依赖关系,就是依靠功能来实现的。RPM安装软件包时,如果所需功能不存在,则其依赖关系不满足,RPM将中断安装过程。


# rpm -q -R lze


/bin/sh


ld-linux.so.2


libc.so.6


libc.so.6(GLIBC_2.0)


libc.so.6(GLIBC_2.1)


#


注: 本例查询lze包所需的功能。


7. –provides : 显示软件包提供的功能


一个软件包,可以提供若干功能,这些功能可以是动态链接库等实际的文件,也可以是虚拟的名字(只要其它软件包可以用就行了)。如果想查询某个包提供了哪些功能,要用–provides


选项。


下面的例子查询一个包裹文件所提供的功能:


# rpm -qp –provides zlib-1.1.3-6.i386.rpm


libz.so.1


libz.so.1(GCC.INTERNAL)


#


注: 本包裹文件提供的功能是libz.so.1动态链接库。


8. –conflicts : 显示软件包冲突的功能


何谓冲突?冲突就是不同软件包之间不能共存的现象。RPM制作软件包时,可以记录下与本软件包不能共存的功能,这样安装该包时,若冲突的功能已然存在,则RPM将中止安装。


下面的例子查询at-3.1.7-8包是否有与其冲突的功能:


# rpm -q –conflicts at-3.1.7-8


crontabs <= 1.5


#


注: 本例显示at包与版本号小于1.5的crontabs包有冲突存在。


9. –scripts : 显示软件包内置的脚本程序


scripts即脚本,指的是用SHELL语言编写的程序。选用本选项时,RPM将输出软件包所含的各类脚本程序的内容。总共有5类这样的脚本程序,即安装前脚本程序(preinstall),安装后脚本程序(postinstall),卸载前脚本程序(preuninstall),卸载后脚本程序(postuninstall)和校验脚本程序(verify)。


下面的例子列出zsh包的脚本程序:


# rpm -q –scripts zsh-3.0.7-4 | nl


1 postinstall script (through /bin/sh):


2 if [ ! -f /etc/shells ] ; then


3 echo “/bin/zsh” > /etc/shells


4 else


5 echo “/bin/zsh” >> /etc/shells


6 fi


7 /sbin/install-info /usr/info/zsh.info.gz /usr/info/dir


8 –entry=”* zsh: (zsh). An enhanced bourne shell.”


9 preuninstall script (through /bin/sh):


10 if [ "$1" = 0 ] ; then


11 /sbin/install-info –delete /usr/info/zsh.info.gz /usr/info/dir


12 –entry=”* zsh: (zsh). An enhanced bourne shell.”


13 fi


14 postuninstall script (through /bin/sh):


15 if [ "$1" = 0 ] ; then


16 if [ -f /etc/shells ] ; then


17 TmpFile=`/bin/mktemp /tmp/.zshrpmXXXXXX`


18 grep -v ‘^/bin/zsh$’ /etc/shells > $TmpFile


19 cp -f $TmpFile /etc/shells


20 rm -f $TmpFile


21 chmod 644 /etc/shells


22 fi


23 fi


#


注: 本例利用管道技术给查询的每行输出加上了行号,便于观察解释。


第2-8行: 为安装后脚本程序(postinstall)的源代码;


第10-13行: 为卸载前脚本程序(preuninstall)的源代码;


第15-23行: 为卸载后脚本程序(postuninstall)的源代码。


例中所有脚本程序均通过/bin/sh解释执行,本例没有安装前脚本程序(preinstall)和


校验脚本程序(verify)。


10. –triggers : 显示软件包内置的触发脚本程序


触发脚本程序是scripts类脚本程序的扩展,它用于软件包之间的交互控制。触发脚本


程序有安装时触发脚本程序(triggerin),卸载前触发脚本程序(triggerun)和卸载后触发脚


本程序(triggerpostun)三种。


下面的例子列出zsh包中的触发脚本程序:


# rpm -q –triggers zsh-3.0.7-4


triggerpostun script (through /bin/sh) — zsh <= 3.0.7-2


if [ ! -f /etc/shells ] ; then


echo “/bin/zsh” > /etc/shells


else


echo “/bin/zsh” >> /etc/shells


fi


#


注: 输出的第1行说明脚本程序的类别(为卸载后触发脚本程序triggerpostun),用什么程序解释(一般为/bin/sh),和触发的条件(在–之后描述)。本例的触发条件为zsh的版本小于或等于3.0.7-2。如果条件成立,则此脚本程序将会执行。 输出的第2-6行为卸载后触发脚本程序的源代码。


11. –changelog : 显示软件维护记录


changelog即软件维护记录,用它来记录什么人,什么时间,改动了软件的什么地方。通


过查看维护记录,开发者或用户可以了解软件的开发进展情况。


下面的例子查询lze包的维护情况:


# rpm -q –changelog lze-6.0-2


* 五 5月 01 1998 雨亦奇


- 增加多窗口操作


* 一 3月 24 1997 雨亦奇


- 增加块操作命令


#


注: 从本例中就可以看出来,维护记录的书写有一定的规范:以星号(*)开头的行记录维护时间,维护人及其电子邮箱,而以减号(-)开头的行则记录维护的具体内容。


12. –dump : 显示软件包中所有文件的属性信息


如果用户想查看某个软件包内文件的属性信息,请用–dump选项。


# rpm -q –dump file


/usr/bin/file 23948 922138347 abaf6cfd51588ac7c484526fbdb84e5b 0100755 root root 0 0 0 X


/usr/man/man1/file.1 12023 922138346 76d9ff6567ab64a53eab50911272f5c1 0100755 root root 0 1 0 X


/usr/man/man4/magic.4 6625 922138346 b8d126803709f0da7f39f5125a132cd3 0100755root root 0 1 0 X


/usr/share/magic 169350 922138346 3bd2eaf3c5e0e84153ba7df38b7561fc 0100755 root root 0 0 0 X


#


现在根据例子的输出,解释一下RPM包中各个文件所拥有的属性信息:(以第1行为例)


/usr/bin/file : 为文件名;


23948 : 指文件大小(字节数);


922138347 : 指文件最后修改时间(秒数);


abaf6cfd51588ac7c484526fbdb84e5b : 指根据文件内容计算出的MD5检查和;


0100755 : 指文件存取权限;


root : 指文件属主;


root : 指文件属组;


0 : 配置文件标志,为0表示该文件非配置文件,为1表明该文件是配置文件;


0 : 说明文档标志,为0表示该文件非说明文档,为1表明该文件是说明文档;


0 : 指文件类型,为0表示普通文件,非0表示设备文件,包含主从设备号;


X : 符号连接内容,如果文件不是符号连接,则此值为X。


三、定制输出类


定制输出是RPM一项强有力的功能,当用户想要RPM按自己的格式输出软件包信息时,可以通过使用–qf(或–queryformat)选项来实现定制。


定制输出要指定格式化的字符串(类似printf的格式串),该字符串以单引号’或双引号”引祝格式串中可包括普通文本,含转义符的文本,功能标签和数组循环三种不同的组件。


* 普通文本


格式串中的普通文本将按原样输出。


* 含转义符的文本


RPM定义的转义符为,称作反斜杠。当RPM遇到此字符时,会根据预先定义的转义序列,把后面的字符解释后输出。


转义序列如下:


: 输出响铃字符(值为7),效果是喇叭鸣叫一声。


: 输出退格符(值为8),效果是删除光标前面一个字符,且光标后退一个字符位置。


: 输出换页符(值为12),根据终端解释的不同,效果也不相同,有的是实现清屏操作,有的则是换一行。


: 输出换行符(值为10),效果是光标移到下一行。


: 输出回车符(值为13),效果是光标回到行首。


: 输出跳格(值为9),根据终端解释的不同,效果也不同,有的是输出一个空格,有的 则输出最多8个空格。


: 输出垂直方向的跳格(值为11),用处不大。


\ : 输出反斜杠()这个字符。




* 功能标签


RPM内置了很多功能标签,如NAME表示软件名,VERSION表示版本号,RELEASE表示释出号等。输出功能标签所表示的内容时,需用这样一种格式:


%[输出宽度]{功能标签}


注:输出宽度可选,正值表示右对齐输出,负值表示左对齐输出。


如格式串中使用%{NAME}时将输出软件名,使用%20{NAME}时则右对齐输出软件名,宽度为20,而使用%-20{NAME}时则按宽度为20左对齐输出软件名。看看下面的实际例子就会明白:


# rpm -q –qf “%{NAME}:%20{NAME}:%-20{NAME}:” file


file:file:file:


#


功能标签书写不区分大小写,即NAME也可输作name,Name等等。功能标签还可以带有选项,选项用”:选项名”表示,选项名有大小写之分。如%{FILEMODES}默认以数字形式输出,如采用perms选项,即%{FILEMODES:perms},输出结果将采用rwx的形式。请看下面的例子:


# rpm -q –qf “%{filenames} %{FILEMODES:perms}” file


/usr/bin/file -rwxr-xr-x-


#


注: %{filenames}表示包中的文件名。


RPM常用功能标签表


注: 可用rpm –querytags命令查到RPM内置的所有功能标签。


* 数组循环


对于功能标签是数组的,可以用数组循环(用[与]括住的部分)来输出数组的全部内容。数组循环内部可包含功能标签,普通文本和含转义符的文本。RPM将根据循环内部一个或多个数组类型的功能标签所拥有的单元个数,取其最小值,循环同样次数,输出解释或转义后的数据。对于功能标签仅含一个单元的,若想输出多次,则需要在功能标签前面加个等号(=)。


下面的例子以数组循环的方式,输出file包所含的各个文件的文件名及权限,同时输出每一个文件时都要先输出软件包标识。


# rpm -q –qf “[%{=NAME}-%{=VERSION}-%{=RELEASE} : %-20{FILENAMES} : %{FILEMODES:perms}]” file


file-3.26-6 : /usr/bin/file : -rwxr-xr-x-


file-3.26-6 : /usr/man/man1/file.1 : -rwxr-xr-x-


file-3.26-6 : /usr/man/man4/magic.4 : -rwxr-xr-x-


file-3.26-6 : /usr/share/magic : -rwxr-xr-x-


#




通过使用定制输出,我们可以很方便地查找出系统中占用空间最大的软件包。


# rpm -q -a –qf “%{NAME} %{SIZE}” | sort -nr +1 | head -1


kernel-source 65824967


#




注: -a项选择所有已安装的软件包,–qf项定制查询格式, 格式串中用功能标签NAME输出软件名,用SIZE输出软件大小,查询得到的数据通过管道送sort命令,对第2列降序排序后由head命令取第1行内容,这即是占用空间最大的软件包。



RPM完全安装

下载速度太慢了,来这里看看吧。



本文摘自:www.linuxsir.com


从一般意义上说,软件包的安装其实是文件的拷贝,RPM安装软件包,也无外乎此。但RPM要更进一步、更聪明一些就需要多做些工作了。


聪明的安装


从一般意义上说,软件包的安装其实是文件的拷贝,即把软件所用的各个文件拷贝到特定目录。RPM安装软件包,无外乎此。但RPM要更进一步,更聪明一些。在安装前,它通常要执行以下操作:


1.检查软件包的依赖(Dependency)


RPM格式的软件包中可包含有依赖关系的描述,如软件执行时需要什么动态链接库,需要什么程序存在及版本号要求等。当RPM检查时发现所依赖的链接库或程序等不存在或不符合要求时,默认的做法是中止软件包安装。


2.检查软件包的冲突(Conflicts)


有的软件与某些软件不能共存,软件包制作者会将这种冲突记录到RPM软件包中。安装时,若RPM发现有冲突存在,将会中止安装。


3.执行安装前脚本程序(Preinstall)


此类程序由软件包制作者设定,需要在安装前执行。通常是检测操作环境,建立有关目录,清理多余文件等等,为顺利安装作准备。


4.处理配置文件(Configfiles)


RPM对配置文件(Configfiles)有着特别的处理。因为用户常常需要根据实际情况,对软件的配置文件做相应的修改。如果安装时简单地覆盖了此类文件,则用户又得重新手工设置,很麻烦。这种情况下,RPM做得比较明智:它将原配置文件换个名字保存了起来(原文件名后缀加上.rpmorig),用户可根据需要再恢复,避免重新设置的尴尬。


5.解压软件包并存放到相应位置


这是最重要的部分,也是软件包安装的关键所在。在这一步,RPM将软件包解压缩,将其中的文件一个个存放到正确的位置,同时,文件的操作权限等属性相应设置正确。


6.执行安装后脚本程序(Postinstall)


此类程序为软件的正确执行设定相关资源,如修改inetd.conf、运行ldconfig程序以利新的动态链接库生效等等。


7.更新RPM数据库


安装后,RPM将所安装的软件及相关信息记录到其数据库中,便于以后升级、查询、校验和卸载。


8.执行安装时触发脚本程序(Triggerin)


触发脚本程序是指软件包满足某种条件(如已安装软件包sendmail,或file版本大于3.0)时才触发执行的脚本程序,它用于软件包之间的交互控制。触发脚本程序有三类:一是软件包安装时才触发的,称为安装时触发脚本程序(triggerin);二是软件包卸载前触发的,叫作卸载前触发脚本程序(triggerun);三是软件包卸载后才触发执行的,称作卸载后触发脚本程序(triggerpostun)。这些触发脚本程序,大大扩展了RPM软件包管理的功能。


命令格式


安装RPM格式的软件包,可使用如下命令格式: rpm -i [安装选项1 安装选项2...] 包裹文件1 包裹文件2…


注:可用–install代替-i,效果相同。


选项列表


包裹文件


对于要安装的RPM格式的包裹文件,RPM对其名字不作强制要求。用户可以使用以下三种方式的命名样式:


1.典型的命名样式(常用): 格式为:软件名-版本号-释出号.体系号.rpm


注:体系号指的是执行程序适用的处理器体系,如i386体系,sparc体系等。体系号为src时表明为源代码包,否则为执行程序包。


如abc-3.2-1.i386.rpm为执行程序包,软件名为abc,版本号为3.2,释出号为1,适用体系为i386,而abc-3.2-1.src.rpm则为源代码包。


2.URL形式的命名样式(较常用)


* FTP方式的命名格式:ftp://[用户名[:密码]@]主机[:端口]/包裹文件


注:[]括住的内容表示可眩主机可以是主机名,也可是IP地址。包裹文件可含目录信息。如未指定用户名,则RPM采用匿名方式传输数据(用户名为anonymous)。如未指定密码,则RPM会根据实际情况提示用户输入密码。如未指定端口,则RPM使用默认端口(一般为21)。


如ftp://ftp.xxx.com/yyy.rpm(使用匿名传输,主机ftp.xxx.com,包裹文件yyy.rpm);


如ftp://24.109.164.55:1024/pub/yyy.rpm(匿名FTP传输,主机IP:24.109.164.55,使用1024端口,包裹文件在/pub目录下);


如ftp://zhsoft@ftp.xxx.com/yyy.rpm(主机ftp.xxx.com,FTP用户名zhsoft,如有密码,RPM将会自动提示输入);


如ftp://zhsoft:password@ftp.xxx.com/yyy.rpm(主机ftp.xxx.com,FTP用户名zhsoft,密码password)。


3 HTTP方式的命名:格式为:http://主机[:端口]/包裹文件


注:[]括住的内容可眩主机可以是主机名,也可是IP地址。包裹文件可含目录信息。如未指定端口,则RPM默认使用80端口。


如http://www.xxx.com/yyy.rpm(用HTTP获取www.xxx.com主机上的yyy.rpm文件);


如http://www.xxx.com:8080/pub/yyy.rpm(用HTTP获取www.xxx.com主机上/pub目录下的yyy.rpm文件,使用端口8080)。


3.其它形式(很少使用):


命名格式:任意


如将abc-3.2-1.i386.rpm改名为abc.txt,用RPM安装也会安装成功,其根本原因是RPM判定一个文件是否RPM格式,不是看名字,而是看内容,看其是否符合特定的格式。


参数:


一、安装指定用选项


1.hash(或-h):以#显示安装进度,如果一个软件包很大、安装费时时,用户若想及时了解安装进度,必须用此选项。该选项以显示#号表示进度,每个#号表示2%的进度,总共要显示50个#号。下面安装MySQL软件包,如下所示:


# rpm -i –hash MySQL-3.22.32-1.i386.rpm


##################################################


#


从上看出,软件包安装顺利完成。


2.percent:以%(百分比)显示安装进度


percent的含义是百分比,而此选项的作用就是以百分比(%)来显示安装进度的。同样是安装MySQL软件包,下面的输出就不一样:


# rpm -i –percent MySQL-3.22.32-1.i386.rpm


%% 0.000000


%% 0.002600


%% 0.020586


……


%% 100.000000


#


上例中省略了很多输出(……表示)。因为如果软件包很大,则用–percent时输出的内容会很多,所以用户最好用–hash选项,以#号来表示安装进度,这样简洁明了。


3.test:安装测试


所谓安装测试,意即并非真正的安装,它不拷贝和建立任何文件。使用本选项的目的在于:检测软件包的依赖关系是否满足,是否存在潜在的冲突等等。


# rpm -i –test autofs-3.1.3-2.i386.rpm


error: failed dependencies:


mktemp is needed by autofs-3.1.3-2


#


本例进行安装测试时发现了依赖方面的错误,autofs所需要的mktemp包不存在,安装中断。


下面先安装mktemp软件包,再进行autofs安装测试,看情况怎么样:


# rpm -i mktemp-1.5-2.i386.rpm


# rpm -i –test autofs-3.1.3-2.i386.rpm


#


由上看出,这次测试没有出现什么错误。


4.replacepkgs:替换软件包


为什么要替换软件包?原因可能是系统中的软件包已经破坏了,其中一个或多个文件丢失或损毁。如果用户想修复这个软件包,用直接安装的方法,RPM将报错退出:


# rpm -V file


missing/usr/man/man1/file.1


# rpm -i file-3.26-6.i386.rpm


package file-3.26-6 is already installed


#


注:本例先用RPM校验命令校验一下file软件包,发现/usr/man/man1/file.1文件丢失。之后用安装命令安装,RPM提示软件包file-3.26-6已经安装了。(有关RPM校验命令,<<精通RPM之六–校验篇>>中将会有详细的介绍)


如果采用–replacepkgs选项,结果又怎样呢?


# rpm -i –replacepkgs file-3.26-6.i386.rpm


# rpm -V file


#


看来,RPM成功地替换了原软件包,校验一下该包,发现没有错误输出,所以现在的软件包是完整的。


5.replacefiles:替换文件


RPM是聪明的软件包管理器,它维护着每个已安装软件包的文件信息。如果在安装一个新的软件包时,RPM发现其中某个文件和已安装的某个软件包中的文件名字相同但内容不同,那么RPM就会认为这是一个文件冲突,会报错退出:


# rpm -i ff-4.0-2.i386.rpm


file /root/my.a from install of ff-4.0-2 conflicts with file from package zoo-6.0-1


#


注:本例中RPM发现要安装的软件包ff-4.0-2与已安装的软件包zoo-6.0-1中,含有相同的一个文件/root/my.a,但其内容并不相同,所以提示了文件冲突的错误。


如果用户想忽略这个错误,可使用–replacefiles选项,指示RPM发现文件冲突时,直接替换掉原文件即可。注意:除非用户对所冲突的文件有很深的了解,不要轻易替换文件,以免破坏已安装软件包的完整性,确保其能正常运行。


# rpm -i –replacefiles ff-4.0-2.i386.rpm


#


采用该选项后,软件包能顺利安装了。


另外,说到替换文件,若要安装的软件包中的文件已存在,但此文件并不属于任何软件包,RPM的做法是将文件换名保存(文件名后缀加.rpmorig),并且以警告信息提醒用户。如下所示:


# rpm -i foo-6.0-1.i386.rpm


warning: /etc/foo.conf saved as /etc/foo.conf.rpmorig


#


6.allfiles:安装所有文件


读者看到此选项,也许要问:难道RPM安装软件包不是安装其中所有的文件吗? 我的回答是:如果是初次安装的话,RPM确是将包中所有文件全部安装。但是,如果是修复软件包(用–replacepkgs选项),那结果就不一定了。个中原因是:RPM包中有些配置文件可标识为missingok属性(missingok指的是即使丢失,照样OK),这样的包安装后,若这种类型的配置文件被删除,则修复时RPM默认的做法是不再安装这种类型的文件,除非采用–allfiles选项。下面看个实际的例子:


# rpm -i foo-6.0-1.i386.rpm


# ls -l /etc/foo.conf


-rw-r–r– 1 root root9 Oct 11 09:50 /etc/foo.conf


# rm -f /etc/foo.conf


# rpm -i –replacepkgs foo-6.0-1.i386.rpm


# ls -l /etc/foo.conf


ls: /etc/foo.conf: 文件或目录不存在


# rpm -i –replacepkgs –allfiles foo-6.0-1.i386.rpm


# ls -l /etc/foo.conf


-rw-r–r– 1 root root9 Oct 11 09:50 /etc/foo.conf


注:本例中已预先知道foo包中的配置文件/etc/foo.conf带有missingok属性。


(1)用rpm -i命令安装foo包;


(2)用ls命令列一下属于该包的配置文件/etc/foo.conf(能列出来,表明文件存在);


(3)用rm命令删除了这个文件;


(4)用rpm -i –replacepkgs命令修复foo软件包;


(5)因为修复时未用–allfiles选项,所以用ls命令列文件/etc/foo.conf时出错了:文件不存在,没有安装上;


(6)用rpm -i –replacepkgs –allfiles命令安装修复foo软件包;


(7)再度用ls命令列文件,列了出来,表明这次安装上了。


由本例看出,若用户确实想安全恢复(修复)某个软件包,最好使用–allfiles选项。一般情况下则不必这么做,因为带有missingok属性的配置文件本来就是可以丢失的嘛,不必太在意了。


7.force:强制执行


force的含义是强制。–force选项的作用就是强制安装软件包,不考虑软件包是否已安装,也不考虑有没有文件冲突。其效果相当于同时选用–replacepkgs与–replacefiles选项进行安装。


8.excludedocs:不安装说明文档


RPM有多个好功能,其中之一就是:它将文件分为配置文件,说明文档和其它文件三种,这样便于区别对待,灵活处理。


基于RPM安装的LINUX发行版中包括5000多个说明文档,有50M字节,占用的空间不校如果想节省空间,可使用–excludedocs选项以排除安装说明文档。


如软件包file中包含/usr/man/man1/file.1和/usr/man/man4/magic.4两个说明文档。安装时若使用–excludedocs选项,这两个文档就不会被安装。


# rpm -i –excludedocs file-3.26-6.i386.rpm


# ls -l /usr/man/man1/file.1


ls: /usr/man/man1/file.1: 文件或目录不存在


# ls -l /usr/man/man4/magic.4


ls: /usr/man/man4/magic.4: 文件或目录不存在


#


如果用户想让RPM默认不安装说明文档,则可以这么做:编辑~/.rpmmacros文件(用户主目录HOME下的RPM宏文件),加入下面一行:


%_excludedocs 1


其作用是定义RPM内部的_excludedocs宏为1,确认不安装说明文档。


这样的话,就不用在命令行使用–excludedocs选项了。


# rpm -i file-3.26-6.i386.rpm


# ls -l /usr/man/man1/file.1


ls: /usr/man/man1/file.1: 文件或目录不存在


# ls -l /usr/man/man4/magic.4


ls: /usr/man/man4/magic.4: 文件或目录不存在


#


9.includedocs:安装说明文档


RPM一般情况下是安装说明文档的,但是如果用户自行修改了设定(象上面的例子),则RPM就不再安装说明文档了,除非特别指定,这就用到–includedocs选项。这种情况下,只有用此选项才能确保安装说明文档。


# rpm -i –includedocs file-3.26-6.i386.rpm


# ls -l /usr/man/man1/file.1


-rwxr-xr-x 1 root root12023 Mar 23 1999 /usr/man/man1/file.1


# ls -l /usr/man/man4/magic.4


-rwxr-xr-x 1 root root 6625 Mar 23 1999 /usr/man/man4/magic.4


#


10.noscripts:不执行脚本程序


一个RPM软件包中可包含五种脚本程序,即:安装前脚本程序,安装后脚本程序,卸载前脚本程序,卸载后脚本程序和校验脚本程序。安装时使用–noscripts选项,可禁止安装前与安装后脚本程序的执行。


# rpm -i foo-6.0-1.i386.rpm


preinstall is running … done


postinstall is running … done


#


上面不禁止脚本程序的执行,下面不执行脚本程序,请看输出结果:


# rpm -i –noscripts foo-6.0-1.i386.rpm


#


看,因为没有安装前与安装后脚本程序的执行,所以没有什么输出了。


注意:一般用户不要使用此选项。此选项主要提供给软件包制作者使用的。通过禁止执行脚本程序,可以防止因安装带有BUG的软件包而宕掉整个系统。当软件包去掉了BUG后,此选项就不必使用了。


11.nodeps:不检查依赖


RPM管理软件包,不仅管理包中的所有文件,还同时管理着软件包之间的依赖关系。如A依赖于B运行,若B不存在了,则A也就运行不了了。RPM维护着这种关系,尽量避免破坏,以保证软件的正常运行。


# rpm -i autofs-3.1.3-2.i386.rpm


error: failed dependencies:


mktemp is needed by autofs-3.1.3-2


#


本例安装中出现了依赖方面的错误(autofs依赖mktemp,但mktemp不存在),安装过程中断了。如果要RPM不管依赖关系是否正常都安装,就要用–nodeps选项,指示RPM不检查依赖,这样就能正常安装了。


# rpm -i –nodeps autofs-3.1.3-2.i386.rpm


#


注:除非用户对软件包有足够了解,或只想看看软件,否则不要使用本选项,以维护软件间正常的依赖关系。


12.notriggers:不执行触发程序


为了软件包间的交互控制,RPM设计了三种触发程序:安装时触发程序,卸载前触发程序和卸载后触发程序。为了防止因某一软件包的安装而引发安装时触发程序的执行,可以使用–notriggers选项。


13.ignorearch:忽略体系与ignoreos :忽略操作系统


何谓体系?体系就是CPU的类别,有Intel的x86(如i386,i486系列)体系,有Sun的sparc体系等等。当一个软件包建立时,RPM就为其指定了所适用的CPU体系,也为其指定了所适用的操作系统。这样做的好处就是,RPM容易知道为一台计算机所建立的软件包是否适用于兼容于另一台计算机。RPM的资源配置文件(默认为/usr/lib/rpm/rpmrc)中,就定义了体系的兼容关系(arch_compat表达)和操作系统的兼容关系(os_compat表达)。RPM安装一个包裹文件时,要做这样一个兼容方面的检查。如果用户想忽略体系,不管其是否兼容,请用–ignorearch选项安装。如果也不管操作系统是否兼容,可用–ignoreos选项。需要指出的是,若非知道自己这样的目的,否则不要试图这样做。


14.ignoresize:不检查空间大小


RPM安装软件包前,首先要检查当前系统是否有足够的剩余空间,如果空间不足的话,安装将无法完成。使用本选项的目的,在于指示RPM不做空间大小方面的检查,意即不管系统是否有容纳要安装的软件包的空间,照直安装就行了。


15.relocate:重定位


RPM软件包在制作过程中,可以定义一个或多个重定位前缀,以此方便软件的重定位(即把软件包中的文件放到自定义的目录下面),从而增加软件包安装的灵活性。


本选项用于更换指定的重定位目录,如果一个包有多个重定位前缀,可以使用本选项多次。


# rpm -qpl file-3.26-6.i386.rpm


/usr/bin/file


/usr/man/man1/file.1


/usr/man/man4/magic.4


/usr/share/magic


# rpm -i –relocate /usr=/tmp file-3.26-6.i386.rpm


# rpm -ql file


/tmp/bin/file


/tmp/man/man1/file.1


/tmp/man/man4/magic.4


/tmp/share/magic


#


注:本例中先用rpm -qpl列出包裹文件file-3.26-6.i386.rpm当中的文件,可以看到其中的文件均是以/usr开头的。之后进行重定位安装,将/usr换作/tmp。最后从列出已安装的file包的文件列表可以看出,原来的/usr目录前缀换作指定的前缀/tmp了,这样实现了软件的重定位。(关于RPM查询命令,详见<<精通RPM之五–查询篇>>)


16.badreloc:强制重定位


RPM软件包的重定位,依赖于制作时重定位前缀的定义。如果没有定义重定位前缀,或者用户安装时所指定的重定位前缀不存在,则RPM会报错退出,中断安装。此时,若用本选项,则RPM会不管这些错误,进行强制的重定位安装。注:本选项和–relocate选项同时使用时才有意义。


如上例,采用并不存在的重定位前缀/usr/man进行安装:


# rpm -i –relocate /usr/man=/tmp file-3.26-6.i386.rpm


path /usr/man is not relocateable for package file-3.26-6


#


RPM提示了错误:/usr/man目录在file-3.26-6包中是不可重定位的。


如加上–badreloc选项,结果怎么样:


# rpm -i –relocate /usr/man=/tmp –badreloc file-3.26-6.i386.rpm


# rpm -ql file


/usr/bin/file


/tmp/man1/file.1


/tmp/man4/magic.4


/usr/share/magic


#


由上可以看到,这样的强制重定位获得通过,之后再用查询命令rpm -ql列一下file包的文件,就会发现原来的/usr/man/man1/file.1定位成了/tmp/man1/file.1,而/usr/man/man4/magic.4则成了/tmp/man4/magic.4。怎么样?神奇吧!


17.excludepath:不安装指定目录下的文件


利用此选项,可以禁止RPM安装某些指定目录下的文件。如不想安装file软件包中的说明文档,除了可使用–excludedocs选项外,还可使用本选项。因为file的说明文档均在目录/usr/man下面。


# rpm -i –excludepath /usr/man file-3.26-6.i386.rpm


# rpm -qls file


normal/usr/bin/file


not installed /usr/man/man1/file.1


not installed /usr/man/man4/magic.4


normal/usr/share/magic


#


注:例子中先安装file软件包,并用–excludepath禁止安装/usr/man下的文件,再用RPM查询命令rpm -qls列出file包的文件及状态,可以看到:/usr/man下的两个文件均未安装(not installed)。


18.justdb:仅更新数据库


安装软件包使用此选项后,RPM将只更新其数据库数据,文件系统不更新,意即并不拷贝和建立包中的文件。


# rpm -i –justdb file-3.26-6.i386.rpm


# rpm -qls file


normal/usr/bin/file


normal/usr/man/man1/file.1


normal/usr/man/man4/magic.4


normal/usr/share/magic


# ls -l /usr/bin/file


ls: /usr/bin/file: 文件或目录不存在


#


注:例子中安装file包但指明只更新数据库,结果是:虽然用查询命令查到该软件包中所有文件状态均正常(normal),但用ls命令列包中所含文件/usr/bin/file,该文件却不存在。这表明包中文件并未建立。


19.prefix:指定重定位前缀


如前所述,可重定位的软件包可含一个或多个重定位前缀,可用–relocate选项来改变某个重定位前缀之值。–prefix选项仅能用来改变默认的重定位前缀(默认是第一个重定位前缀),它不需要说明原重定位前缀。下面的例子同样将file包安装到/tmp目录:


# rpm -qpl file-3.26-6.i386.rpm


/usr/bin/file


/usr/man/man1/file.1


/usr/man/man4/magic.4


/usr/share/magic


# rpm -i –prefix /tmp file-3.26-6.i386.rpm


# rpm -ql file


/tmp/bin/file


/tmp/man/man1/file.1


/tmp/man/man4/magic.4


/tmp/share/magic


#


20.ftpproxy:指定FTP代理主机


本选项指定FTP代理主机,主机可以是主机名,也可以是IP地址。


21.ftpport:指定FTP端口


本选项指定FTP协议使用的TCP端口,系统默认是21。


请看下面的例子:


# rpm -iv –ftpport 8888 ftp://root@xwboc/tmp/file-3.26-6.i386.rpm


Password for root@xwboc:


Password for root@xwboc:


Retrieving ftp://root@xwboc/tmp/file-3.26-6.i386.rpm


file-3.26-6


#


本例中用FTP方式安装file软件包,数据传输使用8888端口。执行中,RPM先提示输入root用户的密码两次,之后下载(retrieve)软件,最后成功安装。


22.httpproxy:指定HTTP代理主机


本选项指定HTTP代理主机,主机可以是主机名,也可以是IP地址。


23.httpport:指定HTTP端口


本选项指定HTTP协议使用的TCP端口,系统默认是80。下面的例子就指定了80端口来安装autofs软件,当然不指定也行,因为系统默认的就是这个端口。


# rpm -iv –httpport 80 http://24.109.164.55/rpms/autofs-3.1.3-2.i386.rpm


Retrieving http://24.109.164.55/rpms/autofs-3.1.3-2.i386.rpm


autofs-3.1.3-2


#


注:同FTP方式一样,RPM都是下载再安装。


二、通用选项


所谓通用选项,就是不管是安装,升级,卸载还是其它软件包操作,统统适用的选项。 这样的选项主要以下几个:


1.-v:显示附加信息


一般情况下,RPM和不少LINUX命令(如cp,rm,mv等)一样,都本着尽可能少输出信息的原则(除非必要,否则不要输出),这样做是为了避免浪费CPU资源。所以,当用户使用某个命令后没有什么输出,这就意味着命令执行成功了。如果有什么错误,程序会提示的。RPM也是这个样子。为了使RPM输出多一点的信息,可以使用-v选项。


如不带此选项安装file包,没有输出:


# rpm -i file-3.26-6.i386.rpm


#


而采用-v选项后安装时输出了包名:


# rpm -i -v file-3.26-6.i386.rpm


file-3.26-6


#


2.-vv:显示调试信息


选用-vv选项,可以使RPM输出更多的信息。这些信息,主要供RPM软件开发者研究使用的,一般用户也可以看看,从中可以知道RPM究竟干些什么。


下面采用此选项安装file包,同时使用管道线(|)将输出数据送nl命令,以带行号输出每行数据。




从执行结果看,输出的信息很多,其中以D:开头的行均是调试信息。现在逐行解释:


第1行:统计要安装的软件包个数;


第2行:RPM找到1个包;


第3行:查看哪些包需要下载(这些要下载的包,都是以FTP或HTTP形式书写的包名);


第4行:下载了0个包;


第5-10行:取包裹文件的文件头信息,算出软件包占用的空间68019(字节),以利检查


系统是否有足够空间。


第11行:打开RPM数据库;


第12行:找到0个源代码包,1个执行代码包;


第13-18行:检查软件包的依赖关系。其依赖(requires)的东西均得到满足(satisfied)。


第19行:准备安装执行代码包;


第20行:取得已安装文件系统的列表;


第21-26行:再度取包裹文件头信息,算出软件包占用空间;


第27-31行:列出包中文件及要执行的操作,第27行的test=0表示不是进行安装测试,


file包中的文件均要执行创建操作(create)。


第32行:如果有安装前执行脚本程序的话,执行它;


第33行:安装软件包file-3.26-6;


第34行:如果有安装后执行脚本程序的话,执行它。


3.root:指定根目录


指定根目录ROOT,其作用在于将系统所有操作限定在指定的目录下面,这样RPM操作的数据库位置变了,软件包的安装位置也变了。它是通过chroot系统调用实现的。RPM默认的数据库目录是/var/lib/rpm,如果指定根目录为/usr,则RPM的数据库目录将变为/usr/var/lib/rpm。同样,如果包中有个文件为/etc/zhsoft.txt,则安装后为/usr/etc/zhsoft.txt。


看下面的例子:


# rpm -i –root /usr file-3.26-6.i386.rpm


failed to open /usr/var/lib/rpm/packages.rpm


error: 不能打开 /usr/var/lib/rpm/packages.rpm


#


注:指定RPM根目录为/usr安装file出现错误,RPM打不开/usr/var/lib/rpm/packages.rpm文件,这是因为实际上在/usr/var/lib/rpm目录下没有任何RPM数据库。如果想成功安装,可用初始化RPM数据库命令来建立RPM数据库,命令是rpm –initdb –root /usr(这些功能将在以后讲到)。


4.rcfile:指定RPM资源配置文件


RPM的资源配置文件里,存放着RPM的默认设置,有编译选项optflags,体系定义arch_canon,兼容定义arch_compat,宏文件定义macrofiles等。RPM默认的资源配置文件(按读取顺序)为:/usr/lib/rpm/rpmrc,/etc/rpmrc,~/.rpmrc。(后两个文件现在意义不大了,如今一般换作RPM宏文件了。较之资源配置文件,宏文件有更大的灵活性。)


如果想让RPM使用用户指定的资源配置文件,就用–rcfile来设定,可同时设定多个文件,文件间以冒号(:)分隔,如/usr/lib/rpm/rpmrc:/etc/rpmrc:~/.rpmrc这种形式。


5.dbpath:指定RPM数据库目录


本选项不同于–root选项,它仅仅是指定RPM数据库的目录,并不改变安装文件的位置。



linux下软件的基本安装和卸载

linux软件的安装和卸载一直是困扰许多新用户的难题。在Windows中,我们可以使用软件

自带的安装卸载程序或在控制面板中的“添加/删除程序”来实现。与其相类似,在linux下有一

个功能强大的软件安装卸载工具,名为RPM。它可以用来建立、安装、查询、更新、卸载软件。

该工具是在命令行下使用的。在Shell的提示符后输入rpm,就可获得该命令的帮助信息。

软件的安装

linux下软件的安装主要有两种不同的形式。第一种安装文件名为xxx.tar.gz; 另一种安

装文件名为xxx.i386.rpm。以第一种方式发行的软件多为以源码形式发送的;第二种方式则是

直接以二进制形式发送的。

对于第一种,安装方法如下:

1. 首先,将安装文件拷贝至你的目录中。例如,如果你是以root身份登录上的,就将软

件拷贝至/root中。

#cp xxx.tar.gz /root

2. 由于该文件是被压缩并打包的,应对其解压缩。命令为:

#tar xvzf filename.tar.gz

3. 执行该命令后,安装文件按路径,解压缩在当前目录下。用ls命令可以看到解压缩后

的文件。通常在解压缩后产生的文件中,有“Install”的文件。该文件为纯文本文件, 详细讲

述了该软件包的安装方法。

4. 执行解压缩后产生的一个名为configure的可执行脚本程序。 它是用于检查系统是否

有编译时所需的库,以及库的版本是否满足编译的需要等安装所需要的系统信息。为随后的编

译工作做准备。命令为: #./configure

5. 检查通过后,将生成用于编译的MakeFile文件。此时,可以开始进行编译了。编译的

过程视软件的规模和计算机性能的不同,所耗费的时间也不同。命令为: #make。

6. 成功编译后,键入如下的命令开始安装:

#make install

7. 安装完毕,应清除编译过程中产生的临时文件和配置过程中产生的文件。键入如下命

令:

#make clean

#make distclean

至此,软件的安装结束。

对于第二种,其安装方法要简单得多。

同第一种方式一样,将安装文件拷贝至你的目录中。然后使用rpm来安装该文件。 命

令如下:

#rpm -i filename.i386.rpm

rpm将自动将安装文件解包,并将软件安装到缺省的目录下。 并将软件的安装信息注

册到rpm的数据库中。参数i的作用是使rpm进入安装模式。


软件的卸载

1.软件的卸载主要是使用rpm来进行的。卸载软件首先要知道软件包在系统中注册的名称。键入命令:

#rpm -q -a

即可查询到当前系统中安装的所有的软件包。

2. 确定了要卸载的软件的名称,就可以开始实际卸载该软件了。键入命令:

#rpm -e [package name]

即可卸载软件。参数e的作用是使rpm进入卸载模式。对名为[package name]的软件包进行

卸载。由于系统中各个软件包之间相互有依赖关系。如果因存在依赖关系而不能卸载, rpm将

给予提示并停止卸载。你可以使用如下的命令来忽略依赖关系,直接开始卸载:

#rpm -e [package name] -nodeps

忽略依赖关系的卸载可能会导致系统中其它的一些软件无法使用

2004年11月16日

1. 软件获取:
    Apache:去http://httpd.apache.org/download.cgi 下载;
    JDK:去http://jakarta.apache.org/site/binindex.cgi下载(我的是1.4.2);
    Tomcat:去http://apache.bestwebcover.com/jakarta/tomcat-4/下载;
    JK:去http://mirrors.mix5.com/apache/jakarta/tomcat-connectors/jk2/binaries/win32/ 下载。

2. 安装Apache、JDK和Tomcat,这就不用说了吧。

3. 将获取的Apache版的JK包jakarta-tomcat-connectors-jk2.0.4-win32-apache2.0.49.zip解压缩到JK目录,将JK/conf/mod_jk2.conf.sample和JK/conf/workers2.properties.sample复制到Apache/conf/目录下,并改名为mod_jk2.conf和workers2.properties,用文本编辑器打开mod_jk2.conf文件,将”/usr/local/etc/apache2/workers2.properties”改为workers2.properties文件的绝对路径,我的是”JkSet config.file “E:\Apache2047\conf\workers2.properties”";将JK/modules/mod_jk2.so复制到Apache的modules/目录下,JK/doc/目录是一些说明文档,有兴趣你可以看看。

4. 用文本编辑器打开Apache/conf/httpd.conf文件,找到LoadModule 语句,在LoadModule 区域的最后面加一句”LoadModule jk2_module “modules/mod_jk2.so”";

5. 最后,重新启动Apache和tomcat。(命令行:net stop apache2、tomcat/bin/shutdown.bat;net start apache2、tomcat/bin/startup.bat)

6. 在浏览器访问http://localhost/jkstatus将会看到JK的运行状态信息,访问http://localhost/examples/ 将会看到Tomcat的示例页面,整合完毕。

7. BTW,如果你想在Apache中添加更多的Tomcat虚拟目录,请在workers2.properties中添加。