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)。此文件放置在权限为 0644、uid 为 0 和 gid 为 0 的 tar 记录中。此 tar 记录(缺少 tar 结束记录)经过 gzip 压缩,形成签名 tar 段,并连接到组合的控制段和数据段的前面。abuild-sign 负责生成这些签名段。
Apk 将通过在 /etc/apk/keys 中查找名为exactly <key_name>.rsa.pub 的文件来验证签名。如果找不到此类文件,则验证失败。
控制段包含 .PKGINFO 文件中的软件包元数据,以及 apk 在软件包安装和删除期间使用的所有脚本(如果有)。由于历史原因,控制 tar 段中的所有文件都以点号开头(.)。控制段的构建方法是将软件包的每个文件放入 tar 记录中,连接这些 tar 记录,对 tar 记录进行 gzip 压缩,然后将它们连接到数据 tarball 的前面。此 gzip 流的 SHA1 哈希值用作校验和CAPKINDEX 文件中的字段。
数据 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- 构建软件包的提交哈希值
- 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) 结尾,并且软件包的记录之间有一个空行。
的apk_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=扩展属性,S=文件哈希)
以下字段是重复的,并且成组构成一组为安装软件包而对系统进行的修改。
ACL 行指定为 uid、冒号、gid、冒号和模式。
- F- 由软件包创建的目录名称,重复
- M- 目录 ACL,仅当与默认值 0:0:0755 不同时
- R- 文件名,相对于前面的目录名称
- a- 文件 ACL
- Z- 文件校验和,如果软件包中的校验和不为 none,则 aQ1前缀表示这将是以 base64 格式的 SHA1 哈希值