bootloader及grub概述
启动引导装载程序(bootloader),就是系统启动时在执行POST加电自检功能的BIOS程序之后、操作系统内核运行之前这中间所运行的一段程序,bootloader的主要作用是加载内核,并将整个系统的控制权移交给内核。常见的bootloader有Windows的ntloader、Linux的lilo、grub及grub2等。其中,在CentOS 5/6系列上使用的是grub,而在CentOS 7开始则使用grub;lilo则常见于手机,因此lilo是使用者最多的一种bootloader。
Windows:
ntloader
Linux:
LILO:LInux LOader
GRUB:Grand Unified Bootloader
GRUB 0.X:Grub Legacy
GRUB 1.X:Grub2
就MBR分区方法而言,大多数Bootloader都分为多个阶段来引导,其中第一阶段存放于MBR中,用于引导装载第二阶段。而grub作为Bootloader的一种也不例外,它是分为stage1,stage2,stage1.5这三个阶段来引导的:stage1的主要工作是加载stage1.5,stage1.5的主要工作是加载文件系统驱动,让stage1中的bootloader能够识别stage2所在分区的上的文件系统,stage1.5会提供多种文件系统的驱动,如下:
[root@localhost grub]
# ls -1F
device.map
e2fs_stage1_5
fat_stage1_5
ffs_stage1_5
grub.conf
iso9660_stage1_5
jfs_stage1_5
menu.lst@
minix_stage1_5
reiserfs_stage1_5
splash.xpm.gz
stage1
stage2
ufs2_stage1_5
vstafs_stage1_5
xfs_stage1_5
[root@localhost grub]
#
可以看见,每个stage1.5文件对应一种文件系统,而借助于stage1.5阶段所提供的文件系统驱动,stage1就可以通过加载其中某一种文件系统驱动来识别stage2所在分区的文件系统了。举个例子,如果stage2所在分区上的文件系统是ext4,那么stage1就会通过stage1.5提供的e2fs_stage1_5来识别stage2。完成对stage2的识别和加载之后,stage2就能够加载stage2所在分区上(即/boot所在分区)的内核文件和ramdis文件(注意:ramdisk文件并非必须)至内存中了。此外,grub的功能主要是通过stage2来实现的,在系统启动时,stage2可以向用户提供菜单,并提供交互式接口,允许用户通过菜单选择要加载的内核或操作系统,另外,如果用户有需要,stage2还可以为菜单提供保护机制,而保护机制有两种,一种是为编辑菜单提供认证,另外一种是为启动的内核或操作系统提供认证。以下总结grub(stage2)的主要功能:
grub(stage2)的功用:
(1)向用户提供菜单,并提供交互式接口。例如,在启动时可进入菜单,通过键入e键进入编辑模式,可以编辑菜单,此时会读取配置文件;也可以通过键入c键可以进入命令行模式,即进入交互式接口,可以自己手动指定要启动的内核而不读取grub配置文件;
(2)加载用户选择的内核或操作系统。在选择时允许用户传递参数给内核,也可以隐藏菜单的具体内容;
(3)为菜单提供保护机制。可以为编辑菜单提供认证,用户需要通过认证方可编辑指定菜单;也可以为内核或操作系统提供认证,用户需要通过认证方可启动指定的内核或操作系统;
演示:
启动时进入编辑菜单:
键入e键可以编辑菜单,如下所示,再此时再键入一次e键就可以编辑选定的参数了。
按下Esc键可以返回第一个菜单界面,再键入c键可以直接进入命令行模式(交互式接口):
通过’help’可查看帮助,而’help KEYWORD’则可以查看指定项的详细帮助:
可以通过find命令查找文件,例如查找/boot分区下的内核文件:
用户可以通过这个交互式接口指定要加载的内核及ramdisk文件,但在此之前要先指定grub的根分区(注意:stage2所在分区即为grub的根分区,这里grub的根不一定是文件系统的根),而要指定grub的根分区则必须采用grub识别设备的方式来指定,grub识别设备是通过命令‘root (hd#,#)’来指定的,各部分解释如下:
root:用于切换grub所在分区;
hd
#:磁盘编号,用数字表示;从0开始编号;
#:分区编号,用数字表示;从0开始编号;
需要注意的是,用户在指定要加载的内核或操作系统时,通常需要指定grub的根(root (hd#,#)),并且指定Kernel及initrd所在路径,必要时传递一些参数给Kernel。但是,Kernel及initrd是以grub的“根”作为起始目录的,也就是说如果/boot作为基本磁盘分区独立出来时,那么Kernel及initrd在指定路径时的起始目录为’/’;如果/boot不作为基本磁盘分区,而是根分区(‘/’)之下的一个目录时,那么此时grub的“根”即为文件系统的根,Kernel及initrd的起始目录为/boot/。
用户可在交互式接口下手动指定要加载的Kernel及initrd。在进入菜单时和刚才一样,键入c键进入grub命令行模式(交互式接口),而当/boot为独立分区时,分别指定kernel及initrd的在grub的“根”下的文件路径,如下所示:
这里在Kernel指定路径之后至少还要传递两个参数,一个是’ro’,指明是以只读方式挂载根文件系统,’root=xxx’这一样则指明根文件系统所在分区,这里实验环境的根文件系统所在分区是一个LVM逻辑卷。最后键入’boot’即可加载指定的内核或操作系统并完成启动。
更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2017-03/141971p2.htm
Grub的配置文件:/boot/grub/grub.conf <— /etc/grub.conf(链接文件)
配置项:
defaults=#:设定默认要启动的菜单项;菜单项(title)从0开始编号;
timeout=#:设定菜单项等待用户选择的时长;
splashimage=(hd#,#)/PATH/TO/XPM_PIC_FILE:指明菜单项背景图片的文件路径;
hiddenmenu:隐藏菜单;
password [–md5] STRING:菜单编辑认证;
title TITLE:定义菜单项“标题”;可出现多次;
root (hd#,#):grub查找stage2及Kernel等文件所在设备的分区,即grub的“根”;
kernel /PATH/TO/VMLINUZ-FILE [PARAMETERS]:指明启动的内核;
initrd /PATH/TO/INITRAMFS-FILE:指明内核匹配的ramdisk文件;
password [–md5] STRING:启动选定的内核或操作系统时进行认证;
演示:
添加系统启动时的菜单项,首先编辑/etc/grub/grub.conf文件,如图:
保存退出,并重新启动:
[root@localhost ~]
# reboot
可以看到如下界面:
重新编辑菜单,为CentOS 6 (test)这一菜单项指向的内核添加启动认证:
[root@localhost ~]
# grub-md5-crypt
Password:
//
输入设定的密码;
Retype password:
$1$n.0tB/$AStqQTLYFdyC5GcI0BymR/
//
得到单向加密后的密码字符串;
[root@localhost ~]
#
复制加密得到的密码字符串,添加至/etc/grub/grub.conf文件中CentOS 6 (test)菜单项之下:
重新启动至菜单界面,这时如果要选择CentOS 6 (test)这一菜单项来启动时就需要通过密码验证才能加载内核:
同样可添加菜单编辑认证,在/etc/grub/grub.conf文件中作如下修改:
这里全局的菜单编辑认证加密的密码同样可以由grub-md5-crypt生成,此处直接使用内核认证的密码。
重新启动,进入菜单界面:
这里只能先键入p键并输入密码才能编辑菜单。
实例一:
新加硬盘,为这块新添加的硬盘安装grub程序,制作成在用户空间能单独运行bash的系统,并把硬盘拆下来装至另外的物理主机。
首先添加一块20G的硬盘:
启动主机,首先为这块硬盘分区:/dev/sdb1, /dev/sdb2, /dev/sdb3,其中/dev/sdb1作为/boot分区,/dev/sdb2作为swap分区,而/dev/sdb3作为/分区:
[root@localhost ~]
# fdisk /dev/sdb
分区后强制让内核重新识别:
[root@localhost ~]
# partx -a /dev/sdb
BLKPG: Device or resource busy
error adding partition 1
BLKPG: Device or resource busy
error adding partition 2
BLKPG: Device or resource busy
error adding partition 3
[root@localhost ~]
#
[root@localhost ~]
# cat /proc/partitions //查看内核分区信息;
major minor
#blocks name
8 0 41943040 sda
8 1 512000 sda1
8 2 41430016 sda2
8 16 20971520 sdb
8 17 112423 sdb1
//
内核已识别;
8 18 2104515 sdb2
8 19 5253255 sdb3
253 0 37330944 dm-0
253 1 4096000 dm-1
对各分区进行格式化:
[root@localhost ~]
# mke2fs -t ext4 /dev/sdb1
[root@localhost ~]
# mke2fs -t ext4 /dev/sdb3
[root@localhost ~]
# mkswap /dev/sdb2
根分区挂载至/mnt/sysroot/,/boot分区挂载至/mnt/sysroot/boot:
[root@localhost ~]
# mkdir /mnt/sysroot
[root@localhost ~]
# mkdir /mnt/sysroot/boot
[root@localhost ~]
# mount /dev/sdb3 /mnt/sysroot/
[root@localhost ~]
# mount /dev/sdb1 /mnt/sysroot/boot/
给/dev/sdb这块磁盘安装grub:
[root@localhost ~]
# grub-install --root-directory=/mnt/sysroot /dev/sdb
//
注意:这里--root-directory不能指为
/mnt/sysroot/boot
,因为它会自动到
/mnt/sysroot
目录下
查找boot目录;
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
/mnt/sysroot/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/sda
(hd1)
/dev/sdb
[root@localhost ~]
#
查看文件:
[root@localhost ~]
# cd /mnt/sysroot/boot/
[root@localhost boot]
# ls //查看/mnt/sysroot/boot分区下的文件;
grub lost+found
//
缺少Kernel文件和ramdisk文件;
[root@localhost boot]
# cd grub/
[root@localhost grub]
# ls -1 //查看/mnt/sysroot/boot/grub目录下的文件;
device.map
e2fs_stage1_5
fat_stage1_5
ffs_stage1_5
iso9660_stage1_5
jfs_stage1_5
minix_stage1_5
reiserfs_stage1_5
stage1
stage2
ufs2_stage1_5
vstafs_stage1_5
xfs_stage1_5
//
在grub目录下缺少grub的配置文件grub.conf;
为/mnt/sysroot/boot目录下添加Kernel及ramdisk文件(此处直接复制/dev/sda上的文件):
[root@localhost ~]
# cp /boot/vmlinuz-2.6.32-642.el6.x86_64 /mnt/sysroot/boot/vmlinuz
[root@localhost ~]
# cp /boot/initramfs-2.6.32-642.el6.x86_64.img /mnt/sysroot/boot/init
ramfs.img
创建grub的配置文件(/mnt/sysroot/boot/grub/grub.conf),并设定各属性:
default=0
//
设定启动第一项;
timeout=5
//
设定等待用户选择菜单的时长为5秒;
title CentOS 6 (Express)
//
设定菜单标题;
root (hd0,0)
//
原本是(hd1,0),但拆下来装至另一空物理机上则为(hd0,0);
kernel
/vmlinuz
ro root=
/dev/sda3
init=
/bin/bash
//
这里也一样,在本机上是
/dev/sdb3
,但装至另一空物理主机上则转为
/dev/sda3
;
//
此外,这里设定内核启动用户空间的第一个应用程序是
/bin/bash
,而不是原来的upstart;
initrd
/initramfs
.img
根据FHS在根目录下创建各个基础目录:
[root@localhost ~]
# cd /mnt/sysroot/
[root@localhost sysroot]
# mkdir etc bin sbin usr var dev mnt media proc sys root lib
lib64 home
拷贝/bin/bash程序及其所依赖到的库文件:
[root@localhost ~]
# cp /bin/bash /mnt/sysroot/bin/
[root@localhost ~]
#
[root@localhost ~]
# ldd /bin/bash //查看bash程序所依赖到的库文件;
linux-vdso.so.1 => (0x00007ffdd21fa000)
//
库文件的访问入口;
libtinfo.so.5 =>
/lib64/libtinfo
.so.5 (0x0000003f02200000)
libdl.so.2 =>
/lib64/libdl
.so.2 (0x0000003efda00000)
libc.so.6 =>
/lib64/libc
.so.6 (0x0000003efde00000)
/lib64/ld-linux-x86-64
.so.2 (0x0000003efd600000)
[root@localhost ~]
#
[root@localhost ~]
# cp /lib64/libtinfo.so.5 /mnt/sysroot/lib64/
[root@localhost ~]
# cp /lib64/libdl.so.2 /mnt/sysroot/lib64/
[root@localhost ~]
# cp /lib64/libc.so.6 /mnt/sysroot/lib64/
[root@localhost ~]
# cp /lib64/ld-linux-x86-64.so.2 /mnt/sysroot/lib64/
以同样的方法,拷贝/bin/ls程序及其所依赖到的库文件。
所有步骤完成之后,先执行根切换测试一下:
[root@localhost ~]
# chroot /mnt/sysroot/
bash
-4.1
#
bash
-4.1
# ls -1
bin
boot
dev
etc
home
lib
lib64
lost+found
media
mnt
proc
root
sbin
sys
usr
var
bash
-4.1
#
bash
-4.1
# exit //由bash内嵌命令exit退出;
exit
[root@localhost ~]
#
[root@localhost ~]
# sync //执行同步;
测试成功!
关机之后,查看刚才添加的磁盘文件名 ==> CentOS 6.8-1.vmdk:
新建虚拟机:
创建时选择“使用现有虚拟磁盘”:
选择刚才查看到的磁盘文件(CentOS 6.8-1.vmdk):
创建完成之后启动新建的虚拟机,可以看到菜单界面如下:
因为默认会开启selinux,而这里系统没有selinux的相关程序及配置文件,因此必须编辑菜单,关闭内核的selinux功能:
编辑完之后,点击’b’键启动:
启动之后顺利取得bash,并且可以运行ls程序:
实验到此结束。
实例二:
破坏本机grub stage1,在不重启的情况下修复号grub。
用dd命令破坏grub:
[root@localhost ~]
# dd if=/dev/sda of=/tmp/mbr.bak count=1 bs=512 //先备份MBR;
1+0 records
in
1+0 records out
512 bytes (512 B) copied, 0.000376481 s, 1.4 MB
/s
[root@localhost ~]
#
[root@localhost ~]
# dd if=/dev/zero of=/dev/sda count=1 bs=100 //开始执行破坏操作;
1+0 records
in
1+0 records out
100 bytes (100 B) copied, 0.0010733 s, 93.2 kB
/s
//
注意:破坏其前446Bytes即可。
修复grub:
方式一:
[root@localhost ~]
# grub-install --root-directory=/ /dev/sda
方式二:
[root@localhost ~]
# dd if=/dev/zero of=/dev/sda count=1 bs=100
1+0 records
in
1+0 records out
100 bytes (100 B) copied, 0.000691542 s, 145 kB
/s
[root@localhost ~]
# grub
.....(中间省略).....
grub>
grub> root (hd0,0)
//
查看设备;
root (hd0,0)
Filesystem
type
is ext2fs, partition
type
0x83
grub>
grub> setup (hd0)
//
安装grub;
setup (hd0)
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
//
这里只安装对应文件系统的stage1.5文件(当前为ext4文件系统);
Running
"embed /grub/e2fs_stage1_5 (hd0)"
... 27 sectors are embedded.
succeeded
Running
"install /grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/grub/stage2 /grub/grub.conf"
... succeeded
Done.
grub>
grub> quit
quit
[root@localhost ~]
#
//
注意:在grub命令行之下执行setup安装时,它会自动去读取指定设备的
/boot/grub
目录下的stage1
、stage1.5以及stage2文件,如果被破坏或者不存在则重新安装。
实例三:
破坏本机grub stage1,而后在救援模式下修复之。
破坏grub:
[root@localhost ~]
# dd if=/dev/zero of=/dev/sda count=1 bs=100
1+0 records
in
1+0 records out
100 bytes (100 B) copied, 0.000432857 s, 231 kB
/s
重新启动,因为硬盘上的grub程序被破坏,这时第一个被扫描到有bootloader的是光盘,所以直接进入光盘,看到如下界面,这里选择进入救援模式:
系统提示会将原有的根文件系统挂载至光盘系统的/mnt/sysimage目录下,选择”Continue”。
点击”OK”进入光盘的shell:
执行根切换,并安装grub,而后重新启动:
这样就可以正常启动系统了。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-03/141971.htm