您的位置:首页 > 其它

根文件系统移植之使用busybox

2016-05-20 16:49 387 查看
使用工具

前提

步骤
一 busybox的移植
首先创建一个根文件目录

解压busybox工具包设置ARCH和CROSS_COMPILE变量

配置busybox

编译 make

安装make install

二 建全根目录系统重点就是etc下的配置文件
完善目录结构

完善C运行库

完善etc目录添加初始化配置脚本
fstab

inittab

profile

etcinitdrcS

增加其它功能

挂载sysfs 文件系统

动态创建设备节点

增加devnull devconsole

配置终端显示的lognamehostname命令行提示符

使用工具:

busybox:官网下载地址

发现busybox编译与交叉编译器的版本联系是很紧密的,很多时候busybox和cross-gcc都是不兼容的,所以还是按厂家给的手册上的对应版本弄的比较好。比如用arm-linux-gcc-4.4.3编译busybox.1.24.0会出错误,用arm-linux-gcc-4.4.3编译busybox.1.19.0就完美编译.同样的4.9.4的gcc编译busybox.1.19.0也出错.

前提 :

在制作前请先设置好板子的bootloader,以便使内核启动时能直接mount到NFS根文件系统,我用的FL2440的bootloader,如何设置请看我的另一篇文章FL2440 NFS根文件系统启动之bootloader的设置 。如果用u-boot的同学请自查资料,网上一堆。

步骤:

一 busybox的移植

实质就是为linux系统安装一些必要的可执行程序

首先创建一个根文件目录

/home/anzyelay/Desktop/arm/myrootfs

解压busybox工具包,设置ARCH和CROSS_COMPILE变量。

方法有三:

修改顶层Makefile文件

ARCH ?= $(SUBARCH) –》ARCH ?= arm

CROSS_COMPILE ?= –》CROSS_COMPILE ?=arm-none-linux-gnueabi-

在make时指定ARCH 和 CROSS_COMPILE

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

在make menuconfig 配置菜单中更改Cross Compiler prefix选项

顺便说明下arm-linux-其实跟arm-none-linux-gnueabi-是一样的,arm-linu-的一系列命令都是链接到对应的arm-none-linux-gnueabi-上的

配置busybox

要注意一点,当你不选中下面的选项时,那就是默认使用动态库,这时要将交叉编译器下的动态库文件COPY到根文件目录的lib/目录下。如果选中就不用了,这里我使用动态的,不然文件系统会很大。

Busybox Settings—>

Build Options—>

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

还可配置make install的安装目录,如果不选,默认安装在当前的busybox下的./__install/下,我设置为刚才创建的目录,如果使用默认的,等会安装好后手动将__install/下的文件拷贝到

Busybox Settings—>

Installation Options (“make install” behavior) —>

(/home/anzyelay/Desktop/arm/myrootfs)BusyBox installation prefix

busybox里也自带了很多小工具,比如命令自动补齐,ls时文件着色等等都可以自己依需要裁剪。我使用默认配置就好

编译 make

安装make install

这时在看我们的根目录就会多出些文件:

anzyelay@ubuntu:arm$ cd myrootfs/
anzyelay@ubuntu:myrootfs$ ls
bin  linuxrc  sbin  usr
anzyelay@ubuntu:myrootfs$ ls bin/
ash      conspy         dumpkmap  grep      kill      mkdir       netstat        reformime     setserial  true
base64   cp             echo      gunzip    linux32   mknod       nice           rev           sh         umount
busybox  cpio           ed        gzip      linux64   mktemp      pidof          rm            sleep      uname
cat      cttyhack       egrep     hostname  ln        more        ping           rmdir         stat       usleep
catv     date           false     hush      login     mount       ping6          rpm           stty       vi
chattr   dd             fdflush   ionice    ls        mountpoint  pipe_progress  run-parts     su         watch
chgrp    df             fgrep     iostat    lsattr    mpstat      printenv       scriptreplay  sync       zcat
chmod    dmesg          fsync     ipcalc    lzop      mt          ps             sed           tar
chown    dnsdomainname  getopt    kbd_mode  makemime  mv          pwd            setarch       touch
anzyelay@ubuntu:myrootfs$


