class="21089">
各位是否曾經對電腦整個開機的流程感到好奇呢 ? 這一次 , 我們所要討論的
主題 , 就是 Linux 從開機的一瞬間到 login 為止 , 到底發生了什麽事情 ?
想必各位都知道 , 在剛開機時 , 由於 80x86 的特性 , CS ( Code Segment )
這個暫存器中全部都放著 1 , 而 IP ( Instruction Pointer ) 這個暫存器
中全部都放著 0 , 換句話說 , CS=FFFF 而 IP=0000 , 此時 , CPU 就依據
CS 及 IP 的值 , 到 FFFF0H 去執行那個地方所放的指令 . 這時候 , 由於
FFFF0H 已經到了高位址的頂端 , 所以 , FFFF0H 這個地方 , 總是會放一個
JMP 指令 , 跳到比較低的位址 . 接著 , ROM BIOS 就會作一些檢查的動作
像記憶體 , 鍵盤 等...... 並在我們俗稱的 UMB ( Upper Memory Block )
之中掃描 , 看看是否有合法的 ROM 存在 ( 比如 SCSI 卡上的 ROM ) .
假如有 , 就到裡面去執行一些東西 , 執行完之後再繼續剛才的行程 . 到了
最後 , 讀取磁碟機上的第一個 sector . 在這裡 , 我假設各位由硬碟啟動
因此 , 就硬碟的構造而言 , 它的第一個 sector 稱為 MBR ( Master Boot
Record ) . 因為一個 sector 是 512 bytes , 而 MBR 這 512 bytes 可分
為兩個部份 , 第一個部份為 Pre-Boot 區 , 占了 446 bytes ; 第二部份
是 Partition Table , 占了 66 bytes . Pre-Boot 區的作用之一 , 就是
去看看那個 Partition 被標成 Active , 然後去讀那個 Partition 的 Boot
區 .
在 Linux 的啟動方面 , 一般人最常把 LILO 放在 MBR 或 Superblock
假如你把 LILO 放在 MBR , 那很明顯的 , 當讀取到 MBR 的時候 , LILO
就被執行 , 此時 , 你的螢幕上會出現; boot: 接著 , 就進行 Load Kernel
的動作 . 在另一方面來說 , 假如你把 LILO 安裝在 Superblock , 通常你
還會有一個管理開機的程式 , 也許是住在 MBR ( 像 OSBS ) 或者是放在一
個單獨的 Partition ( 像 OS/2 的 Boot Manager ) . 再由這個管理開機
的程式去讀取 LILO , 進而做 Load Kernel 的動作 .
好了 , 到了目前為止 , 我們已經講到 Load Kernel 的動作 . Kernel 被
load 到 memory 中之後 , 接著進行一連串 probe 周邊的動作 , 像串聯埠
並聯埠 , 軟碟 , 音效卡 , 硬碟 , 光碟機 等 ...... 接著 mount root
partition . 在這之後 , kernel 會起動 init 這個 process . init 這
個 process 的 PID 為 1 , 它是所有 process 的祖先 .
接下來呢 ? 系統就開始執行; /rc.d/rc.S; , 在這裡 , 我們暫時打住 ,
先對大概的 initialization script 執行的順序作一個浏覽 , 請看下面
的流程 :
init[1]
rc.Sbegin;;;;<--- 目前我們已經講到這裡
rc.serialbegin
rc.serialend
rc.Send
init[1] enter runlevel 5
rc.Mbegin
rc.inet1;begin
rc.inet1;end
rc.inet2;begin
rc.inet2;end
rc.font;;begin
rc.font;;end
rc.local;begin
rc.local;end
rc.Mend
login
上面的流程清楚的指出 , 在 rc.S 這個 shell script 中 , 會去執行 rc.serial
接著再執行 rc.M , rc.M 中又包含了 rc.inet1 , rc.inet2 , rc.font , rc.local
最後執行 login . 在下面的內容中 , 將為各位介紹這幾個 shell script
從下面開始 , 凡是每一列之前有一個 # 的 , 為原來 shell script 中的注解
有兩個 # 的 , 為筆者加上的注解 , 當然啦 , 沒有任何 # 的為 shell script
的內容 , 而對命令或內容的解釋 , 一律都寫在命令或內容的前面 .
首先由 rc.S 開始 :
***************************** rc.S **********************************
#!/bin/sh
#
# /etc/rc
#
# These commands are executed at boot time by init(8).
# User customization should go in /etc/rc.local.
echo '======== rc.S is running !; System Initializing Now !!! ========'
PATH=/sbin:/usr/sbin:/bin:/usr/bin
## 打開所有 swap ! 下面 /sbin/swapon -a 的意思是 : 使得 /etc/fstab 中被記錄
## 成 swap 的 device 全部啟動 .
/sbin/swapon -a
## 喔 ! 下面這個指令 update 就很重要了 , 它負責每隔一段固定的時間 , 就將
## buffer 中的資料 , 利用 sync 寫回磁碟機上 , 並將 superblock 做 update
## 的動作 . 使用 ps 這個指令看看有那些 process , 就可看到 update 還有一個
## bdflush , 這兩個 process 都是必然要存在的 , 可不要隨便砍掉 , 要不然 ,
## 萬一系統 crash 了 , 那磁碟機裡面的資料就不是最新的了 ......
/sbin/update &
## 利用 echo -n >> 制造一個檔案 , 並用 rm -f 這個檔案來測試 root partition
## 是不是 read-only 或者是可讀寫
READWRITE=no
if echo -n >> "Testing filesystem status"; then
rm -f "Testing filesystem status"
READWRITE=yes
fi
## 假如 root partition 是 read-only 就作 fsck 的動作 , 假如不是 read-only
## 而是 read-write 的話 , 就做下面 else 之後的動作
if [ ! $READWRITE = yes ]; then
## 利用 fsck 做檢查及修復檔案系統的工作 , 後面接的兩個參數 -A , -a .
## -A 的意思是 : fsck 會依據 /etc/fstab 中的記錄 , 去檢查所有的檔案
## 系統 ; 而 -a 就是 auto 的意思 , 當 fsck 有修復的動作時 , 它不會問
## 你問題 , 而直接修復 .
/sbin/fsck -A -a
## 假如 fsck 有 error , [ $? -gt 1 ] 括號裡面的意思是 : 若上個命令的
## 傳回值大於 1 , 而上個命令就是 fsck . 讓我們看看 fsck 的傳回值 :
##0;- No errors
##1;- File system errors corrected
##2;- File system errors corrected, system should
##; be rebooted if file system was mounted
##4;- File system errors left uncorrected
##8;- Operational error
##16- Usage or syntax error
##128; - Shared library error
## 很明顯的 , 若有任何錯誤產生的話 , 那 fsck 的傳回值都大於 1 . 其實
## 就我的觀點認為 , 應該寫成 if [ $? -ge 1 ] 比較好 . 既然有錯呢 , 系統
## 應該就要跳至單人模式 , 在單人模式中主要就是 /etc/rc.d/rc.K
## 中的兩件事 : 關掉 swap 及 卸下所有的檔案系統 , 而最後重新 login .
## 一般正常的情況下 ,; if 下面這一大段是不會執行的 , 而會跳至下面
## 標有 *************************; Normal 1; ************************* 處
if [ $? -gt 1 ] ; then
echo
echo
echo "**************************************"
echo "fsck returned error code - REBOOT NOW!"
echo "**************************************"
echo
echo
/bin/login
fi
## ******************************; Normal 1; **************************
## 當 fsck 檢查沒有錯誤之後 , 就把 root partition 重新 mount 上來
## 下面指令的參數有三個 , -w 代表mount 成可讀寫 , -n 代表把一個 file-
## system mount 上來 , 但不會把記錄寫到 /etc/mtab 中 , 在上次對 /etc/mtab
## 介紹時有提到 , 當我們使用 mount 這個指令把一個 filesystem mount 上來
## 的時候 , /etc/mtab 就會記錄 ! 利用 -n 這個 option 可使得做 mount 的動
## 作 , 卻不會記錄 . -o 後面可以接許多的選項 , 在這裡 , 我們給它的選項是
## remount . remount 的意思是 : 重新 mount 一個已經被 mount 的 filesystem
## 這個選項通常被用來改變該 filesystem 的讀寫旗號 ,尤其是把 filesystem
## 從 read-only 的狀態 , 改變成 read-write 的狀態 .
echo "Remounting root device with read-write enabled."
/sbin/mount -w -n -o remount /
## 在前面的情況中 , 都是 root partition 為 read-only 的狀態下 , 所做的一些
## 工作 , 到了最後一個指令 /sbin/mount -w -n -o remount / , 才把 root
## partition mount 成 read-write . 各位有沒有看到前面那行 :
## if [ ! $READWRITE = yes ]; then ..... 下面這個 else 就是與這個 if 對應
## 也就是說 , 前面那個 if 的區塊中 , 所作的工作都是在 root partition 為
## read-only 的條件成立下所作的事 , 那很明顯的 , 下面這個 else 就是 root
## partition 為 read-write 的條件下所作的工作 . 假如你的 root partition
## 為 read-writeable 的話 , 那麽系統就會顯示下面的訊息 . cat << EOF 所作的
## 事 , 就是把 EOF 之前的訊息全部顯示在螢幕上 :
## 我想 , 下面的訊息寫得很明顯了 , 它說 : 你的 root partition 被 mount 成
## read-write , 沒有辦法檢查 , 要使檢查的動作能夠順利的進行 , 你必須把
## root partition mount 成 read-only ! 那要怎麽做呢 ? 很容易 , 只要利用
## rdev -R /<your_kernel_name> 1; 就可以了 ......
else
cat << EOF
*** Root partition has already been mounted read-write. Cannot check!
For filesystem checking to work properly, your system must initially mount
the root partition as read only. Please modify your kernel with 'rdev' so
that
it does this. If you're booting with LILO, type:
rdev -R /vmlinuz 1
(^^^^^^^^; ... or whatever your kernel name is.)
If you boot from a kernel on a floppy disk, put