進程介紹
對於Linux系統的運行來說,init程式是最基本的程式之一。但你仍可以大部分的忽略它。一個好的Linux發行版本通常隨帶有一個init的配置,這個配置適合於絕大多數系統的工作,在這樣一些系統上不需要對init做任何事。通常,只有你在碰到諸如串列終端掛住了、撥入(不是撥出)
數據機、或者你希望改變預設的運行級別時你才需要關心init。
當
核心啟動了自己之後(已被裝入記憶體、已經開始運行、已經初始化了所有的設備驅動程式和數據結構等等),通過啟動用戶級程式init來完成引導進程的核心部分。因此,init總是第一個進程(它的進程號總是1)。
核心在幾個位置上來查尋init,這幾個位置以前常用來放置init,但是init的最適當的位置(在Linux系統上)是/sbin/init。如果核心沒有找到init,它就會試著運行/bin/sh,如果還是失敗了,那么系統的啟動就宣告失敗了。
當init開始運行,它通過執行一些管理任務來結束引導進程,例如檢查檔案系統、清理/tmp、啟動各種服務以及為每個終端和
虛擬控制台啟動getty,在這些地方用戶將登錄系統。
在系統完全起來之後,init為每個用戶已退出的終端重啟getty(這樣下一個用戶就可以登錄)。init同樣也收集孤立的進程:當一個進程啟動了一個子進程並且在子進程之前終止了,這個子進程立刻成為init的子進程。對於各種技術方面的原因來說這是很重要的,知道這些也是有好處的,因為這便於理解進程列表和
進程樹圖。init的變種很少。絕大多數Linux發行版本使用sysinit(由Miguel van Smoorenburg著),它是基於System V的init設計。UNIX的BSD版本有一個不同的init。最主要的不同在於運行級別:System V有而BSD沒有(至少是傳統上說)。這種區別並不是主要的。在此我們僅討論sysvinit。 配置init以啟動getty:/etc/inittab檔案
當init啟動後,init讀取/etc/inittab配置檔案。當系統正在運行時,如果發出HUP信號,init會重讀它;這個特性就使得對init的配置檔案作過的更改不需要再重新啟動系統就能起作用了。 /etc/inittab檔案有點複雜。我們將從配置getty行的簡單情況說起。
etc/inittab中的行由四個冒號限定的域組成:
id:runlevels:action:process
下面對各個域進行了描述。另外,/etc/inittab可以包含空行以及以數字元號(’#’)開始的行;這些行均被忽略。
id 這確定檔案中的一行。對於getty行來說,指定了它在其上運行的終端(設備檔案名稱/dev/tty後面的字元)。對於別的行來說,是沒有意義的(除了有長度的限制),但它必須是唯一的。
runlevels 該行應考慮的運行級別。運行級別以單個數字給出,沒有
分隔設定。
action 對於該行應採取的動作,也即,respawn再次運行下一個域中的命令,當它存在時,或者僅運行一次。
運行的命令
為了在第一個
虛擬終端上(/dev/tty1)運行getty、在所有的正規多用戶運行級別中(2-5),應該寫入下面這行:
1:2345:respawn:/sbin/getty 9600 tty1
第一個域指出這是對應於/dev/tty1的行。第二個域說明它套用於運行級別2,3,4和5。第三個域是說在命令退出之後,應被再次執行(因此,用戶可以登錄、退出並且再次登錄)。最後一個域是在第一個虛擬終端上運行getty的命令。
如果你需要給系統增加終端或者撥入
數據機線路,你應該給/etc/inittab增加更多的行,每一行對應一個終端或一條撥入線。詳細信息,參見init、inittab以及getty的manual page。如果一個命令運行時失敗了,並且init配置成重運行它,它會使用許多的系統資源:init運行它、它失敗了、init再運行它、再次失敗等等,沒完沒了。為了避免這樣,init將追蹤一個命令重運行了多少次,並且如果重運行的頻率太高,它將被延時五分鐘後再運行。
一個運行級別(run level)是init以及整個系統的狀態,它定義了能夠提供什麼
系統服務。運行級別用數字來定義,見表7-1。對於如何使用用戶定義運行級別(2到5)沒有一致的意見。有些
系統管理員使用運行級別來定義哪個子系統工作,也即,X是否能運行、網路是否能工作等等。其他人總是讓所有子系統工作著或者單獨地運行以及停止它們,而不改變它們的運行級別,因為運行級別對於控制他們的系統來說顯得太粗率了。你必須自己決定,但是按照你的Linux發行版本的做法來做也許是最容易的了。
在Linux中初始化腳本在/etc/inittab 檔案(或稱初始化表)中可以找到關於不同運行級別的描述。其描述如下:
# 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(/etc/X11/prefdm )
# 6 - reboot (Do NOT set initdefault to this)
運行級別數
0 終止系統
1 單用戶模式(用於特別管理)
2-5 正常操作(用戶定義)
6 重啟動
運行級別通過如下行所示的行在/etc/inittab中配置:
l2:2:wait:/etc/init.d/rc 2
第一個域是任意給的符號,第二個域指出是運行級別2。第三個域說明當進入該運行級別時,init應該運行第四個域中的命令一次,並且init應該等待它的結束。在進入運行級別2時,在需要時/etc/init.d/rc命令運行或者停止服務。第四個域中的命令做所有設定一個運行級別的艱巨工作。它啟動還沒有運行的服務,並且停止在新的運行級別中不應再運行的服務。確切的命令是什麼以及運行級別是如何配置的,依賴於各個Linux發行版本。當init開始運行時,它在/etc/inittab中查尋一行,該行指定了預設的運行級別:
id:2
:initdefault
通過給
核心一個single或emergency
命令行參數,你可以在init運行開始時轉到一個非預設的運行級別上。例如,核心命令行參數可以通過LILO給出。這使得你可以選擇單用戶模式(運行級別 1)。當系統正在運行時,telinit命令可以改變運行級別。當運行級別改變時,init就運行/etc/inittab中相應的命令。
/etc/inittab中的特殊配置
/etc/inittab有些特殊的特性,它允許init對特別的環境作出回響。這些與眾不同的特性在第三個域中由
關鍵字標出。一些例子如下:
powerwait 當系統電源失敗時,允許init關閉系統。這裡假設使用了UPS以及用於監視UPS和通知init電源失敗的軟體。
ctrlaltdel 當用戶在控制台上按了ctrl-alt-del組合鍵時,允許init重新(啟動)引導系統。注意,
系統管理員能夠配置對ctrl-alt-del組合鍵的回響為其它的什麼,例如,忽略它,如果系統是在一個公共的環境中(或者開始nethack。)
sysinit 當系統引導時要執行的命令。例如,這個命令通常是清理/tmp。
上面所列並不是全部。對於所有的
關鍵字以及如何使用它們請參見inittab的manual page。
單用戶模式
一個很重要的運行級別是單用戶模式(single user mode)(運行級別1),在這個模式中只有
系統管理員在使用機器並且只有很少的
系統服務在運行,如登錄服務。對於一些管理任務來說單用戶模式是必須的,如在/usr分區上運行fsck,因為這需要該分區沒被載入,除非幾乎所有的系統服務都被終止了,否則不可能會有這種情況。通過telinit請求運行級別1,一個運行著的系統可以轉換到單用戶模式。在啟動時,可以通過在
核心的命令行上給出single或emergency來進入單用戶模式:核心同樣也將命令行給init,init會理解那個單詞並且不會使用預設的運行級別。(核心命令行輸入的方法依賴於系統是如何引導的。)在載入檔案系統之前,引導進入單用戶模式有時是需要的,這樣就可以手工運行fsck命令了,否則的話很可能損壞/usr分區(在一個有問題的檔案系統上的任何操作會更進一步地損壞它,所以fsck要儘早地運行)。如果啟動時fsck的自動檢查失敗了,啟動描述檔案init就會自動地進入單用戶模式。這是試圖避免系統使用一個檔案系統,這個檔案系統損壞的太嚴重以至於fsck都不能夠自動地修復它。這樣的毀壞情況是相當少的,通常是硬碟有問題或是在試驗一個
核心版本,但是有準備總比沒有好。作為一個安全措施,一個正確配置的系統應該在運行單用戶模式的shell之前要求口令。否則的話,只要給LILO輸入適當的一行參數就很容易地以
root身份進入系統。(當然,如果由於檔案系統的問題而使/etc/passwd毀壞時,就不是這樣了。如果是這樣的話,你手頭最好有張引導
軟碟。)