第 26 章 更新和升级 FreeBSD

如果发现翻译错误,请直接 发起PR修改

26.1. 简介

FreeBSD 在发布之间处于不断的开发中。有些人喜欢使用官方发布的版本,而其他人则喜欢与最新的开发保持同步。然而,即使是官方发布的版本也经常会更新以修复安全和其他关键问题。无论使用哪个版本, FreeBSD 都提供了所有必要的工具来保持系统更新,并允许在版本之间进行轻松升级。本章介绍如何跟踪开发系统以及保持 FreeBSD 系统最新的基本工具。

阅读完本章后,您将了解:

  • 如何使用 freebsd-update 或 Git 来保持 FreeBSD 系统的最新状态。

  • 如何将已安装系统的状态与已知的原始副本进行比较。

  • 如何使用 Git 或文档 port 来保持已安装文档的最新状态。

  • 两个开发分支之间的区别:FreeBSD-STABLE 和 FreeBSD-CURRENT。

  • 如何重建和重新安装整个基础系统。

在阅读本章之前,您应该:

在本章中,使用 git 来获取和更新 FreeBSD 源代码。可选地,可以使用 devel/git port 或软件包。

26.2. FreeBSD 更新

及时应用安全补丁和升级到操作系统的新版本是系统管理的重要方面。FreeBSD 包含一个名为 freebsd-update 的实用程序,可用于执行这两个任务。

该实用程序支持对 FreeBSD 进行二进制安全性和勘误更新,无需手动编译和安装补丁或新内核。二进制更新适用于安全团队当前支持的所有架构和版本。支持的版本列表及其预计的生命周期日期可在 https://www.FreeBSD.org/security/ 上找到。

该实用程序还支持将操作系统升级到次要点版本以及升级到另一个发布分支。在升级到新版本之前,请查看其发布公告,因为其中包含与该版本相关的重要信息。发布公告可从 https://www.FreeBSD.org/releases/ 获取。

如果存在使用 freebsd-update(8) 功能的 crontab(5),在升级操作系统之前必须将其禁用。

本节描述了 freebsd-update 使用的配置文件,演示了如何应用安全补丁以及如何升级到次要或主要操作系统版本,并讨论了升级操作系统时的一些考虑因素。

26.2.1. 配置文件

freebsd-update 的默认配置文件可以直接使用。一些用户可能希望调整默认配置文件 /etc/freebsd-update.conf ,以便更好地控制该过程。该文件中的注释解释了可用的选项,但以下内容可能需要更多的解释:

# Components of the base system which should be kept updated.
Components world kernel

该参数控制着哪些部分的 FreeBSD 将保持最新。默认情况下,会更新整个基础系统和内核。也可以指定单个组件,例如 src/basesrc/sys 。然而,最好的选择是将其保持默认状态,因为更改它以包括特定项需要列出每个所需的项。随着时间的推移,这可能会导致源代码和二进制文件不同步,从而产生灾难性后果。

# Paths which start with anything matching an entry in an IgnorePaths
# statement will be ignored.
IgnorePaths /boot/kernel/linker.hints

为了在更新过程中保留指定目录,例如 /bin/sbin 的内容不变,可以将它们的路径添加到此语句中。此选项可用于防止 freebsd-update 覆盖本地修改。

# Paths which start with anything matching an entry in an UpdateIfUnmodified
# statement will only be updated if the contents of the file have not been
# modified by the user (unless changes are merged; see below).
UpdateIfUnmodified /etc/ /var/ /root/ /.cshrc /.profile

此选项仅会更新指定目录中未修改的配置文件。用户所做的任何更改都会阻止这些文件的自动更新。还有另一个选项 KeepModifiedMetadata ,它会指示 freebsd-update 在合并过程中保存更改。

# When upgrading to a new FreeBSD release, files which match MergeChanges
# will have any local changes merged into the version from the new release.
MergeChanges /etc/ /var/named/etc/ /boot/device.hints

freebsd-update 应尝试合并的配置文件目录列表。文件合并过程是一系列类似于 mergemasterdiff(1) 补丁,但选项较少。合并可以被接受、打开编辑器或导致 freebsd-update 中止。如果不确定,备份 /etc 并接受合并。有关 mergemaster 的更多信息,请参阅 mergemaster(8)

# Directory in which to store downloaded updates and temporary
# files used by FreeBSD Update.
# WorkDir /var/db/freebsd-update

该目录是用于存放所有补丁和临时文件的位置。在用户进行版本升级的情况下,该位置应至少有 1GB 的可用磁盘空间。

# When upgrading between releases, should the list of Components be
# read strictly (StrictComponents yes) or merely as a list of components
# which *might* be installed of which FreeBSD Update should figure out
# which actually are installed and upgrade those (StrictComponents no)?
# StrictComponents no

当将此选项设置为 yes 时,freebsd-update 将假设 Components 列表是完整的,并且不会尝试在列表之外进行更改。实际上,freebsd-update 将尝试更新属于 Components 列表的每个文件。

请参考 freebsd-update.conf(5) 获取更多详细信息。

26.2.2. 应用安全补丁

应用 FreeBSD 安全补丁的过程已经简化,管理员可以使用 freebsd-update 来保持系统完全更新。有关 FreeBSD 安全公告的更多信息,请参阅 “FreeBSD 安全公告”

可以使用以下命令下载和安装 FreeBSD 安全补丁。第一个命令将确定是否有可用的未解决补丁,并且如果应用了这些补丁,将列出将被修改的文件。第二个命令将应用这些补丁。

# freebsd-update fetch
# freebsd-update install

如果更新应用了任何内核补丁,系统将需要重新启动以引导到已打补丁的内核。如果补丁被应用于正在运行的二进制文件,受影响的应用程序应该重新启动,以便使用已打补丁的二进制版本。

通常,用户需要准备好重新启动系统。要知道系统是否需要由于内核更新而重新启动,请执行命令 freebsd-version -kuname -r。如果输出不同,请重新启动系统。

系统可以通过将以下条目添加到 /etc/crontab 来配置每天自动检查更新:

@daily                                  root    freebsd-update cron

如果存在补丁,它们将会自动下载但不会被应用。系统会向 root 用户发送一封电子邮件,以便可以审查这些补丁,并使用 freebsd-update install 命令手动安装它们。

如果出现任何问题,freebsd-update 可以使用以下命令回滚最后一组更改:

# freebsd-update rollback
Uninstalling updates... done.

如果内核或任何内核模块被修改,系统应该重新启动,并且应该重新启动任何受影响的二进制文件。

只有 GENERIC 内核可以被 freebsd-update 自动更新。如果安装了自定义内核,则需要在 freebsd-update 完成更新后重新构建和安装它。默认的内核名称是 GENERIC。可以使用 uname(1) 命令来验证其安装情况。

始终保留一个 GENERIC 内核的副本在 /boot/GENERIC 中。这对于诊断各种问题和进行版本升级非常有帮助。请参考 使用 FreeBSD 9.X 及更高版本的自定义内核 了解如何获取 GENERIC 内核的副本的说明。

除非已更改 /etc/freebsd-update.conf 中的默认配置,否则 freebsd-update 将与其他更新一起安装更新的内核源代码。然后可以按照通常的方式重新构建和重新安装新的自定义内核。

freebsd-update 分发的更新并不总是涉及内核。如果内核源代码没有被 freebsd-update install 修改过,那么重新构建自定义内核是不必要的。然而,freebsd-update 总是会更新 /usr/src/sys/conf/newvers.sh 文件。通过 uname -r 命令报告的 -p 数字表示的当前补丁级别是从这个文件中获取的。即使没有其他变化,重新构建自定义内核也可以使 uname 准确地报告系统的当前补丁级别。这在维护多个系统时特别有帮助,因为它可以快速评估每个系统中安装的更新。

26.2.3. 执行次要和主要版本升级

从一个 FreeBSD 的次要版本升级到另一个次要版本被称为 次要版本 升级。一个例子:

  • 从 FreeBSD 13.1 升级到 13.2 。

主要版本升级会增加主要版本号。一个例子:

  • FreeBSD 13.2 升级至 14.0。

通过为 freebsd-update 提供一个发布版本目标,可以执行两种类型的升级。

在每次新的 RELEASE 之后, FreeBSD 软件包构建服务器在有限的时间内 不会 使用较新的操作系统版本。这为许多用户提供了连续性,这些用户在发布公告后不会立即升级。例如:

  • 在 13.1 版本达到生命周期结束之前,将在运行 13.1 的服务器上构建适用于 13.1 和 13.2 用户的软件包。

 — 而且,至关重要的是:

  • 在 13.1 上构建的内核模块可能 不适用于 13.2。

因此,无论是小型还是大型操作系统升级,如果您的软件包要求包括任何内核模块:

  • 准备好从源代码构建模块

如果系统正在运行自定义内核,请确保在升级之前在 /boot/GENERIC 目录下存在一个 GENERIC 内核的副本。请参考 使用 FreeBSD 9.X 及更高版本的自定义内核 以获取 GENERIC 内核的副本的说明。

在 FreeBSD 13.1 系统上运行以下命令将升级到 FreeBSD 13.2:

# freebsd-update -r 13.2-RELEASE upgrade

在接收到命令后,freebsd-update 将评估配置文件和当前系统,以尝试收集执行升级所需的信息。屏幕上将显示一个列表,列出已检测到和未检测到的组件。例如:

Looking up update.FreeBSD.org mirrors... 1 mirrors found.
Fetching metadata signature for 13.1-RELEASE from update1.FreeBSD.org... done.
Fetching metadata index... done.
Inspecting system... done.

The following components of FreeBSD seem to be installed:
kernel/smp src/base src/bin src/contrib src/crypto src/etc src/games
src/gnu src/include src/krb5 src/lib src/libexec src/release src/rescue
src/sbin src/secure src/share src/sys src/tools src/ubin src/usbin
world/base world/info world/lib32 world/manpages

The following components of FreeBSD do not seem to be installed:
kernel/generic world/catpages world/dict world/doc world/games
world/proflibs

Does this look reasonable (y/n)? y

在这一点上,freebsd-update 将尝试下载升级所需的所有文件。在某些情况下,用户可能会被要求回答关于安装哪些文件或如何继续的问题。

当使用自定义内核时,上述步骤将产生类似以下的警告:

WARNING: This system is running a "MYKERNEL" kernel, which is not a
kernel configuration distributed as part of FreeBSD 13.1-RELEASE.
This kernel will not be updated: you MUST update the kernel manually
before running "/usr/sbin/freebsd-update install"

此警告可以在此时安全地忽略。更新的 GENERIC 内核将作为升级过程中的中间步骤使用。

一旦所有补丁都下载到本地系统后,它们将被应用。这个过程可能需要一些时间,具体取决于机器的速度和工作负载。然后将合并配置文件。合并过程需要一些用户干预,因为可能需要合并文件或者在屏幕上出现编辑器进行手动合并。每次成功合并的结果都会在进程继续时显示给用户。如果合并失败或被忽略,进程将中止。用户可能希望在以后的某个时间备份 /etc 目录并手动合并重要文件,例如 master.passwdgroup

系统尚未进行修改,因为所有的修补和合并都在另一个目录中进行。一旦所有的修补程序都成功应用,所有的配置文件都已经合并,并且看起来进程将顺利进行,用户可以使用以下命令将更改提交到磁盘:

# freebsd-update install

首先,将对内核和内核模块进行补丁。如果系统正在运行自定义内核,请使用 nextboot(8) 命令将内核设置为下一次启动时更新的 /boot/GENERIC

# nextboot -k GENERIC

在使用 GENERIC 内核重新启动之前,请确保它包含了系统正常启动和连接到网络所需的所有驱动程序,如果正在更新的机器是远程访问的。特别是,如果正在运行的自定义内核包含通常由内核模块提供的内置功能,请确保使用 /boot/loader.conf 工具将这些模块临时加载到 GENERIC 内核中。建议在升级过程完成之前禁用非必要的服务以及任何磁盘和网络挂载。

现在应该使用更新的内核重新启动机器:

# shutdown -r now

一旦系统恢复在线状态,使用以下命令重新启动 freebsd-update。由于进程的状态已被保存,freebsd-update 将不会从头开始,而是继续进行下一阶段并删除所有旧的共享库和对象文件。

# freebsd-update install

根据库版本号是否有所增加,安装过程可能只有两个阶段,而不是三个阶段。

升级已完成。如果这是一个主要版本的升级,请按照 在主要版本升级后升级软件包 中描述的步骤重新安装所有端口和软件包。

26.2.3.1. 使用 FreeBSD 9.X 及更高版本的自定义内核

在使用 freebsd-update 前,请确保 /boot/GENERIC 目录下存在一个 GENERIC 内核的副本。如果只构建了一个自定义内核,那么 /boot/kernel.old 目录下的内核就是 GENERIC 内核。只需将此目录重命名为 /boot/GENERIC

如果自定义内核已经构建了多次,或者不知道自定义内核已经构建了多少次,请获取与当前操作系统版本匹配的 GENERIC 内核的副本。如果可以物理访问系统,则可以从安装介质中安装 GENERIC 内核的副本:

# mount /cdrom
# cd /cdrom/usr/freebsd-dist
# tar -C/ -xvf kernel.txz boot/kernel/kernel

或者,也可以从源代码重新构建并安装 GENERIC 内核:

# cd /usr/src
# make kernel __MAKE_CONF=/dev/null SRCCONF=/dev/null

为了使这个内核被 freebsd-update 识别为 GENERIC 内核,必须确保 GENERIC 配置文件没有被任何方式修改过。同时建议在构建内核时不使用任何其他特殊选项。

不需要重新启动到 GENERIC kernel 内核,因为 freebsd-update 只需要存在 /boot/GENERIC 文件。

26.2.3.2. 在主要版本升级后升级软件包

通常,在小版本升级后,已安装的应用程序将继续正常工作,没有问题。主要版本使用不同的应用程序二进制接口(ABIs),这将导致大多数第三方应用程序无法正常工作。在进行主要版本升级后,所有已安装的软件包和端口都需要升级。可以使用 pkg upgrade 命令升级软件包。要升级已安装的端口,请使用类似于 ports-mgmt/portmaster 的实用工具。

强制升级所有已安装的软件包将使用存储库中的新版本替换软件包,即使版本号没有增加。这是因为在升级 FreeBSD 的主要版本之间时,ABI 版本会发生变化。可以通过执行以下操作来完成强制升级:

# pkg-static upgrade -f

使用以下命令可以重新构建所有已安装的应用程序:

# portmaster -af

该命令将显示每个具有可配置选项的应用程序的配置屏幕,并等待用户与这些屏幕进行交互。为了防止这种行为,并仅使用默认选项,请在上述命令中包含 -G

一旦软件升级完成,通过最后一次调用 freebsd-update 来完成升级过程,以解决升级过程中的所有问题。

# freebsd-update install

如果临时使用了 GENERIC 内核,现在是构建和安装新的自定义内核的时候了,可以按照 配置 FreeBSD 内核 中的说明进行操作。

将机器重启到新的 FreeBSD 版本。升级过程现在已经完成。

26.2.4. 系统状态比较

可以使用 freebsd-update IDS 命令来测试已安装的 FreeBSD 版本与已知的良好副本之间的状态。该命令评估系统实用程序、库和配置文件的当前版本,并可用作内置的入侵检测系统(IDS)。

这个命令不能替代真正的入侵检测系统,比如 security/snort。由于 freebsd-update 将数据存储在磁盘上,篡改的可能性是显而易见的。虽然可以通过使用 kern.securelevel 和在不使用时将 freebsd-update 数据存储在只读文件系统上来减少这种可能性,但更好的解决方案是将系统与安全磁盘(如 DVD 或安全存储的外部 USB 磁盘设备)进行比较。使用内置工具提供 IDS 功能的替代方法在 “二进制验证” 中有描述。

