使用 busybox 制作磁盘镜像文件

本文制作的磁盘镜像文件(*.img)用于在 Qemu virt 上启动 Linux

busybox 用于提供基础的系统命令,如 cat tree man dd chmod 等等

首先下载、配置、编译 busybox

1.1 下载并解压 BusyBox

下载最新版本的 BusyBox 源码:

bash 复制代码
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xjf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
1.2 配置 BusyBox (静态编译)

这是最关键的一步。我们需要静态编译 BusyBox,这样它就不依赖系统中的动态链接库(glibc),可以直接在我们的极简环境中运行。

  1. 运行配置菜单:

    bash 复制代码
    make menuconfig
  2. 进入设置:

    • Settings --->
    • 勾选 [*] Build static binary (no shared libs)
  3. 保存并退出。

1.3 编译与安装

这里需要注意是否需要交叉编译

bash 复制代码
make -j$(nproc)
make install

编译完成后,生成的文件会在当前目录下的 _install 文件夹中。

bash 复制代码
m@m-ThinkPad-T14-Gen-2i:~/chy/busybox-1.36.1/_install$ ls
bin  linuxrc  sbin  usr

此时 rootfs 目录结构初具雏形。

我们需要在 _install 的基础上完善 Linux 运行所需的目录结构。

bash 复制代码
cd _install
mkdir -p dev proc sys etc/init.d tmp var

Linux 内核启动后会执行第一个程序 PID1(默认顺序是 /sbin/init, /etc/init, /bin/init, /bin/sh)。在使用 busybox 构建出来的 rootfs 中,他会先找到 /sbin/init,/sbin/init 会读取配置文件 /etc/inittab,我们提供这个文件,让 /sbin/init fork 出 bash------PID2

bash 复制代码
# 创建文件
sudo touch mnt/etc/inittab

# 写入配置
sudo sh -c 'cat <<EOF > mnt/etc/inittab
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -t sysfs sysfs /sys
::sysinit:/bin/mount -t devtmpfs devtmpfs /dev
::sysinit:/bin/echo "------------------------------"
::sysinit:/bin/echo "   System Boot Initialized"
::sysinit:/bin/echo "------------------------------"

# 在主控制台上启动 Shell
# "console" 关键字会自动匹配内核启动参数中的 console=...
console::askfirst:-/bin/sh

# 处理重启和关机信号
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
EOF'

制作分区磁盘镜像 (Partition Image)

这是本任务的核心部分。我们将创建一个文件,将其虚拟为磁盘,创建分区,格式化,并写入数据。

3.1 创建空镜像文件

我们将创建一个大小为 128 MB 的空镜像文件。

bash 复制代码
cd .. # 回到上级目录
dd if=/dev/zero of=disk.img bs=1M count=128

这部分为镜像文件创建了分区表和分区,其实这一步是不必要的。创建分区表和分区后,这个镜像文件应该称为磁盘镜像(它的第 00 个字节是分区表(MBR 或 GPT)和引导代码。文件系统并不在开头,而是被埋在文件内部的某个位置(通常是第 20482048 个扇区之后)。 ),对他的挂载会稍微复杂一点,但他在实际使用时的适配性会好一点。如果不创建分区和分区表,那整个镜像文件就是分区镜像(它的第 00 个字节开始就是文件系统(如 ext4, FAT32)的超级块(Superblock)。),可以直接挂载,但在一些场景下不好用。

3.2 创建分区表

使用 fdisk 创建一个主分区。

bash 复制代码
# 通过管道自动输入命令:n(新建), p(主分区), 1(编号), 回车(默认起始), 回车(默认结束), w(写入)
echo -e "n\np\n1\n\n\nw" | fdisk disk.img
3.3 格式化并挂载

由于我们要操作镜像文件内部的分区,需要使用 losetup 将其映射为回环设备。

bash 复制代码
# 将镜像映射到 loop 设备,-P 参数会自动扫描分区
sudo losetup -P -f --show disk.img

假设输出的设备是 /dev/loop0(请根据实际输出调整),那么分区就是 /dev/loop0p1

格式化为 ext4:

bash 复制代码
sudo mkfs.ext4 /dev/loop0p1

挂载分区:

bash 复制代码
mkdir -p mnt sudo mount /dev/loop0p1 mnt

3.4 写入 RootFS

将之前 BusyBox 生成的 _install 目录下的所有内容复制到挂载点。

bash 复制代码
sudo cp -r busybox-1.36.1/_install/* mnt/

现在 rootfs 中有 dev 目录,但其中还没有设备文件。虽然 /sbin/init 会重新 mount dev 目录,但是在那之前我们需要创建一些更基础的设备文件。

设备文件和普通文件的区别:普通文件和设备文件在磁盘中都对应一个 inode, 普通文件的 inode 中存储着一组指针,指向磁盘上具体的扇区,这些扇区里存储这文件的内容。设备文件的 inode 中不存储指向扇区的指针,而是存储着

  1. 设备类型:如 c 字符设备; b 块设备

  2. 主次设备号:主设备号即对应的驱动程序的 id, 次设备号即该驱动管理的具体设备编号

创建设备文件的方法就是把当前主机 rootfs 中的已有设备文件复制过来(这里的 -a 是必须的)

bash 复制代码
# 直接从宿主机复制 console 和 null
sudo cp -a /dev/console mnt/dev
sudo cp -a /dev/null mnt/dev

卸载并断开连接:

bash 复制代码
sudo umount mnt
sudo losetup -d /dev/loop0

现在,disk.img 就是一个包含完整 BusyBox 系统的可启动分区镜像了。

相关推荐
EndingCoder2 小时前
索引类型和 keyof 操作符
linux·运维·前端·javascript·ubuntu·typescript
石小千2 小时前
Linux清除缓存
linux·运维
weixin_516023072 小时前
VESTA在Linux下的安装
linux·运维·服务器
Mr -老鬼2 小时前
移动端跨平台框架的选型指南
经验分享·移动开发·框架·团队开发·个人开发·跨平台
Nautiluss3 小时前
一起调试XVF3800麦克风阵列(十四)
linux·人工智能·音频·语音识别·dsp开发
架构师沉默3 小时前
企业级开发项目的 Cursor rules
经验分享
耶耶耶耶耶~3 小时前
arch linux 安装
linux·运维·服务器
iYun在学C3 小时前
驱动程序开发(字符设备驱动框架实验)
linux·c语言·嵌入式硬件
ashcn20014 小时前
linux 制作一个自解压文件
linux·运维·服务器