# 26.7.使用软件包更新 FreeBSD

从 14.0-RELEASE 开始，FreeBSD 项目已经使用 [pkg(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg\&sektion=8\&format=html) 发布了一套基本系统的软件包。pkg 的便利性已不再局限于 FreeBSD ports。现在，FreeBSD 本身也可以使用 [pkg(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg\&sektion=8\&format=html)。基本系统的软件包及其使用方式传统上被称为 *pkgbase*。

官方 packages 的发布始于 [2023 年 10 月](https://lists.freebsd.org/archives/freebsd-pkgbase/2023-October/000221.html)。在 FreeBSD 14 中使用它们目前仍属于实验性。

从 15.0-RELEASE 开始，[freebsd-base(7)](https://man.freebsd.org/cgi/man.cgi?query=freebsd-base\&sektion=7\&format=html) 将以技术预览（tech preview）的形式支持：

* 安装
* 小版本升级
* 大版本升级

freebsd-base 最终将取代：

* 诸如 `base.txz`、`kernel.txz` 这样的 tar 压缩包分发文件，它们在过去用于通过 [bsdinstall(8)](https://man.freebsd.org/cgi/man.cgi?query=bsdinstall\&sektion=8\&format=html) 安装操作系统
* [freebsd-update(8)](https://man.freebsd.org/cgi/man.cgi?query=freebsd-update\&sektion=8\&format=html) 用于系统更新

当前的计划是让 `freebsd-update` 与 pkg 协同工作。

> **警告**
>
> 分发集的替换仍需要一些时间，直到 freebsd-base 完全稳定！

基本系统的软件包补充了从源代码构建和安装的方式（[文档链接](https://docs.freebsd.org/en/books/handbook/cutting-edge/#makeworld)），对于希望构建自定义内核或用户空间的用户，这条路径依然可用。用户也可以从本地源代码构建自定义的基本系统软件包，或完全依赖官方提供的软件包。

## 26.7.1 将主机转换为使用 freebsd-base

FreeBSD 14.0-RELEASE 或之后的版本可以转换为使用基本系统的软件包。更早的版本必须先使用 freebsd-update 升级，然后才能进行转换。

在转换过程中，推荐使用 FreeBSD 基金会赞助的 [pkgbasify](https://github.com/FreeBSDFoundation/pkgbasify) 工具。请按照其中给出的说明进行操作。

[freebsd-update(8)](https://man.freebsd.org/cgi/man.cgi?query=freebsd-update\&sektion=8\&format=html) 将会被增强，使其能与 pkg 和 pkgbasify 协同工作。

> **警告**
>
> 请注意，此迁移过程需要额外最多 5 GiB 的可用空间，用于下载、解包并重新放置所有冲突的文件。pkgbasify 工具不会对磁盘空间进行检查，因此在运行迁移前，确保有足够空间是用户自己的责任。

[pkgbasify(8)](https://man.freebsd.org/cgi/man.cgi?query=pkgbasify\&sektion=8\&format=html)（或 [D51594](https://reviews.freebsd.org/D51594) 及其对应的 Ports 请求的最终产物）执行六项主要任务：

* 使用 [bectl(8)](https://man.freebsd.org/cgi/man.cgi?query=bectl\&sektion=8\&format=html) 创建一个备份引导环境（仅适用于 ZFS）
* 创建新的 package 仓库配置文件
* 升级现有系统组件，如 base、kernel、lib32、debug
* 合并现有与新的配置文件
* 更新 passwd 和 capabilities 数据库
* 立即重启 sshd

## 26.7.2 使用 freebsd-base 升级主机

> **警告**
>
> 这部分仍在开发中，因此请务必小心，尤其是在将现有系统转换为使用 freebsd-base 时。

如果还没有自定义 pkg 仓库配置文件的文件夹，请创建一下：

```sh
# mkdir -p /usr/local/etc/pkg/repos/
```

为了使用 freebsd-base 仓库，创建一个名为 `FreeBSD-base.conf` 的 pkg 仓库配置文件：

```sh
FreeBSD-base {
    url = "pkg+https://pkg.freebsd.org/${ABI}/base_release_${VERSION_MINOR}";
    mirror_type = "srv";
    signature_type = "fingerprints";
    fingerprints = "/usr/share/keys/pkg";
    enabled = yes;
}
```

关于具体配置选项的更多信息，请参见 [pkg.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=pkg.conf\&sektion=5\&format=html)。

可以选择不同的分支（通过相应修改 `url`）：

**表 2. freebsd-base 分支**

| 分支          | 更新频率                      | URL                                                 |
| ----------- | ------------------------- | --------------------------------------------------- |
| main        | 每天两次 —— 12:00 与 00:00 UTC | `pkg+https://pkg.freebsd.org/${ABI}/base_latest`    |
| main        | 每周一次 —— 周日 12:00 UTC      | `pkg+https://pkg.freebsd.org/${ABI}/base_weekly`    |
| stable/14   | 每天两次 —— 12:00 与 00:00 UTC | `pkg+https://pkg.freebsd.org/${ABI}/base_latest`    |
| stable/14   | 每周一次 —— 周日 12:00 UTC      | `pkg+https://pkg.freebsd.org/${ABI}/base_weekly`    |
| releng/14.3 | 每天两次 —— 12:00 与 00:00 UTC | `pkg+https://pkg.freebsd.org/${ABI}/base_release_3` |
| releng/15.0 | 每天两次 —— 12:00 与 00:00 UTC | `pkg+https://pkg.freebsd.org/${ABI}/base_release_0` |
| stable/15   | 每天两次 —— 12:00 与 00:00 UTC | `pkg+https://pkg.freebsd.org/${ABI}/base_latest`    |
| stable/15   | 每周一次 —— 周日 12:00 UTC      | `pkg+https://pkg.freebsd.org/${ABI}/base_weekly`    |

要升级系统，根据所需的发行版本修改配置文件，然后运行：

```sh
# pkg update -r FreeBSD-base
# pkg upgrade -r FreeBSD-base
```

检查这些软件包是否正确，并接受更改。

使用以下命令重启系统：

```sh
# shutdown -r now
```

### 26.7.2.1 主版本升级

如果使用 ZFS，启动环境能让升级在不打断运行中软件的情况下完成。如果系统的根分区并不使用 ZFS：升级前请做好备份。

#### 26.7.2.1.1 准备工作

将 `/usr/local/etc/pkg/repos/FreeBSD-base.conf` 修改为目标主版本，例如对 15.0-RELEASE 使用 `base_release_0`，使其如下所示：

> **警告**
>
> 这个文件后续可能会在 RELEASE 中以不同路径出现。

```sh
FreeBSD-base {
    url = "pkg+https://pkg.freebsd.org/${ABI}/base_release_0";
    mirror_type = "srv";
    signature_type = "fingerprints";
    fingerprints = "/usr/share/keys/pkg";
    enabled = yes;
}
```

> **警告**
>
> 由于 FreeBSD 14 的 pkgbase 仍处于实验阶段，从 14 到 15 的更新，即 pkgbase 主版本更新同样是实验性的。撰写本手册时，在一些极端情况下主版本升级会移除 pkg，从而导致 pkg 段错误。这是 15.0-RELEASE 的 [已知问题](https://github.com/freebsd/pkg/issues/2475)。解决方法：在升级前锁定 pkg：
>
> ```sh
> # pkg -c /mnt/upgrade lock pkg
> ```
>
> 从 FreeBSD 14 实验性升级到 15（或 16.0-CURRENT）之后，应安装元包 `FreeBSD-set-minimal`。

保存非基本系统软件包的列表，以便之后可能需要：

```sh
pkg prime-origins | sort -u > /var/tmp/pkg-prime-origins.txt
```

#### 26.7.2.1.2 主版本升级（根分区使用 ZFS）

使用 [bectl(8)](https://man.freebsd.org/cgi/man.cgi?query=bectl\&sektion=8\&format=html) 创建启动环境，并按目标版本命名：

```sh
# bectl create 15.0-RELEASE
```

创建目录，再将新的启动环境挂载到该目录，以便通过 [chroot(8)](https://man.freebsd.org/cgi/man.cgi?query=chroot\&sektion=8\&format=html) 与 pkg 配合使用：

```sh
# mkdir /mnt/upgrade
# bectl mount 15.0-RELEASE /mnt/upgrade
```

接下来的步骤会将启动环境升级到指定版本。

> **警告**
>
> 此步骤可能会移除非基本系统的软件包，其中也可能包括正在运行的桌面环境。

设置环境变量 ABI 来执行主版本升级（将 amd64 替换为对应架构，将 15 替换为目标版本）。将 pkg-static 的 chroot 目录指定为启动环境的挂载点：

```sh
# env ABI=FreeBSD:15:amd64 pkg-static -c /mnt/upgrade upgrade -r FreeBSD-base
```

将会出现提示，询问是否忽略版本不匹配，如下所示：

```sh
Newer FreeBSD version for package FreeBSD-zoneinfo:
To ignore this error set IGNORE_OSVERSION=yes
- package: 1500058
- running userland: 1500000
Ignore the mismatch and continue? [y/N]:
```

检查并确认。

要检查升级是否成功，`chroot` 到该启动环境的挂载点并运行 `freebsd-version -kru`：

```sh
# chroot /mnt/upgrade
# freebsd-version -ku
# exit
```

临时激活该启动环境，然后重新启动系统：

```sh
# bectl activate -t 15.0-RELEASE
# shutdown -r now
```

如果系统运行不正常：重新启动系统即可停止使用临时激活的启动环境，下一次开机将回到升级前的环境。

如果系统在重启后稳定运行，请不要忘记永久激活此启动环境，以避免意外启动到旧系统：

```sh
# bectl activate 15.0-RELEASE
```

#### 26.7.2.1.3. 主版本升级（根分区未使用 ZFS）

设置环境变量 ABI 来升级主版本（将 amd64 替换成架构，将 15 替换成目标版本）。

```sh
# env ABI=FreeBSD:15:amd64 pkg-static upgrade -r FreeBSD-base
```

会出现询问是否忽略版本不匹配的提示，看起来如下：

```sh
Newer FreeBSD version for package FreeBSD-zoneinfo:
To ignore this error set IGNORE_OSVERSION=yes
- package: 1500058
- running userland: 1500000
Ignore the mismatch and continue? [y/N]:
```

检查并确认。

要检查升级是否成功，运行 `freebsd-version -ku`。

然后重启。

#### 26.7.2.1.4. 升级后的任务

如果在更新过程中将 pkg 锁定作为权宜之计，那么像这样移除锁：

```sh
# pkg unlock pkg
```

在升级到新的 major 版本之后，可能需要更新并升级已安装的软件包，使之与 ABI 版本匹配。

```sh
# pkg upgrade
```

如遇到问题，可以考虑向 [FreeBSD 支持](https://www.freebsd.org/support/) 寻求帮助。

## 26.7.3. 手动构建 pkgbase 并发布到本地网络

在构建自定义 pkgbase 软件包时，先克隆 FreeBSD 源码树：

```sh
# cd /usr/src
# git clone https://github.com/freebsd/freebsd-src.git /usr/src
```

检出要构建软件包所对应发行版的分支：

```sh
# git checkout releng/14.3
```

开始构建过程，根据可用资源，这可能需要一些时间。根据 CPU 核心数量设置并行进程数。

此示例面向 8 核 CPU：

```sh
# make -j8 buildworld && make -j8 buildkernel && make -j8 packages
```

如果构建频繁，可以考虑使用 [devel/ccache](https://cgit.freebsd.org/ports/tree/devel/ccache/) 利用缓存加快后续构建。

构建完成后，软件包会被保存到 `/usr/obj/usr/src/repo/FreeBSD:14:amd64/14.3p2` 或类似目录，具体取决于构建的版本。

要将这些软件包发布到网络，设置 nginx 服务，并在 http server 配置中使用如下位置：

```sh
location /FreeBSD:14:amd64 {
   alias /usr/obj/usr/src/repo/FreeBSD:14:amd64/;
   autoindex on;
 }
```

然后重新加载 nginx 服务。

在未使用 https 的情况下，在客户端使用一个简短的配置文件来指定刚构建的 pkgbase 版本，编辑 `/usr/local/etc/pkg/repos/upgrade.conf`：

```sh
upgrade: {
	url         = http://ip.of.the.server/FreeBSD:14:amd64/14.3p2
	enabled     = yes
}
```

并按照上文所述使用它（但使用 `-r upgrade` 而不是 `FreeBSD-base`）。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://handbook.bsdcn.org/di-26-zhang-freebsd-geng-xin-yu-sheng-ji/26.7.-pkgbase.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
