Linux操作系統中/sbin/init程序的執行過程

當init啓動後,它通過執行各種啓動事務來繼續引導進程(檢查並監視文件系統,啓動後臺程序daemons,等等),直至完成用戶所有操作環境的設置工作。這裏主要涉及4個程序:init、getty(agetty)、login和shell程序。這4個程序之間的關係見下圖所示。

init進程的主要任務是根據/etc/rc文件中設置的信息,執行其中設置的命令,然後根據/etc/inittab文件中的信息,爲每一個允許登錄的終端設備使用fork()創建一個子進程,並在每個新創建的子進程中運行agetty (getty)程序。而init進程則調用wait(),進入等待子進程結束狀態。每當它的一個子進程結束退出,它就會根據wait()返回的pid號知道是哪個對應終端的子進程結束了,因此就會爲相應終端設備再創建一個新的子進程,並在該子進程中重新執行agetty程序。這樣,每個被允許的終端設備都始終有一個對應的進程爲其等待處理。

在正常的操作下,init確定agetty正在工作着以允許用戶登錄,並且收取孤立進程。孤立進程是指那些其父輩進程已結束的進程;在Linux中所有的進程必須屬於單棵進程樹,所以孤立進程必須被收取。當系統關閉時,init負責殺死所有其它的進程,卸載所有的文件系統以及停止處理器的工作,以及任何它被配置成要做的工作。

getty程序的主要任務是設置終端類型、屬性、速度和線路規程。它打開並初始化一個tty端口,顯示提示信息,並等待用戶鍵入用戶名。該程序只能由超級用戶執行。通常,若/etc/issue文本文件存在,則getty會首先顯示其中的文本信息,然後顯示登錄提示信息(例如:plinux login: ),讀取用戶鍵入的登錄名,並執行login程序。

爲了能讓init程序運行getty,/etc/inittab文件中必須含有getty(agetty)命令。/etc/inittab文件中有關agetty的內容例子見如下所示。

列表 3.1 poeigl-1.2中的inittab文件

# inittab for linux, poeigl 1.2

# format:

# ttyline:termcap-entry:getty-command

tty1:con80x60:/bin/agetty 9600 tty1

tty2:con80x60:/bin/agetty 9600 tty2

tty3:con80x60:/bin/agetty 9600 tty3

tty4:con80x60:/bin/agetty 9600 tty4

# tty5:con80x60:/bin/agetty 9600 tty5

# tty64:dumb:/bin/agetty 9600 tty64

# tty65:dumb:/bin/agetty -m -t60 2400 tty65

每個終端都有自己的getty命令。其中列出了tty1—tty4對應的登錄項信息。以’#’開始的是註釋行。第1列是所用終端設備名稱,第2列是指定終端的類型,這裏指定了終端類型是con80x60。第3列是所執行的命令及其參數。最後兩行中的tty64和tty65對應連接在串行端口上的終端。

對於使用串行端口與主機直接相連的終端以及通過modem撥號連接的終端,Linux的agetty程序還有其它一些屬性。如在讀取登錄名時自動調整tty的設置信息,例如奇偶校驗位、檫除字符、行結束字符以及上檔鍵字符等。可選擇地從鏈接的Hayes兼容modem信息中檢測出傳輸波特率。

/dev/inittab中每一項的參數格式與具體使用哪一種getty程序有關。目前一般常用的getty程序有如下幾種:

1.agetty(有時直接稱爲getty):容易設置,無須配置文件。適用於直接連接的終端;

2.getty(getty_ps的一部分):適用於直接連接的終端;

3.mgetty:最適合於通過modem連接,也可用於直連;

4.uugetty:僅用於通過modem連接終端,是getty_ps軟件包的部分;

5.mingetty:簡單的getty。適用於控制檯終端或虛擬終端;

6.fbgetty:適用於控制檯或虛擬終端。

Redhat 9系統默認配置中帶有mingetty和agetty兩個程序。控制檯或虛擬終端使用的是mingetty。對於實際的字符終端則一般使用agetty。因此在Redhat 9系統的/etc/inittab文件中會看到以下的信息。

列表 3.2 RedHat 9系統的/etc/inittab文件中有關getty的信息

# 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

其中第1列表示名稱tty後的數字,2345表示該mingetty的運行層。respawn表示如果該mingetty被終止,則mingetty將再次自動執行。/sbin/mingetty是命令。ttyn代表/dev/ttyn(n表示數字1—5)。

在登錄到Linux系統中之後,你會發現(使用”top”或”ps –ax”命令)自己終端原來的getty進程已經找不到了。因爲getty進程執行了login程序,被替換成了login進程,並且最後被替換成你的登錄shell進程。

當你在”login: “提示符下鍵入了你的用戶名後,getty會讀取用戶名並且去執行login程序,也把用戶名信息傳給了它。因此getty進程被替換成了login進程。此時login進程會接着要求你輸入口令。在口令檢查通過後就會去執行/etc/passwd文件中對應你用戶名項中記錄的程序。通常這個程序是bash shell程序。因此原來的getty進程最終被替換成了bash進程,對應的這三個程序也就都具有相同的進程ID。

