5.2. 软件包元信息

Debian 软件包不仅是一个待安装文件的归档。它是一个更大结构的一部分,它描述与其它 Debian 软件包的关系(依赖、冲突、建议)。在软件包生命周期的不同阶段(安装、删除、升级),它还提供执行命令的脚本。软件包中的这些数据供包管理工具使用,但不是打包软件的一部分,称为“元信息”(关于其它信息的信息)。

5.2.1. 描述:control 文件

该文件使用一个类似电子邮件头(由 RFC_2822 定义)的结构。例如,apt 包的 control 文件看起来是这样的:

  1. $

基础知识 RFC -- 互联网标准

RFC 是 “征求建议”的缩写。RFC通常是一份描述将要成为互联网的标准的技术文档。在成为标准并被冻结之前,这些标准被提交给大众评估(这就是名字的由来)。 IETF(互联网工程专家组)决定这些文档的演进更新(建议标准、草案或标准)。

RFC 2026 定义了互联网协议标准化的程序。

http://www.faqs.org/rfcs/rfc2026.html

5.2.1.1. 依赖:Depends 域

依赖关系是在软件包头部的 Depends 域中定义的,它是软件包能够正常运行所需要满足的一系列条件。包管理工具诸如 apt 依靠这个信息来安装该软件所依赖的恰当版本的库。对于每一项依赖,可以限定依赖的版本范围来满足条件。换句话说,可以这样表达:我们需要版本号等于或者大于“2.15”的 libc6 软件包(写作 “libc6 (>= 2.15)”)。版本比较操作符使用如下:

  • <<:小于;

  • <=:小于或等于;

  • =:等于(注意, “2.6.1” 不等于 “2.6.1-1”);

  • >=:大于或等于;

  • >>:大于。

碰到条件时,以逗点做为交集 “and” 符号。以直线 (“|”) 为联集 “or” 符号 (它是包容性的或 “or”、不是排它性的非此即彼 “either/or”)。优先级比 “and” 高,可以无限次使用。因此,相依性 “(A or B) and C” 可写成 A | B, C。另个例子,“A or (B and C)” 应写成 “(A or B) and (A or C)”,因为 Depends 字段不接受以括号改变逻辑操作数 “or” 与 “and”的优先次序。所以须写成 A | B, A | C

http://www.debian.org/doc/debian-policy/ch-relationships.html

相依性系统是保证程序顺利运作的良好机制,但它也有另个用法 「元软件包」。这些空的软件软件包内容只有相依性的说明。由元软件包维护者把一群程序的相依性描述在其中;例如,apt install *meta-package* 将自动安装所有用到元软件包相依的文件。gnome、kde-full 与 linux-image-amd64 软件包就是元软件包之一。

DEBIAN 政策 预依赖, 一个更苛刻的 取决于

“预相依性”,列在软件包标头的 “Pre-Depends” 字段,满足完整的正常相依性;它的语法是相同的。正常相依性系指必须在声明相依性前先解开并配置的问题软件包。预相依性规定在运行软件包的预安装脚本前,必须先解开并配置软件包,就是在安装之前。

