包管理简介

过去,许多 Linux 程序以源代码的形式发行,用户把源代码构建为所需的程序或程序集;源代码还附带必需的手册页、配置文件等等。现在,大多数 Linux 发行商使用称为包 的预构建的程序或程序集,包便于在发行版上安装。在本文中,学习帮助安装、更新和删除包的包管理 工具。本文主要关注 Red Hat 开发的 Red Hat Package Manager (RPM),以及 Duke University 物理系最初为管理 Red Hat Linux 系统开发的 Yellowdog Updater Modified (YUM)。

从用户的角度来说,基本的包管理功能由命令提供。Linux 开发人员一直致力于让 Linux 更容易使用,他们开发了其他工具(包括 GUI 工具)来补充基本工具,这对最终用户隐藏了基本工具的一部分复杂性。在本文和 学习 Linux,101:Debian 包管理 中,我们主要讨论基本工具,但是也会提到一些其他工具,让您能够继续研究它们。

RPM、YUM 和 APT(适用于 Debian 系统)有许多相似之处。它们都可以安装和删除包。关于安装的包的信息保存在数据库中。它们都有基本的命令行功能,同时通过其他工具提供对用户更友好的界面。它们都可以从 Internet 获取包。

在安装 Linux 系统时,通常会安装许多包。这个集合可能是根据系统的用途定制的,比如服务器、桌面或开发工作站。有时候,可能需要安装新的包以添加新功能,更新现有的包,甚至删除不再需要或已经被新的包取代的包。我们来看看如何完成这些任务以及如何解决一些相关的难题,比如寻找包含某一命令的包。

RPM

Red Hat 于 1995 年引入了 RPM。RPM 现在是 Linux Standard Base (LSB) 中采用的包管理系统。rpm 命令选项分为三组:

  1. 用于查询和检查包
  2. 用于安装、升级和删除包
  3. 用于执行其他功能

在本文中,我们主要关注前两组命令选项。在 RPM 的手册页中可以找到其他功能的相关信息。

还应该注意 rpm 是操作 RPM 的主要命令,而 .rpm 是 RPM 文件使用的扩展名。所以 “一个 rpm” 或 “某某 rpm” 一般是指 RPM 文件,而 rpm 通常指命令。

YUM

YUM 在 RPM 系统中增加了自动更新和包管理,包括依赖关系管理。与 Debian Advanced Packaging Tool (APT) 一样,除了了解系统上安装的包之外,YUM 还使用存储库。存储库是包的集合,通常可以通过网络连接访问它们。

安装 RPM 包

假设您想学 Lisp,一位同事让您使用 gcl 命令。您试着输入 gcl --help、which gcl 或 type gcl。但是,如果系统无法找到 gcl,您可能会看到与清单 1 相似的输出。

清单 1. 没有找到 gcl 命令

[ian@echidna ~]$ gcl --help bash: gcl: command not found [ian@echidna ~]$ which gcl /usr/bin/which: no gcl in (/usr/lib64/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerber os/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/ sbin:/home/ian/bin) [ian@echidna ~]$ type gcl bash: type: gcl: not found

您可能会问同事要安装哪个包,也可能猜想 gcl 命令应该在 gcl 包中。这种猜测常常是对的,但是也不总是。我们稍后会看到如何寻找正确的包。在这里,需要 gcl 包。假设您已经下载或以其他方式获得了这个包的拷贝,可以使用带 -i(代表安装)选项的 rpm 命令安装它,见清单 2。

清单 2. 用 rpm 安装 gcl —— 第一次尝试

[root@echidna ~]# rpm -i gcl-2.6.8-0.6.20090701cvs.fc12.x86_64.rpm error: Failed dependencies: gcl-selinux is needed by gcl-2.6.8-0.6.20090701cvs.fc12.x86_64

rpm 命令知道这个包有一个依赖包,但是它并不帮助您解决依赖问题。您需要自己获取依赖包,然后再次尝试,看看是否还有其他依赖包 — 重复这个过程,直到满足所有依赖关系为止。好消息是,可以向 rpm 命令提供要安装的包的列表,如果满足所有依赖关系,它会以正确的次序安装所有包。因此,您至少不必以正确的次序手工安装每个包。

如果您使用过 Debian 的 APT,可能希望有像 apt-get 命令一样的功能,apt-get 命令会寻找需要的东西(包括依赖包)并安装它们。对于基于 RPM 的系统,YUM (Yellowdog Updater Modified) 提供这种功能。清单 3 说明如何使用带 install 选项的 yum 命令安装 gcl 和必需的 gcl-selinux 包。

清单 3. 使用 yum 安装 gcl

[root@echidna ~]# yum install gcl Loaded plugins: presto, refresh-packagekit Setting up Install Process Resolving Dependencies --> Running transaction check ---> Package gcl.x86_64 0:2.6.8-0.7.20100201cvs.fc12 set to be updated --> Processing Dependency: gcl-selinux for package: gcl-2.6.8-0.7.20100201cvs.fc12.x86_64 --> Running transaction check ---> Package gcl-selinux.x86_64 0:2.6.8-0.7.20100201cvs.fc12 set to be updated --> Finished Dependency Resolution Dependencies Resolved ===================================================================================== Package Arch Version Repository Size ===================================================================================== Installing: gcl x86_64 2.6.8-0.7.20100201cvs.fc12 updates 6.3 M Installing for dependencies: gcl-selinux x86_64 2.6.8-0.7.20100201cvs.fc12 updates 17 k Transaction Summary ===================================================================================== Install 2 Package(s) Upgrade 0 Package(s) Total download size: 6.4 M Installed size: 40 M Is this ok [y/N]: y Downloading Packages: Setting up and reading Presto delta metadata updates/prestodelta | 964 kB 00:01 Processing delta metadata Package(s) data still to download: 6.4 M (1/2): gcl-2.6.8-0.7.20100201cvs.fc12.x86_64.rpm | 6.3 MB 00:12 (2/2): gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64.rpm | 17 kB 00:00 ------------------------------------------------------------------------------------- Total 398 kB/s | 6.4 MB 00:16 Running rpm_check_debug Running Transaction Test Transaction Test Succeeded Running Transaction Installing : gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64 1/2 Installing : gcl-2.6.8-0.7.20100201cvs.fc12.x86_64 2/2 Installed: gcl.x86_64 0:2.6.8-0.7.20100201cvs.fc12 Dependency Installed: gcl-selinux.x86_64 0:2.6.8-0.7.20100201cvs.fc12 Complete!