开始比较之前,请指定要将结果保存到的输出文件:

# freebsd-update IDS >> outfile.ids

系统将会被检查,并且会将文件的详细列表以及已知发布版本和当前安装版本的 SHA256 哈希值发送到指定的输出文件中。

列表中的条目非常长,但输出格式很容易解析。例如,要获取与发布版本不同的所有文件的列表,请执行以下命令:

# cat outfile.ids | awk '{ print $1 }' | more
/etc/master.passwd
/etc/motd
/etc/passwd
/etc/pf.conf

由于存在更多的文件,此示例输出已被截断。一些文件具有自然的修改。例如,如果系统中添加了用户,/etc/passwd 文件将被修改。内核模块可能会有所不同,因为 freebsd-update 可能已经对它们进行了更新。要排除特定的文件或目录,请将它们添加到 /etc/freebsd-update.conf 文件中的 IDSIgnorePaths 选项中。

26.3. 更新引导代码

以下手册描述了引导代码和引导加载程序的升级过程:gpart(8)gptboot(8)gptzfsboot(8)loader.efi(8)

26.4. 更新文档集合

文档是 FreeBSD 操作系统的一个重要组成部分。虽然 FreeBSD 网站上始终提供最新版本的文档(文档门户),但拥有一个最新的本地副本也是很方便的,包括 FreeBSD 网站、手册、常见问题解答和文章。

本节介绍如何使用源代码或 FreeBSD Ports Collection 来保持本地的 FreeBSD 文档最新。

有关编辑和提交文档更正的信息,请参阅 FreeBSD 文档项目新贡献者入门指南(FreeBSD Documentation Project Primer for New Contributors)。

26.4.1. 从源代码更新文档

从源代码重新构建 FreeBSD 文档需要一系列工具,这些工具不是 FreeBSD 基本系统的一部分。可以按照 FreeBSD 文档项目入门指南中的 these steps 来安装所需的工具。

安装完成后,使用 git 获取文档源代码的干净副本:

# git clone https://git.FreeBSD.org/doc.git /usr/doc

下载文档源文件可能需要一些时间。请让它运行直到完成。

未来可以通过运行以下命令获取文档源的更新:

# git pull

一旦文档源的最新快照被获取到 /usr/doc 目录下,所有准备工作就完成了,可以更新已安装的文档。

可以通过输入以下命令来执行完整更新:

# cd /usr/doc
# make

26.5. 跟踪开发分支

FreeBSD 有两个开发分支:FreeBSD-CURRENT 和 FreeBSD-STABLE。

本节提供了每个分支及其预期受众的解释,以及如何使系统与每个相应分支保持最新的说明。

26.5.1. 使用 FreeBSD-CURRENT

FreeBSD-CURRENT 是 FreeBSD 开发的“最前沿”,使用 FreeBSD-CURRENT 的用户需要具备较高的技术能力。希望跟踪开发分支但技术水平较低的用户应该选择跟踪 FreeBSD-STABLE。

FreeBSD-CURRENT 是 FreeBSD 的最新源代码,包括正在进行中的工作、实验性的更改以及可能存在于下一个官方发布版本中的过渡机制。虽然许多 FreeBSD 开发人员每天编译 FreeBSD-CURRENT 源代码,但在某些短暂的时间内,源代码可能无法构建。这些问题会尽快解决,但是 FreeBSD-CURRENT 是否带来灾难或新功能可能取决于源代码同步的时间。

FreeBSD-CURRENT 提供给三个主要的利益群体使用:

  1. 活跃在 FreeBSD 社区中,正在积极参与源代码树某个部分工作的成员。

  2. FreeBSD 社区的活跃测试人员。他们愿意花时间解决问题,就 FreeBSD 的变化和整体方向提出主题建议,并提交补丁。

  3. 希望密切关注事物、使用当前源代码进行参考,或偶尔发表评论或贡献代码的用户。

FreeBSD-CURRENT 不应被视为在下一次发布之前获取新功能的快速途径,因为预发布功能尚未经过完全测试,很可能包含错误。它也不是获取错误修复的快速方式,因为每个提交都有可能引入新的错误而不是修复现有的错误。 FreeBSD-CURRENT 在任何情况下都不是“官方支持”的。

要追踪 FreeBSD-CURRENT:

  1. 加入 FreeBSD-CURRENT mailing listCommit messages for the main branch of the src repository 邮件列表。这是非常重要的,可以看到人们对系统当前状态的评论,并接收有关 FreeBSD-CURRENT 当前状态的重要公告。

    Commit messages for the main branch of the src repository 列表记录每次更改的提交日志条目,以及可能的副作用的相关信息。

    要加入这些邮件列表,请转到 FreeBSD list server,点击要订阅的列表,并按照说明进行操作。为了跟踪整个源代码树的变化,而不仅仅是 FreeBSD-CURRENT 的变化,请订阅 Commit messages for all branches of the src repository

  2. 与 FreeBSD-CURRENT 源代码同步。通常情况下,使用 git 从 FreeBSD Git 存储库的 main 分支检出 -CURRENT 代码(请参阅 “使用 Git”)。

  3. 由于存储库的大小,一些用户选择只同步他们感兴趣的或者他们正在贡献补丁的源代码部分。然而,计划从源代码编译操作系统的用户必须下载整个 FreeBSD-CURRENT,而不仅仅是选择的部分。

    在编译 FreeBSD-CURRENT 之前,请仔细阅读 /usr/src/Makefile 文件,并按照 从源代码更新 FreeBSD 中的说明进行操作。阅读 FreeBSD-CURRENT mailing list/usr/src/UPDATING 文件以了解其他引导程序的更新情况,有时在进行下一个版本发布的过程中可能需要这些更新。

  4. 积极参与!鼓励 FreeBSD-CURRENT 用户提交他们对增强功能或修复错误的建议。附带代码的建议将会受到欢迎。

