1. busybox簡介
busybox是一個集成了一百多個最常用linux命令和工具的軟件,它將許多常用的LINUX命令和工具結合到了一個單獨的可執行程序中。雖然與相應的GNU工具比較起來,busybox所提供的功能和參數略少,但在比較小的系統(例如啟動盤)或者嵌入式系統中,已經足夠了。
busybox在設計上就充分考慮了硬件資源受限的特殊工作環境。它采用一種很巧妙的辦法減少自己的體積:所有的命令都通過“插件”的方式集中到一個可執行文件中,在實際應用過程中通過不同的符號鏈接來確定到底要執行哪個操作。例如最終生成的可執行文件為busybox,當為它建立一個符號鏈接ls的時候,就可以通過執行這個新命令實現列目錄的功能。采用單一執行文件的方式最大限度地共享了程序代碼,甚至連文件頭、內存中的程序控制塊等其他操作系統資源都共享了,對於資源比較緊張的系統來說,是最合適不過了。
Busybox配置如下:
Build Options--->
[*] Build BusyBox as a static binary (no shared libs)
Installation Options --->
Login/Password Management Utilities --->
Do you want to build BusyBox with a Cross Compiler。如果要對其他平台進行編譯就要選擇它並設置相應的編譯程序前綴。我們選擇armv5l-linux-,前面加上絕對路徑。
Login/Password Management Utilities--->
[*]Use internal password and group functions rather than system functions。這里設置使用busybox自己的password和shadow文件的功能。
如果需要一個交互的登錄界面,則選擇getty、login和passwd
編譯make TARGET_ARCH=arm,生成的目標代碼位於_install目錄下。
2. 文件系統啟動過程
Linux的啟動過程主要分成兩個階段:
1.啟動內核。在這個階段,內核裝入內存並在初始化每個設備驅動器時打印信息。
2.執行程序init。裝入內核並初始化設備后,運行init程序。init程序處理所有程序的啟動,包括重要系統程序和其它指定在啟動時裝入的軟件。
現在主要詳細介紹一下文件系統的啟動過程,即linux啟動過程的第二階段,大概分為以下幾個過程:
(1)運行init
init的進程號是1,從這一點就能看出,init進程是系統所有進程的起點,linux在完成核內引導以后,就開始運行init程序。init程序需要讀取配置文件/etc/inittab,以查看下一步做什么。inittab是一個不可執行的文本文件,它有若干行指令所組成,告訴 init 要進入什么運行級別,以及在哪里可以找到該運行級別的配置文件。以下是qsan的inittab文件(部分注釋省略):
# The default runlevel.
id:4:initdefault:
# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS
# /etc/init.d executes the S and K scripts upon change of runlevel.
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l6:6:wait:/etc/init.d/rc 6
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -h now
# /sbin/getty invocations for the runlevels.
# Example how to put a getty on a serial line (for a terminal)
T0:134:respawn:/sbin/getty -L ttyS0 115200 vt100
T1:1:respawn:/sbin/getty -L ttyS1 115200 vt100
以上面的inittab文件為例,來說明一下inittab的格式。其中以#開始的行是注釋行,除了注釋行之外,每一行都有以下格式:
id:runlevel:action:process
id–入口標識符,用於標識文件/etc/inittab中的每一個登記項。它是一個1-4位的字符串,對於getty或mingetty等其他login程序項,要求id與tty的編號相同,否則getty程序將不能正常工作。
runlevel – 運行級。說明該登記項適用於哪一個運行級。為空表示適用於所有級別.它是init所處於的運行級別標識,一般使用0-6以及S或s。0、1、6運行級別被系統保留。0作為halt動作,1作為重啟至單用戶模式,6為重啟。S和s意義相同,表示單用戶模式,且無需inittab文件,因此也不在inittab中出現,實際上,進入單用戶模式時,init直接在控制台(/dev/console)上運行/sbin/sulogin。runlevel可以是並列的多個值,以匹配多個運行級別,對大多數action來說,僅當runlevel與當前運行級別匹配成功才會執行。
action – 定義init命令應該向進程實施什么動作。包括以下:
respawn-無論何時它終止,均重新啟動命令
wait-運行命令一次。在繼續之前,init等待它終止
once-運行命令一次
boot-命令在啟動過程中運行。忽略運行等級字段
bootwait-命令在啟動過程中運行,忽略運行等級字段。在繼續之前,init等待該進程終止
initdefault-定義Linux系統的默認運行等級
powerwait-停電時命令運行。在繼續之前,init等待該進程終止
powerfail-停電時命令運行。在繼續之前,init不等待該進程終止
powerokwait-恢復電力時命令運行。在繼續之前,init等待該進程終止
powerfailnow-UPS發出電池即將耗盡的信號時,運行該命令
process - 是具體的執行程序。程序后面可以帶參數。
(2)系統初始化
sysinit、boot、bootwait等action將在系統啟動時無條件運行,而忽略其中的runlevel。因此init進程首先會執行etc/init.d/rcS腳本,rcS內容如下:
#首先,定義PATH、runlevel、prevlevel然后導出到環境中
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
#然后,判斷是不是第一次安裝系統,如果是,則檢查並且執行安裝程序留下的腳本
if [ -x /sbin/unconfigured.sh ]
then
/sbin/unconfigured.sh
fi
. /etc/default/rcS
export VERBOSE
#捕捉INT、QUIT、TSTP信號,
trap":"INT QUIT TSTP
#檢查/etc/rcS.d/目錄,看是否有以S開頭並且緊跟兩個字符(實際上
#一般是兩個數字0-99)命名的非普通(! -f"$i")文件,如果有則根據
#文件的類型作出兩個選擇
# 1,是.sh結尾的腳本時執行
# 2,如果不是.sh結尾的腳本,則傳遞給start參數執行這個文件
for i in /etc/rcS.d/S??*
do
# Ignore dangling symlinks for now.
[ ! -f"$i"]&& continue
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
done
#這是為了兼容其他系統的/etc/rc.boot腳本
[ -d /etc/rc.boot ]&& run-parts /etc/rc.boot
#這也是用於第一次安裝系統后需要執行的腳本,安裝成功后,系統上
#一般沒有這個腳本
if [ -x /sbin/setup.sh ]
then
/sbin/setup.sh
fi
#/etc/rc.S/rcS腳本執行結束.返回/inittab
(3)啟動對應運行級別的守護進程
返回/inittab,接下來根據系統進入的運行級別,啟動對應運行級別的守護進程,這里為4,init將執行配置文件inittab中的以下這行:
l4:4:wait:/etc/init.d/rc 4
這一行表示以4為參數運行/etc/rc.d/rc,/etc/rc.d/rc是一個Shell腳本,它接受4作為參數,去執行/etc/rc.d/rc4.d/目錄下的所有的rc啟動腳本,/etc/rc.d/rc4.d/目錄中的這些啟動腳本實際上都是一些鏈接文件,而不是真正的rc啟動腳本,真正的rc啟動腳本實際上都是放在/etc/rc.d/init.d/目錄下。而這些rc啟動腳本有着類似的用法,它們一般能接受start、stop、restart、status等參數。
/etc/rc.d/rc4.d/中的rc啟動腳本通常是K或S開頭的鏈接文件,對於以S開頭的啟動腳本,將以start參數來運行。而如果發現存在相應的腳本也存在K打頭的鏈接,而且已經處於運行態了(以/var/lock/subsys/下的文件作為標志),則將首先以stop為參數停止這些已經啟動了的守護進程,然后再重新運行。這樣做是為了保證是當init改變運行級別時,所有相關的守護進程都將重啟。
(4)建立終端
rc執行完畢后,返回init。這時基本系統環境已經設置好了,各種守護進程也已經啟動了。init接下來會打開終端,以便用戶登錄系統,如以下2行:
T0:134:respawn:/sbin/getty -L ttyS0 115200 vt100
T1:1:respawn:/sbin/getty -L ttyS1 115200 vt100
從上面可以看出在1、3、4的運行級別中將以respawn方式運行getty程序,它會顯示一個文本登錄界面,這個界面就是我們經常看到的登錄界面,在這個登錄界面中會提示用戶輸入用戶名,而用戶輸入的用戶名將作為參數傳給login程序來驗證用戶的身份。
注意:如果想繞過登錄驗證過程,想直接進入shell界面的話,則把以上兩行注釋掉,改為:T0:134:respawn:/bin/sh
(5)登錄系統,啟動完成
getty進程接收到用戶名后,啟動login進程.
login進程要求用戶輸入口令.
用戶輸入口令.
login進程對username和password進行檢查.
login啟動shell進程.
shell進程根據/etc/password中的shell類型,啟動相應的shell.並啟動/etc/profile文件和$HOME/.bash_profile文件.最后出現shell提示符,等待用戶輸入命令.
至此,啟動過程結束。
3. login驗證過程
Linux的帳號驗證程序是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文件,就執行它,在這些文件中又可能調用了其它配置文件,所有的配置文件執行后,各種環境變量也設好了,這時會出現大家熟悉的命令行提示符,到此整個啟動過程就結束了。
以下是passwd,shadow和group腳本的格式說明:
/etc/passwd密碼文件的格式如下所示:
用戶名:口令:用戶標識號:組標識號:注釋性描述:主目錄:登錄Shell
user_name:password:uid:gid:comment:home:shell
每行有很多項組成,項與項之間用":"隔開.每項的說明如下:
user_name 用戶名
password 登錄密碼,初始設置時為空
uid 用戶識別號(User ID),是一數值,每個用戶的識別號不同
gid 用戶組識別號,參見/etc/group文件
comment 注釋,可以任意字符,一般用來說明用戶的身份特征
home 家目錄名
shell 該用戶缺省shell,一般取值為:/bin/sh,/bin/ksh,/bin/csh
/etc/shadow文件格式如下:
登錄名:加密口令:最后一次修改時間:最小時間間隔:最大時間間隔:警告時間:不活動時間:失效時間:標志
username:passwd:last:may:must:warn:expire:disable:reserved
username 使用者名稱
passwd 編碼密碼
last 密碼上次更動日期,以從1970年1月1日算起的天數代表
may 密碼改變前天數
must 密碼最常使用天數
warn 代表期限前幾天就事先警告使用者
expire 超過密碼過期天數后,就關閉該帳號
disable 帳號關閉,以從1970年1月1日算起的天數代表
reserved 預備欄位
/etc/group文件格式如下:
group_name:password:gid:members_list
每行有四項組成,項與項之間用":"隔開.
group_name 用戶組名
password 用戶組密碼,一般為空
gid 用戶組識別號(Group ID),是一數值,每個組的識別號不同
members_list 該組成員列表,由一個或多個用戶名組成,用戶名之間用逗號隔開
注:一個最簡單的文件系統至少需要包含以下幾個目錄,/sbin,/bin,/dev(需要console和ttyS0兩個文件),/proc,/etc(需要inittab,rcS文件),/home.