apt对预依赖的要求非常严格,因为它在安装软件包的时候增加了严格约束。因此,预依赖关系的安装软件的时候不鼓励,除非绝对需要。它甚至建议在加入预依赖前直接咨询开发人员[debian-devel@lists.dibian.org](https://www.debian.org/doc/manuals/debian-handbook/mailto:debian-devel@lists.dibian.org)。这也是一个通用的解决办法。

DEBIAN 政策 推荐建议增强

推荐建议字段描述的依赖关系不是强制性的。“推荐”的依赖,是最重要的,能显著改善由软件包提供的功能,但这并非是必不可少的操作。“建议”的依赖,是次要的,表明某些软件包可以补充或者增加其各自的效果,有充分的理由去单独安装它而不是其它的软件包。

你应该总是安装“推荐”的软件包,除非你知道究竟为什么你不需要它们。相反,“建议”的软件包是不必要安装的,除非你知道为什么你需要它们。

Enhances 增强 字段也描述建议,但是位于不同的内文。实际上位于建议软件包内,而不是受益于建议的软件包内。有可能在不修改软件包的前提下添加建议。因此所有插件、插件与其他的程序延伸可以显示在与软件相关的建议清单内。虽然已存在多年,但是 aptsynaptic 等程序依然忽略此字段的存在。Enhances 字段提出的建议系在传统建议 — Suggests 字段供用户参考。.

5.2.1.2. 冲突:冲突字段

Conflicts 冲突 字段指示不能与其共存的其它软件包。最常见的理由是两个软件包使用相同的名称,或在同个 TCP 端口提供相同的服务,或会隐藏彼此的运作。

dpkg 不会安装冲突的软件包,除非新软件包指明 “取代” 被冲突的软件包,dpkg 才会以新的软件包取代旧的软件包。apt 总是遵循您的指示:若选择安装新软件包,则自动移除造成问题的旧软件包。

5.2.1.3. 不相容性:中断字段

中断 Breaks 字段有一个影响和冲突字段类似,但它具有特殊的意义。它标志着一个包的安装会将另外一个包(或者是特定版本)中断掉。通常而言,两个包之间的不兼容是短暂的,中断关系会特别指出那些不兼容的版本。

已经中断现有软件包时,dpkg 将拒绝安装并且 apt 将更新软件包至新的版本试图解决此问题 (通常可解决此问题,并再度兼容)。

不向后兼容的更新可能会发生这种情况:如果新版本与旧版本的功能不在另一个程序中做特别规定,这将导致故障。中断字段会防止用户继续运行从而遇到这些问题。

5.2.1.4. 预备好的条目:预备字段

这个字段引入了一个很有意思的“虚拟包”的概念。它有很多的角色,但有两个特别重要。第一个是由使用虚拟包关联到的一个通用的服务(包“预备”了这些服务)。第二个表示一个包完全取代了另外一个,所以它也能满足依赖性要求。因此,可以创建一个替换而不必使用相同的包名称的包。

VOCABULARY元软件包和虚拟包

这里必须明确的从虚拟软件包里面区分出元软件包。元软件包是真实的元件包(包含真实的.deb文件),其唯一目的是用来表示依赖性关系。

然而,虚拟软件包并未真实的存在;只是依照通用、逻辑范围 (提供的服务、兼容于标准程序或已存在的软件包等) 辨认真实软件包的手段。

5.2.1.4.1. 提供一个“服务”

让我们以范例详述第一个案子:postfix 或 sendmail 之类的邮件服务器都 “提供” mail-transport-agent 虚拟软件包。因此需要启用该等服务的软件包 (如:smartlist 或 sympa 之类的邮件列表管理器) 只要在其相依性里叙明需要 mail-transport-agent 而不是指明还不兼容的可能解决方案清单 (如 postfix | sendmail | exim4 | …)。更进一步来说,在同个机器安装两个邮件服务器是没有用的,因此每个软件包都声明与 mail-transport-agent 虚拟软件包冲突。系统忽略冲突的两个软件包,但技术上可以禁止同时安装两个邮件服务器。

DEBIAN 政策 虚拟软件包列表

使用虚拟软件包时,每个人都必须同意其名称。这就是在 Debian 政策内把他们标准化的原因。此清单包括邮件服务器 mail-transport-agent、C 语言编译器 c-compiler、网页浏览器 www-browser、网页服务器 httpd、FTP 服务器 ftp-server、图形模式终端机仿真器 x-terminal-emulator (xterm)、以及窗口管理器 x-window-manager。

完整清单参见网站。

http://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt

5.2.1.4.2. 和另一个软件包的可交互性

软件包内容被置于另个较大的软件包内时,Provides 字段就很有意思。例如,libdigest-md5-perl Perl 模块是 Perl 5.6 的选项之一,已被集成入标准的 Perl 5.8 (及其以后的版本,如 5.20 并纳入 Jessie)。所以,软件包 perl 5.8 版之后已被声明 Provides: libdigest-md5-perl 所以只要使用 Perl 5.8 (或更新版) 就已满足其相依性。libdigest-md5-perl 软件包本身早就被删除,因为移除 Perl 旧版之后就没有任何意义。

使用了预备字段来避免中断依赖性关系

图 5.1. 使用了预备字段来避免中断依赖性关系

这个功能非常有用,因为它是永远不可能预料到变化莫测的发展,它不能够调整重命名,或者其他自动替换过的软件,所以它是必要的。

回到基本Perl,一种编程语言

Perl(实用报表提取语言)是非常受欢迎的编程语言。它有许多现成的模块,涵盖了广阔的应用,这些都是由 CPAN(Comprehensive Perl Archive Network,Perl 综合架构网络)提供服务的,CPAN 是一个全面的提供 Perl 软件包的网络。

http://www.perl.org/

http://www.cpan.org/

由于它是一种解释型语言,Perl 语言编写的程序并不需要在执行之前进行编译。这就是大家称其为“Perl 脚本”的原因。

5.2.1.4.3. 过去的限制

虚拟软件包曾有很多限制,最麻烦的是没有版本编号。从上例可知,这种 Depends: libdigest-md5-perl (>= 1.6) 相依性,尽管在 Perl 5.10 里存在,但包管理系统仍认为不满足其相依性 — 虽然实际上已满足了。但是包管理系统不知道相依性没问题,只好选择风险最小的做法,假设其版本是不匹配的。

该限制已经在 dpkg 1.17.11 中解除,在 Jessie 中不再相关。软件包可以给提供依赖的虚拟包指定一个版本,如 Provides: libdigest-md5-perl (= 1.8)

5.2.1.5. 替换文件:替换字段

Replaces 字段指出在其他软件包的文件,但该软件包也合理地取代他们。如果没有指明,dpkg 失败,说明它不能覆写另个软件包的文件 (技术上来说,虽可以强迫使用 --force-overwrite 选项,但这不是标准选项)。因此在加入该字段之前,先允许维护者确认潜在可能的问题,并要求维护者先研究它。

当软件包名称变更时,或者当一个软件包包含在另外一个的时候,此字段的使用是合理的。这也发生在维护者决定从来自相同的源码包的大量二进制包里分发出文件:一个替换的文件不再属于旧的软件包,只有新的才属于。

如果已安装软件包的所有文件都被替换了,那么该软件包将认为将被删除掉。最后,这个字段会鼓励dpkg命令去删除替换掉有冲突的包。

更进一步标签字段

以上述的 apt 为例,还有一个字段未说明,Tag 字段。此字段不是说明软件包的关系,而是把软件包分类。根据若干属性 (接口类型、编程语言、应用范围等) 来分类。尽管如此,并非每个软件包都有精准的标签且未融入所有的 Debian 工具;aptitude 显示该等标签,且可以被搜索。未被 aptitude 搜索的范围,可使用以下的网站浏览标签数据库:

http://debtags.alioth.debian.org/

5.2.2. 配置脚本

除了控制文件之外,每个Debian软件包可能在control.tar.gz的存档中包含了一些脚本,这些脚本在软件包处理的不同的阶段被dpkg调用。Debian政策描述了一些可能的细节,在可能的情况下,指定脚本调用它们所收到的参数。这些顺序可能比较复杂,因为如果脚本中任何一步出现问题的时候,dpkg进程会通过取消安装或者卸载来尝试恢复到一个令人满意的状态(只要是可能的)。

进一步 dpkg 的数据库

所有已安装的软件包的配置脚本都存在/var/lib/dpkg/info/目录,在软件包的名字前会有一个文件名的前缀。此目录的每个软件包还包括一个叫.list的文件扩展,包括列表的文件字段属于哪些包。

/var/lib/dpkg/status文件包含了一些数据块(著名的邮件标题的格式,RFC2822)描述了每个软件包的状态。已经安装的软件包的 control 文件中的信息也会被复制到这里。

在一般情况下,preinst脚本会在安装软件包前执行,而postinst会稍候执行。同样,prerm会在移除一个软件包的之前被调用,postrm 则随后执行。更新软件包相当于是清除掉以前的旧版本并且安装新的软件包。所以在这里我们不可能来详细描述所有的可能的方案,但我们将讨论最常见的两种:安装/更新和移除。

小心 脚本的符号名称

本节中使用特定的名称序列命名配置脚本,例如 old-prermnew-postinst。它们分别是旧版本软件包( 在更新前已安装)中包含的 prerm脚本和新版本软件包(由本次更新所安装)中包含的 postinst 脚本。

提示状态图

Manoj Srivastava 以图解释这些配置脚本被 dpkg 调用的情况。Debian 女子计划也有类似的图;容易了解,略为不够完整。

https://people.debian.org/~srivasta/MaintainerScripts.html

https://wiki.debian.org/MaintainerScripts

5.2.2.1. 安装和升级

这里告诉你,安装的时候发生了什么(或者是更新)

  1. 对于升级,dpkg会调用old-prerm 升级 *新版本*.

  2. 还是对于升级,dpkg执行new-preinst 升级 *旧版本*;对于第一个安装,它会执行 new-preinst 安装。它可能会增加旧版本的最后一个参数,如果软件包已经被安装或者是删除了(但没有清除合并掉旧版本,那么这个配置文件会被保留)。

  3. 新的软件包文件被解压。如果文件已经存在,就被会替换,同时会产生一个临时的备份副本。

  4. 对于更新,dpkg执行old-postrm 升级 *新版本*

  5. dpkg更新所有的内部数据(文件列表,配置脚本等),并删除被替换文件的备份。这是一条不归路: ) dpkg将不能够再访问回退到之前状态所需要的所有元素。

  6. dpkg 将更新配置文件,无法自动管理此工作时,要求用户做决定。详情在此 第 5.2.3 节 “校验,配置文件列表”

  7. 最后,dpkg 通过执行 new-postinst configure *最近一次配置的版本号* 对软件包进行配置。

5.2.2.2. 软件包移除

这里是当移除一个软件包的时候发生了什么:

  1. dpkg 调用prerm 移除

  2. dpkg 移除了所有的软件包文件,只剩下了配置文件和配置的脚本。

  3. dpkg 运行 postrm remove。移除所有配置脚本,保留 postrm。若用户未选择 “清除” 选项,则工作完成。

  4. 对于一个完整的清除包(由dpkg --purgedpkg -P发出的),配置文件也将会被删除,同时一些副本(*.dpkg-tmp,*.dpkg-old,*.dpkg-new)和缓存文件也会被删除掉;dpkg这时会执行postrm purge

术语 Purge,完全移除

当Debian的软件包被移除掉的时候,该软件包的配置文件会被保留下来以便重新安装。同样,守护程序产生的数据(比如LDAP的服务器目录内容,或者是SQL服务器的数据库内容)也常常会被保留。

移除掉软件包所关联的所有数据,必须使用“purge”命令,dpkg -P*软件包*apt-get remove --purge *软件包* 或者是aptitude purge *软件包*

移除该等数据,不能掉以轻心去清除。

config 脚本补充前述的 4 个脚本,软件包以 debconf 取得配置用的信息。安装过程中,此脚本以 debconf 指令询问用户详细的问题。把回应记录在 debconf 数据库供未来的参考。在安装之前先由 apt 逐一运行该等脚本,归纳问题与回答。事前与事后安装脚本可使用该等信息回应用户的期望。

