CentOS系統啟動流程

概述:系統啟動流程是Linux一個重要的內容,深入了解啟動流程會對我們學習Linux起到一個順水推舟的作用。因為CentOS 7改動較大,所以下面的內容只是針對CentOS 5和6來說的。下面進入正題。

啟動流程:

 第一步:POST加電自檢

   此過程的就是為了檢測一下外界的硬件設備是否能夠正常運行,如CPU,內存設備,硬盤等等這些硬件設備是否可以正常工作。

 第二步:BIOS選擇啟動方式

   BIOS對于經常基礎計算機的人應該不會陌生,特別是那些經常裝系統的人,它就是列出幾個選項,讓你選擇以什么方式來啟動系統,常見的有硬盤啟動,光盤,以及網絡方式啟動。

 第三步:BootLoader

   這個步驟略有復雜,但是其實現的功能就是,引導加載系統中的核心文件,并提交到內存運行,它會列出一個grub菜單,其中的選項是我們操作系統的內核,你選擇的內核文件會被加載至內存中運行。

    引導加載器grub:找到內核文件,提供grub菜單

        1)Stage  1,讀取MBR,目的是為了驅動stage2所在的分區(stage2上存放的是內核文件以及rootfs的文件系統驅動)
        2)Stage 1.5,通過Stage1可以識別到stage2所在的分區,然而分區上的文件系統是需要文件系統驅動程序的,stage 1.5就是為了stage2提供文件系統驅動的(在0柱面1扇區后面的63個扇區中存儲)        

        3) 通過stage1和1.5,stage2將被加載(一般為/boot分區),此時stage2,將提供一個內核選擇菜單,并且stage2分區內還有一個 ramdisk或者ramfs文件,其為一個臨時的根文件系統,其中包含了真正的rootfs所需要的驅動文件,所以stage2及內核文件通常放置于一 個基本的磁盤分區(一般為/boot分區).
        注意:ramdisk臨時根文件系統是在安裝操作系統后臨時生成的,它在安裝操作系統后,能掃描當前主機硬盤設備的型號,并找到相關驅動做成一個臨時根


wKiom1fTrJCgYwSaAAAo3bBzkxo171.png

      代碼分析:

[root@localhost testdir]# cp /boot/initramfs-2.6.32-642.el6.x86_64.img . //將/boot下的ramfs文件拷貝至當前目錄
[root@localhost testdir]# zcat initramfs-2.6.32-642.el6.x86_64.img |cpio -id //將其解壓縮
140023 blocks
[root@localhost testdir]# ls        //其包含的內如如下,因為是臨時的根文件,所以目錄結構也類似于我們的rootfs,其中包含rootfs所需要的文件系統的驅動
bin      dracut-004-409.el6  init                initqueue-settled                    lib    netroot    pre-trigger  sbin     tmp
cmdline  emergency           initqueue           initqueue-timeout                    lib64  pre-mount  pre-udev     sys      usr
dev      etc                 initqueue-finished  initramfs-2.6.32-642.el6.x86_64.img  mount  pre-pivot  proc         sysroot  var
[root@localhost testdir]#

 第四步:加載內核文件

   通過上面所選擇的內核文件,來將其加載至內存中解壓縮,分為以下四個步驟

     1)探測可識別到的所有硬件設備。

     2)加載硬件驅動程序(可能借助于ramdisk/ramfs加載驅動)

     3)以只讀方式掛載根文件系統

     4)運行用戶空間的第一個應用程序:/sbin/init

       注意:其中Ramdisk/ramfs即stage2所在分區的rootfs文件系統驅動的文件,有了內核文件及所需要的rootfs的文件系統驅動,為避免內核文件有bug或者人為操作問題,先以只讀方式掛載rootfs

    代碼分析:

wKioL1fTriPQjHNmAAB9ILqHZZQ654.png

 第五步:Init程序初始化

   1)根據init的配置文件獲取到運行級別信息,并獲取系統初始化腳本的文件路徑。(CentOS 5的init文件為/etc/inittab,CentOS6將/etc/inittab文件拆分為多個文件)

     init的配置文件:

       CentOS 5:采用SysV init方式,其特點是啟動用戶空間的服務程序,通常通過腳本進行,有依賴關系的服務將被串行啟動,這也導致了CentOS 5的啟動過程相當緩慢,配置文件為/etc/inittab

       CentOS 6:采用Upstart的方式,其特點是類似于并行啟動;配置文件:/etc/inittab,/etc/init/*.conf

    2)讀取系統初始化腳本/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) 清理操作
    3)根據前面獲取的運行級別,運行/etc/rc.d/rc腳本文件
       /etc/rc.d/目錄下有幾個rc#.d(#號數字,也就是代表運行級別),其目錄下文件為鏈接文件,其指向/etc/init.d/下的服務腳本文家,根據在/etc/inittab獲取的默認運行級別和/etc/rc#.d下的鏈接文件,來啟動和關閉系統的服務,想必現在也能聯想到了為什么不同級別下啟動的服務不相同,為什么有的服務開機啟動,有的卻關閉
       /etc/rc#.d/下的鏈接文件以K或者S開頭,K表示開機要被停止的服務,S表示開機要被啟動的服務,而且服務腳本都會有一個優先級,

        K*:K##*:##運行次序;數字越小,越先運行;數字越小的服務,通常為依賴到別的服務
        S*:S##*:##運行次序;數字越小,越先運行;數字越小的服務,通常為被依賴到的服務

[root@localhost boot]# cd /etc/rc.d
[root@localhost rc.d]# ls
init.d  rc  rc0.d  rc1.d  rc2.d  rc3.d  rc4.d  rc5.d  rc6.d  rc.local  rc.sysinit
[root@localhost rc.d]# cd rc.3.d
root@localhost rc.d]# cd rc3.d
[root@localhost rc3.d]# ls
K01dnsmasq         K35vncserver   K88wpa_supplicant   S08ip6tables    S14nfslock     S26lm_sensors              S95anacron
K02avahi-dnsconfd  K50netconsole  K89dund             S08iptables     S15mdmonitor   S26lvm2-monitor            S95atd
K02NetworkManager  K50snmpd       K89netplugd         S08mcstrans     S18rpcidmapd   S28autofs                  S97rhnsd
K05conman          K50snmptrapd   K89pand             S10network      S19rpcgssd     S55sshd                    S97rhsmcertd
K05saslauthd       K69rpcsvcgssd  K89rdisc            S11auditd       S22messagebus  S56cups                    S97yum-updatesd
K05wdaemon         K73ypbind      K99readahead_later  S12restorecond  S25bluetooth   S56rawdevices              S98avahi-daemon
K10psacct          K74ipmi        S00microcode_ctl    S12syslog       S25netfs       S57vmware-tools-thinprint  S99firstboot
K15httpd           K74nscd        S03vmware-tools     S13cpuspeed     S25pcscd       S80sendmail                S99local
K15svnserve        K74ntpd        S04readahead_early  S13irqbalance   S26acpid       S85gpm                     S99smartd
K20nfs             K85mdmpd       S05kudzu            S13iscsi        S26haldaemon   S90crond
K24irda            K87multipathd  S07iscsid           S13portmap      S26hidd        S90xfs

       wKiom1fTuE3jn7HjAADGphozqfA218.png

     注意:在2345級別的/etc/rc#.d目錄下都會有一個rc.local,它其實也是一個鏈接文件,鏈接到/etc/rc.d/rc.local,它并不是啟動文件,而是一個普通的文件,不過它的優先級最小,所以最后啟動,如果你想要開機做一些什么操作,可以寫到這個腳本里面。

[root@localhost rc3.d]# find /etc/ -name *local
/etc/rc.d/rc2.d/S99local
/etc/rc.d/rc5.d/S99local
/etc/rc.d/rc3.d/S99local
/etc/rc.d/rc4.d/S99local

 wKioL1fTuOCBMVgMAAA29uWUGEc613.png

   代碼分析:以下為CentOS 5中的/etc/inittab文件 

id:3:initdefault:        //獲取默認運行級別;3代表運行級別

# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit    //執行/etc/rc.d/rc.sysinit系統初始化腳本
// 根據前面獲取到的默認運行級別,執行/etc/rc.d/rc腳本文件
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
//下面為/etc/rc.d/rc腳本中的一段代碼
# First, run the KILL scripts.        
for i in /etc/rc$runlevel.d/K* ; do        //這是一個for循環,根據前面獲取的默認級別信息,來關閉/etc/rc#.d/下的服務
        check_runlevel "$i" || continue

        # Check if the subsystem is already up.
        subsys=${i#/etc/rc$runlevel.d/K??}
        [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] \
                || continue

        # Bring the subsystem down.
        if LC_ALL=C egrep -q "^..*init.d/functions" $i ; then
                $i stop        //stop  關閉服務!
        else
                action $"Stopping $subsys: " $i stop
        fi
done

# Now run the START scripts.
for i in /etc/rc$runlevel.d/S* ; do    //這也是個for循環,與上面相反,是啟動/etc/rc#.d/下面對應的腳本文件
        check_runlevel "$i" || continue

        # Check if the subsystem is already up.
        subsys=${i#/etc/rc$runlevel.d/S??}
        [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] \
                && continue

        # If we're in confirmation mode, get user confirmation
        if [ -f /var/run/confirm ]; then
                confirm $subsys
                test $? = 1 && continue
        fi

        update_boot_stage "$subsys"
        # Bring the subsystem up.
        if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then
                export LC_ALL=C
                exec $i start    //啟動服務
        fi
        if LC_ALL=C egrep -q "^..*init.d/functions" $i \
                        || [ "$subsys" = "single" -o "$subsys" = "local" ]; then
                $i start        //啟動服務
        else
                action $"Starting $subsys: " $i start
        fi
done

      下圖為系統啟動時服務開啟的界面wKiom1fTotnyQ5d3AAAo8kiQZsQ648.png

  第六步:啟動終端

     根據前面獲取的默認運行級別來啟動終端,如果運行級別為5,則啟動圖形界面

  第七步:用戶登錄

     系統啟動流程結束!

問題總結:

 在此之前,一直有幾點問題困惑著我,我對它們做了一下總結

   1)內核文件在磁盤上,系統還沒有啟動,系統還沒有啟動,/目錄也沒有掛載,前面說先找到boot分區,但是boot分區也是在/的目錄下,/還沒有,去哪找boot???

   問題解答:注意,此時系統去尋找boot分區下的grub菜單、內核文件及rootfs的驅動并不是通過/目錄來尋找,因為此時的/還沒有掛載,無法找到/下面的boot目錄,而是直接去boot的那個磁盤分區去尋找所需要的文件,具體看一下代碼

[root@localhost ~]# cat /boot/grub/grub.conf //grub的配置文件
....省略.....
title CentOS 6 (2.6.32-642.el6.x86_64)
    root (hd0,0)    //hd0,0表示的是磁盤分區,即stage2所在的分區,此處的意義表示的是將hd0,0先設為/目錄,那么下面
    的 kernel和initrd后面的根"/",表示的也是hd0,0,也就是stage2所在的磁盤分區。避免了通過/目錄來尋找
    boot分區的難題.
    //此時的/vmlinuz-2.6.32....其實就是boot分區下的vmlinuz文件
    kernel /vmlinuz-2.6.32-642.el6.x86_64 ro root=/dev/mapper/vg0-root rd_NO_LUKS rd_NO_DM LANG=en_US.UTF-8 rd_LVM_LV=vg0/swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg0/root  KEYBOARDTYPE=pc KEYTABLE=us rhgb crashkernel=auto quiet rhgb quiet
    //同樣的 /initramfs-2.6.32...其實也是boot分區下的initfamfs文件,只不過直接通過磁盤分區去找到的
    initrd /initramfs-2.6.32-642.el6.x86_64.img
[root@localhost ~]#

   2)上面問題的繼續,即使你先加載boot分區,boot分區系統的系統驅動在哪里呢

   問題解答:從以下代碼得知,分區信息是從1柱面開始的,那么0柱面被狗吃了么?答案是沒有被狗吃,MBR存放在了0柱面,0磁道的第一個扇區內,但是它只占據了512個字節,因為0柱面包括了好多扇區,后面的扇區就是為了存放/boot分區的文件系統驅動的。stage1->stage1.5->stage2這個過程就是為了掛載/boot分區,而其中的stage1.5就是尋找/boot分區的文件系統驅動的。

[root@localhost ~]# df    //df查看/目錄的掛在分區
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda2              7858552   5884648   1568264  79% /
/dev/sda1               295561     16787    263514   6% /boot
tmpfs                   511932         0    511932   0% /dev/shm
[root@localhost ~]# fdisk -l    //查看磁盤分區信息

Disk /dev/sda: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          38      305203+  83  Linux    //注意到,起始柱面是從1柱面開始的,根據此前所學內容,第一個柱面是0柱面
/dev/sda2              39        1048     8112825   83  Linux
/dev/sda3            1049        1305     2064352+  82  Linux swap / Solaris

   3)加載內核后,為避免bug或者人為操作失誤,rootfs先以只讀方式掛載,只讀方式掛載怎么寫數據呢?

   問題解答:內核在讀取到init程序后,其中有一個系統初始化腳本,即/etc/rc.d/rc.sysinit腳本,其中有一段代碼如下,在這rootfs會被重新以讀寫方式掛載。

remount_needed() {
  local state oldifs
  [ "$READONLY" = "yes" ] && return 1
  state=`LC_ALL=C awk '/ \/ / && ($3 !~ /rootfs/) { print $4 }' /proc/mounts`
  oldifs=$IFS
  IFS=","
  for opt in $state ; do
        if [ "$opt" = "rw" ]; then
                IFS=$oldifs
                return 1
        fi
  done
  IFS=$oldifs
  return 0
}

# Remount the root filesystem read-write.
update_boot_stage RCmountfs
if remount_needed ; then    //根據前面定義的函數,來實現rootfs的讀寫掛載 mount -n -o remount,rw /
  action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw /
fi

    

流程圖:

   俗話說的好,一圖抵千言,我將上面所述的啟動流程又畫了一幅圖,希望以更加清晰地描述CentOS的啟動流程。

wKiom1fTj5zC5WgFAAOOI4WkZ3g804.png

   

原創文章,作者:我的滑板鞋,如若轉載,請注明出處:http://www.www58058.com/45982

(0)
我的滑板鞋我的滑板鞋
上一篇 2016-09-12
下一篇 2016-09-13

相關推薦

  • 腳本進階筆記整理

    一、邏輯運算 變量:   本地變量、環境變量、局部變量、位置參數變量、特殊變量   變量賦值:name=value,export name=value,declare -x name=value   變量引用:$name,${name}   注意:有些時候{}不能省略,例如 &n…

    Linux干貨 2017-03-26
  • Linux 第五天: (08月01日) Linux用戶組管理

    Linux 第五天: (08月01日) Linux用戶組管理         管理員 root,0普通用戶 1-65535系統用戶 1-499(centos6), 1-999(centos7)登錄用戶 500(centos6)+, 1000(centos7)+   /etc/passwd 用戶及屬性/etc/…

    Linux干貨 2016-08-08
  • 馬哥linux0803作業內容

    1. 創建sysadmins組 將用戶user1,user2,user3加入sysadmins組中 將user3設置為sysadmins的管理員 用user3登錄,將user2從組中移除 設置sysadmins的密碼centos 設置user1 在創建新文件時,文件的所屬組為sysadmins 刪除user1…3 刪除sysadmins 2、三種權限rwx對…

    Linux干貨 2016-08-08
  • 馬哥網絡教育班第21期+第四周課程練習

    1、復制/etc/skel目錄為/home/tuser1,要求/home/tuser1及其內部文件的屬組和其它用戶均沒有任何訪問權限 [root@CentOS6 ~]# cp -r /etc/skel /home/tuser1 [root@CentOS6 ~]# chmod&nb…

    Linux干貨 2016-07-29
  • 文本處理(1)

    文本處理工具最全整理上半部

    Linux干貨 2018-03-15
  • 文件元數據信息的含義、查看方法,和文件時間戳信息的修改方法

    文件數據分成兩類 元數據,英文叫metadata,是數據的屬性; 數據,英文叫data,是數據本身; 使用stat命令查看元數據信息 [0][root@localhost mylinux]# stat /etc/passwd File: ‘/etc/passwd’ Size: 889 Blocks: 8 IO Block: 4096 regular file…

    Linux干貨 2018-03-01

評論列表(1條)

  • 馬哥教育
    馬哥教育 2016-09-20 10:42

    對于開機啟動流程,文章總結的很棒哦,讀完之后,能讓人學到很多知識呢。

欧美性久久久久