Busybox簡介
busybox是一個開源項目,集合了Linux的常用命令,且體積非常小,一般被用於嵌入式Linux上。
busybox在編寫初期的思想就是簡潔,小巧,強悍,並且設計時從系統資源考慮,節省內存,動態編譯busybox工具包總大小才幾百kb,如果是靜態編譯則才1MB左右,非常適合用於嵌入式開發,與發行版不同,發行版使用的不是busybox,一些流行發行版一般使用的都是GNU fileutils、shellutils,這些工具鏈裏包含了對文件,還有一些shell支持的命令,就是我們常用的ls之類的命令,都屬於GNU的開源項目。
下載Busybox
你可以在它的官網下載到有關Busybox的所有開源版本的源代碼:
https://busybox.net/downloads/
將Busybox製作成根文件系統
前幾篇文章講了如何使用Initramf作爲根文件系統,但是效果並不能達到我們的要求,這篇文章使用busybox做一個完整的根文件系統,並且不將它作爲臨時根文件系統,而是把它當作一個實際根文件系統,供Linux內核使用。
根文件系統簡述
在Linux中,根文件系統就是Linux下“/”目錄,Linux把文件系統掛載到這個目錄下,這個目錄下一般擁有Linux運行時需要的一些設備文件,如塊設備,tty,字符設備文件等。
編譯Busybox
這裏我下載的是1.27.0版本的
wget https://busybox.net/downloads/busybox-1.27.0.tar.bz2
這裏跟大家說一個tar解壓命令的小技巧,原本這種解壓我們需要使用對應的選項,二次解壓後才能得到原文件,這裏我們不需要指定這些,tar命令會自動幫我們分析
tar -xf busybox-1.27.0.tar.bz2
-x是解壓的意思,-f是文件的意思,我們不需要指定解壓格式,tar會自動幫我們分析
busybox目錄結構說明:
applets
主要是實現applets框架的文件
applets_sh
一些有用的腳本,例如:dos2unix、unix2dos等
archival
與壓縮有關的命令源文件,例如:bzip2、gzip等
configs
自帶的一些默認配置文件
console-tools
與控制檯相關的一些命令,例如:setconsole
coreutils
常用的核心命令,例如:cat、rm等
editors
常用的編輯命令,例如:vi、diff等
findutils
用於查找的命令,例如:find、grep等
init
init進程的實現源文件
networking
與網絡相關的命令,例如:telnetl、arp等
shell
與shell相關的實現,例如:ash、msh等
util-linux
Linux下常用的命令,主要是與文件系統相關的,例如:mkfs_ext2等
配置busybox
和Linux一樣,busybox使用menuconfig配置,可以在裏面去裁剪一些不需要的模塊,這裏我們使用這個命令然後選擇靜態編譯,因爲在我們編譯的Linux內核裏,並不自帶GLIBC庫
sudo make menuconfig
選擇“Busybox Setting"
選擇”Build BusyBox as a static binary(no shared libs)” 按下“Y”
然後保存退出,使用make install編譯
sudo make install
編譯完成後會生成很多目錄,其中_install目錄裏就是我們需要的bin文件,除了bin文件還包含了一些根文件系統所具備的一些設備文件
使用ls命令查看一下:
包含了一些基本的文件目錄,如usr,bin這些Linux內核運行時的一些目錄,當然,只有這些目錄是不能算上一個完整的根文件系統目錄的,還需要/dev /tty等目錄。
創建文件系統
busybox編譯完成了,上面也說了_install文件夾下的所有文件,要被拿來製作成文件系統,那麼怎麼製作呢?
很簡單,在Linux上如果要對軟盤或者U盤進行操作,那麼就需要掛載,這裏我們可以使用dd命令先創建一個軟盤,作爲我們的根文件系統的鏡像文件,然後將它掛載到一個目錄下,最後我們把busybox下_install目錄copy到鏡像文件掛載的目錄下,這樣鏡像文件裏就有了一個基礎根文件系統所需要的設備文件目錄,然後在卸載掛載,這樣一個文件系統的鏡像就已經制作完成了。
實踐:
1.創建鏡像文件
dd if=/dev/zero of=rootfs.img bs=4096 count=1024
這裏我們創建一個4MB大小的鏡像文件
然後使用ext3格式格式化這個鏡像文件,前幾篇文章說過,Linux子系統VFS負責與文件系統進行交互,但是VFS只認特定的格式,如NFS,EXT等,所以這裏我們格式化一下,注意如果你的Linux內核不支持ext3,需要在make menuconfig時,選擇file system裏把這一選項按下Y,否則VFS會報內核恐慌
mkfs.ext3 rootfs.img
創建一個目錄作爲掛載點:
mkdir rootfs
掛載:
sudo mount -o loop rootfs.img rootfs/
將busybox下的_install文件夾下的所有文件copy過來
sudo cp -a ../busybox-1.27.0/_install/* rootfs/.
ls看一下:
除了這些文件以外,我們還需要三個設備文件dev proc sys
這裏介紹一些這三個文件的作用:
/sys/ 用於管理存儲文件,文件相關管理 的,sys是運行在內存中的
/proc 用於管理進程,是對進程管理,運行的進程參數管理的
/dev 存放各種設備節點,除了設備節點還會存儲socket,管道文件
這些是Linux內核運行時需要的三個設備節點,這裏我們創建出來,具體這些文件的作用,我後面在寫文件系統組成時會詳細講解,目前各位只需要知道這些文件在運行時,會被Linux內核裏的一些文件管理系統掛載到上面去
注意這些文件需要創建在rootfs文件夾下哦
cd rootfs
sudo mkdir dev proc sys
cd ..
基本一個文件系統的基礎已經搭好了,那麼這樣我們就可以卸載掛載了,然後把這個掛載目錄刪除或者不刪除都可以
sudo umount rootfs
那麼到這一步,基本上一個簡單的根文件系統已經搭好了,可以用作嵌入式,或者amd都可以。
運行
使用qemu指定我們的硬盤路徑,然後模擬運行:
qemu-system-x86_64 -kernel /usr/src/linux-4.10.15/arch/x86/boot/bzImage\
-hda rootfs.img \
-append "root=/dev/sda init=/bin/ash"
這裏來解釋一下選項:
-hda 是指定硬盤文件
-append 這個選項不用多說了,第一篇文章有說過,這裏說一下里面的運行
root=/dev/sda 這個是指定根文件系統掛載點,大家有沒有發現其實我們剛剛創建時,只是創建了一個dev目錄,但是並沒有創建sda這個目錄,這個不用擔心,因爲Linux內核運行時會在自動創建設備文件,並將文件系統掛載到這些文件上,這個sda就是文件系統掛載目錄,這個設備文件必須指定爲sda,經過測試結果是這樣,查的資料是這個設備文件是指整個硬盤,還有sda1,sda2這些是指硬盤下的分區,至於更詳細的資料,還在查閱讀內核代碼中。
最後面,的init可以不用指定,這個就是在根文件目錄下的bin下找一個可執行文件,如果不指定的話Linux內核會自動尋找幾個常用的init
這幾行代碼是位於Linux內核init/main.c文件下的kernel_init函數下,它會去依次使用try_to_run_init_process函數來調用不同的初始化函數,如果你的根文件系統下有對應的文件就ok,如果沒有則會引起內核恐慌,找不到init程序。
與Linux2.6內核不同的是Linux2.6使用的是init_post,這個函數會發生兩次調用,第一次是進入到init_post,完成相關初始化後在去依次創建這些進程。
但是到了我們所使用的內核時,只會發生一次函數調用,初始化前面就已經被完成了,就只會發生調用創建進程的函數,可以說得上是運行速度和資源上的提升了。
因爲在內核裏,一切都最好按照一個整體來設計,這樣就可以省去不必要的接口調用,等函數調用時發生的堆棧保護等問題。
所以這也是爲什麼可以在Linux內核裏看到大量的內聯函數的原因。
運行結果:
注意運行後要按兩下回車,因爲運行時init已經打印出數據來了,但是Linux內核的一些工作是後續完成的,也會打印出來,會導致你可能看不到“#”這個輸入交互字符,建議按兩下回車,刷一下緩衝流,有的時候這會讓人覺得是不是運行沒有成功,哈哈我就是。
添加自己的調試程序
這裏教大家一個小技巧,比如我寫了一個調試程序,那麼我想調試它怎麼辦?
我們可以先掛載鏡像文件,然後把我們的文件打包到bin目錄下就可以了,不過打包的文件要靜態編譯,這一點在第一章已經說過了,這裏就不多說啦。
先隨便寫一個文件:
vim test.c
#include <stdio.h>
int main(){
printf("test!");
return 0;
}
gcc靜態編譯:
gcc -static -o test test.c
然後掛載一下鏡像文件,在把test copy進去
sudo mount -o -loop rootfs.img rootfs
sudo cp test rootfs/bin/
然後運行,Linux內核時到bin目錄下執行即可
記得把鏡像文件分配大一點哦,不然會出現 No space left on device的錯誤。