GRUB(bootloader)引導流程:
GRUB,GRand Unified Bootlader ,是一個來自GUN項目的多操作系統啟動程序。GRUB是多啟動規范的實現,它允許用戶可以在計算機內同時擁有多個操作系統,並在計算機啟動時選擇希望運行的操作系統。GRUB可用於選擇操作系統分區上的不同內核,也可用於向這些內核傳遞啟動參數。
grub版本:
grub 0.x:grub(legacy) Centos 5,6
grub 1.x:grub2 Centos 7
grub legacy版本:
工作流程:當系統啟動時,如果要加載grub所在的磁盤時,會讀取這個磁盤的MBR,同時會加載stage1,stage1會嘗試讀取后扇區的stage1_5階段,stage1_5階段會幫助stage1中的bootloader識別stage2所在的分區上的文件系統,然后加載stage2所在的磁盤分區,這個分區不但有stage2階段,還有內核和ramdisk等。
stage1:運行Boot Loader主程序,這個程序必須要安裝在啟動區,即MBR中。因為MBR空間有限,因此在MBR當中僅安裝Boot Loader的最小程序,並沒有安裝Boot Loader的相關配置文件
stage1_5:MBR之后的扇區,讓stage1中的BootLoader能識別stage2所在的分區上的文件系統(相當於文件系統的驅動)
stage2:boot目錄所在的磁盤分區(/boot/grub)
配置文件:/etc/grub.conf軟鏈接到/boot/grub/grub.conf
/boot/grub/menu.lst軟鏈接到/boot/grub/grub.conf
stage2及內核等通常放置於一個基本磁盤分區(boot分區)
boot單獨分區是用來存放與Linux系統啟動有關的程序,比如內核文件、啟動引導裝載程序,啟動菜單配置文件等;
boot作為一個單獨的分區,也就意味着這個單獨分區下有一個grub,因為grub剛啟動的時候,操作系統還沒有啟動(真正的根文件系統還沒有被加載),所以,不能通過訪問/boot/grub來實現,但是我們又需要訪問這個文件來執行stage2 階段。所以,grub中就有一個root命令,指明的就是把stage2 階段直設為根,而grub自帶有文件系統驅動(stage 1.5),所以就可以直接訪問分區及根下的所有文件即kernel,initrd等來選擇內核啟動;
boot目錄,有沒有單獨分區(或者說引導分區是不是一個獨立的分區),決定了在grub中的訪問路徑是否一樣。而grub中的root命令,指明的就是這個根分區是誰,如果boot被單獨分區了,那么就直接指向這個新分區,訪問路徑就直接把boot給去掉了;如果boot沒有被單獨分區,就是掛在根分區上,那就意味着/boot目錄是繞不過去的,訪問的時候只能先訪問根,在訪問根下的boot。
grub要想訪問某一分區,這個分區必須是基本磁盤分區,不可能是提供了非常復雜的驅動程序(RAID或LVM)。如果想把根做的復雜些(比如LVM)但又不對boot做單獨分區,那把邏輯卷往分區上一放,就找不到grub中的stage2階段了,所以,要想把根做的復雜,就只能把boot作為一個單獨的基本磁盤分區;
如果不使用邏輯卷,boot是可以不用單獨分區的。
stage2的主要功能:
1、提供菜單、並提供交互式接口
e:編輯模式,用於編輯菜單
c:命令模式,交互式接口
2、 加載用戶選擇的內核或操作系統
允許傳遞參數給內核
可隱藏此菜單
3、為菜單提供了保護機制
為編輯菜單進行認證
為啟用內核或操作系統進行認證
GRUB識別硬盤設備:(hd#,#)表示第幾塊磁盤的第幾塊分區
hd# 磁盤編號用數字表示,從0開始編號
# 分區編號用數字表示,從0開始編號
例如(hd0,0)表示第一塊硬盤的第一個分區
grub命令行接口:
help:獲取幫助列表
help KEYWORD:查看指定命令的詳細幫助信息
find (hd#,#)/PATH/TO/SOMEFILE:查找某個磁盤上的某個文件
root (hd#,#):設置grub的根設備(boot目錄所在的磁盤設備)
initrd /PATH/TO/INITRAMFS_FILE:設定選定內核配套的ramdisk文件
boot:引導啟動選定的內核
kernel /PATH/TO/KERNEL_FILE:設定本次啟動時用到的內核;額外還可以添加許多內核支持的cmdline參數:
例如:init=/path/to/init, selinux=0
內核支持的啟動參數:
磁盤相關啟動參數:
root 指定啟動系統的真實根文件系統所在分區 如:root=/dev/sda1
ro 指定根設備在啟動過程中為readly-only(只讀),默認情況下為ro(這里根設備指的是grub的根設備)
rw 指定根設備在啟動過程中為read-write(讀寫)
rootfstype 指定根文件系統類型,如:rootfstype=ext4
console和kernel log相關的啟動參數:
console console的設備和選項,如:console=tty0,console=ttyS0
debug enable kerneldebugging 系統啟動中的所有debug信息
quiet 靜默模式將kernel loglevel設置為KERN_WARNING,在啟動中指非常嚴重的信息
loglevel 設置默認的console日志級別,如:loglevel=7(0~7數字分別為KERN_EMERG,…,KERN_DEBUG)
time 設置在每條kernel log信息前加一個時間戳
內存相關的啟動參數:
mem 指定kernel使用的內存量,mem=n[KMG]
hugepages 設置大頁表頁(4MB大小)的最多個數,hugepages=n
CPU啟動的相關參數:
mce #Enable the machine check exception feature.
nosmp #Run as a single-processor machine. 只使用一個處理器,不使用SMP(多處理器)
max_cpus #max_cpus=n, SMP系統最多能使用的CPU個數
Ramdisk相關的啟動參數:
initrd 指定初始化ramdisk的位置,initrd=filename
noinitrd 不使用initrd的配置,即使配置了initrd參數
初始化相關啟動參數:
init 在啟動時去執行的程序,init=filename,默認值為/sbin/init
PCI相關的啟動參數:
pci #pci相關的選項,我常使用pci=assign_buses,也使用過pci=nomsi
SELinux相關啟動參數:
enforcing #SELinux enforcing狀態的開關,enforcing=0表示僅僅是記錄危險 而不是阻止訪問,enforcing=1完全enable,默認值是0
selinux 在啟動時關閉或開啟SELinux,selinux=0表示關閉,selinux=1表示開啟selinux
手動在grub命令行啟動系統:
grub> root(hd#,#)
grub> kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
grub> initrd /initramfs-VERSION-RELEASE.img
grub> boot
配置文件:/boot/grub/grub.conf
default=# 設定默認啟動菜單項;菜單項(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 與內核匹配的initramfs文件
password [--md5] STRING 啟動選定內核或操作系統時需要認證
每行詳細解釋:
default=#: 設定默認啟動的菜單項;假如同時裝有多個操作系統,0表示定義的第一個title系統,1表示定義的第二個title系統,以此類推
timeout=#:表示可供選擇的等待時間,如果超出5秒,則使用默認的啟動條目default定義的
splashimage=(hd#,#)/PATH/TO/XPM_FILE:菜單背景圖片文件路徑
hiddenmenu:隱藏菜單,默認是不顯示菜單信息,如果要想顯示菜單,可以將該配置信息注釋即可
password [--md5] STRING: 啟動菜單編輯認證
title TITLE:定義菜單項“標題”(操作系統名稱), 可出現多次,用來引導不同的操作系統或內核
root (hd#,#):grub查找stage2及kernel文件所在設備分區;為grub"根"。也就是說,表示的是內核文件的存放位置,這里指的是分區位置,而非根目錄
kernel /PATH/TO/VMLINUZ_FILE [PARAMETERS]:內核的名稱,以及一些啟動時的核心參數。由於啟動過程中需要掛載根目錄,因此就需要指定根目錄所在的分區。rhgb表示色彩顯示,quiet表示靜默模式加載內核
initrd/PATH/TO/INITRAMFS_FILE: 內核匹配的ramfs文件,虛擬文件系統
password [--md5] STRING: 啟動選定的內核或操作系統時進行認證
grub-md5-crypt命令生成密鑰:
[root@localhost ~]# grub-md5-crypt
Password:
Retype password:
$1$TcvuB$S9n4SJLUnvoM3NXYT6Fk2.
編輯grub.conf文件將秘鑰添加到相應位置vim /etc/boot/grub.conf
passwd --md5 $1$TcvuB$S9n4SJLUnvoM3NXYT6Fk2.
實驗1:為編輯啟動菜單進行認證;為啟用內核或操作系統進行認證
1、復制一份內核文件,改名為Tao Linux,並分別在第一個title之前和第二個title之后添加生成的加鹽密碼,保存並退出,並重啟系統;
2、重啟系統之后發現要為進行編輯啟動菜單的認證,效果如下:
3、按“p”鍵輸入密碼之后,可以發現原來的提示信息又回來了,這是我們就可以編輯了
4、選擇第二個內核作為啟動程序,按回車鍵發現要想啟動內核,要輸入密碼認證,說明我們為內核設置的密碼,起作用了。
進入單用戶模式:
1、編輯grub菜單(選定要編輯的title,按"e"命令進行編輯)
2、在選定的kernel后添加1, s, S或single參數都可以
3、在kernel所在行,按"b"命令啟動kernel
實驗2:單用戶模式下修改密碼
1、在進入開機界面的時候,按任意鍵進入菜單界面
2、因為我們在編輯啟動菜單前設置了認證,所以需要輸入密碼,按"p"輸入密碼后進入編輯菜單,然后選定要啟動的內核,按"e"鍵進入編輯模式
3、選定好要啟動的kernel后,按"e"鍵進入,然后在選定的內核后添加1, s, S或single,然后按回車鍵,緊接着在kernel所在行輸入"b"進入單用戶模式
grub安裝:出現grub損壞或給其它硬盤安裝grub
1、通過grub-install命令進行grub安裝(這種方式二進制類的文件可以恢復,但是背景圖片和grub.conf的文件不能恢復。會安裝grub stage1和stage1_5到/dev/DISK磁盤上,並復制GRUB相關文件到 DIR/boot目錄下(這里的DIR指的是boot目錄的上一級目錄)
grub-install -root-directory=DIR /dev/sda
2、在grub命令行進行grub安裝,需要依賴/boot/grub/目錄中除grub.conf之外的其它文件,這些文件都是完好存在情況下才能安裝
grub> root (hd#,#)
grub> setup (hd#)
示例1:重新安裝grub, 用grub-install安裝
1、 dd if=/dev/zero of=/dev/sda bs=200 count=1 模擬破壞掉grub的stage 1(bootloader)
2、grub-install --root-directory=/ /dev/sda 重新安裝grub
示例2:在grub命令提示符下修復grub(需要依賴/boot/grub/中的除grub.conf之外的文件都是完好情況下)
1、dd if=/dev/zero of=/dev/sda bs=200 count=1 模擬破壞掉grub的stage 1(bootloader)
2、grub 進入grub命令提示符下
3、root (hd0,0) 指定grub的根所在的硬盤分區(也就是boot目錄所在的硬盤分區)
4、setup (hd0) 開始安裝grup,需要指定grub所在硬盤
5、quit命令退出grup命令行模式
示例3:在緊急救援模式下修復grub(在grub損壞情況下設備重啟了,這時候肯定起不來了)
1、dd if=/dev/zero of=/dev/sda bs=200 count=1 模擬破壞掉grub的stage 1(bootloader)
2、reboot 重啟設備加載安裝光盤,進入救援模式
選擇將根文件系統掛載到救援模式系統的/mnt/sysimage目錄
提示掛載成功,並可以通過chroot命令切換根
啟動shell
3、進入shell界面,切換根開始修復grub
總結:GRUB啟動故障排除案例
1、MBR中grub損壞,1_5階段的數據損壞,2階段的grub損壞
2、initramfs*.img文件損壞,內核文件損壞
3、/boot/grub/grub.conf文件丟失
4、/etc/fstab丟失,無法掛載根等文件系統
5、/boot 目錄全部的文件丟失
解決方法(都是在救援模式下)
1、MBR中grub損壞,1_5階段的數據損壞,2階段的grub損壞;救援模式:
chroot /mnt/sysimage 切根,改變磁盤根目錄
grub-install /dev/sda 安裝grub引導程序到磁盤/dev/sda的MBR扇區
2、initramfs*.img文件損壞,內核文件損壞
initramfs*.img文件損壞,解決方法:
# chroot=/mnt/sysimage
# mkinitrd /boot/initramfs-$(uname -r).img $(uname -r) #創建
內核文件損壞
# mkdir /mnt/cdrom
# mount /dev/cdrom /mnt/cdrom 掛載光盤
進入/mnt/cdrom/Packages/ 目錄下覆蓋安裝kernel包,
rpm -ivh–replacepkgs kernel-VERSION.rpm –root=/mnt/sysimage –force
安裝完成后會在/boot目錄下自動生成相應版本的vmlinuz文件.(前提是內核版本未更新, 和光盤中的內核版本一致)
3、/boot/grub/grub.conf文件丟失
這個新建一個寫上引導等信息就行
4、/etc/fstab丟失,無法掛載根等文件系統
同樣新建一個/etc/fatab、填寫上掛載信息
LVM的話需要激活LVM邏輯卷
5、/boot目錄全部的文件丟失
結合上面,先MBR修復,然后內核文件修復和initramfs*.img文件修復
示例4:虛擬機下手動制作grub
1、准備好一個新硬盤,分3個分區(根分區、swap、boot)分別格式化,這里的boot單獨分一個區
/boot:mkfs.ext4 /dev/sdb1
/:mkfs.ext4 /dev/sdb2
swap:mkswap /dev/sdb3
2、模擬啟動時的boot目錄,將其掛載到當前系統/mnt/boot/目錄(創建的目錄名一定要為boot)
mkdir /mnt/boot
mount /dev/sdb1 /mnt/boot
3、將制作grub到新硬盤的boot分區(指定根目錄就是boot目錄所在的上一級目錄)
grub-install --root-directory=/mnt /dev/sdb
4、復制當前系統的內核文件和initramfs文件到/mnt/boot/目錄中,並手動創建grub.conf配置文件
cp /boot/vmlinuz-2.6.32-573.el6.x86_64 /mnt/boot/vmlinuz
cp /boot/initramfs-2.6.32-573.el6.x86_64.img /mnt/boot/initramfs.img
vim /mnt/boot/grub/grub.conf
default=0
timeout=5
title centos 6 (Express)
root (hd0,0)
kernel /vmlinuz ro root=/dev/sda2 selinux=0 init=/bin/bash
initrd /initramfs.img
5、為根分區創建常用的一級子目錄
mkdir /mnt/sysroot
mount /dev/sdb2 /mnt/sysroot/
cd /mnt/sysroot/
mkdir -pv etc bin sbin lib lib64 dev proc sys tmp var usr home root mnt media
6、拷貝bash程序和依賴的庫文件到根文件系統上的對應目錄
cp /bin/bash /mnt/sysroot/bin/
ldd /bin/bash 查看bash程序依賴的庫文件
cp /lib64/libtinfo.so.5 /mnt/sysroot/lib64/
cp /lib64/libdl.so.2 /mnt/sysroot/lib64/
cp /lib64/libc.so.6 /mnt/sysroot/lib64/
cp /lib64/ld-linux-x86-64.so.2 /mnt/sysroot/lib64/
sync 將內存數據同步到硬盤
7、用新的硬盤去創建一個虛擬機,檢驗是否能正常啟動
實驗:自制Linux操作系統
1、為CentOS 6系統添加一塊新的硬盤,然后啟動,演示如下:
2、查看新添加的硬盤,並為添加好的磁盤分區,創建文件系統;
[root@CentOS6 ~]# fdisk -l /dev/sd[a-z]
Disk /dev/sda: 85.9 GB, 85899345920 bytes
255 heads, 63 sectors/track, 10443 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0007eba7
Device Boot Start End Blocks Id System
/dev/sda1 * 1 26 204800 83 Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2 26 7859 62914560 8e Linux LVM
/dev/sda3 7860 9165 10490445 83 Linux
/dev/sda4 9166 10443 10265535 5 Extended
/dev/sda5 9166 9819 5253223+ 83 Linux
#可以看到新添加的硬盤sdb
Disk /dev/sdb: 21.5 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
#分三個主分區,分別作為為根分區,swap分區和boot分區,並創建對應的文件系統,操作如下:
[root@CentOS6 ~]# fdisk /dev/sdb #創建分區,
#創建文件系統如下命令:
[root@CentOS6 ~]# mkfs.ext4 /dev/sdb1
[root@CentOS6 ~]# mkswap /dev/sdb2
[root@CentOS6 ~]# mkfs.ext4 /dev/sdb3
#查看創建好的分區
[root@CentOS6 ~]# blkid
/dev/sdb1: UUID="f4921d76-f089-4cb6-8f47-aff34711cb7a" TYPE="ext4"
/dev/sdb2: UUID="3eaa649e-a5c0-4f9c-8887-453368419238" TYPE="swap"
/dev/sdb3: UUID="286c857d-8f52-465f-9ed6-8eeaa3363743" TYPE="ext4"
3、創建一個boot目錄,並把boot分區(sdb1)掛載上;
[root@CentOS6 ~]# mkdir /mnt/boot
[root@CentOS6 ~]# mount /dev/sdb1 /mnt/boot
[root@CentOS6 ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/vg0-root 20511356 1112808 18349972 6% /
tmpfs 502068 0 502068 0% /dev/shm
/dev/sda1 194241 34199 149802 19% /boot
/dev/mapper/vg0-usr 10190136 2473060 7192788 26% /usr
/dev/mapper/vg0-var 20511356 489148 18973632 3% /var
/dev/sda5 5039592 10352 4766580 1% /home
/dev/sdb1 104769 1550 97598 2% /mnt/boot # 掛載的設備sdb1
4、創建grub,並查看
[root@CentOS6 ~]# ls /mnt/boot/
lost+found
[root@CentOS6 ~]# grub-install --root-directory=/mnt /dev/sdb #創建grub
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/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@CentOS6 ~]# ls /mnt/boot/
grub lost+found
[root@CentOS6 ~]# ls /mnt/boot/grub/
device.map fat_stage1_5 iso9660_stage1_5 minix_stage1_5 stage1 ufs2_stage1_5 xfs_stage1_5
e2fs_stage1_5 ffs_stage1_5 jfs_stage1_5 reiserfs_stage1_5 stage2 vstafs_stage1_5
5、要想成為一個真正的系統,還需要內核文件,initrd以及grub/grub.conf這些文件;
[root@CentOS6 ~]# cp /boot/vmlinuz-2.6.32-642.el6.x86_64 /mnt/boot/vmlinuz
[root@CentOS6 ~]# cp /boot/initramfs-2.6.32-642.el6.x86_64.img /mnt/boot/initramfs.img
[root@CentOS6 ~]# vim /mnt/boot/grub/grub.conf #手動編寫配置文件
default=0
timeout=5
title CentOS (Express)
root (hd0,0) # 在當前下為第二塊磁盤應為(hd1,0),但是如果在其它設備上使用為(hd0,0)
kernel /vmlinuz ro root=/dev/sda3 #加載的根目錄所在的分區,因為在其他設備上為第一塊磁盤所以為 /dev/sda3
initrd /initramfs.img #內核匹配的ramfs文件
6、要把/dev/sda3當做根文件系統,就需要掛載,並創建根文件系統下想對應的子目錄:
[root@CentOS6 ~]# mkdir /mnt/sysroot
[root@CentOS6 ~]# mount /dev/sdb3 /mnt/sysroot/
[root@CentOS6 ~]# cd /mnt/sysroot/
[root@CentOS6 sysroot]# ls
lost+found
[root@CentOS6 sysroot]# mkdir -pv etc bin sbin lib lib64 dev proc sys mnt var usr home root tmp media
mkdir: created directory `etc'
mkdir: created directory `bin'
mkdir: created directory `sbin'
mkdir: created directory `lib'
mkdir: created directory `lib64'
mkdir: created directory `dev'
mkdir: created directory `proc'
mkdir: created directory `sys'
mkdir: created directory `mnt'
mkdir: created directory `var'
mkdir: created directory `usr'
mkdir: created directory `home'
mkdir: created directory `root'
mkdir: created directory `tmp'
mkdir: created directory `media'
[root@CentOS6 sysroot]# ls
bin dev etc home lib lib64 lost+found media mnt proc root sbin sys tmp usr var
7、根文件系統的目錄有了,但是要想運行還需要程序,還需要bash,以及基於動態編譯的共享庫文件
[root@CentOS6 sysroot]# cp /bin/bash /mnt/sysroot/bin #復制bash
[root@CentOS6 sysroot]# ldd /bin/bash # 查看庫文件
linux-vdso.so.1 => (0x00007ffd127d9000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x0000003278e00000)
libdl.so.2 => /lib64/libdl.so.2 (0x000000326f200000)
libc.so.6 => /lib64/libc.so.6 (0x000000326f600000)
/lib64/ld-linux-x86-64.so.2 (0x000000326ee00000)
# 復制共享庫中的文件到創建的根目錄中的lib64下
[root@CentOS6 sysroot]# cp /lib64/libtinfo.so.5 /mnt/sysroot/lib64
[root@CentOS6 sysroot]# cp /lib64/libdl.so.2 /mnt/sysroot/lib64
[root@CentOS6 sysroot]# cp /lib64/libc.so.6 /mnt/sysroot/lib64
[root@CentOS6 sysroot]# cp /lib64/ld-linux-x86-64.so.2 /mnt/sysroot/lib64
8、基本的操作已經完成,使用chroot切換根,進行測試,如下:
[root@CentOS6 sysroot]# chroot /mnt/sysroot/ # 切換根
bash-4.1#
bash-4.1#
bash-4.1# ls # 因為沒有復制命令,所以只能使用內建命令,如果需要使用外部命令,就把命令以及以依賴的庫復制過去就可以了。
bash: ls: command not found
bash-4.1# pwd
/
bash-4.1# exit
exit
9、最后,我們再編輯一下配置文件/mnt/boot/grub/grub.conf
[root@CentOS6 ~]# vim /mnt/boot/grub/grub.conf
default=0
timeout=5
title CentOS (Express)
root (hd0,0)
kernel /vmlinuz ro root=/dev/sda3 init=/bin/bash # 表示要求限定運行的的是/bin/bash 而不是 /sbin/init 這樣就直接把bash當做用戶空間的第一個進程來使用了
initrd /initramfs.img
10、同步內存信息到硬盤
[root@CentOS6 ~]# sync
11、我們新建一個虛擬機,把硬盤改為新創建好的磁盤,測試系統能否啟動?
啟動此虛擬機,如下圖:按e鍵可以看到我們創建的系統文件,選定內核,按b鍵啟動
選定內核,按b鍵啟動,發現系統報錯,什么原因呢?可能是沒有添加selinux策略
選定內核,按e鍵,進入編輯模式,添加selinux=0 ,重新啟動,發現可以正常啟動