工具 debconf

debconf 用于解决在 Debian 安装过程中不断出现的问题询问。如果没有一个最小的配置,所有 Debian 软件包都不具备功能,这个最小配置需要通过调用 postinst shell 脚本 (和其它类似脚本) 里的 echoread 命令来询问。也就是说在大型安装或升级过程里,用户必须在电脑旁回应这些随时出现的问题。感谢 debconf 工具的出现,这些人工交互几乎全部免除了。

debconf 包括很多有趣的功能:要求开发者指明用户的交互;允许本地化显示给用户的字符串 (描述交互的所有翻译保存在 templates 文件);显示给用户的前端问题 (文本模式、图形模式、非交互式);把回应集中在数据库供其他电脑使用 … 但最重要的已可把所有问题,在安装或升级之前,以一列的模式显示给用户。用户可以放任系统自行安装,不必待在电脑旁,紧盯屏幕等待问题。

5.2.3. 校验,配置文件列表

除了稍早提过的维护者脚本与控制数据外,在 Debian 软件包内的 control.tar.gz 可能包括若干有趣的文件。首先,md5sums,包括软件包内所有文件的 MD5 校验。它的优点是允许 dpkg --verify (详情见 第 14.3.3.1 节 “Auditing Packages with dpkg --verify) 检查该等文件在安装后是否被修改。若此文件不存在,dpkg 将在安装时动态产生一个 (并且如同其他控制文件般保存在 dpkg 数据库)。

