NanoBSD 简介

商标

FreeBSD 是 FreeBSD 基金会的注册商标。

许多制造商和销售商用于区分其产品的名称被认为是商标。在本文档中出现这些名称的地方,如果 FreeBSD 项目知道商标声明,则这些名称后面将加上“™”或“®”符号。

摘要

本文档提供有关 NanoBSD 工具的信息,这些工具可用于创建适用于嵌入式应用程序的 FreeBSD 系统映像,适用于 USB 密钥、存储卡或其他大容量存储介质。


1. NanoBSD 简介

NanoBSD 是由 Poul-Henning Kamp <phk@FreeBSD.org> 开发,现在由 Warner Losh <imp@FreeBSD.org> 维护的工具。它为嵌入式应用程序创建一个 FreeBSD 系统映像,适用于 USB 密钥、存储卡或其他大容量存储介质。

它可以用于构建专门的安装映像,这些映像设计用于易于安装和维护通常称为“计算机设备”的系统。计算机设备将硬件和软件捆绑在一起,这意味着所有应用程序都预先安装。该设备插入现有的网络并可以立即(几乎)开始工作。

NanoBSD 的特点包括

  • 端口和软件包与 FreeBSD 中一样工作 - 每个应用程序都可以在 NanoBSD 映像中安装和使用,与 FreeBSD 中相同。

  • 无功能缺失 - 如果可以用 FreeBSD 完成某些操作,则可以使用 NanoBSD 完成相同的操作,除非在创建 NanoBSD 映像时明确从映像中删除了特定功能或特性。

  • 运行时所有内容都是只读的 - 可以安全地拔掉电源插头。在系统非正常关闭后,无需运行 fsck(8)

  • 易于构建和自定义 - 只需使用一个 shell 脚本和一个配置文件,就可以构建满足任意要求的缩减和自定义映像。

2. NanoBSD 如何使用

2.1. NanoBSD 的设计

一旦映像存在于介质上,就可以启动 NanoBSD。默认情况下,大容量存储介质被分成三个部分

  • 两个映像分区:code#1code#2

  • 配置文件分区,可以在运行时挂载到 /cfg 目录下。

这些分区通常以只读方式挂载。

/etc/var 目录是 md(4)(malloc)磁盘。

配置文件分区保留在 /cfg 目录下。它包含 /etc 目录的文件,并在系统启动后短暂以只读方式挂载,因此如果希望更改在系统重启后保留,则需要将修改后的文件从 /etc 复制回 /cfg 目录。

示例 1. 对 /etc/resolv.conf 进行持久更改
# vi /etc/resolv.conf
[...]
# mount /cfg
# cp /etc/resolv.conf /cfg
# umount /cfg

包含 /cfg 的分区应该只在启动时和覆盖配置文件时挂载。

始终挂载 /cfg 不是一个好主意,尤其是在 NanoBSD 系统从可能会受到大量写入分区影响的大容量存储介质上运行时(例如当文件系统同步器将数据刷新到系统磁盘时)。

2.2. 构建 NanoBSD 映像

构建 NanoBSD 需要 FreeBSD 的源代码。要获取源代码

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

有关更多详细信息,请按照以下步骤操作 这里

NanoBSD 映像是使用简单的 nanobsd.sh shell 脚本构建的,该脚本位于 /usr/src/tools/tools/nanobsd 目录中。此脚本创建了一个映像,可以使用 dd(1) 实用程序将其复制到存储介质上。

构建 NanoBSD 映像所需的命令如下

# cd /usr/src/tools/tools/nanobsd (1)
# sh nanobsd.sh (2)
# cd /usr/obj/nanobsd.full (3)
# dd if=_.disk.full of=/dev/da0 bs=64k (4)
1将当前目录更改为 NanoBSD 构建脚本的基目录。
2启动构建过程。
3将当前目录更改为构建的映像所在的目录。
4将 NanoBSD 安装到存储介质上。

2.2.1. 构建 NanoBSD 映像时的选项

构建 NanoBSD 映像时,可以在命令行上向 nanobsd.sh 传递几个构建选项。这些选项会对构建过程产生重大影响。

一些选项用于详细程度

  • -h: 打印帮助摘要页面。

  • -q: 使输出更安静。

  • -v: 使输出更详细

其他一些选项可用于限制构建过程。有时,没有必要从源代码重新构建所有内容,尤其是在已经构建了映像并且只进行了少量更改的情况下。

  • -k: 不要构建内核

  • -w: 不要构建 world

  • -b: 不要构建内核和 world

  • -i: 不要构建磁盘映像。由于不会创建文件,因此无法将其 dd(1) 到存储介质。

  • -f: 不要构建第一个分区(这对于升级很有用)的磁盘映像

  • -n: 在 buildworldbuildkernel 中添加 -DNO_CLEAN。此外,所有在先前运行中已构建的文件都将保留。

可以使用配置文件来调整所需的所有元素。使用 -c 加载它

最后几个选项是

  • -K: 不要安装内核。没有内核的磁盘映像将无法实现正常的引导序列。

2.2.2. 完整的映像构建过程

完整的映像构建过程会经历很多步骤。采取的确切步骤将取决于启动脚本时选择的选项。假设脚本没有任何特定选项运行,那么将会发生以下情况。

  1. run_early_customize: 在提供的配置文件中定义的命令。

  2. clean_build: 只需通过删除先前构建的文件来清理构建环境。

  3. make_conf_build: 从 CONF_WORLDCONF_BUILD 变量组装 make.conf。

  4. build_world: 构建 world。

  5. build_kernel: 构建内核文件。

  6. clean_world: 清理目标目录。

  7. make_conf_install: 从 CONF_WORLDCONF_INSTALL 变量组装 make.conf。

  8. install_world: 安装在 buildworld 期间构建的所有文件。

  9. install_etc: 根据 make distribution 命令,在 /etc 目录中安装必要的文件。

  10. setup_nanobsd_etc: 此时进行的第一个特定于 NanoBSD 的配置。创建 /etc/diskless 并将根文件系统定义为只读。

  11. install_kernel: 安装内核和模块文件。

  12. run_customize: 将调用用户定义的所有自定义例程。

  13. setup_nanobsd: 设置特殊的配置目录布局。将 /usr/local/etc 移动到 /etc/local 并从 /etc/local/usr/local/etc 创建一个符号链接。

  14. prune_usr: 从 /usr 中删除空目录。

  15. run_late_customize: 此时可以运行最后的自定义脚本。

  16. fixup_before_diskimage: 在元日志中列出所有安装的文件

  17. create_diskimage: 根据提供的磁盘几何参数创建实际的磁盘映像。

  18. last_orders: 目前不做任何事情。

2.3. 自定义 NanoBSD 映像

这可能是 NanoBSD 最重要和最有趣的特性。在使用 NanoBSD 进行开发时,您也会花费大部分时间在这里。

调用以下命令将强制 nanobsd.sh 从当前目录中的 myconf.nano 读取其配置

# sh nanobsd.sh -c myconf.nano

自定义通过两种方式完成

  • 配置选项

  • 自定义函数

2.3.1. 配置选项

使用配置设置,可以配置传递给 NanoBSD 构建过程的 buildworldinstallworld 阶段的选项,以及传递给 NanoBSD 主构建过程的内部选项。通过这些选项,可以缩减系统,使其仅占用 64MB。您可以使用配置选项进一步缩减 FreeBSD,直到它只包含内核和用户空间中的两三个文件。

配置文件包含配置选项,这些选项会覆盖默认值。最重要的指令是

  • NANO_NAME - 构建的名称(用于构建工作目录名称)。

  • NANO_SRC - 用于构建映像的源代码树的路径。

  • NANO_KERNEL - 用于构建内核的内核配置文件的名称。

  • CONF_BUILD - 传递给构建的 buildworld 阶段的选项。

  • CONF_INSTALL - 传递给构建的 installworld 阶段的选项。

  • CONF_WORLD - 传递给构建的 buildworldinstallworld 阶段的选项。

  • FlashDevice - 定义要使用的媒体类型。查看 FlashDevice.sub 获取更多详细信息。

根据所需的 NanoBSD 类型,还有许多其他可能相关的配置选项。

2.3.1.1. 通用定制

设计上,有三个阶段可以通过在提供的配置文件中设置变量来进行影响构建过程的更改。

  • run_early_customize:在其他任何事情发生之前。

  • run_customize:在所有标准文件都已布局之后。

  • run_late_customize:在构建过程的最后阶段,就在实际构建 NanoBSD 映像之前。

要在这些步骤中的任何一个步骤中自定义 NanoBSD 映像,最好向相应变量添加一个特定值。

NANO_EARLY_CUSTOMIZE 变量在构建过程的第一步使用。此时,没有关于如何使用该变量的示例,但将来可能会更改。

NANO_CUSTOMIZE 变量在内核、世界等配置文件安装后以及 etc 文件设置为 NanoBSD 安装后使用。因此,这是在构建过程中调整配置选项和添加软件包的正确步骤,例如在 cust_nobeastie 示例中。

NANO_LATE_CUSTOMIZE 变量在创建磁盘映像之前使用,因此它是更改任何内容的最后时刻。请记住,setup_nanobsd 例程已执行,并且 etcconfcfg 目录和子目录已修改,因此此时不应该更改它们。相反,可以添加或删除特定文件。

2.3.1.2. 启动选项

还有一些变量可以更改 NanoBSD 映像的启动方式。两个选项传递给 boot0cfg(8) 以初始化磁盘映像的引导扇区。

  • NANO_BOOT0CFG

  • NANO_BOOTLOADER

使用 NANO_BOOTLOADER 可以选择引导加载程序文件。最常见的选项是 boot0sioboot0 之间,具体取决于设备是否有串行端口。最好避免提供不同的引导加载程序,但这是可能的。为此,最好查看 FreeBSD 手册 中关于引导过程的章节。

使用 NANO_BOOT0CFG,可以调整引导过程,例如选择 NanoBSD 映像实际启动的分区。最好查看 boot0cfg(8) 页面,然后再更改此变量的默认值。一个可能需要更改的选项是引导过程的超时时间。为此,可以将 NANO_BOOT0CFG 变量更改为 "-o packet -s 1 -m 3 -t 36"。这样,引导过程将在大约 2 秒后启动;因为很少需要在实际启动之前等待 10 秒。

了解一下:NANO_BOOT2CFG 变量仅在 cust_comconsole 例程中使用,该例程可以在 NANO_CUSTOMIZE 步骤中调用,前提是设备具有串行端口,并且所有控制台输入和输出都必须通过它进行。请务必检查串行端口的相关参数,因为设置错误的参数值会使其失效。

2.3.1.3. 磁盘映像创建

引导过程的最后一步是磁盘映像创建。通过此步骤,NanoBSD 脚本提供了一个文件,可以简单地将其复制到设备的磁盘上,这将使其启动并开始运行。

为了使脚本生成可用的磁盘映像,需要正确设置许多变量。

  • NANO_DRIVE 变量必须设置为运行时媒体的驱动器名称。通常,默认值 ada0(表示设备上第一个 IDE/ATA/SATA 设备)应该是正确的,但也可以使用其他类型的存储,例如 USB 密钥,在这种情况下,它更可能是 da0。

  • NANO_MEDIASIZE 变量必须设置为将要使用的存储介质的大小(以 512 字节扇区计)。如果您设置错误,NanoBSD 映像可能根本无法启动,并且在启动时会出现一条关于磁盘几何形状不正确的警告消息。

  • /etc/var/tmp 目录在启动时被分配为 md(4)(malloc)磁盘;因此它们的大小可以根据设备的需求进行调整。NANO_RAM_ETCSIZE 变量设置 /etc 的大小;NANO_RAM_TMPVARSIZE 变量设置 /var/tmp 目录的大小,因为 /tmp 符号链接到 /var/tmp。默认情况下,两个 malloc 磁盘的大小都设置为 20 MB。它们始终可以更改,但通常 /etc 的大小不会增长太多,因此 20 MB 是一个不错的起点,而 /var 尤其是在 /tmp 方面,如果不小心的话,可能会增长得更大。对于内存受限的系统,可以选择较小的文件系统大小。

  • 由于 NanoBSD 主要用于为设备构建系统映像,因此假设使用的存储介质将相对较小。因此,布局的文件系统被配置为具有较小的块大小 (4 Kb) 和较小的碎片大小 (512b)。可以使用 NANO_NEWFS 变量修改文件系统的配置选项,但语法必须符合 newfs(8) 命令格式。此外,默认情况下,文件系统启用了软更新。可以查看 FreeBSD 手册 以了解这一点。

  • 可以使用 NANO_CODESIZENANO_CONFSIZENANO_DATASIZE 将不同的分区大小设置为 512 字节扇区的倍数。NANO_CODESIZE 定义前两个映像分区的的大小:code#1code#2。它们必须足够大,才能容纳所有作为 buildworldbuildkernel 过程的结果而产生的文件。NANO_CONFSIZE 定义配置文件分区的的大小,因此它不需要很大;但不要使其太小,以至于无法容纳所有配置文件。最后,NANO_DATASIZE 定义可选分区的的大小,该分区可以在设备上使用。最后一个分区可以用于,例如,保存磁盘上动态创建的文件。

2.3.2. 自定义函数

可以使用配置文件中的 shell 函数微调 NanoBSD。以下示例说明了自定义函数的基本模型。

cust_foo () (
	echo "bar=baz" > \
		${NANO_WORLDDIR}/etc/foo
)
customize_cmd cust_foo

以下是一个更有用的自定义函数示例,它将 /etc 目录的默认大小从 5 MB 更改为 30 MB。

cust_etc_size () (
	cd ${NANO_WORLDDIR}/conf
	echo 30000 > default/etc/md_size
)
customize_cmd cust_etc_size

有几个默认的预定义自定义函数可供使用。

  • cust_comconsole - 在 VGA 设备(/dev/ttyv* 设备节点)上禁用 getty(8) 并启用使用 COM1 串行端口作为系统控制台。

  • cust_allow_ssh_root - 允许 root 通过 sshd(8) 登录。

  • cust_install_files - 从 nanobsd/Files 目录安装文件,该目录包含一些有用的系统管理脚本。

  • cust_pkgng - 从 nanobsd/Pkg 目录安装软件包(还需要 pkg-* 软件包才能引导)。

2.3.3. 添加软件包

可以将软件包添加到 NanoBSD 映像中,以提供设备上的特定功能。为此,您可以:

  • cust_pkgng 添加到 NANO_CUSTOMIZE 变量中,或者

  • 在自定义配置文件中添加 'customize_cmd cust_pkgng' 命令。

两种方法都达到了相同的结果:启动 cust_pkgng 例程。此例程将遍历 NANO_PACKAGE_DIR 目录,以查找所有软件包或 NANO_PACKAGE_LIST 变量中的软件包列表。

在标准 FreeBSD 环境中通过 pkg 安装应用程序时,通常安装过程会将配置文件放在 usr/local/etc 目录中,并将启动脚本放在 /usr/local/etc/rc.d 目录中。因此,在安装必要的软件包后,需要对其进行配置,以便它们能够立即启动。为此,必须将必要的配置文件安装到正确的目录中。这可以通过编写专门的例程来实现,或者可以使用通用的 cust_install_files 例程来从 /usr/src/tools/tools/nanobsd/Files 目录中正确布置文件。通常,每个软件包都需要在 /etc/rc.conf 中添加一个语句(有时是多个语句)。

2.3.4. 配置文件示例

用于构建自定义 NanoBSD 映像的配置文件的完整示例可以是

NANO_NAME=custom
NANO_SRC=/usr/src
NANO_KERNEL=MYKERNEL
NANO_IMAGES=2

CONF_BUILD='
WITHOUT_KLDLOAD=YES
WITHOUT_NETGRAPH=YES
WITHOUT_PAM=YES
'

CONF_INSTALL='
WITHOUT_ACPI=YES
WITHOUT_BLUETOOTH=YES
WITHOUT_FORTRAN=YES
WITHOUT_HTML=YES
WITHOUT_LPR=YES
WITHOUT_MAN=YES
WITHOUT_SENDMAIL=YES
WITHOUT_SHAREDOCS=YES
WITHOUT_EXAMPLES=YES
WITHOUT_INSTALLLIB=YES
WITHOUT_CALENDAR=YES
WITHOUT_MISC=YES
WITHOUT_SHARE=YES
'

CONF_WORLD='
WITHOUT_BIND=YES
WITHOUT_MODULES=YES
WITHOUT_KERBEROS=YES
WITHOUT_GAMES=YES
WITHOUT_RESCUE=YES
WITHOUT_LOCALES=YES
WITHOUT_SYSCONS=YES
WITHOUT_INFO=YES
'

FlashDevice SanDisk 1G

cust_nobeastie() (
	touch ${NANO_WORLDDIR}/boot/loader.conf
	echo "beastie_disable=\"YES\"" >> ${NANO_WORLDDIR}/boot/loader.conf
)

customize_cmd cust_comconsole
customize_cmd cust_install_files
customize_cmd cust_allow_ssh_root
customize_cmd cust_nobeastie

所有构建和安装编译选项都可以在 src.conf(5) 手册页中找到,但并非所有选项都可以在构建 NanoBSD 映像时使用或应该使用。构建和安装选项应根据正在构建的映像的需要进行定义。

例如,可能不需要 ftp 客户端和服务器。将 WITHOUT_FTP=TRUE 添加到 CONF_BUILD 部分中的配置文件将避免构建它们。此外,如果 NanoBSD 设备不用于构建程序,则可以在 CONF_INSTALL 部分中添加 WITHOUT_BINUTILS=TRUE;但在 CONF_BUILD 部分中不要添加,因为它们将用于构建 NanoBSD 映像。

不通过编译选项构建特定的程序集可以缩短整体构建时间并降低磁盘映像所需的大小,而不安装相同的特定程序集不会降低整体构建时间。

2.4. 更新 NanoBSD

NanoBSD 的更新过程相对简单。

  1. 像往常一样构建新的 NanoBSD 映像。

  2. 将新映像上传到正在运行的 NanoBSD 设备的未使用分区中。

    此步骤与初始 NanoBSD 安装最重要的区别在于,现在不是使用 _.disk.full(其中包含整个磁盘的映像),而是安装了 _.disk.image 映像(其中包含单个系统分区的映像)。

  3. 重新启动,然后从新安装的分区启动系统。

  4. 如果一切顺利,升级就完成了。

  5. 如果出现问题,请重新启动回上一个分区(其中包含旧的有效映像),以便尽快恢复系统功能。修复新构建的任何问题,然后重复该过程。

要将新映像安装到正在运行的 NanoBSD 系统上,可以使用 updatep1updatep2 脚本,这两个脚本位于 /root 目录中,具体取决于哪个分区正在运行当前系统。

根据哪个服务在提供新 NanoBSD 映像的主机上可用以及首选哪种类型的传输,可以检查以下三种方法之一。

2.4.1. 使用 ftp(1)

如果传输速度是首要考虑因素,请使用以下示例

# ftp myhost
get _.disk.image "| sh updatep1"

2.4.2. 使用 ssh(1)

如果优先考虑安全传输,请考虑使用以下示例

# ssh myhost cat _.disk.image.gz | zcat | sh updatep1

2.4.3. 使用 nc(1)

如果远程主机既没有运行 ftpd(8) 也没有运行 sshd(8) 服务,请尝试以下示例

  1. 首先,在提供镜像的服务器上打开一个 TCP 监听器,并使其将镜像发送到客户端

    myhost# nc -l 2222 < _.disk.image

    确保所使用的端口未被防火墙阻止,以便接收来自 NanoBSD 主机的传入连接。

  2. 连接到提供新镜像的服务器,并执行 updatep1 脚本

    # nc myhost 2222 | sh updatep1

上次修改时间: 2023 年 11 月 27 日,作者 Minsoo Choo