脚本宝典收集整理的这篇文章主要介绍了rootfs -根文件系统制作,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
本文记录了根文件系统的一些知识点,Busybox 工具的使用和 最小根文件系统的制作。
根文件系统是特殊用途的文件系统,必须属于某种文件系统格式。那么文件系统是用来干嘛的?
镜像文件形式
文件夹形式
总结
镜像文件形式的根文件系统主要目的是用来烧录到块设备上,设备上的内核启动后去挂载它。镜像文件形式的根文件系统是由文件夹形式的根文件系统使用专用的镜像制作工具制作而成的。
最初在开发主机中随便 mkdir 创建了一个空文件夹,然后向其中添加一些必要的文件(包括etc 目录下的运行时配置文件、/bin 等目录下的可执行程序、 /lib 目录下的库文件等···)后就形成了一个文件夹形式的 rootfs。 然后这个文件夹形式的 rootfs 可以被 kernel 通过 nfs 方式来远程挂载使用,但是不能用来烧录块设备。我们为了将这个 rootfs 烧录到块设备中,于是用一些专用的软件工具,将其制作成可供烧录的一定格式的根文件系统镜像。
文件夹形式的 rootfs 是没有格式的,制作成镜像后就有了一定的 rootfs 格式了, 格式是由我们的镜像制作过程和制作工具来决定的。 每一种格式的镜像制作工具的用法都不同。
busybox是一个C语言写出来的项目,里面包含了很多.c文件和.h文件。
busybox 这个程序开发出来就是为了在嵌入式环境下构建根文件系统(以下简称 rootfs)使用的,也就是说他就是专门开发的 init 进程应用程序。
busybox 为当前系统提供了一整套的 shell 命令程序集。譬如 vi、cd、mkdir、ls 等。在桌面版的 linux 发行版(譬如 ubuntu、redhat等)中 vi、cd、ls 等都是一个一个的单独的应用程序。但是在嵌入式 linux 中,为了省事我们把 vi、cd 等所有常用的 shell 命令集合到一起构成了一个 shell 命令包,起名叫 busybox。
Busybox 在编写过程中对文件大小进行了优化,并考虑了系统资源有限(比如内存等)的情况。与一般的 GNU 工具集动辄几 M 的体积相比,动态链接的 Busybox 只有几百 K,即使是采用静态链接也只有1 M 左右。Busybox 按模块设计,可以很容易地加入、去除某些命令,或增减命令的某些选项。
VFS 是 linux 内核的一种设计理念、设计机制。全拼 vitrual file system,叫虚拟文件系统。
具体的一些文件系统如 FAT、 NTFS、 ext2、 ext3、 jffs2、 yaffs2、 ubi 等主要设计目的是为了管理块设备(硬盘、 Nand···)
VFS 是借鉴了文件系统的设计理念(通过文件系统将底层难以管理的物理磁盘扇区式访问,转换成目录 + 文件名的方式来访问),将硬件设备的访问也虚拟化成了对目录 + 文件的访问。所以有了 VFS 后我们可以通过设备文件(如/dev/mmcblk0p2) 的方式来访问系统中的硬件设备。
VFS 将对硬件设备的访问和对普通文件的访问给接口统一化了(linux 中一切皆是文件)。VFS 成了一个隔离层,隔离了下层的不同文件系统的差异性,对上层应用提供一个统一的接口。
VFS 将不同文件系统和下层硬件设备(块设备)驱动之间的细节也给屏蔽了。不同类型的文件系统在本身设计时是 不用考虑各种不同的硬件设备的具体操作差异的,这里有一个类似于 VFS 的设计理念。
VFS 机制和 rootfs 挂载与其他文件系统的挂载都是有关联的。内核中有一些 sys proc 这种虚拟文件系统,也是和 VFS 机制有关。 /dev/目录下的设备文件都和 VFS 有关。
目录 | |
---|---|
applets | 主要是实现applets框架的文件 |
applets_sh | 一些有用的脚本,例如:dos2unix、unix2dos等 |
archival | 与压缩有关的命令源文件,例如:bzip2、gzip等 |
configs | 自带的一些默认配置文件 |
console-tools | 与控制台相关的一些命令,例如:setconsole |
coreutils | 常用的核心命令,例如:cat、rm等 |
editors | 常用的编辑命令,例如:vi、diff等 |
findutils | 用于查找的命令,例如:find、grep等 |
init | init进程的实现源文件 |
networking | 与网络相关的命令,例如:telnetl、arp等 |
shell | 与shell相关的实现,例如:ash、msh等 |
util-linux | Linux下常用的命令,主要是与文件系统相关的,例如:mkfs_ext2等 |
Busybox Settings ---> # BusyBox的通用配置,一般采用默认值即可。
Archival Utilities ---> # 压缩、解压缩相关工具。
Coreutils ---> # 最基本的命令,如cat、cp、ls等。
Console Utilities ---> # 控制台相关命令。
Debian Utilities ---> # Debian操作系统相关命令。
Editors ---> # 编辑工具,如vi、awk、sed等。
Finding Utilities ---> # 查找工具,如find、grep、xargs。
Init Utilities ---> # BusyBox init相关命令。
Login/Password Management Utilities ---> # 登陆、用户账号/密码等方面的命令。
Linux Ext2 FS Progs ---> # ext2文件系统的一些工具。
Linux Module Utilities ---> # 加载/卸载模块等相关的命令。
Linux System Utilities ---> # 一些系统命令。
Miscellaneous Utilities ---> # 一些不好分类的命令,如crond、crontab。
Networking Utilities ---> # 网络相关的命令和工具。
Print Utilities ---> # print spool服务及相关工具。
Mail Utilities ---> # mail相关命令。
Process Utilities ---> # 进程相关命令,如ps、kill等。
Runit Utilities ---> # runit程序。
Shells ---> # shell程序。
System Logging Utilities ---> # 系统日志相关工具,如syslogd、klogd。
解压 Busybox 源码后,进入 Busybox 目录,打开图像界面配置菜单:
make menuconfig
进入配置菜单后,进行相关配置。我们可以静态或者动态编译Busybox,选择动态编译,使得Busybox可执行文件更小,选项开关如下:
[ ] Build BusyBox as a static binary (no shared libs)
经过上诉步骤之后,这个时候选择配置界面的 Exit 退出,保存刚刚的配置,之后就可以看到在源代码目录下多了一个 .config 文件。.config 配置文件里面的内容记录了我们刚刚选中的功能。如下所示:
CONFIG_PLATFORM_LINUX=y
每一个都是名值对的形式,名称是一个环境变量,后面的值如果为 Y 代表选中,注释行代表裁减掉的功能。
开始编译并安装
make
make install
生成的文件将默认安装到目录 _install。
BusyBox 编译成功后,在 目录 _install 下可以看到生成的 文件,我们可以继续添加文件,做成一个最小根文件系统。或是直接操作 Busybox 这个可执行文件,用法如下:
./BusyBox 命令 [参数]
其中 命令 是编译 BusyBox 时选中的命令,用法同 Linux 下的命令,只是加上 ./BusyBox 。比如我们在编译时选中的 flashcp 命令,编译成功后,我们把 BusyBox 放到开发板中,就可以直接使用新加入的 flashcp 命令了,而不用重新编译和烧录根文件系统到开发板中:
./BusyBox flashcp /tmp/nfs/usr.sqsh4 /dev/mtd7
inittab 被 /linuxrc(也就是 busybox)执行时所调用而起作用。存放在/etc 目录下,属于一个运行时配置文件,是文本格式的。实际工作的时候 busybox 会(按照一定的格式)解析这个 inittab文本文件,然后根据解析的内容来决定要怎么工作。inittab 的格式在 busybox 中定义的。
将 inittab 文件放到到我们制作的 rootfs 的根目录下的 /etc/ 目录下,启动并且挂载 rootfs 进入了控制台命令行。当前制作的最小 rootfs 就成功了。典型的 inittab :
#/etc/inittab # 井号是注释
::sysinit:/etc/init.d/rcS # 系统启动以后运行 /etc/init.d/rcS 这个脚本文件
console::askfirst:-/bin/sh # 将 console 作为控制台终端,也就是 ttymxc0。
::restart:/sbin/init # 重启的话运行/sbin/init。
::ctrlaltdel:-/sbin/reboot # 按下 ctrl+alt+del 组合键的话就运行 /sbin/reboot(重启系统)
::shutdown:/bin/umount -a -r # 关机的时候执行 /bin/umount,也就是卸载各个文件系统
::shutdown:/sbin/swapoff -a # 关机的时候执行 /sbin/swapoff,也就是关闭交换分区。
冒号在里面是分隔符,分隔开各个部分。以行为单位的,行与行之间没有关联,每一行的配置项都是由 3 个冒号分隔开的 4 个配置值共同确定的( id : runlevels : action : process )。有些配置值可以空缺,空缺后冒号不能空缺。
action 是一个条件/状态,process 是一个可被执行的程序的 pathname。合起来的意思就是:当满足 action 的条件时就会执行 process 这个程序:busybox 最终会进入一个死循环,在这个死循环中去反复检查是否满足各个 action 的条件,如果某个 action 的条件满足就会去执行对应的 process。
动作 | 描述 |
---|---|
sysinit | 在系统初始化的时候 process 才会执行一次。 |
respawn | 当 process 终止以后马上启动一个新的 |
askfirst | 和 respawn 类似,在运行 process 之前在控制台上显示“Please press Enter to activate this console.”。只要用户按下“Enter”键以后才会执行 process。 |
wait | 告诉 init,要等待相应的进程执行完以后才能继续执行。 |
once | 仅执行一次,而且不会等待 process 执行完成。 |
restart | 当 init 重启的时候才会执行 procee。 |
ctrlaltdel | 当按下 ctrl+alt+del 组合键才会执行 process。 |
shutdown | 关机的时候执行 process。 |
之前添加了 /bin/hostname 在 /etc/sysconfig/HOSTNAME 文件中定义了一个 hostname,实际效果是:命令行下 hostname 命令查到的 host 名字正确。但是命令行的提示符是没有显示的。这个问题的解决就要靠profile 文件。将提供的 profile 文件放入 /etc/ 目录下即可。添加之后命令行提示符前面显示:
[@aston210 ]#
profile 文件也是被 busybox(init 进程)自动调用的,所以是认名字的。
在 intttab 中有一个配置项 ::askfirst:-/bin/sh,这个配置项作用就是当系统启动后就去执行 /bin/sh,执行这个就会出现命令行。因此我们这样的安排就会直接进入命令行而不会出现登录界面。我们要出现登录界面,就不能直接执行/bin/sh,而应该执行一个负责出现登录界面并且负责管理用户名和密码的一个程序,busybox 中也集成了这个程序(就是/bin/login 和/sbin/gettty),因此我们要在 inittab 中用 /bin/login 或者 /sbin/getty 去替代 /bin/sh:
: :askfirst : -/bin/sh # 启动后按回车不用登陆直接进入命令行
#: : respawn : -/bin/sh # 可去除按回车的步骤。自己进入命令行
: : sysinit : /bin/login # 启动后进入用户登陆程序,
passwd 文件中存储的是用户的密码设置,shadow 文件中存储的是加密后的密码。我们直接复制 ubuntu 系统中的/etc/passwd 和/etc/shadow 文件到当前制作的 rootfs 目录下,然后再做修改即可。修改方法:只保留 root 那一行,如
root:x:0:0:root:/root:/bin/sh # passwd 文件,最后是 sh
root :tyLxf271Ytqok:0:0:99999:7::: # shadow 文件:123456 的密文
重置密码
getty 实战
inittab 中最常见的用于登录的程序不是 /bin/login,反而是 /sbin/getty。在 busybox 中这两个是一样的,都是 busybox 的符号链接而已,因此不用严格区分这两个。
我们可以在 inittab 中用 getty 替换 login 程序来实现同样的效果。
s3c2410_serial2::respawn:/sbin/getty -L s3c2410..... 115200 vt100
精简 rcS 文件示例
#!/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 # 挂载所有的文件系统,需存在/etc/fstab 文件
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug # 这两行跟/dev 有关
mdev -s
/bin/hostname -F /etc/sysconfig/HOSTNAME # 设置主机名为 HOSTNAME 写的名字
/etc/init.d/rcS 文件是 linux 的运行时配置文件中最重要的一个,其他的一些配置都是由这个文件引出来的。这个文件可以很复杂也可很简单,里面可以有很多的配置项。可以通过修改 rcS 实现开机自启动,例如添加:
runlevel=S # 表示将系统设置为单用户模式
umask 022 # 设置 linux 系统的 umask 值
ifconfig eth0 192.168.1.10 # 设置 IP,默认为 bootcmd 设置的 IP 地址
正式产品中的 rcS 是一个引入,不是真正干活的。真正干活的/etc/init.d/中的其他脚本。
创建好文件/etc/init.d/rcS 以后一定要给其可执行权限!
当提示文件不存在时,可以通过开发板 vi 查看该文件,看看是不是结尾多出来了一个 ^M,有的话删掉即可。这是因为 rcS 文件在 windows 下创建时,行尾换行符为'rn',这个换行符 ubuntu 的 vi 自动进行优化,但是开发板的 vi 却没有,所以只能以^M 显示。
启发:shell 脚本文件如果格式不对,运行时可能会被提示文件不存在。有时候一个应用程序执行时也会提示文件不存在,问题可能是这个程序所调用的一个动态链接库找不到。
umask 测试
umask 是 linux 的一个命令,作用是设置 linux 系统的 umask 值。umask 值决定当前用户在创建文件时的默认权限。
测试结果:
总结:umask 的规律就是:umask 值和默认创建文件的权限值加起来是 666。
PATH 测试
runlevel 测试
mount 测试
mount命令是用来挂载文件系统的。mount -a 是挂载所有的应该被挂载的文件系统,在 busybox中 mount -a 时 busybox 会去查找一个文件 /etc/fstab 文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统(包括了虚拟文件系统)
测试结果:挂载时全部出错:
mount: mounting proc on /proc failed: No such file or directory
mount: mounting sysfs on /sys failed: No such file or directory
mount: mounting tmpfs on /var failed: No such file or directory
mount: mounting tmpfs on /tmp failed: No such file or directory
mount: mounting tmpfs on /dev failed: No such file or directory
原因:根文件系统中找不到挂载点。所谓挂载点就是我们要将目标文件系统(当然这里都是虚拟文件系统)挂载到当前文件系统中的某一个目录中,这个目录就是挂载点。
解决方案:自己在制作的 rootfs 根目录下创建这些挂载点目录即可。
mdev 测试
hostname 测试
静态链接:arm-linux-gcc hello.c -o hello_satic -static //加 -static 命令即可 动态链接:arm-linux-gcc hello.c -o hello_dynamic 实验结果:静态编译连接后生成的 hello_satic 已经可以成功运行。而动态编译链接程序不能执行。 分析:静态链接时,把需要的库文件都链接到了一起,可以独立运行,但是体积大(10 倍)
Linux下运行程序时,无论程序是动态编译还是静态编译,都需要一些基本库的支持。若是根文件系统中没有任何库文件,直接运行程序将提示找不到可执行文件,即使该可执行文件就在当前目录下。为了完善根文件系统,我们需要继续 在 rootfs 中创建 /lib 目录,并添加必要的库文件。在不知道需要哪些库文件的情况下,我们可以直接复制 gcc 中的动态库文件。步骤如下:
找到动态链接库文件:从交叉编译工具链文件夹中寻找,可使用 find -name “libm.so”定位到目标目录。一般安装的编译工具链目录下,如:/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib ( 仅供参考)
复制动态链接库到 roots/lib 目录下。
cp lib/*so* /rootfs/lib/ -rdf # -rdf:保留符号链接而非实体
使用 strip 工具去掉库中符号信息:动态链接库 so 文件中包含了调试符号信息,这些符号信息在运行时是没用的(调试时用的),占用空间。在传统的嵌入式系统中 flash 空间是有限的,为了节省空间常常把这些符号信息去掉。这样节省空间并且不影响运行。
arm-linux-strip *so* # 执行后从 30 M 缩小到了 3.8 M
目录 | 说明 | 补充 |
---|---|---|
linuxrc | 最重要 | 必须存在 |
bin | 可执行文件,最主要的是 busybox | 必须存在 |
sbin | 可执行文件,链接指向 /bin/busybox | 必须存在 |
usr | 系统用户所有的一些文件的存放地,busybox 安装时默认创建 | 可以删除 |
etc | 存放配置文件,被 /linuxrc 所调用执行 | 必须存在 |
lib | 存放的是当前操作系统中的动态和静态链接库文件。 | 必须存在 |
dev | 设备文件 | 必须存在 |
sys | 虚拟文件系统,不可省略的,但是只要创建了空文件夹即可 | 必须存在 |
proc | 虚拟文件系统,不可省略的,但是只要创建了空文件夹即可 | 必须存在 |
mnt | 用来挂载 | 可以删除 |
以上是脚本宝典为你收集整理的rootfs -根文件系统制作全部内容,希望文章能够帮你解决rootfs -根文件系统制作所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。