4、系统配置:System configuration详解、Root filesystem skeleton、自定义/etc/inittab、配置主机名和网络
好,咱们继续往下走。上一章我们把内核和Bootloader搞定了,板子能跑起来了。但你会发现,跑起来之后,系统里啥都没有——没有主机名,没有网络配置,甚至连开机启动的服务都没有。说白了,就是个空壳子。
这一章,我们就来给这个空壳子注入灵魂。我会带你深入Buildroot的System configuration菜单,把根文件系统的骨架、inittab、主机名和网络这些基础配置,一个一个讲透。
4.1 System configuration:藏在菜单里的系统基因
在Buildroot的配置界面里,System configuration这个菜单项,我建议你把它当成系统的「基因编辑室」。你在这里写的每一行配置,都会直接写入最终生成的根文件系统里。
我个人习惯,一上来先改三个东西:
- 系统主机名(System hostname)—— 默认是"buildroot",太没辨识度了
- 欢迎语(System banner)—— 就是登录时看到的那行字
- root密码(Root password)—— 不设密码?生产环境你敢吗?
举个例子,我做过一个工业网关的项目,客户要求每台设备的主机名必须包含MAC地址后四位。我当时就在这个菜单里,配合一个外部的shell脚本,在构建时动态生成主机名。嗯,这个技巧后面会讲到。
核心要点:System configuration里的设置,最终会写入/etc/hostname、/etc/issue、/etc/shadow等文件。你改这里,就等于在改根文件系统的「出厂设置」。
4.2 Root filesystem skeleton:骨架是怎么搭起来的?
你可能会问:Buildroot生成的根文件系统,那些/etc、/bin、/usr目录是从哪来的?答案就是——skeleton(骨架)。
Buildroot自带了一个默认的skeleton,路径在system/skeleton/下面。你可以把它理解成一张「毛坯房」的设计图。里面只有最基本的目录结构和配置文件,比如:
system/skeleton/
├── bin
├── dev
├── etc
│ ├── fstab
│ ├── group
│ ├── hosts
│ ├── inittab
│ ├── passwd
│ └── shadow
├── lib
├── proc
├── sbin
├── sys
├── tmp
└── usr
我在项目中遇到过一种情况:客户要求所有设备的/etc/fstab里,必须预挂载一个特定的NFS共享。如果每次构建完再手动改,那太傻了。我的做法是——自定义skeleton。
具体操作很简单:
- 在项目目录下创建一个自己的skeleton文件夹,比如
board/mycompany/common/skeleton/ - 把Buildroot默认的skeleton复制过来,按需修改
- 在
System configuration菜单里,把Root filesystem skeleton指向你的自定义路径
我的经验:不要直接修改Buildroot自带的skeleton,否则升级版本时会被覆盖。永远用自定义skeleton,这是嵌入式开发的「基本修养」。
4.3 自定义/etc/inittab:让系统按你的节奏启动
聊到/etc/inittab,我得先问一句:你知道系统启动后,第一个用户态进程是谁吗?是init。而init的行为,完全由/etc/inittab控制。
Buildroot默认的inittab长这样:
# 系统初始化
::sysinit:/etc/init.d/rcS
# 启动一个shell在串口上
console::respawn:/sbin/getty -L console 0 vt100
# 按下Ctrl+Alt+Del时重启
::ctrlaltdel:/sbin/reboot
# 关机时执行
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
看起来简单,但坑不少。我曾经在一个项目里,因为忘记在inittab里添加respawn字段,导致串口shell一退出就再也回不来了。你想想看,现场工程师拿着笔记本连上设备,敲了个exit,然后屏幕就黑了...那场面,尴尬不?
所以,我总结了几条inittab的「黄金法则」:
- 串口登录:一定要用
respawn,保证shell挂了能自动重启 - 开机自启脚本:放在
/etc/init.d/rcS里,inittab里用sysinit触发 - 看门狗喂狗:如果硬件有看门狗,建议在inittab里加一个喂狗进程,用
respawn保活
注意:如果你自定义了skeleton,记得把修改后的inittab放进去。否则Buildroot会用默认的,你的改动不会生效。
4.4 配置主机名和网络:让设备有「身份」
主机名这东西,看着不起眼,但少了它,网络服务可能就起不来。比如DHCP客户端,很多时候需要主机名来标识自己。
在Buildroot里配置主机名,有两种方式:
| 方式 | 方法 | 适用场景 |
|---|---|---|
| 静态配置 | 在System configuration里直接填写 | 所有设备用同一个主机名 |
| 动态生成 | 在post-build脚本里修改/etc/hostname |
每台设备需要唯一主机名 |
我比较推荐第二种方式。举个例子,你可以写一个post-build脚本:
#!/bin/bash
# 根据MAC地址生成主机名
MAC=$(cat ${TARGET_DIR}/sys/class/net/eth0/address | tr -d ':')
echo "device-${MAC}" > ${TARGET_DIR}/etc/hostname
然后把这个脚本放到board/mycompany/post-build.sh,在Buildroot的System configuration里指定它。每次构建,主机名都不一样。
网络配置呢?我建议分两步走:
- 开发阶段:用
/etc/network/interfaces配置静态IP,方便调试 - 量产阶段:默认用DHCP,或者通过uboot传参动态设置
Buildroot默认的网络配置在/etc/network/interfaces里,你可以通过自定义skeleton来修改它。比如:
# 配置eth0为静态IP
auto eth0
iface eth0 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
避坑指南:我曾经在配置网络时,忘了在Buildroot里开启ifupdown软件包。结果interfaces文件写好了,系统启动后网络根本没起来。检查一下BR2_PACKAGE_IFUPDOWN有没有选上。
好了,这一章的内容就这些。系统配置、skeleton、inittab、主机名和网络,这几块是Buildroot构建嵌入式系统的「地基」。地基打牢了,后面加什么软件包都不慌。
下一章,我们会聊到Filesystem images——怎么把根文件系统打包成你想要的格式。到时候见。