chroot,即 change root directory (更改 root 目錄)。在 linux 系統中,系統默認的目錄結構都是以 `/`,便是以根 (root) 開始的。而在使用 chroot 以後,系統的目錄結構將以指定的位置做爲 `/` 位置。shell
回頁首bash
在通過 chroot 以後,系統讀取到的目錄和文件將不在是舊系統根下的而是新根下(即被指定的新的位置)的目錄結構和文件,所以它帶來的好處大體有如下3個:測試
增長了系統的安全性,限制了用戶的權力;ui
在通過 chroot 以後,在新根下將訪問不到舊系統的根目錄結構和文件,這樣就加強了系統的安全性。這個通常是在登陸 (login) 前使用 chroot,以此達到用戶不能訪問一些特定的文件。spa
創建一個與原系統隔離的系統目錄結構,方便用戶的開發;code
使用 chroot 後,系統讀取的是新根下的目錄和文件,這是一個與原系統根下文件不相關的目錄結構。在這個新的環境中,能夠用來測試軟件的靜態編譯以及一些與系統不相關的獨立開發。ci
切換系統的根目錄位置,引導 Linux 系統啓動以及急救系統等。
chroot 的做用就是切換系統的根位置,而這個做用最爲明顯的是在系統初始引導磁盤的處理過程當中使用,從初始 RAM 磁盤 (initrd) 切換系統的根位置並執行真正的 init。另外,當系統出現一些問題時,咱們也可使用 chroot 來切換到一個臨時的系統。
爲了更好的理解 chroot 發揮的做用,咱們將嘗試指定一個特定的位置進行根目錄切換。可是因爲在通過 chroot 以後,系統讀取到的 bin/ 等與系統相關目錄將再也不是舊系統根目錄下的,而是切換後新根下的目錄結構和文件,所以咱們有必要準備一些目錄結構以及必要的文件。
清單 1. 準備切換的目錄結構
Busybox 被稱爲是嵌入式 Linux 中的瑞士軍刀。Busybox 包含了許多有用的命令,如 cat、find 等,可是它的體積卻很是的小。
$ pwd
/home/wstone/Build/work
$ tree .
.
|-- bin
| |-- ash -> busybox
| |-- bash
| `-- busybox
|-- etc
`-- newhome
這裏使用了靜態編譯後的 busybox 來提供必要的命令,使用靜態編譯僅是爲了不動態庫文件的拷貝。固然咱們也能夠拷貝舊系統的下的命令到新的目錄結構中使用,可是那些命令一般是動態編譯的,這就意味着咱們不得不拷貝相關的動態庫文件到相應的目錄結構中。同時這裏的 bash 也非真正的 Bourne Again shell,而是一個執行 ash 的 shell 腳本。在清單 2中,展現了位於舊系統中的 chroot 命令的使用。須要注意的是在使用 chroot 時,要求擁有相關的操做權限。
$ pwd |
咱們能夠看到當前路徑(/home/wstone/Build/work/),在通過 chroot 後轉變成了 `/` 目錄,同時重新根下讀取了與系統相關的目錄結構。使用 ls
命令失敗是因爲咱們建立的測試目錄結構中並無包含命令 ls
,可是咱們成功的使用了 busybox 中的 ls
。以上看到的只是 chroot 的一種使用方式,其實標準的 chroot (Coreutils - GNU core utilities 提供的 chroot)使用方式有2種:
[1] chroot NEWROOT [COMMAND...] |
剛纔咱們使用的是方式[2]。這將在沒有給定環境時,默認執行 `/bin/sh
`,可是當給定環境後,將運行 `${SHELL} –i
`,即與環境相同的可交互的 shell。咱們的目錄結構中並無包含sh,顯然清單 2中的 chroot 運行了 `${SHELL} –i
`。固然咱們也能夠在進行切換時指定須要的命令,即便用方式[1]。
# chroot . /bin/ash
#
在清單 4 中,嘗試了在通過 chroot 後,執行新目錄結構下的 ash shell。不得不說的是,若是新根下的目錄結構和文件準備的夠充分,那麼一個新的簡單的 Linux 系統就可使用了。其實更爲常見的是在初始 RAM 磁盤 (initrd)中使用 chroot,以此來執行系統的 init
。清單 5 中,展現的是在 Linux 2.4 內核 initrd 中使用 chroot。
清單 5. 在 Linux 2.4 內核 initrd 中使用 chroot 的示例
mount /dev/hda1 /new-root |
因爲 Linux 內核的升級,initrd 處理機制和格式發生了變化,在 Linux 2.6 內核 initrd 中不能再使用 pivot_root,所以通常也再也不使用 chroot,而是選擇使用 busybox 提供的 switch_root 或者 klibc 提供的 run-init 進行根目錄的切換。(這並非說不能在 Linux 2.6內核 initrd 中使用 chroot,選擇 switch_root 或 run-init 僅是出於習慣和方便的考慮。)可是實質上,它們僅是將 chroot 的功能進行了封裝,以此更加方便簡單的切換根目錄。
清單 6. 在 Linux 2.6 內核 initrd 中 chroot 的使用
[1] find -xdev / -exec rm '{}' '; |
switch_root 和 run-init 完成了相似清單 6中的功能,刪除 rootfs 的所有內容以釋放空間,以及掛載新的根文件系統並進行切換。在 busybox 和 klibc中也有提供 chroot 命令,只是功能上與 Coreutils (GNU core utilities) 包含的 chroot 有稍許差別。
上面介紹了 chroot 及其使用,可是編寫一個簡單的 chroot 並不複雜,下面咱們就嘗試編寫chroot 以此來更好的認識 chroot 的處理過程,先編寫一個粗略的 chroot 而後再完善它的功能。chroot 的編寫涉及了2個函數,chroot() 以及 chdir(),它們都包含在 unistd.h 頭文件中。
#include <unistd.h> |
chroot() 將切換參數 path 所指位置爲根目錄 (/),chdir() 用來將當前的工做目錄改變成以參數path 所指的目錄。以此咱們能夠編寫一個很是粗略的 `chroot`。
#include <unistd.h> |
這個粗略的 `chroot` 僅能切換當前位置爲根目錄,同時默認執行 ash shell,不包含任何的錯誤處理及警告。編寫並保存代碼爲test.c
。在清單 9 中,展現了這個粗略 `chroot` 的使用狀況,成功的進行了根目錄的切換。
$ gcc -Wall test.c -o test |
下面給出功能將近完整的 chroot ,加上了一些錯誤處理並新增了可執行指定命令的功能。當在沒有給出 chroot 切換後要執行的命令時,默認執行 `/bin/sh
`,同時檢測環境以確認使用何種 shell。
#include <stdio.h> |
保存以上代碼爲 newchroot.c
文件,編譯後運行測試其功能。最後要指出的是,本文中的 `chroot` 並無使用靜態編譯。若是有必要(如,在 initrd 中使用 chroot),chroot 應該使用靜態編譯,如果使用動態編譯,那麼要拷貝相關的動態庫文件到相應目錄結構中。
$ gcc -Wall newchroot.c -o newchroot |
在 Linux 系統初始引導的過程當中,一般都有使用 chroot。可是 chroot 的好處不只於此,它還增長了系統的安全性等。而經過本文後半部分對 chroot 的認識,我相信讀者能夠更好的發揮chroot 的做用。