清单 3 中的输出表明,YUM 在名为 “updates” 的存储库中找到了 gcl.x86_64 0:2.6.8-0.7.20100201cvs.fc12 和 gcl-selinux.x86_64 0:2.6.8-0.7.20100201cvs.fc12(稍后详细讨论),并判断出总下载大小。按 “y” 同意之后,它下载这两个包,然后安装依赖包,最后安装 gcl。在本文后面会进一步讨论依赖关系。

包的位置

在前一节中,学习了如何安装 RPM 包。但是,包来自什么地方呢?yum 如何知道从哪里下载包?起点是 /etc/yum.repos.d/ 目录,这个目录常常包含几个 repo 文件。这是 repo 的默认位置,但是可以在 YUM 配置文件(通常是 /etc/yum.conf)中指定其他位置。清单 4 给出 fedora-updates.repo,我们从它所对应的位置获取 gcl 并安装在我的 Fedora 12 系统上。

典型的 repo 文件分为三个部分,一个用于一般的包,一个用于调试包,最后一个用于源代码包。常常可以从不同的位置(即镜像)获取发行版的包拷贝。所以 repo 文件告诉 yum 在哪里可以找到每个部分的最新镜像列表。注意,发行版的发布级别和机器架构表示为参数,所以对于我的 x86_64 Fedora 12 系统,yum 会从 https://mirrors.fedoraproject.org/metalink?repo=updates-released-f12&arch=x86_64 下载列表。

除了存储库位置之外,repo 文件还指出某个存储库是否启用了,以及是否应该使用 GPG 签名检查下载的包。

清单 4. fedora-updates.repo

[ian@echidna ~]$ cat /etc/yum.repos.d/fedora-updates.repo [updates] name=Fedora $releasever - $basearch - Updates failovermethod=priority #baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever /$basearch/ mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$r eleasever&arch=$basearch enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch [updates-debuginfo] name=Fedora $releasever - $basearch - Updates - Debug failovermethod=priority #baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever /$basearch/debug/ mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-deb ug-f$releasever&arch=$basearch enabled=0 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch [updates-source] name=Fedora $releasever - Updates Source failovermethod=priority #baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever /SRPMS/ mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-sou rce-f$releasever&arch=$basearch enabled=0 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch

YUM 和 RPM 使用本地数据库判断安装的包。本地数据库中存储的包元数据是从启用的存储库获取的。尽管很少需要为本地数据库操心,但是可以使用 yum clean 命令清除本地存储的信息的不同部分,使用 yum makecache 在本地数据库中为启用的 repo 创建信息。例如,如果修改了 repo 配置,就可能需要这么做。

删除 RPM 包

如果要删除包,可以使用 yum 的 remove 选项或 rpm 的 -e 选项。使用 rpm -e 删除 gcl 的试运行见清单 5。如果可以删除这个包,就不会有输出。

清单 5. 试删除 gcl

[root@echidna ~]# rpm -e --test gcl

与使用 apt-get 模拟删除 Debian 包不同,RPM 系统并不维护自动安装的包的相关信息,所以无法通过试删除查明哪些依赖包也可以删除。但是,如果在单一命令中指定多个要删除的包,那么没有依赖关系的包会先于有依赖关系的包删除。

与安装包不同,当使用 rpm 删除包时,在删除包之前没有提示。但是,如果试图删除其他包需要的包,它不会执行删除操作,您会看到清单 6 所示的错误消息。

清单 6. 用 rpm 删除依赖包

[root@echidna ~]# rpm -e gcl-selinux error: Failed dependencies: gcl-selinux is needed by (installed) gcl-2.6.8-0.7.20100201cvs.fc12.x86_64

如果使用 yum remove,在执行事务测试之后会显示提示。如果试图删除的包是其他已安装包的依赖包,YUM 会提议删除这些包和依赖包,见清单 7。

清单 7. 用 yum 删除依赖包

[root@echidna ~]# yum remove gcl-selinux Loaded plugins: presto, refresh-packagekit Setting up Remove Process Resolving Dependencies --> Running transaction check ---> Package gcl-selinux.x86_64 0:2.6.8-0.7.20100201cvs.fc12 set to be erased --> Processing Dependency: gcl-selinux for package: gcl-2.6.8-0.7.20100201cvs.fc12.x86_64 --> Running transaction check ---> Package gcl.x86_64 0:2.6.8-0.7.20100201cvs.fc12 set to be erased --> Finished Dependency Resolution Dependencies Resolved ===================================================================================== Package Arch Version Repository Size ===================================================================================== Removing: gcl-selinux x86_64 2.6.8-0.7.20100201cvs.fc12 @updates 90 k Removing for dependencies: gcl x86_64 2.6.8-0.7.20100201cvs.fc12 @updates 40 M Transaction Summary ===================================================================================== Remove 2 Package(s) Reinstall 0 Package(s) Downgrade 0 Package(s) Is this ok [y/N]: n Exiting on user Command Complete!

