BusyBox制作根文件系统

文件系统的特点:
    Linux系统将磁盘、flash等存储设备划分为若干个分区,在不同的分区存放不同类别的文件,与Windows的C盘类似,Linux一样要在一个分区上存放系统启动所必须的文件,比如内核映像文件(在嵌入式系统中,内核一般单独存放在一个分区中)、内核启动后运行的第一个程序(init)、给应用户提供操作界面的shell程序、应用程序所依赖的库等。这些必须的、基本的文件合称为根文件系统,他们存放在一个分区中。Linux系统启动后首先挂接这个分区,称为挂接(mount)根文件系统。其他分区上所有的目录、文件的集合,也称为文件系统。
   Linux以树状结构管理所有目录,文件,其他分区挂接在某个目录上,这个目录被称为挂接点或安装点,然后就可以通过这个目录来访问这个分区上的文件了。比如根文件系统被挂接在根目录"/"上后,在根目录下就有根文件系统的各个目录、文件:/bin、/sbin、/mnt 等;再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录、文件。

      在一个分区上存储文件时,需要遵循一定的格式,这种格式称为文件系统类型,比如ntfs,ext2,yaffs等。除这些拥有实实在在的存储分区的文件系统类型外,Linux还有几种虚拟的文件系统类型,比如proc、sysfs等,他们的文件并不存储在实际的设备上,而是在访问他们是由内核临时生成。

根文件系统目录结构:
1、/bin 目录:
    该目录下存放所有用户都可以使用的、基本的命令。这些命令在挂接其他文件系统之前就可以使用。
2、/sbin目录:
    该目录下存放系统命令,即只有管理员才能使用的命令,系统命令还可以存放在/usr/sbin、/usr/local/sbin 目录下。/sbin目录找那个存放的是基本的系统命令,他们用于启动系统,修复系统等,也是在挂接其他文件系统之前就可以使用/sbin。不是急需使用的系统命令存放在/usr/bin目录下,本地安装的系统命令存放在/usr/local/sbin目录下。
3、/dev目录:
    存放设备文件,可以使用udev机制维护这个目录。
4、/etc目录:
    存放各种配置文件,其下的目录和文件都是可选的,他们依赖于系统中所拥有的应用程序,依赖于这些程序是否需要配置文件。
5、/lib目录:
    存放共享库和可加载模块(即驱动程序),共享库用于启动系统、运行根文件系统中的可执行程序,比如/bin、/sbin目录下的程序。其他不适根文件系统所必须的库文件可以放在其他目录,比如/usr/lib、/var/lib等。
6、/home目录:用户目录,在/home目录下都有一个普通用户名命名的子目录,存放用户相关的配置文件。
7、/root目录:
8、/usr目录:
9、/var目录:
10、/proc目录:
    这是一个空目录,常作为proc文件系统的挂接点,proc文件系统是个虚拟的文件系统,它没有实际的存储设备,里面的目录、文件都是由内核临时生成的,用来表示系统的运行状态,也可以操作其中的文件控制系统。系统启动后,使用以下命令挂接proc文件系统(通常在/etc/fstab进行设置以自动挂接)。
mount -t proc none /proc
11、/mnt目录:
12、/tmp目录:

    一些需要生产临时文件的程序要用到/tmp目录,所以/tmp目录必须存在,并且可以访问。

init进程介绍及用户程序启动过程:
    init进程是由内核启动的第一个(也是唯一的一个)用户进程(进程ID为1),它根据配置文件决定启动哪些程序,比如执行某些脚本、启动shell、运行用户指定的程序等。init进程是后续所有进程的发起者,比如init进程启动/bin/sh程序后,才能够在控制台上输入各种命令。

    init进程的执行程序通常是/sbin/init,上面讲述的init进程的作用只不过是/sbin/init这个程序的功能。我们完全可以编写自己的/sbin/init程序,或者传入命令行参数"init =xxx"指定某个程序作为init程序运行。 通常使用busybox集成的init程序。

busybox init进程的启动子进程:(其源代码在init/init.c文件中)。
    如果存在/etc/inittab文件,busybox init 程序解析它,然后按照他的指示创建各种子进程,否则使用默认的配置创建子进程。
    /etc/inittab 文件中每个条目用来定义一个子进程,并确定他的启动方法,格式如下:
<id>:<runlevels>:<action>:<process>
    对于busybox init进程,上述各个字段作用如下:
