翻譯了grub2官方手冊的絕大部份內容,而後本身整理了一下。由於內容有點雜,因此章節安排上可能不是太合理,敬請諒解。html
本人譯做集合:http://www.cnblogs.com/f-ck-need-u/p/7048359.htmlnode
本文主要介紹的是grub2,在文末對傳統grub進行了簡述,但在grub2的內容部分中包含了不少grub2和傳統grub的對比。linux
若是僅僅是想知道grub2中的boot.img/core.img/diskboot.img/kernel.img或者傳統grub中stage1/stage1_5/stage2文件的做用,請直接跳至相關內容處閱讀。ios
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Changes-from-GRUB-Legacy.html#Changes-from-GRUB-Legacyshell
只說明幾個主要的:express
1.配置文件的名稱改變了。在grub中,配置文件爲grub.conf或menu.lst(grub.conf的一個軟連接),在grub2中更名爲grub.cfg。centos
2.grub2增添了許多語法,更接近於腳本語言了,例如支持變量、條件判斷、循環。安全
3.grub2中,設備分區名稱從1開始,而在grub中是從0開始的。性能優化
4.grub2使用img文件,再也不使用grub中的stage一、stage1.5和stage2。bash
5.支持圖形界面配置grub,但要安裝grub-customizer包,epel源提供該包。
6.在已進入操做系統環境下,再也不提供grub命令,也就是不能進入grub交互式界面,只有在開機時才能進入,算是一大缺憾。
7.在grub2中沒有了好用的find命令,算是另外一大缺憾。
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Naming-convention.html#Naming-convention
(fd0) :表示第一塊軟盤 (hd0,msdos2) :表示第一塊硬盤的第二個mbr分區。grub2中分區從1開始編號,傳統的grub是從0開始編號的 (hd0,msdos5) :表示第一塊硬盤的第一個邏輯分區 (hd0,gpt1) :表示第一塊硬盤的第一個gpt分區 /boot/vmlinuz :相對路徑,基於根目錄,表示根目錄下的boot目錄下的vmlinuz, :若是設置了根目錄變量root爲(hd0,msdos1),則表示(hd0,msdos1)/boot/vmlinuz (hd0,msdos1)/boot/vmlinuz:絕對路徑,表示第一硬盤第一分區的boot目錄下的vmlinuz文件
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/General-boot-methods.html#General-boot-methods
grub2支持兩種方式引導操做系統:
通常只使用第一種方式,只有想引導grub默認不支持的操做系統時纔會使用第二種方式。
在傳統grub軟件安裝完後,在/usr/share/grub/RELEASE/目錄下會生成一些stage文件。
[root@xuexi ~]# ls /usr/share/grub/x86_64-redhat/ e2fs_stage1_5 ffs_stage1_5 jfs_stage1_5 reiserfs_stage1_5 stage2 ufs2_stage1_5 xfs_stage1_5 fat_stage1_5 iso9660_stage1_5 minix_stage1_5 stage1 stage2_eltorito vstafs_stage1_5
在grub2軟件安裝完後,會在/usr/lib/grub/i386-pc/目錄下生成不少模塊文件和img文件,還包括一些lst列表文件。
[root@server7 ~]# ls /usr/lib/grub/i386-pc/*.mod | wc -l 257 [root@server7 ~]# ls -lh /usr/lib/grub/i386-pc/*.lst -rw-r--r--. 1 root root 3.7K Nov 24 2015 /usr/lib/grub/i386-pc/command.lst -rw-r--r--. 1 root root 936 Nov 24 2015 /usr/lib/grub/i386-pc/crypto.lst -rw-r--r--. 1 root root 214 Nov 24 2015 /usr/lib/grub/i386-pc/fs.lst -rw-r--r--. 1 root root 5.1K Nov 24 2015 /usr/lib/grub/i386-pc/moddep.lst -rw-r--r--. 1 root root 111 Nov 24 2015 /usr/lib/grub/i386-pc/partmap.lst -rw-r--r--. 1 root root 17 Nov 24 2015 /usr/lib/grub/i386-pc/parttool.lst -rw-r--r--. 1 root root 202 Nov 24 2015 /usr/lib/grub/i386-pc/terminal.lst -rw-r--r--. 1 root root 33 Nov 24 2015 /usr/lib/grub/i386-pc/video.lst [root@server7 ~]# ls -lh /usr/lib/grub/i386-pc/*.img -rw-r--r--. 1 root root 512 Nov 24 2015 /usr/lib/grub/i386-pc/boot_hybrid.img -rw-r--r--. 1 root root 512 Nov 24 2015 /usr/lib/grub/i386-pc/boot.img -rw-r--r--. 1 root root 2.0K Nov 24 2015 /usr/lib/grub/i386-pc/cdboot.img -rw-r--r--. 1 root root 512 Nov 24 2015 /usr/lib/grub/i386-pc/diskboot.img -rw-r--r--. 1 root root 28K Nov 24 2015 /usr/lib/grub/i386-pc/kernel.img -rw-r--r--. 1 root root 1.0K Nov 24 2015 /usr/lib/grub/i386-pc/lnxboot.img -rw-r--r--. 1 root root 2.9K Nov 24 2015 /usr/lib/grub/i386-pc/lzma_decompress.img -rw-r--r--. 1 root root 1.0K Nov 24 2015 /usr/lib/grub/i386-pc/pxeboot.img
當使用grub來管理啓動菜單時,那麼boot loader都是grub程序安裝的。
傳統的grub將stage1轉換後的內容安裝到MBR(VBR或EBR)中的boot loader部分,將stage1_5轉換後的內容安裝在緊跟在MBR後的扇區中,將stage2轉換後的內容安裝在/boot分區中。
grub2將boot.img轉換後的內容安裝到MBR(VBR或EBR)中的boot loader部分,將diskboot.img和kernel.img結合成爲core.img,同時還會嵌入一些模塊或加載模塊的代碼到core.img中,而後將core.img轉換後的內容安裝到磁盤的指定位置處。
它們之間更具體的關係見下文。
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/BIOS-installation.html#BIOS-installation
嚴格地說是core.img的安裝位置,由於boot.img的位置是固定在MBR或VBR或EBR上的。
(1).MBR
MBR格式的分區表用於PC BIOS平臺,這種格式容許四個主分區和額外的邏輯分區。使用這種格式的分區表,有兩種方式安裝GURB:
這兩種方法有不一樣的問題。
使用嵌入的方式安裝grub,就沒有保留的空閒空間來保證安全性,例若有些專門的軟件就是使用這段空間來實現許可限制的;另外分區的時候,雖然會在MBR和第一個分區中間留下空閒空間,但可能留下的空間會比這更小。
方法二安裝grub到文件系統,但這樣的grub是脆弱的。例如,文件系統的某些特性須要作尾部包裝,甚至某些fsck檢測,它們可能會移動這些block。
GRUB開發團隊建議將GRUB嵌入到MBR和第一個分區之間,除非有特殊需求,但仍必需要保證第一個分區至少是從第31kB(第63個扇區)以後纔開始建立的。
如今的磁盤設備,通常都會有分區邊界對齊的性能優化提醒,因此第一個分區可能會自動從第1MB處開始建立。
(2).GPT
一些新的系統使用GUID分區表(GPT)格式,這種格式是EFI固件所指定的一部分。但若是操做系統支持的話,GPT也能夠用於BIOS平臺(即MBR風格結合GPT格式的磁盤),使用這種格式,須要使用獨立的BIOS boot分區來保存GRUB,GRUB被嵌入到此分區,不會有任何風險。
當在gpt磁盤上建立一個BIOS boot分區時,須要保證兩件事:(1)它最小是31kB大小,但通常都會爲此分區劃分1MB的空間用於可擴展性;(2)必需要有合理的分區類型標識(flag type)。
例如使用gun parted工具時,能夠設置爲bios_grub標識:
# parted /dev/sda toggle partition_num bios_grub # parted /dev/sda set partiton_num bios_grub on
若是使用gdisk分區工具時,則分類類型設置爲"EF02"。
若是使用其餘的分區工具,可能須要指定guid,則能夠指定其guid爲"21686148-6449-6e6f-744e656564454649"。
下圖是某個bios/gpt格式的bios boot分區信息,從中可見,它大小爲1M,沒有文件系統,分區表示爲bios_grub。
下圖爲gpt磁盤在圖形界面下安裝操做系統時建立的Bios boot分區。
在傳統的grub上,能夠直接在bash下敲入grub命令進入命令交互模式,但grub2只能在系統啓動前進入grub交互命令行。
按下e見能夠編輯所選菜單對應的grub菜單配置項,按下c鍵能夠進入grub命令行交互模式。
這裏的安裝指的不是安裝grub程序,而是安裝Boot loader,但通常都稱之爲安裝grub,且後文都是這個意思。
安裝方式很是簡單,只需調用grub2-install,而後給定安裝到的設備名便可。
shell> grub2-install /dev/sda
這樣的安裝方式,默認會將img文件放入到/boot目錄下,若是想自定義放置位置,則使用--boot-directory選項指定,可用於測試練習grub的時候使用,但在真實的grub環境下不建議作任何改動。
shell> grub2-install --boot-director=/mnt/boot /dev/fd0
若是是EFI固件平臺,則必須掛載好efi系統分區,通常會掛在/boot/efi下,這是默認的,此時可直接使用grub2-install安裝。
shell> grub2-install
若是不是掛載在/boot/efi下,則使用--efi-directory指定efi系統分區路徑。
shell> grub2-install --efi-directory=/mnt/efi
grub2-install其實是一個shell腳本,用於調用其餘工具,真正的功能都是其餘工具去完成的,因此若是很是熟悉grub內部命令和機制,徹底能夠不用grub2-install。
對應傳統的grub安裝命令爲grub-install,用法和grub2-install同樣。
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Images.html#Images
img文件是grub2生成的,stage文件是傳統grub生成的。下面是各類文件的說明。
grub2生成了好幾個img文件,有些分佈在/usr/lib/grub/i386-pc目錄下,有些分佈在/boot/grub2/i386-pc目錄下,它們之間的關係,相信看了下文以後就會明白了。
下圖描述了各個img文件之間的關係。其中core.img是動態生成的,路徑爲/boot/grub2/i386-pc/core.img,而其餘的img則存在於/usr/lib/grub/i386-pc目錄下。固然,在安裝grub時,boot.img會被拷貝到/boot/grub2/i386-pc目錄下。
(1)boot.img
在BIOS平臺下,boot.img是grub啓動的第一個img文件,它被寫入到MBR中或分區的boot sector中,由於boot sector的大小是512字節,因此該img文件的大小也是512字節。
boot.img惟一的做用是讀取屬於core.img的第一個扇區並跳轉到它身上,將控制權交給該扇區的img。因爲體積大小的限制,boot.img沒法理解文件系統的結構,所以grub2-install將會把core.img的位置硬編碼到boot.img中,這樣就必定能找到core.img的位置。
(2)core.img
core.img根據diskboot.img、kernel.img和一系列的模塊被grub2-mkimage程序動態建立。core.img中嵌入了足夠多的功能模塊以保證grub能訪問/boot/grub,而且能夠加載相關的模塊實現相關的功能,例如加載啓動菜單、加載目標操做系統的信息等,因爲grub2大量使用了動態功能模塊,使得core.img體積變得足夠小。
core.img中包含了多個img文件的內容,包括diskboot.img/kernel.img等。
core.img的安裝位置隨MBR磁盤和GPT磁盤而不一樣,這在上文中已經說明過了。
(3)diskboot.img
若是啓動設備是硬盤,即從硬盤啓動時,core.img中的第一個扇區的內容就是diskboot.img。diskboo.img的做用是讀取core.img中剩餘的部分到內存中,並將控制權交給kernel.img,因爲此時還不識別文件系統,因此將core.img的所有位置以block列表的方式編碼,使得diskboot.img可以找到剩餘的內容。
該img文件由於佔用一個扇區,因此體積爲512字節。
(4)cdboot.img
若是啓動設備是光驅(cd-rom),即從光驅啓動時,core.img中的第一個扇區的的內容就是cdboo.img。它的做用和diskboot.img是同樣的。
(5)pexboot.img
若是是從網絡的PXE環境啓動,core.img中的第一個扇區的內容就是pxeboot.img。
(6)kernel.img
kernel.img文件包含了grub的基本運行時環境:設備框架、文件句柄、環境變量、救援模式下的命令行解析器等等。不多直接使用它,由於它們已經整個嵌入到了core.img中了。注意,kernel.img是grub的kernel,和操做系統的內核無關。
若是細心的話,會發現kernel.img自己就佔用28KB空間,但嵌入到了core.img中後,core.img文件才只有26KB大小。這是由於core.img中的kernel.img是被壓縮過的。
(7)lnxboot.img
該img文件放在core.img的最前部位,使得grub像是linux的內核同樣,這樣core.img就能夠被LILO的"image="識別。固然,這是配合LILO來使用的,但如今誰還適用LILO呢?
(8)*.mod
各類功能模塊,部分模塊已經嵌入到core.img中,或者會被grub自動加載,但有時也須要使用insmod命令手動加載。
grub2的設計方式和傳統grub大不相同,所以和stage之間的對比關係其實沒那麼標準,可是將它們拿來比較也有助於理解img和stage文件的做用。
stage文件也分佈在兩個地方:/usr/share/grub/RELEASE目錄下和/boot/grub目錄下,/boot/grub目錄下的stage文件是安裝grub時從/usr/share/grub/RELEASE目錄下拷貝過來的。
(1)stage1
stage1文件在功能上等價於boot.img文件。目的是跳轉到stage1_5或stage2的第一個扇區上。
(2)*_stage1_5
*stage1_5文件包含了各類識別文件系統的代碼,使得grub能夠從文件系統中讀取體積更大功能更復雜的stage2文件。從這一方面考慮,它相似於core.img中加載對應文件系統模塊的代碼部分,可是core.img的功能遠比stage1_5多。
stage1_5通常安裝在MBR後、第一個分區前的那段空閒空間中,也就是MBR gap空間,它的做用是跳轉到stage2的第一個扇區。
其實傳統的grub在某些環境下是能夠不用stage1_5文件就能正常運行的,可是grub2則不能缺乏core.img。
(3)stage2
stage2的做用是加載各類環境和加載內核,在grub2中沒有徹底與之相對應的img文件,可是core.img中包含了stage2的全部功能。
當跳轉到stage2的第一個扇區後,該扇區的代碼負責加載stage2剩餘的內容。
注意,stage2是存放在磁盤上的,並無像core.img同樣嵌入到磁盤上。
(4)stage2_eltorito
功能上等價於grub2中的core.img中的cdboot.img部分。通常在製做救援模式的grub時纔會使用到cd-rom相關文件。
(5)pxegrub
功能上等價於grub2中的core.img中的pxeboot.img部分。
安裝grub2的過程大致分兩步:一是根據/usr/lib/grub/i386-pc/目錄下的文件生成core.img,並拷貝boot.img和core.img涉及的某些模塊文件到/boot/grub2/i386-pc/目錄下;二是根據/boot/grub2/i386-pc目錄下的文件向磁盤上寫boot loader。
固然,究竟是先拷貝,仍是先寫boot loader,不必去搞清楚,只要/boot/grub2/i386-pc下的img文件必定能經過grub2相關程序再次生成boot loader。因此,既能夠認爲/boot/grub2/i386-pc目錄下的img文件是boot loader的特殊備份文件,也能夠認爲是boot loader的源文件。
不過,img文件和boot loader的內容是不一致的,由於img文件還要經過grub2相關程序來轉換纔是真正的boot loader。
對於傳統的grub而言,拷貝的不是img文件,而是stage文件。
如下是安裝傳統grub時,grub作的工做。很不幸,grub2上沒有該命令,也沒有與之等價的命令。
grub> setup (hd0) Checking if "/boot/grub/stage1" exists... yes Checking if "/boot/grub/stage2" exists... yes Checking if "/boot/grub/e2fs_stage1_5" exists... yes Running "embed /boot/grub/e2fs_stage1_5 (hd0)"... 15 sectors are embedded. succeeded Running "install /boot/grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded Done.
首先檢測各stage文件是否存在於/boot/grub目錄下,隨後嵌入stage1_5到磁盤上,該文件系統類型的stage1_5佔用了15個扇區,最後安裝stage1,並告知stage1 stage1_5的位置是第1到第15個扇區,之因此先嵌入stage1_5再嵌入stage1就是爲了讓stage1知道stage1_5的位置,最後還告知了stage1 stage2和配置文件menu.lst的路徑。
grub2的默認配置文件爲/boot/grub2/grub.cfg,該配置文件的寫法彈性很是大,但絕大多數須要修改該配置文件時,都只需修改其中一小部份內容就能夠達成目標。
grub2-mkconfig程序可用來生成符合絕大多數狀況的grub.cfg文件,默認它會自動嘗試探測有效的操做系統內核,並生成對應的操做系統菜單項。使用方法很是簡單,只需一個選項"-o"指定輸出文件便可。
shell> grub2-mkconfig -o /boot/grub2/grub.cfg
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Simple-configuration.html#Simple-configuration
grub2-mkconfig是根據/etc/default/grub文件來建立配置文件的。該文件中定義的是grub的全局宏,修改內置的宏能夠快速生成grub配置文件。實際上在/etc/grub.d/目錄下還有一些grub配置腳本,這些shell腳本讀取一些腳本配置文件(如/etc/default/grub),根據指定的邏輯生成grub配置文件。如有興趣,不放讀一讀/etc/grub.d/10_linux文件,它指導了建立grub.cfg的細節,例如如何生成啓動菜單。
[root@xuexi ~]# ls /etc/grub.d/ 00_header 00_tuned 01_users 10_linux 20_linux_xen 20_ppc_terminfo 30_os-prober 40_custom 41_custom README
在/etc/default/grub中,使用"key=vaule"的格式,key所有爲大小字母,若是vaule部分包含了空格或其餘特殊字符,則須要使用引號包圍。
例如,下面是一個/etc/default/grub文件的示例:
[root@xuexi ~]# cat /etc/default/grub GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet" GRUB_DISABLE_RECOVERY="true"
雖然可用的宏較多,但可能用的上的就幾個:GRUB_DEFAULT、GRUB_TIMEOUT、GRUB_CMDLINE_LINUX和GRUB_CMDLINE_LINUX_DEFAULT。
如下列出了部分key。
(1).GRUB_DEFAULT
默認的菜單項,默認值爲0。其值可爲數值N,表示從0開始計算的第N項是默認菜單,也能夠指定對應的title表示該項爲默認的菜單項。使用數值比較好,由於使用的title可能包含了容易改變的設備名。例若有以下菜單項:
menuentry 'Example GNU/Linux distribution' --class gnu-linux --id example-gnu-linux { ... }
若是想將此菜單設爲默認菜單,則可設置"GRUB_DEFAULT=example-gnu-linux"。
若是GRUB_DEFAULT的值設置爲"saved",則表示默認的菜單項是"GRUB_SAVEDEFAULT"或"grub-set-default"所指定的菜單項。
(2).GRUB_SAVEDEFAULT
默認該key的值未設置。若是該key的值設置爲true時,若是選定了某菜單項,則該菜單項將被認爲是新的默認菜單項。該key只有在設置了"GRUB_DEFAULT=saved"時纔有效。
不建議使用該key,由於GRUB_DEFAULT配合grub-set-default更方便。
(3).GRUB_TIMEOUT
在開機選擇菜單項的超時時間,超過該時間將使用默認的菜單項來引導對應的操做系統。默認值爲5秒。等待過程當中,按下任意按鍵均可以中斷等待。
設置爲0時,將不列出菜單直接使用默認的菜單項引導與之對應的操做系統,設置爲"-1"時將永久等待選擇。
是否顯示菜單,和"GRUB_TIMEOUT_STYLE"的設置有關。
(4).GRUB_TIMEOUT_STYLE
若是該key未設置值或者設置的值爲"menu",則列出啓動菜單項,並等待"GRUB_TIMEOUT"指定的超時時間。
若是設置爲"countdown"和"hidden",則不顯示啓動菜單項,而是直接等待"GRUB_TIMEOUT"指定的超時時間,若是超時了則啓動默認菜單項並引導對應的操做系統。在等待過程當中,按下"ESC"鍵能夠列出啓動菜單。設置爲countdown和hidden的區別是countdown會顯示超時時間的剩餘時間,而hidden則徹底隱藏超時時間。
(5).GRUB_DISTRIBUTOR
設置發行版的標識名稱,通常該名稱用來做爲菜單的一部分,以便區分不一樣的操做系統。
(6).GRUB_CMDLINE_LINUX
添加到菜單中的內核啓動參數。例如:
GRUB_CMDLINE_LINUX="crashkernel=ro root=/dev/sda3 biosdevname=0 net.ifnames=0 rhgb quiet"
(7).GRUB_CMDLINE_LINUX_DEFAULT
除非"GRUB_DISABLE_RECOVERY"設置爲"true",不然該key指定的默認內核啓動參數將生成兩份,一份是用於默認啓動參數,一份用於恢復模式(recovery mode)的啓動參數。
該key生成的默認內核啓動參數將添加在"GRUB_CMDLINE_LINUX"所指定的啓動參數以後。
(8).GRUB_DISABLE_RECOVERY
該項設置爲true時,將不會生成恢復模式的菜單項。
(9).GRUB_DISABLE_LINUX_UUID
默認狀況下,grub2-mkconfig在生產菜單項的時候將使用uuid來標識Linux 內核的根文件系統,即"root=UUID=..."。
例如,下面是/boot/grub2/grub.cfg中某菜單項的部份內容。
menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8' {
......
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto biosdevname=0 net.ifnames=0 quiet LANG=en_US.UTF-8
initrd16 /initramfs-3.10.0-327.el7.x86_64.img
}
雖然使用UUID的方式更可靠,但有時候不太方便,因此能夠設置該key爲true來禁用。
(10).GRUB_BACKGROUND
設置背景圖片,背景圖片必須是grub可讀的,圖片文件名後綴必須是".png"、".tga"、".jpg"、".jpeg",在須要的時候,grub會按比例縮小圖片的大小以適配屏幕大小。
(11).GRUB_THEME
設置grub菜單的主題。
(12).GRUB_GFXPAYLOAD_LINUX
設置爲"text"時,將強制使用文本模式啓動Linux。在某些狀況下,可能不支持圖形模式。
(13).GRUB_DISABLE_OS_PROBER
默認狀況下,grub2-mkconfig會嘗試使用os-prober程序(若是已經安裝的話,默認應該都裝了)探測其餘可用的操做系統內核,併爲其生成對應的啓動菜單項。設置爲"true"將禁用自動探測功能。
(14).GRUB_DISABLE_SUBMENU
默認狀況下,grub2-mkconfig若是發現有多個同版本的或低版本的內核時,將只爲最高版本的內核生成頂級菜單,其餘全部的低版本內核菜單都放入子菜單中,設置爲"y"將所有生成爲頂級菜單。
(15).GRUB_HIDDEN_TIMEOUT(已廢棄,但爲了向後兼容,仍有效)
使用"GRUB_TIMEOUT_STYLE={countdown|hidden}"替代該項
(16).GRUB_HIDDEN_TIMEOUT_QUIET(已廢棄,但爲了向後兼容,仍有效)
配合GRUB_HIDDEN_TIMEOUT使用,可使用GRUB_TIMEOUT_STYLE=countdown來替代這兩項。
對於特殊的字符須要轉義。有三種方式轉義:使用反斜線、使用單引號、使用雙引號。
反斜線轉義方式和shell同樣。
單引號中的全部字符串都是字面意思,沒有任何特殊意義,即便單引號中的轉義符也被認爲是純粹的字符。因此'\''是沒法保留單引號的。單引號須要使用雙引號來轉移,因此應該寫"'"。
雙引號和單引號做用同樣,但它不能轉義某幾個特殊字符,包括"$"和"\"。對於雙引號中的"$"符號,它任什麼時候候都保留本意。對於"\",只有反斜線後的字符是'$'、'"'、'\'時才表示轉義的意思,另外 ,某行若以反斜線結尾,則表示續行,但官方不建議在grub.cfg中使用續行符。
使用$符號引用變量,也可使用${var}的方式引用var變量。
支持位置變量,例如$1引用的是第一個參數。
還支持特殊的變量,如$?表示上一次命令的退出狀態碼。若是使用了位置變量,則還支持$*、$@和$#,$*表明的全部參數總體,各參數之間是不可分割的,$@也表明全部變量,但$@的各參數是能夠被分割的,$#表示參數的個數。
能夠在grub.cfg中使用簡單的命令。各命令之間使用換行符或分號表示該命令結束。
若是在命令前使用了"!",則表示邏輯取反。
這是grub.cfg中最重要的項,官方原文:https://www.gnu.org/software/grub/manual/html_node/menuentry.html#menuentry
該命令定義了一個名爲title的grub菜單項。當開機時選中該菜單項時,grub會將chosen環境變量的值賦給"--id"(若是給定了"--id"的話),執行大括號中的命令列表,若是直到最後一個命令都所有執行成功,且成功加載了對應的內核後,將執行boot命令。隨後grub就將控制權交給了操做系統內核。
--class:該選項用於將菜單分組,從而使得grub能夠經過主題樣式爲不一樣組的菜單顯示不一樣的樣式風格。一個menuentry中,可使用屢次class表示將該菜單分到多個組中去。
--users:該選項限定只有此處列出的用戶才能訪問該菜單項,不指定該選項時將表示全部用戶都能訪問該菜單。
--unrestricted:該選項表示全部用戶都有權訪問該菜單項。
--hotkey:該選項爲該菜單項關聯一個熱鍵,也就是快捷鍵,關聯熱鍵後只要按下該鍵就會選中該菜單。熱鍵只能是字母鍵、backspace鍵、tab鍵或del鍵。
--id:該選項爲該菜單關聯一個惟一的數值。id的值能夠由ASCII字母、數字//下劃線組成,且不得以數字開頭。
全部其餘的參數包括title都被看成位置參數傳遞給大括號中的命令,但title老是$1,除title外的其他參數,位置值從前向後類推。
具體如何編寫grub.cfg文件,繼續看下文的命令和變量。
官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Commands.html#Commands
grub2支持不少命令,有些命令只能在交互式命令行下使用,有些命令可用在配置文件中。在救援模式下,只有insmod、ls、set和unset命令可用。
無需掌握全部的命令,掌握用的上的幾個命令便可。
help [pattern]
顯示能匹配到pattern的全部命令的說明信息和usage信息,若是不指定patttern,將顯示全部命令的簡短信息。
例如"help cmos"。
用於啓動已加載的操做系統。
只在交互式命令行下可用。其實在menuentry命令的結尾就隱含了boot命令。
set [envvar=value] unset envvar
前者設置環境變量envvar的值,若是不給定參數,則列出當前環境變量。
後者釋放環境變量envvar。
分別用於列出已加載的模塊和調用指定的模塊。
注意,若要導入支持ext文件系統的模塊時,只需導入ext2.mod便可,實際上也沒有ext3和ext4對應的模塊。
linux file [kernel_args] linux16 file [kernel_args]
都表示裝載指定的內核文件,並傳遞內核啓動參數。linux16表示以傳統的16位啓動協議啓動內核,linux表示以32位啓動協議啓動內核,但linux命令比linux16有一些限制。但絕大多數時候,它們是能夠通用的。
在linux或linux16命令以後,必須緊跟着使用init或init16命令裝載init ramdisk文件。
通常爲/boot分區下的vmlinuz-RELEASE_NUM文件。
但在grub環境下,boot分區被看成root分區,即根分區,假如boot分區爲第一塊磁盤的第一個分區,則應該寫成:
linux (hd0,msdos1)/vmlinuz-XXX
或者相對路徑的:
set root='hd0,msdos1'
linux /vmlinuz-XXX
在grub階段能夠傳遞內核的啓動參數(內核的參數包括3類:編譯內核時參數,啓動時參數和運行時參數),能夠傳遞的啓動參數很是很是多,完整的啓動參數列表見:http://redsymbol.net/linux-kernel-boot-parameters。這裏只列出幾個經常使用的:
init= :指定Linux啓動的第一個進程init的替代程序。 root= :指定根文件系統所在分區,在grub中,該選項必須給定。 ro,rw :啓動時,根分區以只讀仍是可讀寫方式掛載。不指定時默認爲ro。 initrd :指定init ramdisk的路徑。在grub中由於使用了initrd或initrd16命令,因此不須要指定該啓動參數。 rhgb :以圖形界面方式啓動系統。 quiet :以文本方式啓動系統,且禁止輸出大多數的log message。 net.ifnames=0:用於CentOS 7,禁止網絡設備使用一致性命名方式。 biosdevname=0:用於CentOS 7,也是禁止網絡設備採用一致性命名方式。 :只有net.ifnames和biosdevname同時設置爲0時,才能徹底禁止一致性命名,獲得eth0-N的設備名。
例如:
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=edb1bf15-9590-4195-aa11-6dac45c7f6f3 ro rhgb quiet LANG=en_US.UTF-8
另外,root啓動參數有多種定義方式,可使用UUID的方式指定,也能夠直接指定根文件系統所在分區,如"root=/dev/sda2",
initrd file
只能緊跟在linux或linux16命令以後使用,用於爲即將啓動的內核傳遞init ramdisk路徑。
一樣,基於根分區,可使用絕對路徑,也可使用相對路徑。路徑的表示方法和linux或linux16命令相同。例如:
linux16 /vmlinuz-0-rescue-d13bce5e247540a5b5886f2bf8aabb35 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet
initrd16 /initramfs-0-rescue-d13bce5e247540a5b5886f2bf8aabb35.img
search [--file|--label|--fs-uuid] [--set [var]] [--no-floppy] [--hint args] name
經過文件[--file]、卷標[--label]、文件系統UUID[--fs-uuid]來搜索設備。
若是使用了"--set"選項,則會將第一個找到的設備設置爲環境變量"var"的值,默認的變量"var"爲'root'。
搜索時可以使用"--no-floppy"選項來禁止搜索軟盤,由於軟盤速度很是慢,已經被淘汰了。
有時候還會指定"--hint=XXX",表示優先選擇知足提示條件的設備,若指定了多個hint條件,則優先匹配第一個hint,而後匹配第二個,依次類推。
例如:
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1' 367d6a77-033b-4037-bbcb-416705ead095
else
search --no-floppy --fs-uuid --set=root 367d6a77-033b-4037-bbcb-416705ead095
fi
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet LANG=en_US.UTF-8
initrd16 /initramfs-3.10.0-327.el7.x86_64.img
上述if語句中的第一個search中搜索uuid爲"367d6a77-033b-4037-bbcb-416705ead095"的設備,但使用了多個hint選項,表示先匹配bios平臺下/boot分區爲(hd0,msdos1)的設備,以後還指定了幾個hint,但由於search使用的是uuid搜索方式,因此這些hint選項是多餘的,由於單磁盤上分區的uuid是惟一的。
再舉個例子,若是某啓動設備上有兩個boot分區(如多系統共存時),分別是(hd0,msdos1)和(hd0,msdos5),若是此時不使用uuid搜索,而是使用label方式搜索:
search --no-floppy --fs-label=boot --set=root --hint=hd0,msdos5
則此時將會選中(hd0,msdos5)這個boot分區,若不使用hint,將選中(hd0,msdos1)這個boot分區。
直接返回true或false布爾值。
計算"expression"的結果是否爲真,爲真時返回0,不然返回非0,主要用於if、while或until結構中。
string1 == string2 |
string1與string2相同 |
string1 != string2 |
string1與string2不相同 |
string1 < string2 |
string1在字母順序上小於string2 |
string1 <= string2 |
string1在字母順序上小於等於string2 |
string1 > string2 |
string1在字母順序上大於string2 |
string1 >= string2 |
string1在字母順序上大於等於string2 |
integer1 -eq integer2 |
integer1等於integer2 |
integer1 -ge integer2 |
integer1大於或等於integer2 |
integer1 -gt integer2 |
integer1大於integer2 |
integer1 -le integer2 |
integer1小於或等於integer2 |
integer1 -lt integer2 |
integer1小於integer2 |
integer1 -ne integer2 |
integer1不等於integer2 |
prefixinteger1 -pgt prefixinteger2 |
剔除非數字字符串prefix部分以後,integer1大於integer2 |
prefixinteger1 -plt prefixinteger2 |
剔除非數字字符串prefix部分以後,integer1小於integer2 |
file1 -nt file2 |
file1的修改時間比file2新 |
file1 -ot file2 |
file1的修改時間比file2舊 |
-d file |
file存在且是目錄 |
-e file |
file存在 |
-f file |
file存在而且不是一個目錄 |
-s file |
file存在而且文件佔用空間大於零 |
-n string |
string的長度大於零 |
string |
string的長度大於零,等價於-n string |
-z string |
string的長度等於零 |
( expression ) |
將expression做爲一個總體 |
! expression |
非(NOT) |
expression1 -a expression2 |
與(AND),也可使用expression1 expression2,但不推薦 |
expression1 -o expression2 |
或(OR) |
讀取文件內容,藉此能夠幫助判斷哪一個是boot分區,哪一個是根分區。
交互式命令行下使用。
清屏。
當即裝載一個指定的文件做爲grub的配置文件。但注意,導入的文件中的環境變量不在當前生效。
在grub.cfg丟失時,該命令將排上用場。
echo [-n] [-e] string
"-n"和"-e"用法同shell中echo。若是要引用變量,使用${var}的方式。
導出環境變量,若在configfile的file中導出環境變量,將會在當前環境也生效。
關機或重啓
ls [args]
若是不給定任何參數,則列出grub可見的設備。
若是給定的參數是一個分區,則顯示該分區的文件系統信息。
若是給定的參數是一個絕對路徑表示的目錄,則顯示該目錄下的全部文件。
例如:
probe [--set var] --partmap|--fs|--fs-uuid|--label device
探測分區或磁盤的屬性信息。若是未指定--set,則顯示指定設備對應的信息。若是指定了--set,則將對應信息的值賦給變量var。
--partmap:顯示是gpt仍是mbr格式的磁盤。
--fs:顯示分區的文件系統。
--fs-uuid:顯示分區的uuid值。
--label:顯示分區的label值。
將環境變量保存到環境變量塊中,以及列出當前的環境變量塊中的變量。
loopback [-d] device file
將file映射爲迴環設備。使用-d選項則是刪除映射。
例如:
loopback loop0 /path/to/image ls (loop0)/
進入和退出normal模式,normal是相對於救援模式而言的,只要不是在救援模式下,就是在normal模式下。
救援模式下,只能使用很是少的命令,而normal模式下則可使用很是多的命令。
password user clear-password password_pbkdf2 user hashed-password
前者使用明文密碼定義一個名爲user的用戶。不建議使用此命令。
後者使用哈希加密後的密碼定義一個名爲user的用戶,加密的密碼經過"grub-mkpasswd-pbkdf2"工具生成。建議使用該命令。
當開機時選中某個菜單項啓動時,該菜單的title將被賦值給chosen變量。該變量通常只用於引用,而不用於修改。
grub2加載的core.img的目錄路徑,是絕對路徑,即包括了設備名的路徑,如(hd0,gpt1)/boot/grub2/。該變量值不該該修改。
指定默認的菜單項,通常其後都會跟隨timeout變量。
default指定默認菜單時,可以使用菜單的title,也可使用菜單的id,或者數值順序,當使用數值順序指定default時,從0開始計算。
設置菜單等待超時時間,設置爲0時將直接啓動默認菜單項而不顯示菜單,設置爲"-1"時將永久等待手動選擇。
當默認菜單項啓動失敗,則使用該變量指定的菜單項啓動,指定方式同default,可以使用數值(從0開始計算)、title或id指定。
指定該平臺是"pc"仍是"efi",pc表示的就是傳統的bios平臺。
該變量不該該被修改,而應該被引用,例如用於if判斷語句中。
在grub啓動的時候,grub自動將/boot/grub2目錄的絕對路徑賦值給該變量,使得之後能夠直接從該變量所表明的目錄下加載各文件或模塊。
例如,可能自動設置爲:
set prefix = (hd0,gpt1)/boot/grub2/
因此可使用"$prefix/grubN.cfg"來引用/boot/grub2/grubN.cfg文件。
該變量不該該修改,且若手動設置,則必須設置正確,不然牽一髮而動全身。
該變量指定根設備的名稱,使得後續使用從"/"開始的相對路徑引用文件時將從該root變量指定的路徑開始。通常該變量是grub啓動的時候由grub根據prefix變量設置而來的。
例如prefix=(hd0,gpt1)/boot/grub2,則root=(hd0,gpt1),後續就可使用相對路徑/vmlinuz-XXX表示(hd0,gpt1)/vmlinuz-XXX文件。
注意:在Linux中,從根"/"開始的路徑表示絕對路徑,如/etc/fstab。但grub中,從"/"開始的表示相對路徑,其相對的基準是root變量設置的值,而使用"(dev_name)/"開始的路徑才表示絕對路徑。
通常root變量都表示/boot所在的分區,但這不是絕對的,若是設置爲根文件系統所在分區,如root=(hd0,gpt2),則後續可使用/etc/fstab來引用"(hd0,gpt2)/etc/fstab"文件。
該變量在grub2中通常不用修改,但若修改則必須指定正確。
另外,root變量還應該於linux或linux16命令所指定的內核啓動參數"root="區分開來,內核啓動參數中的"root="的意義是固定的,其指定的是根文件系統所在分區。例如:
set root='hd0,msdos1'
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet LANG=en_US.UTF-8
initrd16 /initramfs-3.10.0-327.el7.x86_64.img
通常狀況下,/boot都會單獨分區,因此root變量指定的根設備和root啓動參數所指定的根分區不是同一個分區,除非/boot不是單獨的分區,而是在根分區下的一個目錄。
首先寫一個grub.cfg。例如此處,在msdos磁盤上安裝了兩個操做系統,CentOS 7和CentOS 6。
# 設置一些全局環境變量 set default=0 set fallback=1 set timeout=3 # 將可能使用到的模塊一次性裝載完 # 支持msdos的模塊 insmod part_msdos # 支持各類文件系統的模塊 insmod exfat insmod ext2 insmod xfs insmod fat insmod iso9660 # 定義菜單 menuentry 'CentOS 7' --unrestricted { search --no-floppy --fs-uuid --set=root 367d6a77-033b-4037-bbcb-416705ead095 linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro biosdevname=0 net.ifnames=0 quiet initrd16 /initramfs-3.10.0-327.el7.x86_64.img } menuentry 'CentOS 6' --unrestricted { search --no-floppy --fs-uuid --set=root f5d8939c-4a04-4f47-a1bc-1b8cbabc4d32 linux16 /vmlinuz-2.6.32-504.el6.x86_64 root=UUID=edb1bf15-9590-4195-aa11-6dac45c7f6f3 ro quiet initrd16 /initramfs-2.6.32-504.el6.x86_64.img }
而後執行grub安裝操做。
shell> grub2-install /dev/sda
由於本文主要介紹grub2,因此傳統的grub只簡單介紹下,其實前面已經說起了不少傳統grub和grub2的比較了。另外,傳統grub已足夠強大,足夠應付通常的需求。
例如安裝到/dev/sda上。
shell> grub-install /dev/sda
default=0 # 默認啓動第一個系統 timeout=5 # 等待超時時間5秒 splashimage=(hd0,0)/grub/splash.xpm.gz # 背景圖片 hiddenmenu # 隱藏菜單,若要顯式,在啓動時按下ESC title Red Hat Enterprise Linux AS (2.6.18-92.el5) # 定義操做系統的說明信息 root (hd0,0) kernel /vmlinuz-2.6.18-92.el5 ro root=/dev/sda2 rhgb quiet initrd /initrd-2.6.18-92.el5.img
在說明配置方法以前,須要說明一個關鍵點,boot是不是一個獨立的分區,它影響後面路徑的配置。
在一個正常的操做系統中查看/boot/grub/grub.conf文件,能夠在NOTICE段看到提示,說你是否擁有一個獨立的boot分區?若是有則意味着kernel和initrd的路徑是從/開始的而不是/boot開始的,如/vmlinuz-xxx,若是沒有獨立的boot分區,則kernel和initrd的路徑中須要指明boot路徑,例如Boot沒有分區而是在/文件系統下的一個目錄,則/boot/vmlinuz-xxx。
root (hd0,0)定義grub識別的根。通常定義的都是boot所在的分區,grub只能識別hd,因此這裏只能使用hd,hd0表示在第一塊磁盤上,hd0,0的第二個0表示boot在第一個分區上,grub2在分區的計算上是從1開始的,這是傳統grub和grub2不一樣的地方。
kernel定義內核文件的路徑和啓動參數,等價於grub2的linux命令或linux16命令。首先說明參數,ro表示只讀,root=/dev/sda[N]或者root=UUID="device_uuid_num"指定根文件系統所在的分區,這是必須的參數。rhgb表示在操做系統啓動過程當中使用圖形界面輸出一些信息,將其省略能夠加快啓動速度,quiet表示啓動操做系統時靜默輸出信息。再說明路徑,若是是boot是獨立分區的,則kernel的路徑定義方式爲/vmlinuz-xxx,若是沒有獨立分區,則指明其絕對路徑,通常都是在根文件系統下的目錄,因此通常爲/boot/vmlinuz-xxx。
initrd定義init ramdisk的路徑,路徑的定義方式同kernel。除了路徑以外沒有任何參數。
或者使用下圖的UUID的方式。
若是沒有指定root=的選項,將報錯「no or empty root …… dracut…kernel panic」的錯誤。以下圖。