升级 RPM 包

既然已经了解了如何安装和删除 RPM,我们来看看如何把 RPM 包升级到更高级别。可以使用 yum update 更新整个系统,还可以指定单一包或通配符。清单 8 说明如何更新所有名称以 “gr” 开头的包。注意,这里使用撇号防止 shell 展开 “*”。

清单 8. 使用 yum update 执行更新

[root@echidna ~]# yum update 'gr*' Loaded plugins: presto, refresh-packagekit Setting up Update Process Resolving Dependencies --&gt; Running transaction check ---&gt; Package grep.x86_64 0:2.6.3-1.fc12 set to be updated ---&gt; Package groff.x86_64 0:1.18.1.4-20.fc12 set to be updated --&gt; Finished Dependency Resolution Dependencies Resolved ===================================================================================== Package Arch Version Repository Size ===================================================================================== Updating: grep x86_64 2.6.3-1.fc12 updates 228 k groff x86_64 1.18.1.4-20.fc12 updates 1.5 M Transaction Summary ===================================================================================== Install 0 Package(s) Upgrade 2 Package(s) Total download size: 1.7 M Is this ok [y/N]: y Downloading Packages: Setting up and reading Presto delta metadata Processing delta metadata Download delta size: 854 k http://fedora.fastsoft.net/pub/linux/fedora/linux/updates/12/x86_64/drpms/grep-2.5.3- 6.fc12_2.6.3-1.fc12.x86_64.drpm: [Errno 14] HTTP Error 404 : http://fedora.fastsoft.n et/pub/linux/fedora/linux/updates/12/x86_64/drpms/grep-2.5.3-6.fc12_2.6.3-1.fc12.x86_ 64.drpm Trying other mirror. (1/2): grep-2.5.3-6.fc12_2.6.3-1.fc12.x86_64.drpm | 214 kB 00:00 (2/2): groff-1.18.1.4-18.fc12_1.18.1.4-20.fc12.x86_64.drpm | 640 kB 00:00 Finishing rebuild of rpms, from deltarpms <delta rebuild> | 1.7 MB 00:02 Presto reduced the update size by 52% (from 1.7 M to 854 k). Running rpm_check_debug Running Transaction Test Transaction Test Succeeded Running Transaction Updating : grep-2.6.3-1.fc12.x86_64 1/4 Updating : groff-1.18.1.4-20.fc12.x86_64 2/4 Cleanup : grep-2.5.3-6.fc12.x86_64 3/4 Cleanup : groff-1.18.1.4-18.fc12.x86_64 4/4 Updated: grep.x86_64 0:2.6.3-1.fc12 groff.x86_64 0:1.18.1.4-20.fc12 Complete!

如果知道 RPM 文件的位置,或者已经下载了它们,那么也可以使用 rpm 命令执行更新。这与安装相似,只是要使用 -U 或 -F 选项而不是 -i 选项。这两个选项的差异是, -U 选项更新现有的包,如果这个包还没有安装,就安装它;而 -F 选项只升级或刷新 已经安装的包。因此,经常使用 -U 选项,尤其是在命令行包含 RPM 列表的情况下。这样的话,就会安装未安装的包,升级已经安装的包。常常使用另外两个选项 -v(详细)和 -h(# 标志)提供进度显示。清单 9 说明如何使用 rpm 命令更新 vim-common、vim-enhanced 和 vim-minimal 包。我们已经把 vim-common 和 vim-enhanced 包下载到根用户的主目录中,而 vim-minimal 包要从一个更新镜像获取。

清单 9. 用 rpm 更新包

[root@echidna ~]# ls *.rpm vim-common-7.2.411-1.fc12.x86_64.rpm vim-enhanced-7.2.411-1.fc12.x86_64.rpm [root@echidna ~]# rpm -Uvh *.rpm http://mirrors.usc.edu/pub/linux/distributions\ &gt; /fedora/linux/updates/12/x86_64/vim-minimal-7.2.411-1.fc12.x86_64.rpm Retrieving http://mirrors.usc.edu/pub/linux/distributions/fedora/linux/updates/12/x86 _64/vim-minimal-7.2.411-1.fc12.x86_64.rpm Preparing... ########################################### [100%] 1:vim-common ########################################### [ 33%] 2:vim-enhanced ########################################### [ 67%] 3:vim-minimal ########################################### [100%]

查询 RPM 包

您在前面的示例中看到,用 rpm 命令安装 rpm 需要包文件的完整名称(或 URL),比如 gcl-2.6.8-0.6.20090701cvs.fc12.x86_64.rpm。另一方面,用 yum 安装或用这两个命令删除 rpm 只需要包名,比如 gcl。与 APT 一样,RPM 在内部数据库中维护安装的包的信息,因此允许使用包名操作安装的包。在本节中,看看可以使用 rpm 的 -q(代表查询)选项或相关联的 yum 查询从数据库获取的一些信息。

基本查询只检查包是否已经安装了,如果安装了,就查询版本。增加 -i 选项会得到包的相关信息。注意,安装、升级或删除包需要根权力,但是非根用户也可以查询 rpm 数据库。

清单 10. 显示 gcl 的相关信息

[ian@echidna ~]$ yum list gcl Loaded plugins: presto, refresh-packagekit Installed Packages gcl.x86_64 2.6.8-0.7.20100201cvs.fc12 @updates [ian@echidna ~]$ rpm -q gcl gcl-2.6.8-0.7.20100201cvs.fc12.x86_64 [ian@echidna ~]$ yum info gcl Loaded plugins: presto, refresh-packagekit Installed Packages Name : gcl Arch : x86_64 Version : 2.6.8 Release : 0.7.20100201cvs.fc12 Size : 40 M Repo : installed From repo : updates Summary : GNU Common Lisp URL : http://www.gnu.org/software/gcl/ License : GPL+ and LGPLv2+ Description: GCL is a Common Lisp currently compliant with the ANSI standard. : Lisp compilation produces native code through the intermediary of : the system's C compiler, from which GCL derives efficient : performance and facile portability. Currently uses TCL/Tk as GUI. [ian@echidna ~]$ rpm -qi gcl Name : gcl Relocations: (not relocatable) Version : 2.6.8 Vendor: Fedora Project Release : 0.7.20100201cvs.fc12 Build Date: Tue 23 Mar 2010 03:20:36 PM EDT Install Date: Wed 05 May 2010 01:01:34 PM EDT Build Host: x86-02.phx2.fedoraproject. org Group : Development/Languages Source RPM: gcl-2.6.8-0.7.20100201cvs.fc12.sr c.rpm Size : 41667750 License: GPL+ and LGPLv2+ Signature : RSA/8, Tue 23 Mar 2010 04:14:06 PM EDT, Key ID 9d1cc34857bbccba Packager : Fedora Project URL : http://www.gnu.org/software/gcl/ Summary : GNU Common Lisp Description : GCL is a Common Lisp currently compliant with the ANSI standard. Lisp compilation produces native code through the intermediary of the system's C compiler, from which GCL derives efficient performance and facile portability. Currently uses TCL/Tk as GUI.

详细的清单显示与 RPM 包相关联的一些标记。注意,rpm 和 yum 以不同的格式显示不同的信息。在本文中,我们都使用标准命令选项提供的基本输出。如果希望使用 rpm --queryformat 选项定制查询输出,请参考手册页。如果希望了解您的 rpm 版本支持的所有标记,应该运行 rpm --querytags。

如清单 10 所示,可以使用 yum 列出安装的包。还可以用它列出有更新可用的包、可以安装的包以及具有其他性质的包,比如废弃的包或存储库中最近添加的包。甚至可以使用 yum 搜索包。在清单 11 中可以看到,texmacs 包还没有安装,但是可以从 fedora 存储库获取它。如果搜索 “texmacs”,会看到提到它的四个包。很容易看出为什么会找到 TeXmacs* 包。使用 yum info pydot 查明为什么也会找到 pydot 包。

清单 11. 搜索 "texmacs"

[ian@echidna ~]$ yum list texmacs Loaded plugins: presto, refresh-packagekit Available Packages TeXmacs.x86_64 1.0.7.2-2.fc12 fedora [ian@echidna ~]$ yum search texmacs Loaded plugins: presto, refresh-packagekit ================================= Matched: texmacs ================================== TeXmacs-devel.i686 : Development files for TeXmacs TeXmacs-devel.x86_64 : Development files for TeXmacs TeXmacs.x86_64 : Structured wysiwyg scientific text editor pydot.noarch : Python interface to Graphviz's Dot language

对于后面的查询示例,我们主要使用 rpm,因为它的选项更丰富。许多示例也可以使用 yum 完成,yum 有一些基本 rpm 选项不具备的功能。

RPM 包和其中的文件

用户常常希望知道一个包中有哪些文件,或者某个文件来自哪个包。使用 -ql 选项列出 gcl 包中的文件,见清单 12。这个包中有许多文件,所以这里只给出部分输出。

清单 12. 显示 gcl 包中的文件

[ian@echidna ~]$ rpm -ql gcl /usr/bin/gcl /usr/lib/gcl-2.6.8 /usr/lib/gcl-2.6.8/clcs /usr/lib/gcl-2.6.8/clcs/sys-proclaim.lisp /usr/lib/gcl-2.6.8/cmpnew /usr/lib/gcl-2.6.8/cmpnew/gcl_cmpmain.lsp /usr/lib/gcl-2.6.8/cmpnew/gcl_cmpopt.lsp /usr/lib/gcl-2.6.8/cmpnew/gcl_collectfn.lsp . . . /usr/share/info/gcl-tk.info.gz /usr/share/info/gcl.info-1.gz /usr/share/info/gcl.info-2.gz /usr/share/info/gcl.info-3.gz /usr/share/info/gcl.info-4.gz /usr/share/info/gcl.info-5.gz /usr/share/info/gcl.info-6.gz /usr/share/info/gcl.info-7.gz /usr/share/info/gcl.info-8.gz /usr/share/info/gcl.info-9.gz /usr/share/info/gcl.info.gz /usr/share/man/man1/gcl.1.gz

通过在查询中添加 -c 选项,可以把列出的文件限制为配置文件。-d 选项把输出限制为文档文件。

查询包文件

上面的包查询命令在 RPM 数据库中查询已经安装的包。如果刚下载了一个包,想获取同类信息,可以在查询中使用 -p(代表包文件)选项并指定包的文件 名(与安装包时一样)。清单 13 显示前面下载的两个 vim 包的信息。我们只作为根用户运行它,因为文件在根用户的主目录中。可以添加其他查询选项,比如用 -l 列出文件,用 -i 列出信息。

清单 13. 显示两个 vim 包的包文件信息

[root@echidna ~]# rpm -qp *.rpm vim-common-7.2.411-1.fc12.x86_64 vim-enhanced-7.2.411-1.fc12.x86_64

查询安装的所有包

-a 选项把查询应用于安装的所有包。这会生成许多输出,所以通常同时使用一个或多个筛选器,比如用 sort 进行排序,用 more 或 less 进行分页输出,用 wc 获取包或文件内容,用 grep 搜索您不确定名称的包。清单 14 给出以下查询:

  1. 系统上所有包的排序列表
  2. 系统上所有包的数量
  3. 系统上所有包中的所有文件的数量
  4. 用 RPM 安装的所有文档文件的数量
  5. 搜索名称中包含 “gcl” 的所有包(区分大小写)

清单 14. 对所有包执行查询

[ian@echidna ~]$ rpm -qa | sort | more aalib-libs-1.4.0-0.18.rc5.fc12.x86_64 abrt-1.0.8-2.fc12.x86_64 abrt-addon-ccpp-1.0.8-2.fc12.x86_64 abrt-addon-kerneloops-1.0.8-2.fc12.x86_64 abrt-addon-python-1.0.8-2.fc12.x86_64 abrt-desktop-1.0.8-2.fc12.x86_64 abrt-gui-1.0.8-2.fc12.x86_64 abrt-libs-1.0.8-2.fc12.x86_64 abrt-plugin-bugzilla-1.0.8-2.fc12.x86_64 abrt-plugin-logger-1.0.8-2.fc12.x86_64 abrt-plugin-runapp-1.0.8-2.fc12.x86_64 abyssinica-fonts-1.0-5.fc12.noarch acl-2.2.49-2.fc12.x86_64 ... [ian@echidna ~]$ rpm -qa | wc -l 1792 [ian@echidna ~]$ rpm -qal | wc -l 281052 [ian@echidna ~]$ rpm -qad | wc -l 45686 [ian@echidna ~]$ rpm -qa | grep -i gcl gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64 gcl-2.6.8-0.7.20100201cvs.fc12.x86_64

使用 rpm -qa 可以简化对多个系统的管理。如果把排序的输出重定向到一台机器上的文件,然后在另一台机器上也这么做,就可以使用 diff 程序寻找差异。

哪个包包含某一文件?

既然可以列出所有包和一个包中的所有文件,现在就掌握了查明哪个包包含某一文件所需的所有信息。但是,rpm 命令的 -f(或 --file)选项可以帮助找到包含某一文件的包。假设您想知道前面看到的哪个 vim 包提供 vim 命令。您需要文件的完整路径。清单 15 说明如何使用 which 命令得到 vim 命令的完整路径,可以使用这个输出作为 rpm -qf 命令的输入。注意,`which guile-config` 前后的符号是反撇号。在 Bash shell 中,另一种使用方法是 $(which vim)。

清单 15. 哪个包提供 vim 可执行文件

[ian@echidna ~]$ which vim /usr/bin/vim [ian@echidna ~]$ rpm -qf `which vim` vim-enhanced-7.2.411-1.fc12.x86_64 [ian@echidna ~]$ rpm -qf $(which vim) vim-enhanced-7.2.411-1.fc12.x86_64

RPM 依赖关系

在前面看到删除 gcl-selinux 包的操作失败了,这是因为存在依赖关系。除了文件之外,RPM 包可能包含其他包所依赖的任意功能。

如您所见,依赖关系通常会正常发挥作用。如果需要同时安装几个包,其中一些依赖于其他包,那么只需使用 yum,或者向 rpm -Uvh 命令提供完整的列表,它会分析依赖关系并按正确的次序执行安装。

除了在安装或删除包时产生的错误消息之外,还可以通过几种方法查明包需要或依赖的文件或功能。

rpm 命令提供的一个选项可以查询安装的包或包文件,从而查明它们依赖或需要 什么功能。这个选项是 --requires,它可以简写为 -R。清单 16 显示 gcl 需要的功能。如果要查询包文件而不是 RPM 数据库,那么添加 -p 选项并使用完整的 RPM 文件名。

清单 16. gcl 需要什么

[ian@echidna ~]$ rpm -qR gcl /bin/sh /bin/sh /bin/sh /sbin/install-info /sbin/install-info gcl-selinux libX11.so.6()(64bit) libc.so.6()(64bit) libc.so.6(GLIBC_2.11)(64bit) libc.so.6(GLIBC_2.2.5)(64bit) libc.so.6(GLIBC_2.3)(64bit) libc.so.6(GLIBC_2.3.4)(64bit) libc.so.6(GLIBC_2.4)(64bit) libc.so.6(GLIBC_2.7)(64bit) libc.so.6(GLIBC_2.8)(64bit) libdl.so.2()(64bit) libgmp.so.3()(64bit) libm.so.6()(64bit) libm.so.6(GLIBC_2.2.5)(64bit) libreadline.so.6()(64bit) libtcl8.5.so()(64bit) libtk8.5.so()(64bit) libz.so.1()(64bit) rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) &lt;= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) &lt;= 4.0-1 rtld(GNU_HASH) rpmlib(PayloadIsXz) &lt;= 5.2-1

