嵌入式Linux文件系统是指在一个物理设备上的任何文件组织和目录,它构成了Linux系统上所有数据的基础,Linux程序、库、系统文件和用户 文件都驻留其中,因此,它是系统中庞大复杂且又是最为基本和重要的资源。值得提出的是,Linux系统中的文件不仅包括普通的 文件和目录,每个和设备相关的实际实体也都被映射为一个文件,例如磁盘、打印机、终端等等。这样的设备文件又称为特殊文件。所以,Linux下的文件是操作系统服务和设备的简单而又统一的接口,从某种意义上可以说,Linux里的一切事物都是文件。
在嵌入式Linux系统中,嵌入式Linux文件系统的结构是基于树状的,根在顶部,各个目录和文件从树根向下分支。目录树的最顶端被称为根目录(/)。在后面介绍的所构造文件系统结构图(图1)即显示了树状的文件系统。Linux操作系统由一些目录和许多文件组成,例如,图中的/bi n目录包含二进制文件的可执行程序,/sbin目录用于存储管理系统的二进制文件,/etc目录包含绝大部分的Linux系统配置文件 ,/lib目录存储程序运行时使用的共享库,/dev目录包含称为设备文件的特殊文件,/proc目录实际上是一个虚拟文件系统,/tmp目录用于存储程序运行时生成的临时文件,/home目录是用户起始目录的基础目录,/var目录保存要随时改变大小的文件,/usr目录及其子目录对嵌入式Linux系统的操作非常重要,它保存着系统上的一些最重要的程序以及包含你安装的大型软件包。
由于嵌入式设备的一些特殊性,使得嵌入式Linux文件系统除了满足一般文件系统的基本要求外,还有一些自身的特性:
嵌入式Linux文件系统面对的存储介质特殊;嵌入式Linux文件系统有快速恢复的特殊要求;物理文件系统的多样性和动态可装配性;需要嵌入式Linux文件系统具有跨操作平台的安全性;嵌入式Linux文件系统要能满足整个系统的实时性要求。
嵌入式Linux文件系统有安全性和均衡负载这样的要求,而日志型文件系统可以很好地解决安全性的问题。经过几年来的发展。日志型的嵌入式Linux文件系统已成为嵌入式Linux文件系统的主流。
嵌入式Linux 文件系统的设计
● 实验主机和目标平台的连接
实验主机和目标平台的连接有两种方法。一种是以太网连接,这种连接方式可以进行内核文件、根文件系统映像文件的下载。另一种是串口连接,这样的连接方式可以供调试之用。对于以太网连接,作者使用一根普通网线,将实验主机和目标平台都连接在Hub 上。这样做既简单,也不妨碍实验主机与外部网络的通讯。对于串口连接,用一根串口线连接目标平台的Ful Function UART(FFUA RT)串口和实验主机的串口。主要是在调试阶段使用这种连接方式,在目标平台的标准输入还未被驱动的情况下。用实验主机的标准输入控制目标平台,向目标平台发控制命令。
● 构建嵌入式Linux文件系统
首先建立一个文件系统的工作空间。创建目录/bome/work,我们所构造的文件系统就在work这个目录中。建立基本目录,如:bin,dev,etc,lib,mnt,procsbin,tmp,usr,vat,tools具体结构图见图1(图中所显示的文件都是目录文件)。其中,tools是便于开发而创建的目录。因为整个系统要求尽量小,所以应只包含一些必须的二进制程序。而开发过程中需要用到的命令就放在 tools中,将PATH 包含tools即可。/etc目录下只包含了一些启动过程的配置文件,/lib目录下的modules于目录包含了可动态加载到核心的各种模块。另外,目录var下还应创建两个子目录log和run,负责记录系统的日志和运行状态。整个文件系统中除了tmp 和var目录放在SDRAM内以外,其他所有目录都放在Flash中,因为trap和var中的内容需要经常写入,所以放在可读写的RAM里。
插图1: 构建嵌入式Linux文件系统的树状结构
当在目标平台实现了一个嵌入式Linux之后,为了很好地管理操作系统和用户的数据文件,引入了嵌入式Linux文件系统。物理文件系统是JFFS2 ,考虑到扩充物理文件系统的要求,保留了Linux的VFS层次。考虑到存储设备扩充的要求,在Linux内核中加入了对MTD设备的支持。根据上面的叙述,可给出整个文件系统的体系结构图,见图2所示。
插图2: 嵌入式Linux文件系统体系结构
构建嵌入式Linux文件系统最基本的要求就是系统能够在此基础上启动运行起来,电路板克隆所以,/sbin下的init程序必不可少。init程序是引导过程完成后内核运行的第一个程序,它能启动全部其他程序。只要init完成运行全部必要的程序,系统就开始建立并开始运行。当程序开始启动时,init读取一个配置文件inittab,这个文件位于/etc下,它确定了init在启动和关机时的工作特性。在我们开发的这个嵌入式系统中,所有的文件内容只需保留与开发要求有关的必须部分。
这个系统运行单用户模式启动:启动后立即运行rc.sysinit脚本,进行系统初始化动作。rc.sysinit脚本也进行了精简,只保留了以读写的方式重新加载(mount)根文件系统的操作(内核启动时只以只读的方式加载了根文件系统),具体rc.sysinit脚本中的内容 如下:
# Remount the root filesystem read-write
# mount -n -o remount.rw / mount -o remount.rw -n/dev/mtdblock2/mount -a
为了开发过程用户与系统能进行交互,启动了/bin/bash这个命令解释器。用户在键盘上输入某些命令,bash将读取输入加以解析然后执行该程序。/tools中的telnetd和/sbin中的pppd分别是远程登陆和串口通讯的后台程序,加入它们也是为了方便开发。
另外,为了尽量精简内核,程序都以动态链接库文件的方式编译,即当程序运行到所需库文件时才动态加载。所以保证库文件的完整性就显得相当重要。为确保运行各种程序都能在/lib目录中找到合适的库文件,就干脆对/lib中的库文件不作任何删减,而完整的/lib目录(含子目录及全部库文件)也不过2MB 大小。
● 配置嵌入
式Linux文件系统用户
这一步骤的实现,体现了该嵌入式操作系统的一大特色---安全性。pcb抄板为了防止系统中的文件被误改或被恶意破坏,我们设置组和用户,让只有隶属于特定组的特定用户才能对特定的程序进行合法操作。/etc目录中没有列入管理组的group文件和管理用户的pass wd文件,所以在设置文件或目录的所有权时,全部用id号来代替组名和用户名。用chown命令来改变文件的所有权,如chown 0.0 i nittab(前一个“0”代表属组,后一个“0”代表用户),修改后的inittab文件的详细信息为:-rw-r-r-- 1 0 0 237 Jul 26 l0:30 inittab
将系统中所有的文件和目录按照其具体类型和要求,为其设定特定的组和用户对它的所有权。例如,/etc中的module.conf配置文件的所有权是module组和module用户。那么只有组和用户同为module的程序(比如/lib/modules/中的程序)才有权查看module.c onf文件,其他非root用户的程序都打不开这个文件。这样,除了root用户,其他不具有操作权限的用户就不可能对那些特殊文件, 如有关网络、安全等重要信息进行执行和修改。而拥有root用户权限的文件只有init和bash两个。init用于完成系统的初始化过程,并不涉及对其他文件和程序的操作;bash是开发过程中用户与系统交互的需要,便于对文件系统进行修改,开发完成后的实际系统并不需要bash,可删除。这样,各个文件和程序均在自己所属的组和用户中运行,不会互相干扰。使得整个系统有条不紊,不会发生程序越权误操作的现象。保证了操作系统本身的安全性,也让试图窃取或破坏数据的攻击者无机可乘。