淺析 Linux 初始化 init 系統(1):sysvinit

發表於2015-03-16

從 sysvinit 到 systemd

近年來,Linux 系統的 init 程式經歷了兩次重大的演進,傳統的 sysvinit 已經淡出歷史舞臺,新的 init 系統 UpStart 和 systemd 各有特點,而越來越多的 Linux 發行版採納了 systemd。本文簡要介紹了這三種 init 系統的使用和原理,每個 Linux 系統管理員和系統軟體開發者都應該瞭解它們,以便更好地管理系統和開發應用。本文是系列的第一部分,主要講述 sysvinit 的特點和使用。

什麼是 Init 系統,init 系統的歷史和現狀

Linux 作業系統的啟動首先從 BIOS 開始,接下來進入 boot loader,由 bootloader 載入核心,進行核心初始化。核心初始化的最後一步就是啟動 pid 為 1 的 init 程式。這個程式是系統的第一個程式。它負責產生其他所有使用者程式。

init 以守護程式方式存在,是所有其他程式的祖先。init 程式非常獨特,能夠完成其他程式無法完成的任務。

Init 系統能夠定義、管理和控制 init 程式的行為。它負責組織和執行許多獨立的或相關的始化工作(因此被稱為 init 系統),從而讓計算機系統進入某種使用者預訂的執行模式。

僅僅將核心執行起來是毫無實際用途的,必須由 init 系統將系統代入可操作狀態。比如啟動外殼 shell 後,便有了人機互動,這樣就可以讓計算機執行一些預訂程式完成有實際意義的任務。或者啟動 X 圖形系統以便提供更佳的人機介面,更加高效的完成任務。這裡,字元介面的 shell 或者 X 系統都是一種預設的執行模式。

大多數 Linux 發行版的 init 系統是和 System V 相相容的,被稱為 sysvinit。這是人們最熟悉的 init 系統。一些發行版如 Slackware 採用的是 BSD 風格 Init 系統,這種風格使用較少,本文不再涉及。其他的發行版如 Gentoo 是自己定製的。Ubuntu 和 RHEL 採用 upstart 替代了傳統的 sysvinit。而 Fedora 從版本 15 開始使用了一個被稱為 systemd 的新 init 系統。

可以看到不同的發行版採用了不同的 init 實現,本系列文章就是打算講述三個主要的 Init 系統:sysvinit,UpStart 和 systemd。瞭解它們各自的設計特點,並簡要介紹它們的使用。

在 Linux 主要應用於伺服器和 PC 機的時代,SysVinit 執行非常良好,概念簡單清晰。它主要依賴於 Shell 指令碼,這就決定了它的最大弱點:啟動太慢。在很少重新啟動的 Server 上,這個缺點並不重要。而當 Linux 被應用到移動終端裝置的時候,啟動慢就成了一個大問題。為了更快地啟動,人們開始改進 sysvinit,先後出現了 upstart 和 systemd 這兩個主要的新一代 init 系統。Upstart 已經開發了 8 年多,在不少系統中已經替換 sysvinit。Systemd 出現較晚,但發展更快,大有取代 upstart 的趨勢。

本文的第一部分先簡要介紹 sysvinit。

Sysvinit 概況

sysvinit 就是 system V 風格的 init 系統,顧名思義,它源於 System V 系列 UNIX。它提供了比 BSD 風格 init 系統更高的靈活性。是已經風行了幾十年的 UNIX init 系統,一直被各類 Linux 發行版所採用。

執行級別

Sysvinit 用術語 runlevel 來定義”預訂的執行模式”。Sysvinit 檢查 ‘/etc/inittab’ 檔案中是否含有 ‘initdefault’ 項。 這告訴 init 系統是否有一個預設執行模式。如果沒有預設的執行模式,那麼使用者將進入系統控制檯,手動決定進入何種執行模式。

sysvinit 中執行模式描述了系統各種預訂的執行模式。通常會有 8 種執行模式,即執行模式 0 到 6 和 S 或者 s。

每種 Linux 發行版對執行模式的定義都不太一樣。但 0,1,6 卻得到了大家的一致贊同:

  • 0 關機
  • 1 單使用者模式
  • 6 重啟

