多重開機的隨身碟

不小心多買了一顆 32G 的隨身碟, 手癢就把他做成了多重開機的 linux 開機碟。 之前試過幾次都失敗,這次照著 arch wiki 自己 config 不用現成的解決方案, 在弄壞自己筆電的 grub 後,終於成功了。

主要是想達成能直接把 live-cd 的 iso 檔放進隨身碟後, 就能直接開機,不用 cat live-cd.iso > /dev/sdb 把隨身碟 成開機碟。

以前能用 grub4dos 達成這種功能, 只要把 iso 檔放進他裡面的 iso 目錄, 就能在開機選單裡直接選他開機。

後來想自己用 grub 達成,也修了蠻多次 grub, 自認對 grub 的介面還算熟悉, 應該能自己做一顆用 grub2 的開機碟了。 於是就 google 了一下,開始照著 wiki 做了。

基本上照著 他的部驟 走就裝好了, 唯一問題是沒有教怎麼用光碟開機。 用光碟開機首先要初始化 grub,然後載入一些基本模組, 之後再載入核心和映像檔,最後開機。 用 grub 開機的基本方法可以參閱 開放文化基金會的救援指引

grub config 撰寫

那些模組有點麻煩,我是直接去抄我的 debian 的 /boot/grub.cfg , 其語法類似 bash,有一點 linux 程度的都看得懂。 反正就他做了什麼命令,我就跟著做, 然後看哪些是判斷測試類的不重要 code,可能可以刪掉。 成果是 multiboot-flash-drive-grub.cfg 的 header 部份到 menuentry 開始前, 也就是從第 8 行到第 50 行間。

總之裝好後,就可以把 iso 光碟檔先丟到 /boot/iso/ 下, 然後寫那個光碟的 menuentry 了。

menuentry 的寫法大概就主要二行開機命令, 用 linux 命令載入核心,用 initrd 載入初始映象檔。 之後好像不用 boot 指令, 可能 menuentry 會自動呼叫 boot?不是很確定。 但麻煩的是載入核心時要傳入參數, 每個發行版的參數不同,要參考原有光碟的參數。

# debian 的參數
menuentry 'Debian GNU/Linux' {
    # 載入   核心路徑                 參數
    linux    /vmlinuz-4.9.0-8-amd64 root=/dev/sda1 ro quiet
    initrd   /initrd.img-4.9.0-8-amd64
}

基本上就先把該光碟 mount 起來, 看一下有沒有 /boot/grub/grub.cfg 之類的檔案。 像 貴哥的 finnix 就有 /boot/grub/loopback.cfg , 內容大概如下:

menuentry "Boot Finnix 110 (64-bit)" {
        linux /boot/x86/linux64 findiso=${iso_path} vga=791 nomodeset quiet toram --
        initrd /boot/x86/initrd.xz
}

很明顯就是要你在載入核心時傳入該光碟映像檔的位置, 然後還要指定一些奇怪的東西。 最後那個 toram 則是指示開機後把整個 os 放到 ramdisk 裡。 (finnix 是不到 1G 的作業系統, 以現在電腦動輒 4G 以上的 ram 來說,是輕鬆放得下的。)

所以把 finnix-ckhung16c.iso 放到 /boot/iso/ 目錄後, 就加入以下的 menuentry:

menuentry "Boot Finnix 110 (64-bit)" {

        # 掛載光碟到 (loop) 裝置
        loopback loop /boot/iso/linux/finnix-ckhung16c.iso

        # 指定核心的路徑,在 (loop) 的 boot/x86/linux64
        # 參數基本照抄原本的 loopback.cfg,
        # 但指定 iso 的路徑在 /boot/iso/finnix-ckhung16c.iso
        linux (loop)/boot/x86/linux64 findiso=/boot/iso/finnix-ckhung16c.iso vga=791 nomodeset quiet toram --
        initrd (loop)/boot/x86/initrd.xz
}

然後就能在開機後的 grub 選單看到 Boot Finnix 110 (64-bit) 這項了, 如果 夠幸運 就能開機了。

路徑的地雷

有一點比較麻煩是那個路徑, 就是 findiso=/boot/iso/finnix-ckhung16c.iso 這個參數。 因為事實上你開機時 grub 的根目錄不是開機後 os 的根目錄, 而且你有很多顆硬碟和很多分割區,(至少插著的隨身碟和原本電腦的硬碟二顆。) 所以他會把哪顆當根目錄,然後找到 /boot/iso/finnix-ckhung16c.iso 呢? 誰知道,總之我這樣寫 finnix 能開機。

像 ubuntu 的參數就要指定另一個檔案:

linux   /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash ---

我試著把 root 先設到 iso 裡,再設路徑,也是沒用。 總之我不知道怎麼用 ubuntu 核心開機。

loopback loop /boot/iso/ubuntu-18.04-desktop-amd64.iso
set root=(loop)
linux   /casper/vmlinuz  file=/preseed/ubuntu.seed boot=casper quiet splash ---

其實多數發行版都會有一些路徑參數要設,然後多半設不好。 所以用 grub 掛載 iso 開機容易有問題。

syslinux memdisk

arch wiki 好像還有介紹另一個 syslinux memdisk 的方式, 相比 grub 是掛載光碟後,再讀取核心來開機; syslinux memdisk 是直接把光碟讀到 ram 裡, 然後讓系統把 ram 當開機的硬碟, 當作插入一片光碟一樣開機,不會這種要改寫參數的問題。

該怎麼說,grub 雖然可以讓你讀到光碟的內容, 相比 memdisk 只能把整個光碟檔塞到 ramdisk 裡, 然後當作另一個裝置開機,算是一種進步; 但這種進步卻不如老方法的穩定好用。實在是諷刺。

但現今 uefi 漸漸取代 bios,grub 支援 uefi 了, 但不確定 syslinux 和 memdisk 這麼老的東西能不能在 uefi 上運作。 現在要嘛等各發行版統一 kernel 的開機參數, (我看是不可能,linux 發行版這麼多年了也沒有統一。) 要嘛再研究一次 syslinux memdisk。