侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 743 篇文章
  • 累计创建 64 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Linux基础(57)之GRUB引导加载器的基本应用

zze
zze
2019-12-15 / 0 评论 / 0 点赞 / 803 阅读 / 9236 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

GRUB 全称为“Grand Unified BootLoader”,目前有两个大版本:

  • grub 0.x:grub legacy,传统 grub;
  • grub 1.x;grub 2,完全重写的,在实现上有巨大变化,只是在某些工作特性上仍然兼容 grub legacy;

grub的组成

grub 由三部分组成:

  • stage1:bootloader,存放在 mbr 分区的前 446 字节中;
  • stage1_5:mbr 之后的扇区,作用是让 stage1 中的 bootloader 能驱动识别 stage2 所在分区上的文件系统;
  • stage2:存放在磁盘分区上,一般在 /boot/grub/ 下;

它的配置文件为 /boot/grub/grub.conf/etc/grub.conf 是它的链接文件。

当系统启动时,当前硬件平台上的 BIOS 必须能识别硬盘,然后 BIOS 才能够帮我们加载硬盘中的 mbr 区,在 mbr 中存放了 grub 的 stage1,从而能加载到 stage1,然后会尝试去读取 mbr 随后扇区中的 stage1_5,这个 stage1_5 读到之后,就能够借助它来驱动 stage2 所在的磁盘分区(该分区还存有内核文件、ramdisk 或 ramfs,这也是 grub 随后能加载到内核文件的原因)。
stage2 及内核等通常放置于一个基本的磁盘分区,可以理解,因为 stage1_5 阶段不可能过于复杂,如果 stage2 所在的磁盘分区过于复杂,stage1_5 未必能帮助 stage1 驱动该磁盘分区,从而也不能找到 stage2,导致 grub 无法启动。

grub的功用

这部分功用其实是 stage2 的,mbr 中的 446 字节显然不可能完成如此强大的功能。

1、提供菜单,并提供交互式接口;

  • e:编辑模式,用于编辑菜单;
  • c:命令模式,打开内置的命令提示符,是一个交互式接口;

2、加载用户选择的内核或操作系统;

  • 允许传递参数给内核;
  • 可隐藏菜单;

3、为菜单提供了保护机制;

  • 为编辑菜单进行认证;
  • 为启动内核或操作系统进行认证;

grub寻找stage2和内核

上面有提到过,grub 的 stage2 和配置文件一般是存放于 /boot/grub/ 目录下,查看该目录:

image.png

这个 /boot 目录可分为两种情况:

  1. 根文件系统位于一个分区,/boot 就仅仅是根文件系统上的一个目录,该目录中存放了内核以及 grub;
  2. 根文件系统位于分区 1,内核和 grub 位于分区 2,而根文件系统上的 /boot 目录其实是分区 2 的挂载点;

在 grub 启动时操作系统是未启动的,所以根文件系统其实也是未加载的,此时在上述两种情况中内核文件(假如文件名为 vmlinuz)和 grub 目录的访问路径也是不一样的:

  • 情况 1,因内核和 grub 直接与根文件系统在同一个分区,且位于根文件系统下的 /boot 目录,所以直接访问这个分区上的根文件系统的 /boot/vmlinuz 就可以访问到内核文件,/boot/grub 就可以访问到 grub 目录;
  • 情况 2,因内核和 grub 与根文件系统不在同一个分区,而 grub 在 stage1 阶段通过 stage1_5 是直接访问内核和 grub 所在分区,此时内核和 grub 目录的路径就分别为 /vmlinuz/grub

所以 grub 在寻找 stage2 以及内核文件时,首先要确定 stage2 及内核位于哪个磁盘上的哪个分区。
对 grub legacy 来讲,它对设备通常使用 hd#,#hd 是 “hard disk”的缩写,# 表示数字) 进行表示,第一个 # 表示磁盘编号即第几块磁盘,第二个 # 表示第几个分区,它们都从 0 开始编号。

grub的命令行接口

grub 的作用已经很清晰了,它无非就是帮助加载用户选定的操作系统或内核,这个内核肯定是在某个磁盘的某个分区之上,那它到底是在哪个磁盘的哪个分区之上呢?

先在 grub 界面下键入 c 进入命令行提示符下一起来看一下它内置的命令:
1、help:获取帮助列表;
2、help <command>:获取指定命令的帮助;
3、find (hd#,#)/<file>:查找指定磁盘分区上的某个文件;
4、root (hd#,#):设定根设备;
5、kernel <kernel_file>:指定本次引导启动时用到的内核文件;

额外还可以添加许多内核支持使用的命令行参数,如:

  • 1sSsingle 设定单用户运行级别;
  • init=<init_program> 可设置默认的 init 程序;
  • selinux=0 设定禁用 selinux;

6、initrd <initramfs_file>:设定为选定的内核提供额外文件的 ramdisk(或 ramfs)。

ramdisk 的版本要和内核版本完全一致。

7、boot:引导启动选定的内核;

下面是直接通过命令行接口来设定引导启动的例子:
1、切换根设备:

grub> root (hd0,0)

切换根设备为第 1 块磁盘的第 1 个分区。

2、指定引导的内核文件:

grub> kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=/dev/mapper/vg_zze-lv_root quiet

ro:以只读模式加载根文件系统;
root=/dev/mapper/vg_zze-lv_root:指定根文件系统对应的设备文件(视实际系统情况而定);
quiet:静默模式;

3、指定与当前内核匹配的 ramfs 文件:

grub> initrd /initramfs-2.6.32.431.el6.x86_64.img

4、启动:

grub> boot

grub的配置文件

再回头进入编辑模式会发现默认的选项其实就是命令行中设置的几项:

image.png

而这些信息是加载 grub 的配置文件得到的,上面有说过,grub 的配置文件为 /boot/grub/grub.conf,进入系统查看这个文件:

# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/mapper/vg_zze-lv_root
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-431.el6.x86_64)
	root (hd0,0)
	kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=/dev/mapper/vg_zze-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_zze/lv_root rd_LVM_LV=vg_zze/lv_swap  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
	initrd /initramfs-2.6.32-431.el6.x86_64.img

上述配置文件各项信息的描述如下:

default:默认启动的菜单选项,从 0 开始;
timeout:超时时间,如果在超时时间内未作出反应,则跳过菜单显示以默认的菜单选项启动;
splashimage:启动系统时默认使用的背景图片;
hiddenmenu:隐藏菜单;
password [--md5] <pwd>:菜单编辑认证,--md5 表示使用 md5 加密后的密码认证,如果不指定则使用明文认证;
title:grub 中的菜单选项,可有多个,用来引导不同的内核和操作系统,对 Linux 系统而言每一个菜单选项对通过缩进的方式定义了如下几项:
    root:根设备,grub 查找 stage2 及 kernel 文件所在设备分区,这个根是针对 grub;
    kernel:内核文件及传递给内核的参数;
    initrd:与内核匹配的 ramfs 文件;
    passwd [--md5] <pwd>:启动选定的操作系统或内核认证;

认证

先使用 grub 提供的工具生成一下 md5 加密后的密码:

[root@zze ~]# grub-md5-crypt
Password: 
Retype password: 
$1$Lvt4i0$Zkk/226bKU77aufJhqscT0

菜单编辑认证

菜单编辑认证可以让用户在编辑 grub 菜单前提示输入密码,校验通过后才能进行编辑操作,只需要在和 title 平级的区域使用 password 项定义认证方式。
在配置文件中加入一行:

password --md5 $1$Lvt4i0$Zkk/226bKU77aufJhqscT0

重启进入 grub,键入 e 编辑菜单项会有如下提示:

image.png

键入 p 输入密码校验通过后就可以正常编辑了。

启动认证

启动认证可以让用户在启动指定内核或系统前提示输入密码,校验通过后才能够正常启动,只需要在指定菜单 title 下通过缩进的方式定义 password 参数即可。
title 下添加如下行:

password --md5 $1$Lvt4i0$Zkk/226bKU77aufJhqscT0

重启进入 grub,选定操作系统启动会有如下提示:

image.png

输入正确的密码后则会正常启动。

进入单用户模式

可以通过 grub 给内核传递参数以进入单用户模式,步骤如下。
1、编辑 grub 菜单,选定要编辑的菜单,键入 e 即可。

image.png

2、选定内核,键入 e 进入编辑模式,在其后输入 1single

image.png

3、回车,返回到内核选定处,键入 b 引导启动。

image.png

4、进入单用户模式成功。

grub的修复

先破坏一下 mbr 分区中的 grub:

dd if=/dev/sda of=/root/mbr.bak count=1 bs=512
dd if=/dev/zero of=/dev/sda bs=200 count=1

未关机修复

未关机指的是 mbr 分区被破坏后还没有关机,此时就可以直接在当前操作系统使用工具重装 grub。

方式一 grub-install

可以直接通过 grub-install 命令来重新安装 grub 到 mbr 中:

grub-install --root-directory=/ /dev/sda

该种方式不要求根下有 boot 目录,它会自动创建。

方式二 grub

也可使用 grub 命令来重新安装 mbr 中的 grub,

# grub
grub> root (hd0,0)
grub> setup (hd0)

此种方式是将本机已存在的 grub 各阶段文件安装到指定位置,所以使用此种方式的前提是当前系统根目录下已有了 boot 目录,且 boot 目录下有 grub 的 stage1、stage1_5、stage2 还有配置文件的存在,否则不可行。

关机后修复

关机后指的是 mbr 分区被破坏后并且关机了,由于 mbr 分区中的 grub 的 stage1 已经被破坏,所以已经不能通过引导启动操作系统了,因为引导程序已经挂了,如下:

image.png

此时我们就可以使用原系统的镜像来修复。
1、光驱选择系统镜像,并连接,重新启动:

image.png

2、可以看到此时进入了安装系统的界面,选择“Rescue installed system”回车进入救援模式:

也可以在安装系统界面键入 ESC 进入命令行窗口,输入 linux rescue 回车进入救援模式。
救援模式其实就类似于 Win PE,是一个小的 Linux 系统。

image.png

3、救援模式会试图去查找我们已经安装过的 Linux 系统,并且将原根文件系统挂载到当前环境的 /mnt/sysimage 下,选择 Continue 即可:

image.png

4、选择 Start shell 并回车就打开了 bash 的命令提示符,接下来我们就可以键入命令来重新安装 grub。
切换根目录到 /mnt/sysimage,执行安装操作:

chroot /mnt/sysimage/
grub-install --root-directory=/ /dev/sda

5、重启,断开光驱的连接,会发现成功引导进入原来的操作系统了。

0

评论区