通過 chroot 解決 Linux 系統無法啟動的問題


這篇博客講述了博主為了安裝 sqlite3,不小心刪了 boot 目錄下的內核,還重啟系統。結果重啟失敗,通過 Ubuntu 安裝 U 盤和 chroot 修復的故事。

想在學校的服務器上裝一個 sqlite3,被告知之前一次更新內核由於 boot 目錄滿了,沒有更新成功,需要完成內核的更新才能進行其它軟件的安裝。我一看 boot 分區里已經有了很多版本的內核,想都沒想就把舊版本的內核 mv 到了 home 目錄下,只在 boot 中留了最新版本的內核,然后執行 update-grub 命令再重啟,BOOM,系統開不起來了...剛剛才提示的上一次內核更新沒有完全結束,怎么會腦子一抽只留不完整的最新內核呢!

 

一、修復過程

沒辦法,只好帶了一個 Ubuntu 的安裝 U 盤跑去機房。用 U 盤啟動后,選擇“試用 Ubuntu”進入 liveCD(或者應該叫 liveUSB?)。幸好之前把舊版本的內核在 home 目錄下備份了,把完整的舊內核復制回 boot 目錄,執行 update-grub 后,得到了錯誤提示:

/usr/sbin/grub-probe: error: failed to get canonical path of `aufs'.

上網搜索了一下,aufs 是一種特殊的文件系統,liveCD 里有用。原來我們執行 update-grub 的環境是在 liveCD 中,而不是我們要修復的硬盤上的系統,當然會報錯。接下來我們就要通過 chroot 把環境轉換到硬盤上的系統中,再重新安裝 grub 並 update-grub 就能完成修復。

1. 掛載分區

為了 chroot 到硬盤上的系統中,首先需要掛載硬盤分區。通過  sudo fdisk -l  命令可以查看硬盤的分區情況,尋找 root 目錄所在的分區。下面用我的虛擬機進行演示。我的虛擬機並沒有給 boot 目錄或者 usr 目錄或者 var 目錄一類的單獨分區,而是全部划在一塊硬盤分區里。執行 fdisk 后,可以看到以下輸出:

fdisk 執行結果

可以看出,我的根目錄在硬盤的第一個分區里,我們執行  sudo mount /dev/sda1 /mnt  把它掛載到 mnt 目錄下。

有的系統在分區時,會把根目錄放在一個邏輯分區里,這時候根目錄所在的分區顯示的 Type 會是 LVM(我學校的服務器就是這樣的)。這時候,根目錄所在分區的設備名一般是 /dev/mapper/xxx,xxx 這個字符串一般會指示這個邏輯分區底下有什么目錄,比如 xxx 里面包含 root 一般就是這個邏輯分區底下有根目錄。那么我們就要執行  sudo mount /dev/mapper/xxx /mnt 完成根目錄的掛載。

還有的系統在分區時,可能會把 boot 目錄或者 usr 目錄或者 var 目錄等等單獨分區下(我學校的服務器就是把 boot 目錄單獨分區)。在完成根目錄的掛載后,還需要把這些目錄掛載到根目錄底下。比如 boot 目錄單獨分區,設備名是 /dev/sdXY,那么就要執行  sudo mount /dev/sdXY /mnt/boot  完成 boot 目錄的掛載。

2. 掛載虛擬文件系統

Linux 系統運行過程中,還需要 /proc、/dev、/run 等虛擬文件系統。參考資料 1 中使用下面這個命令統一完成虛擬文件系統的掛載:

 for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i /mnt$i; done 

我在虛擬機中執行這個指令成功了,但是在修復學校服務器時不知道為什么不能成功(但是現在也無法重現這個失敗...)。所以我使用了參考資料 2 中的命令完成虛擬文件系統的掛載:

sudo mount -t proc /proc /mnt/proc
sudo mount --rbind /sys /mnt/sys
sudo mount --rbind /dev /mnt/dev
sudo mount --rbind /run /mnt/run

我后來特地搜索了一下 mount 指令的幾個選項,-B(或者 --bind)可以掛載一個文件系統中已有的子目錄,--rbind 則是遞歸版的 --bind(可以看一下 這篇博客 了解兩者的區別),-t 則是指定掛載的文件系統類型。網上也說  sudo mount -B /proc /mnt/proc  和  sudo mount -t proc /proc /mnt/proc  一般沒什么區別,所以也不太知道發生了什么...如果有知道區別的朋友還請留言賜教。

3. chroot + 重新安裝 grub

完成以上 chroot 的准備后,我們就可以執行  chroot /mnt  將環境切換到硬盤上的系統了。現在執行  grub-install /dev/sdX (sdX 是你硬盤上的系統所在的設備名)就能在系統所在的設備上重新安裝 grub,再執行  update-grub  完成 boot 目錄下可用內核的掃描並更新 grub 即可(記得在 update 前先把 boot 目錄下損壞的內核移走,只留下好的內核)。最后重新啟動,硬盤上的系統又能啟動啦!

 

二、如何安全刪除內核

手動刪除 boot 下的內核有一定風險,我們應該如何安全地刪除內核呢?各種豐富的軟件包安裝器或管理器給了我們很大的便利。以 Debian 系的系統 Ubuntu 為例,我們可以通過 dpkg 查看現在已經安裝了哪些內核。執行  dpkg --get-selections | grep linux ,我的虛擬機中結果如下:

dpkg 命令執行結果

其中 linux-image-xxx,linux-headers-xxx 就是內核相關的了。

我們可以利用 grep 匹配不需要的內核,用軟件包管理器刪除即可。假如我們只想留下 4.13.0-37 的內核,可以執行

sudo apt purge `dpkg --get-selections | grep linux | grep 4.13.0 | grep -v 37 | cut -f1`

這一段 shell 命令的意思是:先通過 dpkg --get-selections 查看現在已經安裝了哪些軟件包,再通過 grep 把所有名字含 linux 的軟件包選出來,再把其中所有名字含 4.13.0 的軟件包選出來,再把其中所有名字里不含 37 的軟件包選出來(-v 選項表示選出不匹配的字符串),再把每一行的第一列都選出來。這樣就獲得了所有不需要的內核的名字,再用 apt purge 刪除即可。當然,grep 命令還需要根據自己機器上已有內核的名稱進行調整;而且在刪除之前,一定要確認一下是不是真的刪除這些內核,防止不想刪除的內核被匹配上了,結果誤刪除。畢竟刪除內核還是一個比較有風險的操作...

刪除完畢后,一般會自動更新 grub。不過為了保險起見,還是手動執行一下 update-grub 比較好。這樣就安全地刪除了不需要的內核。

 

參考資料:

1. https://help.ubuntu.com/community/Grub2/Installing#via_ChRoot:通過 chroot 安裝 grub;

2. https://wiki.archlinux.org/index.php/change_root:chroot 環境的准備;

3. http://www.wutianqi.com/?p=3699:mount --bind 和 mount --rbind 的區別。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM