這是關於在 Linux 啟動初期做奇怪事情的四部分系列的第一部分。

要用新作業系統取代你的 Linux 安裝,你可以直接下載預先準備好的磁碟映像檔到磁碟,執行類似下面的指令:

不需要先存到其他地方,直接將資料流導入磁碟。然後你就可以重新啟動進入那個作業系統,恭喜你,已經安裝好新的作業系統。這甚至適用於大多數 EFI 機器,無需額外執行 efibootmgr 指令,因為 EFI 韌體會自動偵測新的 EFI 系統分割區!

這個指令之所以可行,是因為 /dev/sdX、/dev/nvmeX 等磁碟裝置可以直接從檔案系統存取,遵循古老的 Unix 概念「萬物皆檔案」。你可以寫入 /dev/sdX 檔案,這會直接寫入磁碟!

我最初這麼做的原因是因為我不想多付 Contabo 每月 1.5 美元的物件儲存費用,僅為了能從預製磁碟映像啟動 VPS。

我覺得這是個有趣的技巧,一個關於永恆 curl | sh 辯論的搞笑玩笑。我可以寫篇部落格文章,告訴你怎麼自己做,一千字,我學到東西,你也學到東西,我拿到網路點數,雙贏。

問題是事情沒那麼簡單。我一直問下一個問題,不斷剝開洋蔥的下一層,不斷翻開魔法書的下一頁……結果變成了四篇部落格系列,結局出乎意料。

那我們從頭開始吧?

現在,樹莓派基金會提供一套軟體,能自動完成所有步驟,但以前你必須這樣做。

Stack Exchange 上有個答案列出確切步驟。

透過執行

sudo dd bs=1M if=your_image_file_name.img of=/dev/sdx

將映像檔內容複製到 SD 卡。

他們也說要做 sha256sum 驗證,但說實話,沒人真的會做,連 Caligula 用戶都不會。

一個合理的改進是,如果你已經知道 URL,可以直接用 wget 或 curl 從命令列下載檔案。

但當然,沒規定你一定要先下載成檔案。dd 如果沒有指定 if= 參數會從標準輸入讀取,所以你可以用管線輸入 dd,達成不產生中間檔案的效果。

當然,也沒規定你一定要用 dd。dd 只是因為區塊對齊和快取機制讓寫入磁碟更有效率。你也可以直接重定向標準輸出:

恭喜,你已經從基本原理推導出最初的搞笑前提。

我略過了 Stack Exchange 文章中提到映像檔是壓縮檔,需要先解壓的部分。但這是個很好的轉折,因為事實上有很多變化方式:

坦白說,從網路直接寫入磁碟的方法無窮無盡!

假設你有一台在 Contabo 運行的虛擬機,從 /dev/sda 啟動,你想用自己的 OS 映像重新映像它。要怎麼調整這個方法?

當然,你得先知道怎麼製作這樣的 OS 映像。幸運的是,你可以先在虛擬機安裝任何作業系統(甚至 Windows!),然後使用產生的原始磁碟映像。

用 QEMU 做這件事,你先要建立一個原始磁碟映像,最好容量不要太大(複製後可以擴充)。

接著用安裝程式啟動你的 OS:

完成所有設定步驟後,就完成了。你可以把 disk.img 放到你的網頁伺服器上。

我用的是 NixOS,整個流程都自動化了!我只要 import <nixpkgs/nixos/lib/make-disk-image.nix> 就能得到磁碟映像。如果你也用 Nix,可以透過閱讀它的文件原始碼學習如何使用。

製作好映像後,我們要卸載目標磁碟。這很簡單,只要輸入 umount /dev/sdX 或 umount /dev/nvmeX,例如:

喔,對了。要替換的磁碟是系統主磁碟,系統正是從它啟動的。

系統可能會阻止你卸載 /dev/sda1,但即使掛載著,也不會阻止你寫入 /dev/sda1 或 /dev/sda!你覺得 parted、gparted、fdisk 怎麼在系統運行時操作磁碟?

我執行了以下指令並輸入密碼:

我原本以為這不會成功。程式必須載入記憶體才能執行,理論上可能可行。但同時機器上還有其他程序運行,這樣做可能會導致核心當機。

但理論在實踐面前毫無意義。

指令沒有輸出,但 iftop 顯示有資料傳輸:

等了一會兒,程式結束並輸出:

我們嘗試在系統運行時覆寫 OS,結果在 77.8% 時崩潰!可能發生很多事,崩潰細節很有趣,但總結就是我們做了蠢事,導致蠢結果。

或許還是先卸載裝置再寫入比較好。

不過,我們得思考這背後的意義。怎麼在保持 OS 運行的同時卸載 OS 磁碟,然後覆寫它?

這聽起來像是佛教的矛盾冥想謎題,但解決方法其實很簡單:直接啟動到一個沒有掛載舊系統的全新 OS!

大多數 Linux 發行版的安裝程式都預裝了必要工具和網路功能。Arch 和 NixOS 安裝程式非常適合這用途!Fedora 安裝程式也可以用。你甚至不必執行安裝程式本身,只要有網路和終端機存取,就能盡情執行 curl > /dev/sda。

這正是我用來覆寫 Contabo VPS 的方法。Contabo 允許你啟動到基於 Debian 的救援映像,而非磁碟上的系統,我就啟動到那裡,然後用 wget -O- > /dev/sda 安裝新 OS!

我做了第二次,心想:「有沒有辦法自動化?」

真的想想看。覆寫磁碟所需的工具在覆寫前就已存在磁碟上。理論上,你可以把這些工具複製到記憶體,卸載其他所有東西,然後從記憶體覆寫磁碟,實現原地交換。

磁碟和啟動不可能那麼神奇……真的嗎?

用其他常見檔案傳輸協定如 gopher、BitTorrent、SMTP、magic-wormhole、NFS、RFC 1149 或 FCC Part 97 來完成這件事,留給讀者自行嘗試。