5.2. 软件包元信息

The Debian package is not only an archive of files intended for installation. It is part of a larger whole and describes its relationship with other Debian packages (requisites, dependencies, conflicts, suggestions). It also provides scripts that enable the execution of commands at different stages in the package’s lifecycle (installation, upgrade, removal). These data are used by the package management tools but are not part of the packaged software; they are, within the package, what is called its “meta-information” (information about other information).

5.2.1. 描述:control 文件

This file uses a structure similar to email headers (as defined by RFC 2822) and is fully described in the Debian Policy and the manual pages deb-control(5) and deb822(5).

https://www.debian.org/doc/debian-policy/ch-controlfields.html

For example, for apt, the control file looks like the following:

  1. $

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

RFC is the abbreviation of “Request For Comments”. An RFC is generally a technical document that describes what will become an Internet standard. Before becoming standardized and frozen, these standards are submitted for public review (hence their name). The IETF (Internet Engineering Task Force) decides on the evolution of the status of these documents (proposed standard, draft standard, or standard).

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

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

5.2.1.1. 依赖:Depends 域

The dependencies are defined in the Depends field in the package header. It is a list of conditions to be met for the package to work correctly. This information is used by tools such as apt in order to install the required libraries, tools, drivers, etc. in appropriate versions fulfilling the dependencies of the package to be installed. For each dependency, it is possible to restrict the range of versions that meet that condition. In other words, it is possible to express the fact that we need the package libc6 in a version equal to or greater than “2.15” (written “libc6 (>= 2.15)”). Version comparison operators are as follows:

  • <<:小于;

  • <=:小于或等于;

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

  • >=:大于或等于;

  • >>:大于。

In a list of conditions to be met, the comma serves as a separator. It must be interpreted as a logical “and”. In conditions, the vertical bar (“|”) expresses a logical “or” (it is an inclusive “or”, not an exclusive “either/or”). Carrying greater priority than “and”, it can be used as many times as necessary. Thus, the dependency “(A or B) and C” is written A | B, C. In contrast, the expression “A or (B and C)” should be written as “(A or B) and (A or C)”, since the Depends field does not tolerate parentheses that change the order of priorities between the logical operators “or” and “and”. It would thus be written A | B, A | C.

https://www.debian.org/doc/debian-policy/#document-ch-relationships

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

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

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

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

DEBIAN 政策 推荐建议增强

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

You should always install the “recommended” packages, unless you know exactly why you do not need them. This is now also the default for APT unless configured otherwise. Conversely, it is not necessary to install “suggested” packages unless you know why you need them. The behavior of apt can be controlled by using the APT::Install-Recommends and APT::Install-Suggests configuration options or the corresponding command line options --[no-]install-recommends and --[no-]install-suggests.

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

5.2.1.2. 冲突:冲突字段

The Conflicts field indicates when a package cannot be installed simultaneously with another. The most common reasons for this are that both packages include a file of the same name and path, or provide the same service on the same TCP port, or would hinder each other’s operation.

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. 和另一个软件包的可交互性

The Provides field is also interesting when the content of a package is included in a larger package. For example, the libdigest-md5-perl Perl module was an optional module in Perl 5.6, and has been integrated as standard in Perl 5.8 (and later versions, such as 5.28 present in Buster). As such, the package perl has since version 5.8 declared Provides: libdigest-md5-perl so that the dependencies on this package are met if the user has Perl 5.8 (or newer). The libdigest-md5-perl package itself has eventually been deleted, since it no longer had any purpose when old Perl versions were removed.

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

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

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

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

Perl (Practical Extraction and Report Language) is a very popular programming language. It has many ready-to-use modules that cover a vast spectrum of applications, and that are distributed by the CPAN (Comprehensive Perl Archive Network) servers, an exhaustive network of Perl packages.

https://www.perl.org/

https://www.cpan.org/

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

5.2.1.4.3. 过去的限制

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

This limitation has been lifted in dpkg 1.17.11, and is no longer relevant. Packages can assign a version to the virtual packages they provide with a dependency such as Provides: libdigest-md5-perl (= 1.8).

5.2.1.5. 替换文件:替换字段

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

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

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

更进一步标签字段

In the apt example above, we can see the presence of a field that we have not yet described, the Tag field. This field does not describe a relationship between packages, but is simply a way of categorizing a package in a thematic taxonomy. This classification of packages according to several criteria (type of interface, programming language, domain of application, etc.) has been available for a long time. Despite this, not all packages have accurate tags and it is not yet integrated in all Debian tools; aptitude displays these tags, and allows them to be used as search criteria. For those who are repelled by aptitude‘s search criteria, the following website allows navigation of the tag database:

https://wiki.debian.org/Debtags

5.2.2. 配置脚本

In addition to the control file, the control.tar.gz archive for each Debian package may contain a number of scripts, called by dpkg at different stages in the processing of a package. The Debian Policy describes the possible cases in detail, specifying the scripts called and the arguments that they receive. These sequences may be complicated, since if one of the scripts fails, dpkg will try to return to a satisfactory state by canceling the installation or removal in progress (insofar as it is possible).

进一步 dpkg 的数据库

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

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

In general, the preinst script is executed prior to installation of the package, while postinst follows it. Likewise, prerm is invoked before removal of a package and postrm afterwards. An update of a package is equivalent to removal of the previous version and installation of the new one. It is not possible to describe in detail all the possible scenarios here, but we will discuss the most common two: an installation/update and a removal.

小心 脚本的符号名称

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

提示状态图

Manoj Srivastava and Margarita Manterola made the following diagrams explaining how the configuration scripts are called by dpkg.

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

https://www.debian.org/doc/debian-policy/ap-flowcharts.html

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. 校验,配置文件列表

In addition to the maintainer scripts and control data already mentioned in the previous sections, the control.tar.gz archive of a Debian package may contain other interesting files. The first, md5sums, contains the MD5 checksums for all of the package’s files. Its main advantage is that it allows dpkg --verify (which we will study in 第 14.3.4.1 节 “Auditing Packages with dpkg --verify) and debsums (from the package of the same name; see 第 14.3.4.2 节 “审核软件包:debsums 及其限制”) to check if these files have been modified since their installation. Note that when this file doesn’t exist, dpkg will generate it dynamically at installation time (and store it in the dpkg database just like other control files).

conffiles lists package files that must be handled as configuration files (see also deb-conffiles(5)). Configuration files can be modified by the administrator, and dpkg will try to preserve those changes during a package update.

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

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

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

These options apply to dpkg and are explained in detail in dpkg(1) or dpkg --force-help, but most of the time the administrator will work directly with the aptitude or apt programs. It is, thus, necessary to know the syntax used to indicate the options to pass to the dpkg command (their command line interfaces are very similar).

  1. #

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

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

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

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

The --force-confask option requires dpkg to display the questions about the configuration files, even in cases where they would not normally be necessary. Thus, when reinstalling a package with this option, dpkg will ask the questions again for all of the configuration files modified or deleted by the administrator. This is very convenient, especially for reinstalling the original configuration file if it has been deleted and no other copy is available: a normal re-installation won’t work, because dpkg considers removal as a form of legitimate modification, and, thus, doesn’t install the desired configuration file.