如何搶救 Linux 上不能開機的 GRUB 2

本文翻譯自 Linux.com,原作者為 Carla Schroder:https://www.linux.com/learn/tutorials/776643-how-to-rescue-a-non-booting-grub-2-on-linux/

從前我們使用過的舊版 GRUB,也就是 Grand Unified Linux Bootloader 0.97 版,雖然有許多優點,但隨著它變得過時且開發者也渴望更多功能,於是我們才有了 GRUB 2。

重大改寫的 GRUB 2 在許多方面有著顯著差異。例如允許從可移除式媒體開機,以及透過選項設定進入系統 BIOS。一改將所有設定寫在一個簡單的 /boot/grub/menu.lst 檔案中,它利用各種腳本程式進行設定的方式更為複雜,預設腳本為 /boot/grub/grub.cfg。不過你不會直接編輯這個腳本,這個腳本程式不是讓人而是讓其他腳本來修改的。我們這些卑微的用戶只能編輯主要用來控制 GRUB 選單外觀的 /etc/default/grub。我們還可以編輯 /etc/grub.d/ 底下的腳本。正是這些腳本將你的作業系統開機,控制外部應用程式像是 memtest 與 os_prober,接著再進行主題設定。當你執行 update-grub 指令時,/boot/grub/grub.cfg 會從 /etc/default/grub 以及 /etc/grub.d/* 建構出來,因此每當你修改後都要再次執行。

好消息是 update-grub 腳本能夠找出核心、開機檔案,並將所有作業系統加入你的 GRUB 開機選單中,所以你不再需要手動執行。

我們將學習如何修復常見的兩大錯誤。當你開機後系統停在 grub> 提示符,那是 GRUB 2 的命令 shell。這意味著 GRUB 2 雖然正常啟動並載入了 normal.mod 模組 (以及放在 /boot/grub/[arch]/ 底下的其他模組),卻找不到你的 grub.cfg 檔案。如果你看到的是 grub rescue>,這表示它找不到 normal.mod,因此可能也找不到你所有的開機檔案。

怎麼會這樣?核心也許更改了磁碟配置,或者你移動了你的硬碟,你改過分割區,或者安裝了新的作業系統並且搬動了許多檔案。在這些情況下,雖然你的開機檔案還在,GRUB 卻找不到。因此你可以在 GRUB 提示符上尋找你的開機檔案,設定其位置,然後開機並修復你的 GRUB 設定。

GRUB 2 命令 Shell

GRUB 2 命令 shell 就和舊版 GRUB 的 shell 一樣強大。你可以用它來找開機映像、核心、root 檔案系統。事實上,它允許你在本地機器上擁有所有檔案系統的存取權,而不需理會權限或其他保護措施。雖然有些人可能視此為安全漏洞,但就像一句老 Unix 格言所說的,誰擁有實體存取就等於擁有機器。

當你在 grub> 提示符下,你可以使用許多類似其他命令 shell 的功能,像是歷史命令與 tab 鍵的自動完成。grub rescue> 限制較多,不提供上述兩項功能。

當你在可運作系統上做實驗時,當你的 GRUB 開機選單出現時按下 C 鍵以開啓 GRUB 命令 shell。你可以利用方向鍵在選單項目上捲動以停止開機倒數。在 GRUB 指令列上做些實驗是很安全的,因為你所做的更動都不是永久性的。如果你已經看到 grub> 或 grub rescue>,表示你已經準備好了。

下列幾個指令可以用在 grub> 與 grub rescue> 上。你應該執行的第一個指令是啟動分頁,為的是分頁顯示過長的指令輸出:

grub> set pager=1

在等號兩邊不能有空格。現在讓我們做點小小探索。輸入 ls 來列出 GRUB 能看到的所有分割區:

grub> ls
(hd0) (hd0,msdos2) (hd0,msdos1)

這些 msdos 代表什麼?這表示這個系統有舊的 MS-DOS 分割表,而不是新的 Globally Unique Identifiers 分割表 (GPT)。如果你用的是 GPT,它會顯示 (hd0,gpt1)。現在讓我們多探查一番。使用 ls 指令來看你系統上有哪些檔案:

grub> ls (hd0,1)/
lost+found/ bin/ boot/ cdrom/ dev/ etc/ home/  lib/
lib64/ media/ mnt/ opt/ proc/ root/ run/ sbin/ 
srv/ sys/ tmp/ usr/ var/ vmlinuz vmlinuz.old 
initrd.img initrd.img.old

好哇,我們找到 root 檔案系統了。你可以省略 msdos 與 gpt 的標籤。如果你省略斜線,則會顯示分割區的資訊。你可以用 cat 指令讀取系統上的任何檔案:

grub> cat (hd0,1)/etc/issue
Ubuntu 14.04 LTS \n \l

讀取 /etc/issue 能幫助在多重開機系統上辨識你的各個 Linux。

從 grub> 開機

以下是如何從 grub> 提示符上設定開機檔案並開啓系統。我們從 ls 指令執行得知 (hd0,1) 上有個 Linux 的 root 檔案系統,你可以繼續搜尋直到你確認 /boot/grub 在哪裡。接著執行以下指令,以使用你的 root 分割區、核心、initrd 映像:

grub> set root=(hd0,1)
grub> linux /boot/vmlinuz-3.13.0-29-generic root=/dev/sda1
grub> initrd /boot/initrd.img-3.13.0-29-generic
grub> boot

第一行設定 root 檔案系統所在的分割區。第二行告訴 GRUB 你想要使用的核心。只要輸入 /boot/vmli 並使用 tab 鍵自動完成填滿路徑。輸入 root=/dev/sdX 來設定 root 檔案系統的位置。沒錯,這看起來有些多餘,不過如果你沒指定,你會得到核心 panic 錯誤。如何得知正確的分割區?hd0,1 = /dev/sda1、hd1,1 = /dev/sdb1、hd3,2 = /dev/sdd2。剩下的你應該能類推出來。

第三行是設定 initrd 檔案,跟核心必須是同樣的版本號。

第四行是進行開機。

在某些 Linux 系統上,目前的核心與 initrd 會被符號連接到 root 檔案系統的最上層:

$ ls -l /
vmlinuz -> boot/vmlinuz-3.13.0-29-generic
initrd.img -> boot/initrd.img-3.13.0-29-generic

因此你可以在 grub> 這樣開機:

grub> set root=(hd0,1)
grub> linux /vmlinuz root=/dev/sda1
grub> initrd /initrd.img
grub> boot

從 grub-rescue> 開機

如果你是在 GRUB 救援 shell,指令會有所不同,而且你必須載入 normal.mod 和 linux.mod 模組:

grub rescue> set prefix=(hd0,1)/boot/grub
grub rescue> set root=(hd0,1)
grub rescue> insmod normal
grub rescue> normal
grub rescue> insmod linux
grub rescue> linux /boot/vmlinuz-3.13.0-29-generic root=/dev/sda1
grub rescue> initrd /boot/initrd.img-3.13.0-29-generic
grub rescue> boot

當你載入這些模組後,應該就能使用 tab 鍵自動完成了。

讓修復永久生效

當你成功開機後,執行下列指令以永久性修復 GRUB:

# update-grub
Generating grub configuration file ...
Found background: /usr/share/images/grub/Apollo_17_The_Last_Moon_Shot_Edit1.tga
Found background image: /usr/share/images/grub/Apollo_17_The_Last_Moon_Shot_Edit1.tga
Found linux image: /boot/vmlinuz-3.13.0-29-generic
Found initrd image: /boot/initrd.img-3.13.0-29-generic
Found linux image: /boot/vmlinuz-3.13.0-27-generic
Found initrd image: /boot/initrd.img-3.13.0-27-generic
Found linux image: /boot/vmlinuz-3.13.0-24-generic
Found initrd image: /boot/initrd.img-3.13.0-24-generic
Found memtest86+ image: /boot/memtest86+.elf
Found memtest86+ image: /boot/memtest86+.bin
done
# grub-install /dev/sda
Installing for i386-pc platform.
Installation finished. No error reported.

當你執行 grub-install 時,記得你正在把開機磁區安裝到你的硬碟上,而不是分割區。所以不要用 /dev/sda1 這樣的分割區號碼。

如果這樣做都不能修復你亂七八糟的系統,試試看 超級 GRUB2 live 救援磁碟。官方 GNU GRUB 手冊 2.0 應該也會有幫助。




自由軟體鑄造場電子報 : 第 246 期 專訪中央大學「支援行動裝置使用者與虛擬實驗平台之雲端技術研究」整合型計畫

分類: 源碼秘技