conffiles 列出必须当配置文件处理的软件包文件。管理员可修改配置文件,升级软件包时 dpkg 将保留这些变动。

实际上,在这种情况下,dpkg的行为会尽可能地智能:如果两个版本之间并没有改变标准的配置文件,那么dpkg就什么也不会作。但是,如果文件已经被修改,它会尝试更新此文件。这会产生两种可能的情况:一是管理员没有碰配置文件,在这种情况下dpkg会自动安装新版本;二是文件已经被修改了,在这种情况下dpkg会询问管理员希望使用哪个版本(旧版本或者新的)。为了帮助用户作出选择,dpkg会提供“差异”,这会显示两个版本之间的差异。如果用户选择保留旧的版本,新的将被存储在文件夹的同一个位置并以.dpkg-dist为后缀名的文件中。另外一个可能的操作是由暂时中断的dpkg来编辑该文件,并试图重新恢复相关的修改(之前被验证的差异)。

更进一步 避免配置文件问题

dpkg 处理配置文件升级,但经常中断作业,要求管理者键入数据。如此一来,就不能以无中断方式一气呵成升级作业。此指令提供选项让系统依同样的逻辑自动回应:--force-confold 保留该文件的旧版本;--force-confnew 使用该文件的新版本 (即使该文件未被管理者修改,仍使用指定的选择,极少发生问题)。加入 --force-confdef 选项告诉 dpkg 在可能情况下自行决定 (换句话说,不改变原配置文件),只在其他的情况下,才使用 --force-confnew--force-confold

这些选项使用 dpkg,但是大多数时间管理员会直接用 aptitudeapt-get。实际上,有必要知道 dpkg 的语法参数来使用dpkg命令(命令行的界面是非常相似的)。

  1. #

此选项可直接保存在 apt 的配置内。只需把下列这行字写入 /etc/apt/apt.conf.d/local 文件内:

  1. DPkg::options { "--force-confdef"; "--force-confold"; }

把此选项纳入配置文件,意味着 aptitude 之类的图形接口程序也会使用这些选项。

更进一步 强制 dpkg 询问配置文件问题

--force-confask 选项要求 dpkg 显示有关配置文件的问题,即使不是必要的问题也需显示。因此,以此选项重新安装软件包时,dpkg 将再询管理者修改过的配置文件问题。这种方式极为便利,尤其是重新安装已经被删除且无可用复本的原始配置文件:普通的重新安装无效,因为 dpkg 认为移除是合法的修改,因此不会安装预期的配置文件。