构建您自己的 Live CD

作者:Daniel Barlow

您可能听说过 Knoppix,这是一个基于 Debian 的发行版,它将 2GB 的应用程序压缩到一张独立的 CD 中。它已被用作 Linux 演示工具、救援盘,甚至作为 Debian 安装程序。它启发了一系列相关的项目,范围从包含 Knoppix 的 CD(加上或减去一些额外的软件包)到系统的完全重新架构。

我最近开始制作一个用于产品演示的 live CD。我首先拆解了 Knoppix CD,看看它是如何工作的,最终得到一个 Makefile 和一些辅助文件,这些文件显然受到 Knoppix 的启发,但几乎没有衍生代码。这就是我学到的。

简要介绍

如果您将 Knoppix CD 放入 CD-ROM 驱动器并挂载它,您很快就会注意到它看起来不太像普通的 Linux 安装。有一些图形文件和一个免费音乐曲目,但没有 init,没有 /dev,也没有 /bin。魔力在于名为 /KNOPPIX/KNOPPIX 的大文件,这是一个为 cloop 设备压缩的 ISO9660 文件系统镜像。

内核中的标准 loop 设备允许您访问文件系统中的文件,就像它是一个设备一样;对设备块的请求被映射到对底层文件中块的请求。因为您可以挂载该设备,这意味着您可以创建文件系统镜像并像访问真正的硬件磁盘一样访问它们。如果您从网上下载了 Knoppix,您将拥有一个可以 loop 挂载以查看其内容的 ISO9660 镜像

# mkdir /tmp/knoppix-cd
# mount -o loop -r \
$HOME/KNOPPIX_V3.3-2003-09-24-EN.iso /tmp/knoppix-cd

cloop 压缩 loop 设备更进一步。在这种 loop 设备的改进中,每个块都使用 gzip 压缩,并在访问时透明地解压缩。/KNOPPIX/KNOPPIX 是此设备的镜像,在启动期间挂载——这就是 Knoppix 如何将 2GB 内容放入 650MB CD 中的方法。

如果您只想查看内部文件系统,则无需在常用的内核中安装 cloop。安装 cloop-utils 软件包并使用 extract_compressed_fs,如下所示。您需要在 /var/tmp 或您决定放置镜像的任何位置大约 2GB 的可用空间

# mkdir /tmp/knoppix-cloop
# extract_compressed_fs \
   /tmp/knoppix-cd/KNOPPIX/KNOPPIX \
    >/var/tmp/KNOPPIX-cloop
# mount -o loop /var/tmp/KNOPPIX-cloop \
   /tmp/knoppix-cloop
# find /tmp/knoppix-cloop -print

您可以查看,但不能修改——ISO9660 文件系统是只读的。要修改发行版,您首先需要将两个文件系统镜像复制到普通目录

# mkdir $HOME/my-knoppix-tree  \
    $HOME/my-knoppix-cd-tree
# tar -C /tmp/knoppix-cloop -cf - . | \
    tar -C $HOME/my-knoppix-tree -xvpf -
# tar -C /tmp/knoppix-cd -cf - . | \
    tar -C $HOME/my-knoppix-cd-tree -xvpf -
# umount /tmp/knoppix-cd /tmp/knoppix-cloop

现在,您可以尽情修改了。最方便的方法是使用 chroot 命令将根目录更改为 Knoppix 内部树

# mount -t proc none $HOME/my-knoppix-tree/proc
# cp /etc/resolv.conf \
$HOME/my-knoppix-tree/etc/resolv.conf
# chroot $HOME/my-knoppix-tree /bin/sh

从这里,您可以使用所有常用的 Debian 软件包管理命令(dpkg、apt-get 等)来安装或删除您喜欢的任何内容。完成后,退出 chroot 并卸载 proc,除非您想将开发系统的进程列表永久保存在 CD 上。然后,使用create_compressed_treemkisofs来创建内部和外部镜像

# mkisofs -L -R -l -V "KNOPPIX ISO9660" -v \
-allow-multidot $HOME/my-knoppix-tree | \
create_compressed_fs - 65536 > \
$HOME/my-knoppix-cd/KNOPPIX/KNOPPIX

# mkisofs -l -r -J -V "KNOPPIX with local stuff" \
-hide-rr-moved -v -b KNOPPIX/boot-en.img \
-c KNOPPIX/boot.cat -o knoppix.iso \
$HOME/my-knoppix-cd