1、<id>:表示这个进程要使用的控制台(即标准输入输出错误设备)。如果省略,则使用与init进程一样的控制台。
2、<runlevles>:对于busybox init程序,这个字段没有意义,可以省略。
3、<action>:表示init进程如何控制这个子进程,有8中取值(执行时机)。
sysinit 系统启动后最先执行
wait 执行完sysinit类进程后执行
once
respawn
askfirst
shutdown
restart
4、<process>:要执行的程序,它可以是可执行程序,也可以是脚本。如果<procsee>字段前有"-"字符,这个程序被称为“交互的”。
   
     在/etc/inittab 文件的控制下,init进程的行为总结如下:
 a、在系统启动前期,init进程首先启动<action>为sysinit、wait、once的3类子进程。
 b、在系统正常运行期间,init进程首先启动<action>为respawn、askfirst的两类子进程。
 c、在系统退时,执行<action>为shutdown、restart、ctlatdel的3类子进程(之一或全部)。
 
     如果根文件系统中没有/etc/inittab 文件,busybox init程序将使用如下默认的inittab条目:
 ::sysinit:/etc/init.d/rcS
 ::askfirst:/bin/sh
 tty2::askfirst:/bin/sh
 tty3::askfirst:/bin/sh
 tty4::askfirst:/bin/sh
 ::ctrlaltdel:/sbin/reboot
 ::shutdown:/sbin/swapoff -a
 ::shutdown:/bin/umount -a -r
 ::restart:/sbin/init
 
 /etc/inittab实例:
 放在busybox 的exampes/intitab 文件,创建一个inittab,内容如下:
 
 #/etc/inittab
 #这是init进程启动的第一个子进程,它是一个脚本,可以在里面指定用户想执行的操作
 #比如挂接其他文件系统,配置网络等
 ::sysinit:/etc/init.d/rcS
  #启动shell,以/dev/ttySAC0作为控制台
 ttySAC0::askfirst:-/bin/sh
  #按下Ctrl + Alt +Del 之后执行的程序,不过在串口控制台中无法输入 Ctrl + Alt +Del组合键
 ::ctrlaltdel:/sbin/reboot
 #重启、关机前执行的程序

 ::shutdown:/bin/umount -a -r


移植busybox:
    busybox将众多的UNIX命令集合进一个很小的可执行程序中,其按模块进行设计,可以很容易地加入、去除某些命令,或增减命令的某些选项。使用busybox创建最小根文件系统时,只需要在/dev目录下创建必要的设备节点、在/etc目录下创建一些配置 文件就可以了,如果busybox使用动态连接,还要在/lib目录下包含库文件。 
 
编译、安装busybox:
一、下载,解压busybox:
   tar xjf busybox-1.7.0.tar.bz2
   busybox集合了几百个命令,在一般系统中并不需要全部使用,可以通过配置busybox 来选择这些命令,定制某些命令的功能(选项)、指定busybox的连接方法(动态链接还是静态链接)、指定busybox的安装路径。
二、配置busybox,在busybox-1.7.0目录下执行"make menuconfig"命令即可进入配置界面:
   使用默认配置,执行"make menuconfig"后退出,保存配置即可。
   
   busybox常用配置选项:
   1、busybox的性能微调。
    设置TAB键补全:
    Busybox Settings--->
    Busybox Library Tuning --->
    [*] Tab competion
   2、连接/编译选项。
    指定是否使用静态连接:
    Build Options --->
    [ ] Build BusyBox as a static binary (no shared libs)
    使用glibs时,如果静态编译busybox会提示以下警告信息,表示会出现一些莫名其妙的问题。
    #warning static linking against glibs produces buggy executables
  所以使用动态连接的busybox,在构造根文件系统是需要在/lib目录下方直glibs库文件。
   3、Archival Utilities选项。
        选择tar命令:
    Archival Utilities --->
    [*] tar
   4、Linux Module Utilites选项。
    要使用可加载模块,Linux Module Utilities下面的配置要选上.
    Linux Module Utilities --->
    [*]
    [*]
    ...
   5、Linux System Utilities 选项。
    支持mdev,这可以很方便的构造/dev目录,并且可以支持热拔插设别,另外为方便调试,选中mount、umount命令,并让mount命令支持NFS(网络文件系统)。
    Linux System Utilities --->
    [*] mdev
    [*] Support /etc/mdev.conf
    [*] Support command execution as device addition/removal
    [*] mount
    [*] Supprot mounting NFS file systems
    [*] umount
    [*] umonut -a option
   
   6、Networing Utilities选项
    增加ifconfig命令:
    Networking Utilities --->
    [*] ifconfig
三、编译和安装busybox:
a.修改busybox根目录的Makefile,使用交叉编译器:
修改为:
175 ARCH ?= arm
176 CROSS_COMPILE ?= arm-linux-
b.执行“make”命令编译busybox。
c.安装,执行“make CONFIG_PREFIX = dir_name install ,就可以将busybox安装在dir_name指定的目录下。
    在安装目录下会生成如下文件、目录:(如安装目录/work/nfs_root/fs_mini)
 bin
 linuxrc -> bin/busybox  //(uboot启动参数就是 init=linuxrc)
 sbin
 usr
    其中Linuxrc和上面分析的/sbin/init程序的功能完全一样,其他目录下是各种命令,不过他们都是到/bin/busybox的符号链接,比如  安装目录下的 sbin 目录下/work/nfs_root/fs_mini/sbin的命令:
 halt -> ../bin/busybox
 ifconfig -> ../bin/busybox
 ...

    除bin/busybox外,其他文件都是到bin/busybox的符号链接。

使用glibc库:
    参考制作交叉编译工具链,若已制作交叉编译工具链,则已经生成了glibc库,可以直接使用它来构建根文件系统。
glibc库的组成:
    glibc库的位置是/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib,里面的目录,文件可以分为7类:
 1.加载器ld-2.3.6.so,ld-linux.so.2,动态程序启动前,他们被用来加载动态库。
 2.目标文件(.o)。比如crtl.o crti.o等,在生成应用程序时,这些文件像一般的目标文件一样被连接。
 3.静态库文件(.a)。比如静态数学库libm.a、静态C++库 libstdc++.a等,编译静态程序时会连接他们。
 4.动态库文件(.so、.so.[0-9]*)。他们可能是一个连接文件,编译动态库时会用到这些文件,但是不会连接他们,运行时才连接。
 5.libtool库文件(.la).
 6.ldscripts目录。里面是各种连接脚本,在编译应用程序时,他们被用于指定程序的运行地址、各段的位置等。
 7.其他目录及文件。
 
安装glibc库:
    在开发板上只需啊哟加载器和动态库,假设要构建的根文件系统目录为/work/nfs_root/fs_mini,操作如下:
 $ mkdir -p /work/nfs_root/fs_mini/lib
 $ cd /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib
 $ cp *.so* /work/nfs_root/fs_mini/lib -d
 
    上面复制的库文件不是每一个都会被用到,可以根据应用程序对库的依赖关系保留要用到的,可以通过ldd命令查看一个程序会用到哪些库,主机自带的ldd命令不能查看价差编译出来的程序,有一下两种代替的方法:
 1、如果有uClibc-0.9.28的代码,可以进入utils子目录生成ldd.host工具。
 $ cd uClibc-0.9.28/utils
 $ make ldd.host
然后将生成的ldd.host放到主机/usr/local/bin目录下即可使用。比如对于动态连接的Uusybox,他的库依赖关系如下:
 $ ldd.host busybox
  libcrypt.so.1 => /lib/libcrypt.so.1 (0x00000000)
  libm.so.6 => /lib/libm.so.6 (0x00000000)
  libc.so.6 => /lib/libc.so.6 (0x00000000)
  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
折表示busybox要使用的库文件有libcrypt.so.1 、libm.so.6 、libc.so.6,加载器为/lib/ld-linux.so.2,主机上没有对应的文件没关系,开发板的根文件系统上有就行。
 2、可以使用下面的命令:
 $ arm-linux-readelf -a "your binary" | grep "Shared",
 比如对于动态连接的busybox:

 $ arm-linux-readelf -a ./busybox | grep "Shared"(与上面相比,少了加载器,但要依赖加载器)

构建根文件系统:

    上面两节介绍了编译安装busybox、C库,建立了bin/, sbin/, sur/bin/ ,sur/sbin/, linuxrc,lib/等目录 (busybox安装完的时候就有了bin sbin linuxrc user目录)。
    接下来介绍余下目录的建立。假设开发板根文件系统在主机上的目录为/works/nfs_root/fs_mini。
一、构建etc目录:
    init进程根据/etc/inittab 文件来创建其他子程序,比如调用脚本文件配置IP地址,挂接其他文件系统,最后启动shell等。
   这里要创建3个文件:etc/inittab, etc/init.d/rcS, etc/fstab
   1.创建etc/inittab文件
   在/work/nfs_root/fs_mini/etc 目录下创建一个inittab文件,内容如下:
    # /etc/inittab
    ::sysinit:/etc/init.d/rcS
    ttySAC0::askfirst:-/bin/sh
    ::ctrlaltdel:/sbin/reboot
    ::shutdown:/bin/umount -a -r
   2、创建ect/init.d/rcS文件
   这是一个脚本文件,可以在里面添加想自动执行的命令,以下命令配置IP地址,挂接/etc/fstab指定的文件系统
    #!/bin/sh
    ifconfig eth0 192.168.1.17
    mount -a
   
   第一行表示这是一个脚本文件,运行时使用/bin/sh解析。
   第二行用来配置IP地址。
   第三行挂接/etc/fstab文件指定的所有文件系统。
   要改变这个文件的属性,使它能够执行:
    chmod +x etc/init.d/rcS
   3、创建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
   
   /etc/fstab 文件被用来定义文件系统的静态信息,这些信息被用来控制mount 命令的行为,文件中个字段的意义如下:
   1.device:要挂载的设备
      比如/dev/hda2  /dev/mtdblock1 等设备文件,也可以是其他格式,比如对于proc文件系统,这个字段没有意义,可以是任 意值;对于NFS文件系统,这个字段为<host>:<dir>.
   2.mount-point:挂接点
   3.type:文件系统类型。
      比如proc,jffs2,nfs等,也可以是auto,表示自动检测文件系统类型。
   4.option:挂接参数,以逗号隔开。
   
   /etc/fstab的作用不仅仅是用来控制mount -a 的行为,即使是一般的mount命令也受它控制,其他常用挂接参数:
   
    参数名 说明 默认值
    auto/noauto 决定执行mount-a时是否自动挂接 auto
    user/nouser user:允许普通用户挂接 nouser:只允许root用户挂接       nouser
    exec/noexec 决定是否允许运行所挂接的设备上的程序 exec
    Ro 以只读方式挂接 --
    rw 以读写方式挂接 --
    sync/async 修改文件的时候,是否同步写入设备中 sync
    defaults rw、suid、dev、exec、auto、nouser、async等的组合 --
   
   5、dump和fsck order:用来决定控制dump、fsck程序的行为。
   
   //inittab 调用rcS,rcS里面mount fstab里面的文件系统,inittab 和fstab的内容都是有固定格式的,rcS是脚本。
二、 构建dev目录:
 有两种方法构建dev目录
 1、静态创建设备文件。
 从系统的启动过程可知,涉及的设备文件又:/dev/mtdblock*(MTD块设备)、/dev/ttySAC*(串口设备)、
  /dev/console、/dev/null,只要建立以下设备就可以启动系统。
    $ mkdir -p /work/nfs_root/fs_mini/dev
    $ cd /work/nfs_root/fs_mini/dev
    $ sudo mknod console c 5 1 
    $ sudo mknod null c 1 3
    $ sudo mknod ttySAC0 c 204 64 //一般系统中ttySAC0主设备号为4,但2440 2410中是204
    $ sudo mknod mtdblock0 b 31 0
    $ sudo mknod mtdblock0 b 31 1
    $ sudo mknod mtdblock0 b 31 2
  其他设备文件可以当系统启动后,使用cat /proc/devices 命令查看内核中注册了那些设备,然后一一创建相应的设备文件。
  2、使用mdev创建设备文件。
     mdev是udev的简化版本,它也是通过读取内核信息来创建设别文件。mdev的用途主要有两个:初始化/dev目录、动态更新/dev目录,和热拔插。要使用mdev,需要内核支持sysfs文件系统,为了减少对flash的读写,还要支持tmpfs文件系统。先确保
内核已经设置了CONFIG_SYSFS、CONFIG_TMPFS配置项。
   mdev相关命令:
   mount -t tmpfs mdev /dev  //使用内存文件系统,减少对Flash的读写
   mkdir /dev/pts //devpts用来支持外部网络连接(telnet)的虚拟终端
   mount -t devpts devpts /dev/pts
   mount -t sysfs sysfs /sys //mdev通过sysfs文件系统获得设备信息
   echo /bin/mdev>/proc/sys/kernel/hotplug //设置内核,当有设备拔插时调用/bin/mdev程序
   mdev -s     //在/dev目录下生产内核支持的所有设备的结点
   
    要在内核启动时自动运行mdev,需要修改/work/nfs_root/fs_mini中的两个文件:etc/fstab和etc/init.d/rcS。
    修改etc/fstab添加3个文件系统,使得后面可以自动挂载,即相当自动执行mount -t tmpfs mdev /dev ;
    mount -t devpts devpts /dev/pts;mount -t sysfs sysfs /sys 3条命令。
    添加的内容:
        # device mount-point type options dump fsck order
        tmpfs /tmp tmpfs defaults 0 0
        sysfs /sys sysfs defaults 0 0
        tmpfs /dev tmpfs defaults 0 0
    修改etc/init.d/rcS,加入下面几行,以自动运行他们:
        mount -a
        mkdir /dev/pts
        mount -t devpts devpts /dev/pts
        echo /sbin/mdev > /proc/sys/kernel/hotplug
        mdev -s
    在使用mdev构造dev目录之前,还要建立两个设备文件:dev/console、/dev/null。
    
    构建其他目录:
    其他目录可以是空目录,比如proc、mnt、tmp、sys、root等,创建他们。
    
    这样一个小小的根文件系统就建立好了,开发板可以通过NFS挂接到这里来作为根文件系统启动。如果不想挂接,可以利用这个根文件系统和制作映像文件的工具(如mkyaffsimage)制作一个映像文件,烧写到开发板,作为开发板的根文件系统。

 

猜你喜欢

转载自blog.csdn.net/qq_22863733/article/details/79717601