Linux文件系统是用于管理和存储的一系列的文件的集合。
对于文件系统,功能上设置包含如下内容。
- 系统启动和文件管理有关的程序(init、systemd、ls、cat、cd等)。
- 存储设备信息的文件,以及系统运行相关的设备文件(/sys、/proc等)。
- 支持软件和脚本运行的环境和库(/lib/、/usr/lib)。
- 其它用于进程和系统处理的目录(/tmp、/var、/opt等)。
文件系统基础
对于文件系统,可能接触过的有busybox、buildroot、yocto、openwrt;类似桌面端的Debian、Ubuntu、Armbian、OpenEuler、麒麟等。
回顾构建和使用这些系统的经历,一些问题一直在困扰我?
- 为什么使用这些工具能够构建可用的文件系统,它们实现的原理是什么,为什么按照这些的步骤就可以实现可用的文件系统。
- busybox、buildroot、debian、openwrt等它们是否有什么联系?
在理解以上问题以前,无论是构建文件系统、交叉编译软件,都可以说迷雾重重;在系统的去理解了这个问题之前,虽然构建了各类型的文件系统,仍然时雾里看花,无法建立体系。
那么什么是文件系统呢?这里用一句话解释,文件系统是被内核和应用访问的,由目录和文件构成的树结构的集合体。它设计上是为内核提供可以对外的访问接口,而在Linux中"一切皆文件的思想"指导下,这些接口又以文件的形式展示。
对于大部分系统来说,U-Boot在完成加载Kernel和设备树、传递启动命令行参数后,并跳转执行后,就不在发挥作用;我们日常打交道的就是内核和文件系统。其中内核向上层暴露了一系列文件和接口,其中接口以glibc库的形式进一步封装,方便上层用于管理。在应用中,通过系统调用、库函数等方式访问这些文件和接口,完成对系统的管理和控制。
典型的系统的框架如下所示。

