一、GRUB(Boot loader)
二、Grub的命令行接口
三、/etc/grub/grub
四、进入单用户模式
五、Grub损坏,修复
六、救援模式
七、ramdisk文件的管理和initrd
八、grub2详解


一、GRUB(Boot loader)
    Grub:GRand Unified Bootloader
        Grub 0.x:grub legacy
        Grub 1.x:grub2
    grub legacy:
        stage:mbr
        stage1_5:mbr之后的扇区中,让stage1中的bootloader能识别stage2所在的分区上的fs
            //提供stage2的文件系统所需的驱动
        stage2:磁盘分区之上的,提供选择界面,供用户选择os
            stage2及内核等通常放置于一个基本磁盘分区
    配置文件:/boot/grub/grub.conf链接文件:/etc/grub.conf
    功用:
        1.提供菜单,并提供交互式接口
            e:编辑模式,用于编辑菜单
            c:命令模式,交互式接口
                root (hd0,0)  //CentOS7的,有时需要set root=
                kernel /vmlinuz-x86_64 ro root=/dev/mapper/vg0-root
                initrd /intramfs*.img
                boot //开机即可
            
            CentOS7:
                insmod gzio
                insmod part_msdos
                insmod xfs
                set root=(hd0,msdos1)/Centos7如何使用
                linux16 /vmlinuz-3.*.x86_64 root=/dev/mapper/centos-root ro //linux取代grub的kernel
                                    //注意vmlinuz前面的 / 不能去掉
                initrd16 /initramfs-*.img
                boot //重新启动即可
            注意:linux16 root=/dev/mapper/centos-root 必须指定,否则会出错
                指定root文件路径
        2.加载用户选择的内核或OS
            允许传递参数给内核
            可隐蔽此菜单
        3.为菜单提供了保护机制
            为编辑菜单进行认证
            为启用内核或os系统进行认证
二、Grub的命令行接口
    help:获取帮助列表
    help root //查看root的帮助信息,设置grub的根设备
        //此时os尚未启动,但是grub有自己的fs驱动可以直接访问
        //但是grub的fs驱动是有限的,不可能太大,因此不能识别软fs,raid,lvm等
    help KEYWORD:详细帮助信息
        //boot是可以不单独分区的,根fs如果使用基本分区的话
        //但是根fs,必须能够被grub识别才可以
        //如果root直接指定根所在分区,boot文件也放在跟分区中也是可以的
        //这时grub root需要指定根所在分区,并能够识别该分区
    如何标识设备:
        (hd#,#) //第#块磁盘的,第#个分区
        (hd0,0) //
    find (hd#,#)/vmlinuz-   
    root DEVICE //设置根设备 root (hd0,0)
    kernel /PATH/TO/KERNEL_FILE  //vmlinuz:z标识压缩存放,设定本次启动时用到的内核文件
        //额外内核支持的很多参数
        init=/paht/to/init
        selinux=0
        root=/dev/mapper/centos-root //根文件系统所在
        ro 只读
        quiet 静默模式
    initrd /PATH/TO/INITRAMFS_FILE //设定为选定的内核提供的额外的文件的ramdisk
    boot :引导启动选定的内核
    
grub2命令行:
    set root=
    set timeout=
    ls (hd1,1)/
    search -f /ntldr
    boot启动
    linux16 指定内核文件
    initrd16 指定initrd文件
    
三、/etc/grub/grub.conf :Centos5,6
    配置项:
        default=# //哪个用来默认启用,菜单项(title)编号从0开始
        timeout=5 //指定菜单选项等待选项的时长
        splashp_w_picpath=(hd#,#)/PATH/TO/INITRAMFS_FILE //默认启用的界面
        //password [--md5] STRING:菜单编辑认证 //可以不用
        hiddenmenu=[0/1] //隐藏菜单
        title TITLE //定义菜单项“标题”
            root (hd#,#):grub查找stage2及kernel文件所在的设备分区,为grub的“根”
            kernel /PATH/TO/VMLINUZ_FILE [ARG] :启动的内核
            initrd /PATH/TO/INITRAMFS_FS  :内核匹配的ramfs文件
            //password [--md5] STRING:启动选定到的内核或os时进行认证
    加密命令:grub-md5-crypt    
        password --md5 jisdjfidjsifjsdiyeou
        password xiaoxin //可以明文存放,但是不安全
    CentOS7:
        grub2-setpassword
    
四、进入单用户模式
        1.编辑grub菜单(e命令)
        2.kernel 最后加上 single/1,s/S
        3.在kernel所在行,键入“b”命令 //Cenetos7 ctrl+x
    CentOS7:也是如此        
        
五、Grub损坏,修复
    安装grub
        //双系统:建议先安装windows后安装linux
        grub-install /grub2-install
    安装新的grub    
        mkdir /mnt/boot
        mount /dev/sdb1 /mnt/boot //sdb是一个新硬盘
        grub-install --root-directory=/mnt /dev/sdb
            //指定root目录/mnt只需指定mnt即可,而不是/mnt/root
        grub将安装在sdb这个硬盘上的mbr中
    新加一个硬盘://当拆了第一个硬盘之后,他就变成了sda
        sdb1:boot
        sdb2:swap
        sdb3:/
    vim /mnt/boot/grub/grub.conf
        default=0
        timeout=5
        title CentOS (EXpress)
            root (hd0,0)
            kernel /vmlinuz ro root=/dev/sda3 selinux=0 init=/bin/bash  //
            initrd /initramfs.img
    cp /boot/vmlinuz*  /mnt/boot/vmlinuz
    cp /boot/initramfs /mnt/boot/initramfs.img
    mkdir /mnt/boot/sysroot ; cd /mnt/boot/sysroot
    mkdir -pv etc bin sbin lib lib64 dev proc sys tmp var usr home mnt media
    
    ldd /bin/bash //查看bash依赖的库
    cp bash命令
    chroot /mnt/sysroot/   //切换根就可以了
    创建一个新的虚拟机
        然后使用刚才建立的硬盘
    
    破坏分区表:
        dd if=/dev/zero of=/dev/sda bs=200 count=1 //小于446,分区表不要破坏
        1.grub-install --roo-directory=/   /dev/sda
        2.grub 命令模式修复
            root (hd0,0) //必须有grub目录,里面的stage1,stage1_5都是存在的
            setup (hd0) //安装第一阶段到第一块硬盘上
            exit
六、救援模式    
    借助于光盘实现
    linux rescue //命令行键入,进入救援模式
    默认会挂载原有的os到/mnt/sysp_w_picpath上
    chroot /mnt/sysp_w_picpath
    grub-install --root-directory=/  /dev/sda
    exit //退出到光盘镜像
    reboot即可
    
练习:
    1.新加硬盘,提供直接单独运行bash系统
        硬盘:新加硬盘-->分区-->mount--
            sdb1:/mnt/boot: //sdb1挂载地        :: /mnt/boot/[vmliuz,intramfs,grub{grub.conf}]    //切换目录
            sdb3:/mnt/sysroot: //sdb3挂在地      ::bin[bash],etc,sbin..                            //真实的根
            grub-install: /mnt
            grub文件
                kernel ...  init=/bin/bash
        注:创建grub的那台主机,需要关机,才可以,否则kernel panic
    2.破坏本机bootloader,grub stage1,在救援模式下修复
    3.为grub设置保护功能
    
七、ramdisk文件的管理和initrd
        1.mkinitrd ,Centos5,6
        2.dracut,Centos6,7
        mkinitrd [options] [initrd-img] kernel-versio
        //为当前正在使用中的内核重新制作ramdisk文件
        mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)
        --with=[module] //手动加载其他模块到initrd文件中
        --preload //initramfs所听的模块,需要预先加载的模块
        dracut 命令
            //更底层,更功能更强悍
            dracut /boot/initramfs-$(uname -r).img $(uname -r)
        mkinitrd -v -f myinitrd.img $(uname -r)
            -f指定要创建的映像文件,指定内核版本
            
boot loader装入kernel, 然后kernel需要执行/sbin/init, 读取这个文件就必须先mount根文件系统,   

    早期是通过启动时的root=参数告诉内核根文件系统在哪个设备上

    现在根文件系统可能位于一个网络存储如NFS或者raid上,比如RAID而散布于多个设备上, 可能位于一个加密设备上需要提供用户名和密码,这时root=参数就显得不够了. 为了应付这种局面, 先后出现两种机制来作为boot loader装载kernel到真正的/sbin/init执行这个启动的桥梁
initrd和initramfs
相同之处:都是由内核执行其上的某个程序(initrd是/linuxrc, initramfs是/init)由这个程序决定加载什么驱动以及如何装载根文件系统

initrd:
ram disk是一个基于ram的块设备,因此它占据了一块固定的内存,而且事先要使用特定的工具比如mke2fs格式化,还需要一个文件系统
驱动来读写其上的文件。如果这个disk上的空间没有用完,这些未用的内存就浪费掉了,并且这个disk的空间固定导致容量有限,要想装入更多的文件就需要重新
格式化。由于Linux的块设备缓冲特性, ram disk上的数据被拷贝到page cache(对于文件数据)和dentry cache(对于目录项), 这个也导致内存浪费.

initramfs:
最初的想法是Linus提出的: 把cache当作文件系统装载. 他在一个叫ramfs的cache实现上加了一层很薄的封装, 其它内核开发人员编写了一个改进版tmpfs, 这个文件系统上的数据可以写出到交换分区, 而且可以设定一个tmpfs装载点的最大尺寸以免耗尽内存.
initramfs就是tmpfs的一个应用.
优点:
    (1)tmpfs随着其中数据的增减自动增减容量.
    (2)在tmpfs和page cache/dentry cache之间没有重复数据.
    (3)tmpfs重复利用了Linux caching的代码, 因此几乎没有增加内核尺寸, 而caching的代码已经经过良好测试, 所以tmpfs的代码质量也有保证.
    (4)不需要额外的文件系统驱动.
    
另外, initrd机制被设计为旧的"root="机制的前端, 而非其替代物,它假设真正的根设备是一个块设备, 而且也假设了自己不是真正的根设备,
这样不便将NFS等作为根文件系统, 最后/linuxrc不是以PID=1执行的, 因为1这个进程ID是给/sbin/init保留的. initrd机制找到真正的根设备后将
其设备号写入/proc/sys/kernel/real-root-dev, 然后控制转移到内核由其装载根文件系统并启动/sbin/init.

initramfs则去掉了上述假设, 而且/init以PID=1执行, 由init装载根文件系统并用exec转到真正的/sbin/init, 这样也导致一个更为干净漂亮的设计.
    

initramfs制作:
    1. 查看initramfs的内容
    # mkdir temp ; cd temp
    # cp /boot/initrd.img-2.6.24-16 initrd.img-2.6.24-16.gz
    # gunzip initrd.img-2.6.24-16.gz
    # cpio -i --make-directories < initrd.img-2.6.24-16

    2. 创建initramfs
    命令:mkinitramfs, update-initramfs

    1) mkinitramfs
    # mkinitramfs -o /boot/initrd.img 2.6.24-16
    Note: 2.6.24-16是需要创建initramfs的kernel版本号,如果是给当前kernel制作initramfs,可以用uname -r查看当前的版本号。
    提供kernel版本号的主要目的是为了在initramfs中添加指定kernel的驱动模块。
    mkinitramfs会把/lib/modules/${kernel_version}/ 目录下的一些启动会用到的模块添加到initramfs中。
    2)update-initramfs
    更新当前kernel的initramfs
    # update-initramfs -u
    在添加模块时,initramfs tools只会添加一些必要模块,用户可以通过在/etc/initramfs-tools/modules文件中加入模块名称来指定必须添加的模块。
    
initrd制作:
    #mkinitrd /boot/initrd.img $(uname -r)    
    如果需要指定哪些module在启动时必须load,需要加上--preload=module或者 --with=module这样的选项。 这两者的区别在于--preload指定的module会在/etc/modprobe.d/* 里声明的任何SCSI模块之前被加载,--with指定的module会在/etc/modprobe.d/* 里声明的任何SCSI模块之后被加载。
    另外还有一个选项需要被注意,即--builtin=module。在manual里这个选项的解释是:Act as if module is built into the kernel being used. mkinitrd will not look for this module, and will not emit an error if it does not exist. This option may be used multiple times.
    根据上面的解释,可以看出builtin选项另外还有一个取巧的用处。以我所用的平台Acer Aspire One为例, 我在用mkinitrd制作RAM disk镜像是出现一个错误“No module ohci-hcd found ...”,遇到这个情况,builtin选项就起作用了,用--builtin=ohci-hcd, mkinitrd就可以忽略ohci-hcd不存在这个事实了。    
    
八、grub2详解
GRUB2是借鉴GRUB改写到更加安全强大到多系统引导程序,现在大部分较新的Linux发行版都是使用GRUB2作为引导程序的。
GRUB2采用了模块化设计,使得GRUB2核心更加精炼,使用更加灵活,同时也就不需要像 GRUB那样分为stage1,stage1_5,stage2这样三个阶段了。
GRUB2和GRUB相比具有如下一些新特征:
    无 stage1 stage1.5 stage2
    配置文件采用新语法,支持脚本,假如新的命令,配置文件名为 grub.cfg
    配置文件 grub.cfg不可写,由 grub2-mkconfig 自动产生,由 update2-grub 维护。
    分区号不再从 0开始,而是从 1开始
    支持更多到文件系统,如:ext4、hfs、ntfs,并可以直接从 lvm和raid中读取文件/li>
    grub2有更可靠的方法在磁盘上有多系统时发现文件和目标内核,可以用命令发现系统设备号或者UUID。
    引入了设备模块,使得 core 镜像保持更小到尺寸
    在启动时没有选择菜单的话,按住shift即可强制显示菜单

GRUB2主要镜像文件:

    boot.img
    boot.img 相当与 GRUB 的 stage1 它被写入 MBR或 boot分区,它不能识别任何文件系统,在GRUB2安装时GRUB2内核镜像在磁盘中到位置写入到 boot.img 中,这就使得 boot.img 能够在不能识别文件系统的情况下加载内核镜像。
    cdboot.img
    当从CD引导情况下被写入内核镜像第一个扇区到内容,它负责加载其余的内核镜像到内存。
    diskboot.img
    当从磁盘引导情况下被写入内核镜像第一个扇区到内容,它负责加载其余的内核镜像到内存。
    pxeboot.img
    当从网络启动时使用到的。
    kernel.img
    此镜像包含GRUB2运行时包含的基本工具,框架驱动、文件句柄、环境变量、安全模式命令行解析器等,他可以直接使用但是通常它会被编译进所有的内核镜像中使用。
    core.img
    这是GRUB2的内核镜像,它由grub-mkp_w_picpath程序将kernel.img和一些模块动态编译而成,一般情况下他已经包含足够的模块去访问/boot/grub,模块机制使得内核镜像能保持很小的尺寸。在某种程度上,它可以被视为 GRUB 中的 stage2。
    *.mod
    这是一些可以动态加载的一些模块,当我们需要时,可以将它们可以被动态加载编译进内核镜像,也可以使用insmod手动加载。他们就代替 GRUB 中的 stage1_5 之类到镜像。

安装 GRUB2
一、grub2-install 脚本

    1.安装 GRUB 文件到 /boot/grub2
    2.复制/usr/lib/grub/i386-pc/ 目录下的*.mod、*.lst、*.img到/boot/grub目录下
    3.调用grub2-probe扫描计算机并收集磁盘和分区信息
    4.调用grub2-mkp_w_picpath构建一个新的new.img
    5.grub2-setup把grub的boot.img写入MBR中,把core.img写进设备的第一个扇区

二、grub2-install 不会调用 grub2-mkconfig生成grub.cfg 我们需要手动调用。
 

    1.grub2-mkconfig脚本调用grub2-mkdevicemap和grub2-probe生成grub.cfg
    2.调用 grub2-set-default设置进入系统的默认内核
    3.调用 grub2-mkdevicemap生成新的device.map,grub-mkdevicemap程序可以创建
    device.map文件,在执行grub-install时会自动执行他以创建映像关系,如果文件不存在,
    则会读取/boot/grub2/devicd.map这个文件,如果映像文件存在,
    则grub读取他创建BIOS drives to OS drives

GRUB2配置
    GRUB2不再使用 menu.list,而是使用全新的配置文件 /boot/grub2/grub.cfg,文件权限为 444,其目的就是为避免手动更新,我们可以借助 grub2-mkconfig -o /boot/grub2/grub.cfg 命令来更新。/boot/grub2 下到模块可以按需自动加载,模块可以在配置文件中配置,每个模块以 ### BEGIN /etc/grub.d/module_config_name ###开始,以### END /etc/grub.d/module_config_name ### 结束,这些对应的模块文件位于 /etc/grub.d目录之下,次目录下的文件名前面到数字决定了文件的执行顺序,数字越小越先执行,自定义选项在40_custom中定义,这些文件必须有执行权限才会被update-grub读取,并把配置合并到grub.cfg中。

 

   /etc/grub.d/00_header
    配置初始的显示项目,如默认选项,时间限制等,一般由/etc/default/grub导入,一般不需要配置
    /etc/grub.d/05_debian_theme
    配置引导画面,文字颜色等主题
    /etc/grub.d/10_linux
    定位当前操作系统使用中的root设备内核的位置
    30_os-prober
    用来搜索linux和其他系统,此脚本中的变量用来指定在/boot/grub/grub.cfg 和 grub2菜单中的名称显示方式,可以修改/etc/default/grub光比这个脚本
    40_custom
    用来加入用户自定义的菜单样板,将会在执行update-grub时更新至grub.cfg中
    41_custom
    判断custom.cfg此配置文件是否存在,如果存在就加载它
    GRUB2在每次生成grub.cfg的时候,都会检查并设置 /etc/default/grub 配置选项,我们可以通过修改/etc/default/grub来改变 GRUB2到行为。
    常用配置选项有以下这些:
    GRUB_DEFAULT
    制定默认菜单选择项,可以是从0开始数字,也可以是 title 后面的字符串,
    当值是‘saved’时有特殊含义:默认的菜单选则项会被保存在GRUB_SAVEDEFAULT中,
    下次启动时会从这个值启动。当值为saved时可以用grub2-set-default和grub2-reboot来设置默认启动项,
    grub2-set-default到下次修改前都有效,grub2-reboot下次启动时生效
    GRUB_SAVEDEFAULT
    只有这个值是true,GRUB_DEFAULT是saved时才会生效
    GRUB_TIMEOUT
    选择菜单的显示时间,默认是5,值是0表示不显示菜单选项,值是-1表示无限等待用户选择
    GRUB_HIDDEN_TIMEOUT
    GRUB2第一次执行时会寻找其他操作系统,如果没有检测到则会将菜单隐藏,
    如果有其他操作系统才会显示菜单,如果参数大于0,则会等待响应的秒数,
    但是不会显示菜单,可以按住shift显示菜单。
    GRUB_DISTRIBUTOR
    菜单中的描述名称,采用命令lsb_release判断,应该是红帽系列的,如果不是就归为Debian
    GRUB_CMDLINE_LINUX
    此行将追加到所有的linux 定义内核行的后面,不论是救援模式还是一般模式
    GRUB_CMDLINE_LINUX_DEFAULT
    次选项只会追加在一般模式后面,同上
    GRUB_TERMINAL=console
    启用console,默认不启用
    GRUB_DISABLE_LINUX_UUID=true
    在GRUB2中指定root时可以使用UUID,默认不启用
    GRUB_GFXMODE=640×480
    图形化菜单的分辨率,默认不启用
    GRUB_DISABLE_LINUX_RECOVERY=true
    禁止显示救援模式
    This entry was written by zpz, posted on 2012 年 11 月 13 日 at 下午 12:01, filed under linux, linux系统管理, shell and tagged grub, GRUB2, grub配置. Bookmark the permalink. Follow any comments here with the RSS feed for this post. Post a comment or leave a trackback: Trackback URL.