使用 linux kernel +busybox 定制linux系统
写在开头:
本来是想使用linux kernel +busybox 制作一个教程的,后来快要结束的时候,死活找不到硬盘,我了解很多文章都有类似的,但是没有谈到硬盘找不到问题,最后历经艰辛,终于把问题解决了,成功启动一个赶紧的的linux 小系统。
目的:
了解linux的启动过程
主要内容:
1. grub 是启动程序的bootloader
2. linux-kernel 是linux的开源内核
3. busybox 是linux的工具集合
启动顺序:
grub-> bzimage > initrd > init > chroot sbin/init (从内存镜像转换车工rootfs)> /etc/inittab > fstab>etc/init.d/rcS
实验环境:
操作系统(编译使用): CentOS 7.4
Kernel 版本 :5.5.2
1. 编译linux kernel
1) 下载及解压:
复制文件到
/usr/src/linux-5.5.2.tar.xz
解压 tar -xvf linux-5.5.2.tar.xz
2)编译linux kernel:
yum install ncusres-devel # 按照需要编译的一些包 cd /usr/src/linux-5.5.2 # 切换到linux源代码目录 make menuconfig #配置内核编译内容,配置一些信息 ,由于是演示,默认就可以了 make -j4 #执行多cpu方式编译 midir /usr/src/modules
make modules_install INSTALL_MOD_PATH=/usr/src/modules #将modules安装在这里
2. 编译busybox
1) 下载及解压:
复制文件到
/usr/src/busybox-1.31.1.tar.bz2
解压 tar -jxvf busybox-1.31.1.tar.bz2
2) 编译busybox
yum install glibc-static # 按照需要编译的静态库包 cd /usr/src/busybox-1.31.1 # 切换到busybox源代码目录 make menuconfig # 配置 Settings->Build Options->Build static binary make install
3. 根据busybox 制作initrd.gz文件
make /usr/src/initrd # 创建初始化目录 cd /usr/src/initrd # 进入工作目录 cp /usr/src/busybox-1.31.1/_install/* -a . #复制所有busybox文件 mkdir proc sys mnt/sysroot dev tmp etc -pv #创建必要的目录 mknod dev/console c 5 1 # 创建console设备 mknod dev/null c 1 3 # 创建null设备 rm linuxrc # 删除软连接,这个文件没啥用看着不舒服而已 touch init # 创建init 引导程,具体内容见下面信息 chmod +x init # 设置可运行程序 find . | cpio -H newc --quiet -o | gzip -9 > /usr/src/initrd.gz #打包initrd
init 文件内容:
#!/bin/sh echo "Mounting proc and sys..." #下面两句有顺序问题,特别奇怪,具体没有深入研究 mount -t sysfs sysfs /sys
mount -t proc proc /proc echo "Detect and export hardware infomation..." mdev -s echo "Mount real rootfs to /mnt/sysroot..." mount -t ext4 -o ro /dev/sda2 /mnt/sysroot echo "Switch to real rootfs..." exec chroot /mnt/sysroot /sbin/init
4. 根据linux kernel 编译输出整理成 vmlinuz
cp /usr/src/linux-5.5.2/arch/x86/boot/bzImage /usr/src/vmlinuz #复制内核
5. 根据busybox 制作rootfs 系统真正的linux目录
make /usr/src/sysroot #创建工作目录 cd sysroot #进入工作目录 cp /usr/src/busybox-1.31.1/_install/* -a . #复制所有busybox文件 rm linuxrc # 删除软连接,这个文件没啥用看着不舒服而已 # 创建目录 mkdir dev var sys mnt etc proc lib home tmp root boot mkdir var/{log,run,lock} mkdir lib/modules
mknod dev/console c 5 1 # 创建console设备 mknod dev/null c 1 3 # 创建null设备 vim etc/inittab #创建rootfs启动文件,内容见下图 vim etc/init.d/rcS #创建启动脚本 chmod +x rcS
vim etc/fstab #当执行mount -a 的时候就会执行这个文件里的挂载
inittab 文件内容:
::sysinit:/etc/init.d/rcS ::askfirst:-/bin/sh ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::restart:/sbin/init
rcS 文件内容:
#!/bin/sh echo -e "Welcome To My Linux" echo "Remount the rootfs..." mount -t ext4 -o remount,rw /dev/sda2 / echo "Detect and export hardware infomation..." mdev -s echo "Mount the other filesystem...fstab" mount -a
fstab
# device mount-point type options dump fsck sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 /dev/sda1 /boot ext4 defaults 0 0 /dev/sda2 / ext4 defaults 1 1
6. 经过上面的步骤已经实现了 vmlinuz(linux 内核) initrd.gz(内存系统盘) sysroot (真正的linux rootfs系统) 都已经准备好了,接下来开始准备一块磁盘。
通过virtual box 创建一块sata磁盘10G 并分成两个区.
[root@centos ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 99G 0 part
├─cl-root 253:0 0 50G 0 lvm /
├─cl-swap 253:1 0 2G 0 lvm [SWAP]
└─cl-home 253:2 0 47G 0 lvm /home
sdb 8:16 0 10G 0 disk
sr0 11:0 1 1024M 0 rom ############################################### [root@centos ~]# fdisk /dev/sdb #开始格式化 Welcome to fdisk (util-linux 2.23.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table
Building a new DOS disklabel with disk identifier 0x3f5d5436.
Command (m for help): n Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended Select (default p): p Partition number (1-4, default 1): 1 First sector (2048-20971519, default 2048): 2048 Last sector, +sectors or +size{K,M,G} (2048-20971519, default 20971519): +5G Partition 1 of type Linux and of size 5 GiB is set Command (m for help): n Partition type:
p primary (1 primary, 0 extended, 3 free)
e extended Select (default p): p Partition number (2-4, default 2): First sector (10487808-20971519, default 10487808): Using default value 10487808 Last sector, +sectors or +size{K,M,G} (10487808-20971519, default 20971519): Using default value 20971519 Partition 2 of type Linux and of size 5 GiB is set Command (m for help): p
Disk /dev/sdb: 10.7 GB, 10737418240 bytes, 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos
Disk identifier: 0x3f5d5436 Device Boot Start End Blocks Id System /dev/sdb1 2048 10487807 5242880 83 Linux
/dev/sdb2 10487808 20971519 5241856 83 Linux
Command (m for help): w
The partition table has been altered! Calling ioctl() to re-read partition table.
Syncing disks.
[root@centos ~]#
开始挂载分好区的盘,并将文件复制到这两分区中,第一个分区定义为boot,第二个分区定义为sysroot ;
mkdir /mnt/boot /mnt/sysroot # 在centos系统上创建两个目录 [root@centos src]# lsblk # 查看刚刚分好区的sdb 盘 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 100G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 99G 0 part ├─cl-root 253:0 0 50G 0 lvm / ├─cl-swap 253:1 0 2G 0 lvm [SWAP] └─cl-home 253:2 0 47G 0 lvm /home sdb 8:16 0 10G 0 disk ├─sdb1 8:17 0 5G 0 part └─sdb2 8:18 0 5G 0 part sr0 11:0 1 1024M 0 rom [root@centos mnt]# mkfs.ext4 /dev/sdb1 #创建文件系统格式 mke2fs 1.42.9 (28-Dec-2013) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 327680 inodes, 1310720 blocks 65536 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=1342177280 40 block groups 32768 blocks per group, 32768 fragments per group 8192 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736 Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done [root@centos mnt]# mkfs.ext4 /dev/sdb2 mke2fs 1.42.9 (28-Dec-2013) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 327680 inodes, 1310464 blocks 65523 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=1342177280 40 block groups 32768 blocks per group, 32768 fragments per group 8192 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736 Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done [root@centos mnt]# blkid /dev/sda1: UUID="cbf299b0-d76d-4efe-8643-c900502683d4" TYPE="xfs" /dev/sda2: UUID="L416ib-7Z3D-rtXt-FqTb-ChsW-j6zH-heeuF2" TYPE="LVM2_member" /dev/mapper/cl-root: UUID="12c02980-3012-4884-8a7d-437195398fdb" TYPE="xfs" /dev/mapper/cl-swap: UUID="c4ea26e2-7424-4a52-aa34-8d9fb4f3fbd2" TYPE="swap" /dev/mapper/cl-home: UUID="7be941f2-fcf6-44b7-b673-f999f1c876b0" TYPE="xfs" /dev/sdb1: UUID="78df7716-e32f-421e-a756-8fe89407e9ec" TYPE="ext4" /dev/sdb2: UUID="c905f4d2-ae58-41f8-85e6-69d1f0237ad2" TYPE="ext4" [root@centos mnt]# [root@centos mnt]# mount /dev/sdb1 /mnt/boot [root@centos mnt]# mount /dev/sdb2 /mnt/sysroot [root@centos mnt]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/cl-root 50G 27G 24G 53% / devtmpfs 910M 0 910M 0% /dev tmpfs 920M 0 920M 0% /dev/shm tmpfs 920M 8.5M 912M 1% /run tmpfs 920M 0 920M 0% /sys/fs/cgroup /dev/sda1 1014M 185M 830M 19% /boot /dev/mapper/cl-home 47G 33M 47G 1% /home tmpfs 184M 0 184M 0% /run/user/0 /dev/sdb1 4.8G 20M 4.6G 1% /mnt/boot /dev/sdb2 4.8G 20M 4.6G 1% /mnt/sysroot
开始复制之前编译好的文件
cp /usr/src/vmlinuz /mnt/boot/ #linux kernel cp /usr/src/initrd.gz /mnt/boot/ #ramdisk 内存镜像(来自于busybox改造) cp -a /usr/src/sysroot/* /mnt/sysroot/ #系统目录集合(来自于busybox改造) [root@centos /]# tree mnt -L 2 mnt
├── boot
│ ├── initrd.gz
│ └── vmlinuz
└── sysroot
├── bin
├── boot
├── dev
├── etc
├── home
├── lib
├── mnt
├── proc
├── root
├── sbin
├── sys
├── tmp
├── usr
└── var
7. 安装grub引导程序到sdb1中
yum install grub2-install #由于centos7以后采用的是grub2 所以直接安装了这个 [root@centos mnt]# grub2-install --boot-directory=/mnt/boot /dev/sdb #安装到boot目录下 Installing for i386-pc platform. Installation finished. No error reported. [root@centos boot]# ll total 9248 drwxr-xr-x. 5 root root 4096 Feb 6 08:25 grub2 -rw-r--r--. 1 root root 1484989 Feb 6 08:03 initrd.gz -rw-r--r--. 1 root root 7975904 Feb 6 08:04 vmlinuz [root@centos boot]#grub2-mkconfig -o /mnt/boot/grub2/grub.cfg #为了方便我采用了先根据系统自动生成,然后再编辑这个文件 [root@centos boot]# vim /mnt/boot/grub2/grub.cfg #编辑内容见下图,去掉很多用不到的内容
grub.cfg 文件内容,仅仅保留了几个核心的信息
# relay display set timeout=5 # entry menuentry 'My Linux' { insmod gzio insmod part_msdos insmod xfs set root='hd0,msdos1' linux16 /vmlinuz root=/dev/sda2 initrd16 /initrd.gz }
8. 通过virtual 将刚刚创建的虚拟硬盘加载进来,并启动虚拟机。。。开始见证奇迹的时候。

欢迎界面出现,成功引导系统。

出错啦
估计猜测分析:
由于系统启动的时候需要挂载/dev/sda2 这块真正的rootfs 系统,可是在加载内存镜像initrd.gz 后,想启动挂载rootfs的时候,找不到硬盘分区了。
这里有个我们打包的时候,在涉及 第三方模块如ext4 驱动的时候,是没有打包到内核中的,但是默认是支持扩展挂载的,所以采用修改initrd.gz 这个文件,这个时候就需要用到modules了(前面只是生成了,还没有用到,所以需要先把这个modules打包进initrd.gz中,让他能找到ext4驱动)
同时也顺便把rootfs 的目录中也一并处理成镜像的样子。
sysroot 和initrd 两个目录一样操作:
cd /mnt/sysroot cp -a /usr/src/modules/lib usr/ #复制modules进入这个文件夹 mkdir usr/lib64 #创建空文件夹,只是为了规范一点 ln -s usr/lib64 lib64 ln -s usr/lib lib #initrd 同样操作 cd /usr/src/initrd cp -a /usr/src/modules/lib usr/ #复制modules进入这个文件夹 mkdir usr/lib64 #创建空文件夹,只是为了规范一点 ln -s usr/lib64 lib64 ln -s usr/lib lib # 重新生成initrd.gz 由于模块我没有精简所以耗时比较久 find . | cpio -H newc --quiet -o | gzip -9 > /usr/src/initrd.gz # 替换 旧的initrd.gz cp initrd.gz /mnt/boot/
通过修改init文件,我虽然进去了镜像系统,但是由于始终没有找到硬盘,导致rootfs没有能进入,也请各位大神帮忙解开这个结,我不知道哪里出了问题。
开始修改 init 不进行rootfs转换,直接进入内存系统:
#!/bin/sh echo "Mounting proc and sys..." mount -t sysfs sysfs /sys
mount -t proc proc /proc echo "Detect and export hardware infomation..." mdev -s exec /bin/sh
把项目两句话注释掉,改成直接执行 exec /bin/sh 作为主进程 echo "Mount real rootfs to /mnt/sysroot..." #mount -t ext4 -o ro /dev/sda2 /mnt/sysroot echo "Switch to real rootfs..." # exec chroot /mnt/sysroot /sbin/init
这个时候内存系统进去了:


但是根本但是在/dev/ 下根本没有sdaX的硬盘分区。
首先驱动也是有的,通过grub也是能看到的。
cat /proc/filesystems

进入刚刚启动时候的grub界面,是能看到硬盘分区的:


终极解决:
---硬盘找不到的问题已经解决,补充进去:
通过修改配置linux kernel 已经解决硬盘找不到的问题:
Device Drivers > SCSI device Support >SCSI Disk Support
SCSI generic support

以上通过修改内核kernel配置后,重新编译覆盖/boot/vmlinuz 文件后,再次启动,终于见到了完美的结局,找到了硬盘,并且成功从内存镜像加载到了rootfs磁盘系统目录,大功告成!!!

后语:
本来在做这个实验的时候,做到了内存的启动,死活不知道为啥硬盘没找到,搞了仅两天时间,没有找到原因,最终偶然的机会,我整理了下思路,既然磁盘没有找到,那应该是modules没有,但是我将所有modules加入到initrd.gz的时候发现打完包后的initrd.g又太大了,所以这种思路我就直接放弃了,我就通过重新修改linux 内核,直接将ext4相关的配置打在了镜像里面,这样文件就不大了,而硬盘找不到的原因呢,由于我采用的是virtubalbox 所以是sata硬盘的scsi ,然后我就到device driver下看了下scsi的加载与搜索情况,发现有个配置没有配置上,于是我就配置上了,并重新打包,再次启动的时候奇迹出现了,终于找到了硬盘。
相关推荐
-
nginx检查提示“unknown directive "stream" in /etc/*/nginx.conf”
nginx检查提示“unknown directive "stream" in /etc/*/nginx.conf”2025-02-26 00:38:21 -
php之多级目录下查找文件中是否含有某个字符串功能实现2025-02-26 00:36:35
-
mysql 启动不了1067错误如何解决?2025-02-26 00:33:31
-
MySQL简单INSERT超慢原因排查2025-02-26 00:22:42
-
mysql分布式数据库的主要构架是什么?2025-02-26 00:06:23