最后,将 knoppix.iso 刻录到 CD-ROM 并启动它。如果您愿意,可以使用 Bochs 或 VMware 在不刻录的情况下进行测试。

深入探讨

然而,当您想要更广泛的自定义时,这种简单的方法开始失效。例如,如果您希望 X 启动特定的窗口管理器,但不希望使用所有 GNOME 或 KDE,则必须自己编辑脚本。这并不难做到,但这意味着您实际上已经 fork 了 Knoppix。当新的 Knoppix 版本发布时,您将不得不再次执行此操作。此外,如果您打算商业销售基于 Knoppix 的 CD,则需要遵守您分发的所有软件的许可证,这意味着确切了解 CD 上包含的内容。我查看的 Knoppix 版本包含一些并非来自 Debian 软件包的文件,有时甚至不是自由软件。

那么,我们是否可以从其他地方开始呢?幸运的是,答案是肯定的。在 Progeny(将其安装程序捐赠给 Debian 项目)、Klaus Knopper(Knoppix 的作者和 cloop 设备的创建者)以及其他 Debian 开发人员(他们正在努力将他的自定义代码添加到 Debian 主要存储库中)的共同努力下,今天我们仅使用 Debian 软件包就可以从头开始构建一个尚可接受的 live CD 系统。本文的其余部分将描述如何操作。

下载

包含此处引用的所有脚本和文件的 tarball 可以在 ftp.linux.org.uk/~dan/livecd 找到。由于空间限制,本文本身没有重现大部分代码。它主要由 Makefile 驱动,包含一些 shell 脚本和一些简单的 Perl,应该很容易理解。如果您没有使用 Debian,您可能会遇到一些问题。如果您使其与其他主机发行版一起工作,请务必发送补丁。

debootstrap 程序提供了您开始使用的 Debian 基础系统。给定 Debian 发行版名称和软件包镜像 URL,debootstrap 会下载并将基础系统安装到您选择的子目录中。这非常灵活;您可以 chroot 进入它,将其用作 UML 根目录,或者,如果您选择的子目录位于其自己的文件系统上,则可以重新启动计算机并直接使用它。您甚至可以将其刻录到 CD 上,这正是我们要做的。不过,我们首先还有一些工作要做。

在测试脚本时,预计会进行大量的 debootstrap 和软件包安装。在进一步深入之前,通过在方便的机器上安装代理软件包存档(例如 apt-proxy)来节省时间和带宽。

添加软件包

Makefile 中的 fix_inner 目标将软件包添加到基础系统。我们做的第一件事是用 /bin/true 替换 start-stop-daemon,以防止安装后脚本在我们的 chroot 中运行服务。完成此操作后,我们反复 chroot 进入系统并运行诸如 apt-get 和 dpkg 之类的命令。

为了测试和实验,我们还有一个 Perl 脚本 run-chroot.pl,它模拟 chroot 区域中的系统启动。它不会启动大多数服务,因为它们已经在主机上运行并且会发生冲突,但它会运行 SSH 服务器和 X 启动脚本。这比每次想要测试某些东西时都写入 CD 并重新启动要方便得多。

自动登录

在单用户演示系统上让人们登录毫无意义。无论如何您都必须告诉他们密码,并且 CD 是只读的,因此他们无法在当前会话之外更改密码。GDM 具有自动登录功能,但为了减小镜像大小,我们希望避免引入所有 GNOME 依赖项。相反,我们只是使用su以非 root 用户身份启动 X 并运行 .xsession 脚本,该脚本打开一个 xterm 和 Emacs 并启动我们的应用程序。autologin-x 脚本安装为 /etc/init.d.autologin-x,并带有适当的符号链接,使其在启动时运行。

该脚本根据 DISPLAY 是否已设置来选择要运行的 X 服务器;如果是,则启动 Xvnc 而不是 XFree86。这样做是为了帮助测试:当 autologin-x 由 xterm 内的 run-chroot.pl 运行时,我们可以使用 VNC 客户端连接到它,以确保所有常用的 X 应用程序都正确启动。当然,为了使 X 在真正的 CD-ROM 上工作,我们需要知道用户拥有的视频硬件。

硬件检测

在硬件技术的改进的帮助下,Linux 中的硬件检测在过去十年中得到了很大改进。与我们过去使用的 ISA 设备相比,现在可靠且安全地检测今天的 PCI 和 USB 硬件要容易得多。

大多数 Linux 发行商都有一些东西可以扫描系统中的 PCI 和 USB 设备并加载适当的模块。Knoppix 使用 Kudzu,最初是为 Red Hat 编写的,但 vanilla Debian 使用 discover 命令。两者在覆盖范围上非常相似;由于它们都是开源的,因此它们可以相互复制硬件数据库。Debian X 服务器软件包已经使用 discover 为 X 配置问题提供默认值,因此我们将坚持使用它。

debconf

我们如何处理检测到的硬件?Debian 软件包具有可人工编辑的配置文件,但它们通常也带有安装后脚本,这些脚本以交互方式创建所述文件的初始版本。在适用的情况下,例如对于 X 和网络配置,这些脚本会运行硬件检测工具。

问题是我们在主机系统上的 chroot 中安装软件包,而检测主机系统的硬件对目标系统没有帮助。我们需要做的是将 debconf 数据库放在可写的位置,以便在启动时我们可以使用 debconf-communicate 来取消配置软件包并运行其 .config 脚本,使其认为它是第一次被配置。这比使用 dpkg-reconfigure 更彻底,dpkg-reconfigure 有时会询问诸如“您确定要重新配置此软件包吗?”之类的问题。这可能会让尚未配置过一次的最终用户感到困惑。有关详细信息,请参阅 debconf-communicate 手册页和 tarball 中的 target/etc/init.d/configure-xserver。

持久存储:Hotplug

CD-ROM 是只读的,ramdisk 在电源关闭时会消失。但是,人们希望保存他们的文件,甚至可以访问他们已经在现有硬盘驱动器或可移动设备(包括 USB 钥匙链和 Zip 驱动器)上创建的文件。同样,大部分繁重的工作已经为我们完成;这次 hotplug 和 autofs 是我们的救星。

Hotplug 监听正在添加或删除的新设备。当它看到新的 USB 存储设备时,它会加载任何必要的模块并创建一个模拟 SCSI 主机。我们仍然需要知道哪些设备可用并挂载它们,这就是 autofs 的用武之地。

autofs 按需挂载和卸载文件系统。使用程序映射,我们可以让 Perl 脚本在用户请求 /media/list 时运行;它创建一个目录,其中包含以附加设备命名的链接。这些链接指向更多的 autofs 挂载点以访问文件系统。在 tarball 中,查看 target/etc/auto.master 和 target/usr/local/sbin/autofs-device-list。

内核

我们基本上使用与 Knoppix 相同的内核配置(查看正在运行的 Knoppix 系统中的 /usr/src/linux/.config,或 tarball 中的 kernel-config),但我们删除对一些明显未使用的东西的支持,例如 ZISOFS。标准的 Debian make-kpkg 工具会修补、构建和安装内核。这是主机系统上的 Debian 依赖项(您需要 cloop-src 软件包),并且由于它可能是唯一重要的此类依赖项,因此可能值得在以后的版本中将其移动到 chroot 中。

文件系统

大多数 UNIX 文件系统都可以只读挂载,但我们确实需要在某些地方写入文件。例如,X 服务器配置文件需要在启动时根据正在使用的硬件写入,debconf 数据库必须更新,并且还有各种日志和锁定文件。

我们使用 tmpfs 文件系统来创建基于 RAM 的文件系统。系统被安排使用此 ramdisk 作为根目录,并期望 /ro 上的 cloop 镜像。然后对于只读目录,我们创建符号链接,例如,从 /usr 到 /ro/usr。

我们保留一个只读目录列表,并检查两次。首先,我们创建一个系统 tarball,其中排除所有这些目录,并用适当的符号链接替换它们。然后将此 tarball 复制到正在运行的系统的根文件系统中。其次,当我们写出要 cloop 压缩的 ISO9660 镜像时,这是要包含的目录列表。

initrd

在系统真正启动之前,我们必须做两件重要的事情。首先,我们需要挂载 cloop 镜像,加载 CD-ROM 需要的任何模块,然后找到并挂载 CD。接下来,我们安装 cloop 设备并在其上挂载内部文件系统。其次,我们为根文件系统创建一个 ramdisk,并将 CD 中的 root_fs.tgz 镜像复制到其中。

我们使用 initrd(初始 ramdisk)支持来创建一个迷你根文件系统,内核在真正的 init 启动之前挂载并运行它。这是一个 gzipped 文件系统。当具有 initrd 支持的内核使用命令行启动时initrd=filename,它加载该文件名的内容并从中创建一个 ramdisk。然后它开始运行该 ramdisk 中的 /linuxrc 文件。

当 linuxrc 完成后,它使用 pivot_root 调用更改为真正的根目录,即 /ramdisk,并执行真正的 init。

initrd 和内核加在一起需要足够小,以便与引导镜像上的所有其他文件一起放入 1.44MB 的 RAM 中。这不是很多空间,因为仅 GNU libc 就大约 1,200K,我们将不得不非常有创意。

dietlibc, Busybox

即使您从未想要 Linux PDA 或车载 MP3 点唱机,现在您也有理由感谢嵌入式 Linux 黑客。我们将使用 Busybox 和 dietlibc 将我们的夸脱放入众所周知的品脱壶中。Busybox 是一个小型的 shell,可以在构建时配置为包含许多常用实用程序作为内置程序,而 dietlibc 是一个为小尺寸优化的替代 C 库。巧合的是,事实证明 Busybox applet 可以满足我们在 initrd 上所需的一切,并且通过与 dietlibc 静态链接,我们可以将所有这些都放入大约 100K 中。为了比较,与 glibc 静态链接的相同 Busybox 选项会得到一个 500K 的可执行文件。

Busybox 的 Applet 使用其 Config.h 文件(在 tarball 中)中的 #defines 启用。一些禁用的选项可能看起来相当随意,但是当您已经可以选择echo *tar cvf /dev/null来列出当前目录,ls真的是一种奢侈品。

我们使用genext2fs,避免了对 loopback 挂载的需求。这从目录树生成一个 ext2 文件系统,我们将其 gzip 并复制到引导软盘镜像中(图 1)。

Building Your Own Live CD

图 1. 轮中轮:完成的 CD 将文件系统镜像嵌套在文件系统镜像内部的文件系统镜像内部。

启动

从 CD-ROM 启动的标准称为 El Torito,最初由 Phoenix BIOS 编写者制定。El Torito 允许在 CD-ROM 上创建一个或多个磁盘镜像。启动时,BIOS 会找到这些镜像并创建一个模拟磁盘,然后从中启动。镜像可以是软盘(1.44MB 或 2.88MB)或硬盘驱动器的镜像。还有一种无模拟模式,其中 BIOS 从指定文件加载扇区并执行它们,而无需设置模拟磁盘。

当然,有一个问题:El Torito 由 BIOS 编写者实现。拥有笔记本电脑或其他有趣硬件的 Linux 用户已经知道,BIOS 并不总是地球上 bug 最少的代码。有人建议,只要他们 concoct 的任何东西能够加载当前版本的 Windows,一些制造商就会很高兴地忽略实际规范。因此,尽管空间限制很痛苦,但为了确保最大的可移植性,我们遵循 Knoppix 的领导并坚持使用单个 1.44MB 软盘镜像。

boot.img

我们在这个 1.44MB 中放入什么?我们可以启动原始 Linux 内核,或者我们可以使用普通的 Linux 引导加载程序,例如 LILO 或 Grub。不过,H Peter Anvin 的 SYSLINUX 工具在易用性方面优于这两种选择。SYSLINUX 创建使用 MS-DOS 文件系统的启动盘,因此我们可以使用用户态 mtools 创建软盘镜像。磁盘需要内核 vmlinuz 文件、syslinux.cfg、任何辅助帮助文件和 initrd 镜像。完成后,我们在其上运行 SYSLINUX。

现在剩下的就是创建我们的文件系统并刻录它们,就像我们之前所做的那样。内部文件系统位于 $(SCRATCH)/CLOOP 中。我们创建一个外部文件系统,其中包含此文件系统、boot.img 和 root_fs.tgz。然后我们将其写入 CD(一个或两个 CD-RW 会很有用)并使用它重新启动。而且,如果运气好的话,它会工作。

总结

作为多年来没有进行过正常安装的长期 Linux 用户,看到最近在硬件检测和自动配置方面所做的工作令人印象深刻。随着时间的推移,我相信它会变得更好。

该项目接下来会走向何方?自动挂载支持需要改进;我们可能会尝试类似 Volumatic 的东西。除此之外,这取决于基于它的产品。但是所有脚本都是自由软件,我期待收到反馈。

本文资源: /article/8060

Daniel Barlow 是英国牛津的一位独立顾问,他在那里破解 Linux 和 Common Lisp 编译器。在他的业余时间,他喜欢糟糕地弹奏电吉他,这很幸运,因为这是他知道的唯一演奏方式。欢迎评论发送至 dan@metacircles.com

加载 Disqus 评论