經過 chroot 解決 Linux 系統沒法啓動的問題

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

想在學校的服務器上裝一個 sqlite3,被告知以前一次更新內核因爲 boot 目錄滿了,沒有更新成功,須要完成內核的更新才能進行其它軟件的安裝。我一看 boot 分區裏已經有了不少版本的內核,想都沒想就把舊版本的內核 mv 到了 home 目錄下,只在 boot 中留了最新版本的內核,而後執行 update-grub 命令再重啓,BOOM,系統開不起來了...剛剛纔提示的上一次內核更新沒有徹底結束,怎麼會腦子一抽只留不完整的最新內核呢!linux

 

1、修復過程

沒辦法,只好帶了一個 Ubuntu 的安裝 U 盤跑去機房。用 U 盤啓動後,選擇「試用 Ubuntu」進入 liveCD(或者應該叫 liveUSB?)。幸虧以前把舊版本的內核在 home 目錄下備份了,把完整的舊內核複製回 boot 目錄,執行 update-grub 後,獲得了錯誤提示:sql

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

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

1. 掛載分區

爲了 chroot 到硬盤上的系統中,首先須要掛載硬盤分區。經過  sudo fdisk -l  命令能夠查看硬盤的分區狀況,尋找 root 目錄所在的分區。下面用個人虛擬機進行演示。個人虛擬機並無給 boot 目錄或者 usr 目錄或者 var 目錄一類的單獨分區,而是所有劃在一塊硬盤分區裏。執行 fdisk 後,能夠看到如下輸出:ubuntu

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 目錄的掛載。app

2. 掛載虛擬文件系統

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

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

我在虛擬機中執行這個指令成功了,可是在修復學校服務器時不知道爲何不能成功(可是如今也沒法重現這個失敗...)。因此我使用了參考資料 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 目錄下損壞的內核移走,只留下好的內核)。最後從新啓動,硬盤上的系統又能啓動啦!

 

2、如何安全刪除內核

手動刪除 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 的區別。

相關文章
相關標籤/搜索