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.
本文件使用的结构与email头相似(如由
RFC 2822 定义的),并且在 Debian 政策和手册页面
deb-control(5) 和
deb822(5) 中充分描述。
例如,对于 apt 软件包,control
文件看起来像这样:
$
apt-cache show apt
Package: apt
Version: 2.2.4
Installed-Size: 4337
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~)
Provides: apt-transport-https (= 2.2.4)
Depends: adduser, gpgv | gpgv2 | gpgv1, libapt-pkg6.0 (>= 2.2.4), debian-archive-keyring, libc6 (>= 2.15), libgcc-s1 (>= 3.0), libgnutls30 (>= 3.7.0), libseccomp2 (>= 2.4.2), libstdc++6 (>= 9), libsystemd0
Recommends: ca-certificates
Suggests: apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), gnupg | gnupg2 | gnupg1, powermgmt-base
Breaks: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~), aptitude (<< 0.8.10)
Description-en: commandline package manager
This package provides commandline tools for searching and
managing as well as querying information about packages
as a low-level access to all features of the libapt-pkg library.
.
These include:
* apt-get for retrieval of packages and information about them
from authenticated sources and for installation, upgrade and
removal of packages together with their dependencies
* apt-cache for querying available information about installed
as well as installable packages
* apt-cdrom to use removable media as a source for packages
* apt-config as an interface to the configuration settings
* apt-key as an interface to manage authentication keys
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, devel::lang:ruby, hardware::storage,
hardware::storage:cd, implemented-in::c++, implemented-in::perl,
implemented-in::ruby, interface::commandline, network::client,
protocol::ftp, protocol::http, protocol::ipv6, role::program,
scope::application, scope::utility, suite::debian, use::downloading,
use::organizing, use::playing, use::searching, works-with-format::html,
works-with::audio, works-with::software:package, works-with::text
Section: admin
Priority: required
Filename: pool/main/a/apt/apt_2.2.4_amd64.deb
Size: 1491328
MD5sum: 24d53e8dd75095640a167f40476c0442
SHA256: 75f07c4965ff0813f26623a1164e162538f5e94defba6961347527ed71bc4f3d
我们来看看上一条命令列出来的部分字段的含义。
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:
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
.
The dependencies system is a good mechanism for guaranteeing the operation of a program, but it has another use with “meta-packages”. These are empty packages that only describe dependencies. They facilitate the installation of a consistent group of programs pre-selected by the meta-package maintainer; as such, apt install meta-package
will automatically install all of these programs using the meta-package's dependencies. The gnome, kde-full and linux-image-amd64 packages are examples of meta-packages.
Conflicts(冲突)
字段指示不能与其共存的其它软件包。最常见的理由是两个软件包使用具有相同的名称和路径的文件,或在相同的 TCP 端口提供相同的服务,或会阻碍彼此的操作。
dpkg
不会安装冲突的软件包,除非新软件包指明 “取代” 被冲突的软件包,dpkg
才会以新的软件包取代旧的软件包。apt
总是遵循您的指示:若选择安装新软件包,则自动移除造成问题的旧软件包。
中断 Breaks
字段有一个影响和冲突
字段类似,但它具有特殊的意义。它标志着一个包的安装会将另外一个包(或者是特定版本)中断掉。通常而言,两个包之间的不兼容是短暂的,中断
关系会特别指出那些不兼容的版本。
已经中断现有软件包时,dpkg
将拒绝安装并且 apt
将更新软件包至新的版本试图解决此问题 (通常可解决此问题,并再度兼容)。
不向后兼容的更新可能会发生这种情况:如果新版本与旧版本的功能不在另一个程序中做特别规定,这将导致故障。中断
字段会防止用户继续运行从而遇到这些问题。
这个字段引入了一个很有意思的“虚拟包”的概念。它有很多的角色,但有两个特别重要。第一个是由使用虚拟包关联到的一个通用的服务(包“提供”了这些服务)。第二个表示一个包完全取代了另外一个,所以它也能满足依赖的要求。因此,可以创建一个替换而不必使用相同的包名称的包。
让我们以范例详述第一个案子:postfix 或 sendmail 之类的邮件服务器都 “提供” mail-transport-agent 虚拟软件包。因此需要启用该等服务的软件包 (如:smartlist 或 sympa 之类的邮件列表管理器) 只要在其相依性里叙明需要 mail-transport-agent 而不是指明还不兼容的可能解决方案清单 (如 postfix | sendmail | exim4 | …
)。更进一步来说,在同个机器安装两个邮件服务器是没有用的,因此每个软件包都声明与 mail-transport-agent 虚拟软件包冲突。系统忽略冲突的两个软件包,但技术上可以禁止同时安装两个邮件服务器。
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.32.1 present in Bullseye). 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.
这个功能非常有用,因为它是永远不可能预料到变化莫测的发展,它不能够调整重命名,或者其他自动替换过的软件,所以它是必要的。
Virtual packages used to suffer from some limitations, the most significant of which was the absence of a version number. To return to the previous example, a dependency such as Depends: libdigest-md5-perl (>= 1.6)
, despite the presence of Perl 5.10, would have never been considered as satisfied by the packaging system — while in fact it most likely was satisfied. Unaware of this, the package system chose the least risky option, assuming that the versions do not match.
This limitation has been lifted in dpkg 1.17.11, and is no longer relevant. Packages, like perl 5.32.1, can assign a version to the virtual packages they provide, such as Provides: libdigest-md5-perl (= 2.55.01)
, and thus allow other packages to use versioned dependencies.
The Replaces
field indicates that the package contains files that are also present in another package, but that the package is legitimately entitled to replace them. Without this specification, dpkg
fails to install the package, stating that it cannot overwrite the files of another package (technically, it is possible to force it to do so with the --force-overwrite
option, but that is not considered standard operation). This allows identification of potential problems and requires the maintainer to study the matter prior to choosing whether to add such a field.
当软件包名称变更时,或者当一个软件包包含在另外一个的时候,此字段的使用是合理的。这也发生在维护者决定从来自相同的源码包的大量二进制包里分发出文件:一个替换的文件不再属于旧的软件包,只有新的才属于。
如果已安装软件包的所有文件都被替换了,那么该软件包将认为将被删除掉。最后,这个字段会鼓励dpkg
命令去删除替换掉有冲突的包。
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).
在一般情况下,preinst
脚本会在安装软件包前执行,而postinst
会稍后执行。同样,prerm
会在移除一个软件包的之前被调用,postrm
则随后执行。更新软件包相当于是清除掉以前的旧版本并且安装新的软件包。所以在这里我们不可能来详细描述所有的可能的方案,但我们将讨论最常见的两种:安装/更新和移除。
在软件包的初始安装和其后续的每次升级时,dpkg
都会调用所谓的维护者脚本,例如prerm
或者preinst
脚本。在软件包生命周期的不同阶段,这些脚本可以执行一些额外的操作。前缀为new-
的脚本来自软件包正在安装或升级到的那个新版本。前缀为old-
的脚本来自软件包正在被升级的那个旧版本。
每次调用中,dpkg
都会向每个脚本传递参数,例如 upgrade new-version
。然后,被调用的脚本可以处理这些参数并执行特定操作;或者,如果在该步骤中没有需要执行的操作,就忽略这些参数并以退出代码0
返回。实践中,许多软件包在生命周期的每个步骤中都不需要执行操作。因此,典型的配置脚本检查特定的单个参数并忽略所有其他参数,隐式地以退出代码0
返回。
以下是安装(或更新)时的情况。 old-version、new-version和last-version-configured参数是实际软件包(旧版和新版)的版本号的占位符:
For an update, dpkg
calls the old-prerm
script and passes upgrade new-version
as arguments.
Still for an update, dpkg
then executes the new-preinst
script with the arguments upgrade old-version
; for the initial installation, it executes the new-preinst
script and passes install
as argument. It may add the old version in the last parameter, if the package has already been installed and removed since (but not purged, and thus configuration files have been retained).
新的软件包文件被解压。如果文件已经存在,就被会替换,同时会产生一个临时的备份副本。
For an update, dpkg
executes the old-postrm
script and passes upgrade new-version
as arguments.
dpkg
更新所有的内部数据(文件列表,配置脚本等),并删除被替换文件的备份。这是一条不归路: ) dpkg
将不能够再访问回退到之前状态所需要的所有元素。
Finally, dpkg
configures the package by executing the new-postinst
script with the arguments configure last-version-configured
.
卸载软件包的步骤和安装类似。主要区别在于这里调用的是软件包的卸载脚本:
dpkg
calls the prerm
script and passes the remove
argument.
dpkg
removes all of the package's files, with the exception of the configuration files and maintainer scripts.
dpkg
executes the postrm
script and passes remove
as argument. Afterwards, all of the maintainer scripts, except the postrm
script, are removed. If the user has not used the “purge” option, the process stops here.
For a complete purge of the package (command issued with dpkg --purge
or dpkg -P
), the configuration files are also deleted, as well as a certain number of copies (*.dpkg-tmp
, *.dpkg-old
, *.dpkg-new
) and temporary files; dpkg
then executes the postrm
script and passes purge
as argument.
config
脚本补充前述的 4 个脚本,软件包以 debconf
取得配置用的信息。安装过程中,此脚本以 debconf
指令询问用户详细的问题。把回应记录在 debconf
数据库供未来的参考。在安装之前先由 apt
逐一运行该等脚本,归纳问题与回答。事前与事后安装脚本可使用该等信息回应用户的期望。
5.2.3. Checksums, List of Configuration Files, et al.
除了前面提到的维护者脚本和控制数据之外,Debian软件包的control.tar.gz
压缩包可能包含其他有趣的文件。
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 节 “用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, which might be the case for some older packages,
dpkg
will generate it dynamically at installation time (and store it in the dpkg database just like other control files).
The file 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
会提供显示 “diff
”,这会显示两个版本之间的差异。如果用户选择旧版本,那么新版本将被存储在文件夹的同一个位置并以 .dpkg-dist
为后缀名的文件中。如果用户选择新版本,那么旧版本将被保留在以 .dpkg-old
为后缀名的文件中。另外一个可能的操作是由暂时中断 dpkg
来编辑该文件,并试图重新恢复相关的修改(之前用 diff
来识别)。
控制压缩包通常也包含其他文件,例如triggers
、shlibs
或symbols
。这些文件在deb-triggers(5)、deb-shlibs(5)和deb-symbols(5)中有很好的描述。
shlibs
系统可以代替共享库声明依赖项的symbols
系统,它更旧、更简单。它定义软件包名称和版本,其可用于查找共享库的特定SONAME版本。而新的symbols
系统定义依赖项的方式则是跟踪库中引入或更改符号的时间。