4. rootfs基础概念
在嵌入式 Linux 系统中,rootfs(根文件系统)是内核启动后挂载的第一个文件系统,也是用户空间所有进程、配置、库和设备的“落脚点”。对于 RK3568 这类 ARM64 平台,rootfs 不仅决定系统能否正常启动,还直接影响后续应用部署、调试和维护的便利性。理解 rootfs 的层次标准、目录结构、BusyBox 的角色、init 进程的职责以及系统库与运行时依赖,是构建可启动、可维护系统的前提。
一、核心原理:FHS 与根目录结构
Linux 根文件系统遵循 FHS(Filesystem Hierarchy Standard,文件系统层次标准)。FHS 规定了各目录的用途,使不同发行版和嵌入式系统之间保持一致性。RK3568 的 rootfs 通常包含以下关键目录:
| 目录 | 用途 | 典型内容 |
|---|---|---|
| /bin | 基础用户命令 | ls、cp、sh、mount |
| /sbin | 系统管理命令 | init、ifconfig、reboot |
| /etc | 系统配置 | inittab、fstab、passwd |
| /lib | 共享库与内核模块 | libc.so、ld-linux、modules |
| /dev | 设备节点 | console、ttyS0、mmcblk |
| /proc | 内核与进程信息 | 虚拟文件系统,运行时生成 |
| /sys | 设备与驱动模型 | 虚拟文件系统,运行时生成 |
| /usr | 用户程序与资源 | bin、lib、share |
| /var | 可变数据 | log、run、tmp |
| /root | root 用户主目录 | 启动脚本、调试文件 |
在嵌入式场景中,/proc 和 /sys 通常由内核在启动时挂载,/dev 可由 devtmpfs 或 mdev 动态管理。因此,制作 rootfs 时不必手动填充这些目录,但必须在启动脚本中正确挂载它们。
二、BusyBox:嵌入式 rootfs 的“瑞士军刀”
BusyBox 将大量常用 Unix 命令集成到一个可执行文件中,通过符号链接或硬链接提供不同命令入口。它体积小、依赖少,非常适合 RK3568 这类资源受限的嵌入式设备。典型 rootfs 中,/bin 和 /sbin 下的命令大多指向 /bin/busybox。
# 查看 busybox 支持的命令
./busybox --list
# 创建符号链接示例
ln -s /bin/busybox /bin/ls
ln -s /bin/busybox /bin/mount
ln -s /bin/busybox /sbin/init
BusyBox 的 init 程序是嵌入式系统最常用的 init 实现。它读取 /etc/inittab,按配置执行系统初始化、启动 shell 或应用程序。相比 systemd,BusyBox init 更轻量,启动流程更直观,适合快速构建和调试。
三、init 进程:用户空间的第一个进程
内核启动完成后,会尝试执行 /sbin/init、/etc/init 或 /bin/init。init 进程 PID 为 1,负责挂载文件系统、启动服务、管理运行级别和回收孤儿进程。在 BusyBox init 中,/etc/inittab 是核心配置文件:
# /etc/inittab 示例
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
其中,sysinit 指定系统初始化脚本,askfirst 在控制台启动一个 shell,ctrlaltdel 定义组合键行为,shutdown 在系统关闭时执行清理。对于 RK3568 产品化系统,通常会将 askfirst 替换为直接启动应用程序,或通过脚本判断启动模式。
init 进程的启动顺序非常关键:先挂载 /proc、/sys、/dev,再加载内核模块,然后配置网络、启动服务,最后进入应用。任何一步失败都可能导致系统无法进入用户空间。
四、系统库与运行时依赖
RK3568 是 ARM64 架构,rootfs 中的可执行文件必须与目标架构匹配。系统库主要包括:
- C 库:glibc 或 musl。glibc 功能完整但体积较大,musl 更轻量,适合嵌入式。
- 动态链接器:如 /lib/ld-linux-aarch64.so.1,负责加载共享库。
- 基础库:libm、libpthread、libdl 等,通常随 C 库提供。
- 应用依赖库:如 libssl、libcurl、Qt 库等,需根据应用需求部署。
检查运行时依赖可使用 readelf 或 ldd:
# 查看可执行文件依赖
readelf -d /bin/busybox | grep NEEDED
# 在目标板上检查动态库
ldd /usr/bin/myapp
如果缺少某个共享库,程序会报 “error while loading shared libraries”。此时需要将对应库文件复制到 /lib 或 /usr/lib,并确保动态链接器路径正确。对于交叉编译环境,还要注意库的版本和 ABI 兼容性。
五、案例与复盘:一个最小可启动 rootfs
假设我们要为 RK3568 构建一个最小 rootfs,步骤如下:
- 创建目录骨架:bin、sbin、etc、lib、dev、proc、sys、usr、var、root。
- 交叉编译 BusyBox,安装到 rootfs。
- 创建 /etc/inittab 和 /etc/init.d/rcS。
- 复制交叉工具链中的 libc 和动态链接器到 /lib。
- 制作镜像并烧录,观察串口启动日志。
常见误区包括:忘记挂载 /proc 导致 ps 命令失败;inittab 路径错误导致 init 无法启动;库文件权限不足导致动态链接失败;/dev/console 不存在导致没有串口输出。复盘时应优先检查内核命令行中的 root= 参数、init 路径和库依赖。
总结来看,rootfs 是 RK3568 系统启动链条中承上启下的关键环节。FHS 提供目录规范,BusyBox 提供轻量命令集,init 负责启动流程,系统库保证程序运行。只有这四者协同正确,系统才能从内核顺利过渡到用户空间,并为后续应用部署打下稳定基础。