Linux【1】-启动管理-8-7-启动引导程序(GRUB)加载内核

在刚刚的启动过程中,我们已经知道启动引导程序(Boot Loader,也就是 GRUB)会在启动过程中加载内核,之后内核才能取代 BIOS 接管启动过程。如果没有启动引导程,那么内核是不能被加载的。

本节,我们就来看看启动引导程序加载内核的过程,当然 initramfs 这个虚拟文件系统也是要靠启动引导程序调用的。在 CentOS 6.x 中,启动引导程序默认是 GRUB,GRUB 是现在最为流行的启动引导程序,我们也用 GRUB 来说明启动引导程序的作用。

早期的 LILO 引导程序已经不是很常见了,GRUB 相比来讲有很多优势,主要有: 支持更多的文件系统。 GRUB 的主程序可以直接在文件系统中查找内核文件。 在系统启动时,可以利用 GRUB 的交互界面编辑和修改启动选项。 可以动态修改 GRUB 的配置文件,这样在修改配置文件之后不需要重新安装 GRUB,而只需重新启动就可以生效。

一、GRUB加载内核的过程

GRUB 的作用有以下几个:

  • 加载操作系统的内核;
  • 拥有一个可以让用户选择的的菜单,来选择到底启动哪个系统;
  • 可以调用其他的启动引导程序,来实现多系统引导。

按照启动流程,BIOS 在自检完成后,会到第一个启动设备的 MBR 中读取 GRUB。在 MBR 中用来放置启动引导程序的空间只有 446 Byte,那么 GRUB 可以放到这里吗?答案是空间不够,GRUB 的功能非常强大,MBRM 空间是不够使用的。那么 Linux 的解决办法是把 GRUB 的程序分成了三个阶段来执行。

Stage 1:执行GRUB主程序

第一阶段是用来执行 GRUB 主程序的,这个主程序必须放在启动区中(也就是 MBR 或者引导扇区中)。但是 MBR 太小了,所以只能安装 GRUB 的最小的主程序,而不能安装 GRUB 的相关配置文件。这个主程序主要是用来启动 Stage 1.5 和 Stage 2 的。

Stage 1.5:识别不同的文件系统

Stage 2 比较大,只能放在文件系统中(分区),但是 Stage 1 不能识别不同的文件系统,所以不能直接加载 Stage 2。这时需要先加载 Stage 1.5,由 Stage 1.5 来加载不同文件系统中的 Stage 2。

还有一个问题,难道 Stage 1.5 不是放在文件系统中的吗?如果是,那么 Stage 1 同样不能找到 Stage 1.5。其实,Stage 1.5 还真没有放在文件系统中,而是在安装 GRUB 时,直接安装到紧跟 MBR 之后的 32KB 的空间中,这段硬盘空间是空白无用的,而且是没有文件系统的,所以 Stage 1 可以直接读取 Stage 1.5。读取了 Stage 1.5 就能识别不同的文件系统,才能加载 Stage 2。

Stage 2:加载GRUB的配置文件

Stage 2 阶段主要就是加载 GRUB 的配置文件 /boot/grub/grub.conf,然后根据配置文件中的定义,加载内核和虚拟文件系统。接下来内核就可以接管启动过程,继续自检与加载硬件模块了。

二、/boot/grub/目录分析

本章第一节就已经讲过,BIOS 在进行完成系统检测之后,就会找到第一个可以启动的设备,并读取该设备的 MBR(主引导记录)以及加载 MBR 中的 boot loader(启动引导程序),这个启动引导程序可以具有菜单功能、直接加载核心文件以及控制权移交的功能等。

另外我们还知道,系统必须要借助启动引导程序,才能加载内核,那么问题来了,MBR 只是占据整个设备的第一个扇区中,其大小也就只有 446 字节而已,但启动引导程序功能这么强大,光程序代码即配置数据就肯定不止 446 字节,是怎么安装的吗?

是这样的,Linux 系统将启动引导程序的程序代码运行与配置数据加载分为以下 2 个阶段:

  • 第一个阶段负责运行启动引导的主程序,该主程序必须要被安装在启动区,或者是 MBR,或者是引导扇区,但我们说过,MBR 的容量实在太小啦,因此,MBR 或引导扇区通常只安装启动引导程序的最小主程序,并不安装相关的配置数据;
  • 第二个阶段是为主程序加载配置文件,包括相关的环境参数文件(文件系统定义以及主要配置文件 menu.1st);

