linux根文件系统制作及VFS/镜像方式挂载实践总结

linux根文件系统制作及VFS/镜像方式挂载实践总结

一、busybox环境

从官网下载最新的busybox-1.33.0.tar.bz2后

第一步:busybox的配置

Busybox make menuconfig

Busybox Settings--->

              Build Options--->

                            [*]Build BusyBox as a static binary(no shared libs)

                           

Busybox Library Tuning--->

              [*]vi-style line editing commands

              [*]Fancy shell prompts

             

Linux Module Utilities--->

              [ ]Simplified modutils

              [*]insmod

              [*]rmmod

              [*]lsmod

              [*]modprobe

              [*]depmod

 

Linux System Utilities--->[*]mdev

              [*]Support /etc/mdev.conf

              [*]Support subdirs/symlinks

              [*]Support regular expressions substitutions when renaming dev

              [*]Support command execution at device addition/removal

              [*]Support loading of firmwares

第二步:编译

make
报错1:
networking/libiproute/ipaddress.c: In function ‘print_addrinfo’:
networking/libiproute/ipaddress.c:333: error: ‘IFA_F_DADFAILED’ undeclared (first use in this function)
networking/libiproute/ipaddress.c:333: error: (Each undeclared identifier is reported only once
networking/libiproute/ipaddress.c:333: error: for each function it appears in.)
make[1]: *** [networking/libiproute/ipaddress.o] Error 1
make: *** [networking/libiproute] Error 2

 

linux根文件系统制作及VFS/镜像方式挂载实践总结

图1

报错2:

==========

libbb/lib.a(inet_common.o): In function `INET6_resolve':

inet_common.c:(.text.INET6_resolve+0x44): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

coreutils/lib.a(mktemp.o): In function `mktemp_main':

mktemp.c:(.text.mktemp_main+0x8c): warning: the use of `mktemp' is dangerous, better use `mkstemp'

networking/lib.a(ipcalc.o): In function `ipcalc_main':

ipcalc.c:(.text.ipcalc_main+0x24c): warning: Using 'gethostbyaddr' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

libbb/lib.a(inet_common.o): In function `INET_resolve':

inet_common.c:(.text.INET_resolve+0x60): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

networking/lib.a(inetd.o): In function `reread_config_file':

inetd.c:(.text.reread_config_file+0x230): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

networking/lib.a(netstat.o): In function `ip_port_str':

netstat.c:(.text.ip_port_str+0x5c): warning: Using 'getservbyport' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

util-linux/lib.a(nsenter.o): In function `nsenter_main':

nsenter.c:(.text.nsenter_main+0x180): undefined reference to `setns'

collect2: ld returned 1 exit status

Note: if build needs additional libraries, put them in CONFIG_EXTRA_LDLIBS.

Example: CONFIG_EXTRA_LDLIBS="pthread dl tirpc audit pam"

make: *** [busybox_unstripped] Error 1

一般是因为交叉工具链与源代码不匹配导致的。 更换更具链或者想办法正面解决,或者如果不用出错的这部分功能去掉这一部分规避即可

 

interface.c:(.text.INET6_input+0x0): undefined reference to `INET6_resolve'

networking/lib.a(interface.o): In function `INET6_sprint':

interface.c:(.text.INET6_sprint+0x20): undefined reference to `INET6_rresolve'

networking/lib.a(interface.o): In function `INET_input':

interface.c:(.text.INET_input+0x4): undefined reference to `INET_resolve'

networking/lib.a(interface.o): In function `INET_sprint':

interface.c:(.text.INET_sprint+0x24): undefined reference to `INET_rresolve'

networking/lib.a(route.o): In function `INET6_displayroutes':

route.c:(.text.INET6_displayroutes+0x154): undefined reference to `INET6_rresolve'

networking/lib.a(route.o): In function `INET6_setroute':

route.c:(.text.INET6_setroute+0x74): undefined reference to `INET6_resolve'

route.c:(.text.INET6_setroute+0x13c): undefined reference to `INET6_resolve'

networking/lib.a(route.o): In function `INET_setroute':

route.c:(.text.INET_setroute+0xc0): undefined reference to `INET_resolve'

route.c:(.text.INET_setroute+0x170): undefined reference to `INET_resolve'

route.c:(.text.INET_setroute+0x1bc): undefined reference to `INET_resolve'

networking/lib.a(route.o): In function `bb_displayroutes':

route.c:(.text.bb_displayroutes+0x124): undefined reference to `INET_rresolve'

route.c:(.text.bb_displayroutes+0x140): undefined reference to `INET_rresolve'

util-linux/lib.a(nsenter.o): In function `nsenter_main':