这些就是我们在终端下用到的一些命令,此时只有这些和一个软链接linuxrc,还不足以构成文件系统。可以偿试启动下会出现如下错误:

Kernel panic - not syncing: No init found.

Try passing init= option to kernel. See Linux Documentation/init.txt

for guidance.

由于我们是动态编译的busybox,所以需要拷贝交叉编译器的动态库,将在下面的第2小节说明。

二 建全根目录系统(重点就是etc/下的配置文件 )

完善目录结构:

anzyelay@ubuntu:myrootfs$ ls
bin  linuxrc  sbin  usr
anzyelay@ubuntu:myrootfs$ mkdir dev etc lib proc sys tmp var
anzyelay@ubuntu:myrootfs$ ls -rt
bin  linuxrc  sbin  usr  var  tmp  sys  proc  lib  etc  dev
anzyelay@ubuntu:myrootfs$


完善C运行库:

如果直接启动系统会出现如下错误:

VFS: Mounted root (nfs filesystem) on device 0:12.
Freeing init memory: 140K
Failed to execute /linuxrc. Attempting defaults...
Kernel panic - not syncing: No init found.  Try passing init= option to kernel..


原因是/linuxrc实质是个软链接–>bin/busybox ,该程序由于没有相关的依赖库,所以无法正常执行,要将用到的动态库都放到/lib下如下命令。(注:不要全部复过来。其中的.a格式的静态库不需要,不然太大了,路径自己找下,直接./arm/4.4.3/lib下的是不行的,我试过。)

