news 2026/10/15 17:55:10

pi-gen镜像导出原理揭秘:fdisk分区、losetup循环设备到zerofree瘦身完整实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pi-gen镜像导出原理揭秘:fdisk分区、losetup循环设备到zerofree瘦身完整实战

【免费下载链接】pi-gen

Tool used to create the raspberrypi.org Raspbian images

项目地址:https://gitcode.com/gh_mirrors/pig/pi-gen
点击查看免费下载

pi-gen 是树莓派官网用来制作 Raspbian 系统镜像的工具(详见 README.md)。它构建流程中最精妙的「镜像导出」阶段堪称磁盘操作范例:先用truncate切出一个原始.img文件,用fdisk非交互写入双分区表,再用losetup循环设备把分区「挂载」成真实块设备,写满 ext4 根文件系统,最后用zerofree把空闲空间清零给镜像瘦身,再打包压缩。下文沿着真实源码,把这些原理一步步讲清楚。

一、镜像导出在哪里被触发?

build.sh 是整个构建的总调度:

  1. 按字母序依次执行所有stage*目录:stage0(debootstrap 引导)→ stage1(可启动的最小系统)→ stage2(Lite)→ stage3(桌面)→ stage4(完整版)→ stage5(Mathematica)。每个阶段产出一个不断长大的rootfs/目录树;
  2. 阶段目录里若存在EXPORT_IMAGE标记文件,就进入导出队列。例如 stage2/EXPORT_IMAGE 声明IMG_SUFFIX="-lite"产出 Lite 镜像,stage4/EXPORT_IMAGE 后缀为空,产出完整镜像;
  3. 所有阶段结束后,build.sh 把STAGE_DIR指向 export-image/,把导出脚本当作「特殊阶段」对队列里的每个系统依次执行;若阶段还声明了EXPORT_NOOBS且非 QEMU 模式,会接着跑 export-noobs/ 打包。

所以镜像导出并不神秘——它就是系统搭建完毕后执行的又一个「阶段」。

二、🧱 创建骨架:truncate 与 fdisk 分区

导出阶段的核心脚本是 export-image/prerun.sh,它先于所有子阶段执行。

2.1 镜像尺寸是怎么算出来的

脚本先用du统计/boot目录与整个 rootfs(排除 apt 缓存)的实际字节数,然后:

  • IMG_SIZE = (boot 大小 + rootfs 大小 + 800MB),向上取整到 4MB 对齐——多出的 800MB 是留给系统日后升级的「增长余量」;
  • boot 分区大小取2×/boot 实际内容,为固件与内核更新留足空间;
  • root 分区起点 = boot 分区末端向上取整到 4MB 边界,再外移 8192 个扇区(4MB)间隙,保证分区对齐整齐。

接着truncate -s按该尺寸创建一个稀疏文件——这就是原始.img,此刻全是零字节、没有任何分区表。

2.2 用 fdisk 非交互写分区表

fdisk -H 255 -S 63采用传统 255 磁头/63 扇区几何,兼容树莓派 Bootloader;再配合 heredoc 管道输入命令,全程无需人工交互:

命令含义
o创建新的 DOS(MBR) 分区表
n新建主分区 1:起始扇区8192(即 4MB 偏移),大小+2×boot/512扇区
t/c分区 1 类型设为c(W95 FAT32 LBA),即 boot 分区
n主分区 2:从对齐后的 root 起始扇区到盘尾,Linux 类型
w将分区表写入镜像文件

最终得到经典的双分区布局:小 FAT32 boot 分区 + 大 ext4 rootfs 分区——和官方镜像烧录进 SD 卡后的布局完全一致。

三、losetup 循环设备:让镜像文件「变成」真实磁盘

分区只是普通文件里的一段字节,要格式化并写入,必须让内核把它们当块设备对待,这正是losetup的职责。

3.1 取出分区字节偏移

export-image/prerun.sh 用parted -s unit b print解析出分区 1、2 的起始字节与长度。

3.2 绑定循环设备

BOOT_DEV=$(losetup --show -f -o "${BOOT_OFFSET}" --sizelimit "${BOOT_LENGTH}" "${IMG_FILE}") ROOT_DEV=$(losetup --show -f -o "${ROOT_OFFSET}" --sizelimit "${ROOT_LENGTH}" "${IMG_FILE}")

三个要点:

  • -f自动挑选/dev/loopN空闲设备;
  • -o指定起始字节偏移,--sizelimit限定长度——每个循环设备精确覆盖一个分区,不多一字节;
  • --show输出设备路径供后续步骤使用。

之后就是熟悉的磁盘操作:

  1. mkdosfs -n boot -F 32把 boot 分区格式化为 FAT32;
  2. mkfs.ext4 -L rootfs格式化根分区,并借-O关闭metadata_csum、64bit、huge_file等新特性(见 prerun.sh#L56-L61),保证老旧固件与工具都能读取;
  3. mount挂载两个分区,rsync把构建好的 rootfs(排除/boot与 apt 缓存)和 boot 文件分别拷入。

数据写完,导出流程进入若干「精装修」子阶段。

四、写入 PARTUUID:让系统找到自己的分区

镜像里的/etc/fstab与/boot/cmdline.txt中还保留着BOOTDEV、ROOTDEV占位符(见 stage1/01-sys-tweaks/files/fstab)。脚本 export-image/03-set-partuuid/00-run.sh 用dd读取镜像文件第 440 字节处 4 字节的 MBR「磁盘签名」,拼上-01/-02得到两个分区唯一的 PARTUUID,再sed改写两处配置:

  • BOOTDEV→PARTUUID=<签名>-01(boot 分区)
  • ROOTDEV→PARTUUID=<签名>-02(根分区)

这样系统开机后按「磁盘签名 + 分区号」而非/dev/mmcblk0p1这类固定设备名查找分区,即使 SD 卡枚举顺序变化也依然稳定。

五、🧹 系统清理与 zerofree 瘦身

最后一个子阶段 export-image/04-finalise/01-run.sh 专职「减重」:

  • 停止 fake-hwclock 服务,hardlink -t合并/usr/share/doc下完全相同的文档文件;
  • 删除 apt 缓存、dpkg 备份、旧日志、图标缓存、machine-id 等「首次开机无用」文件;
  • 日志文件截断为零长度,并把版本信息写入boot/issue.txt与随镜像发布的.info文件。

5.1 为什么 zerofree 能让镜像明显变小

卸载根分区后,脚本对循环设备执行 zerofree:

zerofree 扫描 ext4 文件系统,把所有未写入的自由块清零。

此时镜像文件的原始内容变成:系统文件 + 海量连续零字节。压缩算法(zip、pixz/xz)对连续零数据的压缩比极高,最终打包体积因此远低于分区名义大小——这就是「官方镜像只有几个 GB,而 rootfs 分区却有一千多 MB」的核心技巧。

收尾时 scripts/common 中的unmount_image负责 sync 磁盘、按序卸载挂载点并用losetup -d摘除循环设备;随后按DEPLOY_ZIP开关用zip压缩输出到deploy/目录(susi 分支还支持.img.xz)。

六、📦 导出成果一览

阶段IMG_SUFFIX产物
stage2/EXPORT_IMAGE-liteLite 镜像(无桌面环境)
stage4/EXPORT_IMAGE空完整桌面镜像
stage5/空完整版 + Mathematica

把烧录好的镜像开机,先看到安装引导画面,随后即得到如下 Raspbian 桌面:

七、关键文件路径速查

  • 构建与导出总调度:build.sh
  • 创建 img、fdisk 分区、losetup 挂载、rsync 写数据:export-image/prerun.sh
  • 镜像内 apt 升级与清缓存:export-image/01-set-sources/01-run.sh
  • PARTUUID 替换:export-image/03-set-partuuid/00-run.sh
  • 清理、zerofree 瘦身、zip 打包:export-image/04-finalise/01-run.sh
  • 通用函数(unmount_image、on_chroot 等):scripts/common
  • 构建依赖工具清单:depends

全流程回顾

truncate 创建 img → fdisk 双分区 → parted 解析偏移 → losetup 绑定循环设备 → mkdosfs / mkfs.ext4 → rsync 写入数据 → chroot 内 apt 升级 → 改写 PARTUUID → 系统清理 →zerofree 清零空闲空间→ 摘除循环设备 → zip/pixz 压缩输出至 deploy/

十步走下来,一个「裸目录」就变成了可直接烧录、可引导的系统镜像——这就是「树莓派镜像到底是怎么做出来的」的完整答案。

【免费下载链接】pi-gen

Tool used to create the raspberrypi.org Raspbian images

项目地址:https://gitcode.com/gh_mirrors/pig/pi-gen
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 17:54:09

IGBT损耗计算与变频器功率模块寿命评估

IGBT动态特性参数解构与变频器功率模块损耗计算方法 IGBT动态特性参数解构与测试条件辨析 损耗计算的起点不是数据手册上的 Eon/Eoff 数字&#xff0c;而是产生这些数字的测试条件与实际工况之间的偏差。把偏差量化&#xff0c;才能谈得上精度。 双脉冲平台的测量链路 双脉冲测…

作者头像 李华
网站建设 2026/10/15 17:52:29

三菱CNC数据采集Demo用C#实现全流程详解:EZSocket通信与宏变量读取

简介&#xff1a;C#数据采集Demo面向三菱CNC系统&#xff0c;专为机床自动化工程师、上位机开发者和工业物联网从业者设计&#xff0c;旨在解决机床实时监控、加工参数读取、设备状态追踪及故障日志获取等工业数据采集难题。压缩包约3.52MB&#xff0c;内部包含PDF格式的参考手…

作者头像 李华
网站建设 2026/10/15 17:52:11

IgH EtherCAT软主站落地:PDO/SDO/DC配置与抖动排查

简介&#xff1a;这套代码是基于IgH EtherCAT Master 1.5.2的实践开源项目&#xff0c;面向工业以太网总线开发者&#xff0c;尤其适合需要驱动伺服电机和IO板卡、学习PDO/SDO通信的工程师。资源共113个文件&#xff0c;以头文件&#xff08;h&#xff09;、源文件&#xff08;…

作者头像 李华
网站建设 2026/10/15 17:51:38

Java Web老项目部署指南:从.rar解压到Tomcat运行

简介&#xff1a;这是一套基于Java与MySQL开发的学生成绩管理系统完整源码工程&#xff0c;面向计算机专业初学者及课程设计实践者&#xff0c;解决高校教务场景中学生信息录入、成绩管理、选课操作与数据统计等核心需求。资源包共104个文件&#xff0c;含29个可读性强的Java源…

作者头像 李华