使用BusyBox製作根文件系統

1、BusyBox簡介

BusyBox 是很多標準 Linux 工具的一個單個可執行實現。BusyBox 包含了一些簡單的工具,例如 cat 和 echo,還包含了一些更大、更復雜的工具,例如 grep、find、mount 以及 telnet;有些人將 BusyBox 稱爲 Linux 工具裏的“瑞士軍刀”。

BusyBox 揭露了這樣一個事實:很多標準 Linux 工具都可以共享很多共同的元素。例如,很多基於文件的工具(比如 grep 和 find)都需要在目錄中搜索文件的代碼。當這些工具被合併到一個可執行程序中時,它們就可以共享這些相同的元素,這樣可以產生更小的可執行程序。實際上,BusyBox 可以將大約 3.5MB 的工具包裝成大約 200KB 大小。這就爲可引導的磁盤和使用 Linux 的嵌入式設備提供了更多功能。我們可以對 2.4 和 2.6 版本的 Linux 內核使用 BusyBox。

我們平時用的那些Linux命令就好比是分立式的電子元件,而BusyBox就好比是一個集成電路,把常用的工具和命令集成壓縮在一個可執行文件裏,功能基本不變,而大小卻小很多倍,在嵌入式linux應用中,BusyBox有非常廣的應用。

2、BusyBox的用法

  可以這樣用BusyBox

  #busybox ls

  他的功能就相當運行ls命令

  最常用的用法是建立指向BusyBox的鏈接,不同的鏈接名完成不同的功能.

  #ln -s busybox ls

  #ln -s busybox rm

  #ln -s busybox mkdir

  然後分別運行這三個鏈接:

  #./ls

  #./rm

  #./mkdir

  就可以分別完成了ls、rm和mkdir命令的功能.雖然他們都指向同一個可執行程序BusyBox,但是隻要鏈接名不同,完成的功能就不同, BusyBox就是這麼的神奇。

3、配置編譯BusyBox

? 下載

首先需要下載BusyBox源代碼。可從http://busybox.net上直接下載最新版BusyBox。例如當前最新版爲1.5.1。

? 解壓:

tar xvf busybox-1.5.1.tar.bz2

? 配置

BusyBox的配置程序和Linux內核菜單配置方式簡直一模一樣,十分方便易用。使用make menuconfig命令就可以進行配置。

使用Busybox製作根文件系統 - Smart_zhao - 軍惠博客

配置過程主要有幾點需要修改的:

l 因爲我們要將BusyBox交叉編譯成ARM可執行程序放在開發板上執行,所以需要使用交叉編譯器arm-linux-gcc來編譯BusyBox。所以需要修改BusyBox根目錄下的Makefile,找到

ARCH ?= $(SUBARCH)

CROSS-COMPILE ?=

修改成ARM的配置,如下:

ARM ?= arm

CROSS-COMPILE ?= arm-linux-

l 在BusyBox配置界面裏修改幾個配置:

Busybox Settings --->

Build Options

Build BusyBox as a static binary (no shared libs)

這個選項是一定要選擇的,這樣才能把BusyBox編譯成靜態鏈接的可執行文件,運行時才獨立於其他函數庫,否則必須要其他庫文件才能運行。

Busybox Settings --->

Installation Options

Don’t use /usr

這個選項也是要選上的,否則make install 後BusyBox將安裝在原系統的/usr下,這將覆蓋系統原有的命令。選擇這個選項後,make install後會在BusyBox目錄下生成一個叫_install的目錄,裏面有BusyBox和指向他的鏈接。

Init Utilities --->

init

這個選項最好選上,這樣BusyBox就可以初始化腳本inittab,可以用來初始化Linux系統。

如果要讓BusyBox包含一個可以用於解釋Linux命令的shell,需要配置BusyBox的Shells選項裏的內容:

Shells --->

這裏可選的shell有多種,包括ash,hush,lash,msh。最好使用ash,因爲它是功能最全也最類似於一般Linux系統中的BASH的。同時注意第一行的:

Choose your default shell (none) --->

這裏需要回車進去選擇默認的Shell,例如選擇了ash後,第一行的內容就會變成:

Choose your default shell (ash) --->

這樣BusyBox纔會生成sh的鏈接並且將這個sh指向對應的shell(ash)。

l 其他選項都是一些Linux基本命令選項,可以根據自己的需要選擇配置,第一次的話用默認的設置即可。

? 編譯

如果配置好了BusyBox,就可以使用make命令編譯了。

#make

#make install

默認情況下,make install完成後會在BusyBox目錄下創建一個新的本地子目錄 _install,其中包含了基本的 Linux 環境。在這個目錄中,會有一個鏈接到 BusyBox 的 linuxrc 程序。這個 linuxrc 程序在構建安裝盤或急救盤(允許提前進行模塊化的引導)時非常有用。同樣在這個目錄中,還有一個包含操作系統二進制文件的 /sbin 子目錄。還有一個包含用戶二進制文件的 /bin 目錄。在構建軟盤發行版或嵌入式初始 RAM 磁盤時,可以將這個 _install 目錄遷移到目標環境的根目錄中。

4、製作完整的根文件系統

BusyBox雖然爲我們創建了Linux根系統中最基本的shell和一些常用命令,但是一個根文件系統還不只包含這些,還需要其它的一些內容。

? 創建一個比較完整的根文件系統目錄結構

本章第一節已經介紹了根文件系統中的一些目錄,這些目錄是Linux正常運行時所必需的。我們可以在BusyBox的_install基礎上創建完整的根文件系統目錄,一般步驟如下:

l 在PC上創建一個目標根文件系統的目錄,例如/rootfs,將BusyBox裏的_install目錄裏所有內容複製到這個文件夾裏:cp –r _install /rootfs

l 在/rootfs下創建目錄etc/,dev/,lib/,tmp/,usr/,var/目錄,同時var/目錄裏還需要創建var/run和var/log等目錄。

l 生成etc/裏的設備文件,例如tty,console,fb(FrameBuffer),mtdblock(Memory Technology Device)等,這些設備文件是Linux很多驅動程序及就用程序正常的工作的基礎。這些設備文件都是與相應的硬件相聯繫的,主要包含幾種信息:設備類型,主設備號,次設備號。

其中設備類型主要包括字符設備(Character Device)和塊設備(Block Device),字符設備主要字符的輸入輸出設備如鍵盤、鼠標等,塊設備主要指整塊數據的輸入輸出設備,如FLASH、硬盤等存儲設備,一般包含緩衝區機制。

主設備號用來區分不同種類的設備,而次設備號用來區分同一類型的多個設備。對於常用設備,Linux有約定俗成的編號,如硬盤的主設備號是3,而次設備對應到每個具體的設備上,一般在/proc/devices文件裏可以找到相關信息。

對於一個已存在的設備文件可以通過ls –l 命令來獲取它的設備相關信息。

ls  –l  /dev/console

crw-rw---- 1 root root 5,1 Apr 14 23:08 /dev/console

可以看出第一個字母爲c,這代表/dev/console是字符設備,若第一個字母爲b,則爲塊設備。而root之後的 5,1就分別爲相應設備的主次設備號了。

這裏需要強調一點,設備文件類似於配置文件,存儲的是一些設備信息,裏面不包含特定平臺下的指令,所以設備文件本身是平臺無關的,也就是說在I386上創建的設備文件可以放在ARM的根文件系統,而可以被Linux正確識別的。

基本瞭解設備後,還需要如何創建它們,一般情況下可以使用mknod生成相應設備文件。mknod是Linux中用來創建設備文件的命令,格式如下:

mknode [–m MODE] NAME TYPE [MAJOR MINOR]

其中MODE用於指定設備文件的訪問權限。NAME爲設備文件的文件名,TYPE爲相應的設備類型(字符設備c,塊設備b等),MAJOR和MINOR分別爲主次設備號。

例如要創建剛纔的那個console命令可用如下的命令:

mknode –m 660 console c 5 1

設備文件的創建除了使用mknod命令,還可以使用MAKEDEV命令,MAKEDEV可以較方便的創建一系統的設備文件,一般的Linux發行版都有自帶,其基本格式如下:

MAKEDEV –d directory -m maxdevices device

其中directory爲設備文件的目標存放文件夾,若不指定則爲當前系統下的/dev裏。maxdevices爲最大的設備數,因爲MAKEDEV一般會創建一種設備的一系列設備文件,一般從0開始編號,直到maxdevices,所以一般這個需要指定,要不會生成較多的相關設備文件,而一般我們是不需要這麼多的。最後一個參數device爲對應的設備文件名,包括tty,vt,mem,null,zero,fd,hd,audio,sound等。這些參數的詳細內容以及更多的參數選項,可以參考man手冊。

可以這樣創建硬盤的設備文件hd

MAKEDEV –d /rootfs/dev -m 2 hda

這條命令就會在/rootfs/dev目錄中創建hda和hda1兩個設備文件,指向第一塊硬盤和第一塊硬盤的第一個分區。

對於目標根文件系統中的設備文件,一般都應放在etc/目錄中,可以用如下幾種方法來獲取相應的設備文件:

ü 可以手動用mknod命令一個個的創建設備文件;

ü 可以使用MAKEDEV來創建設備文件;

ü 甚至可以直接拷貝PC系統中部分設備文件至目標根文件系統中。

l 構建lib/目錄。lib/目錄放的是Linux就用程序所需的庫文件,其實也是目標平臺的指令代碼,所以這裏的文件與etc/裏不一樣,必須與相應的硬件平臺相對應,例如i386裏的庫文件放到ARM系統中就不能使用的,這點與Linux的可執行文件一樣。在PC機上使用ls /lib命令就可以看到很多.so結尾的庫文件,這些.so文件就是Linux的動態鏈接庫(類似於Windows下的DLL文件)。要注意的是.so文件名後綴還可能加上一些版本號標誌例如.so.1,.so.1.2等都是動態鏈接庫。

ü 目標根文件系統中的庫文件從哪裏來?

一般這些庫都是事先編譯好的,而且跟編譯器相關的(glibc等),例如我們使用arm-linux-gcc進行編譯則需要相應版本的一些庫文件,這些庫文件可以從編譯器所在的目錄裏直接拷貝。對於ELDK開發包,可以從ELDK目錄下的arm/lib/目錄裏複製相應文件。

ü 目標根文件系統需要哪些基本庫文件?

庫文件實際上是由其它可執行文件來調用的,所以庫文件的取捨是由根文件系統中所包含的可執行文件來決定的。但是要運行可執行文件,一般有幾個是系統必須的。它們是ld(ld-linux),libc,幾乎所有的可執行文件都需要調用到這兩個庫文件。

ld(ld-linux):ld-linux.so 實際上就是一個可執行程序。這是負責執行動態裝載的代碼。它從可執行程序讀取頭信息(ELF格式的),然後通過這些信息判斷必要的庫和需要裝載的庫。之後,執行動態鏈接,修改可執行程序和裝載的庫中的所有地址指針,使程序能夠運行。一般的文件名可能爲ld-2.3.2.so,ld-linux.so.2,這點與編譯器和系統版本有關。

libc:libc.so.6 是以 ld-linux.so.2 爲基礎架構而完成的動態鏈接庫,它幾乎負責了所有常用的標準 C 函數庫,例如 Linux 下寫的 Socket 程序,其中的connect()、bind()、send() .....之類的函數,都是由 libc.so.6 所提供的。

所以一個最基本的lib/目錄應該至少包含這ld-linux.so.2和libc.so.6這兩個文件。

ü 應用程序需要哪些庫文件?

前面已經說過動態鏈接庫是由應用程序(可執行文件)調用的,那對於一個特定的可執行文件是如何判斷它需要哪些庫文件的?一般可以編譯器的ldd命令來查看,例如arm-linux-gcc包含了arm-linux-ldd命令用來查看ARM可執行文件調用的動態鏈接庫。arm-linux-ldd的功能就是列出可執行文件及動態鏈接庫運行時需要的庫文件,例如,對於剛纔所指的libc.so.6可以查找出其需要的動態鏈接庫。這裏我們假設爲ELDK裏的libc。