可以看到,文件系统提供系统和应用程序的运行环境;通过glibc库,以及相关文件,实现应用层对于内核的访问。
文件系统目录
基于上节信息说明,就可以将文件系统进一步拆解,主要包含如下结构内容。
- 创建包含系统工作需要的目录
(bin, dev, etc...) - 必须的配置文件和服务,以及权限管理机制
(/etc/profile, /etc/init.d/...) - 运行的必要环境变量和执行程序
(bash, tar...) - 支持上述程序或脚本运行的库
(libc.so, libdrm.so...) - 用户安装的扩展系统功能的程序
(/usr/bin/,/sbin/)。
理解了上述这些,就可以进一步去掌握文件系统各目录的功能,具体如下。
bin: 必须,存放系统执行的必备二进制工具,用于系统启动和快速访问,如bash,cp,mkdir等。boot: 可选,启动目录,存放启动文件;可在系统启动时加载执行,可以不存在。dev: 必须,包含了与硬件设备相关的特殊文件。dev目录下的文件在系统启动时由内核自动创建,这些文件是系统提供的访问内核硬件的接口文件,用于与硬件设备、驱动程序以及其他内核的数据交互。etc: 必须,系统配置文件目录,用于管理系统启动配置项和服务项,如启动脚本,系统服务,网络配置。etc/fstab:定义文件系统的静态信息的文件。它包含了系统中硬盘分区、挂载点、文件系统类型、挂载选项等信息,用于指导系统如何挂载文件系统。etc/hosts:包含了本机或其他主机的IP地址和对应的主机名,以及主机名的别名。etc/passwd:包含用户信息的文件,如用户名,权限以及启动后执行的脚本命令。etc/shadow etc/passwd:影子口令文件,用户密码信息存放在此处,root权限可读。etc/init.d/rc*:启动、或改变运行集执行的脚本文件。
home:根目录,通过adduser创建的自定义用户目录位于此目录下;一般仅特定用户支持的文件和工具也安装在此。lib:必须,用于存放系统所需的共享库文件的目录。这些库文件包含了程序运行时所需要的函数和数据,以便程序能够正确地执行。lib32/lib64:可选,用于存放32位和64位系统所需的共享库文件的目录(有些系统可以全部都在lib目录下)。lost+found:可选,用于存储文件系统中的碎片文件和丢失文件的目录。当文件系统发生错误时,可能会产生一些碎片文件或丢失文件,这些文件通常位于lost+found目录下media:可选,用于挂载可移动存储设备的目录,提供方便,统一的挂载点mnt:可选,mnt目录是一个挂载点,用于临时挂载文件系统。它通常用于挂载外部存储设备或网络文件系统,以便用户可以轻松地访问和操作这些文件系统。opt:可选,用于存放独立的第三方软件包,这些软件包通常不是操作系统的核心组件,提供可选的安装目录。proc:必须,和/dev/类似,不过与设备不同,这里提供应用层操作内核配置和参数的接口(包括硬件),使得用户和应用程序可以通过/proc来查看有关系统硬件、当前正在运行进程的信息,甚至可以更改其中某些文件来改变内核的运行状态。root:必须,root用户的工作目录,存储root用户的个人文件和配置信息。run:可选,是一个临时文件目录,用于存储系统启动以来的信息,重启后,系统会自动删除相关信息。sbin:必须,主要放置了一些系统管理的必备程序。sys:必须,虚拟文件系统目录,也称为sysfs,它提供了对内核对象和设备树的访问。tmp:必须,临时文件存储目录,其作用是为应用程序和用户提供公共的临时文件存储空间,重启后会清除tmp缓存信息。usr: 必须,用户安装的软件和文件,以及系统默认的软件和文件,包含了系统的核心文件和应用程序。var: 可选,包含了在系统运行过程中会改变的文件,这些文件通常包括日志文件、临时文件和缓存文件。
上面是文件系统的目录结构和功能说明,对于Linux用户来说,主要接触的目录为/bin、/usr、/sbin、/lib、/etc目录等配置和管理整个系统,对于嵌入式开发者,还需要关注/dev、/proc、/sys目录用于查看内核系统的状态。
关于rootfs目录的标准定义参考网址: http://www.pathname.com/fhs
文件系统构建说明
文件系统的构建过程,就是创建上述目录,并在对应目录下添加相应文件、库或者程序的过程。也就是说,手动创建这些目录,然后添加文件、库或者程序,也可以构建可用的文件系统。而上面提到文件系统的构建过程,本质上也是实现这些目录和文件的过程;当然方法可能千差万别,既有手动编译构建,也有下载安装。理解了文件系统的本质,那么构建系统和交叉编译的问题就有另外的思路去理解。
构建系统的步骤可以分为如下:
- 完善系统启动必须的动态库;放置在/lib和/usr/lib目录。
- 安装系统启动的必要命令工具,如init,bash(sh), cp, ls等,放置在/bin, /sbin目录
- 创建系统执行的必要配置和服务,主要是启动进程、磁盘管理、用户管理和配置服务等,主要在/etc目录实现。
至此,一个基于命令行的,可命令行访问的最小文件系统构建完成。
busybox构建说明
BusyBox的构建就是基于上述逻辑。不过这样构建的系统只支持最基本的功能,如/etc启动配置,基本shell命令(ls, cd,mv)等。需要支持更多的功能,就需要去找源码单独编译移植,然后将动态库和程序安装到相应的目录中,这就涉及交叉编译的内容。
当然部分复杂的系统会构建服务器端存储已经编译好的程序和库,直接下载即可,apt、yum的原理即是于此。
基于busybox的系统构建仅提供必要的命令工具和文件;系统中需要的目录,动态库和配置文件都需要手动创建或添加。这种方式其实十分麻烦,而且不同版本或库的兼容性问题处理也十分繁杂,只能用于了解系统构建过程,在实践中很少使用。
buildroot构建说明
为了解决这类问题,就有技术人员发起项目;通过脚本工具链,以BusyBox这类方案为基础、集合Linux平台常用工具、配合界面化的管理,实现通过配置命令的方式直接生成打包完整的文件系统,这就是buildroot的框架本质。
当然Buildroot项目支持更加全面,不仅包含以busybox,systemd的基础系统,还支持扩展添加python,lua等软件;通过类似内核Kconfig的图形化配置,Buildroot兼顾了自动化构建和系统完全可裁剪系统的优点,对于低性能嵌入式soc方案,目前就是较优选择。
yocto构建说明
Buildroot是通用的方案,适配大部分的SOC,这也带来了配置的复杂度。对于某个特定的SOC,应用就需要很多适配硬件的配置项的调整,这也是文件构建的痛点和难点。部分厂商参考这个思路,以某个U-Boot和Kernel版本为基础,根据自家平台进一步整理个性化,包含私有的配置和更丰富的软件,然后打包以SDK形式发布,允许用户直接编译使用,Yocto系统就是按照这个思路设计的。
比起Buildroot来说,Yocto更加个性化和专用化,用户可以在修改很少配置项的情况下实现丰富的功能,也是常见的选择。
当然,有些芯片厂商或者方案商也会根据行业的特殊需求定制对应的系统。例如openwrt就服务于软路由实现,自带网络层转发管理和远程Web控制,其内部也集成下载工具,支持通过opkg安装离线和本地软件,是为路由应用专门定制的os系统。
Debian构建说明
BusyBox、Buildroot、Yocto和Openwrt这些文件系统的构建都涉及到环境构建和编译,不仅构建需要耗费大量的时间,而且文件系统的编译也十分依赖系统环境的支持。
在编译过程中,不同版本的系统环境以及库支持往往千差万别,如何解决编译的兼容问题也是构建平台的大麻烦。那么有没有将需要的二进制执行文件,脚本,配置文件压缩后放置在指定地址;用户只需要下载解压,执行安装既可以生成,不需要编译就可以完善系统呢?类似桌面端的Ubuntu使用iso安装,再通过apt更新程序版本;这当然存在,嵌入式Linux端也有同样的解决方案。Debian文件系统就是基于此方法构建的,其中debootstrap可以理解为专用的系统下载和构建工具。
Ubuntu则属于对Debian的进一步整合,包含更多的库和程序。当然也还有其它一些文件系统在Debian或Ubuntu上进一步整合,如Armbian、麒麟、OpenEuler等。虽然构建方式不同,也更加复杂,但仍然属于此类文件系统。
至此,主流文件系统的构建方式讲解完毕;理解了这些,就可以更清晰的构建文件系统,这样就可以更有条理的进行后续文件系统的编译学习。