1. 实验目的:
(1)熟悉busybox相关知识及应用。
(2)利用busybox制作一个文件系统。
(3)熟悉Linux根文件系统的组织形式。
(4)定制、编译根文件系统。
2. 基础知识介绍:
1)Linux根文件系统目录结构
/bin目录下用来存放所以用户都可以使用的基本命令,该目录必须与根文件系统在同一分区中,常用的命令有:cat、chgrp、chmod、cp、ls、sh、kill、mount、umount、mkdir、mknod等。
/sbin目录用于存放系统命令,只有管理员才能使用,系统命令还可以存放在/usr/sbin、/usr/local/sbin目录下。该目录下常用的目录有:shutdown、reboot、fdisk、fsck等。
/dev目录用于存放设备文件,读写某个设备文件可以操作某个具体硬件。比如通过访问“/dev/ttySAC0”文件可以操作串口0,通过“/dev/mtdblock1”可以访问MTD设备的第二分区。
/etc目录用于存放各种配置文件。
文件 | 描述 |
export | 用来配置NFS文件系统 |
fstab | 用来指明当执行“mount -a”时,需要挂接的文件系统 |
mtab | 用来显示已经加载的文件系统 |
ftpusers | 启动FTP服务时用来配置用户的访问权限 |
group | 用户的组文件 |
inittab | Init进程的配置文件 |
ld.so.conf | 其他共享库的路径 |
passwd | 密码文件 |
/lib目录用于存放共享库和可加载模块(即驱动程序)。共享库是可执行程序不可缺少的。
目录/文件 | 描述 |
libc.so.* | 动态链接C库 |
ld* | 链接器、加载器 |
modules | 内核可加载模块存放的目录 |
/home目录用于存放用户相关的配置文件,每个普通用户,都有一个以用户名命名的子目录。
/usr目录用来存放共享、只读的程序和数据。
目录 | 描述 |
bin | 很多用户命令放在这个目录下 |
include | C程序的头文件,这在PC上进行开发时才用到,在嵌入式系统中不需要 |
lib | 库文件 |
local | 本地目录 |
sbin | 非必需的系统命令 |
share | 架构无关的数据 |
X11R6 | XWINDOW系统 |
games | 游戏 |
src | 源代码 |
/var目录用于存放可变的数据,比如spool目录,log文件、临时文件。
/proc目录常作为proc文件系统的挂接点,proc是个虚拟文件系统,它没有实际的存储设备,里面的目录、文件都是由内核临时生成的,用来表示系统的运行状态。
挂接命令# mount -t proc none /proc(常在/etc/fstab中设置以自动挂接)。
/mnt目录用于临时挂接某个文件系统。
/tmp目录用于存放临时文件,一些需要生成临时文件的程序要用到该目录。
2)Linux文件属性
文件类型 | 描述 | 符号 |
普通文件 | 最常见的文件类型 | - |
目录文件 | 目录也作为一种文件 | d |
字符设备文件 | 用来访问字符设备 | c |
块设备文件 | 用来访问块设备 | d |
FIFO管道 | 用于进程间的通信 | p |
套接字SOCKET | 用于进程间的网络通信 | s |
连接文件 | 它指向一个文件,有软连接、硬连接 | l标识软连接,没有专门的符号表示硬连接,硬连接也是普通文件。ln readme.text ln_hard创建硬连接,ln -s readme.text ln_hard创建软连接。 |
文件的信息:
228883 | -rw-r--r-- | 2 | root | root | 6 | Sep 27 22:10 | readme.txt | ||||||||
文件的索引节点inode | 文件种类和权限 | 硬连接数 | 文件拥有者 | 所属群组 | 文件或目录大小 | 最后访问或修改时间 | 文件名或目录名 | ||||||||
— | r | w | x | r | — | — | r | — | — | ||||||
文件类型 | 文件拥有者权限 | 与所有人同组的用户权限 | 其他用户的权限 |
制作根文件系统就是创建以上目录,并且在里面创建可执行文件、配置文件,比如在/bin、/sbin目录下存放必要的可执行程序,在/etc目录下存放配置文件,在/lib目录下存放库文件。
3)init进程及用户程序启动
Init进程是由内核启动的第一个(也是唯一一个)用户进程(进程ID为1),它根据配置文件觉得启动哪些程序,比如执行某些脚本、启动shell、运行用户指定的程序等。Init进程的执行程序通常是/sbin/init。
static noinline int init_post(void) { if (ramdisk_execute_command) { run_init_process(ramdisk_execute_command); printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command); } if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); } |
4)Busybox init进程
Busybox是一个集成了一百多个最常用的linux命令和工具的软件,相当于是个工具箱,而且该软件只有1M左右。它包含的简单命令有:ls、cat、ehco等,复杂的命令有:grep、find、mount以及telnet。
利用busybox可以创建/bin、/sbin、/usr/bin、/usr/sbin目录下的必要可执行程序、命令。
如果存在/etc/inittab文件,Busybox创建的/sbin/init进程解析它,创建相应的子进程,如果不存在/etc/inittab文件,/sbin/init进程使用默认的配置创建子进程。
Busybox init程序流程
/etc/inittab文件中的每个条目定义一个子进程,格式如下:
<id>:<runlevels>:<action>:<process>
上述各字段的含义:
<id>:表示这个进程使用的控制台:标准输入、标准输出、标准错误,如果省略,则使用与init进程一样的控制台。
<runlevels>:对于Busybox init进程,该字段没有意义,可以省略。
<action>:表示Busybox init进程如何来控制要创建的子进程。
<process>:表示Busybox init要创建的子进程以及用于该进程的命令参数。
3. 编译/安装Busybox1.23.0
1)配置Busybox:Busybox集合了几百个命令,并不是全部都需要,通过配置Busybox来选择需要的命令、指定Busybox的连接方式(动态连接还是静态连接)、指定Busybox的安装路径。
在Busybox1.23.0目录下执行“make menuconfig”命令进入配置界面。使用默认配置即可。
图 2-1Busybox配置界面
2)编译、安装busybox
修改Busybox根目录的Makefile,如下:
ARCH ?= arm CROSS_COMPILE ?= arm-linux- |
然后执行make命令,最后安装,执行“make CONFIG_PREFIX=/home/ckf/fs install”命令(命令格式make CONFIG_PREFIX=dir_path install)。
完成以上操作后,在/home/ckf/fs install目录下生产的文件如图2-2所示:
图2-2 busybox创建的文件
其中linuxrc和/sbin/init程序功能完全一样;其他目录下是各种命令程序,它们都是到/bin/busybox的符号连接。因此在开发板上,运行“ls”和运行“busybox ls”是一样的。
4.使用glibc库来生产lib文件
1)glibc库介绍
glibc库放在/usr/local/arm/4.3.2/lib目录下。
加载器ld-2.3.6.so、ld-linux.so.2:动态程序启动前,它们被用来加载动态库。
‚目标文件.o:比如crt1.o、crti.o、crtn.o等,在生产应用程序时,这些文件像一般的目标文件一样被连接。
ƒ静态库文件.a:比如静态数学库libm.a、静态C++库libstdc++.a等,编译静态程序时会连接它们。
④动态库文件.so、.so[0-9]*:比如动态数学库libm.so、动态C++库libstdc++.so等,它们可能是一个连接文件。编译动态库时会用到这些文件,但是不会连接它们,运行时才连接。
⑤libtool库文件.la:在连接库文件时,这些文件会被用到,比如它们列出了当前库文件所以来的其他库文件,程序运行时无需这些文件。
⑥gconv目录:里面有头字符集的动态库,比如ISO8859-1.so、GB18030so等。
⑦ldscripts目录:里面是各种连接脚本,在编译应用程序时,它们被用于指定程序的运行地址、各段的位置等。
2)安装glibc库
操作如下:
mkdir -p //home/ckf/fs/lib cd //usr/local/arm/4.3.2/lib cp *.so* /home/ckf/fs/lib -d |
至此,在fs文件夹下已经建立了bin/、sbin/、usr/bin/、usr/sbin/、usr/sbin/、lib/等目录,需要接着只要建立剩下的目录。
5.创建剩下的目录及文件
1)创建etc目录及该目录下的文件
Init进程根据/etc/inittab文件来创建其他子进程,比如调用脚本文件配置IP地址、挂接其他文件系统、最后启动shell等。在etc目录下需要创建3个文件:etc/inittab、etc/init.d/rcS、etc/fstab。
仿照Busybox的examples/inittab文件,在/home/ckf/fs 目录下创建etc目录,然后再该目录下创建一个inittab文件,内容如下:
# /etc/inittab ::sysinit:/etc/init.d/rcS ttySAC0::askfirst:-/bin/sh ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r |
‚创建etc/init.d/rcS脚本文件:在里面添加需要自动执行的命令,一下命令配置IP地址,挂接/etc/fstab指定的文件系统。
# !/bin/sh 表示这是一个脚本文件,运行时使用/bin/sh解析 Ifconfig eht0 10.13.62.111 用来配置开发板的IP地址 mount -a 挂接/etc/fstab文件指定的所有文件系统 mkdir /dev/pts mount -t devpts devpts /dev/pts echo /bin/mdev > /proc/sys/kernel/hotplug mdev -s |
ƒ创建etc/fstab文件,表示执行“mount -a”命令后将挂接proc、tmpfs文件系统。
# device mount-point type options dump fsck order proc /proc proc defaults 0 0 tmpfs /tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0 tmpfs /dev tmpfs defaults 0 0 |
device表示要挂接的设备,比如/dev/hda2、/dev/mtdblock1等设备文件;也可以使其他格式,对于proc文件系统这个字段没有意义,可以使任意值;对于NFS文件系统,这个字段为<host>:<dir>。
mount-point表示挂接点。
type:文件系统类型,比如proc、jffs2、yaffs、ext2、nfs等,可以填auto,表示自动检测文件系统类型。
Options表示挂接参数,以逗号隔开。
dump和fsck order分别用来控制dump、fsck程序的行为。
④创建dev目录(使用mdev创建设备文件)
mdev通过读取内核信息来创建设备文件。它的作用主要是:初始化/dev目录、动态更新;还支持热插拔,即插入、卸下设备时执行某些动作。
使用mdev,需呀内核支持sysfs文件系统,为了减少对Flash的读写,还要支持tmpfs文件系统。修改etc/fstab文件自动挂载文件系统、etc/init.d/rcS加入要自动运行的命令。
需要注意:通过mdev生产mdev的/dev目录中,S3C2410、S3C2440是串口名是s3c2410_serial0,需要修改etc/inittab文件。
另外,mdev是通过init进程来启动的,在使用mdev构造/dev目录之前,init进程需要用到设备文件/dev/console、/dev/null。
$ mkdir -p /home/ckf/fs/dev $ cd /home/ckf/fs/dev $ sudo mknod connsole c 5 1 $ sudo mmknod null c 1 3 |
⑤创建其他目录
其他目录可以是空目录,比如proc、mnt、tmp、sys、root等
cd /home/ckf/fs Mkdir proc mnt tmp sys root |
6.制作jffs2映像文件
所谓制作文件系统映像文件,就是将一个目录下的所有内容按照一定的格式存放到一个文件中,该映像文件可以直接烧写到存储设备上。制作不同类型的文件系统映像文件需要使用不同的工具。
$ mkfs.jffs2 -n -s 512 -e 16KiB -d fs -o fs_jffs2 |
7.烧写jffs2映像文件
nfs 0x30000000 10.13.62.122:/opt/nfs/fs.jffs2
nand erase 0x200000 0x800000
nand write.jffs2 0x30000000 0x200000 $(filesize)
set bootargs noinitrd console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2
Saveenv
8.查看已经挂载的文件系统
cat /proc/mounts
查看dev目录。