Mandrake9.0的啟動過程(從init開始)(二)
2024-07-21 02:35:19
供稿:網(wǎng)友
在內(nèi)核引導結(jié)束并啟動/sbin/init之后,系統(tǒng)就轉(zhuǎn)入用戶態(tài)的運行。在這之后創(chuàng)建的一切進程,都是在用戶態(tài)進行。 這里先要講清楚一個概念:就是init進程雖然是從內(nèi)核開始的,即在前面所講的init/main.c中的init()函數(shù)在啟動后就已經(jīng)是一個核心線程,但在轉(zhuǎn)到執(zhí)行/sbin/init之后,內(nèi)核中的init()就變成了/sbin/init程序,狀態(tài)也轉(zhuǎn)變成了用戶態(tài),也就是說核心線程變成了一個普通的進程。這樣一來,內(nèi)核中的init函數(shù)實際上只是init進程的入口,它在執(zhí)行execve("/sbin/init",argv_init,envp_init)時改變成為一個普通的用戶進程。這就是exec系列函數(shù)替換進程映像的變身大法,只要你學過unix環(huán)境下的多進程編程,應該都能理解這一點。
除此之外,它們的代碼來源也有差別,內(nèi)核中的init()函數(shù)的源代碼在/init/main.c中,是內(nèi)核的一部分。而/sbin/init程序的源代碼是sysvinit軟件包的一部分,可以從FTP://ftp.cistron.nl/pub/people/miq...程序,如:halt, init, killall5, last, lastb (鏈接至 last), mesg, pidof (鏈接至 killall5), poweroff (鏈接至 halt), reboot (鏈接至 halt), runlevel, shutdown, sulogin, telinit (鏈接至 init), utmpdump 和 wall等等。對于啟動過程而言,這里最重要的就是init程序。它啟動之后,要完成很多任務:檢查文件系統(tǒng),啟動各種后臺服務進程,最后為每個終端和虛擬控制臺啟動一個getty進程供用戶登錄。由于所有其它用戶進程都是由init派生的,因此它又是其它一切用戶進程的父進程。
init進程啟動后,就要按照/etc/inittab的內(nèi)容進程系統(tǒng)設置。下面就是manfrake9.0的inittab內(nèi)容:
#
# inittab This file describes how the INIT PRocess should set up
# the system in a certain run-level.
#
# Author: Miquel van Smoorenburg,
# Modified for RHS linux by Marc Ewing and Donnie Barnes
#
# Default runlevel. The runlevels used by Mandrake Linux 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)
#
id:5:initdefault:
# System initialization.
si::sysinit:/etc/rc.d/rc.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
# Things to run in every runlevel.
ud:nce:/sbin/update
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly.
pf:owerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345owerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
# 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
從中可以看到,inittab的每一行由四個字段組成。
分別是:
id:runlevels:actionrocess
id:是每一行的標識符,長度一般為2個字符而且在整個inittab中必須唯一。對于getty或其他login程序項,要求id與tty的編號相同,否則getty程序?qū)⒉荒苷9ぷ鳌?br /> runlevels:指定運行級別,一般使用0-6以及S或s。運行級別是指init進程的整個系統(tǒng)的一個運行狀態(tài),它定義了系統(tǒng)所提供的服務,常見的運行級別如下:0,系統(tǒng)終止;1,單用戶模式;3沒有網(wǎng)絡文件系統(tǒng)支持的多用戶模式;4,保留;5,啟動到Xwindow;6,重新啟動,S和s意義相同,表示單用戶模式且無需inittab文件,因此也不必在inittab中出現(xiàn),實際上,進入單用戶模式時,init直接在控制臺(/dev/console)上運行/sbin/sulogin。實際上,7-9的運行級別也是可以使用的,只是傳統(tǒng)的Unix系統(tǒng)沒有定義這幾個級別。級別可以是并列的多個值,以匹配多個運行級別,對大多數(shù)action來說,僅當runlevel與當前運行級別匹配成功才會執(zhí)行。。
action:指出的是init程序執(zhí)行process命令的方式。initdefault是一個非凡的action值,用于標識缺省的運行級別。當init進程由核心啟動后,它將讀取inittab中的initdefault項,取得其中的運行級別,并作為當前的運行級別。假如沒有inittab文件,或者其中沒有initdefault項,init將在控制臺上請求輸入運行級別。respawn 在進入相應runlevel時執(zhí)行,假如該進程結(jié)束,init會再起一個進程執(zhí)行同樣的命令。once在進入有runlevels指定的運行級別時運行并且只執(zhí)行一次。wait的執(zhí)行效果和once一樣,但init會等待該命令結(jié)束。ctrlaltdel指定在用戶按下Ctrl-Alt-Del時執(zhí)行的命令。powerfail 在系統(tǒng)接收到掉電信號時啟動相關(guān)進程。powerwait 和powerfail一樣,在系統(tǒng)接收到掉電信號時啟動相關(guān)進程,并等待進程終止,在進程終止前不做任何其它操作。off 若該項相關(guān)進程已經(jīng)存在則強行終止,否則忽略。sysinit、boot、bootwait等action將在系統(tǒng)啟動時無條件運行,而忽略其中的運行級別,其中sysinit 指定需要運行的第一個程序(或腳本),boot將在sysinit之后執(zhí)行,bootwait的執(zhí)行效果和boot一樣,但init會等待該命令結(jié)束,其余的action(不含initdefault)都與某個運行級別相關(guān),可以在inittab的man手冊中找到各個action的定義的具體描述。
process:給出每行要執(zhí)行的命令。
知道inittab的字段意義以后,我們來看一下inittab的結(jié)構(gòu)。inittab的第一行是設定系統(tǒng)的運行級別,如下所示:
id:5:initdefault:
從以上的介紹中可以知道,系統(tǒng)的運行級別是5,也就是系統(tǒng)啟動時自動進入xwindow。接著進行系統(tǒng)初始化:
si::sysinit:/etc/rc.d/rc.sysinit
這樣init進程就會執(zhí)行/etc/rc.d/rc.sysinit。這個腳本最常見的動作就是激活交換分區(qū),檢查磁盤,加載硬件模塊,這些動作無論哪個運行級別都是需要優(yōu)先執(zhí)行的。只有在rc.sysinit執(zhí)行完以后init進程才會執(zhí)行其他的boot或bootwait動作。假如沒有boot或bootwait動作,init進程就接著執(zhí)行下面的內(nèi)容:
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
這里,系統(tǒng)將會根據(jù)運行級別選擇要執(zhí)行的命令。從前面我們已經(jīng)知道系統(tǒng)的運行級別是5,所以實際上只有這一行被執(zhí)行了:
l5:5:wait:/etc/rc.d/rc 5
這一行的最后是以參數(shù)5運行/etc/rc.d/rc,實際上就是運行/etc/rc.d/rc3.d下的所有程序(或腳本)。用ls命令查看/etc/rc.d/rc3.d目錄,如下:
[kj501@c4 kj501]$ ls /etc/rc.d/rc3.d/
K09dm@ S16ypserv@ S56rawdevices@ S90crond@
K55routed@ S17alsa@ S56xinetd@ S90postgresql@
K90MySQL@ S18sound@ S60cups@ S91smb@
S01usb@ S20random@ S60nfs@ S92lisa@
S03iptables@ S20xfs@ S60rwhod@ S95innd@
S05harddrake@ S25netfs@ S66yppasswdd@ S95kheader@
S10network@ S26apmd@ S75keytable@ S99devfsd@
S11portmap@ S26ypxfrd@ S80postfix@ S99hamboot@
S12syslog@ S40atd@ S85httpd@ S99linuxconf@
S13partmon@ S40saslauthd@ S85numlock@ S99local@
S14nfslock@ S55named@ S85proftpd@
S15gpm@ S55sshd@ S89internet@
這些文件都是一些系統(tǒng)服務程序,以“S”打頭的文件用來在進入運行級別5時啟動服務進程,以“K”打頭的文件用來在系統(tǒng)關(guān)閉,離開運行級別5之前終止服務進程。后面的數(shù)字大小決定執(zhí)行的先后次序,對于以”K“打頭的服務進程,按照從高到低的順序執(zhí)行,對于以”S“打頭的服務進程,按照從低到高的順序執(zhí)行。
假如用ls -l 查看這些文件,就會發(fā)現(xiàn)它們大部分都是到/etc/rc.d/init.d目錄下各個shell腳本的符號鏈接,而且這些腳本一般能接受start、stop、restart、status等參數(shù),在啟動時以start參數(shù)啟動以“S”打頭的腳本鏈接,假如存在一個同樣的腳本鏈接但是以”K“打頭,也會先執(zhí)行以”K“打頭的腳本鏈接,然后再執(zhí)行以”S“打頭的腳本鏈接,以保證這個服務進程是重新啟動的。要注重在這些腳本的最后,都有一個S99local@的鏈接,這個鏈接是鏈接到/etc/rc.d/rc.local,而不是象其它腳本鏈接一樣鏈接到/etc/rc.d/init.d下。可以在這個rc.local加入一些每個運行級別都要執(zhí)行但又必須在系統(tǒng)服務進程啟動后才能執(zhí)行的命令,比如說對一些系統(tǒng)服務程序的參數(shù)設置。執(zhí)行這些腳本之后,下面就要執(zhí)行一個在每個運行級別都要執(zhí)行的命令:
ud:nce:/sbin/update
這句話表明每一個運行級別都要運行命令update,此程序每隔30秒把內(nèi)存緩沖區(qū)的內(nèi)容回寫一次,稱為"同步",以防止系統(tǒng)崩潰或忽然掉電造成的數(shù)據(jù)丟失和損壞。在這