剖析Linux系统启动过程(二)
生活随笔
收集整理的這篇文章主要介紹了
剖析Linux系统启动过程(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? 各位是否曾經對電腦整個開機的流程感到好奇呢 ? 這一次 , 我們所要討論的主題 , 就是 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 rootpartition . 在這之后 , kernel 會起動 init 這個 process . init 這個 process 的 PID 為 1 , 它是所有 process 的祖先 .
接下來呢 ? 系統就開始執行 /rc.d/rc.S , 在這里 , 我們暫時打住 , 先對大概的 initialization script 執行的順序作一個瀏覽 , 請看下面的流程 :
init[1]
rc.S begin <--- 目前我們已經講到這里
rc.serial begin
rc.serial end
rc.S end
init[1] enter runlevel 5
rc.M begin
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.M end
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 / 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 it in the drive and type:
rdev -R /dev/fd0 1
This will fix the problem *AND* eliminate this annoying message. :^)
EOF
?
下面這個指令沒什么好說的 , 就是暫停 10 秒鐘 , 讓 user 能夠有充足的
時間看完上面的信息
sleep 10
fi
?
刪除 /etc/mtab /etc/nologin /etc/utmp
/bin/rm -f /etc/mtab* /etc/nologin /etc/utmp
? 制造 /etc/utmp , 這是一個很典型制造空文件的寫法 . /dev/null 這個 node
蠻有趣的 , 在某一方面來說 , 它有點像是一個 " 黑洞 " . 怎么說呢?各位可以試試看下面的指令 ls >> /dev/null , 當你使用這個指令之后會發生什么事呢 ? 什么也沒發生 , 而且 ls 的輸出就好像被丟到黑洞里 , 無影無蹤了 . 那也許你會想 : 那這有什么用 ? 我的回答是 : 的確沒有什么很大的用處 , 但當你想抑制輸出的信息時 , 你就會用得到了 .
cat /dev/null >> /etc/utmp
?
依據 fstab ( filesystem table ) 中的描述 , 自動的掛上文件系統但此時因為 TCP/IP 還沒有設定 , 故不用 NFS
echo 'Mount Filesystem !!!'
/sbin/mount -avt nonfs
?
設定系統的時鐘 . 下面這幾行所做的事就是 : 看看 /sbin/clock 這個文件是不是可執行的 , 假如可以執行 , 就把 CMOS 中的時間設定為系統的時間 .
if [ -x /sbin/clock ]; then
echo 'Set System Clock'
/sbin/clock -s
fi
?
下面的四行若沒有 mark , 則每次開機 issue 及 motd 都會被改變 , 這應該可算是 FAQ 級的問題了 ...... 因為我有自己設計的 issue 及 motd , 所以下面的四行前面都有 # , 被注釋掉 .?假如你要有自己的設定 , 下面一定都要 mark 起來
#echo > /etc/issue
#echo Welcome to Linux /bin/uname -a | /bin/cut -d\ -f3. >> /etc/issue
#echo >> /etc/issue
#echo "/bin/uname -a | /bin/cut -d\ -f1,3. (Posix)." > /etc/motd
?
接下來 , 將執行 rc.serial , 顧名思義 , rc.serial 是作串口設定的工作在 rc.serial 中 , 內容雖然也是很簡單 , 但并不像 rc.S 那樣直接 . 換句話說 , 讀者至少要 " 稍微 " 懂一點 shell programming , 所以說呢 , 假如還不會 shell programming 的讀者呢 , 都應該趕快去找一本書來看一下 , 在這篇文章的結尾 , 我會提出一些書單 , 各位可以去找找這幾本書 ......
/bin/sh /etc/rc.d/rc.serial
echo '============== rc.S is finish NOW !!! ================='
?
?
到了這里 , rc.S 的最後一步 , 是去執行 rc.serial . 大家可以看一看/rc.d/rc.serial . 好像很長的樣子 , 但實際上呢 , 各位必然發現到了 , 這個shell script 大部份指令的前面都有一個 '#' 號 , 這代表著 , 這些指令完全不會被執行 . 所以呢 , 真正有用的只不過寥寥十幾行吧 ! 在另一方面來說 , 假如你是用網卡連上網絡 , 那 rc.serial 對你并沒有什么大用處.
?
**************************** rc.serial **************************
#!/bin/sh
#
# /etc/rc.serial
# Initializes the serial ports on your system
#
# Version 2.01
echo '================= rc.serial is begin !!! ================'
cd /dev
下面三行中的前兩行是設定一些變量 , 由于在這個 shell script 中 , 需要 用到 /bin/setserial -b 這個指令 , 或是需要用到所有以 cua 開頭的 node的次數太多了 , 因此 , 把它們設定為一個變量 , 是一個不錯的方法 . 尤其 PORTS=`echo cua? cua??` 這是一個聰明的寫法 , 那為什么不寫成 PORT= `echo cua*` 呢 ? 各位可以在 /dev 下分別使用這兩個指令 , 觀察輸出到底有什么不同 ......
SETSERIAL="/bin/setserial -b"
PORTS=`echo cua? cua??`
echo -n "Configuring serial ports...."
?
下面這行 , 沒有學過 shell programming 的人很可能會看不懂 , 不過沒有關系 , 這行中的 ${SETSERIAL} 會被換成 /bin/setserial -b , 而${PORTS}?會被換成 cua0 cua1 cua2 ....... cua31 , 所以整句翻譯就是:/bin/setserial -b -W cua0 cua1 cua2 cua3 cua4 cua5 cua6 ...... cua31那這行指令到底在做什么呢 ? 其實只是在做中斷偵測的工作.
${SETSERIAL} -W ${PORTS}
?
各位看到下面原來的注釋了吧 . 當你有一些特殊的卡時 , 你可以把相對應部份前面的 '#' 去掉 , 以便能做自動設定的工作 . 其實呢 , 這種情況實在不多 , 大部份人的設備都差不了多少 , 說到關于串口 , 差異就更少了 .
#
# AUTOMATIC CONFIGURATION
#
# Uncomment the appropriate lines below to enable auto-configuration
# of a particular board. Or comment them out to disable them....
#
?
## 好了 , 這下我們又多了一個變量 : AUTO_IRQ , 這在下面會用到 .
AUTO_IRQ=auto_irq
?
## 下面幾行非常整齊 , 它們可以分別被換成 :
## /bin/setserial -b /dev/cua? auto_irq skip_test autoconfig
## setserial 說穿了也沒什么 , 這個指令可以讓你對 serial port 做設定及回報
## 的動作 , 像 IRQ , I/O port 啦等等的事情 . 一般的情況下 , 大家的電腦中
## 通常只有 COM1-COM4 , 但假如你想增加新的 port , 那 setserial 就派上用
## 場了 .
# These are the standard COM1 through COM4 devices
#
# If you have an internal modeme with a Rockwell Chipset, add a "skip_test"
# to the /dev/cua3 line below. (It's not added by default because it will
# screw up people with 8514 displays).
#
${SETSERIAL} /dev/cua0 ${AUTO_IRQ} skip_test autoconfig
${SETSERIAL} /dev/cua1 ${AUTO_IRQ} skip_test autoconfig
${SETSERIAL} /dev/cua2 ${AUTO_IRQ} skip_test autoconfig
${SETSERIAL} /dev/cua3 ${AUTO_IRQ} autoconfig
# These are for the first AST Fourport board (base address 0x1A0)
#
${SETSERIAL} /dev/cua4 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua5 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua6 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua7 ${AUTO_IRQ} autoconfig
# These are for the second AST Fourport board (base address 0x2A0)
#
${SETSERIAL} /dev/cua8 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua9 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua10 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua11 ${AUTO_IRQ} autoconfig
?
## 從這里以下 , 我省略了一大段 , 因為這一大段都是支持特殊的卡
# These are the 3rd and 4th ports on the Accent Async board.
#
#${SETSERIAL} /dev/cua12 ${AUTO_IRQ} autoconfig
#${SETSERIAL} /dev/cua13 ${AUTO_IRQ} autoconfig
#
?
.
.
.
.
.
.
.
?
## 好了 , 我們跳掉了一大段 , 直到這里 . 各位看到下面的注解了 .
## 假如你想用手動的方法指定 IRQ , I/O port , 及指定 chip 的型號
## 那你可以拿掉下面對應那行前面的 '#' 并作適當的修改 , 比如說
## 你用的是比較新的 16550 或 16550A , 而不是 16450 , 那你就可以
## 在下面用手動的方法指定 . 實際上 , 用 autoconfig 及 autoirq
## 的選項就可以了 , 沒有必要用手動的方式 . 除非偵測不到 .
###############################################################
#
# MANUAL CONFIGURATION
#
# If you want to do manual configuration of one or more of your
# serial ports, uncomment and modify the relevant lines.
#
###############################################################
# These are the standard COM1 through COM4 devices
#
#${SETSERIAL} /dev/cua0 uart 16450 port 0x3F8 irq 4
#${SETSERIAL} /dev/cua1 uart 16450 port 0x2F8 irq 3
#${SETSERIAL} /dev/cua2 uart 16450 port 0x3E8 irq 4
#${SETSERIAL} /dev/cua3 uart 16450 port 0x2E8 irq 3
.
.
.
.
.
.
.
.
## Ok , 到此 , rc.S 及 rc.serial 已經結束 , 因為截稿時間的關系 , rc.M
## rc.inet1 , rc.inet2 , rc.font , rc.local 將在以后為各位介紹 .
echo "done."
${SETSERIAL} -bg ${PORTS}
echo ' ====================== rc.serial is complete !!! ==================='
?
?
* 關于 Shell Programming 的書單 :
Title: The Unix C Shell Field Guide
Authors: Gail Anderson and Paul Anderson
Publisher: Prentice Hall
Edition: 1986
ISBN: 0-13-937468-X
這本是 C-Shell 的 Bible , 想學 C-Shell 的人 , 可以去看這本書 .
?
Title: Unix Shell Programming
Authors: Stephen Kochan and Patrick Wood
Publisher: Hayden
Edition: 1990
ISBN: 0-672-48448-X
喔 ! 這本書以 Bourne Shell 為主 , 內容深入淺出 , 讀者很容易就可以了解
這本書的內容 , 進而掌握 Bourne Shell 的精髓 . 此外 , 這本書也有提到
Korn Shell , 大體上來說 , 是一本值得看的好書 .
?
*如何聯系作者 :
E-Mail Address : jhhsu@csie.nctu.edu.tw
u8217017@cc.nctu.edu.tw
Dormitory : 交通大學十舍 317R
..
?
?
Linux 開機程序之研討
CCCA 資工86 許景華
在上次的介紹中 , 我們已經看完了 rc.S 及 rc.serial 這兩個 shell script .
現在 , 我們將把剩下的 shell script 再作一個介紹 .
首先還是看看全部的流程 :
?
init[1]
rc.S begin
rc.serial begin
rc.serial end
rc.S end <-- 上一次我們說明到這里
init[1] enter runlevel 5
rc.M begin
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.M end
login
?
這次主要的部份可分為兩項 : 因為 init 將會去讀取 inittab , 所以 inittab
將被列為第一部份的重點 , 而第二部份就是 rc.M , rc.font , rc.local
這幾個 shell script 的說明 . ( rc.inet1 , rc.inet2 這兩個關于網絡的
shell script 將在以后單獨說明 )
好了 , 我們先從 inittab 看起吧 ! 看看上面的流程 , 在第一行 : init[1]
也就是 init 這個 process 被啟動之后 , 它會去讀取 /etc/inittab 這個文件
以完成系統的啟動 . 從這里 , 我們看到了 LINUX 的確融合了 SVR4 及 SunOS
的一些特性 , inittab 這個文件 , 在 SunOS 系統中是不存在的 , 但是它卻是
SVR4 典型的文件 . init 這個 process 會依據 /etc/inittab 中所記載的內容
進入不同的 run-level 并啟動不同的 process . 所以 inittab 的重要性
可見一斑 . 那什么叫 run-level 呢 ? 所謂 run-level 就是系統中定義了許多
不同的 level , 而系統會隨著 level 的不同而去啟動不同的資源 .
現在就讓我們來看一下 /etc/inittab 中的內容 :
在 /etc/inittab 這個文件中 , 每一列是一個進入點 , 假如我們仔細觀察每一列
的話 , 那我們就會很容易的發現 , /etc/inittab 的每一列可以被 " : " 這個
字符分成好幾個欄位 . 這幾個欄位的格式如下 :
id:runlevels:action:process
而它們代表的意義分別如下 :
id : 由兩個獨特的字符所組成的辨示符號 , 在比較新的 UNIX 系統中 , 已不
受只能有兩個字符的限制 .
runlevels : 指出下面一個欄位中的 action 以及 下下個欄位中的 process
會在那些 runlevel 中被執行 . 這一欄的合法值有 0,1,2...6
s 以及 S . 而在正常的啟動程序之后 , Superuser 可以使用
telinit 這個指令來改變系統的 runlevel . 又因為在 LINUX 中
, runlevel 的預設值是 5 ( 等一下就會看到 ) 所以 , 只有
那些每一列中 runlevel 那欄有 5 這個值的 , 后面的 process
才會被啟動 . 所以 , 我們就可以想像的到 : " 由于系統的
runlevel 不同 , 所起動的 process 也不盡相同 , 所以系統
起動的資源在每個不同的 runlevel 就會有差異存在 .
action : 這個欄位有一點復雜 , 在這個欄位中記錄著 init 在啟動相對應的
process 時 , 對 process 所采取的動作 , 而合法的動作有下面幾項:
initdefault : 指出系統在啟動時 , 預設進入的 run-level 值 ,
比如說 , 我們可以在 /etc/inittab 中找到下面這
一列 : id:3:initdefault:
很明顯的 , 系統將在啟動時 , 進入 runlevel 為 3
的模式 . 當然 , 你可以把 3 改成 4 試試看 , 如
果你改成了 4 , 那將會執行 /etc/rc.d/rc.4 , 也
就是 run xdm . xdm 在以后有機會的話 , 將為各
位介紹 ......
sysinit : 在系統起動時 , 這個 process 會被執行 . 而所有 process
前的 action 中有 boot 及 bootwait 的 process , 必
須等到這些 action 為 sysinit 的 process 執行完之后
它們才能夠執行 .
wait : 在起動一個 process 之后 , 若要再起動另一個 process , 則
必需等到這個 process 結束之后才能繼續 .
respawn : 代表這個 process 即使在結束之后 , 也會重新被啟動 ,
最典型的例子就是 getty ( 在 LINUX 中為 agetty ) .
看看下面的循環 :
-- getty --> login --> shell --> logout --
^ |??????????????????????????????????????? |
? |<---------------------------------------|
即使在 getty 結束之后 , 它也會重新被啟動 .
ctrlaltdel : 想必有人會以鍵盤上的 Ctrl , Alt , 及 Del 這三個
鍵來達到使系統 shutdown 的目的 , 現在我們果然在
/etc/inittab 中看到了這一列 :
ca::ctrlaltdel:/sbin/shutdown -t3 -rf now
所以說 , 當我們按下這三個鍵的時候 , init 會收到
SIGINT 這個 signal , 接著就執行 shutdown 的動作
不過 , 我們最好不要養成按 Ctrl-Alt-Del 來使系統
shutdown 的習慣 , 尤其在單用戶多任務的操作系統 , 像
OS/2 , 甚至 Windows 95 , shutdown 幾乎都是標準
的關機程序了 , 更何況是多用戶多任務的 LINUX , 所以 ,
shutdown 這個指令是一定要熟悉的 .
除了上面的幾個 action 之外 , 另外還有一些合法的 action , 但這
些 action 并不需要太注意 , 要用的時候再利用 man init 去查詢就
可以了 .
process : 這一欄中可以是 shell script 或是可執行的程序 .
好了 , 當我們了解 /etc/inittab 中每一欄的意義之后 , 要看懂 /etc/inittab
就是一件輕松愉快的工作了 . 在 /etc/inittab 檔中 , 我們可以看到下面這一段
c1:12345:respawn:/sbin/agetty 38400 tty1
c2:12345:respawn:/sbin/agetty 38400 tty2
c3:45:respawn:/sbin/agetty 38400 tty3
c4:45:respawn:/sbin/agetty 38400 tty4
c5:45:respawn:/sbin/agetty 38400 tty5
c6:456:respawn:/sbin/agetty 38400 tty6
簡單來說 , 系統在起動之后會制造出六個虛擬的 console . 我想大家應該有試過
用 Ctrl-Alt + F1 - F6 可在這六個 console 之間切換 ; 若你使用 XWindows 時
想暫時回到 console 下時 , 可用 Ctrl-Alt + F1 - F6 這三個鍵來選擇 , 若想
回到 XWindows 下時 , 只要以 Ctrl-Alt-F7 就可以回到 XWindows 下了 . 基本
上 , 對於 memory 比較少的人 , 可以不要開那么多的虛擬 console , 那么就可
以去掉上面的幾列 . 還有 , 在前面我們也提過 , 可以把預設的 runlevel 從 5
改成 6 , 對於 beginner 來說 , 系統一啟動完就直接進入 XWindows 也許是一個
不錯的設定方法 ......
介紹完 /etc/inittab 之后 , 我們接著看 rc.M ! 由前面的流程當中 , 我們看到
rc.M 中又包含了四個 shell script , 其中 rc.inet1 及 rc.inet2 是有關于網絡
的設定 ; rc.font 是作字體的設定 , 而 rc.local 中可以放一些想要起動的
daemon .
我們現在就來看看 rc.M , 依照往例 , 前面有兩個 "#" 的為加上去的注釋 .
只有一個 "#" 的為原來的注釋 :
#!/bin/sh
#
# rc.M This file is executed by init(8) when the system is being
# initialized for one of the "multi user" run levels (i.e.
# levels 1 through 6). It usually does mounting of file
# systems et al.
#
# Version: @(#)/etc/rc.d/rc.M 2.02 02/26/93
#
# Author: Fred N. van Kempen,
# Heavily modified by Patrick Volkerding
#
## 顯示進入多用戶模式
echo "Going multiuser..."
?
## 下面一列的意思是 : 假如你在文字模式的 console 下 , 在15分鐘內都沒有動作
## 的話 , 屏幕就會自動暗下來 , 簡單的說 , 就是 screen saver 的功能 .
/bin/setterm -blank 15
?
## 執行 crond 這個 daemon . 不用說 , crond 在系統中扮演了很重要的角色 ,
## 它負責每過一段時間后 , 就去看看 /var/spool/cron/crontabs 中有那些 file
## 要運行 , 這些 file 往往有一個固定的時間 , 比如說 : 每個月的 1 號 , 每
## 天凌晨等 ...... 我們可以用平常的編輯器編好一個文件 , 里面的格式如下 :
##
## 分 時 日 月 星期 命令
##
## 舉例來說 , 59 23 31 12 * /etc/wall happy_new_year
## 在每年的 12 月 31 號晚上 11 點 59 分 會對每個系統上的 user 送出
## happy_new_year 中的內容
##
## 接著我們可以利用 crontab <文件名> 這個指令來把此文件放到
## /var/spool/cron/crontabs中. 我們可以看看 /var/spool/cron/crontab 下
## 有一個 root 的文件 , 看看里面的內容 :
##
## 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/lib/atrun
##
## 所以各位看到了 , 在前兩期提到的 at 命令是五分鐘才被 run 一次的
##
## 再舉一個簡單的例子好了 : 我們先用一般的文本編輯器造出一個名為 crontest
## 的檔案 , 內容如下 :
##
## 5 * * * * ls -la ~/ >> ~/hehehaha
##
## 接著 , 我們鍵入下面的命令 : crontab crontest
## 此時 , 從內容得知 , 每五分鐘 crond 就會執行 ls -la , 把你 home directory
## 的內容加入 hehehaha 這個文件中 .
##
## 當然啦 ! 這個例子簡直是毫無意義可言 :) 但是 , 大家既然知道了基本原理 ,
## 利用 crontab , at 這些指令 , 就可以簡化一些系統管理的動作 , 同時在執行
## 一些工作時 , 也會比較有彈性 .
/usr/sbin/crond -l10 >>/var/adm/cron 2>&1
?
## 假如 /etc/HOSTNAME 不能讀取的話 , 就把 darkstar.frop.org 當成 HOSTNAME
## 中的內容 . 老實說 , 下面這三列去掉也不打緊 ......
if [ ! -r /etc/HOSTNAME ]; then
echo "darkstar.frop.org" > /etc/HOSTNAME
fi
?
## 下面從 if 到 fi 夾起來的部份 , 主要就是在執行 rc.inet1 , rc.inet2 . 這
## 些都是網絡設定的工作 , 尤其是 rc.inet2 , 啟動了一大堆 daemon , 這部份
## 要牽扯到的東西太多了 . 像 subnet 與 netmask 等 ...... 類似這種觀念 ,
## 都不是三言兩語就可以玩完的 , 所以就留待以后再說 .
if [ -x /etc/rc.d/rc.inet1 ];
then
/bin/hostname `cat /etc/HOSTNAME | cut -f1 -d .`
/bin/sh /etc/rc.d/rc.inet1
/bin/sh /etc/rc.d/rc.inet2
else
/sbin/hostname_notcp `cat /etc/HOSTNAME | cut -f1 -d .`
/usr/sbin/syslogd
/usr/sbin/klogd
/usr/sbin/lpd
fi
?
## 在某些資源獨占的情況下 , 一些應用程序往往會制造出 lock 文件 . 假如這些
## lock 文件在重新開機以后還是存在的話 , 那就很不好了 . 所以 , 下面就是在
## 作這些刪除 lock 文件的動作 , 并把一些輸出的信息丟到 /dev/null 去 .
## 在上一期的內容中 , 我們就有提到 /dev/null 了 , 也有提到抑制信息輸出的
## 方法 . 現在我們果然看到了一個實例 ......
/bin/rm -f /var/spool/locks/* /var/spool/uucp/LCK..* /tmp/.X*lock 1> /dev/null 2> /dev/null
?
## 假如你有玩 hunt 這個 game 的話 , 那在 /tmp 下會有一個 socket 類型的文件
## 我們要把它刪除之后才能開始另一個 game ......
if [ -r /tmp/hunt -o -r /tmp/hunt.stats ]; then
echo "Removing your stale hunt sockets from /tmp..."
/bin/rm -f /tmp/hunt*
fi
?
## 設定 share library 的 link 及 cache . 這個指令只有 Superuser 才能使用
## 的 , 它也相當的重要 . 萬一你的 /etc/ld.so.cache 很不幸的 corrupt 了 ,
## 那我們也可以利用這個指令來讓它重新 link , 先刪除 /etc/ld.so.cache ,
## 再以 ldconfig -v 重新制造就可以了 .
/sbin/ldconfig
?
## 起動 sendmail daemon , 并且讓它 15 分鐘就去看一看 spool , 處理收發信件
if [ -x /usr/sbin/sendmail ]; then
echo "Starting sendmail daemon (/usr/sbin/sendmail -bd -q 15m)..."
/usr/sbin/sendmail -bd -q 15m
fi
?
## 假如 /etc/rc.d/rc.font 是可讀的話 , 就執行 rc.font 這個 shell script ,
## 而這個 shell script 主要是設定 text mode 下屏幕的字體
if [ -r /etc/rc.d/rc.font ]; then
/etc/rc.d/rc.font
fi
?
## 在系統管理中 , 我們常常把一些 local 的東西另外放在一個地方 , 這樣才不
## 會與原來的東西混淆 . 同時 , 因為 local 的東西更新版本的速度總是也比較
## 快 , 在這種情況下 , 常常會變動的東西也可以放在 local 的區域中 , 這樣
## 管理起來比較方便 . 也許各位也注意到了 : 為什么會有 /usr/bin 及
## /usr/local/bin 之分 . 就個人認為 , 像自己 compile 出來的東西 , 假如
## 覺得還不錯 , 就可以把它放在 /usr/local/bin , 因為它是新增的 , 所以我
## 把它放在 /usr/local/bin . 當然啦 , 這只是個人喜好罷了 , 你要放那里
## 都是可以的 , 只要找得到 , 易于使用及管理就好 .
## 同樣的 , 若我們要起動一些新增的 daemon 或 shell script , 那放在
## 是不錯的選擇 .
## 下面一列就是去執行 rc.local 中的設定 , 通常是一些 daemon 或是 shell
## script
/etc/rc.d/rc.local
?
# All done.
?
到這里 , rc.M 已經結束了 , 我們來看看從 rc.M 之中執行的 rc.font 及
rc.local ......
下面是 rc.font 的內容 :
#!/bin/sh
#
# This selects your default screen font from among the ones in
# /usr/lib/kbd/consolefonts.
#
## 我想下面這一列的命令非常明顯了 , 就是設定 console 中的字體 , 你可以
## 改成自己喜歡的字體 . 或者你也可以利用 fontconfig 這個指令來改變 .
setfont /usr/lib/kbd/consolefonts/default8x16
?
?
看完了 rc.font 后 , 我們來看看 rc.local 的內容 . 我所要說的是 : rc.local
畢竟是自己設定的區域 , 所以每個人的可能都不一樣 , 就我而言 , 因為我多 run
了一些 daemon , 所以與大家的可能不太相同 . 所以 , rc.local 作參考就可以了.
下面是我的 rc.local :
#! /bin/sh
# Put any local setup commands in here
# Running selection
?
## lpd 是控制打印機的 daemon , 要想在 LINUX 下用打印機 , 這個 daemon 必需
## 要被起動 , 此外還要修改 /etc/printcap . 詳細的情況要去看 PRINT-HOWTO
echo -n "lpd"
/etc/lpd
?
## httpd 就是 WWW server 的 daemon . 想必大家都用過 Mosaic , Netscape 等
## 的瀏覽器 . 但假如我們想建立自己的 WWW server , httpd 必須要執行 .
echo -n " httpd"
/usr/local/etc/httpd/src/httpd
?
## 在 WWW 的時代還沒來臨以前 , gopher 可說是具有最方便的信息索引功能 , 即使
## 到了現在 , gopher 仍然占有一席之地 , 在這里 , 因為我有建立自己的 gopher
## server , 所以 gopherd 必需被起動 .
echo -n " gopherd"
/usr/local/sbin/gopherd -u nobody
?
## 下面這個指令是 mouse 在 console 下做 cut & paste
echo -n "Running selection..."
selection -t ms &
echo ' '
作者Blog:http://blog.csdn.net/loef/
想必各位都知道 , 在剛開機時 , 由于 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 rootpartition . 在這之后 , kernel 會起動 init 這個 process . init 這個 process 的 PID 為 1 , 它是所有 process 的祖先 .
接下來呢 ? 系統就開始執行 /rc.d/rc.S , 在這里 , 我們暫時打住 , 先對大概的 initialization script 執行的順序作一個瀏覽 , 請看下面的流程 :
init[1]
rc.S begin <--- 目前我們已經講到這里
rc.serial begin
rc.serial end
rc.S end
init[1] enter runlevel 5
rc.M begin
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.M end
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 / 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 it in the drive and type:
rdev -R /dev/fd0 1
This will fix the problem *AND* eliminate this annoying message. :^)
EOF
?
下面這個指令沒什么好說的 , 就是暫停 10 秒鐘 , 讓 user 能夠有充足的
時間看完上面的信息
sleep 10
fi
?
刪除 /etc/mtab /etc/nologin /etc/utmp
/bin/rm -f /etc/mtab* /etc/nologin /etc/utmp
? 制造 /etc/utmp , 這是一個很典型制造空文件的寫法 . /dev/null 這個 node
蠻有趣的 , 在某一方面來說 , 它有點像是一個 " 黑洞 " . 怎么說呢?各位可以試試看下面的指令 ls >> /dev/null , 當你使用這個指令之后會發生什么事呢 ? 什么也沒發生 , 而且 ls 的輸出就好像被丟到黑洞里 , 無影無蹤了 . 那也許你會想 : 那這有什么用 ? 我的回答是 : 的確沒有什么很大的用處 , 但當你想抑制輸出的信息時 , 你就會用得到了 .
cat /dev/null >> /etc/utmp
?
依據 fstab ( filesystem table ) 中的描述 , 自動的掛上文件系統但此時因為 TCP/IP 還沒有設定 , 故不用 NFS
echo 'Mount Filesystem !!!'
/sbin/mount -avt nonfs
?
設定系統的時鐘 . 下面這幾行所做的事就是 : 看看 /sbin/clock 這個文件是不是可執行的 , 假如可以執行 , 就把 CMOS 中的時間設定為系統的時間 .
if [ -x /sbin/clock ]; then
echo 'Set System Clock'
/sbin/clock -s
fi
?
下面的四行若沒有 mark , 則每次開機 issue 及 motd 都會被改變 , 這應該可算是 FAQ 級的問題了 ...... 因為我有自己設計的 issue 及 motd , 所以下面的四行前面都有 # , 被注釋掉 .?假如你要有自己的設定 , 下面一定都要 mark 起來
#echo > /etc/issue
#echo Welcome to Linux /bin/uname -a | /bin/cut -d\ -f3. >> /etc/issue
#echo >> /etc/issue
#echo "/bin/uname -a | /bin/cut -d\ -f1,3. (Posix)." > /etc/motd
?
接下來 , 將執行 rc.serial , 顧名思義 , rc.serial 是作串口設定的工作在 rc.serial 中 , 內容雖然也是很簡單 , 但并不像 rc.S 那樣直接 . 換句話說 , 讀者至少要 " 稍微 " 懂一點 shell programming , 所以說呢 , 假如還不會 shell programming 的讀者呢 , 都應該趕快去找一本書來看一下 , 在這篇文章的結尾 , 我會提出一些書單 , 各位可以去找找這幾本書 ......
/bin/sh /etc/rc.d/rc.serial
echo '============== rc.S is finish NOW !!! ================='
?
?
到了這里 , rc.S 的最後一步 , 是去執行 rc.serial . 大家可以看一看/rc.d/rc.serial . 好像很長的樣子 , 但實際上呢 , 各位必然發現到了 , 這個shell script 大部份指令的前面都有一個 '#' 號 , 這代表著 , 這些指令完全不會被執行 . 所以呢 , 真正有用的只不過寥寥十幾行吧 ! 在另一方面來說 , 假如你是用網卡連上網絡 , 那 rc.serial 對你并沒有什么大用處.
?
**************************** rc.serial **************************
#!/bin/sh
#
# /etc/rc.serial
# Initializes the serial ports on your system
#
# Version 2.01
echo '================= rc.serial is begin !!! ================'
cd /dev
下面三行中的前兩行是設定一些變量 , 由于在這個 shell script 中 , 需要 用到 /bin/setserial -b 這個指令 , 或是需要用到所有以 cua 開頭的 node的次數太多了 , 因此 , 把它們設定為一個變量 , 是一個不錯的方法 . 尤其 PORTS=`echo cua? cua??` 這是一個聰明的寫法 , 那為什么不寫成 PORT= `echo cua*` 呢 ? 各位可以在 /dev 下分別使用這兩個指令 , 觀察輸出到底有什么不同 ......
SETSERIAL="/bin/setserial -b"
PORTS=`echo cua? cua??`
echo -n "Configuring serial ports...."
?
下面這行 , 沒有學過 shell programming 的人很可能會看不懂 , 不過沒有關系 , 這行中的 ${SETSERIAL} 會被換成 /bin/setserial -b , 而${PORTS}?會被換成 cua0 cua1 cua2 ....... cua31 , 所以整句翻譯就是:/bin/setserial -b -W cua0 cua1 cua2 cua3 cua4 cua5 cua6 ...... cua31那這行指令到底在做什么呢 ? 其實只是在做中斷偵測的工作.
${SETSERIAL} -W ${PORTS}
?
各位看到下面原來的注釋了吧 . 當你有一些特殊的卡時 , 你可以把相對應部份前面的 '#' 去掉 , 以便能做自動設定的工作 . 其實呢 , 這種情況實在不多 , 大部份人的設備都差不了多少 , 說到關于串口 , 差異就更少了 .
#
# AUTOMATIC CONFIGURATION
#
# Uncomment the appropriate lines below to enable auto-configuration
# of a particular board. Or comment them out to disable them....
#
?
## 好了 , 這下我們又多了一個變量 : AUTO_IRQ , 這在下面會用到 .
AUTO_IRQ=auto_irq
?
## 下面幾行非常整齊 , 它們可以分別被換成 :
## /bin/setserial -b /dev/cua? auto_irq skip_test autoconfig
## setserial 說穿了也沒什么 , 這個指令可以讓你對 serial port 做設定及回報
## 的動作 , 像 IRQ , I/O port 啦等等的事情 . 一般的情況下 , 大家的電腦中
## 通常只有 COM1-COM4 , 但假如你想增加新的 port , 那 setserial 就派上用
## 場了 .
# These are the standard COM1 through COM4 devices
#
# If you have an internal modeme with a Rockwell Chipset, add a "skip_test"
# to the /dev/cua3 line below. (It's not added by default because it will
# screw up people with 8514 displays).
#
${SETSERIAL} /dev/cua0 ${AUTO_IRQ} skip_test autoconfig
${SETSERIAL} /dev/cua1 ${AUTO_IRQ} skip_test autoconfig
${SETSERIAL} /dev/cua2 ${AUTO_IRQ} skip_test autoconfig
${SETSERIAL} /dev/cua3 ${AUTO_IRQ} autoconfig
# These are for the first AST Fourport board (base address 0x1A0)
#
${SETSERIAL} /dev/cua4 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua5 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua6 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua7 ${AUTO_IRQ} autoconfig
# These are for the second AST Fourport board (base address 0x2A0)
#
${SETSERIAL} /dev/cua8 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua9 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua10 ${AUTO_IRQ} autoconfig
${SETSERIAL} /dev/cua11 ${AUTO_IRQ} autoconfig
?
## 從這里以下 , 我省略了一大段 , 因為這一大段都是支持特殊的卡
# These are the 3rd and 4th ports on the Accent Async board.
#
#${SETSERIAL} /dev/cua12 ${AUTO_IRQ} autoconfig
#${SETSERIAL} /dev/cua13 ${AUTO_IRQ} autoconfig
#
?
.
.
.
.
.
.
.
?
## 好了 , 我們跳掉了一大段 , 直到這里 . 各位看到下面的注解了 .
## 假如你想用手動的方法指定 IRQ , I/O port , 及指定 chip 的型號
## 那你可以拿掉下面對應那行前面的 '#' 并作適當的修改 , 比如說
## 你用的是比較新的 16550 或 16550A , 而不是 16450 , 那你就可以
## 在下面用手動的方法指定 . 實際上 , 用 autoconfig 及 autoirq
## 的選項就可以了 , 沒有必要用手動的方式 . 除非偵測不到 .
###############################################################
#
# MANUAL CONFIGURATION
#
# If you want to do manual configuration of one or more of your
# serial ports, uncomment and modify the relevant lines.
#
###############################################################
# These are the standard COM1 through COM4 devices
#
#${SETSERIAL} /dev/cua0 uart 16450 port 0x3F8 irq 4
#${SETSERIAL} /dev/cua1 uart 16450 port 0x2F8 irq 3
#${SETSERIAL} /dev/cua2 uart 16450 port 0x3E8 irq 4
#${SETSERIAL} /dev/cua3 uart 16450 port 0x2E8 irq 3
.
.
.
.
.
.
.
.
## Ok , 到此 , rc.S 及 rc.serial 已經結束 , 因為截稿時間的關系 , rc.M
## rc.inet1 , rc.inet2 , rc.font , rc.local 將在以后為各位介紹 .
echo "done."
${SETSERIAL} -bg ${PORTS}
echo ' ====================== rc.serial is complete !!! ==================='
?
?
* 關于 Shell Programming 的書單 :
Title: The Unix C Shell Field Guide
Authors: Gail Anderson and Paul Anderson
Publisher: Prentice Hall
Edition: 1986
ISBN: 0-13-937468-X
這本是 C-Shell 的 Bible , 想學 C-Shell 的人 , 可以去看這本書 .
?
Title: Unix Shell Programming
Authors: Stephen Kochan and Patrick Wood
Publisher: Hayden
Edition: 1990
ISBN: 0-672-48448-X
喔 ! 這本書以 Bourne Shell 為主 , 內容深入淺出 , 讀者很容易就可以了解
這本書的內容 , 進而掌握 Bourne Shell 的精髓 . 此外 , 這本書也有提到
Korn Shell , 大體上來說 , 是一本值得看的好書 .
?
*如何聯系作者 :
E-Mail Address : jhhsu@csie.nctu.edu.tw
u8217017@cc.nctu.edu.tw
Dormitory : 交通大學十舍 317R
..
?
?
Linux 開機程序之研討
CCCA 資工86 許景華
在上次的介紹中 , 我們已經看完了 rc.S 及 rc.serial 這兩個 shell script .
現在 , 我們將把剩下的 shell script 再作一個介紹 .
首先還是看看全部的流程 :
?
init[1]
rc.S begin
rc.serial begin
rc.serial end
rc.S end <-- 上一次我們說明到這里
init[1] enter runlevel 5
rc.M begin
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.M end
login
?
這次主要的部份可分為兩項 : 因為 init 將會去讀取 inittab , 所以 inittab
將被列為第一部份的重點 , 而第二部份就是 rc.M , rc.font , rc.local
這幾個 shell script 的說明 . ( rc.inet1 , rc.inet2 這兩個關于網絡的
shell script 將在以后單獨說明 )
好了 , 我們先從 inittab 看起吧 ! 看看上面的流程 , 在第一行 : init[1]
也就是 init 這個 process 被啟動之后 , 它會去讀取 /etc/inittab 這個文件
以完成系統的啟動 . 從這里 , 我們看到了 LINUX 的確融合了 SVR4 及 SunOS
的一些特性 , inittab 這個文件 , 在 SunOS 系統中是不存在的 , 但是它卻是
SVR4 典型的文件 . init 這個 process 會依據 /etc/inittab 中所記載的內容
進入不同的 run-level 并啟動不同的 process . 所以 inittab 的重要性
可見一斑 . 那什么叫 run-level 呢 ? 所謂 run-level 就是系統中定義了許多
不同的 level , 而系統會隨著 level 的不同而去啟動不同的資源 .
現在就讓我們來看一下 /etc/inittab 中的內容 :
在 /etc/inittab 這個文件中 , 每一列是一個進入點 , 假如我們仔細觀察每一列
的話 , 那我們就會很容易的發現 , /etc/inittab 的每一列可以被 " : " 這個
字符分成好幾個欄位 . 這幾個欄位的格式如下 :
id:runlevels:action:process
而它們代表的意義分別如下 :
id : 由兩個獨特的字符所組成的辨示符號 , 在比較新的 UNIX 系統中 , 已不
受只能有兩個字符的限制 .
runlevels : 指出下面一個欄位中的 action 以及 下下個欄位中的 process
會在那些 runlevel 中被執行 . 這一欄的合法值有 0,1,2...6
s 以及 S . 而在正常的啟動程序之后 , Superuser 可以使用
telinit 這個指令來改變系統的 runlevel . 又因為在 LINUX 中
, runlevel 的預設值是 5 ( 等一下就會看到 ) 所以 , 只有
那些每一列中 runlevel 那欄有 5 這個值的 , 后面的 process
才會被啟動 . 所以 , 我們就可以想像的到 : " 由于系統的
runlevel 不同 , 所起動的 process 也不盡相同 , 所以系統
起動的資源在每個不同的 runlevel 就會有差異存在 .
action : 這個欄位有一點復雜 , 在這個欄位中記錄著 init 在啟動相對應的
process 時 , 對 process 所采取的動作 , 而合法的動作有下面幾項:
initdefault : 指出系統在啟動時 , 預設進入的 run-level 值 ,
比如說 , 我們可以在 /etc/inittab 中找到下面這
一列 : id:3:initdefault:
很明顯的 , 系統將在啟動時 , 進入 runlevel 為 3
的模式 . 當然 , 你可以把 3 改成 4 試試看 , 如
果你改成了 4 , 那將會執行 /etc/rc.d/rc.4 , 也
就是 run xdm . xdm 在以后有機會的話 , 將為各
位介紹 ......
sysinit : 在系統起動時 , 這個 process 會被執行 . 而所有 process
前的 action 中有 boot 及 bootwait 的 process , 必
須等到這些 action 為 sysinit 的 process 執行完之后
它們才能夠執行 .
wait : 在起動一個 process 之后 , 若要再起動另一個 process , 則
必需等到這個 process 結束之后才能繼續 .
respawn : 代表這個 process 即使在結束之后 , 也會重新被啟動 ,
最典型的例子就是 getty ( 在 LINUX 中為 agetty ) .
看看下面的循環 :
-- getty --> login --> shell --> logout --
^ |??????????????????????????????????????? |
? |<---------------------------------------|
即使在 getty 結束之后 , 它也會重新被啟動 .
ctrlaltdel : 想必有人會以鍵盤上的 Ctrl , Alt , 及 Del 這三個
鍵來達到使系統 shutdown 的目的 , 現在我們果然在
/etc/inittab 中看到了這一列 :
ca::ctrlaltdel:/sbin/shutdown -t3 -rf now
所以說 , 當我們按下這三個鍵的時候 , init 會收到
SIGINT 這個 signal , 接著就執行 shutdown 的動作
不過 , 我們最好不要養成按 Ctrl-Alt-Del 來使系統
shutdown 的習慣 , 尤其在單用戶多任務的操作系統 , 像
OS/2 , 甚至 Windows 95 , shutdown 幾乎都是標準
的關機程序了 , 更何況是多用戶多任務的 LINUX , 所以 ,
shutdown 這個指令是一定要熟悉的 .
除了上面的幾個 action 之外 , 另外還有一些合法的 action , 但這
些 action 并不需要太注意 , 要用的時候再利用 man init 去查詢就
可以了 .
process : 這一欄中可以是 shell script 或是可執行的程序 .
好了 , 當我們了解 /etc/inittab 中每一欄的意義之后 , 要看懂 /etc/inittab
就是一件輕松愉快的工作了 . 在 /etc/inittab 檔中 , 我們可以看到下面這一段
c1:12345:respawn:/sbin/agetty 38400 tty1
c2:12345:respawn:/sbin/agetty 38400 tty2
c3:45:respawn:/sbin/agetty 38400 tty3
c4:45:respawn:/sbin/agetty 38400 tty4
c5:45:respawn:/sbin/agetty 38400 tty5
c6:456:respawn:/sbin/agetty 38400 tty6
簡單來說 , 系統在起動之后會制造出六個虛擬的 console . 我想大家應該有試過
用 Ctrl-Alt + F1 - F6 可在這六個 console 之間切換 ; 若你使用 XWindows 時
想暫時回到 console 下時 , 可用 Ctrl-Alt + F1 - F6 這三個鍵來選擇 , 若想
回到 XWindows 下時 , 只要以 Ctrl-Alt-F7 就可以回到 XWindows 下了 . 基本
上 , 對於 memory 比較少的人 , 可以不要開那么多的虛擬 console , 那么就可
以去掉上面的幾列 . 還有 , 在前面我們也提過 , 可以把預設的 runlevel 從 5
改成 6 , 對於 beginner 來說 , 系統一啟動完就直接進入 XWindows 也許是一個
不錯的設定方法 ......
介紹完 /etc/inittab 之后 , 我們接著看 rc.M ! 由前面的流程當中 , 我們看到
rc.M 中又包含了四個 shell script , 其中 rc.inet1 及 rc.inet2 是有關于網絡
的設定 ; rc.font 是作字體的設定 , 而 rc.local 中可以放一些想要起動的
daemon .
我們現在就來看看 rc.M , 依照往例 , 前面有兩個 "#" 的為加上去的注釋 .
只有一個 "#" 的為原來的注釋 :
#!/bin/sh
#
# rc.M This file is executed by init(8) when the system is being
# initialized for one of the "multi user" run levels (i.e.
# levels 1 through 6). It usually does mounting of file
# systems et al.
#
# Version: @(#)/etc/rc.d/rc.M 2.02 02/26/93
#
# Author: Fred N. van Kempen,
# Heavily modified by Patrick Volkerding
#
## 顯示進入多用戶模式
echo "Going multiuser..."
?
## 下面一列的意思是 : 假如你在文字模式的 console 下 , 在15分鐘內都沒有動作
## 的話 , 屏幕就會自動暗下來 , 簡單的說 , 就是 screen saver 的功能 .
/bin/setterm -blank 15
?
## 執行 crond 這個 daemon . 不用說 , crond 在系統中扮演了很重要的角色 ,
## 它負責每過一段時間后 , 就去看看 /var/spool/cron/crontabs 中有那些 file
## 要運行 , 這些 file 往往有一個固定的時間 , 比如說 : 每個月的 1 號 , 每
## 天凌晨等 ...... 我們可以用平常的編輯器編好一個文件 , 里面的格式如下 :
##
## 分 時 日 月 星期 命令
##
## 舉例來說 , 59 23 31 12 * /etc/wall happy_new_year
## 在每年的 12 月 31 號晚上 11 點 59 分 會對每個系統上的 user 送出
## happy_new_year 中的內容
##
## 接著我們可以利用 crontab <文件名> 這個指令來把此文件放到
## /var/spool/cron/crontabs中. 我們可以看看 /var/spool/cron/crontab 下
## 有一個 root 的文件 , 看看里面的內容 :
##
## 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/lib/atrun
##
## 所以各位看到了 , 在前兩期提到的 at 命令是五分鐘才被 run 一次的
##
## 再舉一個簡單的例子好了 : 我們先用一般的文本編輯器造出一個名為 crontest
## 的檔案 , 內容如下 :
##
## 5 * * * * ls -la ~/ >> ~/hehehaha
##
## 接著 , 我們鍵入下面的命令 : crontab crontest
## 此時 , 從內容得知 , 每五分鐘 crond 就會執行 ls -la , 把你 home directory
## 的內容加入 hehehaha 這個文件中 .
##
## 當然啦 ! 這個例子簡直是毫無意義可言 :) 但是 , 大家既然知道了基本原理 ,
## 利用 crontab , at 這些指令 , 就可以簡化一些系統管理的動作 , 同時在執行
## 一些工作時 , 也會比較有彈性 .
/usr/sbin/crond -l10 >>/var/adm/cron 2>&1
?
## 假如 /etc/HOSTNAME 不能讀取的話 , 就把 darkstar.frop.org 當成 HOSTNAME
## 中的內容 . 老實說 , 下面這三列去掉也不打緊 ......
if [ ! -r /etc/HOSTNAME ]; then
echo "darkstar.frop.org" > /etc/HOSTNAME
fi
?
## 下面從 if 到 fi 夾起來的部份 , 主要就是在執行 rc.inet1 , rc.inet2 . 這
## 些都是網絡設定的工作 , 尤其是 rc.inet2 , 啟動了一大堆 daemon , 這部份
## 要牽扯到的東西太多了 . 像 subnet 與 netmask 等 ...... 類似這種觀念 ,
## 都不是三言兩語就可以玩完的 , 所以就留待以后再說 .
if [ -x /etc/rc.d/rc.inet1 ];
then
/bin/hostname `cat /etc/HOSTNAME | cut -f1 -d .`
/bin/sh /etc/rc.d/rc.inet1
/bin/sh /etc/rc.d/rc.inet2
else
/sbin/hostname_notcp `cat /etc/HOSTNAME | cut -f1 -d .`
/usr/sbin/syslogd
/usr/sbin/klogd
/usr/sbin/lpd
fi
?
## 在某些資源獨占的情況下 , 一些應用程序往往會制造出 lock 文件 . 假如這些
## lock 文件在重新開機以后還是存在的話 , 那就很不好了 . 所以 , 下面就是在
## 作這些刪除 lock 文件的動作 , 并把一些輸出的信息丟到 /dev/null 去 .
## 在上一期的內容中 , 我們就有提到 /dev/null 了 , 也有提到抑制信息輸出的
## 方法 . 現在我們果然看到了一個實例 ......
/bin/rm -f /var/spool/locks/* /var/spool/uucp/LCK..* /tmp/.X*lock 1> /dev/null 2> /dev/null
?
## 假如你有玩 hunt 這個 game 的話 , 那在 /tmp 下會有一個 socket 類型的文件
## 我們要把它刪除之后才能開始另一個 game ......
if [ -r /tmp/hunt -o -r /tmp/hunt.stats ]; then
echo "Removing your stale hunt sockets from /tmp..."
/bin/rm -f /tmp/hunt*
fi
?
## 設定 share library 的 link 及 cache . 這個指令只有 Superuser 才能使用
## 的 , 它也相當的重要 . 萬一你的 /etc/ld.so.cache 很不幸的 corrupt 了 ,
## 那我們也可以利用這個指令來讓它重新 link , 先刪除 /etc/ld.so.cache ,
## 再以 ldconfig -v 重新制造就可以了 .
/sbin/ldconfig
?
## 起動 sendmail daemon , 并且讓它 15 分鐘就去看一看 spool , 處理收發信件
if [ -x /usr/sbin/sendmail ]; then
echo "Starting sendmail daemon (/usr/sbin/sendmail -bd -q 15m)..."
/usr/sbin/sendmail -bd -q 15m
fi
?
## 假如 /etc/rc.d/rc.font 是可讀的話 , 就執行 rc.font 這個 shell script ,
## 而這個 shell script 主要是設定 text mode 下屏幕的字體
if [ -r /etc/rc.d/rc.font ]; then
/etc/rc.d/rc.font
fi
?
## 在系統管理中 , 我們常常把一些 local 的東西另外放在一個地方 , 這樣才不
## 會與原來的東西混淆 . 同時 , 因為 local 的東西更新版本的速度總是也比較
## 快 , 在這種情況下 , 常常會變動的東西也可以放在 local 的區域中 , 這樣
## 管理起來比較方便 . 也許各位也注意到了 : 為什么會有 /usr/bin 及
## /usr/local/bin 之分 . 就個人認為 , 像自己 compile 出來的東西 , 假如
## 覺得還不錯 , 就可以把它放在 /usr/local/bin , 因為它是新增的 , 所以我
## 把它放在 /usr/local/bin . 當然啦 , 這只是個人喜好罷了 , 你要放那里
## 都是可以的 , 只要找得到 , 易于使用及管理就好 .
## 同樣的 , 若我們要起動一些新增的 daemon 或 shell script , 那放在
## 是不錯的選擇 .
## 下面一列就是去執行 rc.local 中的設定 , 通常是一些 daemon 或是 shell
## script
/etc/rc.d/rc.local
?
# All done.
?
到這里 , rc.M 已經結束了 , 我們來看看從 rc.M 之中執行的 rc.font 及
rc.local ......
下面是 rc.font 的內容 :
#!/bin/sh
#
# This selects your default screen font from among the ones in
# /usr/lib/kbd/consolefonts.
#
## 我想下面這一列的命令非常明顯了 , 就是設定 console 中的字體 , 你可以
## 改成自己喜歡的字體 . 或者你也可以利用 fontconfig 這個指令來改變 .
setfont /usr/lib/kbd/consolefonts/default8x16
?
?
看完了 rc.font 后 , 我們來看看 rc.local 的內容 . 我所要說的是 : rc.local
畢竟是自己設定的區域 , 所以每個人的可能都不一樣 , 就我而言 , 因為我多 run
了一些 daemon , 所以與大家的可能不太相同 . 所以 , rc.local 作參考就可以了.
下面是我的 rc.local :
#! /bin/sh
# Put any local setup commands in here
# Running selection
?
## lpd 是控制打印機的 daemon , 要想在 LINUX 下用打印機 , 這個 daemon 必需
## 要被起動 , 此外還要修改 /etc/printcap . 詳細的情況要去看 PRINT-HOWTO
echo -n "lpd"
/etc/lpd
?
## httpd 就是 WWW server 的 daemon . 想必大家都用過 Mosaic , Netscape 等
## 的瀏覽器 . 但假如我們想建立自己的 WWW server , httpd 必須要執行 .
echo -n " httpd"
/usr/local/etc/httpd/src/httpd
?
## 在 WWW 的時代還沒來臨以前 , gopher 可說是具有最方便的信息索引功能 , 即使
## 到了現在 , gopher 仍然占有一席之地 , 在這里 , 因為我有建立自己的 gopher
## server , 所以 gopherd 必需被起動 .
echo -n " gopherd"
/usr/local/sbin/gopherd -u nobody
?
## 下面這個指令是 mouse 在 console 下做 cut & paste
echo -n "Running selection..."
selection -t ms &
echo ' '
作者Blog:http://blog.csdn.net/loef/
總結
以上是生活随笔為你收集整理的剖析Linux系统启动过程(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 重温struts
- 下一篇: DevExpress Asp.net(6