4、构建基础目录结构:创建标准目录
好,到了这一步,我们终于要开始动手搭建根文件系统的骨架了。说白了,就是创建那些你天天见、但可能从来没想过为什么存在的目录——/bin、/sbin、/usr、/etc、/lib、/dev、/proc、/sys 等等。
我刚开始做嵌入式的时候,觉得这步就是 mkdir 一下,没什么技术含量。后来有一次,我图省事少建了一个 /run 目录,结果某个服务启动时直接报错,排查了半天才发现是 tmpfs 挂载点没地方落。嗯,从那以后我再也不敢小看这个步骤了。
4.1 为什么需要这些目录?
你想想看,Linux 根文件系统不是随便扔一堆文件就完事的。它有一套约定俗成的规矩——FHS(Filesystem Hierarchy Standard)。这套标准规定了每个目录该放什么、不该放什么。
我个人的习惯是:先理解,再动手。下面这张图能帮你快速建立整体认知:
4.2 各目录的职责
咱们一个一个来看。我按实际使用频率和重要性排个序:
| 目录 | 用途 | 典型内容 | 是否必须 |
|---|---|---|---|
/bin |
用户级基础命令 | ls, cp, mv, cat, sh | ✅ 必须 |
/sbin |
系统管理命令 | init, mount, fdisk, ifconfig | ✅ 必须 |
/usr |
用户软件资源 | 头文件、库、文档、额外工具 | ✅ 必须 |
/etc |
系统配置文件 | passwd, fstab, inittab | ✅ 必须 |
/lib |
共享库和内核模块 | ld-linux.so, libc.so | ✅ 必须 |
/dev |
设备节点 | console, null, ttyS0 | ✅ 必须 |
/proc |
进程和内核信息(虚拟) | cpuinfo, meminfo, uptime | ✅ 必须 |
/sys |
设备和驱动信息(虚拟) | class, block, devices | ✅ 必须 |
/tmp |
临时文件 | 运行时产生的临时数据 | ⚠️ 建议 |
/var |
可变数据 | 日志、缓存、锁文件 | ⚠️ 建议 |
/run |
运行时数据(tmpfs) | pid 文件、socket | ⚠️ 建议 |
/mnt |
临时挂载点 | U盘、SD卡挂载目录 | 🔧 按需 |
💡 我的经验:嵌入式系统里,/proc 和 /sys 虽然是虚拟文件系统,但目录必须提前创建好。否则内核启动时 mount 会失败,很多工具直接罢工。我见过有人把 /proc 漏了,结果 ps 命令报错,排查了半天才发现是目录没建。
4.3 动手创建目录
好了,理论说完了,咱们直接上命令。假设你的根文件系统暂存目录是 ~/rootfs:
# 创建基础目录
mkdir -p ~/rootfs/bin
mkdir -p ~/rootfs/sbin
mkdir -p ~/rootfs/usr
mkdir -p ~/rootfs/etc
mkdir -p ~/rootfs/lib
mkdir -p ~/rootfs/dev
mkdir -p ~/rootfs/proc
mkdir -p ~/rootfs/sys
mkdir -p ~/rootfs/tmp
mkdir -p ~/rootfs/var
mkdir -p ~/rootfs/run
mkdir -p ~/rootfs/mnt
# 验证结果
ls -la ~/rootfs/
执行完之后,你应该能看到类似这样的输出:
drwxr-xr-x 2 user user 4096 Mar 15 10:00 bin
drwxr-xr-x 2 user user 4096 Mar 15 10:00 dev
drwxr-xr-x 2 user user 4096 Mar 15 10:00 etc
drwxr-xr-x 2 user user 4096 Mar 15 10:00 lib
drwxr-xr-x 2 user user 4096 Mar 15 10:00 mnt
drwxr-xr-x 2 user user 4096 Mar 15 10:00 proc
drwxr-xr-x 2 user user 4096 Mar 15 10:00 run
drwxr-xr-x 2 user user 4096 Mar 15 10:00 sbin
drwxr-xr-x 2 user user 4096 Mar 15 10:00 sys
drwxr-xr-x 2 user user 4096 Mar 15 10:00 tmp
drwxr-xr-x 2 user user 4096 Mar 15 10:00 usr
drwxr-xr-x 2 user user 4096 Mar 15 10:00 var
⚠️ 权限说明:默认权限是 755(drwxr-xr-x),这没问题。但 /tmp 和 /var/tmp 建议改成 777,因为很多程序需要在这里创建临时文件。命令:chmod 1777 ~/rootfs/tmp。那个 1 是 sticky bit,防止用户乱删别人的临时文件。
4.4 /usr 目录的内部结构
/usr 是个大目录,里面还有子目录。我个人习惯一次性建好,省得后面补:
mkdir -p ~/rootfs/usr/bin
mkdir -p ~/rootfs/usr/sbin
mkdir -p ~/rootfs/usr/lib
mkdir -p ~/rootfs/usr/include
mkdir -p ~/rootfs/usr/share
mkdir -p ~/rootfs/usr/local
为什么要这么分?说白了,/usr 是给用户安装的软件用的。/usr/bin 放用户命令,/usr/sbin 放系统管理命令,/usr/lib 放库文件,/usr/include 放头文件——编译程序时要用。
4.5 设备节点的预创建
/dev 目录比较特殊。现代系统大多用 devtmpfs 或 udev 动态管理设备节点,但根文件系统刚启动时,内核还没挂载 devtmpfs,所以你得先手动创建几个关键节点:
# 创建控制台和 null 设备
sudo mknod -m 600 ~/rootfs/dev/console c 5 1
sudo mknod -m 666 ~/rootfs/dev/null c 1 3
# 验证
ls -la ~/rootfs/dev/
输出应该是:
crw------- 1 root root 5, 1 Mar 15 10:00 console
crw-rw-rw- 1 root root 1, 3 Mar 15 10:00 null
⚠️ 重要提醒:主设备号和次设备号不能写错。console 是 5,1,null 是 1,3。我曾经有一次把 console 的主设备号写成了 4,结果内核启动后控制台完全没有输出,屏幕一片黑。嗯,排查了半小时才发现是 mknod 参数错了。
4.6 创建过程的自动化脚本
每次手动敲这么多 mkdir 太累了。我建议你写个脚本,以后复用:
#!/bin/bash
# create_rootfs_dirs.sh - 创建根文件系统标准目录
ROOTFS_DIR="${1:-~/rootfs}"
echo "Creating standard directories under ${ROOTFS_DIR}..."
# 核心目录
mkdir -p ${ROOTFS_DIR}/{bin,sbin,etc,lib,dev,proc,sys}
# 扩展目录
mkdir -p ${ROOTFS_DIR}/{tmp,var,run,mnt}
# /usr 子目录
mkdir -p ${ROOTFS_DIR}/usr/{bin,sbin,lib,include,share,local}
# 设备节点
sudo mknod -m 600 ${ROOTFS_DIR}/dev/console c 5 1
sudo mknod -m 666 ${ROOTFS_DIR}/dev/null c 1 3
# 设置 /tmp 权限
chmod 1777 ${ROOTFS_DIR}/tmp
echo "Done. Directory structure created successfully."
保存为 create_rootfs_dirs.sh,然后:
chmod +x create_rootfs_dirs.sh
./create_rootfs_dirs.sh ~/rootfs
4.7 常见问题与避坑
- 目录权限不对:有些程序要求
/tmp可写,权限必须是 777。如果忘了,程序启动时会报 "Permission denied"。 - 设备节点缺失:没有
/dev/console,内核启动后你看不到任何输出。没有/dev/null,很多程序会崩溃。 - /proc 和 /sys 没建:虽然它们是挂载点,但目录必须存在。否则 mount 命令会失败。
- /run 目录被忽略:现在很多系统服务(如 systemd)依赖
/run存放 pid 文件。没有它,服务可能无法正常启动。
💡 我的习惯:每次建完目录后,我会用 tree ~/rootfs 看一眼整体结构。如果没装 tree,用 find ~/rootfs -type d | sort 也行。一目了然,心里踏实。
好,目录结构搭好了。下一步就是往里面填充内容了——把编译好的 busybox、库文件、配置文件一个个放进去。不过那是后面章节的事,咱们先把基础打牢。