其中,与 GRUB(启动引导程序)相关的配置文件,都放置在 /boot/grub 目录中。我们来看看这个目录下到底有哪些文件。

[root@localhost ~]# cd /boot/grub/
[root@localhost grub]# ll -h
总用量274K
-rw-r--r--. 1 root root 63 4月 10 21:49 device.map
#GRUB中硬盘的设备文件名与系统的设备文件名的对应文件
-rw-r--r--. 1 root root 14K 4月 10 21:49 e2fs_stage1_5 #ext2/ext3文件系统的Stage 1.5文件
-rw-r--r--. 1 root root 13K 4月 10 21:49 fat_stage1_5
#FAT文件系统的Stage 1文件
-rw-r--r--. 1 root root 12K 4月 10 21:49 ffs_stage1_5
#FFS文件系统的Stage 1.5文件
-rw-------.1 root root 737 4月 10 21:49 grub.conf
#GRUB的配置文件
-rw-r--r--. 1 root root 12K 4 月 10 21:49 iso9660_stage1_5
#iso9660文件系统的Stage 1.5文件
-rw-r--r--. 1 root root 13K 4月 10 21:49 jfs_stage1_5
#JFS文件系统的Stage 1.5文件
Irwxrwxrwx. 1 root root 11 4月 10 21:49 menu.lst ->./grub.conf
#GRUB的配置文件。和grub.conf是软链接,所以两个文件修改哪一个都可以
-rw-r--r--. 1 root root 12K 4 月 10 21:49 minix_stage1_5
#MINIX文件系统的Stage 1.5文件
-rw-r--r--. 1 root root 15K 4 月 10 21:49 reiserfs_stage1_5
#ReiserFS文件系统的Stage 1.5文件
-rw-r--r--. 1 root root 1.4K 11 月 15 2010 splash.xpm.gz
#系统启动时,GRUB程序的背景图像
-rw-r--r--. 1 root root 512 4月 10 21:49 stage1
#安装到引导扇区中的Stage 1的备份文件
-rw-r--r--. 1 raot root 124K 4月 10 21:49 stage2 #Stage2的备份文件
-rw-r--r--. 1 root root 12K 4月 10 21:49 ufs2_stage1_5
#UFS文件系统的Stage 1.
-rw-r--r--. 1 root root 12K 4 月 10 21:49 vstafs_stage1_5
#vstafs文件系统的Stage 1.5文件
-rw-r--r--. 1 root root 14K 4月 10 21:49 xfs_stage1_5
#XFS文件系统的Stage 1.5文件

可以看到,这个目录中主要就是 GRUB 的配置文件和各种文件系统的 Stage1.5 文件。不过 GRUB 的配置文件有两个:/boot/grub/grub.conf 和 /boot/grub/menu.lst,这两个配置文件是软链接,所以修改哪一个都可以。

三、GRUB磁盘分区表示法

我们已经知道 Linux 系统分区的设备文件名的命名是有严格规范的,类似于 /dev/sda1 代表第一块 SCSI 硬盘的第一个主分区。但是在 GRUB 中分区的表示方法却完全不同,采用了类似 hd(0,0) 的方式来表示分区。

其实也很好理解,其中:

  • hd 代表硬盘,不再区分是 SCSI 接口硬盘,还是 IDE 接口硬盘,都用 hd 代表;
  • 第一个 0 代表 Linux 系统查找到的第一块硬盘,第二块硬盘为 2,以此类推;
  • 第二个 0 代表这块硬盘的第一个分区,以此类推;

也就是说,hd(0,0) 代表的是第一块硬盘的第一个分区,和 Linux 系统中 /dev/sda1 的含义类似,只是不再区分是 SCSI 硬盘还是 IDE 硬盘。我们用表 1 来说明一下 Linux 系统对分区的描述和 GRUB 中对硬盘的描述。

表 1 分区表示

硬 盘	分 区	Linux中的设备文件名	GRUB中的设备文件名
第一块SCSI硬盘	第一个主分区	/dev/sdal	hd(0,0)
                第二个主分区	/dev/sda2	hd(0,1)
				扩展分区	/dev/sda3	hd(0,2)
				第一个逻辑分区	/dev/sda5	hd(0,4)

第二块SCSI硬盘	第一个主分区	/dev/sdb1	hd(1,0)
				第二个主分区	/dev/sdb2	hd(1,1)
				扩展分区	/dev/sdb3	hd(1,2)
				第一个逻辑分区	/dev/sdb5	hd(1,4)

四、 /boot/grub/grub.conf(GRUB配置文件)内容详解

本节,我们就来看看 GRUB 的配置文件 /boot/grub/grub.conf 中到底写了什么。命令如下:

[rootdlocalhost ~]# vi /boot/grub/grub.conf
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
#以上为GRUB的整体设置
title CentOS (2.6.32-279.el6.i686)
root (hdO,0)
kernel /vmlinuz-2.6.32-279.el6.i686 ro root=OOID=b9a7ala8-767f-4a87-8a2b-a535edb362c9 rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel= auto LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-279.el6.i686.img

这个文件的内容可以分成两部分:前 4 行为 GRUB 的整体设置;title 以下 4 行为要启动的 CentOS 系统的具体配置。这里只安装了一个系统,如果多系统并存,那么每个系统都会有类似的 title 行存在(不一定都是 4 行)。

我们先看整体设置:

  • default=0:默认启动第一个系统。也就是说,如果在等待时间结束后,用户没有选择进入哪个系统,那么系统会默认进入第一个系统。如果有多系统并存,那么每个系统都会有自己的 title 字段,如果想要默认进入第二个系统,这里就可以设为 default=1。
  • timeout=5:等待时间,默认是 5 秒。也就是在进入系统时,如果 5 秒内用户没有按下任意键,那么系统会进入 default 字段定义的系统。当然,也可以手工修改这个等待时间,如果timeout=0,则不会等待直接进入系统;如果 timeout=-1,则会一直等待用户输入,而不会自动进入系统。
  • splashimage=(hd0,0)/gnjb/splash.xpm.gz:用来指定 GRUB 启动时的背景图像的保存位置。记得 CentOS 6.x 启动时后台的蓝色图像吧,就是这个文件的作用。不过这个文件具体在哪里呢?我们已经说过,hd(0,0) 代表第一块硬盘的第一个分区,而笔者的系统在安装时 /boot 分区就是第一个分区,所以这个背景图像的实际位置就是 /boot/gmb/splash.xpm.gz。
  • hiddenmenu:隐藏菜单。启动时默认只能看到读秒,而不能看到菜单。如果想要看到菜单,则需要按任意键。如果注释了这句话,那么启动时就能直接看到菜单了。

再来介绍 CentOS 系统的具体配置:

  1. title CentOS(2.6.32-279.d6.i686):title 就是标题的意思,也就是说,在 title 后面写入的是什么,系统启动时在 GRUB 的启动菜单中看到的就是什么。
  2. root(hd0,0):是指启动程序的保存分区。这里要注意,这个 root 并不是管理员。在我的系统中,/boot 分区是独立划分的,而且设备文件名为 /dev/sda1,所以在 GRUB 中就被描述为 hd(0,0)。
  3. kernel /vmlinuz-2.6.32-279.el6.i686 ro root=UUID=b9a7a1a8-767f-4a87-8a2b-a535edb362c9 rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=auto LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet。其中:
  • /vmlinuz-2.6.32-279.el6.i686:指定了内核文件的位置,这里的 / 是指 boot 分区。
  • ro:启动时以只读方式挂载根文件系统,这是为了不让启动过程影响磁盘内的文件系统。
  • root=UUID=b9a7a1 a8-767f-4a87-8a2b-a535edb362c9:指定根文件系统的所在位置。这里和以前的Linux版本不太一样了,不再通过分区的设备文件名或卷标号来指定,而是通过分区的 UUID 来指定的。

那么,如何査询分区的 UUID 呢?方法有很多种,最简单的办法就查询 /ec/fstab 文件。命令如下:

[root@localhost ~]# cat /etc/fstab | grep"/ "
UUID=b9a7a1a8-767f-4a87-8a2b-a535edb362c9 / ext4 defaults 1 1

可以看到"/“分区的 UUID 和 kernel 行中的 UUID 是匹配的。注意一下 grep 后的”/",在"/“后是有空格的。

以下禁用都只是在启动过程中禁用,是为了加速系统启动的:

rd_NO_LUKS:禁用 LUKS,LUKS 用于给磁盘加密。
rd_NO_MD:禁用软 RAID。
rd_NO_DM:禁用硬 RAID。
rd_NO_LVM:禁用 LVM。

