Apk 规范

来自 Alpine Linux
(重定向自 Apk internals
此材料为在制品...

在此通知移除之前,请勿遵循此处的说明。
(上次编辑者:Zcrayfish,于 2024 年 10 月 14 日。)

有关 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 段包含一个文件,该文件是控制段的 SHA1 哈希的二进制签名。

签名文件是控制 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 的文件来验证签名。/etc/apk/keys。如果未找到此类文件,则验证失败。

控制段包含软件包元数据,位于 .PKGINFO 文件中,以及 apk 在软件包安装和删除期间使用的所有脚本(如果有)。由于历史原因,控制 tar 段中的所有文件都以点(.)开头。控制段的构建方式是将软件包的每个文件放入 tar 记录中,连接这些 tar 记录,对 tar 记录进行 gzip 压缩,然后将它们连接到数据 tarball 的前面。此 gzip 流的 SHA1 哈希用作 APKINDEX 文件中的校验和C字段。

数据 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_entryapk_pkg_write_index_entry函数 package.c 定义了当前接受的字段。截至 2022 年 7 月,这些字段是

  • C- 文件校验和,请参见下文
  • P- 软件包名称(对应于 PKGINFO 中的pkgnamepkgname
  • V- 软件包版本(对应于pkgverpkgname
  • pkgverAarch- 架构(对应于 PKGINFO 中的 arch),可选
  • S- 整个软件包的大小,整数
  • I- 已安装大小,整数(对应于 PKGINFO 中的sizepkgname
  • sizeTpkgdescpkgname
  • - 描述(对应于 PKGINFO 中的pkgdescurlpkgname
  • U- url(对应于 PKGINFO 中的licensepkgname
  • urlLorigin- 架构(对应于 PKGINFO 中的 arch),可选
  • - 许可证(对应于 PKGINFO 中的licensemaintainer- 架构(对应于 PKGINFO 中的 arch),可选
  • o- 来源(对应于 PKGINFO 中的builddate- 架构(对应于 PKGINFO 中的 arch),可选
  • originmcommit- 架构(对应于 PKGINFO 中的 arch),可选
  • - 维护者(对应于 PKGINFO 中的maintainerprovider_priority- 架构(对应于 PKGINFO 中的 arch),可选
  • t- 构建时间(对应于 PKGINFO 中的dependbuilddate
  • c- 提交(对应于 PKGINFO 中的providesbuilddate
  • commitkinstall_ifbuilddate

- provider 优先级,整数(对应于

provider_priorityD- 依赖项(对应于 PKGINFO 中的depend,通过空格连接成一行)

p

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

- provides(对应于 PKGINFO 中的

provides

  • i- install if(对应于 PKGINFO 中的
  • install_if软件包校验和字段
  • 软件包校验和字段是软件包中第二个 gzip 流(控制流)的 SHA1 哈希值。二进制哈希摘要是 base64 编码的。这以Q1
  • 为前缀,以区别于旧索引格式中使用的 MD5 哈希值。使用标准命令行工具无法计算此校验和,但 apk-tools 可以在其index

操作中计算它。

APKINDEX 记录示例

  • 已安装数据库 V2apk 使用已安装数据库来跟踪已安装的软件包以及这些软件包对系统所做的修改。此文件位于 /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=文件哈希)D以下字段是重复的,并且成组构成一组对系统进行的修改,以安装软件包。
ACL 行指定为 uid、冒号、gid、冒号和模式。