anzyelay@ubuntu:myrootfs$ cp /usr/local/arm/4.4.3/arm-none-linux-gnueabi/sys-root/lib/*.so* lib/ -av
anzyelay@ubuntu:myrootfs$ du -h lib
8.5M    lib


总共8.5M,还可以用arm-linux-strip命令缩小下,要用全路径命令才成功。不然出错。

相对路径时错误:

anzyelay@ubuntu:myrootfs$ arm-linux-strip lib/*
/usr/local/arm/4.4.3/bin/.arm-none-linux-gnueabi-strip: unable to copy file 'lib/ld-2.9.so'; reason: Permission denied
... ...


绝对路径时正确:

anzyelay@ubuntu:myrootfs$ sudo /usr/local/arm/4.4.3/bin/arm-none-linux-gnueabi-strip lib/*
/usr/local/arm/4.4.3/bin/.arm-none-linux-gnueabi-strip:lib/libgcc_s.so: File format not recognized
anzyelay@ubuntu:myrootfs$
anzyelay@ubuntu:myrootfs$ du -h lib
4.3M    lib
anzyelay@ubuntu:myrootfs$


效果很明显。。strip并不是压缩库而是去除一些调试信息和符号信息,具体可以自行arm-linux-strip –help下,回显是:Removes symbols and sections from files。。。

完善etc/目录,添加初始化配置脚本。

etc/主要是存放系统的配置文件,内核在启动和运行过程中需要读取这些配置文件,busybox提供了一些初始化范例脚本,直接拷贝过来更改就好(也可以用开发板提供的更改)。如下:

anzyelay@ubuntu:myrootfs$ ls etc/
anzyelay@ubuntu:myrootfs$ cp -a ../busybox-1.22.1/examples/bootfloppy/etc/* etc/
anzyelay@ubuntu:myrootfs$ tree etc/
etc/
├── fstab
├── init.d
│   └── rcS
├── inittab
└── profile

1 directory, 4 files
anzyelay@ubuntu:myrootfs$


etc/目录文件说明:

fstab

static file system information.存放的是系统中的文件系统信息,定义了需要挂载的文件系统以及挂载点的信息

格式:< file system > < mount point > < type > < options > < dump > < pass >

参考实例:

anzyelay@ubuntu:_install$ cat etc/fstab

proc /proc proc defaults 0 0

tmpfs /tmp tmpfs defaults 0 0

sysfs /sys sysfs defaults 0 0

tmpfs /dev tmpfs defaults 0 0

说明:

file system :需要挂载的文件系统的所在设备或分区,如果是nfs类则写成:serverIP:/共享目录

注: tmpfs 是一个临时文件系统,驻留于你的交换分区或是内存中(取决于你的使用情况)。使用它可以提高文件访问速度,并能保证重启时会自动清除这些文件。

mount point :设备挂载目录,需要挂载的文件系统的挂载点

type :要挂载设备或是分区的文件系统类型

options:挂载参数(noauto,auto、user、exec、ro、rw)对于大多数系统使用”defaults”就可以

dump:是否提供备份功能,0为不备份,1为要备份

pass:是否开机时对文件系统进行检查,该字段被fsck命令用来决定在启动时需要被扫描的文件系统的顺序,根文件系统”/”对应该字段的值应该为1,其他文件系统应该为2。若该文件系统无需在启动时扫描,则设置该字段为0

inittab

init的启动配置文件,其中指定了一些启动脚本、程序的路径,并指定在哪些运行级别执行它们。

格式:< id > :< runlevels > :< action > :< process >

参考实例:

::sysinit:/etc/init.d/rcS //是init进程启动的第一个子进程,它是一个脚本

::respawn:-/bin/sh//启动shell,以/dev/console作为控制台

#tty2::askfirst:-/bin/sh //

::ctrlaltdel:/bin/umount -a -r //按下Ctrl+Alt+Del执行的程序

说明:

id:登记项标识符,最多为4个字符。用于惟一地标识/etc/inittab文件中的每一个登记项 (但只是个名称,对init没任何作用)

runlevels :对于Busybox init程序,这个字段没有意义,可以省略。

action :init进程如何控制process,8种(sysinit、wait、once、respawn、askfirst、shutdown、restart、ctrlatdel)取值:

sysinit:不论runlevels在哪个执行等级,系统会在执行boot 及bootwait之前执行

wait:在sysinit进程后执行第4项指定的process,并等待它执行完毕才继续执行其他动作。

respawn:如果相应的进程还不存在,那么init就启动该进程,同时不等待该进程的结束就继续扫描/etc/inittab文件;当该进程死亡时,init将重新启动该进程。如果相应的进程已经存在,那么init将忽略该登记项并继续扫描/etc/inittab文件。

askfirst:启动完respawn进程后执行,与respawn类似,不过init进程先输出“please press enter to activate this console”,等用户输入回车键之后才启动子进程。

shutdown:当系统关机时执行,即重启、关闭系统命令。

restart:当Busybox中配置了CONFIG_FEATURE_USE_INITAB,并且init进程接收到SIGHUP信号时执行,先重新读取、解析/etc/inittab文件,再执行restar程序。

ctrlaltdel:按下Ctrl+Alt+Del组合键时执行。

init进程启动顺序:

在系统启动前期:执行sysinit、wait、once的3类子进程。

在系统正常启动期间:执行respawn、askfirst的两类子进程,并监视他们,发现某个子进程退出时重新启动它。

在系统退出时:执行shutdown、restart、ctrlaltdel的3类子进程。

process:要执行的程序,可以是可执行程序,也可以是脚本,程序后面可以带参数。如果process字段前有’-‘字符,这个程序被称为“交互的”。

profile

全局环境配置文件,详细说明请参考Environment variables

参考实例

anzyelay@ubuntu:busybox-1.19.0$ cat ../myrootfs/etc/profile
\# /etc/profile: system-wide .profile file for the Bourne shells
echo  " Processing  /etc/profile... "
LOGNAME=`id  -un`
PS1='[\u@\h:\/\W]# '
HOSTNAME=`/bin/hostname`
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then
HOSTNAME=localhost  #如果为空则显示此名
fi
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
export LOGNAME  PS1  PATH


etc/init.d/rcS

脚本文件,在init配置文件中定义了此为第一个要执行的程序,那就最先执行。可以在此脚本中添加自动执行的命令:

实例参考:

anzyelay@ubuntu:_install$ cat etc/init.d/rcS

#! /bin/sh

/bin/mount -a

mkdir -p /dev/pts

mount -t devpts devpts /dev/pts

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

/sbin/mdev -s

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

其中
/bin/mount -a
意思就是执行挂载fstab文件指定的文件系统,“ Mount all filesystems (of the given types) mentioned in fstab.”

看了上面的介绍就知道:文件系统的启动先由init进程按inittab配置的顺序执行/etc/init.d/rcS脚本,该脚本里执行到mount -a这句时就按fstab文件定义的挂载配置挂载文件系统。,如果不更改直接NFS挂载会出错,“can’t open /dev/tty2: No such file or directory”,原因就是inittab中有一句“tty2::askfirst:-/bin/sh”,将其注释就可以正常启动了。

增加其它功能

到这一步,我们的文件系统就可以正常启动了,如果/sys,/dev/下面都是空的, 那是因为你还没有在fstab里没有挂载sys等文件系统当然看不到了。要想实现更多功能,就要配置etc/目录下的文件了。比如动态创建设备节点等。。

挂载sysfs 文件系统

当不挂载sysfs文件系统时,你只能看到你自己创建的文件,而在sys/下看不到其它文件,所以必须在fstab中增加以实现对文件系统的挂载, eg:加一条 sysfs /sys sysfs defaults 0 0

你在/sys下就可以看到其它文件了。

动态创建设备节点

设备节点的动态管理由mdev或udev来完成(其实mdev是busybox做的一个精简的udev,适合在嵌入式系统上使用),busybox中编译配置默认自带了mdev(如果没有请加上mdev选项),编译安装后在sbin下有个mdev可执行程序。有了这个可执行程序还需要适当配置才能动态的创建节点,因为mdev的执行也是要有条件的。1.详见参考文档2.这里有个翻译过的

“Both require sysfs support in the kernel and have it mounted at /sys. For dynamic updates, you also need to have hotplugging enabled in your kernel.”

简单的只需在etc/init.d/rcS脚本中增加如下就可:

[0] mount -t proc proc /proc

[1] mount -t sysfs sysfs /sys

[2] echo /sbin/mdev > /proc/sys/kernel/hotplug

[3] mdev -s

这下重启后是不是可以在/dev下看到设备节点文件了呢?也可以将0,1两个挂载配置写到fstab去,这里改成mount -a就行了。如下:

anzyelay@ubuntu:myrootfs$ cat etc/fstab

proc /proc proc defaults 0 0

sysfs /sys sysfs defaults 0 0

anzyelay@ubuntu:myrootfs$ cat etc/init.d/rcS

#! /bin/sh

/bin/mount -a #执行fstab中的文件挂载

echo /sbin/mdev > /proc/sys/kernel/hotplug #设置内核,当有设备插拔时调用/sbin/mdev程序

/sbin/mdev -s #在/dev目录下生成内核支持的所有设备的结点

上面这个是简化版,可能会出
/etc/init.d/rcS: line 4: can't create /proc/sys/kernel/hotplug: nonexistent directory
的错误 ,要用一个full版的,在[2] echo之前要加上如下语句:

[4] mount -t tmpfs tmpfs /dev #同样可以写到fstab中

[5] mkdir /dev/pts

[6] mount -t devpts devpts /dev/pts

增加/dev/null /dev/console

引述网上找到的原因说:

虽然这两个设备文件在内核挂载完文件系统后,系统会利用mdev自动创建,可是在此之前,即在内核挂载文件系统之前。init进程会用到这两个设备文件。如果没有这两个设备文件会提示如下一些信息 Warning: unable to open an initial console

cd dev
mknod console c 5 1
mknod null c 3 1


配置终端显示的“logname@hostname”命令行提示符

logname 和 hostname分别由LOGNAME 和HOSTNAME这两个环境变量来保存,而命令行提示符的显示格式是由PS1这个环境变量配置

PS1=“comand list”

命令列表有很多参数如下:

  ! 显示该命令的历史记录编号。

  # 显示当前命令的命令编号。

  $ 显示$符作为提示符,如果用户是root的话,则显示#号。

  \ 显示反斜杠。

  \d 显示当前日期。

  \h 显示主机名。

  \n 打印新行。

  \nnn 显示nnn的八进制值。

  \s 显示当前运行的shell的名字。

  \t 显示当前时间。

  \u 显示当前用户的用户名。

  \W 显示当前工作目录的名字。

  \w 显示当前工作目录的路径

man hostname 可见如下:

hostname - show or set the system’s host name

设置名称命令如下(将之写入rcS脚本中执行):

/bin/hostname -F /名称文件

#文件可以自行更改,hostname会到名称文件中获得要设置的名称,读取时忽略#号行

这两个变量的获取命令如下(将之写入etc/profile配置中):

HOSTNAME=`/bin/hostname`#不要少了“`”这个符号

LOGNAME=`id -un`

所以设置如下:

配置busybox添加支持PS1的选项 

Busybox Settings —>

  Busybox Library Tuning —>

  [*] Username completion

  [*] Fancy shell prompts

设置名称

创建hostname要读取名称时的保存文件/etc/hostname(一般放在etc下),在其内加入名称就行如:

anzyelay.com

在etc/init.d/rcS脚本中添加设置语句设置名称如下:

/bin/hostname -F /etc/hostname

配置环境变量:

在/etc/profile添加如下:

HOSTNAM=`/bin/hostname`
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then
HOSTNAME=localhost  #如果为空则显示此名
fi
PS1=`[\u@\h:\W]# `
PATH=/bin:/sbin:/usr/bin:/usr/sbin   
export PS1 HOSTNAME PATH


此时启动显示如下:

[@anzyelay.com:/]#ls

bin etc linuxrc sbin tmp var

dev lib proc sys usr

新建/etc/passwd,在其中加入如下:

root:x:0:0:root:/root:/bin/sh


立马显示如下信息了:

[root@anzyelay.com:/etc]#


etc/passwd字段说明:

用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell
x表示没有密码,不过一般密码也是保存在shadow中,这里不安全

如果需要组别信息可以新建/etc/group,手动写该文件或直接在开发板上用命令addgroup加入,如下:

[root@bst:/etc]#addgroup root

addgroup: /etc/group: No such file or directory

[root@bst:/etc]#ls

fstab      init.d     inittab    passwd     profile    shadow     sysconfig

[root@bst:/etc]#touch group

[root@bst:/etc]#addgroup root

[root@bst:/etc]#cat group

root:x:1000:


etc/group字段说明:

组名:口令:组标识号:组内用户列表


OK ,初步的根文件系统的移植至些结束,如果要加其它功能移植方法类似,加入依赖库文件,可执行文件,弄好配置文档就OK。触摸屏校准移植在下篇文章中在记录了。下面是错误记录

三 ERROR

1.Kernel panic - not syncing: No init found.

Freeing init memory: 140K
Failed to execute /linuxrc.  Attempting defaults...
Kernel panic - not syncing: No init found.  Try passing init= option to kernel. See Linux Documentation/init.
txt for guidance.
[<c000ea5c>] (unwind_backtrace+0x0/0xec) from [<c034a220>] (panic+0x7c/0x1c0)
[<c034a220>] (panic+0x7c/0x1c0) from [<c0349f7c>] (init_post+0x10c/0x138)
[<c0349f7c>] (init_post+0x10c/0x138) from [<c044e8f4>] (kernel_init+0x164/0x19c)


See Linux Documentation/init.txt for guidance.

8 A) Unable to mount root FS

9 B) init binary doesn’t exist on rootfs

10 C) broken console device

11 D) binary exists but dependencies not available

12 E) binary cannot be loaded

我这里的错误是D,一般按上面的保证了ARCH=arm,交叉编译器也设好了,成功编译出来了并make install了,那就是D缺少依赖文件,或者/etc没有配置好导致找不到init进程。

2.mount: mounting proc on /proc failed: No such file or directory

没有proc目录,在目录下mkdir一个就行了。

3.Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

用arm-linux-gcc-4.9.4 编译busybox-1.25.0成功的这后运行却成了这样



查了好久,内核配置中已选了EABI了,而且同一个内核镜像用之前的系统文件是正常的,后来发现将4.4.3里的库文件移到lib里就有变成如下了:



anzyelay@ubuntu:lib$ arm-linux-strings libc.so.6 | grep GLIBC_
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_PRIVATE


看来是4.4.3的libc不支持2.14版.将4.9.4里的的移过来得到如下



看来也不是这个glibc,百度是目标机和编译器的glibc两者不一致导致.郁闷了,把4.9.4的版本的lib挪过来一致了不行,低版本的又不支持.估计应该是我的4.9.4的交叉编译器也有问题,因为我单独用它编译busybox居然出错.如下





,明明有这个头文件,就是出错,查不出来了, 给跪了,这嵌入式移植真麻烦.安心用厂家提供的编译器吧…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: