busybox

有 了 LILO 和 kernel p_w_picpath 之后,接下来,我们要安排 root 文件系统。由于 flash 盘的空间只有 16M 字节,可以说,这是对我们最大的挑战。这里首先要向大家介绍小型嵌入式 Linux 系统安排 root 文件系统时的一个常用的利器:BusyBox。

Busybox 是 Debian GNU/Linux 的大名鼎鼎的 Bruce Perens 首先开发,使用在 Debian 的安装程序中。后来又有许多 Debian developers 贡献力量,这其中尤推 busybox 目前的维护者 Erik Andersen,他患有×××,可是却是一名优秀的自由软件开发者。

Busybox 编译出一个单个的独立执行程序,就叫做 busybox。但是它可以根据配置,执行 ash shell 的功能,以及几十个各种小应用程序的功能。这其中包括有一个迷你的 vi 编辑器,系统不可或缺的 /sbin/init 程序,以及其他诸如 sed, ifconfig, halt, reboot, mkdir, mount, ln, ls, echo, cat ... 等等这些都是一个正常的系统上必不可少的,但是如果我们把这些程序的原件拿过来的话,它们的体积加在一起,让人吃不消。可是 busybox 有全部的这么多功能,大小也不过 100K 左右。而且,用户还可以根据自己的需要,决定到底要在 busybox 中编译进哪几个应用程序的功能。这样的话,busybox 的体积就可以进一步缩小了。

使用 busybox 也很简单。只要建一个符号链接,比方 ln -s /bin/busybox /bin/ls,那么,执行 /bin/ls 的时候,busybox 就会执行 ls 的功能,也会按照 ls 的方式处理命令行参数。又比如 ln -s /bin/busybox /sbin/init,这样我们就有了系统运行不可或缺的 /sbin/init 程序了。当然,这里的前提是,你在 busybox 中编译进去了这两个程序的功能。

这里面要提出注意的一点是,busybox 的 init 程序所认识的 /etc/inittab 的格式非常简单,而且和常规的 inittab 文件的格式不一样。所以读者朋友们在为这个 busybox 的 init 写 inittab 的时候,要注意一下不同的语法。至于细节,就不在我们这里多说了,请大家参考 Busybox 的用户手册。

 


 

 

从启动到进入 shell

busybox 安装好以后,我们就可以考虑重新启动,一直到进入 shell 提示符了。这之前,我们要准备一下 /etc 目录下的几个重要的文件,而且要把 busybox 用到的 library 也拷贝过来。

用 ldd 命令,后面跟要分析的二进制程序的路径名,就可以知道一个二进制程序,或者是一个 library 文件之间的互相依赖关系,比如 busybox 就依赖于 libc.so 和 ld-linux.so ,我们有了这些知识,就可把动手把所有需要的 library 拷贝到 flash 盘上。由于我们的 flash 盘说大不大,说小倒也不小,有 16M 字节之多。我们直接就用 Glibc 的文件也没有太多问题。如果读者朋友们有特殊的需要,觉得 Glibc 太庞大了的话,可以考虑用 uClibc,这是一个非常小巧的 libc 库,功能当然没有 Glibc 全,但是足够一个嵌入式系统使用了。本文就不再介绍 uClibc 了。

库程序拷贝过来以 后,我们就可以考虑系统启动的步骤了。启动的时候,先是 lilo,接下来就是 kernel,kernel 初始化之后,就调用 /sbin/init,然后由 init 解释 /etc/inittab 运行各种各样的东西。inittab 会指导 init 去调用一个最重要的系统初始化程序 /etc/init.d/rcS,我们将要在 rcS 中完成各个文件系统的 mount,此外,还有在 rcS 中调用 dhcp 程序,把网络架起来。rcS 执行完了以后,init 就会在一个 console 上,按照 inittab 的指示开一个 shell,或者是开 getty + login,这样用户就会看到提示输入用户名的提示符。我们这里为了简单起见,先直接进入 shell,然后等到调试成功以后,再改成直接进入 X Window。

关于 inittab 的语法,我们上面已经提到过了,希望读者朋友们去查权威的 busybox 的用户手册。这里,我们先要讲一下文件系统的构成情况。

 


 

 

安排文件系统

大 家已经看到,我们的 root 文件系统为了避免麻烦,用的是标准的 ext2 文件系统。由于我们的硬盘空间很小,只有不到 16M,而且我们还要在上面放上 X Window,所以,如果我们全部用 ext2 的话,Flash 盘的有限空间会很快耗尽。我们唯一的选择是采用一个适当的压缩文件系统。考虑到 /usr 目录下面的内容在系统运行的时候,是不需要被改写的。我们决定选择只读的压缩文件系统 cramfs 来容纳 /usr 目录下面的全部内容。

cramfs 是 Linus Torvalds 本人开发的一个适用于嵌入式系统的小文件系统。由于它是只读的,所以,虽然它采取了 zlib 做压缩,但是它还是可以做到高效的随机读取。既然 cramfs 不会影响系统读取文件的速度,又是一个高度压缩的文件系统,对于我们,它就是一个相当不错的选择了。

我们首先把 /usr 目录下的全部内容制成一个 cramfs 的 p_w_picpath 文件。这可以用 mkcramfs 命令完成。得到了这个 usr.img 文件之后,我们还要考虑怎样才能在系统运行的时候,把这个 p_w_picpath 文件 mount 上来,成为一个可用的文件系统。由于这个 p_w_picpath 文件不是一个通常意义上的 block 设备,我们必须采用 loopback 设备来完成这一任务。具体说来,就是在前面提到的 /etc/init.d/rcS 脚本的前面部分,加上一行 mount 命令:

mount -o loop -t cramfs /usr.img /usr

 

这样,就可以经由 loopback 设备,把 usr.img 这个 cramfs 的 p_w_picpath 文件 mount 到 /usr 目录上去了。哦,对了,由于要用到 loopback 设备,读者朋友们在编译内核的时候,别忘了加入内核对这个设备的支持。对于系统今后的运行来说,这个 mount 的效果是透明的。cramfs 的压缩效率一般都能达到将近 50%,而我们的系统上绝大部分的内容是位于 /usr 目录下面,这样一来,原本可能要用到 18M 的 Flash 盘,现在可能只需要 11M 就可以了。一个 14M 的 /usr 目录,给压缩成了仅仅 7M。

上面考虑了压缩问题,下 面还要考虑到,Flash 盘毕竟不像普通硬盘,多次的擦写毕竟不太好,所以我们考虑,在需要多次擦写的地方,使用内存来做。这个任务,我们考虑用 tmpfs 来完成。至于 tmpfs 和经典的 ramdisk 的比较,我们这里就不多说了。一般说来,tmpfs 更加灵活一些,tmpfs 的大小不像 ramdisk,可以顺着用户的需要增长或者缩小。我们选择把 /tmp、/var 等几个目录做成 tmpfs。这只需要我们在 /etc/fstab 里面加上两行类似下面的文字就可以了:

none /var tmpfs default 0 0

 

然后别忘了在 /etc/init.d/rcS 里面靠近开头的地方,加上 mount -a。这样,就可以把 /etc/fstab 里面指定的所有的文件系统都 mount 上来了。

 


 

 

X Window

进 行到这里,读者朋友们可能会以为,X Window 的安装可能会很复杂。其实不然,由于我们上面的架子搭好了,X Window 的安装非常简单,只需要把几个关键的程序拷贝过来就可以了。一般说来,只需要 /usr/X11R6 目录下面的 bin 和 lib 两个目录。然后,根据用户各自的需要,还可以做大幅的裁减。比如,如果你的局域网上有一个开放的 xfs 字体服务器的话,你可以把所有本地的字体都删掉,而使用远端的字体服务器。如果只需要运行有限的程序,别忘了把没有用的 library 都删掉。此外,还可以把多余的 X Window 的 driver 都删掉,只保留本机的显示卡所需要的 driver 就可以了。

当然,这一关免不了要做多次测试。

 


 

 

其它技巧

如果你的工作系统式在另外一台机器上,通过局域网和本机互联的话,ssh 是一个不错的工具。此外,ssh 中带的 scp 用起来和普通的 cp 拷贝程序差不多,非常方便。用 ssh 和 scp 来共享文件,远程试验,你就可以不需要在办公室里跑来跑去的了。

如果你需要一个 MS Windows 上运行的 X Server 和 xfs 字体服务器,可以考虑包括在 Red Hat 的 Cygwin 工具箱中的 XFree86 系统。