规划:向172.16.45.1这虚拟机(宿主机)上添加一块2G左右的硬盘,分为boot和sysroot俩个区。其中boot作为启动分区,sysroot作为根文件系统。完全针对小系统的平台最小的编译内核,而后一步步增加小系统的功能。达到使用一个新虚拟机(目标机)加载此硬盘,便可以跑起来的目的。
内核版本:3.10.67
硬盘接口:SCSI,SCSI是lsi的接口。任何硬盘都是pci总线上的,首先就应该支持pci。
文件系统:ext4
busybox版本:1.22.1
dropbear版本:2013.58
编译内核对各种功能的支持:
64位系统 --> cpu类型 --> 硬盘 --> 文件系统 --> 输入设备 --> 设备文件 --> 网络功能
由于小系统不支持模块的装载,所以将所有的功能都做进内核。因此,无需ramdisk。
系统启动流程:
POST --> BIOS(boot sequence) --> MBR (bootloader) --> kernel(ramdisk) --> /sbin/init --> 设定默认运行级别 --> 使用/etc/rc.d/rc.sysinit脚本进行系统初始化 --> 分别关闭和启动对应级别的所有服务 --> 启动字符终端 --> 启动图形终端(如果默认级别为5)--> 显示登录提示
目录:
1 小系统正式搞起
1.1 切换过快的修复方法
1.2 正式开始
1.2.1 内核编译
1.2.2 切换至目标主机
1.2.3 编译内核使其支持文件系统
1.2.4 返回目标机继续
1.2.5 为目标机提供init
1.2.6 返回目标机继续
1.2.7 为输入设备提供驱动
1.2.8 返回目标机继续
1.2.9 为目标机提供init脚本
1.2.10 为目标机提供设备文件
1.2.11 为目标机提供网络功能
1.3 通过busybox继续完善目标机
1.3.1 busybox编译
1.3.2 为目标机init提供配置文件
1.3.3 提供虚拟终端
1.3.4 让目标机支持用户登录
1.3.5 让目标机拥有主机名并且开机激活网卡
1.3.6 让目标机支持ssh远程登录
如果宿主机和目标机之间的切换过快就会出现错乱,可能会造成目标机内核恐慌。修复方法:将根文件系统中的所有文件备份,然后再将此分区卸载后格式化,再挂载并恢复。
备份:
[root linux]# cd /mnt/sysroot/ [root sysroot]# find . | cpio -o -H newc --quiet > ~/sysroot.img.1 [root ~]# umount /mnt/sysroot/ [root ~]# mke2fs -t ext4 /dev/sdb2 [root ~]# mount /dev/sdb2 /mnt/sysroot/
恢复:
[root sysroot]# cpio -i < ~/sysroot.img.1
1、首先进行分区,第一个分区作为/boot分区50M,第二个1G
[root ~]# fdisk /dev/sdb # 宿主机上识别为sdb,但在目标机上就是sda了。
2、格式化并挂载
[root ~]# mke2fs -t ext4 /dev/sdb1 # 如果想使用别的文件系统也行,但是内核编译时就要与之对应。 [root ~]# mke2fs -t ext4 /dev/sdb2 [root ~]# mkdir /mnt/{boot,sysroot} [root ~]# mount /dev/sdb1 /mnt/boot/ [root ~]# mount /dev/sdb2 /mnt/sysroot/
3、按照启动流程,接下来安装bootloader
[root ~]# grub-install --root-directory=/mnt /dev/sdb # 安装的路径必须是boot目录的父目录。
(1) 验证grub是否安装成功:
[root ~]# ls /mnt/boot/ grub/ lost+found/ # grub目录已存在 [root ~]# ls /mnt/boot/grub/ # 1.5阶段已存在 device.map fat_stage1_5 iso9660_stage1_5 minix_stage1_5 stage1 ufs2_stage1_5 xfs_stage1_5 e2fs_stage1_5 ffs_stage1_5 jfs_stage1_5 reiserfs_stage1_5 stage2 vstafs_stage1_5
1.5阶段的文件除了修复之外没有任何作用
4、编译内核
[root ~]# yum install @"Development Tools" @"Server Platform Development" –y # 准备开发环境 [root ~]# tar xf linux-3.10.67.tar.xz -C /usr/src # 内核版本不宜太新,目前最新版4.0.4 [root ~]# cd /usr/src [root src]# ln -s linux-3.10.67/ linux [root src]# cd linux [root linux]# make allnoconfig # 将所有内核的选择清空,手动选择编译的内容。使用make help查看帮助信息。 [root linux]# vim .config # 进行查看,为y的都是最最基本的功能。 [root linux]# make menuconfig # 开始编译
1、为了兼容宿主机,使用64位内核:[*] 64-bit kernel
2、选择cpu类型,这里选择的是速龙cpu:
Processor type and features ---> Processor family (Generic-x86-64) ---> (X) Opteron/Athlon64/Hammer/K8
3、启动对多核的支持:
Processor type and features ---> [*] Symmetric multi-processing support
4、启动动态装卸载模块:
[*] Enable loadable module support ---> [*] Module unloading(模块强制卸载)
1、启动对pci总线的支持:Bus options (PCI etc.) ---> [*] PCI support
2、加入硬盘的驱动:
Device Drivers ---> SCSI device support ---> <*> SCSI device support、<*> SCSI disk support
(1) 光选择了这些还不够,因为SCSI有物理层、传输层、应用层这三层驱动。因此还需要使用lspci命令查看磁盘的接口:
[root ~]# lspci 00:0d.0 SATA controller: Intel Corporation 82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode] (rev 02) 00:14.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI # 这两点才是关键
3、返回上一级选择:
[*] Fusion MPT device support ---> <*> Fusion MPT ScsiHost drivers for SPI、<*> Fusion MPT misc device (ioctl) driver(为了保证对杂项的支持)、[*] Fusion MPT logging faciliy(日志功能)
4、保存后编译
[root linux]# make bzImage # 编译为bz2压缩格式 Kernel: arch/x86/boot/bzImage is ready (#1) # 内核所在位置 [root linux]# ls arch/x86/boot/bzImage –hl # 内核仅有1.5M -rw-r--r--. 1 root root 1.5M May 19 22:40 arch/x86/boot/bzImage
1、将内核复制到目标主机中,并提供grub配置文件
[root linux]# cp arch/x86/boot/bzImage /mnt/boot/ [root linux]# vim /mnt/boot/grub/grub.conf timeout=3 default=0 title linux (3.10.67) root (hd0,0) kernel /bzImage ro root=/dev/sda2
2、将宿主机挂起,目标主机加载磁盘并开机一试。结果报错,内核恐慌。需要文件系统的支持才行。
1、为了保证兼容性,也选择了ext2和ext3:
File systems ---> <*> The Extended 4 (ext4) filesystem、<*> Ext3 journalling file system support、<*> Second extended fs support
2、但是文件系统也是作为应用程序存在的,因此还需要开启内核对可执行文件的支持才行。linux系统上大多数的应用程序都是elf格式的。
Executable file formats / Emulations ---> [*] Kernel support for ELF binaries、<*> Kernel support for scripts starting with #!(支持脚本)
3、保存后make bzImage编译,完成后覆盖,挂起宿主机后,返回目标机继续。注意:两个主机间切换不宜过快,不然会造成文件系统错乱。
4、在编译的内核目录/usr/src/linux/下的/init/main.c文件中,定义了init程序的查找路径
if (!run_init_process("/sbin/init") || !run_init_process("/etc/init") || !run_init_process("/bin/init") || !run_init_process("/bin/sh")) return 0;
5、从中可以看出优先级最高的是/sbin/init,最低的则是/bin/sh。如果想要使用别的路径,可以将路径写入,重新编译内核就行,因为毕竟这是源代码。
内核再次恐慌:init没找到。这是没有提供init所致,提供init最简单的方法,就是将宿主机上的bash程序移植到目标机上。
1、现在需要用到小系统的第二个分区了,先建立各种目录:
[root ~]# mkdir /mnt/sysroot/{bin,dev,etc,lib,lib64,media,proc,root,sbin,sys,tmp,usr,var}
2、写一个脚本用于移植各种应用程序及其库文件,通过此脚本移植bash程序。
3、移植完成后测试:
[root ~]# chroot /mnt/sysroot/ /bin/bash
4、指明init的位置
[root ~]# vim /mnt/boot/grub/grub.conf kernel /bzImage ro root=/dev/sda2 init=/bin/bash # 新增
5、挂载宿主机,重启目标机。
这次是启动了,但是敲键盘没有任何反应,这是因为缺少硬盘启动:
键盘:
Device Drivers ---> Input device support ---> [*] Keyboards --->
鼠标:
非usb:
Device Drivers ---> Input device support ---> [*] Mice --->
usb:
Device Drivers ---> [*] USB support ---> <*>Support for Host-side USB --> <*>xHCI HCD (USB 3.0) support、<*>EHCI HCD (USB 2.0) support、<*>OHCI HCD support(1.1)、<*>UHCI HCD (most Intel and VIA) support (1.1)
保存退出
[root linux]# make bzImage [root linux]# cp arch/x86/boot/bzImage /mnt/boot/
这次没问题了,敲回车后就OK,一个简陋的小系统就此搞定。
[root ~]# vim /mnt/sysroot/sbin/init # 建立脚本 #!/bin/bash echo -e "\twelcome to \033[31mlinux\033[0m" mount -n -t proc proc /proc mount -n -t sysfs sysfs /sys mount -n -o remount,rw /dev/sda2 / /bin/bash [root ~]# chmod +x /mnt/sysroot/sbin/init
1、复制mount命令及库文件至目标主机
[root ~]# vim /mnt/boot/grub/grub.conf kernel /bzImage ro root=/dev/sda2 init=/sbin/init # 将其改为/sbin/init,其实可以将其删除。因为默认就会找/sbin/init
2、切换至目标主机 --> 目标机一切OK,但此时的目标机设备目录下没有任何设备文件。
2.6内核版本之前的设备文件,无论启动与否,设备文件都在/dev目录下。一样以来,就无法通过设备文件的存在与否,判断设备是否启动。因此,2.6以后做出了改进:通过udev对设备文件进行创建。udev是通过/sys输出的硬件接口相关的参数信息,临时的、动态的创建设备文件。但这种动态的创建对于当前的小系统来说,显然是不现实的。因为udev是个很复杂的系统,依赖很多的组件。好在内核提供了能自动创建它所探测到的硬件接口的功能。现在就使用此功能为小系统输出设备文件。
1、此功能的实现十分简单,但也十分简陋
[root ~]# cd /usr/src/linux [root linux]# make menuconfig
Device Drivers ---> Generic Driver Options ---> [*] Maintain a devtmpfs filesystem to mount at /dev --> 保存退出
[root linux]# make bzImage [root linux]# cp arch/x86/boot/bzImage /mnt/boot/
2、挂载devtmpfs伪文件系统
[root linux]# vim /mnt/sysroot/sbin/init mount -n -t devtmpfs none /dev # 新增一行
3、切换至目标主机 --> 设备文件OK
1、查看网卡,两个系统都是一台物理机上的虚拟机,因此它们的网卡都一样
[root ~]# lspci 00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 02) [root ~]# lsmod e1000 160643 0
2、驱动网卡设备:
[root linux]# cd /usr/src/linux [root linux]# make menuconfig
Device Drivers ---> [*] Network device support ---> [*] Ethernet driver support (NEW) --->
3、这里默认选择了许多网卡驱动,将不需要的统统去掉。保留这些:
[*] Intel devices --> <*> Intel(R) PRO/1000 Gigabit Ethernet support、[*] Intel (82586/82593/82596) devices (NEW)(可选)
4、让内核支持网络功能
[*] Networking support ---> Networking options ---> [*] TCP/IP networking --> [*] IP: multicasting(支持组播,可选)、[*] IP: advanced router(高级路由,可选) --> 保存退出
[root linux]# make bzImage [root linux]# cp arch/x86/boot/bzImage /mnt/boot/
5、通过脚本移植一些网络相关的命令至目标机,然后切换至目标机。
6、通过ifconfig命令将lo和eth0激活后,可以使用ping这台主机。ping通就没问题了。
这个小系统到此就ok了,但是还是有许多功能无法实现,这就需要busybox了。
busybox是一个相当强悍的工具,它本体只有一点几兆,却能模拟数百个常用的命令。将它链接至命令名,它就能模仿此命令的功能。它是一个完整的文件系统,编译后,它的所有功能默认都放在源码目录的_install目录下,位置可以修改。用它来搞小系统真是再合适不过。
1、将sysroot目录下的所有文件备份,这些文件都用不着了,备份是为了防止以后还会用到。并且重新格式化sysroot分区。
[root ~]# cd /mnt/sysroot/ [root sysroot]# find . | cpio -o -H newc --quiet > ~/sysroot.img.2 [root sysroot]# cd [root ~]# umount /mnt/sysroot/ [root ~]# fuser -km /mnt/sysroot/ [root ~]# umount /mnt/sysroot/ [root ~]# mke2fs -t ext4 /dev/sdb2 [root ~]# mount /dev/sdb2 /mnt/sysroot/
2、编译busybox,它的编译方式和内核编译差不多。它可以动态编译也可以静态编译,这里选择静态编译,方便点。但是静态编译需要依赖库文件glibc-static和glibc-utils其中之一。
[root ~]# yum install -y glibc-utils glibc-static # 首先安装库文件 [root ~]# tar xf busybox-1.22.1.tar.bz2 [root ~]# cd busybox-1.22.1 [root busybox-1.22.1]# make menuconfig # 打开和内核编译一样的界面
Busybox Settings ---> Build Options ---> [*] Build BusyBox as a static binary (no shared libs) (此项就是编译成静态)
Busybox Settings ---> Installation Options ("make install" behavior) ---> 在这里面就能修改功能默认存放的位置,但意义不大。
3、安装
[root busybox-1.22.1]# make Trying libraries: crypt m Library crypt is not needed, excluding it Library m is needed, can‘t exclude it (yet) Final link with: m DOC busybox.pod DOC BusyBox.txt DOC busybox.1 DOC BusyBox.html
(1) 这里报错,但不用理会
[root busybox-1.22.1]# make install -------------------------------------------------- You will probably need to make your busybox binary setuid root to ensure all configured applets will work properly.
(2) 进入默认功能存放目录
[root busybox-1.22.1]# cd _install/ [root _install]# du –sh # 2.2M 2.2M
(3) 俨然是一个完整的根文件系统,只不过此文件系统只存放了命令而已:
[root _install]# ll total 12 drwxr-xr-x. 2 root root 4096 May 20 04:39 bin lrwxrwxrwx. 1 root root 11 May 20 04:39 linuxrc -> bin/busybox # 所有的命令都只是此文件的符号链接 drwxr-xr-x. 2 root root 4096 May 20 04:39 sbin drwxr-xr-x. 4 root root 4096 May 20 04:39 usr
(4) 可以直接切换至此文件系统:
[root _install]# chroot ./ /bin/sh [ ]# ls bin linuxrc sbin usr [ ]# cd bin [ bin]# cd ../usr [ usr]# ls bin sbin
4、复制到目标机
[root busybox-1.22.1]# cp -a _install/* /mnt/sysroot/ [root busybox-1.22.1]# cd /mnt/sysroot/ [root sysroot]# mkdir -p etc proc var/log usr sys boot tmp dev [root sysroot]# ll total 52 drwxr-xr-x. 2 root root 4096 May 20 04:39 bin drwxr-xr-x. 2 root root 4096 May 20 04:56 boot drwxr-xr-x. 2 root root 4096 May 20 04:56 etc lrwxrwxrwx. 1 root root 11 May 20 04:39 linuxrc -> bin/busybox # 此文件是当做init使用的,但由于sbin目录下有init,所以可以将它删了。 drwx------. 2 root root 16384 May 20 04:11 lost+found drwxr-xr-x. 2 root root 4096 May 20 04:56 proc drwxr-xr-x. 2 root root 4096 May 20 04:39 sbin drwxr-xr-x. 2 root root 4096 May 20 04:56 sys drwxr-xr-x. 2 root root 4096 May 20 04:56 tmp drwxr-xr-x. 4 root root 4096 May 20 04:39 usr drwxr-xr-x. 3 root root 4096 May 20 04:56 var drwxr-xr-x. 3 root root 4096 May 20 04:56 dev [root sysroot]# rm -rf linuxrc
5、挂起宿主机,开启目标机。但是报错,没有终端。
配置文件的格式是由busybox官方所规定,位置和格式与centos 5上sysV风格近似。
位置:/etc/inittab
格式:id:runlevel:action:process
[root ~]# cd /mnt/sysroot/etc/ [root etc]# vim inittab ::sysinit:/etc/rc.d/rc.sysinit # 先提供一个初始化脚本 console::respawn:-/bin/sh # 启动一个控制台而不是虚拟终端,id为console,respawn为重新读取 ::ctrlaltdel:/sbin/reboot # 当按下ctrl+alt+del时,系统重启 ::shutdown:/bin/umount -a –r # 关机之前,卸载所有文件系统
此配置文件定义了init应用程序的四种动作,还需要提供rc.sysinit初始化脚本
[root etc]# mkdir rc.d [root etc]# vim rc.d/rc.sysinit [root etc]# vim rc.d/rc.sysinit #!/bin/sh echo -e "\tWelcome to \033[31mLinux\033[0m" echo -e "Remounting the root filesystem..." mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs none /dev mount -n -o remount,rw /dev/sda2 / echo -e "Creating the special files..." /sbin/mdev –s [root etc]# chmod +x rc.d/rc.sysinit # 必须可执行
[root ~]# ls /mnt/sysroot/sbin/mdev /mnt/sysroot/sbin/mdev
mdev有啥用呢?它相当于udev,它能根据sys目录下输出的所有硬件信息,创建各种设备文件。它有个-s选项就是干这事的。
切换至小系统,登陆完成
[root ~]# cd /mnt/sysroot/etc/ [root etc]# vim inittab # 删掉控制台那行 ::sysinit:/etc/rc.d/rc.sysinit tty1::askfirst:/bin/sh # askfirst:使用前询问,说白了就是敲回车才会显示命令提示符。敲回车后执行/bin/sh tty2::askfirst:/bin/sh # 可以提供6个,这里只提供3个。 tty3::askfirst:/bin/sh ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r
切换至目标机,此时可以使用ctrl+alt+f2或者f3在终端间切换。
1、想让系统支持用户登录,最起码得有passwd,shadow,group这三个文件。直接从宿主机重定向至目标机即可。
[root ~]# grep "^root" /etc/passwd > /mnt/sysroot/etc/passwd [root ~]# vim /mnt/sysroot/etc/passwd root:x:0:0:root:/root:/bin/sh [root ~]# grep "^root" /etc/group > /mnt/sysroot/etc/group
2、如果此时切换至目标机系统,手动添加root密码的话,会直接将密码添加至passwd文件中,而不会是shadow文件。但宿主机上的密码加密是sha512,如果直接从宿主机上重定向过去的话,busybox如果不支持512,就认证不了。因此使用openssl手动生成:
[root ~]# openssl passwd -1 -salt `openssl rand -hex 4` Password: $1$ae5c7111$M031WSYUsfDHrm73q/D7v0
3、还是重定向,不过将密码换成生成的密码
[root ~]# grep "^root" /etc/shadow > /mnt/sysroot/etc/shadow [root ~]# vim /mnt/sysroot/etc/shadow root:$1$ae5c7111$M031WSYUsfDHrm73q/D7v0:16567:0:99999:7::: [root ~]# chmod 400 /mnt/sysroot/etc/shadow # shadow文件的权限很关键
4、重新编辑inittab文件,让系统支持用户登录
[root ~]# vim /mnt/sysroot/etc/inittab ::sysinit:/etc/rc.d/rc.sysinit ::respawn:/sbin/getty 9600 tty1 # 无论在哪个终端下,都重新启动/sbin/getty。getty表示启动一个终端,并自动调用login要求用户输入账号和密码后登录。因为它是个串行终端,因此需要指定启动速率。 ::respawn:/sbin/getty 9600 tty2 # 同样只启动3个 ::respawn:/sbin/getty 9600 tty3 ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a –r
5、返回目标机,tty1无法登陆,不知道什么原因,只能使用tty2登录了。可以看到登录成功了。
1、创建主机名配置文件
[root ~]# cd /mnt/sysroot/etc/ [root etc]# mkdir sysconfig [root etc]# vim sysconfig/network HOSTNAME=www
2、编辑初始化脚本,让其读取
[root etc]# vim rc.d/rc.sysinit # 新增3行 echo -e "set the hostname..." [ -r /etc/sysconfig/network ] && source /etc/sysconfig/network [ -n $HOSTNAME ] && hostname $HOSTNAME || hostname localhost
3、由于getty会读取issue文件,因此创建issue文件,来显示登录前的信息
[root etc]# vim issue Kernel \r # 只增加一行显示内核版本
4、再次编辑初始化脚本,让其开机激活网络
[root etc]# vim rc.d/rc.sysinit # 再次新增3行 echo -e "activate the networking..." /sbin/ifconfig lo 127.0.0.1 up /sbin/ifconfig eth0 172.16.45.15 up
5、如果想打开网络间转发功能的话
[root etc]# vim sysctl.conf # 将转发的功能写入其中,在初始化脚本中使用sysctl –p就可以直接读取文件内容。
6、切换到目标机,主机名显示正常,ip激活!
使用轻量级的dropbear
1、在宿主机上编译安装dropbear
[root ~]# tar xf dropbear-2013.58.tar.bz2 [root ~]# cd dropbear-2013.58 [root dropbear-2013.58]# ./configure [root dropbear-2013.58]# make && make install # 由于不用scp,因此直接安装
2、使用脚本复制dropbear,dropbearconvert,dropbearkey这三个命令及其库文件至目标机
3、创建dropbear密钥文件
[root dropbear-2013.58]# cd .. [root ~]# mkdir /mnt/sysroot/etc/dropbear # 先创建密钥存放目录 [root ~]# dropbearkey -t dss -f /mnt/sysroot/etc/dropbear/dropbear_dss_host_key # 第一个 [root ~]# dropbearkey -t rsa -s 2048 -f /mnt/sysroot/etc/dropbear/dropbear_rsa_host_key # 第二个
4、dropbear的运行依赖于fstab文件,因此创建之:
[root ~]# vim /mnt/sysroot/etc/fstab /dev/sda1 /boot ext4 defaults 0 0 /dev/sda2 / ext4 defaults 0 0 proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 none /dev devtmpfs defaults 0 0 devpts /dev/pts devpts mode=620 0 0 # 伪终端,远程登陆依赖伪终端,伪终端需要专门的设备文件,因此挂载至/dev/pts目录下,mode指明权限。
5、这样一来就需要创建/dev/pts目录了:
[root ~]# vim /mnt/sysroot/etc/rc.d/rc.sysinit echo -e "Creating the special files..." /sbin/mdev -s mkdir /dev/pts # 新增这一行
6、远程登陆会检查用户的shell,因此需要定义安全shell
[root ~]# vim /mnt/sysroot/etc/shells /bin/sh /bin/ash /bin/hush /bin/bash
7、ssh依赖nsswtich来完成名称解析
(1) 提供配置文件
[root ~]# vim /mnt/sysroot/etc/nsswitch.conf passwd: files shadow: files group: files hosts: files dns
(2) 复制库文件
[root ~]# cp -d /lib64/libnss_files* /mnt/sysroot/lib64/ [root ~]# cp -d /usr/lib64/libnss3.so /usr/lib64/libnss_files.so /mnt/sysroot/usr/lib64
8、切换至目标机,dropbear启动没问题,但是远程登陆报错,fstab文件没生效,虚拟终端未挂载。
(1) 解决方法是在初始化脚本中新增这两行
(2) 创建/root目录
原文地址:http://10042224.blog.51cto.com/10032224/1654410