根文件系统构建
根文件系统定义
根文件系统首先是内核启动时所 mount(挂载)的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。
根文件系统是 Linux 内核启动以后挂载(mount)的第一个文件系统,然后从根文件系统中读取初始化脚本,比如 rcS, inittab 等。根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的,必须要搭配根文件系统。
常用子目录
目录 | 含义 |
---|---|
/bin | 存放可执行文件一般都是命令 |
/dev | 设备文件 |
/etc | 各种配置文件 |
/lib | linux所需的必备库文件(共享库) |
/mnt | 临时挂载目录(一般为空) |
/proc | 作为 proc 文件系统的挂载点(文件是临时存在的,一般存储系统运行信息文件) |
/usr | Unix 操作系统软件资源目录 |
/var | 存放一些可以改变的数据 |
/sbin | 此目录页用户存放一些可执行文件 |
/sys | 此目录作为 sysfs 文件系统的挂载点 |
/opt | 可选的文件、软件存放区(用户选择放哪些) |
BusyBox构建根文件系统
顶层Makefile修改
1 | 164 CROSS_COMPILE ?= /usr/local/arm/gcc/bin/arm-linux-gnueabihf- |
修改busybox支持中文字符
打开/libbb/printable_string.c
1 | 12 const char* FAST_FUNC printable_string(uni_stat_t *stats, const char |
接着打开文件 busybox-1.29.0/libbb/unicode.c
1 | 1003 static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags) |
配置busybox
要先对 busybox 进行默认的配置,有以下几种配置选项:
①defconfig,缺省配置,也就是默认配置选项。
②allyesconfig,全选配置,也就是选中 busybox 的所有功能。
③allnoconfig,最小配置。
也可以图形化配置
1 | make menuconfig |
配置路径:
1 | Location: |
这个选项不选。
选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大。动态编译的话要求根文件系统中有库文件,但是编译出来的 busybox 会小很多。不能采用静态编译!因为采用静态编译的话 DNS 会出问题!无法进行域名解析 。
继续配置,选上。
1 | Location: |
1 | Location: |
不选simplified modutils
1 | Location: |
最后使能busybox的unicode编码支持中文:
1 | Location: |
编译busybox
要将编译结果存放到前面创建的 rootfs 目录中
1 | make install CONFIG_PREFIX=/home/moss/linux/nfs/rootfs |
busybox 的工作就完成了,但是此时的根文件系统还不能使用,还需要一些其他的文件,我们继续来完善 rootfs。
向根文件系统添加 lib 库
Linux 中的应用程序一般都是需要动态库的 。所以在rootfs中创建一个lib文件夹。
1 | mkdir lib |
库文件从哪里来呢? lib 库文件从交叉编译器中获取,前面我们搭建交叉编译环境的时候将交叉编译器存放到了“/usr/local/arm/”目录中。
进入对应路径的目录:
1 | cd /usr/local/arm/gcc/arm-linux-gnueabihf/libc/lib |
此目录下有很多的* so*(*是通配符)和.a 文件,这些就是库文件,将此目录下所有的so*和.a文件都拷贝到 rootfs/lib 目录中,拷贝命令如下:
1 | cp *so* *.a /home/moss/linux/nfs/rootfs/lib/ -d |
后面的“-d”表示拷贝符号链接,这里有个比较特殊的库文件: ld-linux-armhf.so.3,此库文件也是个符号链接,
要把它变成本身的文件。
1 | rm ld-linux-armhf.so.3 |
然 后 重 进 入 到 /usr/local/arm/gcc/armlinux-gnueabihf/libc/lib 目录中,重新拷贝 ld-linux-armhf.so.3,命令:
1 | cp ld-linux-armhf.so.3 /home/moss/linux/nfs/rootfs/lib/ |
继续进入如下目录中:
1 | cd /usr/local/arm/gcc/arm-linux-gnueabihf/libc/lib |
向rootfs的usr/lib目录添加库文件
在 rootfs 的 usr 目录下创建一个名为 lib 的目录 ,之前arm-linux-gnueabihf/usr/lib的so和.a库文件复制到rootfs/usr/lib目录中
1 | cp *so* *.a /home/moss/linux/nfs/rootfs/usr/lib/ -d |
在根文件系统中创建其他文件夹,如 dev、 proc、 mnt、 sys、 tmp 和 root 等 .
初步测试根文件系统
首先使用nfs挂载根文件系统,首先熟悉bootargs环境变量的root值的格式:
1 | root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gwip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip> |
1 | setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.115: |
完善根文件系统
Linux 内核启动以后需要启动一些服务,而 rcS 就是规定启动哪些文件的脚本文件。在 rootfs 中创建/etc/init.d/rcS 文件
1 | 1 #!/bin/sh |
第 1 行,表示这是一个 shell 脚本。
第 3 行, PATH 环境变量保存着可执行文件可能存在的目录,这样我们在执行一些命令或者可执行文件的时候就不会提示找不到文件这样的错误。
第 4 行, LD_LIBRARY_PATH 环境变量保存着库文件所在的目录。
第 5 行,使用 export 来导出上面这些环境变量,相当于声明一些“全局变量”。
第 7 行,使用 mount 命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab 来指定,所以我们一会还要创建/etc/fstab 文件。
第 8 和 9 行,创建目录/dev/pts,然后将 devpts 挂载到/dev/pts 目录中。
第 11 和 12 行,使用 mdev 来管理热插拔设备,通过这两行, Linux 内核就可以在/dev 目录下自动创建设备节点。
使用chmod给予/ec/init.d/rcS 可执行权限
创建/etc/fstab 文件
fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区,格式如下:
1 | <file system> <mount point> <type> <options> <dump> <pass> |
defaults 包含了 rw、 suid、 dev、 exec、 auto、 nouser 和 async。
fstab 中挂载根目录,因此这里一般设置为 0。
1 | #<file system> <mount point> <type> <options> <dump> <pass> |
创建/etc/inittab 文件
init 程序会读取/etc/inittab这个文件, inittab 由若干条指令组成。每条指令的结构都是一样的,由以“:”分隔的 4 个段组成,格式如下:
1 | <id>:<runlevels>:<action>:<process> |
1 | 示例代码 38.4.3.1 /etc/inittab 文件 |
第 2 行,系统启动以后运行/etc/init.d/rcS 这个脚本文件。
第 3 行,将 console 作为控制台终端,也就是 ttymxc0。
第 4 行,重启的话运行/sbin/init。
第 5 行,按下 ctrl+alt+del 组合键的话就运行/sbin/reboot,看来 ctrl+alt+del 组合键用于重启系统。
第 6 行,关机的时候执行/bin/umount,也就是卸载各个文件系统。
第 7 行,关机的时候执行/sbin/swapoff,也就是关闭交换分区。