26.5.2. 使用 FreeBSD-STABLE

FreeBSD-STABLE 是用于制作主要发布版本的开发分支。更改以较慢的速度进入此分支,并且通常假定它们首先在 FreeBSD-CURRENT 中进行了测试。这仍然是一个开发分支,并且在任何给定时间,FreeBSD-STABLE 的源代码可能适用或不适用于一般使用。它只是另一个工程开发轨道,而不是面向最终用户的资源。没有资源进行测试的用户应该运行最新版本的 FreeBSD。

对于那些对追踪或参与 FreeBSD 开发过程感兴趣的人,尤其是与下一个 FreeBSD 版本相关的人,应该考虑关注 FreeBSD-STABLE。

尽管 FreeBSD-STABLE 分支应该始终能够编译和运行,但无法保证这一点。由于运行 FreeBSD-STABLE 的人比运行 FreeBSD-CURRENT 的人更多,因此不可避免地会在 FreeBSD-STABLE 中发现一些在 FreeBSD-CURRENT 中不明显的错误和边界情况。因此,不应盲目跟踪 FreeBSD-STABLE 。特别重要的是,在没有在开发或测试环境中彻底测试代码的情况下,不要将任何生产服务器更新到 FreeBSD-STABLE。

跟踪 FreeBSD-STABLE 的方法:

  1. 加入 FreeBSD-STABLE mailing list 以便及时了解在 FreeBSD-STABLE 中可能出现的构建依赖项或其他需要特别关注的问题。开发人员还会在这个邮件列表中发布公告,当他们考虑一些有争议的修复或更新时,给用户一个机会回应,如果他们有任何关于拟议变更的问题需要提出。

    加入与正在跟踪的分支相关的 git 列表。例如,跟踪 13-STABLE 分支的用户应该加入 Commit messages for the stable branches of the src repository。该列表记录每个更改的提交日志条目,以及可能的副作用的任何相关信息。

    要加入这些列表,请转到 FreeBSD list server,点击要订阅的列表,并按照说明进行操作。为了跟踪整个源代码树的变化,请订阅 Commit messages for all branches of the src repository

  2. 要安装一个新的 FreeBSD-STABLE 系统,请从 安装最新的 FreeBSD-STABLE 版本,或者使用从 FreeBSD-STABLE 构建的每月快照。有关快照的更多信息,请参考 www.freebsd.org/snapshots

    要编译或升级现有的 FreeBSD 系统到 FreeBSD-STABLE,使用 git 来检出所需分支的源代码。分支名称,例如 stable/13,在 www.freebsd.org/releng 上列出。

  3. 在编译或升级到 FreeBSD-STABLE 之前,请仔细阅读 /usr/src/Makefile 并按照 从源代码更新 FreeBSD 中的说明进行操作。阅读 FreeBSD-STABLE mailing list/usr/src/UPDATING 以了解其他引导程序的最新信息,有时在进行下一个版本发布的过程中可能需要这些信息。

26.5.3. The N-number

在追踪错误时,了解使用哪些版本的源代码创建了出现问题的系统非常重要。 FreeBSD 在内核中提供了编译的版本信息。uname(1) 可以检索到这些信息,例如:

% uname -v
FreeBSD 14.0-CURRENT #112 main-n247514-031260d64c18: Tue Jun 22 20:43:19 MDT 2021     fred@machine:/usr/home/fred/obj/usr/home/fred/git/head/amd64.amd64/sys/FRED

最后一个字段提供了有关内核名称、构建内核的人以及编译位置的信息。观察第四个字段,它由几个部分组成:

main-n247514-031260d64c18

main		(1)
n247514		(2)
031260d64c18	(3)
		(4)
1 Git 分支名称。注意:仅对项目发布的分支(mainstable/XXreleng/XX)进行 n-numbers 的比较才有效。本地分支的 n-numbers 将与其父分支的提交重叠。 <.> n-number 是从包含在该行中的 Git 哈希开始的 Git 存储库的提交线性计数。 <.> 检出树的 Git 哈希 <.> 当内核在具有未提交更改的树中构建时,有时会出现后缀 -dirty 。在此示例中,它不存在,因为 FRED 内核是从原始的检出构建的。

git rev-list 命令用于查找与 Git 哈希对应的 n-number。例如:

% git rev-list --first-parent --count 031260d64c18 (1)
247514 (2)
1 要翻译的 git 哈希(上面示例中的哈希被重用) <.> n-number。

通常这个数字并不是非常重要。然而,当提交了错误修复时,这个数字可以快速确定修复是否存在于当前运行的系统中。开发人员通常会引用提交的哈希值(或提供具有该哈希值的 URL),而不是 n-number,因为哈希值是一个易于识别的变更标识符,而 n-number 则不是。安全公告和勘误通知也会注明一个 n-number,可以直接与您的系统进行比较。当您需要使用浅层 Git 克隆时,您无法可靠地比较 n-number,因为 git rev-list 命令会计算仓库中的所有修订版本,而浅层克隆会省略一些修订版本。

26.6. 从源代码更新 FreeBSD

通过从源代码编译来更新 FreeBSD 相比二进制更新有几个优点。可以使用选项构建代码以充分利用特定的硬件。可以使用非默认设置构建基本系统的部分,或者在不需要或不希望的地方完全省略它们。与仅安装二进制更新相比,构建过程更新系统需要更长时间,但允许完全定制以生成定制版本的 FreeBSD。

26.6.1. 快速入门

这是一个快速参考,用于通过从源代码构建来更新 FreeBSD 的典型步骤。后面的章节将更详细地描述这个过程。

当从 mergemaster(8) 切换到 etcupdate(8) 时,第一次运行可能会错误地合并更改,从而生成虚假的冲突。为了防止这种情况发生,在更新源代码和构建新的系统之前,请执行以下步骤:

# etcupdate extract (1)
# etcupdate diff (2)
1 引导数据库的股票 /etc 文件;有关更多信息,请参阅 etcupdate(8)
2 在引导完成后检查差异。修剪不再需要的本地更改,以减少将来更新中冲突的可能性。
  • 更新和构建

    # git pull /usr/src  (1)
    check /usr/src/UPDATING  (2)
    # cd /usr/src          (3)
    # make -j4 buildworld  (4)
    # make -j4 kernel      (5)
    # shutdown -r now      (6)
    # etcupdate -p         (7)
    # cd /usr/src          (8)
    # make installworld    (9)
    # etcupdate -B         (10)
    # shutdown -r now      (11)
1 获取最新版本的源代码。有关获取和更新源代码的更多信息,请参阅 更新源代码
2 在从源代码构建之前或之后,请检查 /usr/src/UPDATING 是否有任何需要手动执行的步骤。
3 进入源代码目录。

编译整个世界,除了内核之外的一切。

1 编译并安装内核。这相当于执行 make buildkernel installkernel 命令。
2 重新启动系统以加载新内核。
3 在安装世界之前,需要更新和合并位于 /etc/ 的配置文件。
4 进入源代码目录。
5 安装世界。
6 更新并合并 /etc/ 中的配置文件。
7 重新启动系统以使用新构建的世界和内核。

26.6.2. 准备进行源代码更新

阅读 /usr/src/UPDATING 文件。该文件描述了在更新之前或之后必须执行的任何手动步骤。

26.6.3. 更新源代码

FreeBSD 源代码位于 /usr/src/ 目录下。更新源代码的首选方法是通过 Git 版本控制系统。请确认源代码已经处于版本控制下:

# cd /usr/src
# git remote --v
origin  https://git.freebsd.org/src.git (fetch)
origin  https://git.freebsd.org/src.git (push)

这表示 /usr/src/ 已经受到版本控制,可以使用 git(1) 进行更新。

# git pull /usr/src

如果目录最近没有更新,更新过程可能需要一些时间。完成后,源代码将是最新的,可以开始下一节中描述的构建过程。

获取源代码:

如果输出显示 fatal: not a git repository,则表示文件丢失或使用了不同的安装方法。需要重新检出源代码。

表 1. FreeBSD 版本和存储库分支
uname -r 的输出结果 仓库路径 描述

X.Y-RELEASE

releng/X.Y

发布版本加上仅包含关键安全和错误修复补丁。这个分支推荐给大多数用户使用。

X.Y-STABLE

stable/X

稳定版本加上该分支上的所有额外开发。STABLE 指的是应用程序二进制接口(ABI)不会改变,因此为早期版本编译的软件仍然可以运行。例如,为了在 FreeBSD 10.1 上运行而编译的软件仍然可以在稍后编译的 FreeBSD 10-STABLE 上运行。

稳定分支偶尔会有错误或不兼容性,可能会影响用户,尽管这些问题通常会很快修复。

X-CURRENT

main

最新的未发布开发版本的 FreeBSD。CURRENT 分支可能存在重大错误或不兼容性问题,仅推荐给高级用户使用。

使用 uname(1) 命令确定正在使用的 FreeBSD 版本。

# uname -r
13.2-RELEASE

根据 FreeBSD 版本和存储库分支,用于更新 13.2-RELEASE 的源码具有存储路径 releng/13.2 。在检出源码时使用该路径:

# mv /usr/src /usr/src.bak (1)
# git clone --branch releng/13.2 https://git.FreeBSD.org/src.git /usr/src (2)
1 将旧目录移开。如果该目录没有本地修改,可以删除。
2 将从 FreeBSD 版本和存储库分支 的路径添加到存储库 URL 中。第三个参数是本地系统上源代码的目标目录。

26.6.4. 从源代码构建

整个 世界 或者说除了内核外的所有操作系统被编译。首先这样做是为了提供最新的工具来构建内核。然后构建内核本身:

# cd /usr/src
# make buildworld
# make buildkernel

编译后的代码被写入到 /usr/obj

这些是基本步骤。下面描述了用于控制构建的其他选项。

26.6.4.1. 执行清理构建

一些 FreeBSD 构建系统的版本会在临时对象目录 /usr/obj 中保留先前编译的代码。这可以通过避免重新编译未更改的代码来加快后续的构建过程。要强制进行全面的清理重建,请在开始构建之前使用 cleanworld 命令。

# make cleanworld

26.6.4.2. 设置作业数量

增加多核处理器上的构建作业数量可以提高构建速度。使用 sysctl hw.ncpu 确定核心数。处理器和不同版本的 FreeBSD 使用的构建系统各不相同,因此测试是唯一确定不同作业数量如何影响构建速度的可靠方法。作为起点,考虑在核心数的一半和两倍之间选择值。作业数量使用 -j 参数指定。

例 1. 增加构建作业的数量

使用四个作业构建世界和内核:

# make -j4 buildworld buildkernel

26.6.4.3. 仅构建内核

如果源代码发生了变化,必须完成 buildworld。之后,可以随时运行 buildkernel 来构建内核。要仅构建内核:

# cd /usr/src
# make buildkernel

26.6.4.4. 构建自定义内核

标准的 FreeBSD 内核基于一个名为 GENERIC 的_内核配置文件_。 GENERIC 内核包含了最常用的设备驱动程序和选项。有时候,构建一个自定义内核是有用或必要的,可以添加或删除设备驱动程序或选项以满足特定需求。

例如,某人正在开发一台内存严重有限的小型嵌入式计算机,可以删除不需要的设备驱动程序或选项,以使内核稍微变小。

内核配置文件位于 /usr/src/sys/arch/conf/ ,其中 arch 是从 uname -m 命令的输出中获取的。在大多数计算机上,这个值是 amd64 ,因此配置文件目录为 /usr/src/sys/amd64/conf/

/usr/src 可以被删除或重新创建,因此最好将自定义内核配置文件保存在一个单独的目录中,比如 /root。将内核配置文件链接到 conf 目录中。如果该目录被删除或覆盖,可以将内核配置重新链接到新的目录中。

可以通过复制 GENERIC 配置文件来创建自定义配置文件。在这个例子中,新的自定义内核是用于存储服务器的,所以被命名为 STORAGESERVER

# cp /usr/src/sys/amd64/conf/GENERIC /root/STORAGESERVER
# cd /usr/src/sys/amd64/conf
# ln -s /root/STORAGESERVER .

然后编辑 /root/STORAGESERVER,根据 config(5) 中所示的方式添加或删除设备或选项。

通过在命令行中设置 KERNCONF 为内核配置文件来构建自定义内核:

# make buildkernel KERNCONF=STORAGESERVER

26.6.5. 安装编译后的代码

在完成 buildworldbuildkernel 步骤后,新的内核和系统已被安装:

# cd /usr/src
# make installkernel
# shutdown -r now
# cd /usr/src
# make installworld
# shutdown -r now

如果构建了自定义内核,则还必须设置 KERNCONF 以使用新的自定义内核:

# cd /usr/src
# make installkernel KERNCONF=STORAGESERVER
# shutdown -r now
# cd /usr/src
# make installworld
# shutdown -r now

26.6.6. 完成更新

完成更新还需要进行一些最后的任务。任何已修改的配置文件都将与新版本合并,过时的库将被定位并删除,然后系统将重新启动。

26.6.6.1. 使用 etcupdate(8) 合并配置文件

etcupdate(8) 是一个用于管理不作为 installworld 的一部分而更新的文件的工具,例如位于 /etc/ 中的文件。它通过对这些文件所做的更改与本地版本进行三方合并来管理更新。与 mergemaster(8) 的交互提示相比,它还旨在最小化用户干预的程度。

通常情况下,etcupdate(8) 在执行任务时不需要任何特定的参数。然而,第一次使用 etcupdate(8) 时,有一个方便的中间命令用于检查将要执行的操作:

# etcupdate diff

该命令允许用户审计配置更改。

如果 etcupdate(8) 无法自动合并文件,则可以通过手动交互来解决合并冲突,方法是执行以下命令:

# etcupdate resolve

当从 mergemaster(8) 切换到 etcupdate(8) 时,第一次运行可能会错误地合并更改,从而生成虚假的冲突。为了防止这种情况发生,在更新源代码和构建新的系统之前,请执行以下步骤:

# etcupdate extract (1)
# etcupdate diff (2)
1 引导数据库的股票 /etc 文件;有关更多信息,请参阅 etcupdate(8)
2 在引导完成后检查差异。修剪不再需要的本地更改,以减少将来更新中冲突的可能性。

26.6.6.2. 使用 mergemaster(8) 合并配置文件

mergemaster(8) 提供了一种将对系统配置文件所做的更改与这些文件的新版本合并的方法。 mergemaster(8)etcupdate(8) 的替代方法。使用 -Ui 选项,mergemaster(8) 会自动更新未被用户修改的文件,并安装尚未存在的新文件。

# mergemaster -Ui

如果一个文件需要手动合并,交互式显示将允许用户选择保留文件的哪些部分。有关更多信息,请参阅 mergemaster(8)

如果没有使用标准的 /usr/src 路径,必须向 mergemaster(8) 传递另一个参数:

# mergemaster -Ui PATH_TO_SRC

26.6.6.3. 检查过时的文件和库

更新后可能会保留一些过时的文件或目录。这些文件可以位于以下位置:

# make check-old

删除:

# make delete-old

还可能存在一些过时的库。可以使用以下方法检测到这些库:

# make check-old-libs

也删除

# make delete-old-libs

当删除了这些旧库后,仍在使用这些旧库的程序将停止工作。这些程序必须在删除旧库后重新构建或替换。

当所有旧文件或目录都被确认为安全可删除时,可以通过在命令中设置 BATCH_DELETE_OLD_FILES 来避免按下 yEnter 来删除每个文件。例如:

# make BATCH_DELETE_OLD_FILES=yes delete-old-libs

26.6.6.4. 更新后重新启动

更新完成后的最后一步是重新启动计算机,以使所有更改生效:

# shutdown -r now

26.7. 多台机器的追踪

当多台机器需要跟踪同一个源代码树时,让每台系统都下载源代码并重新构建会浪费磁盘空间、网络带宽和 CPU 周期。解决方案是让一台机器完成大部分工作,而其他机器通过 NFS 挂载这个工作。本节介绍了一种实现方法。有关使用 NFS 的更多信息,请参考 “网络文件系统(NFS)”

首先,确定一组将运行相同二进制文件的机器,称为 构建集。每台机器可以有自定义的内核,但将运行相同的用户空间二进制文件。从该集合中选择一台机器作为 构建机器,用于构建世界和内核。理想情况下,这是一台速度快且具有足够空闲 CPU 来运行 make buildworldmake buildkernel 的机器。

选择一台机器作为 测试机器,在将软件更新投入生产之前对其进行测试。这台机器必须能够承受较长时间的停机。它可以是构建机器,但不一定是。

此构建集中的所有机器都需要通过 NFS 从构建机器挂载 /usr/obj/usr/src。对于多个构建集,/usr/src 应该在一个构建机器上,并在其他机器上通过 NFS 挂载。

确保构建集中所有机器上的 /etc/make.conf/etc/src.conf 与构建机器保持一致。这意味着构建机器必须构建基本系统的所有部分,以便构建集中的任何机器都可以安装。此外,每个构建机器应该使用 /etc/make.conf 中的 KERNCONF 设置其内核名称,并且构建机器应该在其 KERNCONF 中列出所有这些内核,将自己的内核列在第一位。构建机器必须在 /usr/src/sys/arch/conf 中拥有每个机器的内核配置文件。

在构建机上,按照 从源代码更新 FreeBSD 中描述的方式构建内核和世界,但不要在构建机上安装任何东西。相反,将构建好的内核安装在测试机上。在测试机上,通过 NFS 挂载 /usr/src/usr/obj。然后,运行 shutdown now 进入单用户模式,以便安装新的内核和世界,并像往常一样运行 mergemaster。完成后,重新启动以返回到正常的多用户操作。

在验证测试机上的一切正常工作后,使用相同的步骤在构建集中的每台其他机器上安装新软件。

相同的方法可以用于 ports 树。第一步是通过 NFS 将 /usr/ports 共享给构建集中的所有机器。要配置 /etc/make.conf 以共享 distfiles,将 DISTDIR 设置为一个由 NFS 挂载映射到 root 用户的可写共享目录。如果要在本地构建端口,则每台机器应将 WRKDIRPREFIX 设置为本地构建目录。或者,如果构建系统要构建并分发软件包给构建集中的机器,则在构建系统上将 PACKAGES 设置为类似于 DISTDIR 的目录。

26.8. 在非 FreeBSD 主机上构建

从历史上看,构建 FreeBSD 需要一个 FreeBSD 主机。如今,FreeBSD 可以在 Linux 发行版和 macOS 上构建。

在非 FreeBSD 主机上构建 FreeBSD 的推荐方法是使用 tools/build/make.py 脚本。该脚本作为 bmake 的包装器,bmake 是 FreeBSD 使用的 make 实现。它确保了必要的工具,包括实际的 FreeBSD 的 make(1) ,被引导并且构建环境被正确配置。特别是,它设置了外部工具链变量,如 XCCXLD 等。此外,该脚本可以将任何额外的命令参数,如 -j 4 用于并行构建或特定的 make 目标,传递给 bmake

最近版本的 bmake 也可以替代 tools/build/make.py 脚本。但在这种情况下,需要手动设置所需的环境变量(最简单的方法是运行 tools/build/make.py --debug 来获取它们的列表)。

否则,构建 FreeBSD 所需的先决条件列表相当简短。实际上,它只需要安装几个依赖项。

在 macOS 上,唯一的依赖是 LLVM。必要的依赖项可以通过包管理器(例如,Homebrew)进行安装。

brew install llvm

在 Linux 发行版上,安装 Clang 10.0 或更新版本,以及 libarchive 和 libbz2 的头文件(通常打包为 libarchive-dev 和 libbz2-dev)。

一旦安装了依赖项,主机就应该能够构建 FreeBSD。

例如,下面的 tools/build/make.py 命令构建整个项目:

MAKEOBJDIRPREFIX=/tmp/obj tools/build/make.py -j 8 TARGET=arm64 TARGET_ARCH=aarch64 buildworld

它在 8 个 CPU 上为目标 aarch64:arm64 构建世界,并使用 /tmp/obj 作为对象文件。请注意,在非 FreeBSD 主机上构建时,变量 MAKEOBJDIRPREFIXTARGETTARGET_ARCH 是必需的。此外,请确保创建由 MAKEOBJDIRPREFIX 环境变量指向的对象目录。

请参考 arch(7)build(7) 以获取更多详细信息。


上次修改时间: September 18, 2024 by fiercex