除了以上这样,命令输出信息中还包含以下内容:

KEYBOARDTYPE=pc KEYTABLE=us:键盘类型。
crashkernel=auto:自动为crashkernel预留内存。
LANG=zh_CN.UTF-8:语言环境。
rhgb:(redhatgraphics boot)用图片来代替启动过程中的文字信息。启动完成之后可以使用dmesg命令来查看这些文字信息。
quiet:隐藏启动信息,只显示重要信息。
initrd/initramfs-2.6.32-279.el6.i686.img:指定了initramfs虚拟文件系统镜像文件的所在位置。

GRUB的配置文件的内容就是这样的,主要是 kernel 行较为复杂。不过,在这个 /boot/gmb/grub.conf 配置文件中,只启动了一个 Linux 系统。如果在 Linux 服务器中 既安装了 Linux 系统,又安装了 Windows 系统,那么 GRUB 的配置文件又是什么样子的呢?

五、多系统并存的GRUB配置文件内容分析

其实每个系统都是用 title 字段来表示的,如果在服务器中又多了一个 Windows 系统,那么在 GRUB 的配置文件中只不过就是多了一个 title 字段而已。不过要注意,我们一般建议先安装 Windows 系统,后安装 Linux 系统。

原因是 Windows 系统的启动引导程序无法把启动过程转交到 Linux 系统的 GRUB 中,自然就不能启动 Linux 系统了。如果我们后安装 Linux 系统,GRUB 就会安装到 MBR 中,覆盖 Windows 系统的启动引导程序。而 GRUB 是可以把启动过程转交到 Windows 系统的启动引导程序中的,所以 Windows 系统和 Linux 系统都可以顺利启动。

当然,如果真的是后安装 Windows 系统,则也可以通过手工再安装一次 GRUB 来覆盖 MBR 中的 Windows 系统的启动引导程序,具体方法后续章节会讲。

那么我们就来看看 Windows 和 Linux 双系统并存的 GRUB 的配置文件是什么样子的。命令如下:

[root@localhost ~]#vi /boot/gmb/gmb.conf
default:0
timeout=-1
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu

title WinXp
rootnoverify (hd0,0)
#指定Windows XP的启动分区。是第一块硬盘的第一个分区
#rootnoverify是不检测此分区的意思
makeactive
#设定分区为激活状态
chainloader +1
#把启动过程转交给此分区的第一个扇区

title CentOS (2.6.32-279.el6.i686)
root (hd0,5)
#Linux系统的/boot分区安装到了第一块硬盘的第六个分区中
kemel/vmlinuz-2.6.32-279.el6.i686 ro
root=UUID=23e5c9d6-77a8-403a-8c0e2bfeffcab5ef rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=auto LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet
initrd/initramfs-2.6.32-279.el6.i686.img

配置文件的变化主要是多了 WinXP 这一段。rootnoverify(hd0,0) 字段说明这个分区不检测,同时标称了 Windows 系统的启动分区在第一块硬盘的第一个分区中。也就是 Windows 系统的 C: 盘在第一块硬盘的第一个分区中。chainloader+1 的意思是,GRUB 会把启动过程转交到位于这个分区的第一个扇区(启动扇区)中的引导程序中。

我们已经知道,为了实现多系统启动,除 MBR 中可以安装启动引导程序外,每个分区的第一个扇区也可以安装启动引导程序。在这个例子中,Windows 系统的启动引导程序就被安装到了 C: 盘所在分区的启动扇区中,chainloader+1 就是 GRU 把启动过程交给了 Windows 系统的启动引导程序,所以可以启动 Windows 系统。

六、GRUB手动安装方法详解

需要手工安装 GRUB 主要有两种情况:

  1. Linux 系统原先不是使用 GRUB 作为引导程序而现在想要使用 GRUB 来作为引导程序;
  2. MBR 中的引导程序被覆盖,需要在 MBR 中重新安装 GRUB,如先安装了 Linux 系统,后安装了 Windows 系统。

下面,我们分别介绍这两种情况如何手工安装 GRUB 引导程序。

6.1 系统中没有GRUB,需要手工安装

我们先来讲第一种情况,就是 Linux 系统中没有安装 GRUB,我们需要重新安装 GRUB;或者打算把不是启动分区的某个分区变成启动分区。比如我的系统中新建了一个分区 /dev/sdb1,并挂载到了 /tdisk/ 目录上,我们查看一下新建立的分区,命令如下:

[root@localhost ~]# df
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/sda3 19923216 1787736 17123412 10% /
tmpfs 312672 0 312672 0% /dev/shm
/dev/sda1 198337 26359 161738 15% /boot
/dev/sdb1 2071384 68632 1897528 4% /tdisk

这个分区是我手工建立的,当然不是系统的默认启动分区(系统默认启动分区是 /boot 分区)。我们用这个分区模拟一个不是采用 GRUB 作为默认引导程序的 Linux 硬盘,在这个分区中手工安装 GRUB 引导程序。也就是说,这个实验成功后,/boot 分区可以启动系统,/tdisk 分区也可以启动系统。

具体安装步骤如下:

1) 使用 grul-install 命令在要启动的分区中安装 GRUB 相关文件

在 /boot 分区中有一个 /boot/grub/ 目录,这个目录中保存的就是 GRUB 的相关文件(如文件系统的 Stage 1.5 文件)。我们查看一下 /boot 分区中的这个目录,如下:

[root@localhost ~]#ls /boot/grub/
device.map ffs_stage1_5 jfs_stage1_5 reiserfs_stage1_5 stage2
xfs_stage1_5 e2fs_stage1_5 grub.conf menu.lst splash.xpm.gz
ufs2_stage1_5 fat_stage1_5 iso9660_stage1_5 minix_stage1_5 stage1
vstafs_stage1_5

但是在 /tdisk 目录中并不存在这些文件,所以第一步就是要在 /tdisk 目录中安装这些 GRUB 相关文件,具体采用 grub-install 命令。这个命令的格式如下:

[root@localhost ~]# grub-install [选项] 设备文件名

选项:

-1-root-directory=DIR:DIR 为实际目录,也就是手工指定 GRUB 相关文件的安装目录;

【例 1】命令标准格式。

[root@localhost ~]# gmb-install /dev/sda
#因为默认 GRUB 就是安装到 /dev/sda 中的,所以不需要指定 --root-directory 选项

我们需要把 GRUB 安装到 /tdisk 分区,所以需要执行以下命令:

[root@localhost ~]# grub-install --root-directory=/tdisk/dev/sdb1
#把GRUB安装至/tdisk分区
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/tdisk/boot/ grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-rnn the script 'grub-install'.
(fd0) /dev/fd0
(hd0) /dev/sda
(hd1) /dev/sdb
#说明安装的设备文件名

查看一下:

[root@localhost ~]# ll /tdisk/boot/grub/
总用量272
-rw-r--r--. 1 root root 45 5 月 22 23:51 device.map
-rw-r--r--. 1 root root 13392 5 月 22 23:51 e2fs_stage1_5
-rw-r--r--. 1 root root 12632 5 月 22 23:51 fat_stage1_5
-rw-r--r--. 1 root root 11760 5 月 22 23:51 ffs_stage1_5
-rw-r--r--. 1 root root 11768 5 月 22 23:51 iso9660_stage1_5
-rw-r--r--. 1 root root 13280 5 月 22 23:51 jfs_stage1_5
-rw-r--r--. 1 root root 11968 5 月 22 23:51 minix_stage1_5
-rw-r--r--. 1 root root 14424 5 月 22 23:51 reiserfs_stage1_5
-rw-r--r--. 1 root root 512 5月 22 23:51 stage1
-rw-r--r--. 1 root root 125984 5月 22 23:51 stage2
-rw-r--r--. 1 root root 12036 5 月 22 23:51 ufs2_stage1_5
-rw-r--r--. 1 root root 11376 5 月 22 23:51 vstafs_stage1_5
-rw-r--r--. 1 root root 13976 5 月 22 23:51 xfs_stage1_5

GRUB 的相关文件已经安装到 /tdisk/boot/grub/ 目录中。当然,这些文件还是需要 GRUB 的配置文件来读取的。大家注意到了吗? /tdisk/boot/grub/ 目录中没有 grub.conf 或 menu.lst 配置文件,这些配置文件还是需要依赖 /boot/grub/ 目录的。

注意,如果系统中没有 grul-install 命令,则说明没有 GRUB 软件,这时可以源码包安装,也可以 RPM 包安装。RPM 包的安装命令如下:

[root@localhost ~]# rpm -ivh /mnt/cdrom/Packages/ grub-0.97-77.el6.i686.rpm

2) 修改GRUB的配置文件

在我们的实验中,GRUB 是已经安装好的,所以可以直接修改 /boot/grub/gmb.conf 配置文件。但如果是没有安装过 GRUB 的 Linux 系统手工安装 GURB,就需要自己建立 GRUB 配置文件了。那么我们修改 /boot/grub/grub.conf 配置文件如下:

[root@localhost ~]# vi /boot/gmb/grub.conf
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-279.el6.i686)
root(hd0,0)
kemel/vmlinuz-2.6.32-279.el6.i686 ro
root=UUID=b9a7a1 a8-767f-4a87-8a2ba535edb362c9 rd_NO_LUKS
KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkemel=auto
LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet
initrd/initramfs-2.6.32-279.el6.i686.img title CentOS tdisk #给自己这个启动分区起个名字吧
root(hd1,0)
#注意启动分区的位置是/dev/sdb1,也就是/tdisk目录
chainloader +1
#使用当前分区所在的启动扇区启动系统

在 title CentOS tdisk 段中不能指定内核镜像和 initramfs 虚拟文件系统,因为在 /tdisk/boot/ 目录中只有 grub 目录,而没有内核镜像文件和 initramfs 虚拟文件系统的镜像文件,所以需要通过 chainloader 来调用启动扇区。

3) 安装GRUB到/dev/sdb1分区的启动扇区中

刚刚通过 GRUB 配置文件中的 chainloader 来调用启动扇区,但是 /dev/sdb1 这个分区是新建立的,它的启动扇区中并没有 GRUB 程序。所以最后一步就是要在 /dev/sdb1 分区的启动扇区中安装 GRUB。这时就要利用 GRUB 交互模式了,如下:

[root@localhost boot]# grub
#启动进入GRUB交互模式
grub> root (hd0,0)
root (hd0,0)
Filesystem type is ext2fs, partition type 0x83
#设定GRUB的主目录,这里只能是(hd0,0),因为内核和虚拟文件系统安装在/dev/sdal中,也就是/boot分区中
grub> find /boot/gnab/stagel
find /boot/grub/stagel (hd1,0)
#查询一下Stage 1安装的分区
#好像有一点问题,我们在/boot和/tdisk分区中都安装了GRUB,只看到了/tdisk分区
grub> find /gcub/stagel
find /grub/stagel (hd0,0)
#只有这样才能看到/boot分区中的Stage 1。因为/boot分区是一个单独分区。上面能看到是因为/tdisk才是分区,而/boot/grub/只是/tdisk分区中的目录
grub> find /vmlinuz-2.6.32-279.el6.1686
find /vmlinuz-2.6.32-279.el6.i686 (hd0,0)
#能够查到内核位置。注意不能通过/boot/vmlinuz-2.6.32-279.el6.i686查询,还是因为/boot是单独分区。但是这次/tdisk分区中没有内核
grub> setup (hd1,0)
setup (hd1,0)
Checking if "/boot/grub/stagel" exists... no
Checking if "/grub/stagel" exists... yes
Checking if "/grub/stage2" exists... yes
Checking if "/grub/e2fs_stage1_5" exists... yes
Running "embed /grub/e2fs_stage1_5 (hd1,0)"... failed (this is not fatal)
Running "embed /grub/e2fs_stage1_5 (hd0,0)"... failed (this is not fatal)
Running "install /grub/stagel d (hd1,0) /grub/stage2 p /grub/grub.conf "...
succeeded
Done
#在/tdisk分区的启动扇区中安装GRUB吧。虽然有两个failed,但这只是两个文件系统的Stage 1.5文件没有安装,并不影响
grub> quit
#退出GRUB交互界面

这时 GRUB 安装完成了,可以重新启动试验一下了。重启后可以看到图 1 所示的界面。

图 1 GRUB界面

当然 /tdisk 分区中并没有真正的内核,所以最终还是要靠 /boot 分区启动。如果是多内核并存的,就可以真正启动了。

总结一下,在 Linux 系统中安装 GRUB,或者在新分区中安装 GRUB 的步骤如下:

  • 需要在 Linux 系统的指定分区中安装 GRUB 的相关文件。这是通过 grub-stall 命令实现的。
  • 需要按照要求修改 GRUB 的配置文件,也就是 /boot/gmb/grub.conf。
  • 需要在分区的启动扇区中安装 GRUB,这是通过 grub 命令的交互模式实现的。 M

