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)安装前准备
官网下载内核及安装开发包组:
[[email protected] ~]# wget https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.10.107.tar.xz
[[email protected] ~]# yum groupinstall"Development tools" "Server Platform Development" -y
[[email protected] ~]# yum install -y ncurses
[[email protected] ~]# yum install bc-y
2)解压缩
[[email protected] ~]# tar xf linux-3.10.107.tar.xz -C /usr/src
[[email protected] ~]# cd /usr/src
[[email protected] src]# ln -s linux-3.10.107.tar.xz linux
[[email protected] src]# cd linux
3)编译内核
先运行make help可以查看编译帮助,这里我们先运行make allnoconfig,对所有默认加载项全部设置为no,执行该命令后即在linux内核顶层目录下生成有.config文件。
[[email protected] linux]# make allnoconfig
[[email protected] 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总线
查看主机硬盘型号,根据型号在内核设置对应的驱动:
[[email protected] ~]# 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)开始编译内核
[[email protected] linux]# make -j 4 bzImage
如果能成功编译,则在编译完成后,内核文件保存在:arch/x86/boot/bzImage
[[email protected] 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:
[[email protected] 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 /
[[email protected] 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) 解压缩、编译
[[email protected] ~]# yum install glibc-static -y ;安装依赖库
[[email protected] ~]# tar xf busybox-1.23.0.tar.bz2
[[email protected] ~]# cd busybox-1.23.0
具体编译步骤可通过查看busybox根目录下INSTALL文件查看:
[[email protected] 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选项配置界面:
[[email protected] busybox-1.23.2]# make menuconfig
上图是一个基于ncurses的文本配置界面,可以根据需要对busybox各选项进行配置。
最后执行编译和安装指令:
[[email protected] busybox-1.23.2]# make && make install
3) 拷贝程序至mini linux根文件系统
[[email protected] busybox-1.23.2]# mount /dev/sdb2 /mnt/sysroot
[[email protected] busybox-1.23.2]# cp -a _install/* /mnt/sysroot
[[email protected] busybox-1.23.2]# cd /mnt/sysroot
[[email protected] sysroot]# rm -f linuxrc
创建根文件系统下其它所需目录,可用如下脚本生成:
[[email protected] 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根文件系统上成功生成用户空间程序:
[[email protected] sysroot]# ls
测试安装之后的busybox程序是否可用:
[[email protected] 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
[[email protected] 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
[[email protected] 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目录下自动创建设备文件,查看其使用说明如下截图:
[[email protected] 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的硬盘,随后即可开机启动,下面是开机后的画面: