打造自己的專屬Linux(二):使用腳本實現自動化建立小Linux與命令移植

這是我前幾天在馬哥的帶領下寫的6個腳本,他們串起來就可以實現(一)篇一所有的功能,很方便吧微笑我們以後要通過不斷倒騰這個小linux,來由淺入深的學習linux的系統構架和調優,最後實現編譯內核,真正意義上打造自己的Linux,如果你有興趣,那我一起學習吧微笑強烈建議自己動手寫出這六個腳本,對腳本的學習幫助非常大。

這六個腳本其實就是(一)篇的幾個步驟組合起來,它們連在一起就可以完全實現(一)篇的目的,六個腳本如下:

一、寫一個腳本,實現將一個硬盤中原有分區信息全部刪除,並重新將其分爲三個區:
1、提示用戶指定要操作的磁盤;如果此硬盤中有新區,顯示分區信息,並判斷此中分區是否仍然處於掛載狀態;
   如果是,則顯示分區和對應的掛載點;否則,則說明分區沒有掛載;
2、提示用戶接下來操作會破壞硬盤上的所有數據,並詢問用戶是否繼續進行;形如:Continue(y/N)?
   如果用戶選擇繼續,則抹除此硬盤上的所有分區信息(如果是仍處理掛載狀態的分區,則需要先卸載);否則退出;
3、將此硬盤分爲三個主分區:
第一個主分區,50M,ext3文件系統
第二個主分區,512M,ext3文件系統
第三個主分區,256M,swap文件系統
要求:上面第2和第3步要求用函數實現;函數執行結束要有返回值;

#!/bin/bash
#the script:rmdisk3.sh

function CH {                                                                             #題目要求的第二個功能
 read -p "WARMING!The next action will clean the DISK!COTINUE?(Y|y.other for quite)" CH
 if [ $CH == 'Y' -o $CH == 'y' ];then
    MOUNT=`mount | grep $1`                                                  #通過grep來抓取mount裏的指定磁盤,看是否被掛載
    for i in $MOUNT;do                                                       #用for循環列表來一個一個卸載掉掛載的分區
       i=`mount | grep /dev/sdb | awk '{print $1}'`
       fuser -km $i                                                          #這個命令用於剔除分區裏的活動用戶保證卸載
       umount $i
       return 0
    done
  else
    exit
  fi
}
function FDISK {                                                 #格式化所選磁盤爲3個分區
  dd if=/dev/zero of=$1 bs=512 count=1                           #dd命令比較特殊它是一種特殊的複製   /dev/zero是一個特殊設備用於吐出0,它們組合起來
  partprobe $1                                                   #意思就是給指定磁盤的第0個塊輸出512個字節0,等於破壞掉他的bootloader和分區信息
echo '                                                           #使用partprobe命令重讀下分區,確保格式化順利進行                                  
n
p
1

+50M
n
p
2

+512M
n
p
3

+256M
t
3
82
w' | fdisk $1 &> /dev/null
  partprobe $1
  sleep 1                                                         #這裏要睡1秒,等待系統將分區信息讀入
  mke2fs -j ${1}1 &> /dev/null                                    #格式化三個分區
  mke2fs -j ${1}2 &> /dev/null
  mkswap ${1}3 &> /dev/null
}

read -p "Chose a disk:" DISK                                      #下面的是提醒用戶的信息  
fdisk -l $DISK | grep ^/dev

for I in `fdisk -l $DISK | grep ^/dev |awk '{print $1}'`;do
  mount | grep "$I"
    if [ $? -ne 0 ];then
      echo "The $I is not mounted."
    else
      echo "The $I is mounted"
    fi
done

read -p "Countinue?(y|n)" P
  if [ $P == 'Y' -o $P == 'y' ];then
       CH $DISK
       FDISK $DISK
       echo -e "\033[32mThe action is suceess!\033[0m"    
  else
       exit
  fi

二、寫一個腳本,實現將上述步驟中創建的分區掛載至某目錄:
1、寫一個函數,接受兩個參數,完成以下功能:   
   參數1爲/boot分區對應的設備,傳遞至函數之後將其掛載至/mnt/boot;
   參數2爲/分區對應的設備,傳遞至函數之後將其掛載至/mnt/sysroot;
   說明:上述的掛載點/mnt/boot和/mnt/sysroot如果事先不存在,需要先創建;如果事先存在,
   且已經被某設備掛載使用,則需要先卸載原來掛載的設備;
2、將第一個腳本中實現的分區1和分區2傳遞給些函數執行;

#!/bin/bash
#
 source /root/LX/1               #這條命令用於連接第一個腳本,可以引用它的變量,路徑一定要對,/root/LX/1是我的存放路徑
#目錄/mnt/boot是否存在,如果不存在,創建,並掛載上磁盤。如果存在,踢掉裏面的活動人員,卸載掛載的磁盤,掛載上剛格式化的分區1
function MOUNT {
      [ -d $A ] &> /dev/null || mkdir $A && fuser $A | umount $A &> /dev/null | mount ${DISK}1 $A
      sleep 1
      [ -d $B ] &> /dev/null || mkdir $B && fuser $B | umount $B &> /dev/null | mount ${DISK}2 $B
}

A=/mnt/boot
B=/mnt/sysroot
MOUNT $A $B
三、寫一個腳本,初始化rootfs
1、寫一個函數,接受一個參數(參數爲第二步驟中掛載的/mnt/sysroot),完成以下功能;
   1)判斷/mnt/sysroot是否存在並且如果存在是否是掛載的一個獨立的分區,如果是,則繼續後面的操作;否則,則提示用戶錯誤信息,而後詢問是否繼續;
   2)在/mnt/sysroot目錄中創建如下子目錄:
   boot, proc, sys, dev, home, root, etc/{rc.d,sysconfig,init.d}, bin, sbin, lib, usr/{bin,sbin,lib,include}, var/{log,run}, tmp, mnt, opt, media;
   3)將上面創建的tmp目錄的權限設置爲1777;
   4)創建文件/mnt/sysroot/etc/inittab,內容如下:
   id:3:initdefault:
   si::sysinit:/etc/rc.d/rc.sysinit
   5)創建文件/mnt/sysroot/etc/rc.d/rc.sysinit,內容如下:
   #!/bin/bash
   echo -e "\t\tWelcome to \033[31;1mLittle\033[0m Linux..."
   
   mount -n -o remount,rw /
   mount -n -a
   
   /bin/bash
   而後給此文件以執行權限;
   6)創建文件/mnt/sysroot/etc/fstab,內容如下:
   /dev/sda2 /ext3    defaults        0 0
   /dev/sda1               /boot                   ext3    defaults        0 0
   sysfs                   /sys                    sysfs   defaults        0 0
   proc                    /proc                   proc    defaults        0 0
2、執行此函數

#!/bin/bash
#
source /root/LX/2

function ROOTFS {
[ -d $B ] && ( mount | grep "$B" &> /dev/null ) || echo "ERRO!The $B is not mounted" | read -p "Countinue?(y|n)" INPUT
  if [ "$INPUT" == 'n' ];then                                       #這是一個判斷函數,防止意外情況發生
      exit
  fi

  cd $B                                              #創建目錄
  mkdir -p boot proc sys dev home root etc/{rc.d,sysconfig,init.d} bin sbin lib usr/{bin,sbin,lib,include} var/{log,run} tmp mnt opt media
  chmod 1777 tmp

cat >> etc/inittab << EOF                             #創建題目要求的幾個文件
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
EOF
cat >> etc/rc.d/rc.sysinit << EOF
#!/bin/bash
echo -e "\t\tWelcome to \033[31m;1mLittle\033[0m Linux..."

mount -n -o remount,rw /
mount -n -a

/bin/bash 
EOF

  chmod 755 etc/rc.d/rc.sysinit
cat >> etc/fstab << EOF
/dev/sda2               /                       ext3    defaults        0 0
/dev/sda1               /boot                   ext3    defaults        0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
EOF
}

ROOTFS $B

四、寫一個腳本,實現二進制命令及對應庫文件的拷貝:
1、寫一個函數,接受兩個參數(參數1爲要複製的命令,參數2爲複製命令對應的目標位置,如/mnt/sysroot),完成以下功能:
   1)判斷參數1所對應的命令是否存在;如果存在:
     取得其目錄路徑,及命令對應的文件的名字;
     而後將此命令複製到參數2對應的路徑下,跟此命令原來的目錄路徑相同的子目錄中;
     比如,如果參數2爲/mnt/sysroot,而命令路徑爲/bin/ls,則需要將ls複製到/mnt/sysroot/bin目錄;如果命令路徑爲/usr/bin/man,則需要將man複製至/mnt/sysroot/usr/bin/中去;
   2)複製命令的同時,判定此命令所依賴的庫文件,而後對每一個庫文件做如下操作:
     取得其目錄路徑,及命令對應的文件的名字;
     而後將此命令複製到參數2對應的路徑下,跟此命令原來的目錄路徑相同的子目錄中;但如果此庫文件已經複製過,則不需要再次複製;
2、執行此函數;

#!/bin/bash
#
function LDD {
  which $1 &> /dev/null || echo "It is not exist" | retrun 5                  #這裏也是一個判斷

  DIR=`which $1 | grep -o "/.*"`                   #防止有別名的命令導致截取錯誤的路徑       
  DIR1=`echo $DIR | sed "s@\(.*\)$1@\1@g"`

  [ -d $B$DIR1 ] || mkdir $B$DIR1               #如果要複製的目錄不存在,創建它
  [ -e $B$DIR ] || cp $DIR $B$DIR1              #如果文件不存在才複製它

  for I in `ldd $DIR | grep -o "/[^[:space:]]*"`;do        #這裏使用ldd命令指定命令的執行文件存放路徑,並通過for循環來複制它的庫文件
      DIR1=`echo $I | sed "s@\(.*\)/[^/]*@\1@g"`
      [ -d $B$DIR1 ] || mkdir $B$DIR1                #這裏的判斷同上
      [ -e $B$I ] ||
cp $I $B$DIR1 << End
n
End
  done
}
  B=/mnt/sysroot
  read -p "Which command you want add:" COM
  LDD $COM

五、寫一個腳本,實現引導分區的設定: 
1、寫一個函數,接受一個參數(參數爲目標Linux的boot目錄),實現以下功能:
  1)創建一個臨時目錄/tmp/litte.XX;
  2)將宿主機的/boot/initrd-`uname -r`.img文件展開至臨時目錄;
  3)修改展開而來的init文件:
    a)註釋掉如下行:
    echo Scanning and configuring dmraid supported devices
    echo Scanning logical volumes
    lvm vgscan --ignorelockingfailure
    echo Activating logical volumes
    lvm vgchange -ay --ignorelockingfailure  vol0
    resume LABEL=SWAP-sda3
    b)將如下行中的設備修改爲你所需要的:
    mkrootdev -t ext3 -o defaults,ro /dev/vol0/root
  4)將修改好的內容重新封閉爲cpio的歸檔文件,並gzip壓縮後存放至參數所指定的目錄;
  5)複製/boot/vmlinuz-`uname -r`至參數所指定的目錄,並重命令爲vmlinuz;
2、執行此函數;
3、說明:此處的`uname -r`只是爲了引用當前系統正在使用的內核和initrd文件,但這並非是必須。即如果你有其它內核和對應的initrd文件,也可使用。

#!/bin/bash
#
source /root/LX/3
KERNEL=vmlinuz
INITRD=initrd.gz
function BOOT {                                                                    #這個函數解開initrd文件,並寫入信息後重新歸檔封裝
     DIR=`mktemp -d /tmp/litte.XX`                              #創建臨時目錄
     cd $DIR
     zcat /boot/initrd-`uname -r`.img | cpio -id                  #釋放initrd到一個臨時目錄

     sed -i 's@echo Scanning and configuring dmraid supported devices@#&@g' init           #修改
     sed -i 's@echo Scanning logical volumes@#&@g' init
     sed -i 's@lvm vgscan --ignorelockingfailure@#&@g' init
     sed -i 's@echo Activating logical volumes@#&@g' init
     sed -i 's@lvm vgchange -ay --ignorelockingfailure  vol0@#&@g' init
     sed -i 's@resume LABEL=SWAP-sda3@#&@g' init
     sed -i "s@\(mkrootdev.* \).*@\1${DISK}2@g" init

     find . | cpio -H newc -o --quiet | gzip -9 > $1/initrd.gz                #再次歸檔壓縮
     CP /Boot/vmlinuz-`uname -r` $1/vmlinuz                       #複製修改並歸檔後的initrd文件到我們的小linux /boot裏

     rm -rf $DIR                      #要養成刪臨時文件的好習慣
}
BOOT $A

六、寫一個腳本,爲目標主機所以磁盤設定grub:
1、寫一個函數,接受四個參數(參數1爲目標磁盤,參數2爲引導分區的掛載點,參數3爲內核文件名,參數4爲initrd文件名),完成以下功能:
1)判斷掛載點路徑的基名是否爲boot,如果不是,則停止執行,並提示用戶修改;否則,則繼續下面的操作;
2)向目標磁盤安裝grub;
3)在參數3中的子目錄grub下建立文件grub.conf;內容類似如下內容:
default=0
timeout=10
title Little Linux
root (hd0,0)
kernel /$3
initrd /$4
2、執行此函數

#!/bin/bash
#
source /root/LX/5

function GRUB {
[ `basename $2` != boot ] && echo "The mounted dir is wrong!Modiy it!" && exit            #判斷,防止出錯
grub-install --root-directory=/mnt/ $1 &> /dev/null                      #安裝grub
cat >> $2/grub/grub.conf << EOF                                          #創建grub.conf文件
default=0
timeout=10
title Little Linux
        root (hd0,0) 
        kernel /$3   ro root=${DISK}2 quite
        initrd /$4
EOF
}

GRUB $DISK $A $KERNEL $INITRD

好了,就是這6個腳本~寫出來後對自己的幫助非常大!


下篇預告:打造自己的專屬Linux(三):給小linux添加網絡模塊,實現關機重啓,登錄界面











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章