6.2 BR中的GRUB被覆盖,需要重新安装GRUB

这种情况最常见的就是先安装了 Linux 系统,后安装了 Windows 系统,导致 MBR 中的 GRUB 被覆盖。而 Windows 系统的启动引导程序又不能识别 Linux 系统,从而导致 Linux 系统不能正常启动。

这种情况解决起来比第一种要简单得多,因为不需要安装 GRUB 的相关文件和修改 GRUB 的配置文件,也就是第一种情况的第一步和第二步不需要执行,因为这是已经安装和修改好的。只需要执行第三步,覆盖 MBR 中的启动引导程序即可。

但是这里的问题是,应该在什么地方启动 GRUB 的交互模式呢?第一种情况是,我们是在 Linux 的命令行中执行 grub 命令,来启动 GRUB 交互模式。第二种情况是已经不能正常启动 Linux 系统了,当然也就没有 Linux 的命令行了。在这种情况下,我们需要先利用 Linux 的光盘修复模式,使用光盘来启动 Linux,进入 Linux 的命令行,再指定 grub 命令。Linux 的光盘修复模式将在后续章节中介绍。

我们先假设已经进入了光盘修复模式中的 Linux 命令行,那么只需执行如下命令即可:

sh-4.1#grub
#启动GRUB交互界面。注意到了吗?提示符不一样了,那是因为系统是从光盘启动的,所以环境变量没有生效
gmb>root (hd0.0)
#同样需要设置GRUB的主目录
grub>setup (hd0)
#直接把GRUB安装到MBR中,所以不需要指定分区
grub>quit
#退出

重启系统之后,就可以发现熟悉的 GRUB 界面又回来了。这种安装 GRUB 的方式要比第一种情况简单,因为这并不是全装,仅仅是覆盖安装而已。

七、GRUB加密方法详解

Linux 在启动时,在 GRUB 管理界面中是可以通过按"e"键进入编辑模式,修改启动选项的。

如图 1 所示,每个启动选项都支持按"e"键进入编辑模式。在编辑模式中可以修改启动模式,比如进入单用户模式(单用户模式主要用于破解密码,我们将在后续章节中讲 解)。

但是有时候,我们不想让用户进入编辑模式,就需要给 GRUB 菜单加密。那么,如何生成加密的密码串呢?可以通过命令 grub-md5-crypt 来实现。命令如下:

[root@localhost ~]# grub-md5-crypt
Password:
Retype password:
#输入两次密码
$1$Y84LB1$8tMY2PibScmuOCc8z8U35/
#生成加密的密码串

这样就可以生成加密的密码串,这个字符串是采用 MD5 加密的,我们会利用这个加密的密码串来加密 GRUB 配置文件。

GRUB 的加密有两种模式:

  • 给每个启动菜单加密,如果不输入正确的密码,则系统不能正常启动;
  • 给 GRUB 菜单整体加密,如果想进入编辑模式,则必须输入正确的密码;

7.1 给每个启动菜单加密

如果给每个启动菜单加密,那么系统在启动时进入相应的启动菜单,必须输入正确的密码,否则系统不能启动。具体的方法如下:

[root@localhost ~]# vi /boot/grub/grub.conf
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-279.el6.i686)
password --md5 $l$Y84LBl$8tHY2PibScmuOCc8z8D35/
#加入password选项,密码串是通过grub-md5-crypt命令生成的
root(hd0,0)
kernel /vmlinuz-2.6.32-279.el6•i686 ro root=UUID=b9a7ala8-767f-4a87-8a2b-a535edb362c9 rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us rd_N0_MD crashkernel=auto LANG=zh_CN.UTF-8 rd_N0_LVM rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-279.el6.i686.img

这样就能加密 CentOS 启动菜单了,在启动时如果不输入正确的密码,是不能启动系统的。需要注意的是,password 选项一定要在 title 下面第一行。

7.2 给GRUB菜单整体加密

如果只是加密单个启动菜单,那么 GRUB 的编辑模式是不能被锁定的,仍然可以按"e"键进入编辑模式。而且在进入编辑模式后,是可以删除 password 字段的,再按"b”(boot启动)键就可以不用密码直接进入系统。这时就需要给 GRUB 菜单整体加密。在整体加密后,如果想进入 GRUB 编辑界面,则必须输入正确的密码。加密方法其实只是把 password 字段换一个位置而已,具体方法如下:

[root@localhost ~]# vi /boot/grub/grub.conf
default=0
timeout=5
password --md5 $l$Y84LBl$8tMY2PibScmuOCc8z8U35/
#将password选项放在整体设置处
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-279.el6.i686)
root (hd0,0)
kernel /vmlinuz-2.6.32-279.el6.i686 ro root=UUID=b9a7ala8-767f-4a87-8a2b-a535edb362c9 rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=auto LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-279.el6.i686.img

这样就会把 GRUB 界面整体加密,要想进入 GRUB 的编辑界面,必须先输入正确的密码,如图 2 所示。

注意到了吗?在 GRUB 界面中已经看不到"e"键了,必须输入"p"键,并输入正确的密码才能进入编辑界面。但是这样加密,在启动 CentOS 时,是不需要密码就能正常启动的。如果既需要 GRUB 的整体加密,又需要系统启动时输入正确的密码,应该怎么做呢?

很简单,方法如下:

default=0
timeout=5
password --md5 $l$Y84LBl$8tHY2PibScmuOCc8z8U35/
splashimage=(hdO,0)/grub/splash.xpm.gz hiddenmenu
title CentOS (2.6.32-279.el6.i686) lock
#在title字段下加入lock选项,代表锁死,如果不输入正确的GRUB密码,则不能启动root(hd0,0)
kernel /vmlinuz-2.6.32-279.el6.i686 ro root=UUID=b9a7ala8-767f-4a87-8a2b-a535edb362c9 rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=auto LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet
initrd / initramf s-2.6.32-27.9 .el6.i686. img

只要在 GRUB 整体配置中加入 password 选项,在 title 中加入 lock 选项,就可以既加密 GRUB 编辑界面,又加密系统启动过程了。是不是很简单?

八、报错

8.1 dracut-initqueue timeout and could not boot – warning /dev/disk/by-id/md-uuid- does not exist

报错的界面:

开机以后按F12,进入的界面

报错原因:

/dev/sda5 挂载到根目录;我通过fdisk 删除了/dev/sda2和/dev/sda4,导致/dev/sda对应的UUID不对应了。

解决办法:

方法一:

报错模式下,可以直接输入 exit 么?

方法二:

在centos7中:在登录内核界面,敲c,进入grub命令行界面。

救援模式可用命令:

救援模式中,可用命令很少

  • set:查看环境变量,这里可以查看启动路径和分区。
  • ls:查看设备
  • insmod:加载模块
  • root:指定用于启动系统的分区,在救援模式下设置grub启动分区
  • prefix:设定grub启动路径
1.罗列所有的磁盘区块:
grub>ls

我的是(hd0),(hd0,msdos1),(hd0,msdos2)

2.确定boot分区:

如果boot不是独立分区则使用

ls (hd0,X)/boot/grub

如果boot为独立分区则使用

ls(hd0,X)/grub2

如果存在,则列出该文件夹里的所有文件,不存在则会报错。

会有如下的输出:

-grub2  grub  grub.cfg  i386-pc ...

然后

grub rescue> ls (hd0,msdos2)/grub2 // 找到/boot分区位置
--> grub2 grub grub.cfg i386-pc ...

找到了boot分区,接下来进行手动引导来进入系统,步骤如下:

grub>insmod xfs
grub>set root=(hd0,msdos1) #为你上一步找到的boot分区
grub> linux16 /vmlinuz-xxxxx root=/dev/sda3
grub> initrd16 /initramfs-.xxxxx.img 

#这两行的xxxxx为你的操作系统内核版本号,操作中直接tab就可以出来选项了
#linux16或者linuxefi命令指定内核的位置,基于上一步指定的根的位置
#root=/dev/sda3 指定系统实际的/分区

grub>boot

​ 执行完之后我的机子进入菜单模式,系统可以正常启动了 (这里不需要reboot哈,不需要重新启动)

​ 接下来进行grub的修复,不修复的话下次重启还是会进入grub命令行模式

​ 首先查看你的/boot/grub2/grub.cfg文件,发现没有,用以下命令来修复

[root@localhost ~]#grub2-mkconfig -o /boot/grub2/grub.cfg

参考资料

药企,独角兽,苏州。团队长期招人,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn