(学习总结)鸟哥基础篇第三版:第二十章

来源:互联网 发布:大数据用什么软件 编辑:程序博客网 时间:2024/06/01 13:52

第二十章、開機流程、模組管理與 Loader

20.1 Linux 的開機流程分析

20.1.1 開機流程一覽

·        載入 BIOS 的硬體資訊與進行自我測試,並依據設定取得第一個可開機的裝置;

·        讀取並執行第一個開機裝置內 MBR 的 boot Loader(亦即是 grub, spfdisk 等程式);

·        依據 boot loader 的設定載入 Kernel ,Kernel 會開始偵測硬體與載入驅動程式;

·        在硬體驅動成功後,Kernel 會主動呼叫 init 程式,而 init 會取得 run-level 資訊;

·        init執行 /etc/rc.d/rc.sysinit 檔案來準備軟體執行的作業環境(如網路、時區等);

·        init執行 run-level 的各個服務之啟動(script 方式);

·        init執行 /etc/rc.d/rc.local 檔案;

·        init執行終端機模擬程式 mingetty 來啟動 login 程式,最後就等待使用者登入啦;

20.1.2 BIOS, boot loader 與 kernel 載入

1.        BIOS, 開機自我測試與 MBR

我們在第零章的計算機概論就曾談過電腦主機架構, 在個人電腦架構下,你想要啟動整部系統首先就得要讓系統去載入 BIOS (Basic Input Output System),並透過 BIOS 程式去載入 CMOS 的資訊,並且藉由 CMOS內的設定值取得主機的各項硬體設定,例如 CPU 與周邊設備的溝通時脈啊、開機裝置的搜尋順序啊、硬碟的大小與類型啊、系統時間啊、各周邊匯流排的是否啟動 Plug and Play (PnP, 隨插即用裝置) 啊、各周邊設備的 I/O 位址啊、以及與 CPU 溝通的 IRQ 岔斷等等的資訊。

在取得這些資訊後,BIOS 還會進行開機自我測試 (Power-on Self Test, POST)。然後開始執行硬體偵測的初始化,並設定 PnP 裝置,之後再定義出可開機的裝置順序,接下來就會開始進行開機裝置的資料讀取了 (MBR 相關的任務開始)。

2.        載入核心偵測硬體與 initrd 的功能

當我們藉由 boot loader 的管理而開始讀取核心檔案後,接下來, Linux 就會將核心解壓縮到主記憶體當中,並且利用核心的功能,開始測試與驅動各個周邊裝置,包括儲存裝置、CPU、網路卡、音效卡等等。此時 Linux 核心會以自己的功能重新偵測一次硬體,而不一定會使用 BIOS 偵測到的硬體資訊喔!也就是說,核心此時才開始接管 BIOS 後的工作了。

[root@www ~]# ls --format=single-column -F /boot

config-2.6.18-92.el5      <==此版本核心被編譯時選擇的功能與模組設定檔

grub/                     <==就是開機管理程式 grub 相關資料目錄

initrd-2.6.18-92.el5.img  <==虛擬檔案系統檔!

System.map-2.6.18-92.el5  <==核心功能放置到記憶體位址的對應表

vmlinuz-2.6.18-92.el5     <==就是核心檔案啦!最重要者!

 

現在來思考一種情況,假設你的 linux 是安裝在 SATA 磁碟上面的,你可以透過 BIOS 的 INT 13 取得 boot loader 與 kernel 檔案來開機,然後 kernel 會開始接管系統並且偵測硬體及嘗試掛載根目錄來取得額外的驅動程式。問題是,核心根本不認識 SATA 磁碟,所以需要載入 SATA 磁碟的驅動程式,否則根本就無法掛載根目錄。但是 SATA 的驅動程式在 /lib/modules 內,你根本無法掛載根目錄又怎麼讀取到 /lib/modules/ 內的驅動程式?我們可以透過虛擬檔案系統來處理這個問題。

虛擬檔案系統 (Initial RAM Disk) 一般使用的檔名為 /boot/initrd ,這個檔案的特色是,他也能夠透過 boot loader 來載入到記憶體中,然後這個檔案會被解壓縮並且在記憶體當中模擬成一個根目錄,且此模擬在記憶體當中的檔案系統能夠提供一支可執行的程式,透過該程式來載入開機過程中所最需要的核心模組,通常這些模組就是 USB, RAID, LVM, SCSI 等檔案系統與磁碟介面的驅動程式啦!等載入完成後,會幫助核心重新呼叫 /sbin/init 來開始後續的正常開機流程。


圖 1.2.3、 BIOS 與 boot loader 及核心載入流程示意圖

20.1.3 第一支程式 init 及設定檔/etc/inittab 與runlevel

1.        Run level:執行等級有哪些?

基本上,依據有無網路與有無 X Window 而將 run level 分為 7 個等級,分別是:

0 - halt (系統直接關機)

1 - single user mode (單人維護模式,用在系統出問題時的維護)

2 - Multi-user, without NFS (類似底下的runlevel 3,但無 NFS 服務)

3 - Full multi-user mode (完整含有網路功能的純文字模式)

4 - unused (系統保留功能)

5 - X11 (與 runlevel 3 類似,但加載使用 XWindow)

6 - reboot (重新開機)

 

2.        /etc/inittab 的內容與語法

[root@www ~]# vim /etc/inittab

id:5:initdefault:                 <==預設的 runlevel 設定, 此 runlevel 為 5

 

si::sysinit:/etc/rc.d/rc.sysinit  <==準備系統軟體執行的環境的腳本執行檔

 

# 7 個不同 run level 的,需要啟動的服務的 scripts 放置路徑:

l0:0:wait:/etc/rc.d/rc 0    <==runlevel 0 在 /etc/rc.d/rc0.d/

l1:1:wait:/etc/rc.d/rc 1    <==runlevel 1 在 /etc/rc.d/rc1.d/

l2:2:wait:/etc/rc.d/rc 2    <==runlevel 2 在 /etc/rc.d/rc2.d/

l3:3:wait:/etc/rc.d/rc 3    <==runlevel 3 在 /etc/rc.d/rc3.d/

l4:4:wait:/etc/rc.d/rc 4    <==runlevel 4 在 /etc/rc.d/rc4.d/

l5:5:wait:/etc/rc.d/rc 5    <==runlevel 5 在 /etc/rc.d/rc5.d/

l6:6:wait:/etc/rc.d/rc 6    <==runlevel 6 在 /etc/rc.d/rc6.d/

 

# 是否允許按下 [ctrl]+[alt]+[del] 就重新開機的設定項目:

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

 

# 底下兩個設定則是關於不斷電系統的 (UPS),一個是沒電力時的關機,一個是復電的處理

pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

 

1:2345:respawn:/sbin/mingetty tty1  <==其實 tty1~tty6 是由底下這六行決定的。

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

 

x:5:respawn:/etc/X11/prefdm -nodaemon <==X window 則是這行決定的!

讓我們解析一下這個檔案吧!首先,這個檔案的語法是利用冒號 (:) 將設定分隔成為四個欄位,每個欄位的意義與說明如下:

[設定項目]:[run level]:[init 的動作行為]:[指令項目]

設定項目:最多四個字元,代表 init 的主要工作項目,只是一個簡單的代表說明。

run level:該項目在哪些 run level 底下進行的意思。如果是35 則代表 runlevel 3 與 5 都會執行。

init 的動作項目:主要可以進行的動作項目意義有:

inittab 設定值

意義說明

initdefault

代表預設的 run level 設定值

sysinit

代表系統初始化的動作項目

ctrlaltdel

代表 [ctrl]+[alt]+[del] 三個按鍵是否可以重新開機的設定

wait

代表後面欄位設定的指令項目必須要執行完畢才能繼續底下其他的動作

respawn

代表後面欄位的指令可以無限制的再生 (重新啟動)。舉例來說, tty1 的 mingetty 產生的可登入畫面, 在你登出而結束後,系統會再開一個新的可登入畫面等待下一個登入。

更多的設定項目請參考 man inittab 的說明。

指令項目:亦即應該可以進行的指令,通常是一些 script 囉。

20.1.4 init 處理系統初始化流程(/etc/rc.d/rc.sysinit)

還記得上面提到 /etc/inittab 裡頭有這一句『 si::sysinit:/etc/rc.d/rc.sysinit 』吧? 這表示:『我開始載入各項系統服務之前,得先做好整個系統環境,我主要利用 /etc/rc.d/rc.sysinit 這個 shell script 來設定好我的系統環境的。』夠清楚了吧?

如果你使用 vim 去查閱過 /etc/rc.d/rc.sysinit 的話,那麼可以發現他主要的工作大抵有這幾項:

·        取得網路環境與主機類型:
讀取網路設定檔 /etc/sysconfig/network ,取得主機名稱與預設通訊閘(gateway) 等網路環境。

·        測試與掛載記憶體裝置 /proc 及 USB 裝置 /sys:
除掛載記憶體裝置 /proc 之外,還會主動偵測系統上是否具有usb 的裝置,若有則會主動載入 usb 的驅動程式,並且嘗試掛載 usb 的檔案系統。

·        決定是否啟動 SELinux :
我們在第十七章談到的 SELinux 在此時進行一些檢測,並且檢測是否需要幫所有的檔案重新編寫標準的 SELinux 類型 (auto relabel)。

·        啟動系統的亂數產生器
亂數產生器可以幫助系統進行一些密碼加密演算的功能,在此需要啟動兩次亂數產生器。

·        設定終端機 (console) 字形:

·        設定顯示於開機過程中的歡迎畫面 (text banner);

·        設定系統時間 (clock) 與時區設定:需讀入 /etc/sysconfig/clock 設定值

·        周邊設備的偵測與 Plug and Play (PnP) 參數的測試:
根據核心在開機時偵測的結果 (/proc/sys/kernel/modprobe ) 開始進行 ide / scsi / 網路 / 音效 等周邊設備的偵測,以及利用以載入的核心模組進行 PnP 裝置的參數測試。

