翻譯了grub2官方手冊的絕大部分內容,然後自己整理了一下。因為內容有點雜,所以章節安排上可能不是太合理,敬請諒解。
本文目錄:
1.1 基礎內容
1.2 安裝grub2
#1.3 grub2設定檔
1.4 命令列和選單項目中的指令
#1.5 幾個常見的內建變數
1.6 grub設定與安裝範例
#1.7 傳統grub簡述
#
本文主要介紹的是grub2,在文末對傳統grub進行了簡述,但在grub2的內容部分中包含了許多grub2和傳統grub的對比。
如果只是想知道grub2中的boot.img/core.img/diskboot.img/kernel.img或傳統grub中stage1/stage1_5/stage2檔案的作用,請直接跳至相關內容處閱讀。
官方手冊原文:
只說明幾個主要的:
#1.設定檔的名稱改變了。在grub中,設定檔為grub.conf或menu.lst(grub.conf的一個軟連結),在grub2中改名為grub.cfg。
2.grub2增添了許多語法,更接近腳本語言了,例如支援變數、條件判斷、循環。
3.grub2中,裝置名稱從1開始,而在grub中是從0開始的。
4.grub2使用img文件,不再使用grub中的stage1、stage1.5和stage2。
5.支援圖形介面配置grub,但要安裝grub-customizer包,epel來源提供該套件。
6.在已進入作業系統環境下,不再提供grub指令,也就是不能進入grub互動介面,只有在開機時才能進入,算是一大缺憾。
7.在grub2中沒有了好用的find指令,算是另一大缺憾。
官方手冊原文:
(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文件
官方手冊原文:
#grub2支援兩種方式引導作業系統:
直接引導:(direct-load)直接透過預設的grub2 boot loader來引導寫在預設設定檔中的作業系統
連結:(chain-load)使用預設grub2 boot loader鍊式引導另一個boot loader,該boot loader將引導對應的作業系統
[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
[root@server7 ~]# ls /usr/lib/grub/i386-pc/*.mod | wc -l257[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转换后的内容安装到磁盘的指定位置处。
它们之间更具体的关系见下文。
官方手册原文:
严格地说是core.img的安装位置,因为boot.img的位置是固定在MBR或VBR或EBR上的。
(1).MBR
MBR格式的分区表用于PC BIOS平台,这种格式允许四个主分区和额外的逻辑分区。使用这种格式的分区表,有两种方式安装GURB:
嵌入到MBR和第一个分区中间的空间,这部分就是大众所称的"boot track","MBR gap"或"embedding area",它们大致需要31kB的空间;
将core.img安装到某个文件系统中,然后使用分区的第一个扇区(严格地说不是第一个扇区,而是第一个block)存储启动它的代码。
这两种方法有不同的问题。
使用嵌入的方式安装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一樣。
官方手冊原文:
##img檔案是grub2產生的,stage檔案是傳統grub產生的。下面是各種文件的說明。 1.2.2.1 grub2中的img檔案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.imgcore.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.imgkernel.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
官方手册原文:
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/grubGRUB_TIMEOUT=5GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=trueGRUB_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來取代這兩項。
官方手冊原文:
並非所有的關鍵字都有用,只是為了日後的功能擴展而提前提供的。
该命令定义了一个名为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外的其余参数,位置值从前向后类推。
break [n]:强制退出for/while/until循环
continue [n]:跳到下一次迭代,即进入下一次循环
return [n]:指定返回状态码
setparams [arg] …:从$1开始替换位置参数
shift [n]:踢掉前n个参数,使得第n+1个参数变为$1,但和shell中不一样的是,踢掉了前n个参数后,从$#-n+1到$#这些参数的位置不变
具体如何编写grub.cfg文件,继续看下文的命令和变量。
官方手册原文:
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类:编译内核时参数,启动时参数和运行时参数),可以传递的启动参数非常非常多,完整的启动参数列表见:。这里只列出几个常用的:
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-416705ead
# else
search --no-floppy --fs-uuid --set=root 367d6a77-033b-4037-bbcb-416705ead095
fi
linux16 /vmlinuz-3.100 .0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet LANG=en_US.UTF-8
#init762/10723/10.3/102.1212.212. .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 4acf3e7e42dcf8e07850af308130fa81 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的長度等於零
|
读取文件内容,借此可以帮助判断哪个是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/imagels (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=0set fallback=1set timeout=3# 将可能使用到的模块一次性装载完 # 支持msdos的模块insmod part_msdos # 支持各种文件系统的模块insmod exfatinsmod ext2insmod xfsinsmod fatinsmod 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」的錯誤。如下圖。
#
以上是對grub2的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!