運行級的概念來自System V,運行級別將啟動過程分成不同的集合,每個集合包含一
組腳本,當init程序“切換運行級”到對應的級別時,相應的腳本就被觸發,切換運行
級可以通過執行init [級別號]完成。(比如,在Linux中,run level 6代表reboot,所
以執行init 6就會引起系統重新啟動)
運行級別的定義每種System V都不完全一樣,只能通過直接讀/etc/inittab來確定,
下面是一個標准的Linux的/etc/inittab,注意這裡解釋的內容來自redhat,但是其他的
版本也大同小異。我們將它分成若干段來解釋,如同一般情況那樣,用#開始的行是注釋
,而非注釋行的語法是:
標號:運行級別:操作方式:命令
標號是這一行的標簽,運行級別用於定義這一行應該用於那些級別,如果為空就定義
為所有級別,操作方式可以是一些確定的字符串,代表如何執行後面的命令,而命令則
給處在進入這一級別時執行的程序。
下面是它的內容:
# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
上面的幾行解釋了缺省的運行級別定義:
停機,系統進入這一級別後關機;
單用戶模式,在這個模式中只能從控制台操作計算機,網絡和終端不啟動,許多文件
系統也沒有連結;
多用戶模式,但關閉了網絡服務支持
完全的多用戶模式,就是我們一般使用的模式
無定義
圖形界面模式,系統切入這一運行級後自動啟動X Window系統
重新啟動
這些級別的定義是任意的,然而你最好不要修改它,尤其是level 0,1和6,因為許多
程序都使用init 0之類的方式實現對系統的控制,其他的Linux發行版本可能會更改2-5
的定義,你需要參考/etc/inittab才能判斷到底那個級別是什麼意思,不過一般來說0,
1和6總是上面的定義。
下面開始才是真正的內容,首先系統必須定義缺省的運行級別:
id:3:initdefault:
initdefault關鍵字決定了缺省的運行級別,在這裡是3,也就是在執行了公共的系統
啟動腳本之後,系統將會執行與級別3對應的那些行
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
這裡的sysinit關鍵字定義了公共的“系統初始化”腳本,在相應於運行級的地方是空
,表示適用於所有運行級別。注意它將在系統進入任何運行級別以前完成,一會我們再
研究這個腳本的內容。
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
這裡開出了六個運行級別的定義,運行級0就去執行命令/etc/rc.d/rc 0,運行級1是
/etc/rc.d/rc 1,.....諸如此類。wait關鍵字表示系統必須等待此命令執行完才能開始
下一步工作。
# Things to run in every runlevel.
ud::once:/sbin/update
這又是一個適用於所有級別的命令。update命令實際是去啟動updated守護進程,以便
定期刷新內存中的超級塊表。Once關鍵字說明這個項只被執行一次。
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
ctrlaltdel定義當熱啟動組合鍵被觸發時系統的行為,這裡定義所有的運行級別對它
的響應都是重新啟動(shutdown –r)
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down
"
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled
"
這兩行定義如何響應ups信息,如果系統掉電(powerfail),執行兩分鐘後關機的指令
;如果關機之前電源恢復,取消關機操作。
# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
2,3,4,5都是多用戶級別,為系統開出6個虛擬屏幕(就是用Alt+Fn即獲得虛擬屏幕)
,respawn關鍵字表示這個動作在每次進入相應運行級別時都會執行。
# Run xdm in runlevel 5
# xdm is now a separate service
x:5:respawn:/etc/X11/prefdm -nodaemon
對於級別5,啟動圖形界面。
歸納一下,系統在讀入inittab以後要做什麼?設置Ctrl+Alt+Del響應,設置好對UPS
的支持,然後應該執行/etc/rc.d/rc.sysinit,然後是/etc/rc.d/rc 3,最後是update
和啟動虛擬屏幕。顯然,系統的主要初始化命令應該在/etc/rc.d/rc.sysinit和/etc/r
c.d/rc 3中完成。
rc.d下的基本腳本
下面我們來研究啟動腳本,這裡的腳本來自redhat 6.1,因為這是個最為廣泛使用的
版本,其他的版本的特有問題將在下一節討論。
首先,系統將執行/etc/rc.d/rc.sysinit,這是個shell腳本,你可以用普通的文本編
輯工具對它進行處理,為了簡便,我們只研究其中較為重要的部分或者較為典型的段落
:
#!/bin/sh
#
# /etc/rc.d/rc.sysinit - run once at boot time
#
# Taken in part from Miquel van Smoorenburg's bcheckrc.
#
# Rerun ourselves through initlog
if [ -z "$IN_INITLOG" ]; then
[ -f /sbin/initlog ] && exec /sbin/initlog $INITLOG_ARGS -r /etc/rc.d/rc.
sysinit
fi
首先,確定系統中是否存在/sbin/initlog文件,如果存在,那麼需要記錄初始化信息
。
# Set the path
PATH=/bin:/sbin:/usr/bin:/usr/sbin
eXPort PATH
設置缺省路徑。
# Read in config data.
if [ -f /etc/sysconfig/network ]; then
. /etc/sysconfig/network
else
NETWORKING=no
HOSTNAME=localhost
fi
這一段是網絡的參數設置,/etc/sysconfig/network的內容是這樣:
NETWORKING=yes
FORWARD_IPV4="yes"
HOSTNAME="openlab.asnc.edu.cn"
GATEWAY=""
GATEWAYDEV=""
顯然,如果這個文件存在,那麼設置網絡的運行參數,如域名,網關等等,這個文件
中可以包含很多的東西。詳細的內容我們在設置網絡的部分介紹
# Source functions
. /etc/rc.d/init.d/functions
/etc/rc.d/init.d是所有的服務腳本存放的地方,而functions是各種服務腳本需要的
一些參數的設置。有興趣的話你可以看一看,不看也不影響什麼。
以下有一段是設置一些顯示信息,接下來是這樣的內容:
# Mount /proc (done here so volume labels can work with fsck)
action "Mounting proc filesystem" mount -n -t proc /proc /proc
連結/proc文件系統,應該記得/proc是用來顯示系統狀態的虛擬文件系統,注意acti
on命令的語法,它顯示一段提示信息,然後去執行相應的命令。
然後的段落有一點意思:
# Turn off sysrq
#if [ "$MAGIC_SYSRQ" = "no" ]; then
# echo "0" > /proc/sys/kernel/sysrq
#fi
$MAGIC_SYSRQ=no意味著你決定不使用內核調試,腳本必須把系統的內核調試功能關閉
,注意接下來的處理方法,在/proc/sys/kernel下建立一個名叫sysrq的文件,並且設置
其內容為"0",就關閉了這項功能,這也是在運行中打開或者關閉內核的某個功能的標准
方法,以後我們會經常看到這樣的例子。
接下來要設置時鐘和鍵盤映射表,裝入系統字體,又是一段冗長的代碼,這裡將它省
略,反正你總可以在自己的系統上看到他們。
# Start up swapping.
action "Activating swap partitions" swapon -a
swapon –a 將讀/etc/fstab文件,這個文件中包含有系統中存在的應該自動掛接的各
種文件系統的列表,同時也包含了關於交換分區的知識,swapon –a將啟動其中標注的
所有交換分區。
# Set the hostname.
action "Setting hostname ${HOSTNAME}" hostname ${HOSTNAME}
# Set the NIS domain name
if [ -n "$NISDOMAIN" ]; then
action "Setting NIS domain name $NISDOMAIN" domainname $NISDOMAIN
else
domainname ""
fi
這兩段設置系統名字,我們應該記得$HOSTNAME已經在/etc/sysconfig/network文件中
設置過,所以這裡的action被執行,而$NISDOMAIN現在是空字符串,所以執行後hostna
me被設置而NIS域名不存在。
if [ -f /fsckoptions ]; then
fsckoptions=`cat /fsckoptions`
else
fsckoptions=
fi
if [ -f /forcefsck ]; then
fsckoptions="-f $fsckoptions"
fi
這裡是與管理員相關的行了。如果系統的/下將存在/forcefsck文件,於是系統自動啟
動fsck程序去檢查文件系統是否有錯誤。接下來是一段關於是否存在/fastboot文件的判
斷,與其大同小異,然後系統將會決定是否啟用PNP,方法和處理MAGIC_SYSRQ是類似的
,這兩段我們不討論了,你可以自己看一下。
# Remount the root filesystem read-write.
action "Remounting root filesystem in read-write mode" mount -n -o remount
,rw /
# Add /proc to /etc/mtab
mount -f -t proc /proc /proc
檢測根文件系統完畢後,系統重新將/連結成讀寫方式,並且將/proc加入到/etc/mta
b中。下面是非常重要的一步,如果系統內核支持可裝載模塊,需要把$USEMODULES變量
設置成"y"並且設置模塊的缺省路徑,參數等等,然後,系統開始裝入模塊:
# load sound modules
if [ -n "$USEMODULES" ]; then
if grep -s -q "^alias sound " /etc/conf.modules ; then
action "Loading sound module" modprobe sound
fi
.........
fi
...........
當這些直接裝入的模塊結束後,為了和以前的方式兼容,也為了管理員的方便,這個
腳本試圖去尋找/etc/rc.d/rc.modules,如果存在就執行它:
# Load modules (for backward compatibility with VARs)
if [ -f /etc/rc.d/rc.modules ]; then
/etc/rc.d/rc.modules
fi
顯然,你可以將自己的模塊初始化命令加入/etc/rc.d/rc.modules使它在啟動時得到
運行。
完成主要模塊的裝入後,系統將開始一系列日常工作,如檢測有問題的文件系統,連
結所有本地文件系統,啟動磁盤限額等等,如果系統還沒有被配置,那麼將啟動配置腳
本,設置網絡,超級用戶口令等等,否則,對於已經配置好的系統,清理記賬文件,准
備進行系統工作。
當一切都完成之後,系統按照inittab的設定,進入運行級3,執行/etc/rc.d/rc 3。
/etc/rc.d/rc是一個很有意思的程序,它是一個shell腳本,其行為是這樣:根據提供
給它的參數,它去尋找相應的目錄rc${arg1}.d,例如,在/etc/rc.d/rc 3執行時,它去
查詢/etc/rc.d/rc3.d下的所有文件,試圖執行那些所有用S或K打頭的腳本,凡是用S開
頭的腳本,它給加上一個start參數,凡是用K打頭的腳本,加上一個stop參數。執行次
序是按照S或K後跟的數值順序。
例如,在現在的例子中,/etc/rc.d/rc 3下存在一個S50inet的腳本,於是 rc 腳本去
執行S50inet start。而S50inet其實是到/etc/rc.d/init.d/inet的一個符號連結,其內
容是(這裡只給出了部分內容):
. /etc/rc.d/init.d/functions
. /etc/sysconfig/network
if [ ${NETWORKING} = "no" ]
then
exit 0
fi
[ -f /usr/sbin/inetd ] exit 0
RETVAL=0
# See how we were called.
case "$1" in
start)
echo -n "Starting INET services: "
daemon inetd
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && toUCh /var/lock/subsys/inet
;;
stop)
echo -n "Stopping INET services: "
killproc inetd
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/inet
;;
*)
echo "Usage: inet {startstopstatusrestartreload}"
exit 1
esac
exit $REVAL
daemon和killproc是在/etc/rc.d/init.d/functions裡面定義的函數,daemon將命令
當成守護進程執行,killproc則殺掉對應進程。顯然,S50inet start的結果是inetd程
序被啟動為一個守護進程。
這裡的方法是啟動服務進程的標准模式,例如你要設置某個服務在runlevel 3被啟動
,那麼你可以自己寫一個腳本,比如說mydaemon,讓mydaemon start啟動服務,mydaem
on stop停止服務,然後將這個腳本復制到/etc/rc.d/init.d中,接著在/etc/rc.d/rc?
.d中建立連接,在rc3.d中連結為S65mydaemon,而在其他目錄中為K65mydaemon,這樣你
的腳本就會在進入和退出運行級3時自動處理了。
除此與run level相關的啟動指令之外,Linux還從BSD中引入了另外一些配置文件,其
中最重要的是/etc/rc.d/rc.local,通常它在執行了全部運行級腳本以後運行,你可以
在這裡定制自己的設置,如歡迎信息等等。
版本之間的區別
如同我們看到的那樣,Redhat的啟動腳本看上去井井有條,要尋找某個功能很容易,
但是要尋找某個命令在何處啟動就顯得比較困難,經常需要從/etc/inittab開始。
Turbo Linux和Red-Flag的腳本和Redhat頗為相似,尤其是紅旗幾乎就是RedHat的中文
版,它們的配置也相當近似。
Slackware的啟動腳本使用另外一種風格,實際上,看上去很象BSD系列。啟動腳本也
在/etc/rc.d下面,但是它把一些在大部分運行級別必須使用的腳本做在了一起,冠以r
c.modules,rc.inet1,rc.inet2等等的名字,這樣對於手工配置系統確實簡單的多,不
過這些文件都相當大,看起來需要耐心。對於這個系統,你只要看一遍/etc/inittab就
能掌握它的配置文件位置了。
Debian/Corel使用一種有趣的方式,看上去頗像Sun的Solaris。實際上,它和RedHat
的方式幾乎是一樣的,但是啟動腳本不是在/etc/rc.d,而是直接位於/etc下,例如/et
c/rc1.d,/etc/rc2.d等等,知道了這一點之後,配置debian就不會感到困難了。
關於Corel Linux我們應該特別地說一句,它的配置文件組織看起來要比RedHat簡單一
些,但是它沒有類似於rc.modules的設定,等價於rc.sysinit的文件是/etc/init.d/rc
S。它的運行級別定義也比較怪異,好像Run Level 2是正常的圖形模式,要配置Corel,
最好是從/etc/inittab直接開始。無論如何,我們不會建議一個新手使用corel Linux。