當註銷登錄(log out)時,則該終端上的所有進程都會被終止(killed),包括登錄shell進程bash。因此,對於在/etc/inittab文件中列出的getty程序,一旦其被替換執行的bash程序被終止或退出,init進程就會爲對應終端重新創建一個getty進程。

login程序則主要用於要求登錄用戶輸入密碼。根據用戶輸入的用戶名,它從口令文件passwd中取得對應用戶的登錄項,然後調用getpass()以顯示”password:”提示信息,讀取用戶鍵入的密碼,然後使用加密算法對鍵入的密碼進行加密處理,並與口令文件中該用戶項中pw_passwd字段作比較。如果用戶幾次鍵入的密碼均無效,則login程序會以出錯碼1退出執行,表示此次登錄過程失敗。此時父進程(進程init)的wait()會返回該退出進程的pid,因此會根據記錄下來的信息再次創建一個子進程,並在該子進程中針對該終端設備再次執行agetty程序,重複上述過程。

login程序也可以被用戶在運行過程中在shell下當作一個命令執行。此時它可以被用隨時從一個用戶切換成另一個用戶。如果執行時沒有給出參數,則login就會顯示輸入用戶名的提示信息。如果用戶不是超級用戶(root),並且/etc/目錄下存在一個名爲nologin的文件,那麼該文件中的信息就會被顯示出來,此次登錄過程也隨即被終止。

如果在/etc/usertty文件中對該用戶指定了特殊的訪問限制,那麼這些限制要求必須滿足。如果是一個超級用戶,那麼所使用的登錄tty設備必須是在/etc/securetty文件中指定的。

在所有這些條件滿足之後,login同樣也會要求用戶輸入密碼並對其進行檢查。如果.hushlogin存在的話,login就會執行一個“安靜”的登錄過程,也即不檢查是否有郵件,也不顯示上次登錄時間和motd文件中的信息。否則如果/var/log/lastlog文件存在的話,就會顯示其中的最後登錄時間。

如果用戶鍵入的密碼正確,則login就會把當前工作目錄(Currend Work Directory)修改成口令文件中指定的該用戶的起始工作目錄。並把對該終端設備的訪問權限修改成用戶讀/寫和組寫,設置進程的組ID。然後利用所得到的信息初始化環境變量信息,例如起始目錄(HOME=)、使用的shell程序(SHELL=)、用戶名(USER=和LOGNAME=)和系統執行程序的默認路徑序列(PATH=)。接着顯示/etc/motd文件(message-of-the-day)中的文本信息,並檢查並顯示該用戶是否有郵件的信息。最後login程序改變成登錄用戶的用戶ID並執行口令文件中該用戶項中指定的shell程序,如bash或csh等。

如果口令文件/etc/passwd中該用戶項中沒有指定使用哪個shell程序,系統則會使用默認的/bin/sh程序。如果口令文件中也沒有爲該用戶指定用戶起始目錄的話,系統就會使用默認的根目錄/。有關login程序的一些執行選項和特殊訪問限制的說明,請參見Linux系統中的在線手冊頁(man 8 login)。

Shell程序是一個複雜的命令行解釋程序,是當用戶登錄系統進行交互操作時執行的程序。它是用戶與計算機進行交互操作的地方。它獲取用戶輸入的信息,然後執行命令。用戶可以在終端上向shell直接進行交互輸入,也可以使用shell腳本文件向shell解釋程序輸入。在Linux系統中,目前常用的shell有:

Bourne Again Shell,/bin/bash

C shell,/bin/csh(或tcsh)

BSD shell/bin/ash(或bsh)

在登錄過程中,系統(login)會從口令文件用戶對應登錄項的最後一個字段知道應該爲用戶執行哪個shell程序。

shell程序中實現了一個具有流控制結構的語言,使用相當廣泛。目前這些shell程序都朝着與IEEE POSIX 1003.2兼容的方向發展,因此它們各自雖然各自有自己的特點,但基本功能已經越來越相象。本書主要介紹bash的工作原理和實現機制,其它幾種shell的實現機制與之類似。

在登錄過程中login開始執行shell時,所帶參數argv[0]的第一個字符是’-’,表示該shell是作爲一個登錄shell被執行。此時該shell程序會根據該字符,執行某些與登錄過程相應的操作。登錄shell會首先從/etc/profile文件以及.profile文件(若存在的話)讀取命令並執行。如果在進入shell時設置了ENV環境變量,或者在登錄shell的.profile文件中設置了該變量,則shell下一步會從該變量命名的文件中讀去命令並執行。因此用戶應該把每次登錄時都要執行的命令放在.profile文件中,而把每次運行shell都要執行的命令放在ENV變量指定的文件中。設置ENV環境變量的方法是把下列語句放在你起始目錄的.profile文件中。

ENV=$HOME/.anyfilename; export ENV

在執行shell時,除了一些指定的可選項以外,如果還指定了命令行參數,則shell會把第一個參數看作是一個腳本文件名並執行其中的命令,而其餘的參數則被看作是shell的位置參數($1、$2等)。否則shell程序將從其標準輸入中讀取命令。

在執行shell程序時可以有很多選項,請參見Linux系統中的有關sh的在線手冊頁中的說明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章