8.2.1、mini linux內核編譯
實驗目的:
對Linux內核以非模塊化手動編譯,並藉助busybox安裝根文件系統,來製作最小化的linux系統。所謂非模塊化,就是將各種所需的硬件驅動、支持的文件系統等直接編譯進內核,所以initramfs也就不需要了,對於網卡驅動,我們採用模塊化編譯,當然也可以根據自己網卡型號,直接將驅動編譯進內核;最終在我們的mini linux上能通過DHCP自動獲取ip並實現基於dropbear的遠程終端登錄。
實驗環境:
操作系統:centos6.8(x86_64)
Linux內核版本:3.10.107
虛擬機:VirtualBox
GCC版本:4.4.7
1)安裝前準備
官網下載內核及安裝開發包組:
[root@bbs ~]# wget https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.10.107.tar.xz
[root@bbs ~]# yum groupinstall"Development tools" "Server Platform Development" -y
[root@bbs ~]# yum install -y ncurses
[root@bbs ~]# yum install bc-y
2)解壓縮
[root@bbs ~]# tar xf linux-3.10.107.tar.xz -C /usr/src
[root@bbs ~]# cd /usr/src
[root@bbs src]# ln -s linux-3.10.107.tar.xz linux
[root@bbs src]# cd linux
3)編譯內核
先運行make help可以查看編譯幫助,這裏我們先運行make allnoconfig,對所有默認加載項全部設置爲no,執行該命令後即在linux內核頂層目錄下生成有.config文件。
[root@bbs linux]# make allnoconfig
[root@bbs linux]# make menuconfig
[*] 64-bit kernel ;64位
[*] Enableloadable module support ---> ;支持模塊裝載
[*] Module unloading ;支持模塊卸載
Processor type and features --->
[*] Symmetric multi-processing support ;對稱多處理器支持
Processor family (Generic-x86-64) --->
(X) Generic-x86-64 ;處理器系列
[*] Networking support ---> ;網絡支持
Networking options --->
<*> Packet socket
[*] IP:DHCP support ;添加對dhcp的支持
[*] IP: BOOTP support
[*] Network packet filtering framework(Netfilter) --->
[*] TCP/IP networking
[*] IP: multicasting
[*] IP: advanced router
[*] IP: kernel level autoconfiguration
Bus options (PCI etc.) --->
[*] PCI support ;支持PCI總線
查看主機硬盤型號,根據型號在內核設置對應的驅動:
[root@bbs ~]# lspci
[*]Enable the block layer --->
Device Drivers --->
Generic DriverOptions --->
[*] Maintain a devtmpfs filesystem tomount at /dev
[*] Automount devtmpfs at /dev, afterthe kernel mounted the rootfs
上面兩項在於將內核探測到的硬件信息輸出至/dev目錄;
[*] Network device support ---> ;網絡設備驅動支持
[*] Ethernet driver support (NEW) --->
[*] Intel devices
<M> Intel(R) PRO/1000 Gigabit Ethernet support ;編譯爲模塊
<*> Serial ATA and Parallel ATA drivers ---> ;支持SATA驅動
[*] ATA ACPI Support
<*> AHCI SATA support
SCSI devicesupport ---> ;支持SCSI驅動
-*- SCSI device support
<*> SCSI disk support
[*] Fusion MPTdevice support ---> ;支持SCSI驅動
<*> Fusion MPT ScsiHost drivers for SPI
<*> Fusion MPT misc device (ioctl) driver
[*] Fusion MPT logging facility
Input device support --->
<*> Mouse interface ;鼠標接口
[*] Keyboards --->
<*> AT keyboard (NEW) ;標準鍵盤
[*] Mice ---> ;鼠標支持
[*]USB support --->
<*> Support for Host-side USB
<*> EHCI HCD (USB 2.0) support ;USB2.0
<*> xHCI HCD (USB 3.0) support ;USB3.0
<*> OHCI HCD support ;USB1.0
<*> UHCIHCD (most Intel and VIA) support ;USB1.0
Executable file formats / Emulations --->
[*] Kernel support for ELF binaries ;支持Linux的ELF可執行程序
<*> Kernel support for scriptsstarting with #! ;支持腳本程序
4)開始編譯內核
[root@bbs linux]# make -j 4 bzImage
如果能成功編譯,則在編譯完成後,內核文件保存在:arch/x86/boot/bzImage
[root@bbs linux]# sync
5)添加一塊新硬盤並安裝grub
步驟如下:
① 、先將/dev/sdb按照基本分區分爲3個:boot,swap(可無需添加),/,並在上面製作對應的文件系統,比如ext4;
② 、在當前宿主機系統上的/mnt目錄下創建名爲boot,sysroot(該目錄下還包含linux系統所需的各子目錄,如:etc,bin,sbin...)的目錄;
③ 、掛載/dev/sdb1至宿主機的/mnt/boot目錄,作爲文件系統訪問入口;
④ 、掛載/dev/sdb2至宿主機的/mnt/sysroot目錄,作爲文件系統訪問入口;
⑤ 、在宿主機上運行如下命令:
# grub-install --root-directory=/mnt/dev/sdb,該步驟就將grub安裝到了宿主機第2 塊磁盤(/dev/sdb)的mbr並安裝了stage1_5和stage2;
⑥ 、拷貝已編譯好的內核:/usr/src/linux/arch/x86/boot/bzImage至/mnt/boot/目錄;
⑦ 、新增文件/mnt/boot/grub/grub.conf,並添加如下內容:
default=0
timeout=5
title Mini Linux
root (hd0,0)
kernel /bzImage ro root=/dev/sda2 init=/sbin/init
⑧ 、使用bincp腳本拷貝bash程序至/mnt/sysroot/bin/目錄下,bincp腳本會自動拷貝二進制文件及其所依賴的庫文件到/mnt/sysroot目錄;
下面爲bincp.sh腳本源碼:
#!/bin/sh
sysdir=/mnt/sysroot
[ -d $sysdir ] || mkdir -p $sysdir
while :
do
echo -n "Please enter a binary executable program[q for quit]:"
read prog
if [ "$prog" = "quit" ] || [ "$prog" = "q" ] ;then
break
fi
if which --skip-alias "$prog" &>/dev/null; then
if [ -f ${sysdir}$(which --skip-alias $prog) ];then
echo "File ${sysdir}$(which $prog) exists"
continue
else
mkdir -p $(dirname ${sysdir}$(which --skip-alias $prog)) &>/dev/null
cp $(which --skip-alias $prog) ${sysdir}$(which --skip-alias $prog)
ldd $(which --skip-alias $prog) | while read line
do
var1=${line#*=>}
var2=${var1%(*}
var3=$(echo $var2|sed -r 's/^[[:space:]]?//')
if [ -n "$var3" ] && [ ! -d $(dirname ${sysdir}$var3) ];then
mkdir -p $(dirname ${sysdir}$var3)
fi
[ -n "$var3" ] && cp $var3 ${sysdir}$var3
done
fi
else
echo "Wrong binary executable program"
continue
fi
done
爲了測試我們上面安裝的grub以及編譯好的linux內核,再配合移植到mini linux上的bash,爲了測試其能否正常工作,這裏我們再手動創建一個init程序進行測試。
新增init文件在/mnt/sysroot/sbin/init:
[root@bbs sysroot]# vi /mnt/sysroot/sbin/init
#!/bin/bash
mount -n -t proc proc /proc
mount -n -t sysfs sys /sys
mount -n -t ext4 /dev/sda1 /boot
mount -n -t ext4 -o remount,rw /dev/sda2 /
[root@bbs sysroot]# chmod +x /sbin/init
上面的init腳本在linux內核完成驅動加載後即爲執行第一個程序:init,該程序可爲二進制格式的ELF也可爲上面編寫的init腳本。
⑨ 在宿主機系統上測試安裝在/dev/sdb磁盤上的bash是否可用,使用命令: chroot /mnt/sysroot
⑩ 重啓宿主機,在BIOS界面調整磁盤開機順序:將第2塊磁盤調整爲第一個開機啓動項即可。
在Mini Linux上啓動後即可進入Bash,如果/sbin/init未能執行成功,也可手動掛載如下文件系統:
bash-4.1# mount -n -t ext4 -oremount,rw /dev/sda2 / ;重新掛載根文件系統,使其可寫
bash-4.1# mount -n -t ext4 /dev/sda1/boot ;將boot分區掛載至/boot目錄
bash-4.1# mount -n -t proc proc /proc
bash-4.1# mount -n -t sysfs sys /sys
bash-4.1# cd /proc
bash-4.1# cat mounts
如果開機mini linux系統能進入bash提示符,則表明上面的步驟沒有問題,下一步就該爲mini linux系統定製根文件系統了:編譯、安裝busybox。
8.2.2、mini linux根文件系統:busybox編譯安裝
Mini Linux:kernel+busybox+dropbear
busybox提供了非常豐富的用戶空間程序,可以在編譯busybox時選擇靜態方式編譯,這樣就不依賴於庫文件了,其通過一個靜態編譯的二進制程序以各種軟鏈接(或者硬鏈接,腳本)的形式提供豐富多樣的小程序。由於通過靜態編譯需要依賴於glibc-static,所以編譯busybox前需要先安裝此程序。
busybox編譯安裝步驟:
1) 下載busybox源碼包:
官網地址:https://busybox.net/
busybox-1.23.0版本地址:
https://busybox.net/downloads/busybox-1.23.0.tar.bz2
2) 解壓縮、編譯
[root@bbs ~]# yum install glibc-static -y ;安裝依賴庫
[root@bbs ~]# tar xf busybox-1.23.0.tar.bz2
[root@bbs ~]# cd busybox-1.23.0
具體編譯步驟可通過查看busybox根目錄下INSTALL文件查看:
[root@bbs busybox-1.23.0]# less INSTALL
從文檔可以看出編譯分爲三步:make menuconfig, make ,make install這點與編譯安裝kernel比較類似。
配置選項中比較關鍵的一項就是確定以靜態方式編譯:
Busybox Settings --->BuildOptions --->[*] Build BusyBox as a static binary (no shared libs)
另外一個選項是配置安裝後的程序文件存放位置:
BusyboxSettings--->Installation Options ("make install" behavior)--->(./_install) BusyBox installation prefix
從默認配置可以看出,安裝完之後的程序保存在busybox頂層目錄下名爲_install的目錄,安裝完後可將該目錄下生成的所有程序文件拷貝至需要的根文件系統上,如/mnt/sysroot。
另外,爲了添加對dhcp客戶端的支持,需要開啓udhcp:
Networking Utilities ---> [*] udhcp client (udhcpc)
下面進入busybox選項配置界面:
[root@bbs busybox-1.23.2]# make menuconfig
上圖是一個基於ncurses的文本配置界面,可以根據需要對busybox各選項進行配置。
最後執行編譯和安裝指令:
[root@bbs busybox-1.23.2]# make && make install
3) 拷貝程序至mini linux根文件系統
[root@bbs busybox-1.23.2]# mount /dev/sdb2 /mnt/sysroot
[root@bbs busybox-1.23.2]# cp -a _install/* /mnt/sysroot
[root@bbs busybox-1.23.2]# cd /mnt/sysroot
[root@bbs sysroot]# rm -f linuxrc
創建根文件系統下其它所需目錄,可用如下腳本生成:
[root@bbs sysroot]# sh createDirs.sh ;運行腳本生成根文件系統下所需其它目錄
#!/bin/sh
#內核版本
kernel_vers="3.10.107"
for dir in etc/{rc.d,init.d,sysconfig/modules} home var/{log,lib,lock,run,lastlog} tmp root usr/{local,src,bin,sbin,lib,lib64,include,etc,share} bin sbin lib/modules/${kernel_vers}/kernel/drivers/net/e1000 lib64 dev/pts sys proc media mnt boot src opt
do
if [ ! -d $dir ];then
mkdir -pv $dir
fi
done
touch lib/modules/${kernel_vers}/modules.dep
chmod 1777 ./tmp
最後在mini linux根文件系統上成功生成用戶空間程序:
[root@bbs sysroot]# ls
測試安裝之後的busybox程序是否可用:
[root@bbs sysroot]# chroot /mnt/sysroot/ /bin/ash
注意:busybox上的shell是能兼容bash的ash,如果想使用bash,則用bincp腳本拷貝至/mnt/sysroot。
4) 創建、配置mini linux文件系統上etc/inittab和etc/rc.d/rc.sysinit
根據linux系統啓動流程我們知道,linux內核在內存自解壓運行後讀取硬件信息、加載硬件驅動、以只讀方式掛載根文件系統之後就執行第一個init程序,我們這裏製作的mini linux的init程序是由busybox提供,其會讀取根文件系統上/etc/inittab配置文件,執行/etc/rc.d/rc.sysinit系統初始化等過程。所以我們需要手動創建文件etc/inittab和etc/rc.d/rc.sysinit用於busybox的init程序讀取該配置文件,以便執行系統初始化和登錄控制檯等功能,另外爲了實現自動掛載文件系統,我們還需要創建etc/fstab文件:
配置文件:etc/inittab
[root@bbs sysroot]# vi etc/inittab
::sysinit:/etc/rc.d/rc.sysinit
tty1::respawn:/bin/sh ;虛擬終端,ctrl+alt+F1可打開此終端
tty2::askfirst:/bin/sh ;虛擬終端,ctrl+alt+F2可打開此終端
tty3::respawn:/bin/sh
tty4::respawn:/bin/sh
ca::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
系統初始化腳本:etc/rc.d/rc.sysinit
[root@bbs sysroot]# vi etc/rc.d/rc.sysinit
#!/bin/sh
#設置主機名
HOSTNAME=$(/bin/hostname)
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ];then
echo "Seting host name to localhost..."
hostname "localhost"
else
echo "Seting host name to $HOSTNAME..."
hostname $HOSTNAME
fi
#打印歡迎信息
echo -e "Welcome to \033[32mMini\033[0m Linux"
#掃描/sys目錄,運行mdev用於生成/dev設備文件
echo "Scan /sysand populate /dev..."
mdev -s
#生成/dev/pts目錄,用於dropbear遠程登錄軟件所用
mkdir -pv /dev/pts
#掛載/etc/fstab中的文件系統
echo "Mountingfile system in fstab..."
mount -a
#再次以讀寫方式掛載根文件系統
echo "Remountingroot file system rw..."
mount -t ext4 -o remount,rw /dev/sda2 /
#開機加載/etc/sysconfig/modules/*.modules模塊
for file in /etc/sysconfig/modules/*.modules ; do
[ -x $file ] && $file
done
#手動配置固定ip及默認路由,如果有用dhcp則註釋掉
#echo "CoufiguringIP address to 192.168.0.119..."
#ifconfig eth0192.168.0.119 up
#ifconfig lo 127.0.0.1up
#route add default gw 192.168.0.1
#啓動dropbear
echo "Startingdropbear..."
if /usr/local/sbin/dropbear ;then
echo -e "Dropbear started \033[32m[ OK ]\033[0m"
else
echo -e "Dropbear started\033[31m[FAILED]\033[0m"
fi
#啓動udhcpc程序
echo "Starting udhcpc..."
for ifc in $(ifconfig-a|awk '{print $1}'|egrep -o eth[0-9]+);do
if ifconfig $ifc up ;then
#senddiscover最大發送5次,若未能獲得租約則立即退出
if /sbin/udhcpc -t 5 -n -i $ifc ;then
echo -e "Start udhcpc on $ifc \033[32m[ OK ]\033[0m"
else
echo -e "Start udhcpc on $ifc \033[31m[FAILED]\033[0m"
fi
else
echo -e "Initialization interface $ifc \033[31m[FAILED]\033[0m"
fi
done
ifconfig lo 127.0.0.1 up
注:mdev工具是busybox用於在系統啓動時掃描/sys目錄下文件並在/dev目錄下自動創建設備文件,查看其使用說明如下截圖:
[root@bbs sysroot]# vi etc/fstab
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
/dev/sda1 /boot ext4 defaults 00
/dev/sda2 / ext4 defaults 00
至此我們已經實現mini linux兩項重要功能:kernel+busybox,下面就可以創建一個新的虛擬機,添加一塊我們安裝有kernel+grub+busybox的硬盤,隨後即可開機啓動,下面是開機後的畫面: