Linux入门攻坚——16、Linux系统启动流程

CentOS5、6的启动流程
    Linux:kernel + rootfs,Linux系统就是内核加上根文件系统。
内核之上是库:
库:函数集合,function,函数具有调用接口,库函数不能单独执行,必须被其他程序调用
    过程调用:procedure,没有返回结果
    函数调用:function,有返回结果

程序:程序调用库或系统调用,完成业务,可以单独执行。

内核设计流派:
    单内核模式:Linux,把所有功能集成于同一个程序
    微内核模式:Windows,Solaris,每种功能使用一个单独子系统实现

Linux内核特点:
    支持模块化:.ko(是内核的模块,相对的有.so,共享对象模块,是共享库的模块文件)
    支持模块的动态装载和卸载;

    组成部分
        核心文件:/boot/vmlinuz-VERSION-release
            ramdisk:
                CentOS 5:/boot/initrd-VERSION-release.img
                CentOS 6:/boot/initramfs-VERSION-release.img
        模块文件:/lib/modules/VERSION-release
ramdisk是用文件来模拟磁盘,提供最开始的根文件系统,以装载系统启动必须的驱动。        

CentOS 系统启动流程:
    POST:加电自检
        ROM:CMOS,BIOS:Basic Input and Output System
        内存是ROM+RAM组成
    BOOT sequence:按次序查找各引导设备,第一个有引导程序的设备即为本次启动用到的设备
        bootloader:引导加载器,程序
            windows:ntloader
            Linux:LILO——LInux LOader;GRUB——GRand Uniform Bootloader,GRUB有0.X版,叫做GRUB Legacy,GRUB 1.X,叫GRUB2
        bootloader功能:提供一个菜单,允许用户选择要启动系统或不同的内核版本;把用户选定的内核装载到内存中的特定空间中,解压、展开,并把系统控制权移交给内核;
    MBR:(0磁道0扇区)
        446:bootloader
        64:fat
        2:55AA

    GRUB:
        bootloader:1st stage
        disk:2nd stage

kernel:
    自身初始化:
        探测可识别到的所有硬件设备;
        加载硬件驱动程序;(有可能会借助于ramdisk加载驱动)
        以只读方式挂载根文件系统;
        运行用户空间的第一个应用程序:/sbin/init

    init程序的类型:
        SysV:init,CentOS 5
            配置文件:/etc/inittab
        Upstart:init,CentOS 6
            配置文件:/etc/inittab, /etc/init/*.conf
        Systemd:systemd,CentOS 7
            配置文件:/usr/lib/systemd/system, /etc/systemd/system

    ramdisk:
        内核中的特性之一:使用缓冲和缓存来加速对磁盘上的文件的访问
        ramdisk --> ramfs,CentOS5将ramdisk模拟成磁盘,导致内核再次缓冲
        CentOS5:initrd,工具程序:mkinitrd
        CentOS6:initramfs,工具程序:mkinitrd,dracut

系统初始化:
    POST --> BootSequence(BIOS) --> Bootloader(MBR) --> kernel(ramdisk) --> rootfs(只读) --> init

/sbin/init
    CentOS 5:
    运行级别:为了系统的运行或维护等应用目的而设定,共0-6,一个7个级别
        0 :关机
        1 :单用户模式(root,无须登录),single,维护模式;
        2 :多用户模式,会启动网络功能,但不会启动NFS,维护模式;
        3 :多用户模式,正常模式,文本界面
        4 :预留级别,可同3级别
        5 :多用户模式,正常模式,图形界面

        默认级别:3,5
        切换级别:init #
        查看级别:runlevel、who -r

各级别的不同之处,主要在于init按照配置文件进行的初始化的不同

配置文件:/etc/inittab   (CentOS 5)
每行定义一种action以及与之对应的process
    id : runlevel : action : process
    action:
        wait:切换至此级别运行一次
        respawn:此process终止,就重新启动之
        initdefault:设定默认运行级别,process省略
        sysinit:设定系统初始化方式,此处一般指定为/etc/rc.d/rc.sysinit

示例:   
    id : 3 : initdefault : 
    si :  : sysinit : /etc/rc.d/rc.sysinit
    l0 : 0 : wait : /etc/rc.d/rc 0
    l1 : 1 : wait : /etc/rc.d/rc 1
    ........
    l6 : 6 : wait : /etc/rc.d/rc 6
    说明:rc 0-->意味着读取/etc/rc.d/rc0.d/目录下的文件(脚本链接),文件以K或S开头
        K*:K##*,##运行次序,越小越先运行,K是Kill要关闭的,数字越小的服务,通常为依赖到别的服务。
        S*:S##*,S是Start,要启动的,数字越小越先运行,数字小的服务,通常为被依赖到的服务。

        for srv in /etc/rc.d/rc0.d/K*;do
            $srv stop
        done
        for srv in /etc/rc.d/rc0.d/S*;do
            $srv start
        done

 

chkconfig命令:查看每个服务在不同级别下是启动还是关闭的。
chkconfig --list

    chkconfig --level 3 NetworkManager  off   修改级别下是启动还是关闭,即修改K或S
添加:
    SysV的服务脚本放置于/etc/rc.d/init.d (/etc/init.d)

        chkconfig --add name
测试添加自定义的服务:testsrv:
1)在/etc/rc.d/init.d目录下新建testsrv文件

2)给testsrv文件增加执行权限:
chmod +x testsrv
3)加到服务中去:
chkconfig --add testsrv
下图是添加服务前的文件

添加后,查看结果:

删除:
    chkconfig --del name
    chkconfig --del testsrv

修改指定的链接类型
    chkconfig [--level levels] name <on | off | reset>
        --level ####:指定要设置的级别;省略时表示2345

特殊的S99local服务:正常级别下,最后启动的一个服务,没有连接至/etc/rc.d/init.d目录下

指向的是上级目录的rc.local,是一个脚本文件,可以将不便或不需要写为服务脚本放于/etc/rc.d/init.d目录下,不需要chkconfig管理,但又想开机时自动运行的命令或脚本写入此文件。

/etc/rc.local也指向/etc/rc.d/rc.local

在init的最后,就是要启动一个供用户登录的会话窗口,使用户可以登录,登录后,启动bash进行交互操作。假设这个登录在inittab中如下:
tty1:2345:respawn:/usr/sbin/mingetty tty1
tty2:2345:respawn:/usr/sbin/mingetty tty2
......
tty6:2345:respawn:/usr/sbin/mingetty tty6
    mingetty会调用login程序,以验证用户登录合法性

/etc/rc.d/rc.sysinit:系统初始化脚本,完成以下功能
    (1)设置主机名
    (2)设置欢迎信息
    (3)激活udev和selinux
    (4)挂载/etc/fstab文件中定义的文件系统
    (5)检测根文件系统,并以读写方式重新挂载根文件系统
    (6)设置系统时钟
    (7)激活swap设备
    (8)根据/etc/sysctl.conf文件设置内核参数
    (9)激活lvm及software raid设备
    (10)加载额外设备的驱动程序
    (11)清理操作

总结:(CentOS 5的init)
/sbin/init --> (/etc/inittab) --> 设置默认运行级别 --> 运行系统初始化脚本、完成系统初始化 -->关闭对应级别下需要关闭的服务,启动需要启动的服务 --> 设置登录终端

CentOS 6:
    init程序为:upstart,由Ubuntu研制,其配置文件:/etc/inittab 、/etc/init/*.conf,主要是后者,即将CentOS5的inittab分割成多个.conf文件。

注意:/etc/init/*.conf文件语法,遵循upstart配置文件语法格式;

网上找的启动流程图:

CentOS5、6忘记密码的解决:
    启动系统时,设置其运行级别1:启动时,提示按任意键进入隐藏的GRUB菜单

    

按e键可以编辑菜单:

root (hd0,0)指定grub根目录所在设备位置,这里是第一个硬盘的第一个分区,这里root是grub的命令,指定boot所在的分区作为grub的根目录
kernel是加载内核,指定内核文件,以只读(ro)加载文件系统的根目录,即根分区,root=。。。参数指定文件系统根分区的位置,使用了lvm
initrd是将.img文件作为虚拟磁盘载入内存,模拟根文件系统,其上有少量驱动程序等,如要使用lvm,必须加载lvm文件系统驱动
以上指定的分区、设备可以参考下面查看到的信息

通过上面的信息,root(hd0,0)就是指定/boot所在的分区,即/dev/sda1,kernel加载的内核文件 /vmlinuz-2.6.32-754.el6.x86_64,实际上是(hd0,0)/vmlinuz-2.6.32-754.el6.x86_64,这里的根是指的boot分区,后面的参数root=/dev/mapper/vg_study610-lv_root,才是指定文件系统的根分区,其使用的是lvm,看上图,mount信息中根“/”的挂载设备就是这里的参数值。initrd是在没有加载文件系统根目录前,模拟的根文件系统,以提供部分驱动。如要想使用真正的根文件系统,必须加载lvm驱动,这个就要放在initrd的文件中。

这里编辑kernel这一行,这个命令行很长,具体如下:
kernel /vmlinuz-2.6.32-754.el6.x86_64 ro root=/dev/mapper/vg_study610-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=vg_study610/lv_swap SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_study610/lv_root  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
在其后添加空格 1或single,表示运行于level 1级别。然后回车,确认修改,回到上一级菜单,然后按b键,表示启动运行这个内核。

不需要输入密码,直接以root登录了,然后可以修改密码。

GRUB(Boot Loader)
grub legacy(grub1)
    stage 1:mbr
    stage1_5:mbr之后的扇区,让stage1中的bootloader能识别stage2所在的分区上的文件系统
    stage2:磁盘分区(/boot/grub/)
    配置文件:/boot/grub/grub.conf  <-- /etc/grub.conf
    stage2及内核等通常放置于一个基本磁盘分区;
    功用:
        (1)提供菜单,并提供交互式接口
            e:编辑模式,用于编辑菜单
            c:命令模式,交互式接口
        (2)加载用户选择的内核或操作系统
            允许传递参数给内核|
            可隐藏此菜单
        (3)位菜单提供了保护机制
            为编辑菜单进行认证
            为启用内核或操作系统进行认证

如何识别设备:
    (hd#,#):第一个#表示磁盘号,第二个#表示第#个分区,都是从0开始编号。

grub的命令行接口:
    find (hd#,#)/PATH/TO/SOMEFILE:查找特定文件
    root (hd#,#):指定根目录
    kernel /PATH/TO/KERNEL_FILE:设定本次启动时用到的内核文件;额外还可以添加许多内核支持使用的cmdline参数,如:
        init=/path/to/init , selinux=0
    initrd l /PATH/TO/INITRAMFS_FILE:设定为选定的内核提供额外文件的ramdisk
    boot:引导启动选定的内核    

手动在grub命令行接口启动系统:
    grub>root (hd0,0)
    grub>kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
    grub>initrd /initramfs-VERSION-RELEASE.img
    grub>boot

grub配置文件:/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:内核匹配的ramfs文件
            password [--md5] STRING:启动选定的内核或操作系统时进行认证

grub-md5-crypt:grub提供的加密工具

安装grub:grub-install命令
    (1)grub-install
        grub-install --root-directory=ROOT /dev/DISK
    (2)grub
        grub>root (hd#,#)
        grub set (hd#)

实验1:新增加一块硬盘,在此硬盘上安装grub并设置init为bash。(即为新盘安装系统)
    (1)新增一块硬盘



        (2)对新增的磁盘做分区

使用fdisk /dev/sdb进行分区

sdb1为boot分区,sdb2为swap分区,sdb3为根分区。
    (3)安装文件系统:

    (4)将sdb1挂载到当前系统中,sdb1作为新系统的boot分区

    (5)安装grub
运行grub-install:
    grub-install --root-directory=/mnt /dev/sdb

这里需要注意的是--root-directory的指定,这里是指定boot的根,实验的boot分区是挂载在/mnt/boot下,所以/mnt/boot应该为boot的根,但是grub安装程序会自动在根下创建boot子目录,所以,如果--root-directory指定为/mnt/boot的话,最终会创建/mnt/boot/boot/grub,所以根目录指定不包括boot子目录。如下的测试:

在grub目录下,可以看到stage1,stage1_5和stage2,stage1此时已经安装到了sdb磁盘的MBR,grub中缺少配置文件,手动创建一个。
同时,在boot的根目录下,此时还没有内核文件与ramfs文件,拷贝当前系统的文件到此目录下:


这里要注意的是:第一条 root (hd0,0)为何是(hd0,0),因为最终这块磁盘要单独作为系统使用,这就成为了第一磁盘,第二条kernel中的root,是最终单独使用磁盘时,作为根目录的磁盘,即前面分区的sdb3,最终成为sda3。
然后,要成为文件系统的根,需要按照FHS,创建相应的目录结构:

拷贝bash程序到对应目录,作为新系统启动后运行的进程,一个程序要运行,不但要拷贝程序本身,还要有对用的共享库,测试拷贝的bash是否可用,可以将根切换到新系统:chroot /mnt/sysroot

修改一下grub.conf配置文件,将kernel命令添加参数init=/bin/bash,即限定kernel后的init是bash,而不是默认的init。
    (6)新建虚拟机,其硬盘使用刚才的磁盘。

    (7),启动新建的虚拟机

启动失败,原因是拷贝的内核中启动了selinux,在配置菜单中添加禁止selinux的参数:


系统引导成功。

实验2:本机grub损坏,但是系统还在运行中。
    (1)备份MBR,然后破坏MBR,但不破坏分区表,即MBR中的前446被破坏:

此时,重启系统就会出错。
    (2)使用grub-install修复:

如此,便修复了MBR。
    (3)还可以进入grub命令交互界面:
指定boot根:root (hd0,0)
修复: setup (hd0)

可以看到,setup检测到stage1不存在了,然后安装执行了stage1,在MBR,然后在随后的27个扇区安装的stage1_5。

如此,也修复完毕。

实验3:本机grub损坏,重启系统了,此时需要使用使用修复模式(Rescue)进行修复,需要另外的启动盘,如光盘、U盘等。
破坏MBR:

重新启动后:

链接ISO文件,从光驱启动:


最后一项回车:

选择Rescue a CentOS system,或者在第一个界面按Esc,进入命令行,键入:linux rescue

可以看到,已经发现了已安装的系统,并将其挂载到/mnt/sysimage下。

按回车,运行shell,在shell下,切换root到原来的系统

再次启动,可以引导。

CentOS6的界面:



以上方法恢复后,重新启动引导后出现如下警告:

等待重新加载后,启动成功。

Linux Kernel
    单内核模式、但充分借鉴了微内核模式的优先,为内核引入模块化机制。
    内核组成部分:
        kernel:内核核心,一般为bzImage,通常在/boot目录下,名称为vmlinuz-VERSION-RELEASE
        kernel object:内核对象,一般放置于/lib/moudles/VERSION-RELEASE/目录下
        内核对象可以做成模块功能的,有三种选择:
            [ ]:N ,不选择,不编译此功能
            [M]:M,选择编译成模块
            [*] :Y,编译成内核核心部分。
        辅助文件:ramdisk,两种
            initrd 和 initramfs
运行中的内核:uname命令
    uname [option]...
        -n:显示节点名称
        -r:显示VERSION-RELEASE号

    lsmod :查看已经装载的内核模块,此命令读取的是/proc/modules文件的内容。

查看某模块详细信息:modinfo [option] 模块名
参数:-n、-p、-a、-d、-l

装载或卸载模块命令:modprobe 
装载:modprobe [-C config-file] [moudlename] [module parameters...]
    配置文件:/etc/modprobe.conf,/etc/modprobe.d/*.conf
卸载:modprobe [-r] modulename...

查询模块信息时,能够看到依赖关系,这个依赖关系是保存在/lib/modules/VERSION-RELEASE/modules.dep文件中,实际使用是将其编译成二进制,即modules.dep.bin文件。

depmod命令:内核模块依赖关系文件及系统信息映射文件的生成工具。
装载或卸载内核模块的其他命令:
    insmod [filename] [module option]
    rmmod modulename

/proc目录
    内核把自己内部状态信息及统计信息,以及可配置参数通过proc伪文件系统加以输出。
    参数:
        只读:输出信息
        可写:可接受用户指定“新值”来实现对内核某功能或特性的配置,主要在 /proc/sys目录
        sysctl命令用于查看或设定此目录中诸多参数
            sysctl -w path.to.parameter=VALUE
        echo命令通过重定向的方式也可以修改大多数参数的值;
            echo "VALUE" > path/to/parameter

sysctl命令,配置文件为/etc/sysctl.conf
    (1)设置某参数: sysctl -w path.to.parameter=VALUE
    (2)通过读取配置文件设置参数:sysctl -p [/path/to/conf_file]
内核中的路由转发:是否开启功能是配置在如下位置的:
    /proc/sys/net/ipv4/ip_forward

默认为0,没有开启路由转发功能
想修改为永久有效,可以编辑/etc/sysctl.conf:

将net.ipv4.ip_forward=0改为=1
修改后不会立即生效,需要重读配置文件

常用的几个参数:
    net.ipv4.ip_forward   :路由转发
    vm.drop_caches    :回收缓存
    kernel.hostname    :主机名

/sys目录
    sysfs:输出内核识别出的各硬件设备的相关属性信息,也有内核对硬件特性的设定信息;有些参数是可以修改的,用于调整硬件的工作特性。
udev通过此路径下输出的信息动态为各设备创建所需要设备文件;udev是运行在用户空间程序;专用工具:udevadmin、hotplug
udev为设备创建设备文件时,会读取其事先定义好的规则文件,一般在/etc/udev/rules.d及/lib/udev/rules.d目录下。

ramdisk文件的制作
    mkinitrd [OPTION...] [<initrd-image>] <kernel-version>
        mkinitrd /boot/initramfs-$(uname -r).img  $(uname -r)
    dracut [OPTION]... <image>  <kernel-version>
        dracut /boot/initramfs-$(uname -r).img  $(uname -r)

ramdisk文件是一个gz压缩文件,修改后缀名后,解压缩,再看文件类型,是cpio归档文件,将其展开,基本上是简化的根系统。sbin/目录下有switch_root,就是内核完成启动后最后的根切换要执行的程序。

编译内核
    前提:
        (1)准备好开发环境;
        (2)获取目标主机上硬件设备的相关信息;
        (3)获取到目标主机系统功能的相关信息,例如要启用的文件系统;

    开发环境:
        Development Tools和Server Platform Development两个包组
    目标主机硬件设备相关信息:
        CPU:cat /proc/cupinfolscpux86info -a (这个需要安装yum install x86info)
        PCI设备:lspci -vlsusb -vlsblk 
    了解全部硬件设备信息,hal-device
 
  编译时可以使用现有配置文件模板,在/boot目录下有当前运行系统编译时的配置文件,可以作为新系统编译时的配置模板:/boot/config-2.6.32-754.el6.x86_64
    开始:
        (1)下载新版本内核源码:如linux-3.10.67.tar.gz   
        (2)解压到/usr/src下:tar xf linux-3.10.67.tar.gz -C /usr/src
        (3)做一个链接:理ln -sv linux-3.10.67.tar.gz linux
        (4)拷贝/boot/config-2.6.32-754.el6.x86_64到/usr/src/linux/下,命名为.config
        (5)make menuconfig,对新编译的版本进行配置

        (6)开始编译,make ,还可以启动多线程make -j 4
        因为make是终端相关的,如果一不小心关闭了终端,结果就悲剧了,所以可以使用screen,打开虚拟屏幕

使用Ctrl+ad退出。
执行make -j 4开始编译。此时终端断开,进入后编译依然存在。
screen -ls查看存在的虚拟屏幕,使用screen -r 编号 重新进入

        (7)make modules_install
        (8)make install
          安装bzImage为/boot/vmlinuz-VERSION-RELEASE
          生成initramfs文件
          编辑grub配置文件
        (9)重启系统,并测试新内核

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值