·        使用者自訂模組的載入
使用者可以在 /etc/sysconfig/modules/*.modules 加入自訂的模組,則此時會被載入到系統當中

·        載入核心的相關設定:
系統會主動去讀取 /etc/sysctl.conf 這個檔案的設定值,使核心功能成為我們想要的樣子。

·        設定主機名稱與初始化電源管理模組 (ACPI)

·        初始化軟體磁碟陣列:主要是透過 /etc/mdadm.conf 來設定好的。

·        初始化 LVM 的檔案系統功能

·        以 fsck 檢驗磁碟檔案系統:會進行 filesystem check

·        進行磁碟配額 quota 的轉換 (非必要):

·        重新以可讀寫模式掛載系統磁碟:

·        啟動 quota 功能:所以我們不需要自訂 quotaon 的動作

·        啟動系統虛擬亂數產生器 (pseudo-random):

·        清除開機過程當中的暫存檔案:

·        將開機相關資訊載入 /var/log/dmesg 檔案中。

20.1.5 啟動系統服務與相關啟動設定檔(/etc/rc.d/rc N & /etc/sysconfig)

·          透過外部第一號參數 ($1) 來取得想要執行的腳本目錄。亦即由 /etc/rc.d/rc 5 可以取得 /etc/rc5.d/ 這個目錄來準備處理相關的腳本程式;

·          找到 /etc/rc5.d/K??* 開頭的檔案,並進行『 /etc/rc5.d/K??* stop 』的動作;

·          找到 /etc/rc5.d/S??* 開頭的檔案,並進行『 /etc/rc5.d/S??* start 』的動作;

·          /etc/rc5.d/K91capi stop -->/etc/init.d/capi stop

·          /etc/rc5.d/S10network start--> /etc/init.d/network start

看到最後一個被執行的項目是啥?沒錯,就是 S99local ,亦即是: /etc/rc.d/rc.local 這個檔案啦!

20.1.6 使用者自訂開機啟動程序(/etc/rc.d/rc.local)

在完成預設 runlevel 指定的各項服務的啟動後,如果我還有其他的動作想要完成時。

20.1.7 根據 /etc/inittab 之設定,載入終端機或X-Window 介面

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

x:5:respawn:/etc/X11/prefdm -nodaemon

這一段代表,在 run level 2, 3, 4, 5 時,都會執行 /sbin/mingetty 這個咚咚,而且執行六個,這也是為何我們 Linux 會提供『六個純文字終端機』的設定所在啊!因為 mingetty 就是在啟動終端機的指令說。

要注意的是那個 respawn 的 init 動作項目,他代表『當後面的指令被終止 (terminal) 時, init 會主動的重新啟動該項目。』這也是為何我們登入 tty1 終端機介面後,以 exit 離開後,系統還是會重新顯示等待使用者輸入的畫面的原因啊!

如果改天您不想要有六個終端機時,就將上面表格當中的某些項目註解掉即可!至於如果我們使用的是 run level 5 呢?那麼除了這六個終端機之外, init 還會執行 /etc/X11/prefdm -nodaemon 那個指令喔!

20.1.8 開機過程會用到的主要設定檔:/etc/modprobe.conf, /etc/sysconfig/*

1.        關於模組: /etc/modprobe.conf (/etc/modprobe.d/)

還記得我們在/etc/rc.d/rc.sysinit當中談到的載入使用者自訂模組的地方嗎?就是在 /etc/sysconfig/modules/ 目錄下啊! 雖然核心提供的預設模組已經很足夠我們使用了,但是,某些條件下我們還是得對模組進行一些參數的規劃,此時就得要使用到 /etc/modprobe.conf 囉!舉例來說,鳥哥的 CentOS 主機的 modprobe.conf 有點像這樣:

[root@www ~]# cat /etc/modprobe.conf

alias eth0 8139too               <==讓 eth0 使用 8139too 的模組

alias scsi_hostadapter pata_sis

alias snd-card-0 snd-trident

options snd-card-0 index=0       <==額外指定 snd-card-0 的參數功能

options snd-trident index=0

這個檔案大多在指定系統內的硬體所使用的模組啦!這個檔案通常系統是可以自行產生的,所以你不必手動去訂正他!不過,如果系統捉到錯誤的驅動程式,或者是你想要使用更新的驅動程式來對應相關的硬體配備時,你就得要自行手動的處理一下這個檔案了。

以上表的第一行為例,鳥哥使用螃蟹卡 (Realtek 的晶片組) 來作為我的網路卡,那螃蟹卡使用的模組就是 8139too 啦!這樣看的懂了吧?當我要啟動網路卡時,系統會跑到這個檔案來查閱一下,然後載入 8139too 驅動程式來驅動網路卡囉!更多的相關說明,請 man modprobe.conf 喔!

载入自定义模组:/etc/sysconfig/modules/*.modules

模组参数:/etc/modprobe.conf(/etc/modprobe.d/)

模组的自定义option是在哪一步进行的载入:其中,mkinitrd所参考的档案为/etc/modprobe.conf (/etc/modprobe.d/*),即默认会将这个文件夹里的模组进行打包。

2.        /etc/sysconfig/*

不說您也知道,整個開機的過程當中,老是讀取的一些服務的相關設定檔都是記錄在 /etc/sysconfig 目錄下的!那麼該目錄底下有些啥玩意兒?我們找幾個重要的檔案來談談:

·          authconfig:
這個檔案主要在規範使用者的身份認證的機制,包括是否使用本機的 /etc/passwd, /etc/shadow 等, 以及 /etc/shadow 密碼記錄使用何種加密演算法,還有是否使用外部密碼伺服器提供的帳號驗證 (NIS, LDAP) 等。系統預設使用 MD5 加密演算法,並且不使用外部的身份驗證機制;

·          clock:
此檔案在設定 Linux 主機的時區,可以使用格林威治時間(GMT),也可以使用台灣的本地時間 (local)。基本上,在 clock 檔案內的設定項目『 ZONE 』所參考的時區位於 /usr/share/zoneinfo 目錄下的相對路徑中。而且要修改時區的話,還得將 /usr/share/zoneinfo/Asia/Taipei 這個檔案複製成為/etc/localtime 才行!

·          i18n:
i18n 在設定一些語系的使用方面,例如最麻煩的文字介面下的日期顯示問題!如果你是以中文安裝的,那麼預設語系會被選擇 zh_TW.UTF8 ,所以在純文字介面之下,你的檔案日期顯示可能就會呈現亂碼!這個時候就需要更改一下這裡啦!更動這個 i18n 的檔案,將裡面的 LC_TIME 改成 en 即可!

·          keyboard & mouse:
keyboard 與 mouse 就是在設定鍵盤與滑鼠的形式;

·          network:
network 可以設定是否要啟動網路,以及設定主機名稱還有通訊閘 (GATEWAY) 這兩個重要資訊呢!

·          network-scripts/:
至於 network-scripts 裡面的檔案,則是主要用在設定網路卡~這部份我們在伺服器架設篇才會提到!

20.1.9 Run level 的切換: runlevel, init

要每次開機都執行某個預設的 run level ,則需要修改 /etc/inittab 內的設定項目,亦即是『 id:5:initdefault: 』裡頭的數字啊;

如果僅只是暫時變更系統的 run level 時,則使用 init [0-6] 來進行 run level 的變更。但下次重新開機時,依舊會是以 /etc/inittab 的設定為準。

假設原本我們是以 run level 5 登入系統的,但是因為某些因素,想要切換成為 run level 3 時

·          先比對 /etc/rc3.d/ 及 /etc/rc5.d 內的 K 與 S 開頭的檔案;

·          在新的 runlevel 亦即是 /etc/rc3.d/ 內有多的 K 開頭檔案,則予以關閉;

·          在新的 runlevel 亦即是 /etc/rc3.d/ 內有多的 S 開頭檔案,則予以啟動;

那我怎麼知道目前的 run level 是多少呢? 直接在 bash 當中輸入 runlevel 即可啊!

20.2      核心與核心模組

那麼核心與核心模組放在哪?

·          核心: /boot/vmlinuz 或 /boot/vmlinuz-version;

·          核心解壓縮所需 RAM Disk: /boot/initrd (/boot/initrd-version);

·          核心模組: /lib/modules/version/kernel 或/lib/modules/$(uname -r)/kernel;

·          核心原始碼: /usr/src/linux 或 /usr/src/kernels/ (要安裝才會有,預設不安裝)

·          如果該核心被順利的載入系統當中了,那麼就會有幾個資訊紀錄下來:

·          核心版本: /proc/version

·          系統核心功能: /proc/sys/kernel

·          問題來啦,如果我有個新的硬體,偏偏我的作業系統不支援,該怎麼辦?很簡單啊!

·          重新編譯核心,並加入最新的硬體驅動程式原始碼;

·          將該硬體的驅動程式編譯成為模組,在開機時載入該模組

模组会在启动服务的时候载入。

20.2.1 核心模組與相依性: depmod

基本上,核心模組的放置處是在 /lib/modules/$(uname -r)/kernel 當中,裡面主要還分成幾個目錄:

arch :與硬體平台有關的項目,例如 CPU 的等級等等;

crypto      :核心所支援的加密的技術,例如 md5 或者是 des 等等;

drivers     :一些硬體的驅動程式,例如顯示卡、網路卡、PCI 相關硬體等等;

fs      :核心所支援的 filesystems ,例如 vfat, reiserfs, nfs 等等;

lib     :一些函式庫;

net  :與網路有關的各項協定資料,還有防火牆模組 (net/ipv4/netfilter/*) 等等;

sound      :與音效有關的各項模組;

 

/lib/modules/$(uname -r)/modules.dep 這個檔案,他記錄了在核心支援的模組的各項相依性。那麼這個檔案如何建立呢?挺簡單!利用 depmod 這個指令就可以達到建立該檔案的需求了!

[root@www ~]# depmod [-Ane]

選項與參數:

-A  :不加任何參數時, depmod 會主動的去分析目前核心的模組,並且重新寫入

      /lib/modules/$(uname -r)/modules.dep 當中。若加入 -A 參數時,則 depmod

      會去搜尋比 modules.dep 內還要新的模組,如果真找到新模組,才會更新。

-n  :不寫入 modules.dep ,而是將結果輸出到螢幕上(standard out);

-e  :顯示出目前已載入的不可執行的模組名稱

 

範例一:若我做好一個網路卡驅動程式,檔名為 a.ko,該如何更新核心相依性?

[root@www ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net

[root@www ~]# depmod

20.2.2 核心模組的觀察: lsmod,modinfo

[root@www ~]# lsmod

Module                  Size  Used by

autofs4                24517  2

hidp                   23105  2

....(中間省略)....

8139too                28737  0

8139cp                 26305  0

mii                     9409  2 8139too,8139cp <==mii 還被 8139cp, 8139too 使用

....(中間省略)....

uhci_hcd               25421  0  <==底下三個是 USB 相關的模組!

ohci_hcd               23261  0

ehci_hcd               33357  0

使用 lsmod 之後,系統會顯示出目前已經存在於核心當中的模組,顯示的內容包括有:

·          模組名稱(Module);

·          模組的大小(size);

·          此模組是否被其他模組所使用 (Used by)。

[root@www ~]# modinfo [-adln] [module_name|filename]

選項與參數:

-a  :僅列出作者名稱;

-d  :僅列出該 modules 的說明 (description);

-l  :僅列出授權 (license);

-n  :僅列出該模組的詳細路徑。

 

範例一:由上個表格當中,請列出 mii 這個模組的相關資訊:

[root@www ~]# modinfo mii

filename:       /lib/modules/2.6.18-92.el5/kernel/drivers/net/mii.ko

license:        GPL

description:    MII hardware support library

author:         Jeff Garzik <jgarzik@pobox.com>

srcversion:     16DCEDEE4B5629C222C352D

depends:

vermagic:       2.6.18-92.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1

# 可以看到這個模組的來源,以及該模組的簡易說明!(是硬體支援函式庫)

 

範例二:我有一個模組名稱為 a.ko ,請問該模組的資訊為?

[root@www ~]# modinfo a.ko

....(省略)....

20.2.3 核心模組的載入與移除:insmod,modprobe, rmmod

好了,如果我想要自行手動載入模組,又該如何是好?有很多方法啦,最簡單而且建議的,是使用 modprobe 這個指令來載入模組,這是因為 modprobe 會主動的去搜尋 modules.dep 的內容,先克服了模組的相依性後,才決定需要載入的模組有哪些,很方便。至於 insmod 則完全由使用者自行載入一個完整檔名的模組,並不會主動的分析模組相依性啊!

[root@www ~]# insmod [/full/path/module_name] [parameters]

 

範例一:請嘗試載入 cifs.ko 這個『檔案系統』模組

[root@www ~]# insmod /lib/modules/$(uname -r)/kernel/fs/cifs/cifs.ko

[root@www ~]# lsmod | grep cifs

cifs                  212789  0

他立刻就將該模組載入囉~但是 insmod 後面接的模組必須要是完整的『檔名』才行!那如何移除這個模組呢?

[root@www ~]# rmmod [-fw] module_name

選項與參數:

-f  :強制將該模組移除掉,不論是否正被使用;

-w  :若該模組正被使用,則 rmmod 會等待該模組被使用完畢後,才移除他!

 

範例一:將剛剛載入的 cifs 模組移除!

[root@www ~]# rmmod cifs

 

範例二:請載入 vfat 這個『檔案系統』模組

[root@www ~]# insmod /lib/modules/$(uname -r)/kernel/fs/vfat/vfat.ko

insmod: error inserting '/lib/modules/2.6.18-92.el5/kernel/fs/vfat/vfat.ko':

-1 Unknown symbol in module

# 無法載入 vfat 這個模組啊!傷腦筋!

使用 insmod 與 rmmod 的問題就是,你必須要自行找到模組的完整檔名才行,而且如同上述範例二的結果,萬一模組有相依屬性的問題時,你將無法直接載入或移除該模組呢!所以近年來我們都建議直接使用 modprobe 來處理模組載入的問題,這個指令的用法是:

[root@www ~]# modprobe [-lcfr] module_name

選項與參數:

-c  :列出目前系統所有的模組!(更詳細的代號對應表)

-l  :列出目前在 /lib/modules/`uname -r`/kernel 當中的所有模組完整檔名;

-f  :強制載入該模組;

-r  :類似 rmmod ,就是移除某個模組囉~

 

範例一:載入 cifs 模組

[root@www ~]# modprobe cifs

# 很方便吧!不需要知道完整的模組檔名,這是因為該完整檔名已經記錄到

# /lib/modules/`uname -r`/modules.dep 當中的緣故啊!如果要移除的話:

[root@www ~]# modprobe -r cifs

·          可以通过,modprobe -c来查看载入模组的option

如果想找到那个设备使用的是哪个模组,可以这样做 => lspci-v => kernel modules => lsmod | egrep -i igb

20.3 Boot loader: Grub

20.3.1 boot loader 的兩個 stage

首先,BIOS会通过INT13来找到Boot Loader。而Boot Loader是在MBR内,但是MBR又只有446bytes,因此,MBR内只安装Boot Loader的最小主程式。

所以 Linux 將 boot loader 的程式碼執行與設定值載入分成兩個階段 (stage) 來執行:

·          Stage 1:執行 boot loader 主程式:
第一階段為執行 boot loader 的主程式,這個主程式必須要被安裝在開機區,亦即是 MBR 或者是 boot sector 。但如前所述,因為 MBR 實在太小了,所以,MBR 或 boot sector 通常僅安裝 boot loader 的最小主程式,並沒有安裝 loader 的相關設定檔;

·          Stage 2:主程式載入設定檔:
第二階段為透過 boot loader 載入所有設定檔與相關的環境參數檔案 (包括檔案系統定義與主要設定檔 menu.lst),一般來說,設定檔都在 /boot 底下。

那麼這些設定檔是放在哪裡啊?這些與 grub 有關的檔案都放置到 /boot/grub 中,那我們就來看看有哪些檔案吧!

[root@www ~]# ls -l /boot/grub

-rw-r--r--  device.map              <==grub 的裝置對應檔(底下會談到)

-rw-r--r--  e2fs_stage1_5           <==ext2/ext3 檔案系統之定義檔

-rw-r--r--  fat_stage1_5            <==FAT 檔案系統之定義檔

-rw-r--r--  ffs_stage1_5            <==FFS 檔案系統之定義檔

-rw-------  grub.conf               <==grub 在 Red Hat 的設定檔

-rw-r--r--  iso9660_stage1_5        <==光碟機檔案系統定義檔

-rw-r--r--  jfs_stage1_5            <==jfs 檔案系統定義檔

lrwxrwxrwx  menu.lst -> ./grub.conf <==其實 menu.lst 才是設定檔!

-rw-r--r--  minix_stage1_5          <==minix 檔案系統定義檔

-rw-r--r--  reiserfs_stage1_5       <==reiserfs 檔案系統定義檔

-rw-r--r--  splash.xpm.gz           <==開機時在 grub 底下的背景圖示

-rw-r--r--  stage1                  <==stage 1 的相關說明

-rw-r--r--  stage2                  <==stage 2 的相關說明

-rw-r--r--  ufs2_stage1_5           <==UFS 的檔案系統定義檔

-rw-r--r--  vstafs_stage1_5         <==vstafs 檔案系統定義檔

-rw-r--r--  xfs_stage1_5            <==xfs 檔案系統定義檔

從上面的說明你可以知道 /boot/grub/ 目錄下最重要的就是設定檔 (menu.lst) 以及各種檔案系統的定義!我們的 loader 讀取了這種檔案系統定義資料後,就能夠認識檔案系統並讀取在該檔案系統內的核心檔案囉。

20.3.2 grub 的設定檔/boot/grub/menu.lst 與選單類型:磁碟代號, menu.lst

grub 的優點挺多的,包括有:

·          認識與支援較多的檔案系統,並且可以使用 grub 的主程式直接在檔案系統中搜尋核心檔名;

·          開機的時候,可以『自行編輯與修改開機設定項目』,類似 bash 的指令模式;

·          可以動態搜尋設定檔,而不需要在修改設定檔後重新安裝 grub 。亦即是我們只要修改完 /boot/grub/menu.lst 裡頭的設定後,下次開機就生效了!

 

1.        硬碟與分割槽在 grub 中的代號

grub 對硬碟的識別使用的是如下的代號:

(hd0,0)

夠神了吧?跟 /dev/hda1 風馬牛不相干~怎麼辦啊?其實只要注意幾個東西即可,那就是:

·          硬碟代號以小括號 ( ) 包起來;

·          硬碟以 hd 表示,後面會接一組數字;

·          以『搜尋順序』做為硬碟的編號,而不是依照硬碟排線的排序!(這個重要!)

·          第一個搜尋到的硬碟為 0 號,第二個為 1 號,以此類推;

·          每顆硬碟的第一個 partition 代號為 0 ,依序類推。

所以說,第一顆『搜尋到的硬碟』代號為:『(hd0)』,而該顆硬碟的第一號分割槽為『(hd0,0)』,這樣說瞭解了吧?反正你要記得,在 grub 裡面,他開始的數字是 0 而不是 1 就是了!

 

2.        /boot/grub/menu.lst 設定檔:

[root@www ~]# vim /boot/grub/menu.lst

default=0     <==預設開機選項,使用第 1 個開機選單 (title)

timeout=5     <==若 5 秒內未動鍵盤,使用預設選單開機

splashimage=(hd0,0)/grub/splash.xpm.gz <==背景圖示所在的檔案

hiddenmenu    <==讀秒期間是否顯示出完整的選單畫面(預設隱藏)

title CentOS (2.6.18-92.el5)    <==第一個選單的內容

        root (hd0,0)

        kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

        initrd /initrd-2.6.18-92.el5.img

在 title 以前的四行,都是屬於 grub 的整體設定。此外,如果 timeout=0 代表直接使用 default 值進行開機而不讀秒,timeout=-1 則代表直接進入選單不讀秒了!

 

開機時可以選擇(1)直接指定核心檔案開機或 (2)將 boot loader 控制權轉移到下個 loader (此過程稱為chain-loader)。每個 title 後面接的是『該開機項目名稱的顯示』,亦即是在選單出現時,選單上面的名稱而已。那麼這兩種方式的設定有啥不同呢?

 

·          直接指定核心開機

既然要指定核心開機,所以當然要找到核心檔案啦!此外,有可能還需要用到 initrd 的 RAM Disk 設定檔。但是如前說的,尚未開機完成,所以我們必須要以 grub 的硬碟識別方式找出完整的 kernel 與 initrd 檔名才行。因此,我們可能需要有底下的方式來設定才行!

1. 先指定核心檔案放置的 partition,再讀取檔案 (目錄樹),

   最後才加入檔案的實際檔名與路徑 (kernel 與 initrd);

   鳥哥的 /boot 為 /dev/hda1 ,因此核心檔案的設定則成為:

root    (hd0,0)          <==代表核心檔案放在那個 partition 當中

kernel  /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

initrd  /initrd-2.6.18-92.el5.img

 

2. 直接指定 partition 與檔名,不需要額外指定核心檔案所在裝置代號

kernel  (hd0,0)/vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

initrd  (hd0,0)/initrd-2.6.18-92.el5.img

上面的 root, kernel, initrd 後面接的參數的意義說明如下:

root :代表的是『核心檔案放置的那個 partition 而不是根目錄』喔!不要搞錯了!以鳥哥的案例來說,我的根目錄為 /dev/hda2 而 /boot 獨立為 /dev/hda1 ,因為與 /boot 有關,所以磁碟代號就會成為 (hd0,0) 囉。

kernel :至於 kernel 後面接的則是核心的檔名,而在檔名後面接的則是核心的參數。由於開機過程中需要掛載根目錄,因此 kernel 後面接的那個 root=LABEL=/1 指的是『Linux 的根目錄在哪個 partition 』的意思。還記得第八章談過的 LABEL 掛載功能吧? 是的,這裡使用 LABEL 來掛載根目錄。至於rhgb 為色彩顯示而 quiet 則是安靜模式 (螢幕不會輸出核心偵測的資訊)。

initrd :就是前面提到的 initrd 製作出 RAM Disk 的檔案檔名啦!

 

·          利用 chainloader 的方式轉交控制權

所謂的 chain loader (開機管理程式的鏈結) 僅是在將控制權交給下一個 boot loader 而已,所以 grub 並不需要認識與找出 kernel 的檔名,『 他只是將 boot 的控制權交給下一個boot sector 或 MBR 內的 boot loader 而已』 所以通常他也不需要去查驗下一個 boot loader 的檔案系統!

一般來說, chain loader 的設定只要兩個就夠了,一個是預計要前往的 boot sector 所在的分割槽代號,另一個則是設定 chainloader 在那個分割槽的 boot sector (第一個磁區) 上!假設我的 Windows 分割槽在 /dev/hda1 ,且我又只有一顆硬碟,那麼要 grub 將控制權交給 windows 的 loader 只要這樣就夠了:

[root@www ~]# vi /boot/grub/menu.lst

....前略....

title Windows partition

         root (hd0,0)    <==設定使用此分割槽

         chainloader +1  <== +1 可以想成第一個磁區,亦即是 boot sector

上面的範例中,我們可以很簡單的這樣想:那個 (hd0,0) 就是 Windows 的 C 槽所在磁碟,而 chainloader +1 就是讓系統載入該分割槽當中的第一個磁區 (就是 boot sector) 內的開機管理程式。不過,由於 Windows 的開機碟需要設定為活化 (active) 狀態,且我們的 grub 預設會去檢驗該分割槽的檔案系統。因此我們可以重新將上面的範例改寫成這樣:

[root@www ~]# vi /boot/grub/menu.lst

....前略....

title Windows partition

         rootnoverify (hd0,0)   <==不檢驗此分割槽

         chainloader +1

         makeactive             <==設定此分割槽為開機碟(active)

grub 的功能還不止此,他還能夠隱藏某些分割槽。舉例來說,我的 /dev/hda5 是安裝 Linux 的分割槽,我不想讓 Windows 能夠認識這個分割槽時,你可以這樣做:

[root@www ~]# vi /boot/grub/menu.lst

....前略....

title Windows partition

         hide (hd0,4)           <==隱藏 (hd0,4) 這個分割槽

         rootnoverify (hd0,0)

         chainloader +1

         makeactive

20.3.3 initrd 的重要性與建立新 initrd 檔案: mkinitrd

會需要 initrd 的原因,是因為核心模組放置於 /lib/modules/$(uname -r)/kernel/ 當中, 這些模組必須要根目錄 (/) 被掛載時才能夠被讀取。但是如果核心本身不具備磁碟的驅動程式時,當然無法掛載根目錄,也就沒有辦法取得驅動程式,因此造成兩難的地步。

initrd 可以將 /lib/modules/....內的『開機過程當中一定需要的模組』包成一個檔案 (檔名就是 initrd),然後在開機時透過主機的 INT 13 硬體功能將該檔案讀出來解壓縮,並且 initrd 在記憶體內會模擬成為根目錄,由於此虛擬檔案系統 (Initial RAM Disk) 主要包含磁碟與檔案系統的模組,因此我們的核心最後就能夠認識實際的磁碟,那就能夠進行實際根目錄的掛載啦!所以說:『initrd 內所包含的模組大多是與開機過程有關,而主要以檔案系統及硬碟模組 (如 usb, SCSI 等) 為主』的啦!

[root@www ~]# mkinitrd [-v] [--with=模組名稱] initrd檔名 核心版本

選項與參數:

-v  :顯示 mkinitrd 的運作過程

--with=模組名稱:模組名稱指的是模組的名字而已,不需要填寫檔名。舉例來說,

       目前核心版本的 ext3 檔案系統模組為底下的檔名:

       /lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko

       那妳應該要寫成: --with=ext3 就好了 (省略 .ko)

initrd檔名:妳所要建立的 initrd 檔名,盡量取有意義又好記的名字。

核心版本  :某一個核心的版本,如果是目前的核心則是『 $(uname -r) 』

 

範例一:以 mkinitrd 的預設功能建立一個 initrd 虛擬磁碟檔案

[root@www ~]# mkinitrd -v initrd_$(uname -r) $(uname -r)

Creating initramfs

Looking for deps of module ehci-hcd

Looking for deps of module ohci-hcd

....(中間省略)....

Adding module ehci-hcd  <==最終加入 initrd 的就是底下的模組

Adding module ohci-hcd

Adding module uhci-hcd

Adding module jbd

Adding module ext3

Adding module scsi_mod

Adding module sd_mod

Adding module libata

Adding module pata_sis

 

[root@www ~]# ll initrd_*

-rw------- 1 root root 2406443 Apr 30 02:55 initrd_2.6.18-92.el5

# 由於目前的核心版本可使用 uname -r 取得,因此鳥哥使用較簡單的指令來處理囉~

# 此時 initrd 會被建立起來,妳可以將他移動到 /boot 等待使用。

 

範例二:增加 8139too 這個模組的 initrd 檔案

[root@www ~]# mkinitrd -v --with=8139too initrd_vbirdtest $(uname -r)

....(前面省略)....

Adding module mii

Adding module 8139too  <==看到沒!這樣就加入了!

其中,mkinitrd所参考的档案为/etc/modprobe.conf,即默认会将这个文件夹里的模组进行打包。

20.3.4 測試與安裝 grub:grub-install, grub shell

最後總結一下:

·          如果是從其他 boot loader 轉成 grub 時,得先使用 grub-install 安裝 grub 設定檔;

·          開始編輯 menu.lst 這個重要的設定檔;

·          透過 grub 來將主程式安裝到系統中,如 MBR 的 (hd0) 或 boot sector 的 (hd0,0) 等等。

[root@www ~]# grub-install [--root-directory=DIR] INSTALL_DEVICE

選項與參數:

--root-directory=DIR 那個 DIR 為實際的目錄,使用 grub-install 預設會將

  grub 所有的檔案都複製到 /boot/grub/* ,如果想要複製到其他目錄與裝置去,

  就得要用這個參數。

INSTALL_DEVICE 安裝的裝置代號啦!

 

範例一:將 grub 安裝在目前系統的 MBR 底下,我的系統為 /dev/hda:

[root@www ~]# grub-install /dev/hda

# 因為原本 /dev/hda 就是使用 grub ,所以似乎不會出現什麼特別的訊息。

# 如果去查閱一下 /boot/grub 的內容,會發現所有的檔案都更新了,因為我們重裝了!

 

範例二:我的 /home 為獨立的 /dev/hda3 ,如何安裝 grub 到 /dev/hda3 (boot sector)

[root@www ~]# grub-install --root-directory=/home /dev/hda3

Probing devices to guess BIOS drives. This may take a long time.

Installation finished. No error reported.

This is the contents of the device map /home/boot/grub/device.map.

Check if this is correct or not. If any of the lines is incorrect,

fix it and re-run the script `grub-install'.

 

(fd0)   /dev/fd0

(hd0)   /dev/hda   <==會給予裝置代號的對應表!

 

[root@www ~]# ll /home/boot/grub/

-rw-r--r-- 1 root root     30 Apr 30 11:12 device.map

-rw-r--r-- 1 root root   7584 Apr 30 11:12 e2fs_stage1_5

....(底下省略)....

# 看!檔案都安裝進來了!但是注意到,我們並沒有設定檔喔!那要自己建立!

 

[root@www ~]# grub

 

# 1. 先設定一下含有 grub 目錄的那個 partition 啊!

grub> root (hd0,0)

 Filesystem type is ext2fs, partition type 0x83

# 鳥哥主機的分割中,/boot/grub 在 /boot 的分割槽,亦即是 /dev/hda1 內喔!

# 另外, grub 也能夠分辨出該分割槽的檔案系統 (ext2)。

 

# 2. 搜尋一下,是否存在 stage1 這個資訊檔案?

grub> find /boot/grub/stage1

 (hd0,2)

# 見鬼!怎麼會只有一個!我們明明有 /boot/grub 與 /home/boot/grub 啊!

# 因為 /boot 是獨立的,因此要找到該檔名就得要用如下的方式:

 

grub> find /grub/stage1

 (hd0,0)

# 這樣就能夠找到囉!要特別注意 grub 找到不是目錄樹,而是裝置內的檔案。

 

# 3. 搜尋一下是否可以找到核心? /boot/vmlinuz-2.6.18-92.el5 ?

grub> find /boot/vmlinuz-2.6.18-92.el5

Error 15: File not found

grub> find /vmlinuz-2.6.18-92.el5

 (hd0,0)

# 再次強調,因為 /boot/ 是獨立的,因此就會變成上頭的模樣囉!

 

# 4. 將主程式安裝上去吧!安裝到 MBR 看看!

grub> setup (hd0)

 Checking if "/boot/grub/stage1" exists... no <==因為 /boot 是獨立的

 Checking if "/grub/stage1" exists... yes     <==所以這個檔名才是對的!

 Checking if "/grub/stage2" exists... yes

 Checking if "/grub/e2fs_stage1_5" exists... yes

 Running "embed /grub/e2fs_stage1_5 (hd0)"...  15 sectors are embedded.

succeeded

 Running "install /grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/grub/stage2

/grub/grub.conf"... succeeded  <==將 stage1 程式安裝妥當囉!

Done.

# 很好!確實有裝起來~這樣 grub 就在 MBR 當中了!

 

# 5. 那麼重複安裝到我的 /dev/hda1 呢?亦即是 boot sector 當中?

grub> setup (hd0,0)

 Checking if "/boot/grub/stage1" exists... no

 Checking if "/grub/stage1" exists... yes

 Checking if "/grub/stage2" exists... yes

 Checking if "/grub/e2fs_stage1_5" exists... yes

 Running "embed /grub/e2fs_stage1_5 (hd0,0)"... failed (this is not fatal)

 Running "embed /grub/e2fs_stage1_5 (hd0,0)"... failed (this is not fatal)

 Running "install /grub/stage1 (hd0,0) /grub/stage2 p /grub/grub.conf "...

succeeded

Done.

# 雖然無法將 stage1_5 安裝到 boot sector 去,不過,還不會有問題,

# 重點是最後面那個 stage1 要安裝後,顯示 succeeded 字樣就可以了!

 

grub> quit

如此一來,就已經將 grub 安裝到 MBR 及 /dev/hda1 的 boot sector 裡面去了!而且讀取的是 (hd0,0) 裡面的 /grub/menu.lst 那個檔案喔!

整個安裝與 grub shell 的動作其實很簡單,如果您有興趣研究的話,可以使用 info grub 去查閱~鳥哥這裡僅介紹幾個有用的指令而已。

·          用『 root (hdx,x) 』選擇含有 grub 目錄的那個 partition 代號;

·          用『 find /boot/grub/stage1 』看看能否找到安裝資訊檔案;

·          用『 find /boot/vmlinuz 』看看能否找到 kernel file (不一定要成功!);

·          用『 setup (hdx,x) 』或『 setup (hdx) 』將 grub 安裝在 boot sector 或 MBR;

·          用『 quit 』來離開 grub shell !

 

20.3.5 開機前的額外功能修改

另外,如果你正在進行開機,那麼請注意,我們可以在預設選單 (鳥哥的範例當中是 30 秒) 按下任意鍵,還可以進行 grub 的『線上編修』功能喔!

20.3.6 關於核心功能當中的 vga 設定

[root@www ~]# grep 'FRAMEBUFFER_CONSOLE' /boot/config-2.6.18-92.el5

CONFIG_FRAMEBUFFER_CONSOLE=y

# 這個項目如果出現 y 那就是有支援啦!如果被註解或是 n ,那就是沒支援啦!

 

[root@www ~]# vim /boot/grub/menu.lst

....(前面省略)....

title CentOS (2.6.18-92.el5)

        root (hd0,0)

        kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet vga=790

        initrd /initrd-2.6.18-92.el5.img

....(後面省略)....

20.3.8 為個別選單加上密碼:grub-md5-crypt

想像一個環境,如果你管理的是一間電腦教室,這間電腦教室因為可對外開放,但是你又擔心某些 partition 被學生不小心的弄亂,因此你可能會想要將某些開機選單作個保護。這個時候,為每個選單作個加密的密碼就是個可行的方案啦!那如何在開機的過程裡面提供密碼保護呢?首先,你必須要建立密碼,而且還需要是加密過後的喔!否則人家跑到 /boot/grub/menu.lst 不就可以探查到你的開機密碼了?那如何建立加密的密碼呢?我們可以透過 grub 提供的 md5 編碼來處理的,如下所示:

[root@www ~]# grub-md5-crypt

Password: <==輸入密碼

Retype password: <==再輸入一次

$1$kvlI0/$byrbNgkt/.REKPQdfg287. <==這就是產生的 md5 密碼!

上面產生的最後一行,由 $ 開始到 . 結束的那行,就是你的密碼經過 md5 編碼過後的咚咚!將這個密碼複製下來吧!假設我們要將第一個選項加入這個密碼,而第四個選項加入另外的密碼,那你應該要這樣做:

[root@www ~]# vim /boot/grub/menu.lst

....(前面省略)....

title CentOS (2.6.18-92.el5)

        password --md5 $1$kvlI0/$byrbNgkt/.REKPQdfg287.

        root (hd0,0)

        kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet vga=790

        initrd /initrd-2.6.18-92.el5.img

....(中間省略)....

title single user mode

        password --md5 $1$GFnI0/$UuiZc/7snugLtVN4J/WyM/

        root (hd0,0)

        kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet single

        initrd /initrd-2.6.18-92.el5.img

上表的案例中,我們兩個選單進入的密碼並不相同,可以進行同學的分類啦!不過這樣也造成一個問題,那就是一定要輸入密碼才能夠進入開機流程,如果你在遠端使用 reboot 重新開機,並且主機前面並沒有任何人的話.... 你的主機並不會主動進入開機程序喔! ^_^

你必須要注意的是:password 這個項目一定要在 title 底下的第一行。不過,此項功能還是可能被破解的,因為使用者可以透過編輯模式 (e) 進入選單,並刪除密碼欄位並按下 b 就能夠進行開機流程了!真糟糕!那怎辦?只好透過整體的 password (放在所有的 title 之前) ,然後在 title 底下的第一行設定 lock ,那使用者想要編輯時,也得要輸入密碼才行啊!設定有點像這樣:

[root@www ~]# vim /boot/grub/menu.lst

default=0

timeout=30

password --md5 $1$kvlI0/$byrbNgkt/.REKPQdfg287.  <==放在整體設定處

splashimage=(hd0,0)/grub/splash.xpm.gz

#hiddenmenu

title CentOS (2.6.18-92.el5)

        lock  <==多了鎖死的功能

        root (hd0,0)

        kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet vga=790

        initrd /initrd-2.6.18-92.el5.img

那麼重新開機後,畫面會像這樣:


圖 3.8.1、 grub 加密的示意圖

你可以看到最下方僅出現 p 的功能,由於 2, 3, 4 選單並沒有使用 lock ,因此這三個選單使用者還是可以執行開機程序, 但是第一個選單由於有 lock 項目,因此除非你輸入正確的密碼,否則第一個選單是無法被載入執行的。 另外,這個項目也能夠避免你的 menu.lst 在開機的過程中被亂改,是具有保密 menu.lst 的功能啦! 與剛剛的選單密碼功能不同。

20.4 開機過程的問題解決

20.4.1 忘記 root 密碼的解決之道

其實在 Linux 環境中 root 密碼忘記時還是可以救回來的!只要能夠進入並且掛載 / ,然後重新設定一下 root 的密碼,就救回來啦!這是因為開機流程中,若強制核心進入 runlevel 1 時,預設是不需要密碼即可取得一個 root 的 shell 來救援的。整個動作有點像這樣:

·          重新開機!一定要重新開機!怎麼重開都沒關係;

·          在開機進入 grub 選單後, (1)在你要進入的選單上面點 'e' 進入詳細設定; (2)將光棒移動到 kernel 上方並點 'e' 進入編輯畫面; (3)然後出現如下畫面來處理:

grub edit> kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/ rhgb quiet single

·          重點就是那個特殊字體的咚咚啦!按下 [enter] 再按下 b 就能夠開機進入單人維護模式了。

進入單人維護模式後,系統會以 root 的權限直接給你一個 shell ,此時你就能夠執行『 passwd 』這個指令來重建 root 的密碼啦!然後直接『 init 5 』就可以切換成為 X 視窗介面囉!就是這麼簡單。

20.4.2 init 設定檔錯誤

前一個 root 密碼挽救的方法其實可以用在很多地方,唯一一個無法挽救的情況,那就是 /etc/inittab 這個檔案設定錯誤導致的無法開機!根據開機流程,我們知道 runlevel 0~6 都會讀取 /etc/inittab 設定檔,因此你使用 single mode (runlevel 1) 當然也是要讀取 /etc/inittab 來進行開機的。那既然無法進入單人維護模式, 就表示這題無解囉?非也非也,既然預設的 init 無法執行,那我們就告訴核心不要執行 init ,改呼叫 bash 啊!可以略過 init 嗎?可以的,同樣在開機進入 grub 後,同樣在 grub edit 的情況下這樣做:

grub edit> kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/ rhgb quiet init=/bin/bash

因為我們指定了核心呼叫的第一支程式 (init) 變成 /bin/bash,因此 /sbin/init 就不會被執行。又根據開機流程的說明,我們知道此時雖然可以利用 root 取得 bash 來工作,但此時 (1)除了根目錄外,其他的目錄都沒有被掛載; (2)根目錄被掛載成為唯讀狀態。因此我們還需要進行一些動作才行!如下所示:


圖 4.2.1、略過 init 的程序,直接進入 bash shell

鳥哥僅下達兩個指令,『 mount -o remount,rw / 』用途是將根目錄重新掛載成為可讀寫,至於『mount -a 』則是參考 /etc/fstab 的內容重新掛載檔案系統!此時你又可以開機進行救援的工作了!只是救援完畢後,你得要使用『 reboot 』重新開機一次才行!

20.4.3 BIOS 磁碟對應的問題 (device.map)

由於目前硬碟很便宜啊,所以很多朋友就想說:『那我能不能將 Windows 安裝在 /dev/hda 而 Linux 安裝在 /dev/hdb ,然後調整 BIOS 的開機裝置順序,如此則兩套系統各有各的 loader 安裝在個別硬碟的 MBR 當中了!』。這個想法非常好,如此一來兩者就不會互相干擾,因為每顆磁碟的MBR 個別有不同作業系統的 loader 嘛!問題是,grub 對磁碟的裝置代號使用的是偵測到的順序啊!也就是說,你調整了 BIOS 磁碟開機順序後,你的 menu.lst 內的裝置代號就可能會對應到錯誤的磁碟上了!啊!真想哭!

bios搜索到的第一颗硬盘的代号为hd0,以此类推。

1号硬盘:(hd0)    /dev/sda => hd0 => menu.lst => root (hd0,0)

2号硬盘:(hd1)    /dev/sdb => hd1 => menu.lst => root (hd1,0)

现在修改bios搜寻的顺序,即1号硬盘变成了hd12号硬盘变成了hd0。但是,由于没有更新device.map的对应,因此当我尝试进入2号硬盘的时候,则会错误的进入的1号硬盘。

沒關係的,我們可以透過 /boot/grub/device.map 這個檔案來寫死每個裝置對 grub 磁碟代號的對應喔! 舉例來說,鳥哥的這個檔案內容如下:

[root@www ~]# cat /boot/grub/device.map

(fd0)   /dev/fd0

(hd0)   /dev/hda

如果你不清楚如何處理的話,也可以利用 grub-install 的功能喔!例如:

[root@www ~]# grub-install --recheck /dev/hda1

這樣 device.map 就會主動的被更新了!這樣瞭解乎?

20.4.4 因檔案系統錯誤而無法開機

如果因為設定錯誤導致無法開機時,要怎麼辦啊?這就更簡單了!最容易出錯的設定而導致無法順利開機的步驟,通常就是 /etc/fstab 這個檔案了,尤其是使用者在實作 Quota 時,最容易寫錯參數, 又沒有經過 mount -a 來測試掛載,就立刻直接重新開機,真要命!無法開機成功怎麼辦?這種情況的問題大多如下面的畫面所示:


圖 4.4.1、檔案系統錯誤的示意圖

看到最後兩行,他說可以輸入 root 的密碼繼續加以救援喔!那請輸入 root 的密碼來取得 bash 並以 mount -o remount,rw / 將根目錄掛載成可讀寫後,繼續處理吧!其實會造成上述畫面可能的原因除了 /etc/fstab 編輯錯誤之外,如果你曾經不正常關機後,也可能導致檔案系統不一致 (Inconsistent) 的情況,也有可能會出現相同的問題啊!如果是磁區錯亂的情況,請看到上圖中的第二行處, fsck 告知其實是 /dev/md0 出錯,此時你就應該要利用 fsck 去檢測 /dev/md0 才是!等到系統發現錯誤,並且出現『clear [Y/N]』時,輸入『 y 』吧!

這個 fsck 的過程可能會很長,而且如果你的 partition 上面的 filesystem 有過多的資料損毀時,即使 fsck 完成後,可能因為傷到系統槽,導致某些關鍵系統檔案資料的損毀,那麼依舊是無法進入 Linux 的。此時,就好就是將系統當中的重要資料複製出來,然後重新安裝,並且檢驗一下,是否實體硬碟有損傷的現象才好!不過一般來說,不太可能會這樣啦~通常都是 fsck 處理完畢後,就能夠順利再次進入 Linux 了。

20.4.5 利用 chroot 切換到另一顆硬碟工作

[root@study /]# cd chroot_test/

[root@studychroot_test]# ls

[root@study chroot_test]#which bash

/bin/bash

[root@studychroot_test]# ldd /bin/bash

        linux-vdso.so.1 =>  (0x00007fff74de7000)

        libtermcap.so.2 =>/lib64/libtermcap.so.2 (0x000000316ba00000)

        libdl.so.2 => /lib64/libdl.so.2(0x000000316b200000)

        libc.so.6 => /lib64/libc.so.6(0x000000316aa00000)

        /lib64/ld-linux-x86-64.so.2(0x000000316a600000)

[root@studychroot_test]# modinfo linux-vdso.so.1

modinfo: could notfind module linux-vdso.so.1

[root@studychroot_test]# cd /chroot_test/

[root@studychroot_test]# mkdir bin etc lib64 var home

[root@studychroot_test]# cp -p /lib64/libtermcap.so.2 /chroot_test/lib64/

[root@studychroot_test]# cp -p /lib64/libdl.so.2 /chroot_test/lib64/

[root@studychroot_test]# cp -p /lib64/libc.so.6 /chroot_test/lib64/

[root@studychroot_test]# cp -p /lib64/ld-linux-x86-64.so.2 /chroot_test/lib64/

[root@studychroot_test]# cp -p /bin/bash /chroot_test/bin/

[root@studychroot_test]# cd /chroot_test/

[root@studychroot_test]# chroot .

bash-3.2#

开机过程:BIOS => 根据BIOS的设置,找到第一块可开机装置 =>通过INT13找到MBR => MBR内只是grub的主程序,指向设定档,或者转交给其他的loader=>通过device map,找到boot文件夹下的initrdvmlinuz =>核心载入分为两步:第一步是利用initrd,模拟一个小型的根盘,载入必要的模组;第二步则是真正的挂载根目录,进行开机 =>按照/etc/inittab进行系统的设定


0 0
原创粉丝点击