LabHub
学习 学习路径 课程

包管理

dpkg 不解依赖图

在 LabHub 中继续学习

一句话总结

apt 是决定安装什么的工具,dpkg 是执行既定安装的工具。理解这种分工,就能立刻明白 dpkg -i 为什么会因依赖错误而停止。

概念图: 决定安装什么的工具 · 执行既定安装的工具 · 解开给定文件;如果依赖不满足,就把软件包留在“未配置”状态 · unpack → configure

为什么需要这些知识

下载一个 .deb 文件并用 dpkg -i 安装,会看到这样的消息。

dpkg: dependency problems prevent configuration of labhub-extra:
 labhub-extra depends on labhub-tool (>= 1.2.0); however:
  Package labhub-tool is not installed.

dpkg 不知道软件仓库,也不知道应从哪里下载什么。它只会解开给定文件;如果依赖不满足,就把软件包留在“未配置”状态。因此,apt-get -f install(fix broken)会与它配套使用,含义是“让 apt 查看仓库,继续解决 dpkg 留下的未完成状态”。

它是如何运作的

.deb 文件实际上是一个 ar archive,其中包含三个部分。

部分 内容
debian-binary 格式版本,通常为 2.0
control.tar.* control 文件、维护脚本(preinst/postinst/prerm/postrm)、conffilesmd5sums
data.tar.* 实际要解压到文件系统的文件

安装分为 unpack → configure 两个阶段。unpack 负责解开 data,configure 则执行 postinst,完成注册服务等收尾工作。dpkg -l 输出开头的两个字符表示这种状态。

标记 含义
ii 请求安装 + 安装完成,状态正常
iU 请求安装 + 只完成 unpack,configure 失败
rc 请求删除 + 仅保留配置文件
pn 未安装,已经 purge

人们经常忽略 rc 状态。“明明删除了,为什么配置还在?”答案就在这里。

dpkg 的查询命令分为三个方向。

dpkg -l                       # 무엇이 설치돼 있나
dpkg -L coreutils             # 이 패키지가 어떤 파일을 깔았나
dpkg -S /usr/bin/ls           # 이 파일은 누가 깔았나
dpkg -s coreutils             # 이 패키지의 메타데이터는 무엇인가
dpkg-query -W -f='${Package} ${Version}\n'

第三种(-S)在实际工作中最常使用。在陌生服务器上发现不明 binary 时,它能在一秒内区分该文件是由软件包安装,还是有人手动放置。如果 dpkg -S 找不到任何结果,说明该文件不受包管理;这类文件升级时不会消失,也很容易不在备份范围内。

在实际工作中会是什么样

配置文件冲突。 upgrade 过程中出现 Configuration file '/etc/foo.conf' ... What would you like to do? 提示。dpkg 会记住登记在 conffiles 中的文件 md5,因此能判断是否被人工修改。如果在提示中随意选择“package maintainer's version”,手工加入的全部调优都会消失。自动化脚本应通过 -o Dpkg::Options::="--force-confold" 明确指定策略。

配置文件会受到特殊处理

.deb 中登记于 conffiles 的文件,适用与其他文件不同的规则。不了解这些规则,更新后可能遇到配置消失,或相反地发现新配置没有生效,而二者原因相同。

更新时,dpkg 会比较三项内容:软件包最初安装的内容当前磁盘中的内容,以及新软件包准备安装的内容

第三种情况正是问题所在。自动更新时无人看到这个问题,因此,服务会在我们的旧文件缺少新版本所需配置项的状态下继续运行。 它会悄然采用默认值,日后才表现为异常症状。因此,更新后需要检查是否出现 .dpkg-dist.dpkg-new.ucf-dist 文件。

rc 状态与配置文件的关系也可由此解释。如前所述,删除软件包后配置仍然存在,是因为 remove 不处理 conffiles,只有 purge 会一并删除。因此,重新安装同一软件包时,旧配置会再次生效,“明明干净重装,为什么还是同样的问题?”就源于此。

最后,如果打算在软件包之外管理配置文件,最好一开始就使用不在 conffiles 中的独立文件。大多数软件包提供 conf.d/ 之类目录,原因就在这里。该目录中的文件不属于软件包,因此更新不会修改,也不会触发三方比较。

下一次实操要做什么

你将使用 dpkg -L/-S/-s 查询系统,并在 fixture 目录中亲手构建 .deb 文件再完成安装。亲自制作软件包,就能确切理解其中包含什么。