天天看點

Linux學習筆記之CentOS6開機流程

在日常使用電腦的時候大家可能會遇到這樣一種場景,計算機昨天用的好好的,下班關機走人,結果第二天一開機發現起不來了,這是為何?接下來就聊聊系統啟動的那些事。

因為是linux與windows在引導系統所用的工具不同(WINDOWS用的ntloader),接下來主要以Linux為主唠叨唠叨(老年癡呆提前了,沒轍)。

計算機的開機按電源鍵接通電源應該算是第一步吧(專業小白三十年,一直被模仿從未被超越),加電以後開始通過BIOS中的設定來先進行硬體的一些自檢,其中包括了CPU這家夥在不在啊,他要是在能不能正常工作啊,要是生病了得囑咐他多喝熱水啊(這句話是跟你女朋友說的,什麼!沒有女票,那就跟别人女朋友說吧,挨打可别來找我O(∩_∩)O~)。

所有硬體檢測都沒問題了,接下來就會根據bios中的boot sequence設定值來開始查找第一個有引導程式的裝置,這個其實就是標明的裝置中有沒有bootloader這個程式可以幫助我們來啟動系統的,下面就進入介紹boot loader這個得力幹将階段。

Boot loader中文名叫引導加載器,他的發展史比較早,初期分成了兩個階段,第一個階段是稱為LILO(Linux loader)這個因為早期的硬體裝置都比較簡單,他也就随大流簡簡單單了起來,雖說簡單但麻雀雖小五髒俱全,該有的都有了隻是因為硬體發展的太快了導緻他顯得力不從心逐漸的被第二階段的grub程式所取代。萬萬沒想到,智能手機大爆發,LILO迎來了他的第二春~,此處不表,自己看去吧。

Grub(Grand Uniform BootLoader)的發展從廣義上來說也分為兩個階段,即0.X階段被稱為GRUB Legacy,在CentOS7後發展到了第二階段即1.X,被稱為GRUB2。

究竟Boot loader有什麼作用呢?一個作用就是我們啟動計算機即将進入centos系統時看到的那個互動式的選擇菜單;另一個作用就是可以讓使用者選擇的系統加載到記憶體中啟動,當系統安裝完成之時,系統的核心檔案一般會放置在單獨劃分的boot分區當中,随之就帶來了一個問題,核心放置在硬碟當中,要讀取核心檔案就要先讀取硬碟驅動,然後讀取檔案系統最後才會讀取到核心檔案,而驅動程式是放置在硬碟當中,此時就陷入了一個“怪圈”,怎麼解決呢?grub程式提出了“三段式”解決方案。

第一階段被稱為stage1,在這一階段是運作boot loader程式,bootloader程式在MBR中,(MBR空間隻有512bytes,bootloader占用了446bytes還有64bytes用來記錄硬碟分區表,2bytes來記錄bootloader程式是否有效),此時運作的boot loader程式隻是最基本的功能,一些配置檔案則被放置在stage2中。

第二階段為stage1_5,他被存放在MBR随後的扇區中,存放了可以讓boot loader能成功進入stage2階段的檔案系統的驅動。

第三階段為stage2,在這個階段boot loader開始加載所有的配置檔案和一些系統啟動的環境參數,這些所需的檔案被存儲在磁盤/boot分區中,第三階段運作完畢一切正常的情況下,核心即被加載到記憶體中,引導階段算是完成了,剩餘的工作就移交給核心。

核心開始進行自解壓,展開做自身初始化,探測各硬體裝置并裝載裝置的驅動程式,然後以隻讀方式挂載根檔案系統,最後一步則是運作使用者空間的第一個程式init,後續的系統初始化工作都移交到init來操作。

而init服務會根據其配置檔案/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、清理操作

下面做一些腳本練習

===我是分割線===**===我是分割線===**===我是分割線===**===我是分割線===

1、寫一個腳本,完成如下功能

(1) 傳遞一個磁盤裝置檔案路徑給腳本,判斷裝置是否存在;

(2) 如果存在,則顯示此裝置上的所有分區資訊;

