自己動手做一個迷你 Linux 系統(轉)
本文將帶領大家構建一個迷你型的 Linux 系統。它佔用的硬碟空間遠小於 16M 位元組,但是卻包括了 XFree86 的 X Window 視窗系統。
目標
本文要構建的這個迷你型的 Linux 系統只能在一臺特定的單機上執行,如果讀者朋友們有興趣的話,在這個系統的基礎上加以改進,是可以構建出通用的、可以在大多數常規 PC 機上即插即用的系統來的。但是這已經不在本文的話題之內了,讀者朋友們如果有興趣,可以透過我的電子郵件和我討論其中的細節問題。
我們的目標 Linux 系統執行在一臺普通的 Intel 386 PC 機上,可以有硬碟,也可以不要硬碟,而用 Flash Disk 來代替。如果是用 Flash 盤的話,需要能夠支援從 Flash 盤啟動,而且 Flash 盤的大小要在 16M 位元組或者以上。我們希望使用者一開機啟動,就直接進入 X Window 圖形介面,執行事先指定好的程式。不需要使用者輸入使用者名稱和密碼進行登入。
我們設定的這個目標有點像一個 X Terminal 終端工作站。稍加改進,還可以做成乾脆無盤的形式,也就是說,連 16M 的 Flash 盤也不要了。不過,這也超出了本文的話題了。讀者朋友們如果有興趣,可以來信和我進行討論。
系統啟動
因為我們要考慮從 Flash 盤進行啟動,所以我們選擇用 LILO 作為我們的 Boot Loader,而不選用 GRUB。這是考慮到 GRUB 有較強的對硬碟和檔案系統的識別能力,而 Flash 盤到底不是標準的硬碟,並且我們選用的檔案系統 GRUB 又不一定認識,搞不好的話 GRUB 反會弄巧成拙。而 LILO 就簡單的多了,它在硬碟開始的 MBR 寫入一個小程式,這個小程式不經過檔案系統,直接從硬碟扇區號,讀出 Kernel Image 裝入記憶體。這樣,保險係數就大大增加。並且也給了我們自由選用檔案系統的餘地。那麼,我們要如何安裝 LILO 呢?
首先,我們要找一塊普通的 800M 左右的 IDE 硬碟,連在目標機器的 IDE 線上。這樣在我們的目標機器上,IDE1 上掛的是 Flash 盤,IDE2 上掛的是一塊工作硬碟。我們用標準的步驟在 IDE2 的標準硬碟上裝上一個 Debian GNU/Linux 系統。當然,如果讀者朋友們手頭沒有 Debian,也可以裝 Red Hat 系統。裝好工作系統之後,要首先做一些裁減工作,把不必要的 Service 和 X Window 等等東西都刪掉。這樣做的目的是增進系統啟動速度,因為我們在後面的工作中,肯定要不停的重新啟動機器,所以啟動速度對我們的工作效率是很關鍵的。
裝好工作系統之後,在 Falsh 盤上做一個 Ext2 檔案系統,這個用 mke2fs 這個命令就可以完成。由於 Flash 盤是接在 IDE1 上的,所以在 Linux 裡面,它的身份是 /dev/hda。本文作者在操作的時候,把整個 Flash 盤劃分了一個整個的分割槽,所以,呼叫 mke2fs 的時候,處理的是 /dev/hda1。讀者朋友們應該可以直接在 /dev/hda 上做一個 Ext2 檔案系統,而不用事先分割槽。
在 Flash 盤上做好了檔案系統之後,就可以把一個編譯好的核心映像檔案 vmlinuz 複製到 Flash 盤上了。注意,必須要先把這個 vmlinuz 映像檔案複製到 Flash 盤上,然後才能在 Flash 盤上安裝 LILO。不然的話,LILO 到時候可是會 LILILILI 打結巴的,因為它會找不到 Kernel Image 在 Flash 盤上的位置的,那樣的話 Flash 盤也就啟動不起來了。還有,如果讀者朋友們在 Flash 盤上用的是一個壓縮的檔案系統的話,到時候 LILO 也會出問題,它雖然能正確的找到 Kernel Image 在硬碟上的起始位置,但是它卻沒有辦法處理被檔案系統重新壓縮過的這個 Kernel Image,不知道該如何把它展開到記憶體中去。
把 Kernel Image 複製過去以後,我們就可以動手編輯一份 lilo.conf 檔案,這份檔案可以就放在工作系統上就行了。但是注意在 lilo.conf 中索引的檔名的路徑可要寫對。這些路徑名都是在工作系統上看上去的路徑名。比如,如果 Flash 盤 Mount 在 /mnt 目錄下面,那麼,在 lilo.conf 中,vmlinuz 的路徑名就是 /mnt/vmlinuz。注意這一點千萬不要搞錯。不然的話,如果一不小心把工作系統的 LILO 給破壞掉了,那就麻煩了。編輯好了 lilo.conf,然後再執行 lilo 命令,注意,要告訴它用這個新的 lilo.conf 檔案,而不要用 /etc/lilo.conf。
安裝好 LILO 之後,我們可以立即重新啟動,測試一下。首先在 BIOS 裡面,設定成從 IDE1 開始啟動,如果我們看到 LILO 的提示符,按回車後還能看到 Kernel 輸出的訊息,這就算是 LILO 的安裝成功了。記得這個操作的方法,以後每次我們更新 Flash 盤上的 Kernel Image,都記得要更新 LILO。也就是說,要重新執行一遍 lilo 命令。
編譯核心
試驗成功 LILO 的安裝以後,我們開始考慮編譯一個新的核心。當然,要編譯新的核心,我們首先要進入我們的工作系統。這裡有兩個辦法進入工作系統,一是在 BIOS 裡面設定從 IDE2 啟動,當然,這就要求當初安裝工作系統的時候,要把 LILO 安裝在 /dev/hdb 上;另一個辦法是還是從 IDE1 啟動,不改變 BIOS 的設定,但是在看到 LILO 的提示符的時候,要鍵入 linux root=/dev/hdb1,最前面的 linux 是在 lilo.conf 裡面定義的一個 entry,我們只採用這個 entry 所指定的 Kernel Image,但是用 /dev/hdb1 作為 root 檔案系統。兩個辦法可能有的時候一個比另一個好,更方便一些。這就要看具體的情況了。不過,它們的設定並不是互相沖突的。
在編譯核心的時候,由於我們的核心是隻有一臺機器使用的,所以我們應該對它的情況瞭如指掌;另外一方面,為了減低不必要的複雜性,我們決定不用 kernel module 的支援,而把所有需要的東西直接編譯到核心的裡面。這樣編譯出來的核心,在一臺普通的 586 主機板上,把所有必要的功能都加進去,一般也不到 800K 位元組。所以,這個辦法是可行的。而且減低了 init scripts 的複雜程度。從執行方面來考慮,由於需要的 kernel 程式碼反正是要裝載到記憶體中的,所以並不會引起記憶體的浪費。
在我們的目標平臺上,我們希望使用 USB 儲存裝置。還有一點要注意的,就是對 Frame buffer 的支援。這主要是為了支援 XFree86。一般說來,如果我們的顯示卡是 XFree86 直接支援的,那當然最好,也就不需要 frame buffer 的核心支援。但是如果 XFree86 不支援我們的顯示卡,我們可以考慮用 VESA 模式。但是 XFree86 的 VESA 卡支援執行起來不太漂亮,還有安全方面的問題,有時在啟動和退出 X Window 的時候會出現破圖。所以我們可以採用 kernel 的 vesa 模式的 frame buffer,然後用 xfree86 的 linux frame buffer 的驅動程式。這樣一般就看不到破圖的現象了,而且安全方面也沒有任何問題。
devfs 也是我們感興趣的話題。如果 kernel 不使用 devfs,那麼系統上的 root 檔案系統就要有 /dev 目錄下面的所有內容。這些內容可以用 /dev/MAKEDEV 指令碼來建立,也可以用 mknod 手工一個一個來建。這個方法有其自身的好處。但是它的缺點是麻煩,而且和 kernel 的狀態又並不一致。相反的,如果使用了 devfs,我們就再也不用擔心 /dev 目錄下面的任何事情了。/dev 目錄下面的專案會有 kernel 的程式碼自己負責。實際使用起來的效果,對記憶體的消耗並不明顯。所以我們選擇 devfs。
busybox
有了 LILO 和 kernel image 之後,接下來,我們要安排 root 檔案系統。由於 flash 盤的空間只有 16M 位元組,可以說,這是對我們最大的挑戰。這裡首先要向大家介紹小型嵌入式 Linux 系統安排 root 檔案系統時的一個常用的利器:BusyBox。
Busybox 是 Debian GNU/Linux 的大名鼎鼎的 Bruce Perens 首先開發,使用在 Debian 的安裝程式中。後來又有許多 Debian developers 貢獻力量,這其中尤推 busybox 目前的維護者 Erik Andersen,他患有癌症,可是卻是一名優秀的自由軟體開發者。
Busybox 編譯出一個單個的獨立執行程式,就叫做 busybox。但是它可以根據配置,執行 ash shell 的功能,以及幾十個各種小應用程式的功能。這其中包括有一個迷你的 vi 編輯器,系統不可或缺的 /sbin/init 程式,以及其他諸如 sed, ifconfig, halt, reboot, mkdir, mount, ln, ls, echo, cat ... 等等這些都是一個正常的系統上必不可少的,但是如果我們把這些程式的原件拿過來的話,它們的體積加在一起,讓人吃不消。可是 busybox 有全部的這麼多功能,大小也不過 100K 左右。而且,使用者還可以根據自己的需要,決定到底要在 busybox 中編譯進哪幾個應用程式的功能。這樣的話,busybox 的體積就可以進一步縮小了。
使用 busybox 也很簡單。只要建一個符號連結,比方 ln -s /bin/busybox /bin/ls,那麼,執行 /bin/ls 的時候,busybox 就會執行 ls 的功能,也會按照 ls 的方式處理命令列引數。又比如 ln -s /bin/busybox /sbin/init,這樣我們就有了系統執行不可或缺的 /sbin/init 程式了。當然,這裡的前提是,你在 busybox 中編譯進去了這兩個程式的功能。
這裡面要提出注意的一點是,busybox 的 init 程式所認識的 /etc/inittab 的格式非常簡單,而且和常規的 inittab 檔案的格式不一樣。所以讀者朋友們在為這個 busybox 的 init 寫 inittab 的時候,要注意一下不同的語法。至於細節,就不在我們這裡多說了,請大家參考 Busybox 的使用者手冊。
從啟動到進入 shell
busybox 安裝好以後,我們就可以考慮重新啟動,一直到進入 shell 提示符了。這之前,我們要準備一下 /etc 目錄下的幾個重要的檔案,而且要把 busybox 用到的 library 也複製過來。
用 ldd 命令,後面跟要分析的二進位制程式的路徑名,就可以知道一個二進位制程式,或者是一個 library 檔案之間的互相依賴關係,比如 busybox 就依賴於 libc.so 和 ld-linux.so ,我們有了這些知識,就可把動手把所有需要的 library 複製到 flash 盤上。由於我們的 flash 盤說大不大,說小倒也不小,有 16M 位元組之多。我們直接就用 Glibc 的檔案也沒有太多問題。如果讀者朋友們有特殊的需要,覺得 Glibc 太龐大了的話,可以考慮用 uClibc,這是一個非常小巧的 libc 庫,功能當然沒有 Glibc 全,但是足夠一個嵌入式系統使用了。本文就不再介紹 uClibc 了。
庫程式複製過來以後,我們就可以考慮系統啟動的步驟了。啟動的時候,先是 lilo,接下來就是 kernel,kernel 初始化之後,就呼叫 /sbin/init,然後由 init 解釋 /etc/inittab 執行各種各樣的東西。inittab 會指導 init 去呼叫一個最重要的系統初始化程式 /etc/init.d/rcS,我們將要在 rcS 中完成各個檔案系統的 mount,此外,還有在 rcS 中呼叫 dhcp 程式,把網路架起來。rcS 執行完了以後,init 就會在一個 console 上,按照 inittab 的指示開一個 shell,或者是開 getty + login,這樣使用者就會看到提示輸入使用者名稱的提示符。我們這裡為了簡單起見,先直接進入 shell,然後等到除錯成功以後,再改成直接進入 X Window。
關於 inittab 的語法,我們上面已經提到過了,希望讀者朋友們去查權威的 busybox 的使用者手冊。這裡,我們先要講一下檔案系統的構成情況。
安排檔案系統
大家已經看到,我們的 root 檔案系統為了避免麻煩,用的是標準的 ext2 檔案系統。由於我們的硬碟空間很小,只有不到 16M,而且我們還要在上面放上 X Window,所以,如果我們全部用 ext2 的話,Flash 盤的有限空間會很快耗盡。我們唯一的選擇是採用一個適當的壓縮檔案系統。考慮到 /usr 目錄下面的內容在系統執行的時候,是不需要被改寫的。我們決定選擇只讀的壓縮檔案系統 cramfs 來容納 /usr 目錄下面的全部內容。
cramfs 是 Linus Torvalds 本人開發的一個適用於嵌入式系統的小檔案系統。由於它是隻讀的,所以,雖然它採取了 zlib 做壓縮,但是它還是可以做到高效的隨機讀取。既然 cramfs 不會影響系統讀取檔案的速度,又是一個高度壓縮的檔案系統,對於我們,它就是一個相當不錯的選擇了。
我們首先把 /usr 目錄下的全部內容製成一個 cramfs 的 image 檔案。這可以用 mkcramfs 命令完成。得到了這個 usr.img 檔案之後,我們還要考慮怎樣才能在系統執行的時候,把這個 image 檔案 mount 上來,成為一個可用的檔案系統。由於這個 image 檔案不是一個通常意義上的 block 裝置,我們必須採用 loopback 裝置來完成這一任務。具體說來,就是在前面提到的 /etc/init.d/rcS 指令碼的前面部分,加上一行 mount 命令:
mount -o loop -t cramfs /usr.img /usr
這樣,就可以經由 loopback 裝置,把 usr.img 這個 cramfs 的 image 檔案 mount 到 /usr 目錄上去了。哦,對了,由於要用到 loopback 裝置,讀者朋友們在編譯核心的時候,別忘了加入核心對這個裝置的支援。對於系統今後的執行來說,這個 mount 的效果是透明的。cramfs 的壓縮效率一般都能達到將近 50%,而我們的系統上絕大部分的內容是位於 /usr 目錄下面,這樣一來,原本可能要用到 18M 的 Flash 盤,現在可能只需要 11M 就可以了。一個 14M 的 /usr 目錄,給壓縮成了僅僅 7M。
上面考慮了壓縮問題,下面還要考慮到,Flash 盤畢竟不像普通硬碟,多次的擦寫畢竟不太好,所以我們考慮,在需要多次擦寫的地方,使用記憶體來做。這個任務,我們考慮用 tmpfs 來完成。至於 tmpfs 和經典的 ramdisk 的比較,我們這裡就不多說了。一般說來,tmpfs 更加靈活一些,tmpfs 的大小不像 ramdisk,可以順著使用者的需要增長或者縮小。我們選擇把 /tmp、/var 等幾個目錄做成 tmpfs。這隻需要我們在 /etc/fstab 裡面加上兩行類似下面的文字就可以了:
none /var tmpfs default 0 0
然後別忘了在 /etc/init.d/rcS 裡面靠近開頭的地方,加上 mount -a。這樣,就可以把 /etc/fstab 裡面指定的所有的檔案系統都 mount 上來了。
X Window
進行到這裡,讀者朋友們可能會以為,X Window 的安裝可能會很複雜。其實不然,由於我們上面的架子搭好了,X Window 的安裝非常簡單,只需要把幾個關鍵的程式複製過來就可以了。一般說來,只需要 /usr/X11R6 目錄下面的 bin 和 lib 兩個目錄。然後,根據使用者各自的需要,還可以做大幅的裁減。比如,如果你的區域網上有一個開放的 xfs 字型伺服器的話,你可以把所有本地的字型都刪掉,而使用遠端的字型伺服器。如果只需要執行有限的程式,別忘了把沒有用的 library 都刪掉。此外,還可以把多餘的 X Window 的 driver 都刪掉,只保留本機的顯示卡所需要的 driver 就可以了。
當然,這一關免不了要做多次測試。
其它技巧
如果你的工作系統式在另外一臺機器上,透過區域網和本機互聯的話,ssh 是一個不錯的工具。此外,ssh 中帶的 scp 用起來和普通的 cp 複製程式差不多,非常方便。用 ssh 和 scp 來共享檔案,遠端試驗,你就可以不需要在辦公室裡跑來跑去的了。
如果你需要一個 MS Windows 上執行的 X Server 和 xfs 字型伺服器,可以考慮包括在 Red Hat 的 Cygwin 工具箱中的 XFree86 系統。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-939932/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 自己做個迷你型linux(轉)Linux
- 動手製做自己的一張軟盤大小的Linux(1) (轉)Linux
- 建立一個自己的 Linux系統Linux
- 自己動手做一個批次doc轉換為docx檔案的小工具
- 做一個自己的工作列 (轉)
- 自己動手寫一個 SimpleVueVue
- 自己動手寫作業系統(第一天)作業系統
- 找人做網站不如自己動手網站
- 自己動手做QQ木馬----郵件傳送篇 (轉)
- RxJava:自己動手擼一個RxBinding(一)。RxJava
- Linux系統安裝,教你安裝一個屬於自己的Linux系統Linux
- 自己動手實現一個前端路由前端路由
- 自己動手寫一個持久層框架框架
- 自己動手搞一個tip 外掛
- 自己動手實現一個EventBus框架框架
- 自己動手實現一個Unix Shell
- 用commander做一個自己的eslint腳手架EsLint
- 自己動手實現一個阻塞佇列佇列
- RxJava:自己動手擼一個RxBinding(二)。RxJava
- 建立小於16M XFree86迷你Linux系統(轉)Linux
- 自己動手開發一個 Web 伺服器(一)Web伺服器
- 手寫一個最迷你的Web伺服器Web伺服器
- iOS動手做一個直播(原理篇)iOS
- 教你動手做一個iOS越獄appiOSAPP
- 用React-Native+Mobx做一個迷你水果商城APPReactAPP
- 自己動手實現一個簡單的 IOC
- 自己動手寫一個Bug管理工具
- 自己動手寫一個簡單的MVC框架MVC框架
- 自己動手設計並實現一個linux嵌入式UI框架LinuxUI框架
- 手寫一個迷你版 HashMap,面試隨便問!HashMap面試
- 在Linux中做系統引導盤(轉)Linux
- 用GHOST對LINUX系統做備份(轉)Linux
- 自己動手做智慧家居之:智慧空調控制
- 一個嵌入式Linux系統的鍵盤驅動實現(轉)Linux
- 如何做一個對賬系統
- 自己動手擼一個cron表示式解析器
- 自己動手實現一個 Java Class 解析器Java
- 自己動手開發一個 Web 伺服器(三)Web伺服器