DOM 的製作 FOR LINUX

作為嵌入式系統,使用環境通常都比較惡劣,而應用又比較簡單。為系統的穩定通常都需要使用DOM、CF卡一類的存儲設備來代替硬碟。因此需要製作一個小於32M的linux運行系統。
使用到的軟體包括:syslinux, busybox, linux kernel 2.4.18, redhat 9
 作為嵌入式系統,使用環境通常都比較惡劣,而應用又比較簡單。為系統的穩定通常都需要使用DOM、CF卡一類的存儲設備來代替硬碟。因此需要製作一個小於32M的linux運行系統。
一、準備軟體環境
1.一套linux的運行環境,選用redhat 9的基本安裝,需要能夠編譯內核方便以後重新編譯內核;
2.bootloader軟體,選用syslinux中的extlinux;
http://syslinux.zytor.com
3.主要系統應用程式,選用busybox;
busybox能夠以一個小型的應用程式提供整個命令集的功能。
http://www.busybox.net


二、製作可以啟動的盤

fdisk /dev/hdc1
本實驗使用cf盤 cf to ide轉換卡,用fdisk對盤進行分區,但這一步驟需要確認哪一個設備是cf卡。這個可以同dmesg來看。

mke2fs /dev/hdc1
格式化cf盤為ext2格式

mkdir /mnt/cf
mount /dev/hdc1 /mnt/cf
extlinux /mnt/cf
安裝bootloader到cf卡上。

完成以後cf卡基本可以引導,現在進行一次重啟動測試一下。
實驗結果,只需要看到Extlinux 的資訊即說明安裝成功。

三、安裝內核和配置引導
由於目前只是實驗先不進行內核裁減,直接使用redhat 9的內核檔。
mount /dev/hdc1 /mnt/cf
cp /boot/vmlinuz-version /mnt/cf/
cp /boot/initrd-version.img /mnt/cf/

vi /mnt/cf/extlinux.conf
寫入一下內容:
default emblinux
display logo.txt
label emblinux
kernel vmlinuz
append root=/dev/hdc1 initrd=initrd.img splash=silent ide=nodma

首先要注意的檔案名為extlinux.conf,因為在syslinux和isolinux中都是使用.cfg的尾碼,這樣可能會給人一個錯覺認為也是用.cfg。結果,我在這個地方花了不少的時間,終於找到一個帖子提到使用extlinux.conf。
另外增加ide=nodma只適用在使用cf卡的情況,這個可以避免啟動時因為讀盤超時而無法繼續的錯誤(0x58)。

完成這些步驟,內核就能引導。
這一步完成,重啟能看到內核引導資訊即為成功。
四、安裝主要應用程式和運行環境
mount /dev/hdc1 /mnt/cf

創建需要的目錄
cd /mnt/cf
mkdir etc bin sbin var usr lib tmp proc initrd dev

根據busybox的說明編譯,然後安裝。
make PREFIX=/mnt/cf install

複製基本的dev文件
cp -arf /dev/* /mnt/cf/dev/
需要進行一些裁減,否則會超過限制大小。

複製busybox下的examples/bootfloppy/etc目錄下檔
cp -arf examples/bootfloopy/etc/* /mnt/cf/etc

編輯init.d/rcS文件
vi /mnt/cf/etc/init.d/rcS
增加
/bin/sh

複製lib
先用ldd busybox看需要哪些so
把相應的so複製到lib目錄下,這一步比較關鍵。
複製/lib/modules和/lib/security目錄到/mnt/cf/lib目錄下,並進行一些裁減。
完成這最後一步,整個啟動盤已經可以正常啟動,並進入shell下。
 from http://www.linuxjiaocheng.com/




******************************************************************************************************


DOM製作流程
專案基本結束,這個是其中系統裁減的一個總結文檔,不知道有沒有人感興趣:)

=============================================

前言:
為了完成用戶的需求,需製作一個完整的環境供AP運行,且存在一些約束條件。

關鍵字:
DOM Kernel Busybox X-Window Window-Manager Interbase nvidia cutdown

目標說明:
在一個64M的DOM(Disk on module)上建立可以運行完整的AP的環境

約束條件:
1、可利用的總空間為64M,由DOM提供,但實際可用空間只有53-59M,原因可能與設備檔和DOM本身有關,未確定
2、顯卡為nvidia系列
3、kernel選用2.4.20,沒有使用redhat自帶的版本。採集卡的Driver目前還只能在2.4.20的kernel下編譯,由於其移植性較差,已經開始考慮重新整理成可適合kernelversion大於2.4.25的所有kernel,參考bttv的最新實現
4、資料庫選用interbase系列,目前使用的為firebird-1.5(firebird為interbase的開源實現,介面和interbase基本相同)。
5、其他附屬的功能要求,在後面的文檔中會有說明

製作流程:
某些部分的原理和實現沒有辦法寫的很全面,但基本上會提供一些url的連接,供相關人員參考。基本上按照製作流程來寫,前後相互牽連的部分不做特別說明。

一、Kernel的選擇和編譯:
由於driver的緣故,只能使用2.4.20的kernel。2.4.20和2.4.25都有對Driver做過嘗試,其他版本的kernel沒有試過,應該是可以的,尚未確認。在2.6的kernel上無法編譯,目前確定的原因是makefile有問題,估計做一些相應的修改還是可以的,可參考bttv的makefile(http://linux.bytesex.org/v4l2/bttv.html)。
回到kernel上來,基本上的編譯原則是儘量減去不需要的部分,以及除了一些需要臨時載入的Driver儘量不要出現module。由於上面所說的理由,DOM中使用的kernel為原始的2.4.20,可以從http://www.kernel.org下載,本文檔的附加檔裏也可以找到。
另外,由於需求的定義,系統啟動時需要顯示splash畫面,所以kernel還需要加入bootsplash功能,這個功能是第三方提供的,作為補丁加入kernel。作法如下:

1、打內核補丁並編譯內核
假設內核原始檔案安裝在/usr/src/linux/。下載bootsplash 3.07(地址:ftp://ftp.suse.com),然後:

yourbox:~ # cd /usr/src/linux
yourbox:/usr/src/linux # patch -p1 < /path/to/bootsplash-3.0.7-2.4.20-vanilla.diff
yourbox:/usr/src/linux #

配置內核,如make menuconfig或make xconfig,在”Console drivers” -> “Frame-Buffer support” 選擇 “VESA VGA graphics console” 或其他與你的顯卡相應的驅動。打開 “Use splash screen instead of boot logo”. 在 “Block Devices”中打開”Initial Ramdisk support”,保存配置並編譯內核,將生成的內核拷到/boot 下,並修改lilo或grub的配置檔以使用新的內核來啟動。

2、加入圖片
下載並安裝splash工具:ftp://ftp.suse.com/pub/people/

# cd ~/splash
# tar xvjf splashutils.tar.bz2
splashutils/
splashutils/Makefile
splashutils/splash.c
[..]
splashutils/ChangeLog
splashutils/COPYING
# cd splashutils
# make splash
gcc -Os -Wall -c -o splash.o splash.c gcc -Os -Wall -o splash splash.o
strip splash
# cp splash /sbin/
# cd ..

將圖片及相關的資訊加入到initrd中去:
/sbin/splash -s -f /etc/bootsplash/themes/yourtheme/config/bootsplash-1024x768.cfg >> /boot/initrd.splash

圖片在附件檔中

3、運行lilo更新配置檔(grub就不用更新了),重新啟動,如果一切正常,就可以看到啟動畫面了。同時會有這樣一些資訊:

vesafb: framebuffer at 0xf0000000, mapped to 0xdc816000, size 65472k vesafb: mode is 1024x768x16, linelength=2048, pages=41 vesafb: protected mode interface info at c000:5137 vesafb: scrolling: redraw
vesafb: directcolor: size=0:5:6:5, shift=0:11:5:0 Looking for splash picture.... silenjpeg size 11165 bytes, found (1024x768, 4912 bytes, v3) Got silent jpeg.

kernel的config檔比較大,在附件中有,這裏就不列舉了。

編譯過程:
1、獲取2.4.20的原始kernel壓縮包(linux-2.4.20.tar.bz2)
2、tar xvjpf linux-2.4.20.tar.bz2
3、cp config-2.4.20 (kernelsource)/.config #拷貝config-2.4.20到kernel source所在目錄中並以.config為新的檔案名
4、cd (kernelsource)
5、make menuconfig #不需要做任何改動,直接退出
6、make dep && make bzImage && make modules && make modules_install && make install
7、如果沒有問題,繼續下一步,如果有問題,請檢查編譯環境是否正確,並重複step 6
8、此時kernel已經編譯完畢,需要做兩件事情,一是保存將來放入DOM的文件,二是將當前的發行版的kernel換成2.4.20,以便後面的nvidia顯卡dirver的正確編譯。
9、創建一個保存目錄,比如~/kernelbackup
10、cp (kernelsource)/arch/i386/boot/bzImage ~/kernelbackup # 保存kernel
11、cp /lib/modules/2.4.20 ~/kernelbackup/ -arf # 保存編譯出的所有modules
12、如果當前的發行版使用的是grub,則修改/boot/grub/grub.conf(如果沒有這個檔可以修改/boot/grub/menu.lst,都是一樣的),如果是lilo,修改/etc/lilo.conf。下面是grub的修改說明,lilo的修改辦法可以參考相關文檔:

# add below to your grub.conf
title new kernel(2.4.20) # title just, u can modify it anywhere
root (hd0,0) # root setup
kernel (hd0,0)/boot/bzImage-2.4.20 ro root=/dev/hda1 vga=791 splash=silent # just.....
initrd (hd0,0)/boot/initrd.splash # splash that show when booting of OS

13、reboot
14、選擇新的啟動選項,檢查是否正確

二、Shell的選擇和編譯:
到目前為止,kernel的裁減基本上結束,下面是shell的選擇和編譯。 對於linux而言,kernel只是提供系統調用介面,本身無法直接使用,需要外部shell的支援。一般shell有幾種選擇,如bash、ash、busybox等,由於busybox相對尺寸最小,而且提供了基本完整的功能,所以選擇busybox做為系統的shell。詳細資訊參閱www.busybox.net,附件中有目前使用的busybox版本。busybox的流程主要是編譯和安裝,從而聯合kernel組成一個基本系統。 busybox的配置檔在附件中有,這裏就不列舉了。

編譯過程:
和kernel基本相似
1、解壓busybox
2、複製config到busybox源碼目錄下
3、make menuconfig #不做改動即可退出
4、make dep && make

三、基本系統的安裝:
到此時,busybox和kernel都已經準備完畢,接下來需要一個分區來安裝他們。 不管是使用一個單獨的分區還是完整的DOM都可以,但總歸需要一個完整的目標分區供使用。假設目標分區為/dev/hdc1,下面的說明會以此為基準。 需要說明的一點是,一開始儘量不要用DOM直接調試,因為其速度和容量都十分的不好,會造成調試的困難,直到調試後期再使用是個比較不錯的主意。

現在進入基本系統的組裝:
# fdisk /dev/hdc1 and format it with ext2 or ext3. My suggest is ext3.
Mount /dev/hdc1 /mnt/dom # mount目標分區
mkdir /mnt/dom/boot
mkdir /mnt/dom/boot/grub
cp (kernelbackup)/bzImage /mnt/dom/boot # copy kernel to dom
cp (kernelbackup)/initrd.splash /mnt/dom/boot # copy initrd splash to dom
mkdir /mnt/dom/lib
mkdir /mnt/dom/lib/modules
cp (kernelbackup)/2.4.20 /mnt/dom/lib/modules -arf # copy all modules to dom cd (busyboxpath)
make PREFIX=/mnt/dom install # install busybox to dom
現在,一個基本系統基本安裝完畢,接下來是配置問題:
mkdir /mnt/dom/etc # all config here
mkdir /mnt/dom/dev # device file
mkdir /mnt/dom/mnt
mkdir /mnt/dom/proc
mkdir /mnt/dom/tmp
mkdir /mnt/dom/var
mkdir /mnt/dom/lib
mkdir /mnt/dom/root # home of root
mkdir /mnt/dom/usr # X window-manager lib, etc
cp (busyboxpath)/examples/bootfloppy/etc/* /mnt/dom/etc -arf # base config
cp /dev/* /mnt/dom/dev -arf # device file. Will cutdown part of all

下面是加入必需的連接庫:
1、ldd busybox
2、查看busybox使用了哪些連接庫,拷貝至目標分區中同樣的路徑下,一般為/lib
3、再用ldd查看連接庫是否還有需要的庫檔,如果有同樣拷貝到目標分區中
4、重複第三步
5、cp /dev/* /mnt/dom/dev/ -arf # 後期還會做一些裁減
Grub配置:
# add below to your grub.conf
title new kernel(2.4.20) # title just, u can modify it anywhere
root (hd0,0) # root setup
kernel (hd0,0)/boot/bzImage-2.4.20 ro root=/dev/hda1 vga=791 splash=silent # just.....
initrd (hd0,0)/boot/initrd.splash # splash that show when booting of OS

現在可以做一些測試,看看基本系統是否工作正常。執行下麵的命令
cd /mnt
mkdir dom
mount /dev/hdc1 dom # mount it
chroot /mnt/dom /bin/sh
如果你看到登陸成功的資訊就表示基本系統沒有什麼問題了。

重新啟動機器,並選擇新的啟動選項,看看基本系統是否正常,如果有問題,重新檢查前面的步驟是否做的有問題。如果啟動正常,那麼,基本系統就基本完備,可以繼續後面的步驟了。

四、Xfree86的裁減和安裝:
基本系統已經正常工作,接下來就是xfree86的裁減和安裝,首先切換到目標分區並確定系統處於正常工作狀態。
在這裏需要說明一下Linux的目錄分佈和作用情況。首先通過“ls /”列舉一下根分區,大致會有以下目錄:
bin boot dev etc home lib mnt opt proc root sbin tmp usr var
下面逐一說明:
bin: shell的工作目錄,比如sh、bash、mount等命令
boot: kernel、ramdisk檔以及grub(lilo)的存放目錄,有的發行版會為此目錄單獨創建一個分區,以防止系統崩潰的影響。在DOM中是不考慮的。
dev: 所有的設備檔都存放在這裏,比如/dev/video0、/dev/hda等。全部設備檔大概要佔用400K左右的空間,但似乎全部拷貝過來的話,DOM總是會報空間不足,但實際還是有空間的,原因不明。目前的做法是對設備檔做了一些調整,去除了不需要的部分,參考後面的檔列表。
etc: Ap配置以及系統配置存放目錄
home:普通用戶的工作目錄根
lib:基本庫存放目錄
mnt:mount
opt:看情形,目前是用做存放firebird
proc:系統工作所需的目錄
root:一般為root的工作目錄,可以調換
sbin:常規命令存放目錄
tmp:一般為臨時目錄
usr:所有擴展命令和xfree86,以及window-manager所在目錄,是系統最大的一個目錄,包含內容最多。對於DOM來說,主要是存放連接庫、xfree86、字體、window-manager等。
Var:臨時目錄,一般在發行版中為存放website檔、安裝檔以及一些log資訊等,在DOM中只作為臨時目錄使用

大致的分佈情況說明完畢,接下來就是具體的裁減工作了。 實際上,xfree86有一些替代實現,比如freedesktop、fb等,甚至framebuffer也是一個可以考慮的方向,但是由於AP使用了nvidia顯卡提供的opengl 1.3介面,導致目前的唯一選擇就是xfree86。也許有其他更小的實現,希望能在以後改進。 進入正題,xfree86的主程序實際上就是一個XFree86,位於/usr/X11R6/bin,有的發行版下X是一個指向XFree86的連接,有的卻是一個完整的程式,但不管怎麼樣,Xfree86就是最主要的程式。現在,在目標分區上mount發行版,以便可以拷貝我們所需要的:
cd /mnt
mkdir dist # create mount path of distribute
mount /dev/hda1 dist # /dev/hda1 is root partition of your distribute. Check it.
現在/mnt/dist就是發行版所在的位置。

mkdir /usr/X11R6
mkdir /usr/X11R6/bin
mkdir /usr/lib
mkdir /usr/X11R6/lib
創建一些需要的目錄。

cp /mnt/dist/usr/X11R6/bin/XFree86 /usr/X11R6/bin -arf 拷貝xfree86的主程序。
cp /mnt/dist/usr/bin/ldd /sbin # copy ldd that is used to cutdown
ldd是用來在DOM的環境中做裁減工作的,直接輸入ldd看看是否可以運行,如果執行有問題,一般是相關的連接庫不全,按照之前的方法複製過來就可以了。

現在,要查看XFree86需要哪些連接庫和配置檔,以保證其可以運行起來。
cd /usr/X11R6/bin
ldd Xfree86
此時會看到很多的連接庫,那麼就需要把這些庫全部從發行版上複製過來,可以直接複製到相對應的目錄下,比如/usr/lib/或者/usr/X11R6/lib/下,需要注意的一點是,有些庫本身還會需要其他的庫,可以一層層的ldd出來,網路中有人做過自動工作的工具,但還是手動裁減比較可靠。全部的庫導入完畢後,嘗試運行/usr/X11R6/bin/XFree86,會看到一些出錯資訊,提示/etc/X11/XF86Config不存在,那麼就將發行版中的/etc/X11目錄全部複製到目標分區中:
cp /mnt/dist/etc/X11 /etc -arf
實際上這個目錄中不是全部都需要的,某些部分是可以刪除的,但我沒有具體實驗,而且尺寸並不是很大,就全部使用了。
現在再執行/usr/X11R6/bin/XFree86,會提示一些庫沒有找到,但實際上之前已經全部複製過來了,原因是從shell執行一條命令的時候,命令所需要的庫是從以下的途徑得到的:
1、搜索/lib
2、搜索/etc/ld.so.cache
之前所複製的庫檔大半是放在/usr/lib和/usr/X11R6/lib下的,而且現在的/etc下還沒有ld.so.cache檔,要生成這個檔就需要ldconfig這個命令:
cp /mnt/dist/sbin/ldconfig /sbin -arf
現在ldconfig是有了,但還需要與之有關的配置檔/etc/ld.so.conf,所以:
vi /etc/ld.so.conf
/usr/lib
/usr/X11R6/lib
現在執行ldconfig,就會在/etc/下出現一個ld.so.cache。以後如果有新加入的庫檔,而且不是存放在/lib/下的,都按照這個步驟來導入。現在,執行/usr/X11R6/bin/XFree86,出現的錯誤提示為無法打開/var/kdb和/var/log。
這裏需要說明配置上的一個修改,cat /etc/fstab,會看到現在的fstab只有一句話:
none /proc proc defaults 0 0
現在要加入一些新的配置,新的fstab如下:
proc /proc proc defaults 0 0
none /var tmpfs defaults 0 0
none /tmp tmpfs defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0
none /data tmpfs defaults 0 0
現在/var、/tmp和/data都是在記憶體中了,其中/data是將來mount磁片的地方,需要手動mkdir出來:
mkdir /data
現在修改/etc/init.d/rcS:
#! /bin/sh

/bin/mount -a

mkdir /var/log
mkdir /var/lib
mkdir /var/lib/xkb

重啟DOM,現在應該存在/var/log、/var/lib、/var/xkb目錄了,當然這些目錄只是存放在記憶體中,所以需要每次啟動時臨時創建。
再運行XFree86,應該會看到一個錯誤的提示,說明還需要opengl的一些連接庫,從發行版中複製出來就可以了。
嘗試在目標分區中執行/usr/X11R6/bin/XFree86,如果沒有進入X介面,需要檢查之前的步驟是否有沒有做對的地方。

五、Window-Manager的選擇安裝:
到目前為止,X已經完全移植到DOM中了,但一個包含基本系統和X的系統還不能滿足AP的要求,接下來是Window-manager的選擇和安裝。
kde和gnome是無法安裝到DOM中的,尺寸太大,可能的選擇包括twm、fluxbox、windowmaker、icewm等,但需要滿足以下幾個條件:
1、有caption,而且Modal dialog不能被切到後臺,以符合用戶的操作習慣
2、X上不能有任何多餘的部分,即除了AP,不存在任何UI,如taskbar之類
3、尺寸要小
4、最好不要有system menu和system buttons

經過挑選,最終選擇了fluxbox作為DOM的window-manager,尺寸相對其他window manager要大一些(10M),但是較好的滿足了以上條件。

安裝過程:
1、下載fluxbox
2、./configure
3、make
4、make install
5、複製相關檔到DOM的相同目錄中
6、測試,如果有問題,重複第一步
等window manager安裝完畢後,一個包含基本系統和window的環境就創建成功了。接下來就是一些附屬部件的裁減和安裝了。

六、其他部件的裁減和安裝:
先切換到發行版。最後定義的資料庫引擎為Firebird 1.5,所以先下載firebird 1.5(http://prdownloads.sourceforge.net/...0-0.i686.tar.gz),然後在發行版上先安裝。firebird會安裝在/opt目錄下,將/opt/firebird複製到目標分區中:
cp /opt/firebird /mnt/dom/opt -arf

然後修改配置檔:
vi /mnt/dom/etc/init.d/rcS
#! /bin/sh

/bin/mount -a

mkdir /var/log
mkdir /var/lib
mkdir /var/lib/xkb

/opt/firebird/bin/fb_lock_mgr &
/opt/firebird/bin/fb_inet_server &

現在切換到目標分區中,會看到進程列表中有一個fb_lock_mgr,這說明firebird已經安裝成功。

由於實際的裁減過程中會遇到各種各樣的問題,有些方面牽涉太廣,以至沒有辦法單獨說明,所以接下來是一些可能會遇到的問題說明:
1、nvidia的驅動需要先在發行版上解開,再執行make && make install > install,然後修改install中的目標路徑以將相關檔安裝到DOM上,比如cp libGL.so /usr/lib改為cp libGL.so /mnt/dom/usr/lib。具體操作就不列舉了。
2、busybox的mount有問題,不能mount -o loop,所以cramfs的檔需要用發行版的mount,所以在dom的/mnt/cramfs目錄下有一個mount,而/bin也有一個mount
3、為了便於調試,在dom中加入了telnet server和ftp client,分別使用的是utelnetd和cmdftp,出處可以通過google搜索
4、grub的安裝使用grub-install即可
5、由於firebird等模組至少需要一個root用戶,而busybox缺省是沒有用戶的,所以需要在/etc下複製兩個檔:shadow和passwd
6、dhcp client使用的是udhcpc
7、字體主要和以下目錄有關:/usr/lib/gconv、/usr/lib/locale、/usr/X11R6/lib/X11/font和/usr/X11R6/lib/X11/locale(限於redhat,其他發行版會有一些差異,但具體內容是一樣的)
8、硬體自檢使用的是hwsetup,並對源代碼做過一些修改,只保留了audio和network card的檢測,在附件裏有原始和修改過的兩個版本,可以對比參考
9、web site功能是用kylix自己實現的,沒有使用apache
10、由於dom的空間不足以攤平所有檔,所以/usr下面的檔全部都是以一個cramfs檔的格式出現的,參看後面的檔列表。

七、DOM的最後安裝和打包:
cramfs文件的創建:
1、確定目標分區的可運行
2、確定/mnt/dom/usr/目錄下的檔完整性
3、mkcramfs /mnt/usr.cramfs /mnt/dom/usr # make a cramfs file of usr path
4、保存/mnt/dom下的完整列表,以備將來的修改
5、rm /mnt/dom/usr/* -rf
6、mkdir /mnt/dom/mnt/cramfs
7、cp /mnt/usr.cramfs /mnt/dom/mnt/cramfs
8、cp /bin/mount /mnt/dom/mnt/cramfs -arf
9、add /mnt/dom/etc/init.d/rcS:/mnt/cramfs/mount -o loop -t cramfs /mnt/cramfs/usr.cramfs /usr

現在,/mnt/dom目錄下就已經是一個除了grub全部都是完整的DOM鏡像了。那麼最後要將這個鏡像導入真實的DOM之中:
mkdir /mnt/realdom
mount /dev/hdc1 /mnt/realdom # assume /dev/hdc1 is real dom
cp /mnt/dom/* /mnt/realdom/ -arf
sync
此時DOM中已經有了一個完整的鏡像,但還沒有grub,那麼執行:
grub-install /dev/hdc1
重新啟動,並在BOIS中選擇真正的DOM,確認DOM的啟動沒有問題。重新切換到發行版,開始做DOM的鏡像檔:
dd if=/dev/hdc of=domfs # domfs is image of dom
保存好這個名字為domfs的鏡像檔,這就是一個可安裝的包,安裝到其他DOM中時,輸入:
dd if=domfs of=/dev/hdc
到目前為止,所有的流程都走了一遍,剩下的就是不斷的實踐和驗證了。

後記:
經過一次完整的裁減過程,很自然的對Linux的整體結構和方式有了很清晰的瞭解,雖然不能對kernel有深入瞭解,但是起碼為以後kernel方面的學習打下了很好的基礎。由於牽涉方面比較多和雜,有些部分只能是實踐過後才能知道其中的訣竅,當然大體的過程是一樣的。

2004-06-01
cyantree


附錄:
DOM文件列表:


**************************************************************************************

第一章 前言
目的
本文的目的,是講述嵌入式Linux系統的建立、開發的一般過程。製作一個小型的Linux的系統,可以移植至其他硬碟、軟碟、優盤、flash rom……

關於作者
九賤,E名kendo,喜歡網路入侵技術、防火牆、入侵檢測技術及網路技術,對Linux也頗感興趣,想認識有共同愛好的朋友。最近閒暇,把一些學過的東西寫下來,總結總結,以作備忘這需。已完成的有《網路入侵檢測設計與Snort2.2源碼分析》和這篇《我也來學做嵌入式Linux》。正在進行中的有《Windows防火牆技術實現大全》和《Linux防火牆實現及源碼分析》。大家可以在CU上,或者是到我的小站www.skynet.org.cn上與我交流

做一個嵌入式Linux系統究竟要做哪些工作
做一個嵌入式Linux系統究竟需要做哪些工作?也就是本文究竟要講述哪些內容?我先介紹一個脈絡,可以做為我們後面工作的一個總的提綱:
第一步、建立交叉編譯環境
沒有交叉開發經驗的讀者,可能一時很難接受這個概念。首先,要明白兩個概念:一般我們工作的機器,稱為開發機、主機;我們製作好的系統將要放到某台機器,如手機或另一台PC機,這台機我們稱為目標主機。
我們一般開發機上已經有一套開發工具,我們稱之為原生開發套件,我們一般就是用它們來寫程式,那麼,那什麼又是交叉編譯環境呢?其實一點也不神秘,也就是在開發機上再安裝一套開發工具,這套開發工具編譯出來的程式,如內核、系統工作或者我們自己的程式,是放在目標主機上運行的。
那麼或許有初學者會問,直接用原生開發工具為目標主機編譯程序不就完了?至少我當初是這麼想的。一般來說,我們的開發機都是X86平臺,原生開發套件開發的工具,也針對X86平臺,而我們的目標主機可能是PowerPC、IXP、MIPS……所以,我們的交叉編譯環境是針對某一類具體平臺的。
一般來講,交叉開發環境需要二進位工具程式、編譯器、C程式庫,嵌入式開發常用的這三類軟體是:
Binutils
Gcc
uClibc
當然,GNU包含的工具套件不僅於此,你還要以根據實際需要,進行選擇

第二步、編譯內核
開發工具是針對某一類硬體平臺,內核同樣也是。這一步,我們需要用第一步中建立的工具,對內核進行編譯,對於有內核編譯經驗的人來說,這是非常簡單的;

第三步、建立根檔系統
也就是建立我們平常看到的bin、dev、proc……這一大堆目錄,以及一些必備的檔;另外,我們還需要為我們的目標系統安裝一些常用的工具軟體,如ls、ifconfig……當然,一個辦法是找到這些工具的源代碼,用第一步建立的交叉編譯工具來編譯,但是這些軟體一是數量多,二是某些體積較大,不適合嵌入式系統,這一步,我們一般都是用busybox來完成的,包括系統引導軟體init;
最後,我們為系統還需要建立初始化的引導檔,如inittab……

第四步、啟動系統
在這一步,我們把建立好的目標、檔、程式、內核及模組全部拷貝到目的機記憶體上,如硬碟。然後為系統安裝bootloader,對於嵌入式系統,有許多引導程式可供我們使用。不過它們許多都有硬體平臺的限制。當然,如果你是工作在X86,可以直接用lilo來引導,事實上,本文就是採用的lilo。
做到這一步,將目標存儲設備掛上目的機,如果順利,就可以啟動系統了。
當然,針對某些特別的平臺,不能像硬碟這樣拷貝了,需要讀卡器、燒錄……但是基本的方法是相通的!

第五步、優化和個性化系統
通過前四步,我們已經得到了一個可以正常工作的系統。在這一步裏,就是發揮你想像的時候了……


本文的工作環境
專案根目錄/home/kendo/project ------>;我將它指定至PATH:$PRJROOT
子目錄及說明
目錄 內容
bootloader 目標板的引導載入程式,如lilo等
build-tools 建立交叉編譯平臺的工具源碼
debug 調試工具及所有相關包
doc 項目中用到的所有文檔
images 編譯好的內核映射,以及根檔系統
kernel 各個版本的Linux內核源碼
rootfs 製作好的根檔系統
sysapps 目標板將要用到的系統應用系統,比如thttpd,udhcpd等
tmp 存放暫存檔案
tools 編譯好的跨平臺開發工具鏈以及C程式庫


工作的腳本
#!/usr/bin

export PROJECT=skynet
export PRJROOT=/home/${PROJECT}
export TARGET=i386-linux
export PREFIX=${PRJROOT}/tools
export TARGET_PREFIX=${PREFIX}/${TARGET}
export PATH=${PREFIX}/bin:/bin:/sbin:/usr/bin:/usr/sbin

cd $PRJROOT


第二章 建立交叉編譯環境
在CU中發表的另一篇同名的貼子裏,我講述了一個全手工創建交叉編譯環境的方法。目前,創建交叉編譯環境,包括建立根檔,一般來講,有兩種方法:
手功創建
可以得到最大程式的個性化定制,缺點是過程繁雜,特別是極易出錯,注意這個“極”字,包括有經驗的開發人員;
自動創建
無它,方便而。

因為前一篇文章中,已經講述了全手工創建交叉編譯環境的一般性方法,本文就不打算再重複這個步驟了,感興趣的朋友,可以再去搜索那篇貼子,提醒一點的就是,在準備工具鏈的時候,要注意各個工具版本之間的搭配、每個工具需要哪些補丁,我建議你在google上針對這兩項搜索一下,準備一個清單,否則……
本章要講述的是自動創建交叉編譯環境的方法。目標,針對商業硬體平臺,廠家都會為你提供一個開發包,我用過XX廠家的IXP425和MIPS的,非常地方便,記得我第一次接觸嵌入式開發,拿著這個開發包自動化創建交叉編譯環境、編譯內核、建立根檔系統、創建Ram Disk,我反復做了三四次,結果還不知道自己究竟做了些什麼,呵呵,夠傻吧……
所以,建議沒有這方面經驗的讀者,還是首先嘗試一下手工創建的方法吧,而本章接下來的內容,是送給曾經被它深深傷害而不想再次去親歷這項工作而又想提高交率而又在通用平臺上工作沒有商業開發包的朋友。

建立交叉開發工具鏈
準備工具:
buildroot-0.9.27.tar.tar
只需要一個軟體?對,其他的不用準備了,buildroot事實上是一個腳本與補丁的集合,其他需要用到的軟體,如gcc、uClibc,你只需在buildroot中指明相應的版本,它會自動去給你下載。
事實上,buildroot到網上去下載所需的所有工作是需要時間的,除非你的帶寬足夠,否則下載軟體時間或許會占去80%,而我在做這項工作之間,所需的工作鏈全部都在我本地硬碟上,我解壓開buildroot後,新建dl檔夾,將所有工具源碼的壓縮包拷貝進去,呵呵,buildroot就不用去網上下載了。

我的軟體清單:
Linux-libc-headers-2.4.27.tar.bz2
Gcc-3.3.4.tar.bz2
binutils 2.15.91.0.2.tar.bz2
uClibc 0.9.27.tar.bz2
genext2fs_1.3.orig.tar.gz
ccache-2.3.tar.gz

將它拷貝到${PRJROOT}/build-tools下,解壓
[root@skynet build-tools]# tar jxvf buildroot-0.9.27.tar.tar
[root@skynet build-tools]#cd buildroot
配置它:
[root@skynet build-tools]#make menuconfig
Target Architecture (i386) --->; 選擇硬體平臺,我的是i386
Build options --->; 編譯選項
這個選項下重要的是(${PRJROOT}/tools) Toolchain and header file location?編譯好的工具鏈放在哪兒?
如果你像我一樣,所有工具包都在本地,不需它到網上自動下載,可以把wget command選項清空;
Toolchain Options --->; 工具鏈選項
--- Kernel Header Options 頭檔它會自動去下載,不過應該保證與你將要用的內核是同一個版本;
[] Use the daily snapshot of uClibc? 使用最近的uClibc的snapshot
Binutils Version (binutils 2.15.91.0.2) --->; Binutils的版本
GCC compiler Version (gcc 3.4.2) --->; gcc 版本

  • Build/install c++ compiler and libstdc++?
    [ ] Build/install java compiler and libgcj? 支援的語言,我沒有選擇java
    [ ] Enable ccache support? 啟用ccache的支援,它用於編譯時頭檔的緩存處理,用它來編譯程序,第一次會有點慢,但是以後的速度可就很理想了,呵呵……
    --- Gdb Options 根據你的需要,選擇gdb的支援

    Package Selection for the target --->;
    這一項我沒有選擇任意一項,因為我打算根檔系統及busybox 等工具鏈創建成工,手工來做。
    Target Options --->; 檔系統類型,根據實際需要選,我用的ext2;

    配置完成後,編譯它:
    [root@skynet build-tools]#make

    這一項工作是非常花時間的,我的工具包全部在本地,也花去我一小時十三分的時間,如果全要下載,我估計網速正常也要多花一兩個鐘頭。

    經過漫長的等待(事實上並不漫長,去打了幾把遊戲,很快過去了):
    ……
    make[1]: Leaving directory `/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3'
    touch -c /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs
    #-@find /home/skynet/build-tools/buildroot/build_i386/root/lib -type f -name \*.so\* | xargs /home/skynet/tools/bin/i386-linux-uclibc-strip --remove-section=.comment --remove-section=.note --strip-unneeded 2>;/dev/null || true;
    /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs -i 503 -b 1056 \
    -d /home/skynet/build-tools/buildroot/build_i386/root -q -D target/default/device_table.txt /home/skynet/build-tools/buildroot/root_fs_i386.ext2

    大功告成!!!

    清點戰利品
    讓我來看看它究竟做了哪些事情吧:
    [root@skynet skynet]# cd tools
    [root@skynet tools]# ls
    bin bin-ccache i386-linux i386-linux-uclibc include info lib libex!ec man usr

    bin:所有的編譯工具,如gcc,都在這兒了,只是加了些指定的首碼;
    bin-ccache:如果在Toolchain optaion中沒有選擇對ccache的支持,就沒有這一項了;
    i386-linux:鏈結檔;實際指向include
    i386-linux-uclibc:uclibc的相關工具;
    include:供交叉開發工具使用的頭文件;
    info:gcc 的info文件;
    lib:供交叉開發工具使用的程式庫文件;
    ……

    現在可以把編譯工具所在目錄XXX/bin添加至PATH了

    測試工具鏈
    如果你現在寫一個程式,用i386-linux-gcc來編譯,運行的程式會告訴你:
    ./test: linked against GNU libc
    因為程式運行庫會尋到默認的/lib:/usr/lib上面去,而我們目前的uclibc的庫並不在那裏(雖然對於目的機來講,這是沒有錯的),所以,也只能暫時靜態編譯,試試它能否工作了。當然,你也可以在建好根檔系統後,試試用chroot……

    第三章 編譯內核
    本章的工作,是為目的機建立一個合適的內核,對於建立內核,我想有兩點值得考慮的:
    1、功能上的選擇,應該能夠滿足需要的情況下,儘量地小;
    2、小不是最終目的,穩定才是;

    所以,最好編譯內核前有一份目的機硬體平臺清單以及所需功能清單,這樣,才能更合理地裁減內核。

    準備工具
    Linux內核源碼,我選用的是Linux-2.4.27.tar.bz2

    編譯內核
    將Linux-2.4.27.tar.bz2拷貝至${PRJROOT}/kernel,解壓
    #cd linux-2.4.27
    //配置
    # make ARCH=i386 CROSS_COMPILE=i386-linux- menuconfig
    //建立源碼的依存關係
    # make ARCH=i386 CROSS_COMPILE=i386-linux- clean dep
    //建立內核映射
    # make ARCH=i386 CROSS_COMPILE=i386-linux- bzImage
    ARCH指明了硬體平臺,CROSS_COMPILE指明了這是交叉編譯,且編譯器的名稱為i386-linux-XXX,這裏沒有為編譯器指明路徑,是因為我前面已將其加入至環境變數PATH。

    又是一個漫長的等待……
    OK,編譯完成,673K,稍微大了點,要移到其他平臺,或許得想辦法做到512以下才好,回頭來想辦法做這個工作。

    安裝內核
    內核編譯好後,將內核及配置檔拷貝至${PRJROOT}/images下。
    # cp arch/i386/boot/bzImage ${PRJROOT}/images/bzImage-2.4.27-rmk5
    # cp vmlinux ${PRJROOT}/images/vmlinux-2.4.27-rmk5
    # cp System.map ${PRJROOT}/images/System-2.4.27-rmk5
    # cp .config ${PRJROOT}/images/2.4.27-rmk5

    我採用了尾碼名的方式重命名,以便管理多個不同版本的內核,當然,你也可以不用這樣,單獨為每個版本的內核在images下新建對應檔夾也是可行的。

    安裝內核模組
    完整內核的編譯後,剩下的工作就是建立及安裝模組了,因為我的內核並沒有選擇模組的支援(這樣擴展性差了一點,但是對於我的系統來說,功能基本上定死了,這樣影響也不太大),所以,剩下的步驟也省去了,如果你還需要模組的支援,應該:
    //建立模組
    #make ARCH=i386 CROSS_COMPILE=i386-linux- modules
    //安裝內核模組至${PRJROOT}/images
    #make ARCH=i386 CROSS_COMPILE= i386-linux- \
    >;INSTALL_MOD_PATH=${PRJROOT}/images/modules-2.4.18-rmk5 \
    >;modules_install

    最後一步是為模組建立依存關係,不能使用原生的depmod來建立,而需要使用交叉編譯工具。需要用到busybox中的depmod.pl腳本,很可惜,我在busybox1.0.0中,並沒有找到這個腳本,所以,還是借用了busybox0.63中scripts中的depmod.pl。
    將depmod.pl拷貝至${PREFIX}/bin目錄中,也就是交叉編譯工具鏈的bin目錄。
    #depmod.pl \
    >;-k ./vmlinux –F ./System.map \
    >;-b ${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules >; \
    >;${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules/2.4.27-rmk5/modules.dep

    注:後面討論移植內核和模組內容時,我只會提到內核的拷貝,因為我的系統並沒有模組的支援。如果你需要使用模組,只需按相同方法將其拷貝至相應目錄即可。

    附,內核編譯清單
    附,內核選擇:
    內核編譯記錄:
    Code maturity level options 不選
    Loadable module support 不選
    Processor type and features 根據實際,選擇處理器類型
    General setup --->;

  • Networking support
  • PCI support
    (Any) PCI access mode
  • PCI device name database
  • System V IPC
  • Sysctl support
    (ELF) Kernel core (/proc/kcore) format
  • Kernel support for ELF binaries
  • Power Management support

    Memory Technology Devices (MTD) --->; MTD設備,我用CF卡,不選

    Parallel port support --->; 不選
    Plug and Play configuration --->; 我的系統用不著即插即用,不選

    Block devices --->;

  • Loopback device support
  • RAM disk support
    (4096) Default RAM disk size (NEW)
  • Initial RAM disk (initrd) support

    Multi-device support (RAID and LVM) --->; 不選

    Networking options --->; 基本上都選了

    ATA/IDE/MFM/RLL support --->; 用了默認的

    Telephony Support --->; 不選

    SCSI support --->; 不選

    Fusion MPT device support --->; 不選

    I2O device support --->; 不選

    Network device support --->; 根據實際情況選擇

    Amateur Radio support --->; 不選

    IrDA (infrared) support --->; 不選

    ISDN subsystem --->; 不選

    Old CD-ROM drivers (not SCSI, not IDE) --->; 不選

    Input core support --->; 不選

    Character devices --->;

  • Virtual terminal
  • Support for console on virtual terminal
  • Standard/generic (8250/16550 and compatible UARTs) serial support
  • Support for console on serial port

    Multimedia devices --->; 不選

    File systems --->;

  • Kernel automounter version 4 support (also supports v3)
  • Virtual memory file system support (former shm fs)
  • /proc file system support
  • Second extended fs support

    Console drivers --->;

  • VGA text console 調試時接顯示器用

    剩下三個都不要
    Sound --->;
    USB support --->;
    Kernel hacking --->;

    第四章 建立根檔系統
    1、建立目錄
    構建工作空間時,rootfs檔夾用來存放根檔系統,
    #cd rootfs
    根據根檔系統的基本結構,建立各個對應的目錄:
    # mkdir bin dev etc lib proc sbin tmp usr var root home
    # chmod 1777 tmp
    # mkdir usr/bin usr/lib usr/sbin
    # ls
    dev etc lib proc sbin tmp usr var
    # mkdir var/lib var/lock var/log var/run var/tmp
    # chmod 1777 var/tmp

    對於單用戶系統來說,root和home並不是必須的。
    準備好根檔系統的骨架後,把前面建立的檔安裝到對應的目錄中去。
    2、拷貝程式庫
    把uclibc的庫檔拷貝到剛才建立的lib文件夾中:
    # cd ${PREFIX}/lib
    [root@skynet lib]# cp *-*.so ${PRJROOT}/rootfs/lib
    [root@skynet lib]# cp -d *.so.[*0-9] ${PRJROOT}/rootfs/lib

    3、 拷貝內核映射和內核模組
    因為沒有模組,所以拷貝模組就省了,
    新建boot目錄,把剛才建立好的內核拷貝過來
    # cd /home/kendo/control-project/daq-module/rootfs/
    # mkdir boot
    # cd ${PRJROOT}/images
    # cp bzImages-2.4.18-rmk5 /home/kendo/control-project/daq-module/rootfs/boot

    4、 建立/dev下邊的設備檔
    在linux中,所有的的設備檔都存放在/dev中,使用mknod命令創建基本的設備檔。
    mknod命令需要root許可權,不過偶本身就是用的root用戶,本來是新建了一個用戶專門用於嵌入式製作的,不過後來忘記用了……
    # mknod -m 600 mem c 1 1
    # mknod -m 666 null c 1 3
    # mknod -m 666 zero c 1 5
    # mknod -m 644 random c 1 8
    # mknod -m 600 tty0 c 4 0
    # mknod -m 600 tty1 c 4 1
    # mknod -m 600 ttyS0 c 4 64
    # mknod -m 666 tty c 5 0
    # mknod -m 600 console c 5 1
    基本的設備檔建立好後,再創建必要的符號鏈結:
    # ln -s /proc/self/fd fd
    # ln -s fd/0 stdin
    # ln -s fd/1 stdout
    # ln -s fd/2 stderr
    # ls
    console fd mem null random stderr stdin stdout tty tty0 tty1 ttyS0 zero

    設備檔也可以不用手動創建,聽說RedHat /dev下的腳本MAKEDEV 可以實現這一功能,不過沒有試過……

    基本上差不多了,不過打算用硬碟/CF卡來做存儲設備,還需要為它們建立相關檔,因為我的CF在目的機器上是CF-to-IDE,可以把它們等同來對待,先看看Redhat 下邊had的相關屬性:
    # ls -l /dev/hda
    brw-rw---- 1 root disk 3, 0 Jan 30 2003 /dev/hda
    # ls -l /dev/hda1
    brw-rw---- 1 root disk 3, 1 Jan 30 2003 /dev/hda1
    對比一下,可以看出,had類型是b,即塊設備,主編號為3,次編號從0遞增,根限位是
    rw-rw----,即660,所以:
    # mknod -m 660 hda b 3 0
    # mknod -m 660 hda1 b 3 1
    # mknod -m 660 hda2 b 3 2
    # mknod -m 660 hda3 b 3 3


    5、添加基本的應用程式
    未來系統的應用程式,基本上可以分為三類:
     基本系統工具,如ls、ifconfig這些……
     一些服務程式,管理工具,如WEB、Telnet……
     自己開發的應用程式

    這裏先添加基本的系統工具,有想過把這些工具的代碼下載下來交叉編譯,不過實在是麻煩,用BusyBox,又精簡又好用……
    將busybox-1.00.tar.gz下載至sysapps目錄下,解壓:
    #tar zxvf busybox-1.00.tar.gz
    #cd busybox-1.00
    //進入配置功能表
    #make TARGET_ARCH=i386 CROSS=i386-linux- PREFIX=${PRJROOT}/rootfs menuconfig
    //建立依存關係
    #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs dep
    //編譯
    #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs
    //安裝
    #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs install

    # cd ${PRJROOT}/rootfs/bin
    # ls
    addgroup busybox chown delgroup echo kill ls mv ping rm sleep
    adduser chgrp cp deluser grep ln mkdir netstat ps rmdir umount
    ash chmod date dmesg hostname login mount pidof pwd sh vi
    一下子多了這麼多命令……
    配置busybox的說明:
    A、如果編譯時選擇了:
    Runtime SUID/SGID configuration via /etc/busybox.conf
    系統每次運行命令時,都會出現“Using fallback suid method ”
    可以將它去掉,不過我還是在/etc為其建了一個檔busybox.conf搞定;
    B、

  • Do you want to build BusyBox with a Cross Compiler? (i386-linux-gcc) Cross Compiler prefix
    這個指明交叉編譯器名稱(其實在編譯時的命令行已指定過了……)
    C、安裝選項下的(${PRJROOT}/rootfs) BusyBox installation prefix,這個指明了編譯好後的工具的安裝目錄。
    D、靜態編譯好還是動態編譯好?即是否選擇
    [ ] Build BusyBox as a static binary (no shared libs)
    動態編譯的最大好處是節省了寶貴空間,一般來說都是用動態編譯,不過我以前動態編譯出過問題(其實是庫的問題,不關busybox的事),出於慣性,我選擇了靜態編譯,為此多付出了107KB的空間。
    E、其他命令,根據需要,自行權衡。


    6、系統初始化檔
    內核啟動時,最後一個初始化動作就是啟動init程式,當然,大多數發行套件的Linux都使用了與System V init相仿的init,可以在網上下載System V init套件,下載下來交叉編譯。另外,我也找到一篇寫得非常不錯的講解如何編寫初始化文件的文件,bsd-init,回頭附在後面。不過,對於嵌入式系統來講,BusyBox init可能更為合適,在第6步中選擇命令的時候,應該把init編譯進去。
    #cd ${PRJROOT}/rootfs/etc
    #vi inittab
    我的inittal文件如下:
    #指定初始化檔
    ::sysinit:/etc/init.d/rcS
    #打開一個串口,串列傳輸速率為9600
    ::respawn:/sbin/getty 9600 ttyS0
    #啟動時執行的shell
    ::respawn:/bin/sh
    #重啟時動作
    ::restart:/sbin/init
    #關機時動作,卸載所有檔系統
    ::shutdown:/bin/umount -a –r

    保存退出;

    再來編寫rcS腳本:
    #mkdir ${PRJROOT}/rootfs/etc/init.d
    #cd ${PRJROOT}/rootfs/etc/init.d
    #vi rcS
    我的腳本如下:
    #!/bin/sh

    #Set Path
    PATH=/sbin:/bin
    export PATH

    syslogd -m 60
    klogd

    #install /proc
    mount -n -t proc none /proc

    #reinstall root file system by read/write mode(need: /etc/fstab)
    mount -n -o remount,rw /

    #reinstall /proc
    mount -n -o remount,rw -t proc none /proc

    #set lo ip address
    ifconfig lo 127.0.0.1

    #set eth0 ip address
    #當然,這樣子做只是權宜之計,最後做的應該是在這一步引導網路啟動腳本,像RedHat
    #那樣,自動讀取所有指定的配置檔來啟動
    ifconfig eth0 192.168.0.68 netmask 255.255.255.0

    #set route
    #同樣的,最終這裏應該是運行啟動路由的腳本,讀取路由配置檔
    route add default gw 192.168.0.1

    #還差一個運行服務程式的腳本,哪位元有現成的麼?
    #網卡/路由/服務這三步,事實上可以合在一步,在rcS這一步中,做一個迴圈,運行指定啟動目錄下的所有腳,先將就著這麼做吧,確保系統能夠正常啟動了,再來寫這個腳本。

    #set hostname
    hostname MyLinux

    保存退出。

    編寫fstab檔
    #vi fstab
    我的fstab很簡單:
    /dev/hda1 / ext2 defaults 1 1
    none /proc proc defaults 0 0

    第五章 讓MyLinux能夠啟動
    前一章,我們把編譯好的內核、應用程式、配置檔都拷貝至rootfs目錄對應的子目錄中去了,這一步,就是把這些檔移植至目的機的記憶體。這裏,我是先另外拿一塊硬碟,掛在我的開發機上做的測試,因為我的本本用來寫文檔,PC機用來做開發機,已經沒有另外的機器了……但是本章只是講述一個一般性的過程,並不影響你直接在目標主機上的工作。
    因為以後目的機識別硬碟序號都是hda,而我現在直接掛上去,則會是hdb、hdc……這樣,安裝lilo時有點麻煩(雖然也可以實現)。所以我想了另一個辦法:
     把新硬碟掛在IDE0的primary上,進入linux後,會被認為是had;
     原來主機的裝Redhat的硬碟,我將它從IDE0的primary上變到了IDE1 的primary,因為它的lilo早已裝好,基本上不影響系統的使用;

    分區和格式化
    BIOS中改為從第二個硬碟啟動;也就是從我原來開發機啟動,新的硬碟被識別成了had。
    #fdisk /dev/hda
    用d參數刪除已存在的所有分區
    用n參數新建一個分區,也是就/dev/hda1
    格式化
    #mkfs.ext2 /dev/hda1

    安裝bootloader
    因為我是X86平臺,所以直接用了lilo,如果你是其這平臺,當然,有許多優秀的bootloader供你選擇,你只需查看其相應的說明就可以了。
    編譯lilo配置檔,我的配置檔案名為target.lilo.conf,置於${PRJROOT}/rootfs/etc目錄。內容如下所示:
    boot=/dev/hda
    disk=/dev/hda
    bios=0x80
    image=/boot/bzImage-2.4.18-rmk5
    label=Linux
    root=/dev/hda1
    append="root=/dev/hda1"
    read-only

    //新建文件夾,為mount做新準備
    #mkdir /mnt/cf
    //把目標硬碟mount上來
    #mount –t ext2 /dev/hdc1 /mnt/cf
    回到rootfs
    #cd ${PRJROOT}/rootfs
    拷貝所有檔至目標硬碟
    #cp –r * /mnt/cf

    這樣,我們所有的檔都被安裝至目標硬碟了,當然,它還不能引導,因為沒有bootloader。使用如下命令:
    # lilo -r /mnt/cf -C etc/target.lilo.conf
    Warning: LBA32 addressing assumed
    Added Linux *
    -r :改變根目標為/mnt/cf ,這樣配置檔其實就是/mnt/cf/etc/target.lilo.conf,也就是我們先前建立的文件。
    當然,完成這一步,需要lilo22.3及以後版本,如果你的版本太舊,比如Redhat9.0自帶的,就會出現下面的資訊:
    #lilo –r /mnt/cf –C etc/target.lilo.conf
    Fatal: open /boot/boot.b: No such file or directory
    這時,你需要升級你的lilo,或者重新安裝一個。

    啟動系統
    #umount /mnt/cf
    #reboot

    將BIOS改為從IDE0啟動,也就是目標硬碟。如果一切順利,你將順利進入一個屬於你的系統。

    回頭再來看看我們的工作空間吧
    [root@skynet lib]# df /dev/hda1
    Filesystem 1K-blocks Used Available Use% Mounted on
    /dev/hda1 3953036 1628 3750600 1% /mnt/cf

    總共花去了我1628KB的空間,看來是沒有辦法放到軟碟裏邊去了^o^,不過一味求小,並不是我的目標。

    [root@skynet skynet]# ls ${PRJROOT}
    bootloader build-tools debug doc images kernel rootfs sysapps tmp tools
    這幾個目錄中的檔,呵呵,與本文一開頭規劃的一樣

    [root@skynet skynet]# ls build-tools/
    buildroot buildroot-0.9.27.tar.tar
    包含了buildroot源碼及壓縮包,事實上buildroot下邊還包括了GNU其他工具的源碼、編譯檔等諸多內容,是我們最重要的一個檔夾,不過到現在它已經沒有多大用處了,如果你喜歡,可以將它刪除掉(不建議)。

    [root@skynet skynet]# ls images
    2.4.18-rmk5 bzImage-2.4.18-rmk5 System-2.4.18-rmk5 vmlinux-2.4.18-rmk5
    內核映射及配置檔等,如果你有模組,因為還有相應的目錄

    [root@skynet skynet]# ls kernel/
    linux-2.4.27 linux-2.4.27.tar.bz2
    內核源碼及壓縮包

    [root@skynet skynet]# ls rootfs/
    bin boot dev etc home lib linuxrc proc root sbin tmp usr var
    製作好的根檔系統,重中之重,注意備份……

    [root@skynet skynet]# ls sysapps/
    busybox-1.00 busybox-1.00.tar.gz
    busybox-1.00源碼包,或許你還要繼續添加/刪除一些命令……

    [root@skynet skynet]# ls tools
    bin i386-linux i386-linux-uclibc include info lib man
    這個也很重要,我們製作好的交叉開發工具鏈。如果你要繼續開發程式,這個目錄重要性就很高了。

    其他目錄暫時是空的。


    第六章 完善MyLinux
    關於進一步的調試,你可以在開發機上使用chroot /mnt/cf /bin/sh這樣的命令,以使我們在目標根檔系統上工作。

    支援多用戶
    因為我在編譯busybox時,已經將它的多用戶那一大堆命令編譯了進來。現在關鍵是的要為其建立相應的檔;
    進入原來的開發機,進入rootfs目錄,切換根目錄
    #chroot rootfs/ /bin/sh
    A、 建立/etc/passwd檔,我的檔內容如下:
    root:x:0:0:root:/root:/bin/bash
    B、 建立/etc/group檔,我的檔內容如下:
    root:x:0:
    bin:x:1:
    sys:x:2:
    kmem:x:3:
    tty:x:4:
    tape:x:5:
    daemon:x:6:
    disk:x:7:
    C、 為root建立密碼
    #passwd root

    試試用addgroup/addusr……這堆命令。然後重啟,從目標硬碟上啟動;從console口,9600登陸試試(因為我在inittab中啟用了ttyS0,我未來的目的機,是沒有顯卡的,需要從console口或SSH進去管理)
    MyLinux login: root
    Password:

    BusyBox v1.00 (2004.10.10-04:43+0000) Built-in shell (ash)
    Enter 'help' for a list of built-in commands.

    ~ #
    成功了……

    增加WEB Server
    Busybox裏邊有httpd選項,不過我編譯時並沒有選擇,所以還是自己來安裝。我使用的軟體是thttpd-2.25b.tar.gz,將它移至sysapps目錄下。
    [root@skynet sysapps]# tar zxvf thttpd-2.25b.tar.gz
    [root@skynet sysapps]# cd thttpd-2.25b
    //配置
    [root@skynet thttpd-2.25b]# CC=i386-linux-gcc ./configure --host=$TARGET
    ……
    i386-linux-gcc -static htpasswd.o -o htpasswd -lcrypt
    make[1]: warning: Clock skew detected. Your build may be incomplete.
    make[1]: Leaving directory `/home/skynet/sysapps/thttpd-2.25b/extras'
    //拷貝至根檔目錄
    [root@skynet thttpd-2.25b]# cp thttpd ${PRJROOT}/rootfs/usr/sbin
    //trip處理
    [root@skynet thttpd-2.25b]# i386-linux-strip ${PRJROOT}/rootfs/usr/sbin/thttpd

    剩下的,就發揮各人的想像吧……


    獨孤九賤 2005-11-1 02:34

    繼續補完

    不好意思,最近工作太忙,好久沒有來搞這個東東了,加之心愛的手機丟了,心情又不太好,不過一切都過去了,繼續來將它補充完整。

    修改啟動腳本
    在前面寫rcS啟動腳本中。當時只是為了系統能夠正常地啟動,在啟動網卡/路由/服務等時,有如下語句:
    ——————————————————————————————————————————————
    #set lo ip address
    ifconfig lo 127.0.0.1

    #set eth0 ip address
    #當然,這樣子做只是權宜之計,最後做的應該是在這一步引導網路啟動腳本,像RedHat
    #那樣,自動讀取所有指定的配置檔來啟動
    ifconfig eth0 192.168.0.68 netmask 255.255.255.0

    #set route
    #同樣的,最終這裏應該是運行啟動路由的腳本,讀取路由配置檔
    route add default gw 192.168.0.1
    ……
    ———————————————————————————————————————————————
    這樣配置的最大壞處就是不能根據配置檔自定義,每次開機都定死了,現在來修改它,將這段語句刪除之,換成如下語句:
    for i in /etc/start/S??* ;do
    # Ignore dangling symlinks (if any).
    [ ! -f "$i" ] && continue

    echo "Running $i ."
    case "$i" in
    *.sh)
    # Source shell script for speed.
    (
    trap - INT QUIT TSTP
    set start
    . $i
    )
    ;;
    *)
    # No sh extension, so fork subprocess.
    $i start
    ;;
    esac
    echo "Done $i ."
    echo
    done
    解釋一下,這段語句的作用,就是啟動/etc/start/目錄下,所有以S開頭的腳本檔,可以啟動兩類,以sh結尾或沒有 sh尾碼的。
    這樣,我們在/etc/目錄下再新建一目錄start/,這裏面就是我們啟動時需要的腳本的。先來啟動網卡。

    修改網卡配置檔
    我是根據Red hat的作法,把網卡配置放在/etc/sysconfig/network-scripts目錄下,類似於ifcfg-ethXX這樣子,它們的語法是:
    DEVICE=eth0
    BOOTPROTO=static
    BROADCAST=88.88.88.255
    IPADDR=88.88.88.44
    NETMASK=255.255.255.0
    NETWORK=88.88.88.0
    ONBOOT=yes
    好,建立這些目錄和檔,我共有兩個檔ifcfg-ethXX。回到/etc/start目錄,建立網卡的啟動腳本S01interface:
    #!/bin/sh

    . /etc/sysconfig/network
    #enable ip_forword
    echo >1 /proc/sys/net/ipv4/ip_forward

    #enable syn_cookie
    echo >1 /proc/sys/net/ipv4/tcp_syncookies

    #enable loopback interface
    /sbin/ifconfig lo 127.0.0.1

    #eanble ethernet interface
    /usr/sbin/bootife

    #set hostname
    if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]
    then
    HOSTNAME=localhost
    fi

    /bin/hostname ${HOSTNAME}

    請注意這個腳本檔,有兩個地方:
    1、包含了另一個配置檔/etc/sysconfig/network,在這裏,我也是照抄了redhat,我的/etc/sysconfig/network這個檔的內容如下:
    NETWORKING=yes
    HOSTNAME=skynet
    GATEWAY=88.88.88.2
    2、在啟動網卡時,我使用了
    #eanble ethernet interface
    /usr/sbin/bootife
    bootife是我自己寫的一個C程式,作用是讀取/etc/sysconfig/network-scripts/下面的ifcfg-ethXX檔,並配置之,本來這裏就該用shell來完成更合適一點,無奈,偶shell功底實在差了一點(剛學幾天),就是想從Redhat中照抄過來,反復試了幾次也沒有成功。所以被逼無奈用C來完成之,後面我會附上我的C的源碼,也希望哪位大哥能夠寫一段Shell的程式代替它,放上來大家共用之。

    修改路由啟動檔
    同樣的,我在/etc/start下,建立新腳本S02route.sh,它的作用是啟動所有配置的靜態路由:
    #!/bin/bash

    . /etc/sysconfig/network
    # Add non interface-specific static-routes.

    if [ -f /etc/sysconfig/static-routes ]
    then
    grep "eth*" /etc/sysconfig/static-routes | while read ignore args ; do
    # echo "/sbin/route add -"$args
    /sbin/route add -$args
    done
    fi

    #Add defalut gw
    /sbin/route add default gw ${GATEWAY}

    OK,啟動時讀取的配置檔是/etc/sysconfig/static-routes ,它的語法和Redhat是一樣的,請參照建立此文件。

    啟動服務程式
    新建啟動腳本S03server:
    #!/bin/sh
    #------------------------------------------------------------------
    #-- Source
    #-- Author(s) : kendo
    #-- Email: kendo999@sohu.com
    #-- http://www.skynet.org.cn
    #-- 2005/10/31
    #------------------------------------------------------------------

    . /etc/sysconfig/bootserver

    if [ "$enable_httpd" = 1 ] ; then
    . /etc/scripts/httpd.sh $1
    fi

    if [ "$enable_adsl" = 1 ] ; then
    ……
    fi

    if [ "$enable_udhcpd" = 1 ] ; then
    ……
    fi

    很簡單,根據相應變數的值,調用相應的腳本。
    1、這些啟動標誌變數,我定義在了/etc/sysconfig/bootserver當中,其內容如下:
    #start server on system boot
    #1:yes 0:no
    enable_httpd=1
    enable_adsl=1
    enable_udhcpd=1

    2、每種服務對應的腳本,我都放在了/etc/scripts下麵。這些腳本,取決於你打算使用哪些服務程式了。腳本的來源,可以自己編寫,有可能其源碼中自帶有,也可以到網上查找……我就不再一一贅述了,

    OK,基本上,腳本的修改就完成了,下一步,將是建立RamDisk。

    ——————————————————————————————————————————————
    附,讀取網卡配置檔,啟動網卡的C源碼:
    /************************************************************************
    ** author:kendo
    ** date:2005/10/26

    ***********************************************************************/

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <dirent.h>
    #include <unistd.h>

    #define NETCFGDIR "/etc/sysconfig/network-scripts/"

    struct _ifcfg{
    char device[8];
    char bootproto[8];
    char br[16];
    char netmask[16];
    char ip[16];
    char network[16];
    int onboot;
    };

    void ParseKey(struct _ifcfg *ifcfg,char *key,char *value)
    {
    if(!strcmp(key,"DEVICE"))
    {
    strcpy(ifcfg->device,value);
    }
    else if(!strcmp(key,"BOOTPROTO"))
    {
    strcpy(ifcfg->bootproto,value);
    }
    else if(!strcmp(key,"BROADCAST"))
    {
    strcpy(ifcfg->br,value);
    }
    else if(!strcmp(key,"IPADDR"))
    {
    strcpy(ifcfg->ip,value);
    }
    else if(!strcmp(key,"NETMASK"))
    {
    strcpy(ifcfg->netmask,value);
    }
    else if(!strcmp(key,"NETWORK"))
    {
    strcpy(ifcfg->network,value);
    }
    else if(!strcmp(key,"ONBOOT"))
    {
    ifcfg->onboot=(strcmp(value,"yes") ? 0 : 1);
    }
    }

    int main(int argc,char **argv)
    {
    FILE *fp;
    DIR *dir;
    int i;
    char filename[50],buf[80];
    char *index,*key,*value,*p;
    struct _ifcfg *ifcfg;
    struct dirent *ptr;

    ifcfg=(struct _ifcfg *)malloc(sizeof(struct _ifcfg));
    memset(ifcfg,0,sizeof(struct _ifcfg));

    dir=opendir(NETCFGDIR); /*打開腳本目錄*/
    while((ptr=readdir(dir))!=NULL) /*讀取所有檔*/
    {
    if(strncmp(ptr->d_name,"ifcfg-eth",9)) /*這裏,只啟動了乙太網卡^o^*/
    {
    continue;
    }
    memset(filename,0,sizeof(filename));
    sprintf(filename,"%s%s",NETCFGDIR,ptr->d_name);
    if((fp=fopen(filename,"r"))==NULL) /*打開配置檔*/
    {
    continue;
    }

    while(!feof(fp))
    {
    memset(buf,0,sizeof(buf));
    if(fgets(buf,80,fp)!=NULL) /*逐行讀取分析*/
    {
    p=strchr(buf,'n');
    if(p)
    {
    *p='';
    }
    index=buf;
    key=strtok(index,"="); /*讀取配置變數*/
    value=strtok(NULL,"="); /*讀取變數的值*/
    ParseKey(ifcfg,key,value); /*分析之,存入結構ifcfg中*/
    }
    }
    /*構建相應的命令*/
    memset(buf,0,80);
    strcpy(buf,"/sbin/ifconfig");

    if(ifcfg->onboot)
    {
    sprintf(buf,"%s %s %s netmask %s broadcast %s",
    buf,
    ifcfg->device,
    ifcfg->ip,
    ifcfg->netmask,
    ifcfg->br);
    /*直接調用system來實現,當然也可以自己通過ioctl來設置,相應源碼,我以前在c/c++版發過*/
    system(buf);
    }
    }
    free(ife);
    return 0;
    }

    platinum 2005-11-1 02:52

    CODE:

     memset(buf,0,80);
     strcpy(buf,"/sbin/ifconfig");</p> <p>if(ifcfg->onboot)
     {
     sprintf(buf,"%s %s %s netmask %s broadcast %s",
     buf,
     ifcfg->device,
     ifcfg->ip,
     ifcfg->netmask,
     ifcfg->br);
     /*直接調用system來實現,當然也可以自己通過ioctl來設置,相應源碼,我以前在c/c++版發過*/
     system(buf);
     

    兩個問題
    1、從這段代碼看,實際調用了 /sbin/ifconfig 來完成網卡的設置,那麼,這個程式是否必須用 root 來執行?
    2、為何不用 system("command") 呢?

    獨孤九賤 2005-11-1 03:03

    回復 19樓 platinum 的帖子

    1、ifconfig本身運行,應該不需要root吧?而至於在shell中的運行許可權,要看看相應的許可權位了,事實上它已經能夠在我的系統中很好的運行了,測試過很多次的。不過現在我的系統,其實沒有用這種方法的,我是自己封裝了一個網卡管理的庫,也就是重寫了ifconfig,不過要把這些代碼發上來,太麻煩了,所以,就用瞭解system簡單了一點。

    2、我不是很理解“為何不用 system("command") 呢?”這句話的含義,我用的是system(buf);你說的是不是為什麼要去構建一個buf,而不是直接用system("/sbin/ifconfig ethXX……")?清楚一點……^o^


    獨孤九賤 2005-11-16 01:44

    繼續工作,交叉編譯SNMP

    一般系統都會有SNMP的支援,下載了net-snmp-5.1.3.1,先看看INSTALL和FAQ文檔(因為以前從來沒有碰過這個東東,見笑了……),按照說明,在原生主機上安裝了一回,安裝完成後,發現在指定安裝目錄下主要包括了幾塊檔:
    bin:SNMP的一些功能腳本和程式;
    sbin:主要的代理程式和trap程式:snmpd和snmptrap
    include/lib:自身相容及第三方開發所需的頭文件及庫文件;
    share:主要是MIB檔;

    然後回到安裝目錄下,運行./configuare --help,仔細查看了其安裝編譯選項,因為我定位的小型的系統,只需具備基本的SNMP功能即可,所以:
    那些bin目錄下的功能程式也不需要,對應--disable-applications
    bin下的腳本也是不需要的,對應:--disable-scripts
    用戶手冊也不需要:--disable-manuals
    關閉ipv6支持:--disable-ipv6
    還有一個--enable-mini-agent選項,說明是編譯出一個最小化的snmpd,比較有趣,試試先。
    對於交叉編譯,還需要用--host指明目標平臺。

    OK,看完了幫助說明,開始編譯了:
    1、配置,根據以上確定的選項:
    [root@skynet root]# CC=i386-linux-gcc ./configure --host=$TARGET --enable-mini-agent --disable-ipv6 --with-endianness=little --disable-applications --disable-manuals --disable-scripts --disable-ucd-snmp-compatibility

    CC指明了編譯器;--host指明了我的目標平臺,這個環境變數在我前面定義的devedaq腳本中。
    還算順利,繼續編譯它:
    [root@skynet net-snmp-5.1.3.1]# make LDFLAGS="-static"

    呵呵,因為沒有裝lib庫,所以我用了-static選項,指明是靜態編譯;

    3、安裝
    安裝就需要指明安裝路徑了,路徑可以在.config的時候指定,因為那個時候,那串東東太長了,我在install時指定也不遲:
    #make prefix=${TARGET_PREFIX} exec_prefix=${TARGET_PREFIX} install

    4、檢查一下:
    [root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/sbin
    total 2120
    -rwxr-xr-x 1 root root 2164301 Nov 16 09:22 snmpd

    snmpd就是我們要的代理主程序了,大約靜態編譯有2M。

    [root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/bin
    total 4380
    -rwxr-xr-x 2 root root 391980 Oct 14 2004 ar
    -rwxr-xr-x 2 root root 581228 Oct 14 2004 as
    ……

    呵呵,那堆程式和腳本沒有安裝,如snmpwalk……

    ls ${TARGET_PREFIX}/lib
    ls -l ${TARGET_PREFIX}/include


    看看我們需要的mib檔:
    [root@skynet net-snmp-5.1.3.1]# ls ${TARGET_PREFIX}/share/snmp
    mib2c.access_functions.conf mib2c.column_defines.conf mib2c.int_watch.conf mib2c.old-api.conf
    mib2c.array-user.conf mib2c.column_enums.conf mib2c.iterate_access.conf mib2c.scalar.conf
    mib2c.check_values.conf mib2c.conf mib2c.iterate.conf mibs
    mib2c.check_values_local.conf mib2c.create-dataset.conf mib2c.notify.conf snmpconf-data

    5、移植
    基本完成了,因為snmpd太大了點,對它進行strip處理:
    先備個份:
    [root@skynet net-snmp-5.1.3.1]# cp ${TARGET_PREFIX}/sbin/snmpd ${TARGET_PREFIX}/sbin/snmpd.bak
    [root@skynet net-snmp-5.1.3.1]# i386-linux-strip ${TARGET_PREFIX}/sbin/snmpd
    [root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/sbin/snmpd
    -rwxr-xr-x 1 root root 503300 Nov 16 09:30 /home/skynet/tools/i386-linux/sbin/snmpd

    經過處理後,還有近500KB了。

    因為只有SNMP agent功能,即snmpd程式,其他的都可以忽略。用了靜態編譯,lib下邊那些libnetsnmp檔都可以不需要了,程式運行
    需要MIB庫,也就是share下的內容,把這兩個東東拷到rootfs相應的目錄中去:
    [root@skynet net-snmp-5.1.3.1]# cp ${TARGET_PREFIX}/sbin/snmpd ${PRJROOT}/rootfs/usr/sbin
    [root@skynet net-snmp-5.1.3.1]# mkdir -p ${PRJROOT}/rootfs/usr/local/share
    [root@skynet net-snmp-5.1.3.1]# cp -r ${TARGET_PREFIX}/share/snmp ${PRJROOT}/rootfs/usr/local/share
    [root@skynet net-snmp-5.1.3.1]# cp EXAMPLE.conf ${PRJROOT}/rootfs/usr/local/share/snmp/snmpd.conf

    最後一步是把安裝目錄下的配置檔範例拷到snmpd啟動時默認的搜索目錄中去。

    6、測試
    打開snmpd.conf看看:
    [root@skynet net-snmp-5.1.3.1]# vi ${PRJROOT}/rootfs/usr/local/share/snmp/snmpd.conf
    有如下語句:
    # sec.name source community
    com2sec local localhost COMMUNITY
    com2sec mynetwork NETWORK/24 COMMUNITY
    定義了兩個用戶,本地及網路的,以及它們的通讀密鑰,按自己的需要修改一下,如:
    # sec.name source community
    com2sec local 127.0.0.1 public
    com2sec mynetwork 0.0.0.0 public

    後面是定義用戶的用戶組等一大堆東東,事實上不用修改它們了。運行它:
    [root@skynet net-snmp-5.1.3.1]# chroot ${PRJROOT}/rootfs /bin/sh


    BusyBox v1.00 (2004.10.13-06:32+0000) Built-in shell (ash)
    Enter 'help' for a list of built-in commands.

    / # snmpd
    / # exit
    在我們自己的根檔系統環境下運行它,然後退出來。用ps查看:
    #ps -aux
    ……
    root 32270 0.0 0.3 1212 936 ? S 09:38 0:00 snmpd

    [root@skynet net-snmp-5.1.3.1]# netstat -anu
    ……
    udp 0 0 0.0.0.0:161 0.0.0.0:*

    呵呵,已經成功啟動了。用一個SNMP管理軟體試試,可以成功地獲取到資訊。OK!

    總結一下:
    1、主程序+MIB庫大了點,共計約2M,不過我確實沒有辦法再小了,而且一味求小,也不是我的目的。
    2、功能稍微簡單了些,只有agent,如果需要,可以類似地把其他程式加上去就可以了。
    3、第一次玩net-snmp,還是有點生疏,比如我靜態編譯二進位程式,並不需要include/lib下的檔,但是如何關閉它們呢?我試過--disable-ucd-snmp-compatibility,不過好像不是這個選項……下次改進了……

    獨孤九賤 2005-11-16 05:38

    繼續工作,使用ramdisk

    前提:內核編譯時得選相應的支援選項,前文已有敍述。

    1、rootfs中的/boot檔夾刪除;
    2、建立ramdisk:
    使用dd命令建立一個空的檔系統映射:
    # dd if=/dev/zero of=images/initrd.img bs=1k count=8192

    大小8192K,用/dev/zero對其初始化;

    利用剛才的空的檔系統映射,建立檔系統並安裝它,使用了mke2fs命令:
    # /sbin/mke2fs -F -v -m0 images/initrd.img

    新建一個暫存檔案夾做mount之用:
    # mkdir tmp/initrd
    把建好的檔系統mount上來:
    #mount -o loop images/initrd.img tmp/initrd
    把根檔系統拷貝過來:
    #cp -av rootfs/* tmp/initrd
    # umount tmp/initrd

    壓縮:
    # gzip -9 <images/initrd.img > images/initrd.bin

    這樣,就得到了images/initrd.bin

    把目標盤mount上來:
    #mount -t ext2 /dev/hda1 /mnt/cf
    新建一個/boot
    #mkdir /mnt/cf/boot

    把剛才建立的ramdisk鏡像拷過來。然後把內核文件bzImage-2.4.27-rmk5也拷進去。
    這樣,boot檔夾裏邊有兩個檔
    initrd.bin
    bzImage-2.4.27-rmk5

    這個時候還不能安裝lilo,因為lilo的配置檔中有/dev/hda……這樣的東東,而目標盤上還沒有……所以,臨時建一個:
    #mkdir /mnt/cf/dev
    #cp -rf ${PRJROOT}/rootfs/dev/hda* /mnt/cf/dev

    修改${PRJROOT}/rootfs/etc/target.lilo.conf,我的配置檔如下:
    boot=/dev/hda
    disk=/dev/hda
    bios=0x80

    image=/boot/bzImage-2.4.27-rmk5
    initrd=/boot/initrd.bin
    root=/dev/hda1
    append="root=/dev/hda1"
    # label=MyLinux
    read-only

    相比以前的,只是加了一句:initrd=/boot/initrd.bin,另外把label去掉了,因為否則lilo會報怨說語法錯誤。

    好了,可以安裝lilo了。以前我們的語句是:
    lilo -r /mnt/cf -C etc/target.lilo.conf
    現在我們的目標盤上沒有etc這個目錄了,更不用說target.lilo.conf,可以借助於工程目錄中的了原文件,當然,我在目標硬碟上新建了/dev,然後把target.lilo.conf拷過去,還是用這句命令安裝lilo。

    這樣,整個系統就完成了。

    總結:還是想把kernel與檔系統都做到initrd.bin中,不過現在還沒有找到可行的辦法,大家也可以跟貼討論如何來做,偶也好學學……

    3 ***********************************************************



    DIY:自己動手做一個迷你 Linux 系統
    http://www-900.ibm.com/developerWorks/cn/linux/embed/diy/index.shtml#author1#author1

    DIY:自己動手做一個迷你 Linux 系統
    趙蔚 (zhaoway@public1.ptt.js.cn)
    自由職業者
    2002 年 9 月
    本文將帶領大家構建一個迷你型的 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 forbiddens 的複雜程度。從運行方面來考慮,由於需要的 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 系統。


    台灣災難都是事後算帳
    無人飛行載具(Unmanned Aerial Vehicle,UAV)為什麼沒大量應用於救災行列


    4 *******************************************************************








    Initializing the CF Card

    Let's start with erasing any existing partitions and creating a new one:
    fdisk /dev/sda (or whatever the device is for your CF card)

    In case you are not familiar with fdisk:
    p (prints all existing partitions) d (deletes a partition)
    n (creates a new partition) w writes and exists
    q quits without saving

    Delete all existing partitions and create a default primary Linux partition (type 83) using all available space. Save and exit (w)

    Format the new partition with:
    mkfs.ext2 /dev/sda1 (replace sda1 with your new partition)

    Create a mount point and mount your CF card:
    mkdir /mnt/flash
    mount -t ext2 /dev/sda1 /mnt/flash (sda1 would be the first partition on the device sda. Make sure you replace sda with the equivalent to your CF card)

    And now, let's create a basic directory structure:
    mkdir /mnt/flash/boot
    mkdir /mnt/flash/bin
    mkdir /mnt/flash/dev
    mkdir /mnt/flash/dev/cciss
    mkdir /mnt/flash/etc
    mkdir /mnt/flash/lib
    mkdir /mnt/flash/opt
    mkdir /mnt/flash/proc
    mkdir /mnt/flash/sbin
    mkdir /mnt/flash/tmp
    mkdir /mnt/flash/var
    mkdir /mnt/flash/usr
    mkdir /mnt/flash/usr/bin
    mkdir /mnt/flash/usr/lib
    mkdir /mnt/flash/etc/init.d
    cd /mnt/flash/dev
    /dev/MAKEDEV std
    /dev/MAKEDEV ttyS0
    /dev/MAKEDEV hda
    /dev/MAKEDEV hde
    /dev/MAKEDEV console
    /dev/MAKEDEV audio
    mknod psaux c 10 1
    mknod console c 5 1
    mknod /mnt/flash/dev/hda b 3 0
    mknod /mnt/flash/dev/hdb b 3 64
    mknod /mnt/flash/dev/hdc b 22 0
    mknod /mnt/flash/dev/hdd b 22 64

    Installing Busy Box

    We need a basic set of unix utilities. Given the memory limitation, we will install BusyBox. Busybox provides a set of basic utilities in a single executable.

    Download the latest version (0.60.5 when I wrote this guide)

    Unpack and compile:
    tar -zxf busybox-0.60.5.tar.gz
    cd busybox-0.60.5
    make
    make install

    Install Busybox on your CompactFlash:
    cp -r _install/* /mnt/flash

    Copying GRUB (Boot Loader)

    Let's now copy a few files from the PC to the CF we will need them later on:
    cp /sbin/grub /mnt/flash/sbin
    cp /sbin/fdisk /mnt/flash/sbin
    cp /sbin/mkfs.ext2 /mnt/flash/sbin
    cp /lib/libcrypt.so.1 /lib/libc.so.6 /lib/ld-linux.so.2 /mnt/flash/lib/
    cp /lib/libext2fs.so.2 /mnt/flash/lib/
    cp /lib/libe2p.so.2 /mnt/flash/lib/
    cp /lib/libcom_err.so.2 /mnt/flash/lib/
    cp /lib/libuuid.so.1 /mnt/flash/lib/

    RH9 comes with two boot loaders: LILO and GRUB. I have never been able to get LILO to work on a CF Card. It always stops at the LI prompt (usually writes LILO) and even though I tried all tricks I found on the web for this known problem, none of them worked. That's why we will use GRUB instead.

    Copy all boot files from your PC to the CF Card:
    cp -vax /boot/* /mnt/flash/boot

    Getting a Kernel

    By copying /boot to your CF Card, you have already copied your existing kernel. If that is good enough for you, then you can skip this section.

    I am not going to spend time on the details here, just grab the latest version from www.kernel.org, untar and do:

    make menuconfig (It is important here to select the right processor according to the machine you will be using. See the Processor Type and Features section)

    make menuconfig
    make dep
    make bzImage

    Once it is done, copy the fresh kernel to your CF Card:
    cp arch/i386/boot/bzImage /mnt/flash/boot/vmlinuz
    cp System.map /mnt/flash/boot/

    Making the CompactFlash card bootable

    Now we have to write the MBR on the Compact Flash. Execute GRUB:
    grub

    You will get to the grub> command line. If you do not have curses installed on your PC, you will get: Error opening terminal Linux. If that is the case, try grub --no-curses

    Grub names the drives in a different way. The first drive would be hd0, the second drive would be hd1, and so on. The partition number is specified with a second digit after a comma. For example hd0,0 is the first partition on the first hard drive. Set your root partition with:
    root (hd1,0) you can hit tab twice after hd and you will get a list of option (bash-style) just to make sure you are talking about the right partition. It might not be (hd1,0)

    Install the MBR with:
    install /boot/grub/stage1 (hd1) /boot/grub/stage2 (again, replace hd1 with your CF drive)
    quit

    More details on GRUB, such as creating a boot menu are beyond the scope of this document. Check this article for more information about GRUB on CompactFlash

    Unmount your CF card with umount /mnt/flash. Your CF card is now ready and will get you to your # prompt. However, you will have to specify your kernel, root partition and init scripts at the GRUB> prompt:

    GRUB> root (hd0,0) (or whatever it is)
    GRUB> kernel /boot/vmlinuz root=/dev/hda1 rw init=/bin/sh
    GRUB> boot

    Replace hda1 with the device corresponding to your CF card. In my case is hda1 as I am using an ACS IDE to CompactFlash adapter in my BluePad Tablet PC

  • 標籤: Linux
    評論: 0 | 引用: 0 | 閱讀: 8594 | 轉發
    顯示Tag關聯文章
    InfoBOX-2500 終身保固機種 (2009-10-15 09:39)
    [ InfoBOX 伺服器使用密技] FTP 無法修改檔案權限怎麼辦? (2009-08-17 17:03)
    [ InfoBOX 伺服器使用密技] 如何申請IP反解設定 (2009-08-17 11:47)
    [ InfoBOX 伺服器使用密技] 如何安裝 phpBB 討論區 (2009-08-14 17:05)
    [ InfoBOX 伺服器使用密技] ISP 說我的伺服器被當成跳板在亂發信 怎麼查 ? (2009-08-14 15:40)
    [ InfoBOX 伺服器使用密技] 郵件伺服器 / 進階設定->防止帳號盜用機制 (2009-08-14 15:27)
    [ InfoBOX 伺服器使用密技] InfoBOX 如何更新韌體? (2009-08-14 15:19)
    [ InfoBOX 伺服器使用密技] 伺服器硬碟不夠用,Linux 如何換新的硬碟 (2009-08-14 14:19)
    [ InfoBOX 伺服器使用密技] 伺服器故障的災難復原機制 (2009-08-14 11:41)
    zimbra mail server 免費的多網域郵件伺服器 (2009-04-20 21:01)
    OnlyYou人脈管理軟體應用技巧(2) 與圖片簽名檔的整合 (2009-02-11 17:22)
    Damon免費網頁空間更換新主機囉! (2009-01-10 00:18)
    虛擬主機 Apache 2.2.6+php5.2.3+MySQL5.0.23~自己來當戰國策 (2009-01-07 01:45)
    ePowerBOX2009 上市~嵌入式Embedded Linux 網站、NAS、FTP、郵件伺服器 (2008-12-26 15:17)
    [ InfoBOX 伺服器使用密技] 垃圾郵件剋星=灰名單排程功能 (2008-09-24 13:30)
    Unix Like 的檔案與目錄權限說明 (2008-02-11 20:20)
    rpm -qil postfix 找出套件的安裝位置 (2007-12-06 11:32)
    EMOS 整理 (2007-08-31 16:33)
    新增 yum 套件 4000多套 (2007-08-31 00:33)
    /etc/passwd 檔超過1萬個 email 帳號無力~ (2007-08-30 00:24)
    找RPM的網址 (2007-08-29 23:57)
    硬碟空間 90% 發信通知 root (2007-08-29 23:53)
    Linux 可讀寫 ntfs 的方式 (2007-08-29 23:51)
    透通式防火牆設定 (2007-08-29 23:47)
    更換 ssh 服務程式的 Port (2007-08-10 23:45)
    將寄到yahoo的信由hinet去轉寄設定 (2007-08-10 23:42)
    postfix 文件 (2007-08-01 18:17)
    SAMBA ACL (2007-07-30 14:22)
    Embedded Linux資源好站 (2007-07-30 00:49)
    ProFTP 教學 (2007-07-29 23:28)
    postfix 對照表 (2007-07-16 01:25)
    Rsync 控制頻寬 (2007-07-06 17:38)
    AD 整合 samba 認證帳號功能 - 檢查要有 winbind (2007-07-05 11:11)
    ROR on mongrel 取代 apache (2007-07-05 00:01)
    CentOS5 自動安裝光碟製作 (2007-06-03 13:17)