#!/bin/bash
#
#Program:View disk space information
#History:0.0.1 2017/03/07 22:06
#Author: MG
disk=''
dir="/tmp/"
until [ $disk ];do
    echo "example:/dev/sd[a-z]"
    read -p "input a disk which you want to view: " disk
done
if `fdisk -l $disk >${dir}/success 2>${dir}/error` ;then
    cat ${dir}/success
else
    cat ${dir}/error
fi      

2、寫一個腳本,完成如下功能

傳遞一個參數給腳本,此參數為gzip、bzip2或者xz三者之一;

(1) 如果參數1的值為gzip,則使用tar和gzip歸檔壓縮/etc目錄至/backups目錄中,并命名為/backups/etc-20160613.tar.gz;

(2) 如果參數1的值為bzip2,則使用tar和bzip2歸檔壓縮/etc目錄至/backups目錄中,并命名為/backups/etc-20160613.tar.bz2;

(3) 如果參數1的值為xz,使用tar和xz歸檔壓縮/etc目錄至/backups目錄中,并命名為/backups/etc-20160613.tar.xz;

(4) 其他任意值,則顯示錯誤壓縮工具,并執行非正常退出;

#!/bin/bash
#
#Program:Three packaging methods
#History:0.0.1 2017/03/07 22:36
#Author: MG
style=("gzip" "bzip2" "xz")
choice=''
sour=/etc
[ -d /backups ] || mkdir /backups
file=/backups/etc-20160603.tar.
function options (){
   echo "compress arguments:"
   echo "=========================="
   for (( i=0;i<${#style[@]};i++)) ;do 
     echo -e "${style[$i]}\033[6G)\033[0m"
   done
   echo "=========================="
}
options
until [ $choice ];do
   read -p "select an option which you want to compress: " choice
done
case $choice in
gzip)
   tar -zcf ${file}gz $sour &>/dev/null
   ;;
bzip2)
   tar -jcf ${file}bz2 $sour &>/dev/null
   ;;
xz)
   tar -Jcf ${file}xz $sour &>/dev/null
   ;;
*)
   echo "wrong argument,script exit"
   exit 10 #wrong argument
   ;;
esac      

3、 寫一個腳本,接受一個路徑參數;

(1) 如果為普通檔案,則說明其可被正常通路;

(2) 如果是目錄檔案,則說明是個通路路徑;

(3) 如果為符号連結檔案,則說明是個通路路徑;

(4) 其他為無法判斷;

#!/bin/bash
#
#Program:Determine file type
#History:0.0.1 2017/03/08 09:45
#Author: MG
echo "example /tmp/test"
read -p "Please input a file: " File
if [ ! -z $File ];then
    #flag="true" && echo $flag
    if [ -d $File ];then
        echo "${File} is a directory."
    elif [ -f $File ];then
        echo "${File} is a common file."
    elif [ -l $File ];then
        echo "${File} is a symlink file."
    else
        echo "unknown file type ."
    fi  
else
    #flag="false" &&echo $flag
    echo "wrong arguments"
    exit 100 #wrong argument
fi      

4、 寫一個腳本,取得目前主機的主機名,判斷

(1) 如果主機名為空或為localhost,或為"(none)",則将其命名為mail.mageedu.com;

(2) 否則,顯示現有的主機名即可;

#!/bin/bash
#
#Program:show the hostname for CentOS7
#History:0.0.1 2017/03/08 08:43
#Author: MG
HNAME=`/bin/hostname`
if [ -z $HNAME -o $HNAME == "(none)" -o $HNAME == 'localhost' ];then
    hostnamectl set-hostname "mail.mageedu.com"
else
    echo $HNAME
fi      

5、 寫一個腳本,完成如下任務

(1) 按順序分别複制/var/log目錄下的每個直接檔案或子目錄至/tmp/test1-testn目錄中;

(2) 複制目錄時,才使用cp -r 指令;

(3) 複制檔案時使用cp指令;

(4) 複制連結檔案時使用cp -d指令;

(5) 餘下的所有類型,使用cp -a 指令;

#!/bin/bash
#
#Program:Determine file type
#History:0.0.1 2017/03/08 09:45
#Author: MG
src=/var/log
dsrc=/tmp/test1-testn
[ -d $dsrc ] || mkdir $dsrc
echo "ready to copy file wait a moment please."
for i in ${src}/* ;do 
    if [ -d $i ];then
        cp -r $i ${dsrc}/
    elif [ -f $i ];then
        cp -r $i ${dsrc}/
    elif [ -l $i ];then
        cp -d $i ${dsrc}/
    else
        cp -a $i ${dsrc}/
    fi  
done
echo -e "Operation completed!"      

6、 請較長的描述CentOS系統的啟動流程(詳細到每個過程系統做了哪些事情)

見文章開篇介紹

7、為運作于虛拟機上的CentOS6添加一塊新硬碟,提供兩個主分區;

(1) 為硬碟建立兩個主分區;并為其安裝grub;

(2) 為硬碟的第一個主分區提供核心和ramdisk檔案;為第二個分區提供rootfs;

(3) 為rootfs提供bash、ls、cat程式及所依賴的庫檔案;

(4) 為grub提供配置檔案;

(5) 将新的硬碟設定為第一啟動項并能夠正常啟動目标主機;

[root@localhost ~]# fdisk -l
Disk /dev/sda: 128.8 GB, 128849018880 bytes
255 heads, 63 sectors/track, 15665 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: 0x0005d62f
   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          64      512000   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2              64        1339    10240000   83  Linux
/dev/sda3            1339        1594     2048000   82  Linux swap / Solaris
/dev/sda4            1594       15666   113028096    5  Extended
/dev/sda5            1594        4144    20480000   83  Linux
/dev/sda6            4144        5419    10240000   83  Linux
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      
Linux學習筆記之CentOS6開機流程
Linux學習筆記之CentOS6開機流程
Linux學習筆記之CentOS6開機流程
[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 ~]# cat /proc/partitions 
major minor  #blocks  name
   8        0  125829120 sda
   8        1     512000 sda1
   8        2   10240000 sda2
   8        3    2048000 sda3
   8        4          1 sda4
   8        5   20480000 sda5
   8        6   10240000 sda6
   8       16   20971520 sdb
   8       17     112423 sdb1
   8       18    2104515 sdb2
   8       19   10490445 sdb3      
[root@localhost ~]# mkfs -t ext4 -L "grubboot" /dev/sdb1
...格式化資料省略      
[root@localhost ~]# mkswap /dev/sdb2
Setting up swapspace version 1, size = 2104508 KiB
no label, UUID=b3a5110c-34f5-459a-aa04-48670d8061ca      
[root@localhost ~]# mkfs -t ext4  -L "grubrootfs" /dev/sdb3
mke2fs 1.41.12 (17-May-2010)
檔案系統标簽=grubrootfs
作業系統:Linux
塊大小=4096 (log=2)
分塊大小=4096 (log=2)
...省略後續資料      
[root@localhost ~]# mkdir /mnt/boot   #給sdb安裝grub時,grub-install指令必須要指定一個boot目錄,否則無法完成操作
[root@localhost ~]# mount /dev/sdb1 /mnt/boot  #将建立的sdb1分區挂載至boot目錄      
[root@localhost ~]# grub-install --root-directory=/mnt /dev/sdb   #root-directory是指定grub的根,後邊的/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      
#此時grub程式已經安裝完成,但要想使其可以單獨挂載至獨立主機上并能成功運作則還需要有核心檔案以及所需要的initramdisk,下面将系統的這兩個檔案複制到/mnt/boot目錄中
[root@localhost mnt]# cp /boot/vmlinuz-2.6.32-573.el6.x86_64 /mnt/boot/vmlinuz-2.6.32
[root@localhost mnt]# cp /boot/initramfs-2.6.32-573.el6.x86_64.img /mnt/boot/initrd-2.6.32      
#當然系統啟動時還需要一個grub的配置檔案,來設定啟動菜單以及啟動時相關參數,可以複制本機的grub.conf也可以自己手動建立一個配置檔案
[root@localhost mnt]# vim boot/grub/grub.conf
default=0
timeout=3
hiddenmenu
title Centos6.7 (grub installation test)
    root (hd0,0)
    kernel /vmlinuz-2.6.32 ro root=/dev/sda3 init=/bin/bash  #此版本僅做測試使用,是以系統初始化完成之後啟動的第一個使用者空間程序不是/sbin/init而是/bin/bash。
    initrd /initramfs-2.6.32
#儲存退出,grub配置檔案完成      

現在就差最後一步了,系統初始化完成之後還需要一個啟動終端來跟使用者互動,但目前這個簡易系統是沒有任何工具可用的,現在就來寫一個腳本來将目前系統的ls、cat和bash這三個工具複制到簡易系統當中來,現在先将系統用到的一些目錄建立出來。(腳本參照12題)

[root@localhost mnt]# cd sysroot
[root@localhost sysroot]# mkdir -pv bin sbin lib lib64 home root etc dev sys proc var usr mnt media      
Linux學習筆記之CentOS6開機流程
Linux學習筆記之CentOS6開機流程
Linux學習筆記之CentOS6開機流程
Linux學習筆記之CentOS6開機流程

        8、 寫一個腳本

(1) 能夠接受四個參數:start,stop,restart,status

start:輸出"starting 腳本名finished."

stop:輸出"stop 腳本名stopped."

restart:輸出"stopping 腳本名 starting 腳本名 finished."

status:輸出"腳本名目前狀态"

(2) 其他任意參數,均報錯退出;

#!/bin/bash
#
#Program:progscript.sh
#History:0.0.1 2017/03/08 21:09
#Author: MG
cat <<EOF
script argument
======================================
1. start   ) start the program       ||
2. stop    ) stop the program        ||
3. restart ) restart the program     ||
4. status  ) show the program status ||
======================================
EOF
declare -i flag=0
read -p "Select the parameters to be operated: " ARGU
START="Starting the ${0} ."
STOP="Stopping the ${0} ."
case $ARGU in
1|start)
    echo "$START"
    flag=0
    ;;
2|stop)
    echo "$STOP"
    flag=1
    ;;
3|restart)
    if [ $flag -eq 0 ];then
       echo "$STOP" && echo "$START"
       flag=0
    else
       echo "$START"
       flag=0
    fi
    ;;
4|status)
    if [ $flag -eq 0 ];then
       echo "${0} has started."
    else
       echo "${0} is not running."
    fi
    ;;
*)
    echo "You select the wrong option,${0} exit!"
    exit 12     #wrong option
    ;;
esac      

9、寫一個腳本,判斷給定的使用者是否登入了目前系統

(1) 如果登入了,則顯示使用者登入,腳本終止;

(2) 每3秒鐘,檢視一個使用者是否登入;

#!/bin/bash
#
#Program:loginuser.sh
#History:0.0.1 2017/03/08 21:54
#Author: MG
until `who |awk '{print $1}'|grep $1 &>/dev/null`;do
    sleep 3
done
echo "$1 has login."      

10、寫一個腳本,顯示使用者標明要檢視的資訊

cpu) display cpu info

mem) display memory info

disk) display disk info

quit) quit

非此四項選擇,則提示錯誤,并要求使用者重新選擇,直到其給出正确選擇為止;

#!/bin/bash
#
#Program:serverinfo.sh
#History:0.0.1 2017/03/08 22:03
#Author: MG
choice='null'

until [ $choice == 'cpu' -o $choice == 'mem' -o $choice == 'disk' -o $choice == 'quit' ];do
cat <<EOF
cpu) display cpu info
mem) display memory info
disk) display disk info
quit) quit
EOF
    read -p "Input an option: " choice
    choice=${choice:='null'}
done
case $choice in
cpu)
   cat /proc/cpuinfo
   ;;  
mem)
    free -mh
   ;;
disk)
   fdisk -l
   ;;
quit)
   echo "exit the script."
   ;;
esac      

11、 寫一個腳本

(1) 用函數實作傳回一個使用者的UID和SHELL;使用者通過參數傳遞而來

(2) 提示使用者輸入一個使用者名或輸入"quit" 退出;

當輸入的是使用者名,則調用函數顯示使用者資訊;

當使用者輸入quit,則退出腳本;進一步顯示鍵入的使用者相關資訊後,再次提醒輸出使用者名或quit;

#!/bin/bash
#
#Program:get user ID and shell
#History:0.0.1 2017/03/08 23:19
#Author: MG
choice='null'
until [ $choice == 'quit' ];do
   echo "input quit could exit this program."
   read -p "Input one user name: " choice
   choice=${choice:=null}
   if [ $choice != 'quit' -a $choice != 'null' ];then
    id $choice &>/dev/null 
    if [ $? -eq 0 ];then
        cat /etc/passwd |grep $choice |awk -v FS=: -v OFS=: '{print $1,$3,$6}'
    fi  
   fi  
done
echo "quit!"      

12、寫一個腳本,完成如下功能(使用函數)

(1) 提示使用者輸入一個可執行指令的名字;擷取此指令依賴的所有庫檔案;

(2) 複制指令檔案至/mnt/sysroot目錄下的對應rootfs的路徑上,例如,如果複制的檔案原路徑是/usr/bin/useradd,則複制到/mnt/sysroot/usr/bin/目錄中;

#!/bin/bash
#
#Program:use this program to backup the system command
#History:0.0.1 2017/03/08 23:19
#Author: MG
declare -i DebugLevel=0
RED="\033[1;31m"
GREEN="\033[32m"
ORANGE="\033[36m"
COL="\033[60G"
FLICKER="\033[5m"
END="\033[0m"
SUCCEED="${COL}[ ${GREEN}succeed${END} ]"
ERROR="${COL}[ ${RED}failed${END} ]"
Target=/mnt/sysroot
function checkQ(){
    if [ -n "$1" ];then
        if [ $1 == 'q' -o $1 == 'Q' ];then
            echo "Exit the script!"
            #break 3 
            exit 
        fi
    fi
}
function inputCOM(){
    flag=$1
    flag=${flag:=newCOM}
    case $flag in
        "newCOM")
            unset Command
            until [ -n "$Command" ];do
                read -p "Input a command: " Command
            done
            ;;
        "renewCOM")
            if [ -z "$Command" ];then
                until [ -n "$Command" ];do
                    read -p "Input a correct command: " Command
                done
            else
                read -p "Input a correct command: " Command
                until [ -n "$Command" ];do
                    read -p "Input a correct command: " Command
                done
            fi
            ;;
     esac
}
[ -d $Target ] || mkdir -p $Target
#ll $Target
inputCOM 
while [ $Command != 'q' -a $Command != 'Q' ];do
    `which $Command &>/dev/null`
    Flag=$?
    #echo "Flag=$?"
    until [ $Flag -eq 0 ];do
        echo -e "Wrong command ${RED}$Command${END}"
        inputCOM "renewCOM"
        `which $Command &>/dev/null`
        Flag=$?
        checkQ $Command
    done
    Command=`which $Command|grep -v "^alias.*"|grep -o "[^[:space:]].*"`
    Comdir=${Command%/*}
    [ ! -d ${Target}${Comdir} ] && mkdir -p ${Target}${Comdir} && echo -e "${Target}${Comdir} create ${COL}[ ${GREEN}succeed${END} ]${END}"
    [ ! -f ${Target}${Command} ] && cp $Command ${Target}${Command} && echo -e "${Command} has copied $Target ${COL}[ ${GREEN}succeed${END} ]"
    [ $DebugLevel -eq 1 ] && echo $Comdir 
    [ $DebugLevel -eq 1 ] && echo $Command
    for Lib in `ldd $Command |grep -o "[^[:space:]]*/lib.[^[:space:]]*"`;do
        [ $DebugLevel -eq 1 ] && echo $Lib
        LibDir=${Lib%/*}
        [ $DebugLevel -eq 1 ] && echo $LibDir
        [ ! -d ${Target}${LibDir} ] && mkdir -p ${Target}${LibDir} && echo -e "${Target}${LibDir} create $SUCCEED"
        [ ! -f ${Target}${Lib} ] && cp $Lib ${Target}${Lib} && echo -e "$Lib has copied ${Target} $SUCCEED"
    done
echo -e "${GREEN}Operation has been completed!${END}${COL}[ ${GREEN}${FLICKER}OK${END} ]"
inputCOM
done      

繼續閱讀