Deb 包(Debian 软件包)是一种用于在 Debian 及其衍生发行版(例如 Ubuntu)中分发和安装软件的标准包装格式。它们构成了 Debian Linux 发行版中的软件包管理系统的核心组成部分,旨在简化软件的分发、安装、更新和卸载流程。在本篇文章中,我们将深入探讨以下内容:
Deb 包基础知识:我们将介绍 Deb 包的基本概念,包括其结构、元数据和工作原理。您将了解如何识别、查找和理解 Deb 包,以及它们在系统中的重要性。
Deb 包制作:我们将详细讨论如何创建自定义的 Deb 软件包。这包括将您的应用程序打包为 Deb 包、定义软件包的依赖性、添加配置文件以及遵循 Debian 软件包制作的最佳实践。
Deb 包后续处理:一旦软件包被安装,我们将研究 Deb 包的后续处理。这包括管理已安装软件包的更新、卸载不再需要的软件包以及处理依赖性。
通过本文,您将深入了解 Deb 包的内部工作方式,并学会创建和管理它们,这对于在 Debian 及其相关发行版上进行软件分发和定制至关重要。
deb 文件是一个 Unix ar Archive 格式的文件,在 Linux 环境中,使用 ar命令可以查看 deb 所打包的具体内容,下面以tcpdump为例看一下
- apt download tcpdump
- 下载tcpdump_4.99.0-2+deb11u1_arm64.deb
- ar -t tcpdump_4.99.0-2+deb11u1_arm64.deb
- debian-binary
- control.tar.xz
- data.tar.xz
很久很久以前,Linux 默认使用 gzip 作为压缩选择,所以那时候你会得到 control.tar.gz 这样的文件,但现在都是使用 xz 压缩格式了,它没有额外耗费太多算力的情况下压缩比率有大幅度的提高。gzip 虽然好,但毕竟是行程码风格的压缩算法,即使是对文本文件其压缩比也有限。
是一个文本文件,包含一个版本号戳记,这代表着 deb 文件格式的版本号,它目前通常都是 2.0。
control.tar.xz 是一个 Debian 软件包(.deb 文件)中的一个部分,它包含了软件包的控制信息。这些信息用于在安装、配置和卸载软件包时管理软件包的元数据。这个文件通常包含了一个叫做 control 的目录,其中包含了多个控制文件,这些文件以纯文本的方式描述了软件包的各种属性和依赖关系。
control 文件:这个文件是必需的,它包含了软件包的基本信息,如软件包的名称、版本、作者、描述等。这些信息用于在包管理系统中注册软件包并显示给用户。- Package: tcpdump
- Version: 4.9.3-4ubuntu0.2
- Architecture: amd64
- Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
- Installed-Size: 1088
- Depends: libc6 (>= 2.14), libpcap0.8 (>= 1.5.1), libssl1.1 (>= 1.1.0), adduser
- Suggests: apparmor (>= 2.3)
- Breaks: apparmor-profiles-extra (<< 1.12~)
- Replaces: apparmor-profiles-extra (<< 1.12~)
- Section: net
- Priority: optional
- Multi-Arch: foreign
- Homepage: https://www.tcpdump.org/
- Description: command-line network traffic analyzer
- This program allows you to dump the traffic on a network. tcpdump
- is able to examine IPv4, ICMPv4, IPv6, ICMPv6, UDP, TCP, SNMP, AFS
- BGP, RIP, PIM, DVMRP, IGMP, SMB, OSPF, NFS and many other packet
- types.
- .
- It can be used to print out the headers of packets on a network
- interface, filter packets that match a certain expression. You can
- use this tool to track down network problems, to detect attacks
- or to monitor network activities.
- Original-Maintainer: Romain Francoise <rfrancoise@debian.org>
Package: 软件包的名称,这里是 "tcpdump"。Version: 软件包的版本,这里是 "4.9.3-4ubuntu0.2"。Architecture: 软件包的体系结构,这里是 "amd64",表示适用于 64 位的 x86 架构。Maintainer: 软件包的维护者或发布者的联系信息,这里是 "Ubuntu Developers ubuntu-devel-discuss@lists.ubuntu.com"。Installed-Size: 软件包的安装大小(以 KB 为单位),这里是 1088 KB。Depends: 软件包的依赖关系,指定了安装该软件包所需的其他软件包,包括 "libc6 (>= 2.14)", "libpcap0.8 (>= 1.5.1)", "libssl1.1 (>= 1.1.0)" 和 "adduser"。Suggests: 软件包的建议安装软件包,这里建议安装 "apparmor (>= 2.3)"。Breaks: 当安装这个软件包时,它会破坏 "apparmor-profiles-extra" 版本小于 "1.12~" 的软件包。Replaces: 当安装这个软件包时,它会取代 "apparmor-profiles-extra" 版本小于 "1.12~" 的软件包。Section: 软件包的所属领域,这里是 "net",表示网络相关的软件包。Priority: 软件包的优先级,这里是 "optional",表示是一个可选的软件包。Multi-Arch: 表示软件包支持多体系结构,这里是 "foreign",表示适用于不同的体系结构。Homepage: 软件包的主页或官方网站,这里是 "https://www.tcpdump.org/"。Description: 软件包的描述,提供了软件包的简要说明,功能和用途。Original-Maintainer: 原始的软件包维护者的联系信息,这里是 "Romain Francoise rfrancoise@debian.org"。preinst、postinst、prerm、postrm 文件:这些文件包含了在软件包安装(inst)和卸载(rm)过程中执行的脚本。preinst 脚本通常用于在安装软件包之前执行一些操作,而 postinst 脚本用于安装后的配置。同样,prerm 脚本用于卸载前的操作,而 postrm 脚本用于卸载后的清理。如下为postinst 该脚本通常在 Debian 软件包安装后执行。它包含了一些脚本命令,用于配置软件包的环境和执行必要的操作
- #!/bin/sh -e
-
- if ! getent group tcpdump >/dev/null 2>&1; then
- addgroup --system --quiet tcpdump
- fi
- if ! getent passwd tcpdump >/dev/null 2>&1; then
- adduser --system --quiet --ingroup tcpdump \
- --no-create-home --home /nonexistent \
- tcpdump
- fi
-
- # Automatically added by dh_apparmor/2.13.3-7ubuntu5.2
- if [ "$1" = "configure" ]; then
- APP_PROFILE="/etc/apparmor.d/usr.sbin.tcpdump"
- if [ -f "$APP_PROFILE" ]; then
- # Add the local/ include
- LOCAL_APP_PROFILE="/etc/apparmor.d/local/usr.sbin.tcpdump"
-
- test -e "$LOCAL_APP_PROFILE" || {
- mkdir -p `dirname "$LOCAL_APP_PROFILE"`
- install --mode 644 /dev/null "$LOCAL_APP_PROFILE"
- }
-
- # Reload the profile, including any abstraction updates
- if aa-enabled --quiet 2>/dev/null; then
- apparmor_parser -r -T -W "$APP_PROFILE" || true
- fi
- fi
- fi
- # End automatically added section
#!/bin/sh -e: 这是脚本的 shebang 行,指定了脚本使用的 shell,这里是 /bin/sh,并启用了 -e 标志,表示如果脚本中的任何命令失败,则整个脚本会立即退出。
if ! getent group tcpdump >/dev/null 2>&1; then: 这是一个条件语句,用于检查是否存在名为 "tcpdump" 的用户组。如果不存在,它会使用 addgroup 命令创建一个名为 "tcpdump" 的系统用户组。addgroup 命令用于添加用户组。
if ! getent passwd tcpdump >/dev/null 2>&1; then: 类似于上面的条件语句,这次检查是否存在名为 "tcpdump" 的用户。如果不存在,它会使用 adduser 命令创建一个名为 "tcpdump" 的系统用户,并将其添加到 "tcpdump" 用户组中。此用户不会有家目录(--no-create-home),而其家目录会被设置为 /nonexistent。
接下来,脚本包含了一段用于处理 AppArmor 配置的代码。它检查是否执行了软件包的 "configure" 操作,并且如果存在名为 "/etc/apparmor.d/usr.sbin.tcpdump" 的 AppArmor 配置文件,则将其重新加载。这是通过使用 apparmor_parser 命令来实现的。
如下为postrm 该脚本通常在 Debian 软件包卸载后执行。它包含了一些脚本命令,用于在软件包卸载过程中执行必要的清理和操作
- #!/bin/sh -e
-
- case "$1" in
- purge)
- userdel tcpdump >/dev/null 2>&1 || true
- groupdel tcpdump >/dev/null 2>&1 || true
- ;;
- esac
-
- # Automatically added by dh_apparmor/2.13.3-7ubuntu5.2
- if [ "$1" = "purge" ] && ! [ -e "/etc/apparmor.d/usr.sbin.tcpdump" ] ; then
- rm -f "/etc/apparmor.d/disable/usr.sbin.tcpdump" || true
- rm -f "/etc/apparmor.d/force-complain/usr.sbin.tcpdump" || true
- rm -f "/etc/apparmor.d/local/usr.sbin.tcpdump" || true
- rm -f /var/cache/apparmor/*/"usr.sbin.tcpdump" || true
- rmdir /etc/apparmor.d/disable 2>/dev/null || true
- rmdir /etc/apparmor.d/local 2>/dev/null || true
- rmdir /etc/apparmor.d 2>/dev/null || true
- fi
- # End automatically added section
case "$1" in: 这是一个 case 语句,根据脚本执行时的第一个参数 $1 的值,选择不同的操作。在这个示例中,它检查 $1 的值是否为 "purge",如果是,将执行相应的操作。
purge): 这是一个 case 语句的分支,当 $1 的值为 "purge" 时执行。它用于处理软件包的卸载操作。
userdel tcpdump >/dev/null 2>&1 || true: 这个命令尝试删除名为 "tcpdump" 的用户。如果用户不存在,它将不会报告错误。这是通过 userdel 命令来实现的。
groupdel tcpdump >/dev/null 2>&1 || true: 类似于上面的命令,这次尝试删除名为 "tcpdump" 的用户组。如果用户组不存在,它将不会报告错误。这是通过 groupdel 命令来实现的。
接下来,脚本包含了一段用于处理 AppArmor 配置的代码。它检查是否执行了软件包的 "purge" 操作,并且如果不存在名为 "/etc/apparmor.d/usr.sbin.tcpdump" 的 AppArmor 配置文件,将删除相关的 AppArmor 配置文件和目录。
conffiles 文件:这个文件列出了软件包安装的配置文件,以便在升级软件包时保留用户的自定义配置。md5sums 文件:这个文件包含了软件包中各个文件的校验和,以确保它们在传输和存储过程中没有被篡改。data.tar.xz 是 Debian 软件包(.deb 文件)中的一个部分,它包含了软件包的实际文件和数据。这个文件通常包含了应该安装到系统的二进制文件、库、配置文件和其他资源。data.tar.xz 文件是通过压缩工具(通常是 xz 或其他压缩工具)进行压缩的,以减小软件包的大小并节省带宽。
当你安装一个 Debian 软件包时,系统会解压缩 data.tar.xz 并将其中的文件复制到系统的相应目录中,以完成软件包的安装。这些文件通常包括可执行文件、库文件、配置文件、文档和其他资源,这些资源是软件包的一部分,用于使软件包在系统上正常运行。如下为tcpdump 包的内容
- data
- ├── etc
- │ └── apparmor.d
- │ └── usr.sbin.tcpdump
- └── usr
- ├── sbin
- │ └── tcpdump
- └── share
- ├── doc
- │ └── tcpdump
- │ ├── changelog.Debian.gz
- │ ├── copyright
- │ ├── examples
- │ │ ├── atime.awk
- │ │ ├── packetdat.awk
- │ │ ├── send-ack.awk
- │ │ └── stime.awk
- │ ├── NEWS.Debian.gz
- │ ├── README.Debian
- │ └── README.md.gz
- └── man
- └── man8
- └── tcpdump.8.gz
etc: 这是一个目录,通常包含配置文件。在这个示例中,它包含了一个名为 "apparmor.d" 的子目录,其中可能包含了与 AppArmor 安全配置相关的文件。
apparmor.d: 这是 etc 目录的子目录,包含与 AppArmor 安全配置有关的文件。在这里,有一个名为 "usr.sbin.tcpdump" 的文件,这可能是与软件包 "tcpdump" 相关的 AppArmor 配置文件。usr: 这是一个目录,通常包含与用户相关的文件和数据。
sbin: 这是 usr 目录的子目录,通常包含可执行的系统命令或工具。在这个示例中,有一个名为 "tcpdump" 的文件,这是软件包 "tcpdump" 的可执行文件。
share: 这是 usr 目录的另一个子目录,通常包含共享的数据和文档。
doc: 这是 share 目录的子目录,包含软件包的文档文件。
tcpdump: 这是 doc 目录的子目录,包含了 "tcpdump" 软件包的文档文件。其中包括一些文本文件和压缩的 changelog、README 等文件。man: 这是 share 目录的子目录,通常包含手册页文件。
man8: 这是 man 目录的子目录,包含第 8 节的手册页文件。在这个示例中,有一个名为 "tcpdump.8.gz" 的手册页文件,用于提供关于 "tcpdump" 命令的信息。AppArmor(Application Armor)是一种Linux内核安全增强系统,用于限制应用程序的能力和权限,以增加系统的安全性。AppArmor通过创建应用程序特定的访问控制规则来实现这一目标,这些规则可以定义哪些文件、目录和系统资源可以由特定的应用程序访问。AppArmor的主要目标是减小应用程序的攻击面,降低系统遭受恶意行为的风险。
- #解压出包中的⽂件到extract⽬录下
- dpkg -X tcpdump_4.9.3-4ubuntu0.2_amd64.deb extract/
- #解压出包的控制信息extract/DEBIAN/下:
- dpkg -e tcpdump_4.9.3-4ubuntu0.2_amd64.deb extract/DEBIAN/
- #修改⽂件XXX
- # 对修改后的内容重新进⾏打包⽣成deb包
- dpkg-deb -b extract/
也可以下载官方源码,在源码基础上打上补丁,再编译,这个需要:
安装必要软件build-essential devscripts
/etc/apt/sources.list 中的deb-src行去掉

- #下载源码
- apt-get source dash
- #修改源码,打补丁或者手动修改
-
- #进入编译
- cd dash-*
- debuild -us -uc # (-us -uc disables signing the package with GPG)
-
- #在目录外生成deb包
可以调用dpkg -i tcpdump_4.9.3-4ubuntu0.2_amd64.deb,大致流程如下

这个图示解释了在安装 Debian 软件包时不同的阶段和状态。让我们对这个图进行简要的解释:
Preinst Install: 当软件包正在被安装时,首先执行 preinst 脚本。这个脚本用于在软件包安装之前执行一些准备工作。
Postinst Configure: 如果 preinst 步骤成功完成,接下来执行 postinst 脚本,用于配置软件包和执行其他必要的操作。如果 preinst 和 postinst 都成功执行,软件包的状态将被设置为 "Installed",表示安装完成。
Postrm Abort-Install: 如果在 preinst 安装阶段发生了错误,系统将调用 postrm 脚本中的 abort-install 部分。这个脚本用于处理在安装失败时的清理操作。如果 abort-install 步骤成功,用户将收到错误消息,并且软件包状态将被设置为 "Not Installed",表示未成功安装。但如果 postrm abort-install 部分也失败了,软件包将被留在一个不正常的状态下,即 "Half Installed, Reinst required"。这意味着即使你想要卸载它,软件包也需要重新安装。
Postinst Configure 失败: 如果在 postinst 配置阶段发生了错误,用户将收到错误消息,软件包的状态将被设置为 "Failed-Config",表示配置失败。
dpkg -r tcpdump

当卸载之前安装的软件包时,如果一切顺利,软件包将被保留在 "Config Files" 状态,这意味着在软件包处于 "Not Installed" 状态之前需要将其清除。
如果在 postrm 阶段出现问题,并且触发了 postinst abort-remove 脚本,那么软件包可能会处于一个奇怪的状态:它仍然标记为 "Installed",但实际上文件已不再存在。如果在卸载过程中的任何步骤失败,当再次尝试卸载软件包时,它将从之前停止的地方继续执行,也就是说,如果 prerm 步骤成功而 postrm 失败,它将从 postrm 继续执行。
这些不同的状态和脚本用于确保在软件包的安装、配置和卸载过程中,系统的状态始终可控,即使在过程中出现问题也能够正确处理。这有助于维护软件包管理的一致性和可靠性。
dpkg -P tcpdump

首先,软件包的配置文件(conffiles)将被删除。这些配置文件包含了软件包的特定配置和设置。
接下来,将调用 postrm purge 脚本,用于执行清理操作。这个脚本通常包括删除软件包相关的文件和目录,以确保软件包完全从系统中清除。

这一部分描述了软件包升级和降级的情况,以及可能涉及的脚本和状态变化。软件包的升级和降级是复杂的过程,它涉及多个脚本的执行和状态的变化,具体取决于操作是否成功。
升级软件包:
如果一切正常,四个脚本按顺序执行,包括 prerm upgrade、preinst upgrade、文件解压、postrm upgrade 和 postinst configure。
如果发生问题,例如在 preinst upgrade 阶段,它可能会导致软件包升级失败,而软件包可能会被留在一个半安装或失败配置的状态中。
降级软件包:
prerm upgrade、preinst upgrade、文件解压、postrm upgrade 和 postinst configure。冲突的软件包:
在试制过程中,如果你的维护脚本写的不正确,那么安装 deb 可能会有意料之外的失败。这不是奇怪的事,问题在于此时 Debian 的包管理系统可能会进入到一种错误的状态。
如果安装一个 deb 导致了意外的终止,你可以采用下面的序列来做清理:
- sudo mv /var/lib/dpkg/info/<packagename>.* /tmp/
- sudo dpkg --remove --force-remove-reinstreq <packagename>
有时候,你可能疑惑于安装流程失败的原因。此时可以打开安装时的详细输出开关,例如:
sudo dpkg -D2 -i
man dpkg 能够查阅到 -D 的可能的取值:
- Number Description
- 1 Generally helpful progress information
- 2 Invocation and status of maintainer scripts
- 10 Output for each file processed
- 100 Lots of output for each file processed
- 20 Output for each configuration file
- 200 Lots of output for each configuration file
- 40 Dependencies and conflicts
- 400 Lots of dependencies/conflicts output
- 10000 Trigger activation and processing
- 20000 Lots of output regarding triggers
- 40000 Silly amounts of output regarding triggers
- 1000 Lots of drivel about e.g. the dpkg/info dir
- 2000 Insane amounts of drivel
更多的时候是版本不匹配
可以在运行环境中打包