nsenter.c:(.text.nsenter_main+0x180): undefined reference to `setns'

coreutils/lib.a(sync.o): In function `sync_common':

sync.c:(.text.sync_common+0x30): undefined reference to `syncfs'

/usr/local/arm/arm-2009q3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.1/../../../../arm-none-linux-gnueabi/bin/ld: busybox_unstripped: hidden symbol `INET_resolve' isn't defined

/usr/local/arm/arm-2009q3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.1/../../../../arm-none-linux-gnueabi/bin/ld: final link failed: Nonrepresentable section on output

collect2: ld returned 1 exit status

Note: if build needs additional libraries, put them in CONFIG_EXTRA_LDLIBS.

Example: CONFIG_EXTRA_LDLIBS="pthread dl tirpc audit pam"

make: *** [busybox_unstripped] Error 1

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

linux根文件系统制作及VFS/镜像方式挂载实践总结

然后去busybox的menuconfig找sync,否掉该选项即可

 

在make menuconfig下查找sync所在的目录位置

linux根文件系统制作及VFS/镜像方式挂载实践总结

将该目录下sync由y选择哪个成n即可

 

route.c:(.text.INET6_setroute+0x124): undefined reference to `INET6_resolve'

networking/lib.a(route.o): In function `bb_displayroutes':

route.c:(.text.bb_displayroutes+0x124): undefined reference to `INET_rresolve'

route.c:(.text.bb_displayroutes+0x140): undefined reference to `INET_rresolve'

 

nsenter.c:(.text.nsenter_main+0x180): undefined reference to `setns

根目录下出现黄色的busybox即编译成功

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

第三步:安装

 

默认的安装目录是make menuconfig的options—>下

linux根文件系统制作及VFS/镜像方式挂载实践总结

就是在根目录下_install目录下。

 

之后我们实际要挂载的根文件系统目录不是这个目录,所以我把实际的安装目录改成我自己要用的挂载目录

linux根文件系统制作及VFS/镜像方式挂载实践总结

linux根文件系统制作及VFS/镜像方式挂载实践总结

之后make install

即可在该目录下看到安装后的busybox

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

二.搭建NFS环境

搭建NFS环境:以运行kernel(该kernel编译时需要在menuconfig中选择支持NFS client)的开发板作为客户端,ubuntu主机作为服务器。这里我们使用NFS来挂载rootfs。

 

1.在ubuntu下要搭建配置NFS服务器

sudo apt-get install nfs-kernel-server
sudo apt-get install nfs-common

 

linux根文件系统制作及VFS/镜像方式挂载实践总结

aston@ubuntu:~/rootfs/aston_rootfs$ sudo vi /etc/exports中添加我们自己的根文件系统目录

linux根文件系统制作及VFS/镜像方式挂载实践总结

chmod 777 -R /home/aston/rootfs/aston_rootfs

sudo showmount -e

看到的依然是

Export list for ubuntu:

/root/rootfs *

sudo exportfs -r更新一下根文件系统目录

sudo showmount localhost -e查看根文件系统目录是否是我们添加的

sudo /etc/init.d/nfs-kernel-server restart重启NFS服务器

 

挂载测试
$ mount -t nfs -o nolock localhost:/root/rootfs /mnt

mount -t nfs -o nolock localhost:/home/aston/rootfs/aston_rootfs /opt 我自己将该目录挂载到/opt目录下试试Opt目录下可以看到根文件系统目录下内容,即挂载成功

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

2.保证开发板作为客户端支持NFS client(编译内核前menuconfig的NFS配置):

1、配置网络部分,主要是使能CONFIG_IP_PNP以在2中能够看到Root file system on NFS选项

Networking support

              Networking options

                            TCP/IP networking

                                                        IP: kernel level autoconfiguration

                                                                      [*] IP: DHCP support

                                                                      [*] IP: BOOTP support                                                              

2、配置开启nfs服务

File systems  --->           

              Network File Systems  --->

                            <*> NFS client support

                            [*] NFS client support for NFS version 3                                  [*] NFS client support for the NFSv3 ACL protocol extension

                            [*] NFS client support for NFS version 4 (EXPERIMENTAL)

                            [*] NFS client support for NFSv4.1 (DEVELOPER ONLY)

                            [*] Root file system on NFS 

3.在开发板与ubuntu能够互ping通前提下,uboot中设置如下启动参数(IP根据实际使用更改)

setenv bootargs root=/dev/nfs nfsroot=192.168.0.10:/home/aston/rootfs/aston_rootfs ip=192.168.0.2:192.168.0.10:192.168.0.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200(注意串口几?init的进程1文件夹目录名是否跟根文件系统的进程1文件名一致?其他就是ip地址)

四、挂载实验

内核挂载根文件系统时串口打印如下:****************************************

[    3.191454] VFS: Cannot open root device "nfs" or unknown-block(0,255)

[    3.197637] Please append a correct "root=" boot option; here are the available partitions:

 

root=/dev/nfs,内核不认识nfs导致的,这个是因为该内核在编译前配置menconfig的时候没有选择NFS客户端选项,还是回到1步中配置编译一下内核。通过uboot下tftp方式快速下载编译后的内核验证。

linux根文件系统制作及VFS/镜像方式挂载实践总结

虽然有不断地打印(是因为我们确实没有添加响应文件导致的),但是挂载成功了制作的根文件系统,且成功进入shell下,说明已经达到我们的目的了

linux根文件系统制作及VFS/镜像方式挂载实践总结

图2

五、inittab详解

上述挂载根文件系统后,会找inittab,不存在时,会用busybox源码中默认的inittab,在执行inittab时,找不到指定目录打印的。Busybox中有如下注释:也存在一个默认inintab文件

linux根文件系统制作及VFS/镜像方式挂载实践总结      

1. inittab简单实验

/etc/inittab的工作原理就是被/linuxrc(也就是busybox)执行时所调用起作用,挂载根文件系统成功后,就会调用inittab,并且解析该文本执行相应的动作。

 

//一个典型的inittab文件内容如下。

#first:run the system script file

::sysinit:/etc/init.d/rcS #将/etc/init.d/rcS设置成系统的初始化文件

::askfirst:-/bin/sh  #运行process前,进入shell控制台前,会询问输出.process一执行就进入控

#制台了,类似respawn,只是respawn进入shell前不会有询问输出了。

::ctrlaltdel:-/sbin/reboot

#umount all filesystem

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

#restart init process

::restart:/sbin/init

 

(1)把该文件放置在/etc/目录下

(2)再次启动内核挂载这个rootfs看效果

(3)实验现象是成功启动并且挂载rootfs进入了控制台命令行。当前制作的最小rootfs成功了

linux根文件系统制作及VFS/镜像方式挂载实践总结

2.inittab格式解析

(1)inittab的工作原理就是被/linuxrc(也就是busybox)执行时所调用起作用。

(2)inittab在/etc目录下,所以属于一个运行时配置文件,是文本格式的(内容是由一系列的遵照一个格式组织的字符组成的),实际工作的时候busybox会(按照一定的格式)解析这个inittab文本文件,然后根据解析的内容来决定要怎么工作。

(3)inittab的格式在busybox中定义的,网上可以搜索到详细的格式说明,具体去参考即可:

第一个:#开始的行是注释

第二个:冒号在里面是分隔符,分隔开各个部分。

第三个:inittab内容是以行为单位的,行与行之间没有关联,每行都是一个独立的配置项,每一个配置项表示一个具体的含义。

第四个:每一行的配置项都是由3个冒号分隔开的4个配置值共同确定的。这四个配置值就是id:runlevels:action:process。值得注意得是有些配置值可以空缺,空缺后冒号不能空缺,所以有时候会看到连续2个冒号。

第五个:每一行的配置项中4个配置值中最重要的是action和process,action是一个条件/状态,process是一个可被执行的程序的pathname。合起来的意思就是:当满足action的条件时就会执行process这个程序。

第六个:明白各个action什么意思

该文档中每一行的格式如下:

<id>:<runlevels>:<action>:<process>

id:该字段通常是busybox的init进程来用来寻找controlling tty,也就是终端设备。这个字段的前面会被加上/dev/。在上面的例子中我的终端设备就是/dev/console。

busybox的inittab与pc使用的inittab不同,第一ID并不是随便取名字的,这个名字要与/dev/目录下是否有对应的文件对应

runlevels:该字段被忽略。也就是说,busybox的init不支持运行级别。

action:该字段用于描述后面process的运行方式。在busybox中,有效的action包括如下几种:

    sysinit——在系统启动阶段,后面的process将被执行。在上面例子中,执行rcS脚本。

    respawn——当后面的process进程结束时,该进程又会被重启。

    askfirst——这个类似于上面的respawn,但是在运行process之前,它会打印"Please press Enter to activate this console.",然后等待用户按下Enter来启动该

                     process。通常askfirst是用于启动终端设备的,如果不想看到这个提示,就像我那样使用respawn,而非askfirst.

    wait——init进程会等待该process执行完毕,然后执行下一项。

    once——process只会执行一次。在上面的例子中,执行telnetd守护进程,-l参数表示连接时,使用login登录。同时执行login程序。

    restart——重新启动init进程时执行process.

    ctrlaltdel——当Ctrl+Alt+Del三个键同时按下后,init进程就会收到SIGINT信号,此时运行process。

    shutdown——在系统关机的时候执行process。在上面的例子中,在关机时卸载了所有已挂载的设备。

process:该字段表示要执行的程序和相应的参数。

console::respawn:-/bin/sh

这句表明:/bin/sh在/dev/console这个tty上被执行。“-”表示该shell为 login shell。

 

如果没有inittab文件,init进程将使用默认的行为:
::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::restart:/sbin/init

注意:理解inittab的关键就是明白“当满足action的条件时就会执行process这个程序。” 你去分析busybox的源代码就会发现,busybox最终会进入一个死循环,在这个死循环中去反复检查是否满足各个action的条件,如果某个action的条件满足就会去执行对应的process。

 

六、busybox源代码简单解析

1、Busybox入口函数

1.找busybox入口函数

Uboot,linux内核等复杂的代码是找链接脚本查入口函数,而busybox相当于普通的应用程序,找有效的main函数作为入口。

2.或者soruce insight搜索main

\libb\Appletlib.c中的main应该是入口,其在响应编译目录下生成了Appletlib.o

Applets.c有main,也生成了Applets.o文件但目的是生成可执行文件applet_tables中间可执行文件

linux根文件系统制作及VFS/镜像方式挂载实践总结

Conf.c中有main,但是该目录在scripts目录下,是帮助这套体系运作或者其他用处

Decompress_bunzip2.c用于压缩解压的

还有的main是被条件编译的,未被真正编入。

2.Busybox如何调用各种命令?

busybox有许多xxx_main函数,这些函数每一个对应一个命令的真正入口函数,入ls_main,

linux根文件系统制作及VFS/镜像方式挂载实践总结

各种程序的实现都是指向busybox的,busybox是如何实现一个程序化身万千各自工作的程序的?是main转xxx_main,也就是busybox每次执行时都先执行main,在main函数中识别我们真正要执行的函数(入ls,pwd对应的函数)。 输入各种命令作为argv[0]传给main()的,然后识别执行对应的xxx_main(ls_main,pwd_main).

 

\libb\Appletlib.c中的main()中,

Argv[0]传给run_applet_and_exit()函数,该函数中找到对应的命令(ls ,pwd等)后就调用

Run_applet_no_and_exit()执行。

linux根文件系统制作及VFS/镜像方式挂载实践总结

linux根文件系统制作及VFS/镜像方式挂载实践总结

一个实际命令的调用

Pwd.c中pwd_main(),关键是从xrealloc_xxxx函数中获取出来,再puts()到shell

linux根文件系统制作及VFS/镜像方式挂载实践总结

xrealloc_xxxx函数实际是调用库函数getcwd()实现pwd的

linux根文件系统制作及VFS/镜像方式挂载实践总结

3、inittab解析与执行

(1)inittab的解析是在init.c/init_main函数中

(2)执行逻辑是:先通过parse_inittab函数解析/etc/inittab(解析的重点是将inittab中的各个action和process解析出来),然后后面先直接执行sysinit和wait和once(注意这里只执行一遍),然后在while(1)死循环中去执行respwan和askfirst。

解析:

linux根文件系统制作及VFS/镜像方式挂载实践总结

按照不同的action执行:

linux根文件系统制作及VFS/镜像方式挂载实践总结

4、busybox的体积优势原理

(1)busybox实际上就是把ls、cd、mkdir等很多个linux中常用的shell命令集成在一起了。集成在一起后有一个体积优势:就是busybox程序的大小比busybox中实现的那些命令的大小加起来要小很多。

(2)busybox体系变小的原因主要有2个:

第一个是busybox本身提供的shell命令是阉割版的(busybox中的命令支持的参数选项比发行版中要少,譬如ls在发行版中可以有几十个-x,但是在busybox中只保留了几个常用的选项,不常用的都删除掉了);

第二个是busybox中因为所有的命令的实现代码都在一个程序中实现,而各个命令中有很多代码函数都是通用的(譬如ls和cd、mkdir等命令都会需要去操作目录,因此在busybox中实现目录操作的函数就可以被这些命令共用),共用会降低重复代码出现的次数,从而减少总的代码量和体积。

(3) busybox的体积优势是嵌入式系统本身的要求和特点造成的。

七、rcS文件

在图2中,根文件系统启动时打印了

Can’t run /etc/init.d/rcS:No such file or directory

/etc/init.d/rcS不仅在inittab中有,在busybox源码中也默认写入了Init_main函数中的parse_inittab()中

linux根文件系统制作及VFS/镜像方式挂载实践总结

1.rcS是啥?

0、/etc/init.d/rcS文件是linux的运行时配置文件中最重要的一个,其他的一些配置都是由这个文件引出来的。这个文件可以很复杂也可以很简单,里面可以有很多的配置项。

1.一个简单的rcS文件内容如下

#!/bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin

 

runlevel=S                                 

prevlevel=N

 

umask 022

 

export PATH runlevel prevlevel

 

mount -a

 

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

mdev -s

 

/bin/hostname -F /etc/sysconfig/HOSTNAME

 

ifconfig eth0 192.168.0.5

 

2、rcS文件内容分析

PATH=xxx

(1)首先从shell脚本的语法角度分析,这一行定义了一个变量PATH,值等于后面的字符串

(2)后面用export导出了这个PATH,那么PATH就变成了一个环境变量。

(3)PATH这个环境变量是linux系统内部定义的一个环境变量,含义是操作系统去执行程序时会默认到PATH指定的各个目录下去寻找。如果找不到就认定这个程序不存在,如果找到了就去执行它。将一个可执行程序的目录导出到PATH,可以让我们不带路径来执行这个程序。

(4)rcS中为什么要先导出PATH?就是因为我们希望一旦进入命令行下时,PATH环境变量中就有默认的/bin /sbin /usr/bin /usr/sbin 这几个常见的可执行程序的路径,这样我们进入命令行后就可以ls、cd等直接使用了。

(5)为什么我们的rcS文件还没添加,系统启动就有了PATH中的值?原因在于busybox自己用代码硬编码为我们导出了一些环境变量,其中就有PATH

linux根文件系统制作及VFS/镜像方式挂载实践总结

linux根文件系统制作及VFS/镜像方式挂载实践总结

开发板shell下

linux根文件系统制作及VFS/镜像方式挂载实践总结

Ubuntu shell下

linux根文件系统制作及VFS/镜像方式挂载实践总结

其中PATH环境变量中有交叉编译工具链,是因为我在/etc/profile中添加了

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

Runlevel

runlevel = S #设置系统运行级别为S,即单用户模式,只有一个控制台终端,供“root”帐号做系统维护。

(1)runlevel也是一个shell变量,并且被导出为环境变量。

(2)runlevel这个环境变量到底有什么用?

(3)runlevel=S表示将系统设置为单用户模式

Ubuntu下

linux根文件系统制作及VFS/镜像方式挂载实践总结

这个N如果是数字代表是从哪一个级别切换过来的,N表示没有上一个级别。

linux根文件系统制作及VFS/镜像方式挂载实践总结

Umask

umask 022   #指定当前用户在创建文件时的默认权限
(1)umask是linux的一个命令,作用是设置linux系统的umask值。
(2)umask值决定当前用户在创建文件时的默认权限。

 

mount -a

(1)mount命令是用来挂载文件系统的
(2)mount -a是挂载所有的应该被挂载的文件系统,在busybox中mount -a时busybox会去查找一个文件/etc/fstab文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统(包括了虚拟文件系统)

 

Mdev

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

mdev -s

(1)mdev是udev的嵌入式简化版本,udev/mdev是用来配合linux驱动工作的一个应用层的软件,udev/mdev的工作就是配合linux驱动生成相应的/dev目录下的设备文件。

(2)因为这个问题涉及到驱动,因此详细讲解要等到驱动部分。这里我们只是通过一些直观的现象来初步理解udev/mdev的工作效果。

(3)在rcS文件中没有启动mdev的时候,/dev目录下启动后是空的;在rcS文件中添加上mdev有关的2行配置项后,再次启动系统后发现/dev目录下生成了很多的设备驱动文件。

(4)/dev目录下的设备驱动文件就是mdev生成的,这就是mdev的效果和意义。

 

hostname

(1)hostname是linux中的一个shell命令。命令(hostname xxx)执行后可以用来设置当前系统的主机名为xxx,直接hostname不加参数可以显示当前系统的主机名。

(2)/bin/hostname -F /etc/sysconfig/HOSTNAME -F来指定了一个主机名配置文件(这个文件一般文件名叫hostname或者HOSTNAME),在该文件中添加主机名字

 

ifconfig

  1. 有时候我们希望开机后进入命令行时ip地址就是一个指定的ip地址(譬如192.168.1.30),这时候就可以在rcS文件中ifconfig eth0 192.168.1.30

2.rcS测试实验

(1)跟文件系统下创建/etc/init.d/rcS,并导入配置,重启开发板挂载

linux根文件系统制作及VFS/镜像方式挂载实践总结

修改权限后再次挂载

linux根文件系统制作及VFS/镜像方式挂载实践总结

之后我在ubuntu自制的根文件系统下查看该文件无异常,再在开发板下查看该文件,发现每一行后^M,应该是结尾是win的/r/n导致的,linux下结尾应该仅仅有/n.而ubuntu做了优化,所以在ubuntu下查看该文件无异常。

在ubuntu该文件中:set ff=unix保存退出即可修改为linux行结尾。

重新挂载:

linux根文件系统制作及VFS/镜像方式挂载实践总结

发现已经成功执行rcS. 其他打印是因为暂时未添加这些目录导致的。

  1. mount: can't read '/etc/fstab': No such file or directory

一个标准的/etc/fstab文件内容:

linux根文件系统制作及VFS/镜像方式挂载实践总结

我们将其放入/etc目录后,还要创建对应的mount point目录,重新挂载

linux根文件系统制作及VFS/镜像方式挂载实践总结

忘记创建对应的mount point目录了,创建,重新挂载

linux根文件系统制作及VFS/镜像方式挂载实践总结

在/proc、/dev等目录下都有很多文件,说明挂载成功。

/dev下的设备驱动比较特殊,是由rcS中以下两行生成的

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

mdev -s

linux根文件系统制作及VFS/镜像方式挂载实践总结

3、umask 022

umask测试

①umask是022的时候,默认touch创建一个文件的权限是644

②umask是044的时候,默认touch创建一个文件的权限是622

③umask是444的时候,默认touch创建一个文件的权限是222

总结:umask的规律就是:umask值和默认创建文件的权限值加起来是666.

3、cant open /etc/sysconfig/HOSTNAME这一行打印

根文件系统未添加HOSTNAME时

Ubuntu下:是自己的主机名

linux根文件系统制作及VFS/镜像方式挂载实践总结

开发板下:是开发板配置的ip地址

linux根文件系统制作及VFS/镜像方式挂载实践总结

根文件系统中创建/etc/sysconfig/目录和文件HOSTNAME,并在文件中添加主机名为kyland.重新挂载

linux根文件系统制作及VFS/镜像方式挂载实践总结

发现,虽然无打印,hostname也能显示kyland,但实际并不是类似

“用户名@主机名”格式,没有实际达到效果。 看下面的“八”解决这个问题

3、ifconfig eth0 192.168.0.3

将rcS中ip配置为0.3,挂载后,ubuntu可以ping通开发板

linux根文件系统制作及VFS/镜像方式挂载实践总结

八、profile文件及添加登录认证

上面发现实际虽然添加了/etc/sysconfig/HOSTNAME中的主机名,但实际没达到“用户名@主机名”效果。

profile文件工作原理是:profile文件也是被busybox(init进程)自动调用的,所以是认名字的。

需要填加/etc/profile文件,一个简单的profile文件如下:

linux根文件系统制作及VFS/镜像方式挂载实践总结

添加该文件后,重新挂载,发现主机名已经成功显示,说明profile已经起作用了

linux根文件系统制作及VFS/镜像方式挂载实践总结

但是@前面没有显示用户名,因为我们没有添加用户登录程序

如何看到用户登录界面:

我们之前intttab中有一个配置项 ::askfirst:-/bin/sh,这个配置项作用就是当系统启动后就去执行/bin/sh,执行这个就会出现命令行。因此我们这样的安排就会直接进入命令行而不会出现登录界面。

我们要出现登录界面,就不能直接执行/bin/sh,而应该执行一个负责出现登录界面并且负责管理用户名和密码的一个程序,busybox中也集成了这个程序(就是/bin/login和/sbin/gettty),因此我们要在inittab中用/bin/login或者/sbin/getty去替代/bin/sh。修改之前的initab文件

linux根文件系统制作及VFS/镜像方式挂载实践总结

重新挂载后,发现有登录认证功能,但用户密码不知道,我们并未设置

linux根文件系统制作及VFS/镜像方式挂载实践总结

用户名和密码的设置

  1. 用户名和密码的设置是和登录程序有关联的,但是/bin/login和/sbin/getty在用户名和密码的管理上是一样的。其实常见的所有的linux系统的用户名和密码的管理几乎都是一样的。

(2)密码一般都是用加密文字的,而不是用明文

添加passwd和shadow文件

(1)为什么用户名和密码不对?因为我们根本没有为root用户设置密码。

(2)linux系统中用来描述用户名和密码的文件是passwd和shadow文件,这两个文件都在etc目录下。passwd文件中存储的是用户的密码设置,shadow文件中存储的是加密后的密码。

(3)我们直接复制ubuntu系统中的/etc/passwd和/etc/shadow文件到当前制作的rootfs目录下,然后再做修改即可。

Ubuntu下:/etc/passwd

第一行表示root用户,进入root用户后会进入/root目录,shell脚本是/bin/bash

linux根文件系统制作及VFS/镜像方式挂载实践总结

Ubuntu下:/etc/shadow

第一行表示root用户密码是后面一串红色密文

linux根文件系统制作及VFS/镜像方式挂载实践总结

(4)我们也仿照上述,在自己的根文件系统下添加并修改/etc/passwd和/etc/shadow,我把用户名改成dyz,密码依然用上述root的密文形式,同时在aston_rootfs下创建目录dyz,因为登录认证后我设置的进入这个目录

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

linux根文件系统制作及VFS/镜像方式挂载实践总结

重新挂载根文件系统,输入dyz,root已经可以成功登录进指定目录

linux根文件系统制作及VFS/镜像方式挂载实践总结

(5) 重置密码实践

ubuntu刚装好的时候默认登录是用普通用户登录的,默认root用户是关闭的。普通用户的密码是在装系统的时候设置的,普通用户登陆后可以使用su passwd root给root用户设置密码,设置了密码后root用户才可以登录。

其实这个原因就是root用户在/etc/shadow文件中加密口令是空白的。所以是不能登录的。

busybox中因为没有普通用户,所以做法是:默认root用户如果加密口令是空的则默认无密码直接登录。等我们登陆了之后还是可以用passwd root给root用户设置密码。

我删除/etc/shadow中密码密文,

linux根文件系统制作及VFS/镜像方式挂载实践总结

重新挂载,发现输入用户名,就直接进入系统中

linux根文件系统制作及VFS/镜像方式挂载实践总结

之后也用passwd给用户dyz设置密码,可以在etc/shadow中看到加密的密码密文

linux根文件系统制作及VFS/镜像方式挂载实践总结

平时有时候我们忘记了自己的操作系统的密码,怎么办?有一种解决方法就是用其他系统(WindowsPE系统或者ubuntu的单用户模式等···)来引导启动,启动后挂载到我们的硬盘上,然后找到/etc/shadow文件,去掉密文密码后保存。然后再重启系统后密码就没了。

getty实战

(1) inittab中最常见的用于登录的程序不是/bin/login,反而是/sbin/getty。

(2)这两个的差别不详,但是在busybox中这两个是一样的。这两个其实都是busybox的符号链接而已。因此不用严格区分这两个

(3)我们可以在inittab中用getty替换login程序来实现同样的效果。

linux根文件系统制作及VFS/镜像方式挂载实践总结

九、静态链接与动态链接

1.静态链接编译的可执译的可执行文件在开发板正常运行

ubuntu的我自制的根文件系统目录下创建helloworld.c

linux根文件系统制作及VFS/镜像方式挂载实践总结

linux根文件系统制作及VFS/镜像方式挂载实践总结

之后重新挂载根文件系统,看该可执行文件,能否在开发板上运行

linux根文件系统制作及VFS/镜像方式挂载实践总结

是无法运行的,

①架构不一样,gcc编译的可执行文件是80386架构,在ubuntu上可以执行。我们需要用arm交叉编译工具链编译,才能用于arm开发板上。因为C语言不能跨平台

②这个是动态链接,需要交叉编译动态链接库

为方便编译,我们添加一个Makefile

linux根文件系统制作及VFS/镜像方式挂载实践总结

编译后:动态链接可执行文件小于静态链接可执行文件大小,因为动态链接库是运行阶段才会去找库文件,而静态可执行文件是直接把需要用的库放入可执行文件中

linux根文件系统制作及VFS/镜像方式挂载实践总结

重新挂载:

linux根文件系统制作及VFS/镜像方式挂载实践总结

静态链接的可执行文件正常,但是动态链接的可执行文件无法执行成功,因为动态链接的可执行文件,在运行时需要在当前运行环境中查找,但是没有找到.

解决方案:将arm-linux-gcc的动态链接库文件复制到开发板rootfs的/lib目录下即可解决。

找到并复制动态链接库文件到rootfs中

(1)我们用的arm-2009q3这个交叉编译工具链的动态链接库在/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib目录下。其他的一些交叉编译工具链中动态链接库的目录不一定在这里,要去找一下。找的方法就是find

(2)复制动态链接库到roots/lib目录下。复制时要注意参数用-rdf,主要目的就是符号链接复制过来还是符号链接。

复制命令:cp lib/*so* ~/rootfs/aston_rootfs/lib / -rdf

或者cp -r 整个目录

(3)现在再去测试./hello_dynamic看看是否可以运行,实验结果是可以运行。

linux根文件系统制作及VFS/镜像方式挂载实践总结

2、使用strip工具去掉库中符号信息

动态链接库so文件中包含了调试符号信息,这些符号信息在运行时是没用的(调试时用的),这些符号会占用一定空间。在传统的嵌入式系统中flash空间是有限的,为了节省空间常常把这些符号信息去掉。这样节省空间并且不影响运行。

去掉符号命令:arm-linux-strip *so*

linux根文件系统制作及VFS/镜像方式挂载实践总结

实际操作后发现库文件由3.8M变成了3.0M,节省了0.8M的空间。

重新挂载后,动态链接的可执行程序依然正常运行。

 

十、开机自启动与主流rcS格式

1、修改rcS实现开机自启动

开机会自动执行的脚本rcS中添加上执行某个程序的语句代码即可

2、前台运行与后台运行

(1)程序运行时占用了当前的控制台,因此这个程序不结束我们都无法使用控制台,这就叫前台运行。默认执行程序就是前台运行的。

(2)后台运行就是让这个程序运行,并且同时让出控制台。这时候运行的程序还能照常运行而且还能够不影响当前控制台的使用。

(3)让一个程序后台运行的方法就是 ./xxx &

3、开机装载驱动等其他开机自动执行

4、实际开发中rootfs的rcS是怎样的

(1)我们以X210开发板九鼎科技做的rootfs中rcS部分来分析

(2)分析inittab发现:sysinit执行rcS,shutdown时执行rcK。

linux根文件系统制作及VFS/镜像方式挂载实践总结

分析/etc/init.d/rcS和rcK文件发现,rcS和rcK都是去遍历执行/etc/init.d/目录下的S开头的脚本文件,区别是rcS传参是start,rcK传参是stop。(下面的*代表该文件是可执行文件)

linux根文件系统制作及VFS/镜像方式挂载实践总结

rcS 会将/etc/init.d/目录下S??* (?匹配一个字符,*匹配多个)按照如下规则执行

linux根文件系统制作及VFS/镜像方式挂载实践总结

十一、将制作好的根文件系统做成镜像

1、mke2fs介绍

(1)mke2fs是一个应用程序,在ubuntu中默认是安装了的。这个应用程序就是用来制作ext2、ext3、ext4等格式的根文件系统的。

(2)一般用来制作各种不同格式的rootfs的应用程序的名字都很相似,类似于mkfs.xxx(譬如用来制作ext2格式的rootfs的工具叫mkfs.ext2、用来制作jffs2格式的rootfs的工具就叫mkfs.jffs2)

(3)ubuntu14.04中的mkfs.ext2等都是mke2fs的符号链接而已。

linux根文件系统制作及VFS/镜像方式挂载实践总结

2、将之前通过VFS方式挂载成功的根文件系统做成镜像

(1)先确认根文件系统大小(去除掉源码等无用文件夹),发现总共5.8M.那我们预留10M空间吧。

镜像名为rootfs.ext2,大小:10M(10240个block,每个block是1024byte)

dd if=/dev/zero of=rootfs.ext2 bs=1024 count=10240

linux根文件系统制作及VFS/镜像方式挂载实践总结

linux根文件系统制作及VFS/镜像方式挂载实践总结

  1. losetup /dev/loop1 rootfs.ext2
  2. mke2fs -m 0 /dev/loop1 10240

linux根文件系统制作及VFS/镜像方式挂载实践总结

  1. 将rootfs.ext2挂载到./ext2_rootfs/目录下,方便对镜像文件中内容的添加修改,注意路径 mount -t ext2 /dev/loop1 ../     

在挂载的目录下出现lost+found说明是正常的

linux根文件系统制作及VFS/镜像方式挂载实践总结

  1. 向../中放入制作好的各种镜像文件

linux根文件系统制作及VFS/镜像方式挂载实践总结

发现,我们之前的根文件系统目录~/rootfs/aston_rootfs目录中的内容竟然没了,没法拷贝到~/rootfs下。 看来不能这么搞啊,得在~/rootfs 下新建一个专门用于挂载的目录,这样根文件系统目录~/rootfs/aston_rootfs中内容才能拷贝。

按照类似步骤重新来一遍,做上述命令都在~/rootfs/下执行,之后再拷贝

linux根文件系统制作及VFS/镜像方式挂载实践总结

(6)

卸载掉,

linux根文件系统制作及VFS/镜像方式挂载实践总结需要退出这个挂载的目录,sudo权限再卸载就好了,

umount /dev/loop1

losetup -d /dev/loop1

然后镜像就做好了

linux根文件系统制作及VFS/镜像方式挂载实践总结

  1. 烧录rootfs.ext2到开发板iNand中,启动看现象

将rootfs.ext2放入windows,插上开发板usb线

开发板进入boot输入fastboot,进入fastboot模式

Dos下进入win的fastboot devices看设备是否存在,再烧录

linux根文件系统制作及VFS/镜像方式挂载实践总结

启动后发现,现象跟之前VFS挂载根文件系统的现象一样的

dyz root进入shell

linux根文件系统制作及VFS/镜像方式挂载实践总结

 

 

 

上一篇:linux rootfs.img的制作


下一篇:linux下,一些关于动态库的问题: