Debian Preseed
这个技巧可能还有其他应用,但我只讨论一个用例,具体来说就是在 pc 和 efi 平台上为 Debian 安装添加 preseed 文件,用于设置在网络配置之前的值。
在 pc 平台上,只要你的 initrd 是 cpio 格式(如今的默认格式),这就相当简单:
#!ipxe
kernel debian/linux <other args>
initrd debian/initrd.gz
initrd debian/preseed.cfg preseed.cfg
boot
其工作方式很简单:第二个 initrd 行加载文件 debian/preseed.cfg,把它命名为 preseed.cfg 并放入一个 cpio 归档中,然后把它和 debian/initrd.gz(一个 gzip 压缩的 cpio 归档)一起作为 initrd 镜像传递给 Linux 内核。Linux 按需解压并把两个 cpio 归档都提取到内存盘中,然后继续正常启动,只是多了一个文件。请注意,Linux 命令行上没有指定 initrd,也不需要指定。
EFI 带来了一些挑战。默认的 iPXE efi 构建不支持 Linux 调用约定。这是一个相对较小的问题,因为 Linux 也支持 efi 调用约定,但两者不同,因为 efi 严格来说没有向 Linux 传递多个 initrd 的概念。不过它确实支持启动文件系统的概念。在 efi linux 上支持多个 initrd 有两种简单的方法。第一种是在编译 iPXE 时加入 linux 支持并使用传统的 Linux 调用约定。这有相当多的问题,这就是为什么 linux 支持不再作为 efi ipxe 的默认配置。更简单的解决方案是创造性地使用 efi 调用约定。
#!ipxe
kernel debian/linux initrd=one.gz initrd=two <other args>
initrd --name one.gz debian/initrd.gz
initrd --name two debian/preseed.cfg preseed.cfg
boot
这个例子比前一个稍微复杂一点,因为 efi linux 要求 initrd 在命令行上传递,而且我们在名称上做了些处理,以确保这易于理解(尽可能容易)并明确告诉 Linux 使用哪个文件。其工作方式如下:ipxe 加载 debian/linux,识别它为 efi 格式,把它和命令行一起存储在内存中;然后加载 debian/initrd.gz,把它命名为 one.gz 并存储在内存中;加载 debian/preseed.cfg,把它命名为 preseed.cfg 并放入一个名为 two 的 cpio 归档中;然后启动 Linux。Linux 加载 one.gz(实际上是 debian/initrd.gz),解压它,从中提取文件并放入内存盘;然后加载 two,从中提取 preseed.cfg(即 debian/preseed.cfg)并放入内存盘。
这也恰好适用于 pc linux 调用约定,因为文件名不会被传递,initrd= 参数会被忽略。只是为了完整性,这里给出一个不改名的最小示例。
#!ipxe
kernel linux initrd=initrd.gz initrd=preseed.cfg <other args>
initrd initrd.gz
initrd preseed.cfg preseed.cfg
boot