# file /eldk/arm/libc.so.6

libc.so.6:symbolic link to `libc-2.3.5.so`

通過file命令看出這裏的libc.so.6實際上是個符號連接,鏈接到libc-2.3.5.so,所以我們繼續追查libc-2.3.5.so:

#file libc-2.3.5.so

libc-2.3.5.so: ELF 32-bit LSB shared object, ARM, version 1(ARM), stripped

從這裏可以明顯的看出這個是ARM的Shared Object,也就是ARM格式的動態鏈接庫。到這裏可以判斷出libc.so.6是ARM指令的。下來看libc.so.6到底需要哪些庫文件:

#arm-linux-ldd libc.so.6

ld-linux.so.2 => not found

可以看出libc.so.6庫文件需要ld-linux.so.2這個動態鏈接庫(not found 說明在當前系統中未找到相應的庫,因爲系統是i386而需要的是ARM格式,所以找不到)。

這樣通過arm-linux-ldd命令就可以確定各個程序所需的動態鏈接庫,然後根據需要放到lib/目錄裏,就組成目標根文件系統的動態鏈接庫集合了。

l 若選擇了BusyBox的init模塊,則需要配置BusyBox的初始化文件。因爲Linux系統加載根文件系統後需要執行一些配置以初始化整個Linux的工作環境及init程序和Shell等。這個文件就是etc/inittab。關於此文件的詳細內容可以查看man inittab。但是BusyBox的inittab格式與一般Linux下的inittab的格式是不同,所以直接拷貝PC機上/etc/inittab文件到BusyBox製作的根文件系統中是不能用的,那怎麼辦呢?

BusyBox自帶了符合它的格式的inittab樣本文件,放在examples目錄下,主要內容包括:

::sysinit:/etc/init.d/rcS

::askfirst:-/bin/sh

tty2::askfirst:-bin/sh

tty3::askfirst:-bin/sh

tty4::askfirst:-bin/sh

#Stuff to do when restarting the init process

::restart:/sbin/reboot

#Stuff to do before rebooting

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a -r

::shutdown:/sbin/swapoff –a

BusyBox的inittab的每一行格式如下:

<id>:<runlevels>:<action>:<process>

總共包含四項,每項間以”:”隔開。

第一二項<id>和<runlevels>在BusyBox都是忽略掉的,所以可以看到BusyBox提供的inittab樣本文件的所有項目都是以兩個冒號”::”開頭的。

第三項<action>爲動作描述,可選項爲sysinit, respawn, askfirst, wait, once, restart, ctrlaltdel 和 shutdown。其中大部分動作可以通過動作名直接理解它的作用。其中askfirst會在登錄shell前提示用戶,而respawn則不會提示。

第四項<process>指定了<action>動作應執行的腳本文件。

知道了格式,下面簡單的分析一下inittab樣本文件:

第一行::sysinit:/etc/init/rcS實際上指定了系統初始化(sysinit)時腳本爲/etc/init/rcS,這個可以根據自己的需要更改的。

但是對於不同的終端設備的不同配置區別在於開頭的標誌,例如對於tty2終端,則有對應的操作 tty2::askfirst:-bin/sh。此行的意思指對於tty2使用shell爲/bin/sh,同時對askfirst(有提示信息再要求登陸)。 若對於某個特定的終端設備可以直接將前面的設備標誌去掉,例如ttyS0, ttyS1等。

第二行::askfirst:-/bin/sh指定了系統第一個終端在加載shell爲/bin/sh,而且在進入shell前會提示用戶。其它行請讀者自行分析。

l 在etc/目錄裏除了inittab文件外,還需要其它的一些基本的文件,例如fstab、passwd、group、inputrc等,由於篇幅所限,不可能一一詳解,讀者可以參考其它書籍或者man手冊,對於一些文件讀者也可借用別的嵌入式根文件系統裏的內容,然後在此基礎上進行修改以符合自己的系統。這裏簡單介紹etc/裏的幾個文件:

ü fstab:這個文件描述系統中各種文件系統的信息。在這個文件中,每個文件系統用一行來描述,在每一行中,用空格或TAB符號來分隔各個字段,文件中以*開頭的行是註釋信息。一般內容可能如下:

/dev/mtdblock2 / jffs2 defaults 0 0

none /tmp ramfs defaults 0 0

none /proc proc defaults 0 0

第一列(字段):設備名或者設備卷標名(一般爲/dev裏的對應的設備文件)

第二列(字段):設備掛載目錄 (例如上面的“/”或者“/tmp”)

第三列(字段):設備文件系統 (例如上面的“ext3”或者“vfat”)

第四列(字段):掛載參數 (具體可以查看幫助man mount)

對於已經掛載好的設備,例如上面的/dev/sda2,現在要改變掛載參數,這時可以不用卸載該設備,而可以使用下面的命令(沒有掛載的設備,remount 這個參數無效)

#mount /mnt -o remount,ro (改defaults爲ro)

關於其它參數請參考man手冊。

第五列(字段):指明是否要備份。(0爲不備份,1爲要備份)

第六列(字段):指明自檢順序。 (0爲不自檢,1或者2爲要自檢,如果是根分區要設爲1,其他分區只能是2)

ü passwd和group保存着Linux系統的用戶組和用戶名等,與硬件平臺無關,爲方便起見,可以從現有的Linux系統中拷貝過去即可。

etc/目錄裏的配置文件較多,不可能一一解釋,請讀者在創建時多參考已有的系統。

5、總結

上面已經介紹一個根文件系統的創建過程,如果完整的按照上面的步驟做下來,應該就會在/rootfs下得到了一個相對完整的根文件系統,這個根文件系統主要BusyBox的bin/、sbin/目錄,etc/系統配置文件目錄以及lib/動態鏈接庫所在目錄等,這樣一個Linux應用程序可執行的最小環境基本已經搭成了。之後可以在這個根文件系統中添加所需的應用程序等等。

但是這個根文件系統又是怎麼放到目標開發板裏的呢?

通常的做法是將整個根文件系統打包成某種文件系統格式的映像,然後下載到目標開發板的存儲設備裏(如FLASH等)。

用什麼程序可以打包?支持幾種格式呢?

通常使用mkfs系統命令。mkfs命令可以生成指定文件系統類型的映像文件。對於不同的文件系統類型需要不同的mkfs命令,例如EXT2,EXT3類型的文件可以使用mkfs.ext2和mkfs.ext3等。而通常嵌入式開發板使用FLASH作爲存儲設備,所以對應的文件系統類型一般爲JFFS2,所以使用命令mkfs.jffs2命令,這個命令一般在開發板提供的工具有,也可以從網上搜索下載,這個命令一般是運行在PC系統上的,所以一般爲I386可執行文件。

mkfs.jffs2的基本命令格式如下:

mkfs.jffs2 -r DIR -o FILE -e SIZE --pad=PADSIZE

其中DIR爲要打包的文件夾,FILE爲輸出的文件路徑,SIZE爲每次擦除的塊大小(默認爲64KB)。PADSIZE爲填充大小,這個參數強制使目標文件大小至少爲PADSIZE字節,若實際數據沒有這麼大,則使用0xFF填充,這個參數很重要,在將映像寫入目標開發板時一般應與實際根文件系統大小相符(類似於總磁盤容量),這樣具有初始化的作用,若不相符合,在掛載這個JFFS2根文件系統時可能會出現一些問題。

下面給個簡單的例子,這個例子將/rootfs的這個根文件系統打包成文件rootfs.img,且總大小爲1M(0x100000字節)。

mkfs.jffs2 -r /rootfs -o rootfs.img -e 0x40000 --pad=0x100000

做好映像文件後就可以將這個映像文件寫入目標板中,通常使用U-BOOT等BootLoader通過網卡下載到開發板內存中,然後再寫入開發板的FLASH裏。在U-BOOT裏若網卡驅動可用,通常用tftp下載,再使用相關的FLASH操作命令寫數據。

發佈了137 篇原創文章 · 獲贊 31 · 訪問量 116萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章