上篇文章,使用BusyBox构建了基础的嵌入式Linux系统的根文件系统,基本的功能可以正常运行,但在个基础功能上,还要许多地方需要完善。

[TOC]

1 完善根文件系统

上篇说道,Linux系统运行起来后,可以正常的执行”ls”等基础命令,但仔细观察系统运行后的打印信息,有一条提示

1
can't run '/etc/init.d/rcS': No such file pngor directory 

说是无法运行“/etc/init.d/rcS”这个文件,因为根文件系统(rootfs)里没有这个文件。这个rcS是什么呢?它其实是一个shell脚本, 在Linux内核启动以后,需要启动一些服务, 而rcS就是规定启动哪些文件的脚本文件。

1.1 创建/etc/init.d/rcS文件

在rootfs中创建/etc/init.d/rcS文件(前两级目录不存在,要先创建文件夹,再创建文件),然后在rcS中输入如下所示内容:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh 

PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH

mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

各行含义如下:

  • PATH环境变量:保存着可执行文件可能存在的目录,这样我们在执行一些命令或者可执行文件的时候就不会提示找不到文件这样的错误。
  • LD_LIBRARY_PATH环境变量:保存着库文件所在的目录
  • export命令:用来导出上面这些环境变量,相当于声明一些“全局变量” 。
  • mount命令:用来挂载所有的文件系统,这些文件系统由文件/etc/fstab来指定,所以后续还要创建/etc/fstab文件。
  • mkdir命令创建目录/dev/pts,然后将devpts挂载到/dev/pts目录中。
  • 最后两行使用mdev来管理热插拔设备,通过这两行,Linux内核就可以在/dev目录下自动创建设备节点。

创建好/etc/init.d/rcS后还定要给其可执行权限(chmod 777)。

1.2 创建/etc/fstab文件

上面说道,rcS在挂载所用的文件系统时,这些文件系统由文件/etc/fstab 来指定,所以还要创建/etc/fstab文件。

在rootfs中创建 /etc/fstab文件, fstab在Linux开机以后自动配置哪些需要自动挂载的分区,格式如下:

1
<file system>    <mount point>   <type>    <options>     <dump>    <pass> 
  • <file system>:要挂载的特殊设备,也可以是块设备,比如/dev/sda等
  • <mount point>挂载点
  • <type>文件系统类型,如ext2、ext3、proc、romfs、tmpfs等
  • <options>挂载选项,一般使用默认的defaults(包含了 rw、suid、dev、exec、auto、nouser和async)
  • <dump>:为1表示允许备份,为0不备份一般不备份
  • <pass>磁盘检查设置,为0表示不检查。根目录‘/’设置为 1,其他的分区从2开始。一般不在fstab中挂载根目录,一般设置为0

按照上述格式,在fstab文件中输入如下内容(第1行是注释):

1
2
3
4
#<file system>  <mount point>   <type>  <options>       <dump>  <pass> 
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0

fstab文件创建完成以后,启动开发板,可以看出,启动成功,且没有提示rcS

注:以上两个文件,可以直接在ubuntu的nfs文件中添加,也可以先通过板子的串口连接到nfs后,在串口窗口操作。我是在ubuntu中操作,然后再连接板子启动。

1.3 创建/etc/inittab文件

系统启动已经没有错误提示了,但我们要仍要创建另一个文件/etc/inittab ,这个文件用于busyboxd的初始化,init 程序会读取/etc/inittab这个文件。

inittab由若干条指令组成,每条指令的结构都是以“:”分隔4个段组成,格式如下:

1
<id>:<runlevels>:<action>:<process> 
  • <id>每个指令的标识符,不能重复。但是对于busybox的init 来说,<id>有着特殊意义。对于busybox而言<id>用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控
    制 tty。
  • <runlevels> :对busybox来说此项完全没用,所以空着。
  • <action>:动作,用于指定<process>可能用到的动作。
  • <process> :具体的动作,比如程序、脚本或命令等。

参考busyboxd的examples/inittab文件,来创建一个/etc/inittab,输入如下内容:

1
2
3
4
5
6
7
#etc/inittab 
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
  • 第 2 行:系统启动以后运行 /etc/init.d/rcS这个脚本文件。
  • 第 3 行:将console作为控制台终端,也就是ttymxc0。
  • 第 4 行:重启将运行 /sbin/init
  • 第 5 行:按下ctrl+alt+del组合键的将运行 /sbin/reboot(注:windows系统的串口软件连接开发板,这个命令无效,因为该组合键会被windows系统拦截而执行windows系统的ctrl+alt+del组合键命令)。
  • 第 6 行:关机的时候执行 /bin/umount,也就是卸载各个文件系统
  • 第 7 行:关机的时候执行 /sbin/swapoff,也就是关闭交换分区

注:我在ubuntu上编辑测文件时,console行出现了红色背景块,但似乎也没什么影响

/etc/inittab文件创建好以后就可以重启开发板即可, 至此,根文件系统要创建的文件就已经全部完成了

总结一下刚才创建的目录文件,如下图

2 根文件系统其他功能测试

根文件系统已经完善了,接下来就来继续测试根文件系统是否好用。

2.1 软件运行测试

先来编写一个简单的c语言程序运行一下,验证库文件是否能用

先在ubuntu的rootfs中(可以先创建一个单独的test文件夹用来测试)创建一个hello.c:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(void)
{
while(1)
{
printf("hello world!\r\n"); //打印
sleep(2); //休眠2秒
}
}

然后使用交叉编译链来编译程序:

1
arm-linux-gnueabihf-gcc hello.c -o hello 

编译后会生成名为hello的可执行文件,可以使用“file”命令查看文件类型以及编码格式:

hello是个32位LSB可执行文件,ARM架构的,并且是动态链接的。

在ubunt中编译完后,重启开发板,在开发板的串口中(串口软件),运行hello文件:

程序每隔2秒打印一次,运行正常,说明我根文件系统中的动态库没有问题。按下“ctrl+c”组合键即可中止该程序。

该程序运行起来,会占用交互窗口,可以让hello进入后台运行,方法是在运行软件的时候加上“&”,即:./hello &

注意:程序在后台运行时,交互串口仍是有打印的,只是这时我们可以敲回车键来输入命令了,与程序的输出互不影响,唯一的影响是程序的输出会打断我们的输入,但可以不理会打断,继续输入命令仍是可以执行命令的。

在后台运行的程序,可以使用ps命令来查看各个进程的id,然后使用kill -9 pid(进程 ID)命令来关闭掉当前运行的程序。

如下图,输入ps命令,可以看到hello程序的进程为101,此时先敲回车键,弹出井号提示符,然后输入kill -9 101,再回车,就可以看到hello进程被杀掉了。

2.2 开机自启动测试

玩过单片机的都知道,单片机的程序烧录进去后,上电就自动开始运行了。那linux系统,写了一个程序,可以像单片机那样开机就运行吗,当然是可以的!

实现开机自启动的原理也很简单,linux在启动时,有一个默认的开机启动脚本(/etc/init.d/rcS这个shell文件),因此修改这个脚本,添加自启动相关内容即可:

自启动代码添加完成以后,重启开发板,可以看到hello这个软件已经开机时自动运行了:

2.3 外网连接测试

这里的外网是相对于局域网这个内外而言的,即测试板子是否能访问百度、QQ这样的网站,先使用ping指令来测试一下:

1
2
3
/ # ping qq.com
ping: bad address 'qq.com'
/ #

在网络连接正常的情况下,无法ping通这些网址,是因为缺少域名解析服务,需要配置域名解析服务器的IP地址。

一般域名可以设置为所处网络的网关地址,比如我的局域网的网关是192.168.5.1。

也可以设置为运营商的域名解析服务器地址:114.114.114.114。

在rootfs中新建文件/etc/resolv.conf,然后在里面输入如下内容:

1
2
nameserver 114.114.114.114
nameserver 192.168.5.1

修改保存退出,再次ping一下QQ网站,可以看出ping QQ成功了!

3 结语

至此!根文件系统的完善工作也完成了。

再来看一下本篇对文件都有哪些修改:

linux移植三巨头:uboot、kernel、rootfs已移植完毕,接下来可以将这三部分整体打包一下,方便系统的通用烧写,下篇见~