3. 根文件系统基础:概念、BusyBox原理与Tina组成
说到根文件系统,很多刚接触嵌入式Linux的朋友容易把它跟内核搞混。我早期带项目时就遇到过一位同事,拿着编译好的内核镜像反复烧写,系统就是起不来——最后发现根文件系统压根没放进去。嗯,这种坑踩过一次就记住了。
说白了,根文件系统就是Linux启动后挂载的第一个文件系统,它提供了系统运行所需的目录结构、基础命令、库文件和配置文件。内核负责驱动硬件,根文件系统负责提供用户态的一切。
3.1 根文件系统的核心概念
根文件系统以/为起点,包含几个关键目录。我整理了一张结构图,帮你快速建立整体认知:
关键认知:根文件系统不是"一个文件",而是一套目录树结构。内核启动后挂载它,然后执行 /sbin/init 作为第一个用户态进程。如果 /sbin/init 找不到,系统会直接 panic。
3.2 BusyBox原理——一个程序包揽天下
嵌入式设备存储空间有限,不可能像PC一样装几百个独立命令。BusyBox就是来解决这个问题的。它把 ls、cp、mv、sh、ifconfig 等200多个常用命令塞进一个可执行文件里,通过符号链接或硬链接来区分调用哪个功能。
我举个例子你就明白了:
# 查看 BusyBox 支持的命令列表
/bin/busybox --list
# 手动调用某个命令
/bin/busybox ls -l /etc
# 符号链接方式
ln -s /bin/busybox /bin/ls
ln -s /bin/busybox /bin/cp
# 执行 /bin/ls 时,BusyBox 通过 argv[0] 判断要执行 ls 功能
BusyBox的编译配置非常灵活。你可以通过 make menuconfig 选择要开启哪些命令,每个命令还可以细调参数。我在Tina上做产品时,一般会关掉那些用不到的——比如设备里没有USB网卡,就把 ifconfig 的无线相关选项去掉,能省下几十KB。
| 特性 | BusyBox | GNU Coreutils |
|---|---|---|
| 单个程序体积 | ~300KB~1MB(视配置) | 每个命令几十KB~几MB |
| 命令数量 | 200+(可裁剪) | 100+(固定) |
| 依赖库 | 通常仅 libc | 依赖较多 |
| 适用场景 | 嵌入式、initramfs | 桌面/服务器 |
| 配置灵活性 | 极高(menuconfig) | 低 |
我的习惯:在Tina中,我会先保持BusyBox默认配置编译一版,启动后跑 busybox --list 看看实际用到了哪些命令,然后回头裁剪。这样不会漏掉关键工具。
3.3 Tina中根文件系统的组成
Tina的根文件系统不是手写的,而是通过一套构建系统自动生成。你执行 make 后,它会经历几个阶段:
- 编译BusyBox — 生成
busybox可执行文件及符号链接 - 安装库文件 — 从工具链的
sysroot复制所需的.so到/lib - 生成配置文件 — 填充
/etc下的 inittab、fstab、passwd 等 - 创建设备节点 — 静态创建
/dev/console、/dev/null等关键节点 - 打包镜像 — 根据配置格式(squashfs、jffs2、ext4、initramfs)生成最终文件
我们来看看Tina根文件系统里几个关键目录的具体内容:
/bin — 用户命令
这里放的是系统启动和日常操作必需的命令。Tina默认包含:
- sh — 默认shell(BusyBox的ash)
- ls, cp, mv, rm, cat, echo — 文件操作基础
- mount, umount — 挂载文件系统
- ps, top, kill — 进程管理
- sed, awk, grep — 文本处理
/sbin — 系统管理命令
这些命令通常只有root权限才能执行:
- init — 1号进程,PID永远为1
- ifconfig, route — 网络配置
- fdisk, mkfs — 磁盘分区格式化
- reboot, poweroff — 系统控制
- logread — 查看syslog
/etc — 配置文件
这是根文件系统里最需要关注的地方。我调试驱动时,一半时间都在跟这里的文件打交道:
| 文件 | 作用 | 常见问题 |
|---|---|---|
| inittab | 定义init启动的进程和运行级别 | 漏写 ttyS0::respawn:/bin/sh 导致串口无shell |
| fstab | 自动挂载表(mmc、nfs、tmpfs等) | 挂载参数错误导致系统启动卡住 |
| init.d/rcS | 系统初始化脚本,按顺序执行 | 脚本里依赖顺序不对,驱动加载失败 |
| passwd / shadow | 用户账户信息 | 忘记设root密码,telnet连不上 |
| resolv.conf | DNS配置 | 域名解析失败,ping IP通但ping域名不通 |
我曾经踩过的坑:有一次调试全志V3s的网卡驱动,系统启动后eth0死活拿不到IP。查了两天,最后发现是 /etc/init.d/rcS 里网络初始化脚本跑在了驱动加载之前。驱动还没注册好,脚本就去 ifconfig eth0 up,当然失败。后来我在rcS里加了 sleep 1 等待驱动就绪,问题解决。
/lib — 库与模块
这个目录决定了你的程序能不能跑起来。Tina的 /lib 通常包含:
- libc.so — C运行时库(glibc或musl,取决于工具链配置)
- ld-linux.so — 动态链接器
- libm.so, libpthread.so, librt.so — 数学、线程、实时库
- modules/ — 内核模块存放目录,驱动
.ko文件放这里 - libgcc_s.so — GCC运行时支持库,某些程序必须
你可以用 readelf -d 查看一个程序依赖哪些库:
# 在Tina开发板上执行
readelf -d /bin/busybox | grep NEEDED
0x00000001 (NEEDED) Shared library: [libc.so]
0x00000001 (NEEDED) Shared library: [ld-linux.so]
BusyBox只依赖libc和链接器,这也是它体积小的原因之一。如果你的应用程序依赖更多库,记得检查 /lib 下有没有,没有的话要从工具链的sysroot里拷过来。
3.4 根文件系统的构建流程
在Tina中,根文件系统的构建是自动化的。但理解它的步骤,对你排查问题非常有帮助:
- 配置阶段 —
make menuconfig选择目标板、文件系统类型、软件包 - 编译阶段 — 编译内核、BusyBox、第三方库、应用程序
- 安装阶段 — 把所有产物安装到一个临时目录(
out/<板型>/compile_dir/target/rootfs) - 后处理阶段 — 设置文件权限、创建设备节点、生成
/etc配置文件 - 打包阶段 — 根据配置生成 squashfs、jffs2、ext4 或 initramfs 镜像
调试技巧:如果你在Tina中改了某个配置文件(比如 inittab),不需要重新编译整个系统。直接修改 out/<板型>/compile_dir/target/rootfs/etc/inittab,然后重新打包镜像即可。我经常用这个方法来快速验证配置修改。
根文件系统是嵌入式Linux的基石。你想想看,内核再牛,没有根文件系统它也跑不了任何应用程序。理解它的组成和构建逻辑,后面做驱动调试、系统裁剪、启动优化才能得心应手。