1. busybox 下載
下載完成後,解壓得到如下圖所示目錄:
busybox 與 內核源碼、u-boot源碼配置類似,也存在默認配置,在configs目錄下面,但因爲其配置比較簡單,一般沒采用默認配置.(思考:如何添加自定義的配置到configs目錄使其能make xx_defconfig)
$ make help //可以查看make 實現哪些功能
2. 編譯busybox
指定ARCH 、CROSS_COMPILE 、SYSROOT
示例:
$ export ARCH = powerpc
$ export CROSS_COMPILE = powerpc-fsl-linux-gnuspe-
若 沒設置CROSS_COMPILE變量,則需要在Busybox Settings-->Build Options --> Cross Compiler prefix 填寫 編譯器的前綴
關於SYSROOT
CONFIG_SYSROOT: |
| |
| If you want to build BusyBox with a cross compiler, then you |
| might also need to specify where /usr/include and /usr/lib |
| will be found. |
| |
| For example, BusyBox can be built against an installed |
| Android NDK, platform version 9, for ARM ABI with |
| |
| CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm |
| |
| Native builds leave this empty. |
| |
| Symbol: SYSROOT [=] |
| Prompt: Path to sysroot |
| Defined at Config.in:632 |
| Location: |
| -> Busybox Settings |
| -> Build Options
若使用交叉編譯器不設置此選項,則可能出現如下問題
以上基本配置完成後,make menuconfig 根據需要配置 (一般不用配置)
需要注意的就幾個點:
1.BusyBox installation prefix 選項 ,執行make install時安裝的目錄,默認設置爲當前源碼目錄的_install
2.使用vi風格時 busybox setting->busybox library tuning下的下面兩個開關打開。第一個是選擇vi風格的命令行。
3. 選中 Build BusyBox as a static binary 可以減少根文件系統空間 ,這樣它自身不需使用動態庫
4.需要注意Linux Module Utilities 和 Linux System Utilities
執行make
執行make install
3. Linux踩坑啓動生成的根文件系統
設置uboot bootargs啓動參數
bootargs=root=/dev/nfs nfsroot=192.168.1.141:/root/rootfs/
ip=192.168.16.88:192.168.16.106:192.168.16.1:255.255.255.0::eth1:off
init=/linuxrc console=ttyS0,115200
此時會因爲找不到/etc/init.d/rcS (第一個執行的腳本) 以及終端設備/dev/tty2等設備無法進入命令行
注意時,/etc/inittab是busybox第一個解析的配置文件,當找不到時會使用默認配置,所以當根文件系統缺少/etc/inittab時也不會出現 can't open /etc/inittab的信息。
下面開始一步一步補充根文件系統缺少的文件和目錄
1.創建etc目錄,新建inittab文件
簡單介紹inittab,詳細後面博客補充
inittab內容以行爲單位,行與行之間沒有關聯,每行都是一個獨立的配置項,每一個配置項表示一個獨立的意思
<id>:<runlevels>:<action>:<process>
<id>: id字段與通常的inittab中的含義不同,它代表的是這個語句中process執行所在的tty設備,內容就是/dev目錄中tty設備的文件名。由於是運行process的tty設備的文件名,所以也不能像通常的inittab那樣要求每條語句id的值唯一
<runlevels>: busybox不支持runlevel(沒具體分析過),所以此字段完全被忽略
runlevel也是一個shell變量,並且導出爲環境變量
runlevel變量的作用:Linux操作系統自從開始啓動至啓動完畢需要經歷幾個不同的階段,這幾個階段就叫做runlevel,同樣,當linux操作系統關閉時也要經歷另外幾個不同的runlevel。設置runlevel,是爲了linux系統避免不必要的重啓動。
Linux系統有7個運行級別(runlevel)
運行級別0:系統停機狀態,系統默認運行級別不能設爲0,否則不能正常啓動
運行級別1:單用戶工作狀態,root權限,用於系統維護,禁止遠程登陸
運行級別2:多用戶狀態(沒有NFS)
運行級別3:完全的多用戶狀態(有NFS),登陸後進入控制檯命令行模式
運行級別4:系統未使用,保留
運行級別5:X11控制檯,登陸後進入圖形GUI模式
運行級別6:系統正常關閉並重啓,默認運行級別不能設爲6,否則不能正常啓動
S, s Single user mode
runlevel=s,表示將系統設置爲單用戶模式
<action>:sysinit, respawn, askfirst, wait,once, restart, ctrlaltdel, shutdown,initdefault 等(其它參考官網 man inittab介紹)
上面標紅比較常用,需要注意的是:
askfirst,它的含義與respawn相同,只是在運行process前,會打出一句話 "please press Enter to active this console",然後等用戶在終端上敲入回車鍵後才運行process。
sysinit :爲init提供初始化命令行的路徑 <一般在inittab爲si::sysinit:/etc/init.d/rcS 表示執行/etc/int.d目錄下rcS腳本>
si 是系統初始化的進程,該字段可以不寫,當寫si時,實踐中出現了can't open /dev/si: No such file or directory,目前還不太清楚與什麼有聯繫
下面爲成熟的文件系統中的實現:
respawn:每當相應的進程終止執行便重新啓動
wait: 告訴init必須等到相應的進程完成才能繼續執行
shutdown:當系統關機時,執行相應的進程
restart:當init重新啓動時,執行相應的進程。
once:僅執行相應的進程一次,而且不會等待它完成
ctrlaltdel:當按下Ctrl-Alt-Delete組合鍵時,執行相應的進程
#first: run the system script file
#控制檯在啓動之前,執行/etc/init.d/rcS程序
::sysinit:/etc/init.d/rcS
#控制檯啓動時,執行/bin/sh程序。若沒有執行類似登錄,則無法出現交互終端
::askfirst:-/bin/sh
#按下ctrl+alt+del,執行/bin/reboot程序
::ctrlaltdel:-/bin/reboot
#關機時,執行/bin/umount程序,並傳入兩個參數, -a –r
::shutdown:/bin/umount -a -r
#重啓,執行/sbin/init程序
::restart:/sbin/init
再次啓動根文件系統會出現can't run '/etc/init.d/rcS': No such file or directory
2.創建rcS文文件,且需要加入執行權限
再次啓動,可以發現能基本出現交互終端
3.繼續深入的驗證,思考下面問題
1)如何讓串口終端登錄 以及登錄時密碼與賬戶如何驗證的
屏蔽/bin/sh ,加入ttyS0:12345:respawn:/sbin/getty -L 115200 ttyS0
說明:一般情況下上面ttyS0應該只需要寫S0,也就是tty的尾綴,但本文完成最終實驗時,發現啓動時若採用S0還是會出現
can't open /dev/S0: No such file or directory,待分析成熟文件系統中如何實現的
#first: run the system script file
#控制檯在啓動之前,執行/etc/init.d/rcS程序
::sysinit:/etc/init.d/rcS
#控制檯啓動時,執行/bin/sh程序。若沒有執行類似登錄,則無法出現交互終端
#::askfirst:-/bin/sh
ttyS0:12345:respawn:/sbin/getty -L 115200 ttyS0
#按下ctrl+alt+del,執行/bin/reboot程序
::ctrlaltdel:-/bin/reboot
#關機時,執行/bin/umount程序,並傳入兩個參數, -a –r
::shutdown:/bin/umount -a -r
#重啓,執行/sbin/init程序
::restart:/sbin/init
完成上面後,啓動時,也會出現can't open /dev/ttyS0: No such file or directory,這是因爲系統此時還沒有在/dev 創建對應的設備文件
2)創建dev目錄後,怎麼讓dev目錄看見對應的設備
現在系統大部分設備節點都是由mdev或者udev根據驅動實現自動創建的,所以只需要讓腳本執行mdev或者udev相關的操作即可
此時在/etc/init.d/rcS中加入下面內容即可
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
mount -a
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
/bin/hostname -F /etc/hostname
上面分爲4個部分:
(a)導出壞境變量
定義PATH變量,後面用export導出,那PATH就變成了環境變量。
PATH環境變量是linux系統內部定義的一個環境變量,含義是操作系統去執行程序時會默認到PATH指定的各個目錄下去尋找。如果找不到就認定這個程序不存在,如果找到了就去執行它。將一個可執行程序的目錄導出到PATH,可以讓我們不帶路徑來執行這個程序。
rcS文件還沒添加,系統啓動就有了PATH的值?原因在於busybox自己用代碼硬編碼爲我們導出了一些環境變量,其中就有PATH。
在busybox的init.c的init_main函數中,有以下幾行代碼,設置了幾個環境變量,其中就有PATH。
/* Make sure environs is set to something sane */
putenv((char *) "HOME=/");
putenv((char *) bb_PATH_root_path);
putenv((char *) "SHELL=/bin/sh");
putenv((char *) "USER=root"); /* needed? why? */
在libbb.h中,有定義bb_PAYH_root_path,其實就是/bin /sbin /usr/bin /usr/sbin
extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */
(b)掛載根文件系統 mount -a
mount命令是用來掛載文件系統的。
mount –a是掛在所有的應該被掛載的文件系統,在busybox中mount –a時busybox會去查找一個文件/etc/fstab文件,這個文件按照一定的格式列出了所有應該被掛載的文件系統(包括了虛擬文件系統)格式統一的
# /etc/fstab: static file system information.
#
# Use 'vol_id --uuid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /var tmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
需要注意的是,mdev/udev 需要掛載 tmpfs - /dev proc-/proc sysyfs - /sys 不然都無法成功創建設備
編輯完/etc/fstab後,還需手動創建proc sys dev 目錄
下面爲沒掛載tmpfs到/dev時,出現的問題
(c) mdev
mdev是udev的嵌入式簡化版本,udev/mdev是用來配合linux驅動工作的一個應用層的軟件,udev/mdev的工作就是配合linux驅動生成相應的/dev目錄下的設備文件。
本來,在dev目錄下,是空目錄。但是當rcS文件中,添加下面兩行,配合上面的文件系統掛載,
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
在dev目錄下,就會生成很多設備文件。這些設備文件,就是mdev生成的。
配置完成後,串口登錄時出現下面輸入密碼的提示,此時因爲沒有對應/etc/passwd,則無法登錄
關於系統密碼登錄這塊的介紹:
inux的賬號驗證程序是login,login會接收getty傳來的用戶名作爲用戶名參數。
然後login會對用戶名進行分析:如果用戶名不是root,且存在/etc/nologin文件,
login將輸出nologin文件的內容,然後退出。這通常用來系統維護時防止非root用戶登錄。
只有/etc/securetty中登記了的終端才允許root用戶登錄,如果不存在這個文件,則root可以
在任何終端上登錄。/etc/usertty文件用於對用戶作出附加訪問限制,如果不存在這個文件,則沒有其他限制。
在分析完用戶名後,login將搜索/etc/passwd以及/etc/shadow來驗證密碼以及設置賬戶的其它信息,
比如:主目錄是什麼、使用何種shell。如果沒有指定主目錄,將默認爲根目錄;如果沒有指定shell,
將默認爲/bin/bash。
login程序成功後,會向對應的終端在輸出最近一次登錄的信息(在/var/log/lastlog中有記錄)
並檢查用戶是否有新郵件(在/usr/spool/mail/的對應用戶名目錄下)。
然後開始設置各種環境變量:
對於bash來說,系統首先尋找/etc/profile腳本文件,並執行它;然後如果用戶的主目錄中存在.bash_profile文件,
就執行它,在這些文件中又可能調用了其它配置文件,所有的配置文件執行後後,
各種環境變量也設好了,這時會出現大家熟悉的命令行提示符,到此整個啓動過程就結束了。
創建/etc/passwd文件,添加下面內容即可
root::0:0:root:/home/root:/bin/sh
當我換成root:x:0:0:root:/home/root:/bin/sh時,登錄居然需要密碼,後面待驗證,感覺和busybox vi編輯模式相關
(d)hostname
hostname是linux中的一個shell命令。命令(hostname xxx)執行後可以用來設置當前系統的主機名爲xxx,直接hostname不加參數可以顯示當前系統的主機名。
設置了主機名,就可以在命令行中,顯示主機名。
沒有設置主機名的時候,使用hostname命令,會打印當前的IP地址。
新建/etc/hostname 且寫入自定義的hostname
3)如何修改根文件系統的提示符
請參考根文件系統的提示符
4. 參考文章