通常在 /etc/inittab 檔案中定義了各種執行模式的工作範圍。比如 RedHat 定義了 runlevel 3 和 5。執行模式 3 將系統初始化為字元介面的 shell 模式;執行模式 5 將系統初始化為 GUI 模式。無論是命令列介面還是 GUI,執行模式 3 和 5 相對於其他執行模式而言都是完整的正式的執行狀態,計算機可以完成使用者需要的任務。而模式 1,S 等往往用於系統故障之後的排錯和恢復。

很顯然,這些不同的執行模式下系統需要初始化執行的程式和需要進行的初始化準備都是不同的。比如執行模式 3 不需要啟動 X 系統。使用者只需要指定需要進入哪種模式,sysvinit 將負責執行所有該模式所必須的初始化工作。

sysvinit 執行順序

Sysvinit 巧妙地用指令碼,檔案命名規則和軟連結來實現不同的 runlevel。首先,sysvinit 需要讀取/etc/inittab 檔案。分析這個檔案的內容,它獲得以下一些配置資訊:

  • 系統需要進入的 runlevel
  • 捕獲組合鍵的定義
  • 定義電源 fail/restore 指令碼
  • 啟動 getty 和虛擬控制檯

得到配置資訊後,sysvinit 順序地執行以下這些步驟,從而將系統初始化為預訂的 runlevel X。

  • /etc/rc.d/rc.sysinit
  • /etc/rc.d/rc 和/etc/rc.d/rcX.d/ (X 代表執行級別 0-6)
  • /etc/rc.d/rc.local
  • X Display Manager(如果需要的話)

首先,執行 rc.sysinit 以便執行一些重要的系統初始化任務。在 RedHat 公司的 RHEL5 中(RHEL6 已經使用 upstart 了),rc.sysinit 主要完成以下這些工作。

  • 啟用 udev 和 selinux
  • 設定定義在/etc/sysctl.conf 中的核心引數
  • 設定系統時鐘
  • 載入 keymaps
  • 使能交換分割槽
  • 設定主機名(hostname)
  • 根分割槽檢查和 remount
  • 啟用 RAID 和 LVM 裝置
  • 開啟磁碟配額
  • 檢查並掛載所有檔案系統
  • 清除過期的 locks 和 PID 檔案

完成了以上這些工作之後,sysvinit 開始執行/etc/rc.d/rc 指令碼。根據不同的 runlevel,rc 指令碼將開啟對應該 runlevel 的 rcX.d 目錄(X 就是 runlevel),找到並執行存放在該目錄下的所有啟動指令碼。每個 runlevel X 都有一個這樣的目錄,目錄名為/etc/rc.d/rcX.d。

在這些目錄下存放著很多不同的指令碼。檔名以 S 開頭的指令碼就是啟動時應該執行的指令碼,S 後面跟的數字定義了這些指令碼的執行順序。在/etc/rc.d/rcX.d 目錄下的指令碼其實都是一些軟連結檔案,真實的指令碼檔案存放在/etc/init.d 目錄下。如下所示:

清單 1.rc5.d 目錄下的指令碼

當所有的初始化指令碼執行完畢。Sysvinit 執行/etc/rc.d/rc.local 指令碼。

rc.local 是 Linux 留給使用者進行個性化設定的地方。您可以把自己私人想設定和啟動的東西放到這裡,一臺 Linux Server 的使用者一般不止一個,所以才有這樣的考慮。

Sysvinit 和系統關閉

Sysvinit 不僅需要負責初始化系統,還需要負責關閉系統。在系統關閉時,為了保證資料的一致性,需要小心地按順序進行結束和清理工作。

比如應該先停止對檔案系統有讀寫操作的服務,然後再 umount 檔案系統。否則資料就會丟失。

這種順序的控制這也是依靠/etc/rc.d/rcX.d/目錄下所有指令碼的命名規則來控制的,在該目錄下所有以 K 開頭的指令碼都將在關閉系統時呼叫,字母 K 之後的數字定義了它們的執行順序。

這些指令碼負責安全地停止服務或者其他的關閉工作。

Sysvinit 的管理和控制功能

此外,在系統啟動之後,管理員還需要對已經啟動的程式進行管理和控制。原始的 sysvinit 軟體包包含了一系列的控制啟動,執行和關閉所有其他程式的工具。

halt

停止系統。

init

這個就是 sysvinit 本身的 init 程式實體,以 pid1 身份執行,是所有使用者程式的父程式。最主要的作用是在啟動過程中使用/etc/inittab 檔案建立程式。

killall5

就是 SystemV 的 killall 命令。向除自己的會話(session)程式之外的其它程式發出訊號,所以不能殺死當前使用的 shell。

last

回溯/var/log/wtmp 檔案(或者-f 選項指定的檔案),顯示自從這個檔案建立以來,所有使用者的登入情況。

lastb

作用和 last 差不多,預設情況下使用/var/log/btmp 檔案,顯示所有失敗登入企圖。

mesg

控制其它使用者對使用者終端的訪問。

pidof

找出程式的程式識別號(pid),輸出到標準輸出裝置。

poweroff

等於 shutdown -h –p,或者 telinit 0。關閉系統並切斷電源。

reboot

等於 shutdown –r 或者 telinit 6。重啟系統。

runlevel

讀取系統的登入記錄檔案(一般是/var/run/utmp)把以前和當前的系統執行級輸出到標準輸出裝置。

shutdown

以一種安全的方式終止系統,所有正在登入的使用者都會收到系統將要終止通知,並且不準新的登入。

sulogin

當系統進入單使用者模式時,被 init 呼叫。當接收到啟動載入程式傳遞的-b 選項時,init 也會呼叫 sulogin。

telinit

實際是 init 的一個連線,用來向 init 傳送單字元引數和訊號。

utmpdump

以一種使用者友好的格式向標準輸出裝置顯示/var/run/utmp 檔案的內容。

wall

向所有有資訊許可權的登入使用者傳送訊息。

不同的 Linux 發行版在這些 sysvinit 的基本工具基礎上又開發了一些輔助工具用來簡化 init 系統的管理工作。比如 RedHat 的 RHEL 在 sysvinit 的基礎上開發了 initscripts 軟體包,包含了大量的啟動指令碼 (如 rc.sysinit) ,還提供了 service,chkconfig 等命令列工具,甚至一套圖形化介面來管理 init 系統。其他的 Linux 發行版也有各自的 initscript 或其他名字的 init 軟體包來簡化 sysvinit 的管理。

只要您理解了 sysvinit 的機制,在一個最簡的僅有 sysvinit 的系統下,您也可以直接呼叫指令碼啟動和停止服務,手動建立 inittab 和建立軟連線來完成這些任務。因此理解 sysvinit 的基本原理和命令是最重要的。您甚至也可以開發自己的一套管理工具。

Sysvinit 的小結

Sysvinit 的優點是概念簡單。Service 開發人員只需要編寫啟動和停止指令碼,概念非常清楚;將 service 新增/刪除到某個 runlevel 時,只需要執行一些建立/刪除軟連線檔案的基本操作;這些都不需要學習額外的知識或特殊的定義語法(UpStart 和 Systemd 都需要使用者學習新的定義系統初始化行為的語言)。

其次,sysvinit 的另一個重要優點是確定的執行順序:指令碼嚴格按照啟動數字的大小順序執行,一個執行完畢再執行下一個,這非常有益於錯誤排查。UpStart 和 systemd 支援併發啟動,導致沒有人可以確定地瞭解具體的啟動順序,排錯不易。

但是序列地執行指令碼導致 sysvinit 執行效率較慢,在新的 IT 環境下,啟動快慢成為一個重要問題。此外動態裝置載入等 Linux 新特性也暴露出 sysvinit 設計的一些問題。針對這些問題,人們開始想辦法改進 sysvinit,以便加快啟動時間,並解決 sysvinit 自身的設計問題。

Upstart 是第一個被廣泛應用的新一代 init 系統。我們在接下來的第二部分介紹 UpStart。

相關文章