如何自己動(dòng)手做一個(gè)迷你型Linux操作系統(tǒng)
因?yàn)槲覀円紤]從 Flash 盤進(jìn)行啟動(dòng),所以我們選擇用 LILO 作為我們的 Boot Loader,而不選用 GRUB。這是考慮到 GRUB 有較強(qiáng)的對(duì)硬盤和文件系統(tǒng)的識(shí)別能力,而 Flash 盤到底不是標(biāo)準(zhǔn)的硬盤,并且我們選用的文件系統(tǒng) GRUB 又不一定認(rèn)識(shí),搞不好的話 GRUB 反會(huì)弄巧成拙。而 LILO 就簡(jiǎn)單的多了,它在硬盤開始的 MBR 寫入一個(gè)小程序,這個(gè)小程序不經(jīng)過(guò)文件系統(tǒng),直接從硬盤扇區(qū)號(hào),讀出 Kernel Image 裝入內(nèi)存。這樣,保險(xiǎn)系數(shù)就大大增加。并且也給了我們自由選用文件系統(tǒng)的余地。那么,我們要如何安裝 LILO 呢?
首先,我們要找一塊普通的 800M 左右的 IDE 硬盤,連在目標(biāo)機(jī)器的 IDE 線上。這樣在我們的目標(biāo)機(jī)器上,IDE1 上掛的是 Flash 盤,IDE2 上掛的是一塊工作硬盤。我們用標(biāo)準(zhǔn)的步驟在 IDE2 的標(biāo)準(zhǔn)硬盤上裝上一個(gè) Debian GNU/Linux 系統(tǒng)。當(dāng)然,如果讀者朋友們手頭沒有 Debian,也可以裝 Red Hat 系統(tǒng)。裝好工作系統(tǒng)之后,要首先做一些裁減工作,把不必要的 Service 和 X Window 等等東西都刪掉。這樣做的目的是增進(jìn)系統(tǒng)啟動(dòng)速度,因?yàn)槲覀冊(cè)诤竺娴墓ぷ髦?,肯定要不停的重新啟?dòng)機(jī)器,所以啟動(dòng)速度對(duì)我們的工作效率是很關(guān)鍵的。
裝好工作系統(tǒng)之后,在 Falsh 盤上做一個(gè) Ext2 文件系統(tǒng),這個(gè)用 mke2fs 這個(gè)命令就可以完成。由于 Flash 盤是接在 IDE1 上的,所以在 Linux 里面,它的身份是 /dev/hda。本文作者在操作的時(shí)候,把整個(gè) Flash 盤劃分了一個(gè)整個(gè)的分區(qū),所以,調(diào)用 mke2fs 的時(shí)候,處理的是 /dev/hda1。讀者朋友們應(yīng)該可以直接在 /dev/hda 上做一個(gè) Ext2 文件系統(tǒng),而不用事先分區(qū)。
在 Flash 盤上做好了文件系統(tǒng)之后,就可以把一個(gè)編譯好的內(nèi)核映像文件 vmlinuz 拷貝到 Flash 盤上了。注意,必須要先把這個(gè) vmlinuz 映像文件拷貝到 Flash 盤上,然后才能在 Flash 盤上安裝 LILO。不然的話,LILO 到時(shí)候可是會(huì) LILILILI 打結(jié)巴的,因?yàn)樗鼤?huì)找不到 Kernel Image 在 Flash 盤上的位置的,那樣的話 Flash 盤也就啟動(dòng)不起來(lái)了。還有,如果讀者朋友們?cè)?Flash 盤上用的是一個(gè)壓縮的文件系統(tǒng)的話,到時(shí)候 LILO 也會(huì)出問題,它雖然能正確的找到 Kernel Image 在硬盤上的起始位置,但是它卻沒有辦法處理被文件系統(tǒng)重新壓縮過(guò)的這個(gè) Kernel Image,不知道該如何把它展開到內(nèi)存中去。
把 Kernel Image 拷貝過(guò)去以后,我們就可以動(dòng)手編輯一份 lilo.conf 文件,這份文件可以就放在工作系統(tǒng)上就行了。但是注意在 lilo.conf 中索引的文件名的路徑可要寫對(duì)。這些路徑名都是在工作系統(tǒng)上看上去的路徑名。比如,如果 Flash 盤 Mount 在 /mnt 目錄下面,那么,在 lilo.conf 中,vmlinuz 的路徑名就是 /mnt/vmlinuz。注意這一點(diǎn)千萬(wàn)不要搞錯(cuò)。不然的話,如果一不小心把工作系統(tǒng)的 LILO 給破壞掉了,那就麻煩了。編輯好了 lilo.conf,然后再運(yùn)行 lilo 命令,注意,要告訴它用這個(gè)新的 lilo.conf 文件,而不要用 /etc/lilo.conf。
安裝好 LILO 之后,我們可以立即重新啟動(dòng),測(cè)試一下。首先在 BIOS 里面,設(shè)置成從 IDE1 開始啟動(dòng),如果我們看到 LILO 的提示符,按回車后還能看到 Kernel 輸出的消息,這就算是 LILO 的安裝成功了。記得這個(gè)操作的方法,以后每次我們更新 Flash 盤上的 Kernel Image,都記得要更新 LILO。也就是說(shuō),要重新運(yùn)行一遍 lilo 命令。
編譯內(nèi)核
試驗(yàn)成功 LILO 的安裝以后,我們開始考慮編譯一個(gè)新的內(nèi)核。當(dāng)然,要編譯新的內(nèi)核,我們首先要進(jìn)入我們的工作系統(tǒng)。這里有兩個(gè)辦法進(jìn)入工作系統(tǒng),一是在 BIOS 里面設(shè)置從 IDE2 啟動(dòng),當(dāng)然,這就要求當(dāng)初安裝工作系統(tǒng)的時(shí)候,要把 LILO 安裝在 /dev/hdb 上;另一個(gè)辦法是還是從 IDE1 啟動(dòng),不改變 BIOS 的設(shè)置,但是在看到 LILO 的提示符的時(shí)候,要鍵入 linux root=/dev/hdb1,最前面的 linux 是在 lilo.conf 里面定義的一個(gè) entry,我們只采用這個(gè) entry 所指定的 Kernel Image,但是用 /dev/hdb1 作為 root 文件系統(tǒng)。兩個(gè)辦法可能有的時(shí)候一個(gè)比另一個(gè)好,更方便一些。這就要看具體的情況了。不過(guò),它們的設(shè)置并不是互相沖突的。
在編譯內(nèi)核的時(shí)候,由于我們的內(nèi)核是只有一臺(tái)機(jī)器使用的,所以我們應(yīng)該對(duì)它的情況了如指掌;另外一方面,為了減低不必要的復(fù)雜性,我們決定不用 kernel module 的支持,而把所有需要的東西直接編譯到內(nèi)核的里面。這樣編譯出來(lái)的內(nèi)核,在一臺(tái)普通的 586 主板上,把所有必要的功能都加進(jìn)去,一般也不到 800K 字節(jié)。所以,這個(gè)辦法是可行的。而且減低了 init scripts 的復(fù)雜程度。從運(yùn)行方面來(lái)考慮,由于需要的 kernel 代碼反正是要裝載到內(nèi)存中的,所以并不會(huì)引起內(nèi)存的浪費(fèi)。
在我們的目標(biāo)平臺(tái)上,我們希望使用 USB 存儲(chǔ)設(shè)備。還有一點(diǎn)要注意的,就是對(duì) Frame buffer 的支持。這主要是為了支持 XFree86。一般說(shuō)來(lái),如果我們的顯卡是 XFree86 直接支持的,那當(dāng)然最好,也就不需要 frame buffer 的內(nèi)核支持。但是如果 XFree86 不支持我們的顯卡,我們可以考慮用 VESA 模式。但是 XFree86 的 VESA 卡支持運(yùn)行起來(lái)不太漂亮,還有安全方面的問題,有時(shí)在啟動(dòng)和退出 X Window 的時(shí)候會(huì)出現(xiàn)花屏。所以我們可以采用 kernel 的 vesa 模式的 frame buffer,然后用 xfree86 的 linux frame buffer 的驅(qū)動(dòng)程序。這樣一般就看不到花屏的現(xiàn)象了,而且安全方面也沒有任何問題。
devfs 也是我們感興趣的話題。如果 kernel 不使用 devfs,那么系統(tǒng)上的 root 文件系統(tǒng)就要有 /dev 目錄下面的所有內(nèi)容。這些內(nèi)容可以用 /dev/MAKEDEV 腳本來(lái)建立,也可以用 mknod 手工一個(gè)一個(gè)來(lái)建。這個(gè)方法有其自身的好處。但是它的缺點(diǎn)是麻煩,而且和 kernel 的狀態(tài)又并不一致。相反的,如果使用了 devfs,我們就再也不用擔(dān)心 /dev 目錄下面的任何事情了。/dev 目錄下面的項(xiàng)目會(huì)有 kernel 的代碼自己負(fù)責(zé)。實(shí)際使用起來(lái)的效果,對(duì)內(nèi)存的消耗并不明顯。所以我們選擇 devfs。
busybox
有了 LILO 和 kernel image 之后,接下來(lái),我們要安排 root 文件系統(tǒng)。由于 flash 盤的空間只有 16M 字節(jié),可以說(shuō),這是對(duì)我們最大的挑戰(zhàn)。這里首先要向大家介紹小型嵌入式 Linux 系統(tǒng)安排 root 文件系統(tǒng)時(shí)的一個(gè)常用的利器:BusyBox。
Busybox 是 Debian GNU/Linux 的大名鼎鼎的 Bruce Perens 首先開發(fā),使用在 Debian 的安裝程序中。后來(lái)又有許多 Debian developers 貢獻(xiàn)力量,這其中尤推 busybox 目前的維護(hù)者 Erik Andersen,他患有癌癥,可是卻是一名優(yōu)秀的自由軟件開發(fā)者。
Busybox 編譯出一個(gè)單個(gè)的獨(dú)立執(zhí)行程序,就叫做 busybox。但是它可以根據(jù)配置,執(zhí)行 ash shell 的功能,以及幾十個(gè)各種小應(yīng)用程序的功能。這其中包括有一個(gè)迷你的 vi 編輯器,系統(tǒng)不可或缺的 /sbin/init 程序,以及其他諸如 sed, ifconfig, halt, reboot, mkdir, mount, ln, ls, echo, cat ... 等等這些都是一個(gè)正常的系統(tǒng)上必不可少的,但是如果我們把這些程序的原件拿過(guò)來(lái)的話,它們的體積加在一起,讓人吃不消??墒?busybox 有全部的這么多功能,大小也不過(guò) 100K 左右。而且,用戶還可以根據(jù)自己的需要,決定到底要在 busybox 中編譯進(jìn)哪幾個(gè)應(yīng)用程序的功能。這樣的話,busybox 的體積就可以進(jìn)一步縮小了。
使用 busybox 也很簡(jiǎn)單。只要建一個(gè)符號(hào)鏈接,比方 ln -s /bin/busybox /bin/ls,那么,執(zhí)行 /bin/ls 的時(shí)候,busybox 就會(huì)執(zhí)行 ls 的功能,也會(huì)按照 ls 的方式處理命令行參數(shù)。又比如 ln -s /bin/busybox /sbin/init,這樣我們就有了系統(tǒng)運(yùn)行不可或缺的 /sbin/init 程序了。當(dāng)然,這里的前提是,你在 busybox 中編譯進(jìn)去了這兩個(gè)程序的功能。
這里面要提出注意的一點(diǎn)是,busybox 的 init 程序所認(rèn)識(shí)的 /etc/inittab 的格式非常簡(jiǎn)單,而且和常規(guī)的 inittab 文件的格式不一樣。所以讀者朋友們?cè)跒檫@個(gè) busybox 的 init 寫 inittab 的時(shí)候,要注意一下不同的語(yǔ)法。至于細(xì)節(jié),就不在我們這里多說(shuō)了,請(qǐng)大家參考 Busybox 的用戶手冊(cè)。
本文引用地址:http://cafeforensic.com/article/201706/349414.htm
從啟動(dòng)到進(jìn)入 shell
busybox 安裝好以后,我們就可以考慮重新啟動(dòng),一直到進(jìn)入 shell 提示符了。這之前,我們要準(zhǔn)備一下 /etc 目錄下的幾個(gè)重要的文件,而且要把 busybox 用到的 library 也拷貝過(guò)來(lái)。
用 ldd 命令,后面跟要分析的二進(jìn)制程序的路徑名,就可以知道一個(gè)二進(jìn)制程序,或者是一個(gè) library 文件之間的互相依賴關(guān)系,比如 busybox 就依賴于 libc.so 和 ld-linux.so ,我們有了這些知識(shí),就可把動(dòng)手把所有需要的 library 拷貝到 flash 盤上。由于我們的 flash 盤說(shuō)大不大,說(shuō)小倒也不小,有 16M 字節(jié)之多。我們直接就用 Glibc 的文件也沒有太多問題。如果讀者朋友們有特殊的需要,覺得 Glibc 太龐大了的話,可以考慮用 uClibc,這是一個(gè)非常小巧的 libc 庫(kù),功能當(dāng)然沒有 Glibc 全,但是足夠一個(gè)嵌入式系統(tǒng)使用了。本文就不再介紹 uClibc 了。
庫(kù)程序拷貝過(guò)來(lái)以后,我們就可以考慮系統(tǒng)啟動(dòng)的步驟了。啟動(dòng)的時(shí)候,先是 lilo,接下來(lái)就是 kernel,kernel 初始化之后,就調(diào)用 /sbin/init,然后由 init 解釋 /etc/inittab 運(yùn)行各種各樣的東西。inittab 會(huì)指導(dǎo) init 去調(diào)用一個(gè)最重要的系統(tǒng)初始化程序 /etc/init.d/rcS,我們將要在 rcS 中完成各個(gè)文件系統(tǒng)的 mount,此外,還有在 rcS 中調(diào)用 dhcp 程序,把網(wǎng)絡(luò)架起來(lái)。rcS 執(zhí)行完了以后,init 就會(huì)在一個(gè) console 上,按照 inittab 的指示開一個(gè) shell,或者是開 getty login,這樣用戶就會(huì)看到提示輸入用戶名的提示符。我們這里為了簡(jiǎn)單起見,先直接進(jìn)入 shell,然后等到調(diào)試成功以后,再改成直接進(jìn)入 X Window。
關(guān)于 inittab 的語(yǔ)法,我們上面已經(jīng)提到過(guò)了,希望讀者朋友們?nèi)ゲ闄?quán)威的 busybox 的用戶手冊(cè)。這里,我們先要講一下文件系統(tǒng)的構(gòu)成情況。
安排文件系統(tǒng)
大家已經(jīng)看到,我們的 root 文件系統(tǒng)為了避免麻煩,用的是標(biāo)準(zhǔn)的 ext2 文件系統(tǒng)。由于我們的硬盤空間很小,只有不到 16M,而且我們還要在上面放上 X Window,所以,如果我們?nèi)坑?ext2 的話,F(xiàn)lash 盤的有限空間會(huì)很快耗盡。我們唯一的選擇是采用一個(gè)適當(dāng)?shù)膲嚎s文件系統(tǒng)??紤]到 /usr 目錄下面的內(nèi)容在系統(tǒng)運(yùn)行的時(shí)候,是不需要被改寫的。我們決定選擇只讀的壓縮文件系統(tǒng) cramfs 來(lái)容納 /usr 目錄下面的全部?jī)?nèi)容。
cramfs 是 Linus Torvalds 本人開發(fā)的一個(gè)適用于嵌入式系統(tǒng)的小文件系統(tǒng)。由于它是只讀的,所以,雖然它采取了 zlib 做壓縮,但是它還是可以做到高效的隨機(jī)讀取。既然 cramfs 不會(huì)影響系統(tǒng)讀取文件的速度,又是一個(gè)高度壓縮的文件系統(tǒng),對(duì)于我們,它就是一個(gè)相當(dāng)不錯(cuò)的選擇了。
我們首先把 /usr 目錄下的全部?jī)?nèi)容制成一個(gè) cramfs 的 image 文件。這可以用 mkcramfs 命令完成。得到了這個(gè) usr.img 文件之后,我們還要考慮怎樣才能在系統(tǒng)運(yùn)行的時(shí)候,把這個(gè) image 文件 mount 上來(lái),成為一個(gè)可用的文件系統(tǒng)。由于這個(gè) image 文件不是一個(gè)通常意義上的 block 設(shè)備,我們必須采用 loopback 設(shè)備來(lái)完成這一任務(wù)。具體說(shuō)來(lái),就是在前面提到的 /etc/init.d/rcS 腳本的前面部分,加上一行 mount 命令: mount -o loop -t cramfs /usr.img /usr
這樣,就可以經(jīng)由 loopback 設(shè)備,把 usr.img 這個(gè) cramfs 的 image 文件 mount 到 /usr 目錄上去了。哦,對(duì)了,由于要用到 loopback 設(shè)備,讀者朋友們?cè)诰幾g內(nèi)核的時(shí)候,別忘了加入內(nèi)核對(duì)這個(gè)設(shè)備的支持。對(duì)于系統(tǒng)今后的運(yùn)行來(lái)說(shuō),這個(gè) mount 的效果是透明的。cramfs 的壓縮效率一般都能達(dá)到將近 50%,而我們的系統(tǒng)上絕大部分的內(nèi)容是位于 /usr 目錄下面,這樣一來(lái),原本可能要用到 18M 的 Flash 盤,現(xiàn)在可能只需要 11M 就可以了。一個(gè) 14M 的 /usr 目錄,給壓縮成了僅僅 7M。
上面考慮了壓縮問題,下面還要考慮到,F(xiàn)lash 盤畢竟不像普通硬盤,多次的擦寫畢竟不太好,所以我們考慮,在需要多次擦寫的地方,使用內(nèi)存來(lái)做。這個(gè)任務(wù),我們考慮用 tmpfs 來(lái)完成。至于 tmpfs 和經(jīng)典的 ramdisk 的比較,我們這里就不多說(shuō)了。一般說(shuō)來(lái),tmpfs 更加靈活一些,tmpfs 的大小不像 ramdisk,可以順著用戶的需要增長(zhǎng)或者縮小。我們選擇把 /tmp、/var 等幾個(gè)目錄做成 tmpfs。這只需要我們?cè)?/etc/fstab 里面加上兩行類似下面的文字就可以了: none /var tmpfs default 0 0
然后別忘了在 /etc/init.d/rcS 里面靠近開頭的地方,加上 mount -a。這樣,就可以把 /etc/fstab 里面指定的所有的文件系統(tǒng)都 mount 上來(lái)了。
X Window
進(jìn)行到這里,讀者朋友們可能會(huì)以為,X Window 的安裝可能會(huì)很復(fù)雜。其實(shí)不然,由于我們上面的架子搭好了,X Window 的安裝非常簡(jiǎn)單,只需要把幾個(gè)關(guān)鍵的程序拷貝過(guò)來(lái)就可以了。一般說(shuō)來(lái),只需要 /usr/X11R6 目錄下面的 bin 和 lib 兩個(gè)目錄。然后,根據(jù)用戶各自的需要,還可以做大幅的裁減。比如,如果你的局域網(wǎng)上有一個(gè)開放的 xfs 字體服務(wù)器的話,你可以把所有本地的字體都刪掉,而使用遠(yuǎn)端的字體服務(wù)器。如果只需要運(yùn)行有限的程序,別忘了把沒有用的 library 都刪掉。此外,還可以把多余的 X Window 的 driver 都刪掉,只保留本機(jī)的顯示卡所需要的 driver 就可以了。當(dāng)然,這一關(guān)免不了要做多次測(cè)試。
其它技巧
如果你的工作系統(tǒng)式在另外一臺(tái)機(jī)器上,通過(guò)局域網(wǎng)和本機(jī)互聯(lián)的話,ssh 是一個(gè)不錯(cuò)的工具。此外,ssh 中帶的 scp 用起來(lái)和普通的 cp 拷貝程序差不多,非常方便。用 ssh 和 scp 來(lái)共享文件,遠(yuǎn)程試驗(yàn),你就可以不需要在辦公室里跑來(lái)跑去的了。
如果你需要一個(gè) MS Windows 上運(yùn)行的 X Server 和 xfs 字體服務(wù)器,可以考慮包括在 Red Hat 的 Cygwin 工具箱中的 XFree86 系統(tǒng)。
評(píng)論