Apk 规范
![]() 在此通知移除之前,请勿遵循此处的说明。 |
有关 apk 的面向最终用户的文档,请查看 Alpine Package Keeper 页面。
此页面旨在记录 apk 软件包管理器的内部数据结构。apk 格式的规范实现是 apk-tools,并且此信息的很大一部分是从阅读源代码中收集而来的。
APK 数据格式有三代。版本 1 已弃用且不再使用,版本 2 目前是 apk-tools 使用的主要版本,版本 3 正在开发中。此页面主要描述版本 2 中使用的数据格式。
背景
Tar 段
Tar 段是一组 tar 记录。正常的 tar 文件在 tar 文件末尾包含两个空记录,以指示 tarball 的结尾。Tar 段缺少这两个记录,因此可以在其他 tar 文件之前连接,并将表现为一个连续的 tar 文件。APK v2 软件包格式同时使用 tar 段和 tarball。
Tar 段可以使用 gzip 压缩进行压缩。Gzip 是一种基于流的文件格式,多个流可以连接在一起。大多数工具会将文件中的多个 gzip 流视为单个流。APK v2 文件知道 gzip 流并使用它们进行文件分段。
软件包格式 V2
二进制格式
APK v2 软件包包含两个 tar 段,后跟一个 tarball,每个都在其自己的 gzip 流中(总共 3 个流)。这些流包含软件包签名、控制数据和软件包数据。软件包数据是一个 tarball,其中包含软件包中包含的文件,这些文件以允许在文件系统根目录解压缩的方式布局,以便所有文件都放置在系统上的正确位置。控制 tar 段包含软件包元数据以及任何安装脚本。签名 tar 段包含一个文件,该文件是对控制段的二进制签名。
签名文件是对控制 tar 段 gzip 流的 SHA1 哈希的 DER 编码的 PKCS1v15 RSA 签名。文件名格式为.SIGN.RSA.<key_name>.rsa.pub(例如.SIGN.RSA.alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub)。此文件放置在 tar 记录内,权限为 0644,uid 为 0,gid 为 0。此 tar 记录(缺少 tar 结尾记录)经过 gzip 压缩,形成签名 tar 段,并连接到组合的控制段和数据段的前面。abuild-sign 负责生成这些签名段。
Apk 将通过在 /etc/apk/keys 中查找名为 exactly <key_name>.rsa.pub 的文件来验证签名(在 /etc/apk/keys 中)。如果找不到此类文件,则验证失败。
控制段包含软件包元数据,位于 .PKGINFO 文件中,以及 apk 在软件包安装和删除期间使用的所有脚本(如果有)。由于历史原因,控制 tar 段中的所有文件都以点号为前缀(.)。控制段的构造方法是将软件包的每个文件放入 tar 记录中,连接这些 tar 记录,对 tar 记录进行 gzip 压缩,然后将它们连接到数据 tarball 的前面。此 gzip 流的 SHA1 哈希用作校验和C在 APKINDEX 文件中的字段。
数据 tarball 是一个标准的 gzipped tarball,带有额外的 PAX 标头,其中包含 tar 标头中每个文件的 SHA1 哈希。哈希包含在名为 APK-TOOLS.checksum.SHA1 的标头中。与其他 tar 流不同,此 tarball 包含两个 tar 结尾空记录。它始终是 APK 软件包的最后一个段。哈希是使用 abuild-tar 工具添加的。
PKGINFO 格式
PKGINFO 文件包含软件包元数据。这是一个纯文本文件,类似于 INI 文件。以 开头的行#是注释,将被忽略。与 INI 文件不同,此文件的解析格式非常严格。每个键值对必须用恰好一个空格、一个等号和一个空格分隔( = )。键可以在此文件中重复,如果找到重复项,则应将其视为值列表。
PKGINFO 中哪些字段有效的规范主要由 abuild 定义。截至 2022 年 7 月,支持以下字段
- pkgname- 软件包名称
- pkgver- 软件包版本
- pkgdesc- 软件包描述
- url- 软件包 URL
- builddate- 软件包构建日期/时间的 Unix 时间戳
- packager- 构建软件包的人员的姓名(通常是电子邮件)
- size- 软件包的已安装大小
- arch- 软件包的架构(例如:x86_64)
- origin- 软件包的来源名称
- commit- 构建软件包所用的 commit 哈希
- maintainer- 软件包维护者的姓名(通常是电子邮件)
- replaces_priority- 软件包的 replaces 优先级字段(整数)
- provider_priority- 软件包的 provider 优先级(整数)
- license- 软件包的许可证字符串
- depend- 软件包的依赖项(重复)
- replaces- 此软件包替换的软件包(重复)
- provides- 此软件包提供的功能(重复)
- triggers- 此软件包触发的软件包(重复)
- install_if- 如果存在这些软件包,则安装此软件包(重复)
- datahash- 数据 tarball 的十六进制编码的 sha256 校验和
PKGINFO 示例
# Generated by abuild 3.9.0-r2 # using fakeroot version 1.25.3 # Wed Jul 6 19:09:49 UTC 2022 pkgname = busybox pkgver = 1.35.0-r18 pkgdesc = Size optimized toolbox of many common UNIX utilities url = https://busybox.net/ builddate = 1657134589 packager = Buildozer <alpine-devel@lists.alpinelinux.org> size = 958464 arch = x86_64 origin = busybox commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb maintainer = Sören Tempel <soeren+alpine@soeren-tempel.net> provider_priority = 100 license = GPL-2.0-only replaces = busybox-initscripts provides = /bin/sh triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/* # automatically detected: provides = cmd:busybox=1.35.0-r18 provides = cmd:sh=1.35.0-r18 depend = so:libc.musl-x86_64.so.1 datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7
软件包构建示例
这是一组部分构建软件包的命令。请勿执行此操作,这主要是一个示例,用于了解这一切是如何组合在一起的。使用官方构建工具来构建软件包。
tar -c .PKGNIFO .pre-install | abuild-tar --cut | gzip -9 > $controldir/control.tar.gz cd $pkgdir; tar -c * | abuild-tar --hash | gzip -9 > $controldir/data.tar.gz cat $controldir/control.tar.gz $controldir/data.tar.gz > mypackage-1.0-r0.apk
索引格式 V2
二进制格式
索引以 APKINDEX.tar.gz 的形式提供,并由 apk 下载以支持软件包数据库。索引的签名方式与软件包类似。索引和软件包之间的主要区别在于,索引文件仅包含两个段。
签名段与软件包段相同,并在其自己的 gzip 流中连接到 APKINDEX tarball 的开头。
APKINDEX tarball 包含两个文件:DESCRIPTION 文件和 APKINDEX 文件。这些文件中的每一个都在其自己的 tar 记录中,并且最后一个记录后跟标准的 tar 结尾空记录。DESCRIPTION 文件是一个简单的文本文件,其中包含索引的描述(例如community v20210212-7170-g5c9853dc69)。APKINDEX 文件是一个文本文件,其中包含存储库中每个软件包的记录,采用基于文本的格式。每个记录都用换行符分隔。
APKINDEX 格式
APKINDEX 文件包含一组从存储库中每个软件包的 PKGINFO 文件中提取的记录。每行都以字母、冒号为前缀,后跟字段的值。行以换行符(\n)结尾,并且软件包的记录之间有一个空行。
Theapk_pkg_write_index_entrypackage.c 的 函数定义了当前接受的字段。截至 2022 年 7 月,这些是
- C- 文件校验和,见下文
- P- 软件包名称(对应于pkgname在 PKGINFO 中)
- V- 软件包版本(对应于pkgver在 PKGINFO 中)
- A- 架构(对应于arch在 PKGINFO 中),可选
- S- 整个软件包的大小,整数
- I- 已安装大小,整数(对应于size在 PKGINFO 中)
- T- 描述(对应于pkgdesc在 PKGINFO 中)
- U- url(对应于url在 PKGINFO 中)
- L- 许可证(对应于license在 PKGINFO 中)
- o- 来源(对应于origin在 PKGINFO 中),可选
- m- 维护者(对应于maintainer在 PKGINFO 中),可选
- t- 构建时间(对应于builddate在 PKGINFO 中),可选
- c- commit(对应于commit在 PKGINFO 中),可选
- k- provider 优先级,整数(对应于provider_priority在 PKGINFO 中),可选
- D- 依赖项(对应于depend在 PKGINFO 中,用空格连接成一行)
- p- provides(对应于provides在 PKGINFO 中,用空格连接成一行)
- i- install if(对应于install_if在 PKGINFO 中,用空格连接成一行)
软件包校验和字段
软件包校验和字段是软件包中第二个 gzip 流(控制流)的 SHA1 哈希。二进制哈希摘要是 base64 编码的。这以 为前缀Q1,以将其与旧索引格式中使用的 MD5 哈希区分开来。无法使用标准命令行工具计算此校验和,但 apk-tools 可以在其index操作中计算它。
APKINDEX 记录示例
C:Q1P4IRU/u5yB4CSnUEBRD1WWwajrY= P:jool-tools V:4.1.5-r0 A:x86_64 S:140605 I:434176 T:Userspace control tools for SIIT / NAT64 Jool U:https://www.jool.mx L:GPL-2.0-only o:jool-tools m:Jakub Jirutka <jakub@jirutka.cz> t:1620480809 c:771b3b0910ea9c7736db6ca4ff5c37ca9cf9af0d D:so:libc.musl-x86_64.so.1 so:libnl-3.so.200 so:libnl-genl-3.so.200 p:cmd:jool=4.1.5-r0 cmd:jool_siit=4.1.5-r0 cmd:joold=4.1.5-r0
已安装数据库 V2
apk 使用已安装数据库来跟踪已安装哪些软件包以及这些软件包对系统进行了哪些修改。此文件位于 /lib/apk/db/installed。已安装文件是一个纯文本文件,格式与 APKINDEX 相同(包含在 APKINDEX.tar.gz 中)。它既未压缩也未签名。已安装文件中的每个记录都以软件包索引记录开头,该记录具有与 APKINDEX 文件相同的字段。已安装文件添加了一些在 database.c 中定义的附加字段。截至 2022 年 7 月,这些附加字段是
- r- 此软件包替换的软件包,空格分隔列表
- q- replaces 优先级,整数,可选
- s- 存储库标签,可选,如果软件包已标记到 world 文件中的存储库,则将设置此标签(例如:linux@testing)
- f- 指示损坏的项目,空格分隔(f=文件,s=脚本,x=xattrs,S=文件哈希)
以下字段是重复的,并且成组构成一组对系统进行的安装软件包的突变。
ACL 行指定为 uid、冒号、gid、冒号和模式。
- F- 由软件包创建的目录名称,重复
- M- 目录 ACL,仅当与默认值 0:0:0755 不同时
- R- 文件名,相对于前面的目录名
- a- 文件 ACL
- Z- 文件校验和,如果软件包中的校验和不是 none,则 aQ1前缀表示这将是以 base64 格式的 SHA1 哈希