把功能与提供它们的包联系起来不太容易。带 deplist 选项的 yum 命令可以提供帮助。如果只指定包名,没有版本号,可能会得到其他已知版本的列表。清单 17 说明如何获得安装的 gcl 版本的依赖列表。

清单 17. 使用 yum deplist 查明 gcl 需要什么

[ian@echidna ~]$ yum deplist $(rpm -q gcl) Loaded plugins: presto, refresh-packagekit Finding dependencies: package: gcl.x86_64 2.6.8-0.7.20100201cvs.fc12 dependency: libc.so.6(GLIBC_2.3.4)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: gcl-selinux provider: gcl-selinux.x86_64 2.6.8-0.6.20090701cvs.fc12 provider: gcl-selinux.x86_64 2.6.8-0.7.20100201cvs.fc12 dependency: libgmp.so.3()(64bit) provider: gmp.x86_64 4.3.1-5.fc12 dependency: libc.so.6(GLIBC_2.8)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libc.so.6(GLIBC_2.4)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libc.so.6()(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: /sbin/install-info provider: info.x86_64 4.13a-7.fc12 provider: info.x86_64 4.13a-9.fc12 dependency: libX11.so.6()(64bit) provider: libX11.x86_64 1.3-1.fc12 dependency: libc.so.6(GLIBC_2.7)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libtcl8.5.so()(64bit) provider: tcl.x86_64 1:8.5.7-4.fc12 provider: tcl.x86_64 1:8.5.7-5.fc12 dependency: libc.so.6(GLIBC_2.11)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libtk8.5.so()(64bit) provider: tk.x86_64 1:8.5.7-2.fc12 provider: tk.x86_64 1:8.5.7-3.fc12 dependency: libc.so.6(GLIBC_2.3)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libm.so.6()(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libz.so.1()(64bit) provider: zlib.x86_64 1.2.3-23.fc12 dependency: rtld(GNU_HASH) provider: glibc.i686 2.11-2 provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 provider: glibc.i686 2.11.1-6 dependency: libdl.so.2()(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libreadline.so.6()(64bit) provider: readline.x86_64 6.0-3.fc12 dependency: /bin/sh provider: bash.x86_64 4.0.33-1.fc12 provider: bash.x86_64 4.0.35-3.fc12 dependency: libc.so.6(GLIBC_2.2.5)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6 dependency: libm.so.6(GLIBC_2.2.5)(64bit) provider: glibc.x86_64 2.11-2 provider: glibc.x86_64 2.11.1-6

这个列表还显示每个功能可能的提供者。可以看到大多数依赖功能可以由多个包级别提供。例如,/bin/sh 可以来自 bash 的两个级别之一。通过使用创造性的筛选,可以把输出缩减为清单 18 所示的包名列表。

清单 18. 把 yum deplist 的输出缩减为只列出包名

[ian@echidna ~]$ yum deplist $(rpm -q gcl) | grep "provider:" | \ > awk '{ print $2 }'|sort|uniq bash.x86_64 gcl-selinux.x86_64 glibc.i686 glibc.x86_64 gmp.x86_64 info.x86_64 libX11.x86_64 readline.x86_64 tcl.x86_64 tk.x86_64 zlib.x86_64

如果只想知道需要安装哪些包,可以运行 yum install,查看在提示接受安装提议之前显示的列表。

除了查明包需要的功能之外,还可能需要了解哪个包提供某一功能。前面演示了如何查明哪个包包含某一文件。清单 19 说明如何使用 rpm 或 yum 查明哪个包提供 gcl-selinux(x86-64) 功能。除了显示提供此功能的已安装包的信息之外,YUM 还显示存储库中可用的包或版本。可以看到,原来的 2.6.8-0.6 版来自 fedora 存储库,而 updates 存储库中有更新的 2.6.8-0.7 版。

清单 19. 哪个包提供 gcl-selinux(x86-64) 功能

[ian@echidna ~]$ rpm -q --whatprovides 'gcl-selinux(x86-64)' gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64 [ian@echidna ~]$ yum whatprovides 'gcl-selinux(x86-64)' Loaded plugins: presto, refresh-packagekit gcl-selinux-2.6.8-0.6.20090701cvs.fc12.x86_64 : SELinux policy for GCL images Repo : fedora Matched from: Other : gcl-selinux(x86-64) gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64 : SELinux policy for GCL images Repo : updates Matched from: Other : gcl-selinux(x86-64) gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64 : SELinux policy for GCL images Repo : installed Matched from: Other : Provides-match: gcl-selinux(x86-64)

RPM 包文件完整性

为了确保完整性,RPM 包包含一个摘要(比如 MD5 或 SHA1),常常经过数字签名。数字签名的包需要用公共密钥进行检验。使用 rpm 的 --checksig(简写为 -K)选项检查 RPM 包文件的完整性。添加 -v 选项以生成更详细的输出常常有帮助。清单 20 给出的示例检查 vim-enhanced RPM 的完整性。

清单 20. 检查 vim-enhanced 包文件的完整性

[root@echidna ~]# rpm -vK vim-enhanced-7.2.411-1.fc12.x86_64.rpm vim-enhanced-7.2.411-1.fc12.x86_64.rpm: Header V3 RSA/SHA256 signature: OK, key ID 57bbccba Header SHA1 digest: OK (f9a199545a515f7ff0716729768b41eb68fe29a8) V3 RSA/SHA256 signature: OK, key ID 57bbccba MD5 digest: OK (d4045f1f72d48073e3f401ee9d1f71cf)

可能会产生下面的输出:

V3 DSA signature: NOKEY, key ID 16a61572

这意味着这个包是经过签名的,但是您的 RPM 数据库中没有所需的公共密钥。注意,以前版本的 RPM 可能以不同的方式提供检验。

如果包是经过签名的,您希望根据签名检验它,就需要找到适当的签名文件并把它导入 RPM 数据库。应该首先下载密钥,然后检查它的指纹,最后使用 rpm --import 命令导入它。更多信息参见 RPM 手册页。还可以在 RPM 主页上找到关于签名的二进制代码的更多信息(见 参考资料 中的链接)。

检验安装的包

与检查 rpm 的完整性一样,还可以使用 rpm -V 检查已安装的文件的完整性。这个步骤确保从 rpm 安装文件之后文件没有修改过。如清单 21 所示,如果包仍然良好,这个命令没有输出;但是,可以添加 -v 选项以产生更详细的输出。

清单 21. 检验已安装的 vim-common 包

[ian@echidna ~]$ rpm -V vim-common

现在,我们作为根用户删除 /usr/bin/xxd 并把 /usr/share/vim/vim72/syntax/bindzone.vim 替换为 /bin/bash。然后再次检查。结果见清单 22。

清单 22. 篡改 vim-common 包

[root@echidna ~]# rpm -qf /usr/bin/xxd /usr/share/vim/vim72/syntax/bindzone.vim vim-common-7.2.411-1.fc12.x86_64 vim-common-7.2.411-1.fc12.x86_64 [root@echidna ~]# rm /usr/bin/xxd rm: remove regular file `/usr/bin/xxd'? y [root@echidna ~]# cp /bin/bash /usr/share/vim/vim72/syntax/bindzone.vim cp: overwrite `/usr/share/vim/vim72/syntax/bindzone.vim'? y [root@echidna ~]# rpm -V vim-common missing /usr/bin/xxd S.5....T. /usr/share/vim/vim72/syntax/bindzone.vim

输出表明对 /usr/share/vim/vim72/syntax/bindzone.vim 文件的 MD5 和、文件大小和 mtime 检查失败了。解决这个问题的一种方法是删除这个包,然后重新安装,依赖于 vim-common 的其他已安装包仍然可以正常运行。这个解决方案使用 rpm 的 --force 选项或 yum 的 reinstall 功能强制重新安装。清单 23 演示如何用 yum 重新安装,然后检查包现在是否良好,检查删除的文件是否已经恢复了。

清单 23. 重新安装 vim-common 包

[root@echidna ~]# yum reinstall vim-common Loaded plugins: presto, refresh-packagekit Setting up Reinstall Process Resolving Dependencies --&gt; Running transaction check ---&gt; Package vim-common.x86_64 2:7.2.411-1.fc12 set to be updated --&gt; Finished Dependency Resolution Dependencies Resolved ===================================================================================== Package Arch Version Repository Size ===================================================================================== Reinstalling: vim-common x86_64 2:7.2.411-1.fc12 updates 6.0 M Transaction Summary ===================================================================================== Remove 0 Package(s) Reinstall 1 Package(s) Downgrade 0 Package(s) Total download size: 6.0 M Installed size: 17 M Is this ok [y/N]: y Downloading Packages: Setting up and reading Presto delta metadata updates/prestodelta | 969 kB 00:00 Processing delta metadata Package(s) data still to download: 6.0 M vim-common-7.2.411-1.fc12.x86_64.rpm | 6.0 MB 00:01 Running rpm_check_debug Running Transaction Test Transaction Test Succeeded Running Transaction Warning: RPMDB altered outside of yum. Installing : 2:vim-common-7.2.411-1.fc12.x86_64 1/1 Installed: vim-common.x86_64 2:7.2.411-1.fc12 Complete! [root@echidna ~]# rpm -V vim-common [root@echidna ~]# ls /usr/bin/xxd /usr/bin/xxd

如果需要更有力的措施

包管理系统通常可以恢复包。但是,如果删除了包中的重要文件,重新安装包但不删除无法解决问题,那么可能需要在重新安装之前删除包。对于这种情况,可能希望删除现有的拷贝并重新安装,但是不希望卸载和重新安装依赖它的所有包。为此,在删除包时,可以使用 rpm 命令的 --nodeps 选项绕过依赖关系检查。在清单 24 中,删除了 vim-common 中的 /usr/bin/xxd 文件,然后演示如何恢复这个包。

清单 24. 用 rpm 更新包

[root@echidna ~]# rm /usr/bin/xxd rm: remove regular file `/usr/bin/xxd'? y [root@echidna ~]# # Oops! we needed that file [root@echidna ~]# rpm -Fvh vim-common-7.2.411-1.fc12.x86_64.rpm [root@echidna ~]# ls /usr/bin/xxd ls: cannot access /usr/bin/xxd: No such file or directory [root@echidna ~]# # Oh! Freshening the package didn't replace the missing file [root@echidna ~]# rpm -e vim-common error: Failed dependencies: vim-common = 2:7.2.411-1.fc12 is needed by (installed) vim-enhanced-2:7.2.411-1.f c12.x86_64 [root@echidna ~]# # Can't remove vim-common because vim-enhanced needs it [root@echidna ~]# rpm -e --nodeps vim-common [root@echidna ~]# # Bypassing the dependency check allowed removal [root@echidna ~]# rpm -Uvh vim-common-7.2.411-1.fc12.x86_64.rpm Preparing... ########################################### [100%] 1:vim-common ########################################### [100%] [root@echidna ~]# # Update (or install) vim-common again [root@echidna ~]# ls /usr/bin/xxd /usr/bin/xxd [root@echidna ~]# # And /usr/bin/xxd is back

现在,如果发生意外或一般的更新失败,您可以以几种方法更新或修复。注意,在安装 RPM 时也可以绕过依赖关系检查,但是这通常不是好做法。

从存储库下载 RPM

尽管 yum 会自动地从存储库获取包,但是您可能希望下载并保存 RPM,比如为了在不连网的系统上安装它们、为了检查它们的内容或有其他原因。可以使用清单 25 所示的 yumdownloader 命令。对于我们的示例,这个包已经安装了,所以没有要下载的包。如果有这样的包,可以使用 --resolve 选项再次下载它们。

清单 25. 下载 gcl 包

[ian@echidna ~]$ yumdownloader --resolve gcl Loaded plugins: presto, refresh-packagekit adobe-linux-i386 17/17 --&gt; Running transaction check ---&gt; Package gcl.x86_64 0:2.6.8-0.7.20100201cvs.fc12 set to be updated --&gt; Finished Dependency Resolution gcl-2.6.8-0.7.20100201cvs.fc12.x86_64.rpm | 6.3 MB 00:01

使用 rpm2cpio

如果下载一个 RPM,需要检查它的内容而不是安装它,可以使用 rpm2cpio 命令把内容转换为 cpio 存档,然后通过 cpio 命令提取出包中的某些或所有文件。清单 26 对 gcl-selinux 包执行转换,然后显示提取出的文件(和目录)。关于 rpm2cpio 和 cpio 命令的更多信息参见它们的手册页。

清单 26. 用 rpm2cpio 提取 gcl-selinux 包

[ian@echidna ~]$ yumdownloader gcl-selinux Loaded plugins: presto, refresh-packagekit gcl-selinux-2.6.8-0.7.20100201cvs.fc12.x86_64.rpm | 17 kB 00:00 [ian@echidna ~]$ mkdir gcl-selinux [ian@echidna ~]$ cd gcl-selinux [ian@echidna gcl-selinux]$ rpm2cpio ../gcl-selinux*.rpm | cpio -idv ./usr/share/selinux/packages/gcl ./usr/share/selinux/packages/gcl/gcl.pp 182 blocks [ian@echidna gcl-selinux]$ find . . ./usr ./usr/share ./usr/share/selinux ./usr/share/selinux/packages ./usr/share/selinux/packages/gcl ./usr/share/selinux/packages/gcl/gcl.pp

寻找 RPM

我们在前面看到 YUM 提供了搜索功能,可以搜索包描述和包名。如果需要查明哪个包包含某个还没有安装的程序,还有几种方法:

  1. 可以猜测可能包含它的包,下载这个包,但是不安装。得到这个包之后,就可以查询它。
  2. 可以搜索 Internet。
  3. 可以试试下面介绍的 command-not-found 功能。

如果通过系统工具无法找到某个 RPM,可以通过 Rpmfind.Net 服务器寻找 RPM。

命令未找到

如果 Bash shell 搜索一个命令,但是没有找到,那么 shell 就搜索 shell 函数 command_not_found_handle。如果 command_not_found_handle 函数存在,shell 以原来的命令和参数作为参数调用它,函数的退出状态成为 shell 的退出状态。如果没有定义此函数,shell 输出错误消息并返回退出状态 127。常常在系统 /etc/bash.bashrc 文件中设置此函数。清单 27 说明如何搜索 command-not-found 功能并安装它。

清单 27. 寻找并安装 command-not-found 功能

[root@echidna ~]# yum search command-not-found Loaded plugins: presto, refresh-packagekit ========================== Matched: command-not-found ========================== PackageKit-command-not-found.x86_64 : Ask the user to install command line : programs automatically You have new mail in /var/spool/mail/root [root@echidna ~]# yum install PackageKit-command-not-found.x86_64 Loaded plugins: presto, refresh-packagekit Setting up Install Process Resolving Dependencies --&gt; Running transaction check ---&gt; Package PackageKit-command-not-found.x86_64 0:0.5.7-2.fc12 set to be updated --&gt; Finished Dependency Resolution Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: PackageKit-command-not-found x86_64 0.5.7-2.fc12 updates 102 k Transaction Summary ================================================================================ Install 1 Package(s) Upgrade 0 Package(s) Total download size: 102 k Installed size: 262 k Is this ok [y/N]: y Downloading Packages: Setting up and reading Presto delta metadata Processing delta metadata Package(s) data still to download: 102 k PackageKit-command-not-found-0.5.7-2.fc12.x86_64.rpm | 102 kB 00:00 Running rpm_check_debug Running Transaction Test Transaction Test Succeeded Running Transaction Installing : PackageKit-command-not-found-0.5.7-2.fc12.x86_64 1/1 Installed: PackageKit-command-not-found.x86_64 0:0.5.7-2.fc12 Complete!

清单 28 说明在安装 PackageKit-command-not-found 之后如何定义这个函数。如果函数无法执行搜索,那么它模拟标准的系统行为,返回 127。

清单 28. command_not_found_handle

[ian@echidna ~]$ type command_not_found_handle command_not_found_handle is a function command_not_found_handle () { runcnf=1; retval=127; [ ! -S /var/run/dbus/system_bus_socket ] && runcnf=0; [ ! -x /usr/sbin/packagekitd ] && runcnf=0; if [ $runcnf -eq 1 ]; then /usr/libexec/pk-command-not-found $1; retval=$?; else echo "bash: $1: command not found"; fi; return $retval }

如果在 清单 1 中运行 gcl 之前安装了这个功能,可能会看到清单 29 所示的输出。

清单 29. 安装 command_not_found_handle 之后尝试运行 gcl

[ian@echidna ~]$ gcl Command not found. Install package 'gcl' to provide command 'gcl'? [N/y]

其他工具

除了 yum 和 rpm 之外,发行商可能提供了用于从存储库安装包或更新整个系统的其他工具。这些工具可能是图形化工具或命令行工具,或者同时提供这两种界面。例如:

  1. YaST (SUSE)
  2. up2date (Red Hat)
  3. Mandrake Software Management (Mandriva)

通常,这些工具以自动或半自动方式处理多个包更新。它们还可能提供显示存储库内容或搜索包的功能。更多信息参见发行版的文档。

PackageKit

讨论包安装就不能不提到 PackageKit,这是一个为更方便地安装和更新软件而设计的系统。它的意图是把不同发行版中使用的所有软件图形化工具统一起来。 PackageKit 使用一个由系统激活的守护进程,这意味着这个守护进程只在需要时激活。Packagekit 有适用于 Gnome (gnome-packagekit) 和 KDE (KPackageKit) 的版本。上面介绍的 command-not-found 功能也是 PackageKit 的组成部分。它包括命令 pkcon(从控制台执行包管理功能)和 pkmon(监视包集活动)。它还包含用于添加软件包或更新系统的图形化工具。图 1 给出 Software Update 图形界面的示例。

图 1. Fedora 12 (Gnome) 上的 Software Update 图形界面

Fedora 12 (Gnome) 上 Software Update 图形界面的屏幕图

除了这里讨论的内容,RPM 和 YUM 包管理系统还有许多特性。本文介绍就到这里为止,想要更加深入的了解,可以参考其他的文章和资料。