使⽤busybox制作rootfs
Build Busybox as a static binary(no shared libs),如果选择上,则busybox将以静态形式进⾏编译,否则将以动态⽅式编译。此外,还需要对交叉编译环境进⾏配置,选择其中的Cross Compiler Perfix,输⼊交叉编译器的前缀,我们的嵌⼊式平台上使⽤的是arm-uclinux-linu TAG:
1 获取源码解压
从busybox的官⽅主页 ,下载busybox的源码,⽬前最新的版本为busybox-1.13.3.tar.bz2
#tar –jvxf busybox-1.13.3.tar.bz2
进⼊解压后的busybox源码⽬录
#cd busybox-1.13.3
2 配置busybox
步骤跟编译linux内核时很像
#make menuconfig
出现⼀个图形界⾯,选择Busybox Settings,这⾥可以对编译、安装以及调试等模式进⾏配置。
然后选择Build Options,对交叉编译器以及编译⽅式进⾏配置。
其中的第⼀项是Build Busybox as a static binary(no shared libs),如果选择上,则busybox将以静态形式进⾏编译,否则将以动态⽅式编译。此外,还需要对交叉编译环境进⾏配置,选择其中的Cross Compiler Perfix,输⼊交叉编译器的前缀,我们的平台上使⽤的是arm-uclinux-linux的交叉编译⼯具。
这⾥我们先选择静态编译,动态⽅式的稍后再讲,注意Build with Large File Support (for accessing files > 2 GB)不要选(默认是选上的),否则编译后会出现如下错误:
miscutils/lib.a(readahead.):In function ‘readahead_main’
readahead.(.adahead_main+0×70):undefined reference to ‘readahead’
collect2:ld returned 1 exit status
make :***[busybox_unstripped ]Error 1
3 编译busybox
#make
4 安usybox
#make install
可以采⽤perfix参数安装到指定⽬录下,格式为:make install prefix=xxx⽬录,如果不特别指定,将默认在busybox源码⽬录下⽣成⼀个
_install⽬录。到此,busybox基本上可以功成⾝退了。我们需要的就是busybox编译出来的这个_install⽬录。
进⼊_install⽬录,可以看到⼀共有3个⽬录和⼀个⽂件,分别是:bin、sbin和usr⽬录以及linuxrc⽂件。
在对这⼏个⽬录进⾏说明之前,先简单介绍⼀下编译⽣成的busybox可执⾏⽂件,它存在于bin⽬录下。Busybox使⽤了带参的main 函数:int main(int argc,char *argv[]),在这个定义中,argc是传递进来的参数的个数(参数数量),⽽argv是⼀个字符串数组,代表从命令⾏传递进来的参数。argv的索引0是命令⾏调⽤的程序名。可以在bin⽬录下进⾏如下操作:
#busybox pwd(注意,busybox这个可执⾏⽂件不需要加./)
当为⼀个可执⾏程序创建符号链接后,在执⾏这个符号链接时,就可以获取到这个符号链接的名字。⽽busybox正是使⽤符号链接的⽅式使⼀个可执⾏程序看起来像很多程序⼀样。对于busybox中包含的每个⼯具来讲,都会创建⼀个符号链接,这样就可以使⽤这些符号链接来调⽤busybox了。然后busybox接着根据argv[0]的值来调⽤内部⼯具。
下⾯分别对install⽬录下的⼏个⽂件进⾏⼀些说明。
Ø bin包含⽤户⼯具,其中,busybox可执⾏⽂件就在这个⽬录下,该⽬录下其他所有⽂件都是指向busybox的符号链接
Ø sbin⽬录包含操作系统⼯具,同样也指向busybox。
Ø linuxrc是⼀个链接⽂件,指向busybox。
5 添加etc⽬录及基本配置⽂件
参考⼀个正常的linux系统将会发现,此时busybox建⽴的⽂件系统还缺少很多⽂件。如果⽤这个作为⽂件系统,将是⽆法运⾏的。⽣成这些配置可以选择的⽅法有2种,⼀种是直接从⼀个正常运⾏的系统中拷贝,另⼀种是借助于busybox的examples。显然,选择第⼆种会容易的多,我们直接拷贝examples/bootfloopy/etc到install⽬录下。
#cp –a ../examples/bootfloppy/etc/ .
然后可以看看etc⽬录下的⽂件,⼀共有3个⽬录和⽂件,下⾯逐⼀对以上⼏个⽂件进⾏分析和说明。
Ø inittab⽂件:系统启动后访问的第⼀个脚本⽂件,后续启动的⽂件都由它指定。下⾯看⼀下busybox中原始的inittab⽂件内容:
::sysint:/etc/init.d/rcS
::respawn:-/bin/sh
tty2::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount –a -r
其中第⼀⾏指定系统的启动脚本为/etc/init.d/rcS
第⼆⾏指定打开⼀个登录会话
第三⾏指定在第三个虚拟终端打开⼀个⽆须登录验证的shell
第四⾏指定了当按下ctrl+alt+del组合键时的执⾏命令
Ø fstab⽂件:定义了⽂件系统的各个“挂载点”,需要与实际的系统相配合。默认的fstab⽂件内容为:
proc /proc proc defaults 0 0
其他的根据需要再进⾏添加,⽐如devpts /dev/pts devpts defaults 0 0就是为UNIX PTYs准备的,后⾯讲telnetd时要⽤到。
Ø profile⽂件:终端登陆之后⾸先运⾏的脚本。
6 添加dev⽬录及基本设备⽂件
调试时要通过串⼝发送消息到终端显⽰。因此串⼝控制台和终端2个设备⽂件是必不可少的。
调试时要通过串⼝发送消息到终端显⽰。因此串⼝控制台和终端2个设备⽂件是必不可少的。
#mkdir dev
#mknod dev/console c 5 1
#mknod dev/ttyAMA0 c 204 64
在启动参数中,设置console=ttyAMA0
7 添加其他常⽤⽬录
可以选择home、root、proc、mnt、lib、var、opt、tmp。
此时,⼀个基本的⽂件系统的功能就已经完成了。可以采⽤NFS进⾏调试。但是,此时你可能会遇到如下问题,系统登录后终端上会不断打印:
cannot open /dev/ttyS2:No such file or directory.
原因出在/etc⽬录下的inittab⽂件,我们看⼀下其内容:
::sysint:/etc/init.d/rcS
::respawn:-/bin/sh
tty2::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount –a -r
这条语句表⽰在第3个虚拟终端打开⼀个⽆须登录验证的shell。⽽我们之前没有建⽴这个tty2设备,因此会出错。解决的办法有2个:⼀是屏蔽该语句,⼆是建⽴该设备节点。我们选择将其屏蔽。
8 相关问题
8.1 使⽤动态⽅式编译 busybox
进⼊Build Options时,不要选择Build Busybox as a static binary,其他所有操作步骤跟静态编译⼀样,你会发现这样建⽴的⽂件系统⽆法启动,终端上打印出如下消息:
Kernel panic-not synving:No init found. Try passing init=option to kernel.
为什么会出现这种问题呢?这就得回到两种编译⽅式的特点上来。静态编译时是将所⽤到的库⽂件⼀起编译了进去,⽽动态编译时是在需要时才调⽤相应的库。我们选择动态编译后,没有添加任何库⽂件就运⾏,显然是会出错的。那么如何查看busybox可执⾏⽂件⾥使⽤的库呢。Readelf这个⼯具提供了解决办法。使⽤如下命令,参数d表⽰将⽂件中所有的动态部分予以显⽰。
# arm-uclibc-linux-readelf -d busybox
Dynamic section at offset 0xca014 contains 18 entries:
标记类型名称/值
0×00000001 (NEEDED) 共享库: [libm.so.0]
0×00000001 (NEEDED) 共享库: [libc.so.0]
0×0000000c (INIT) 0xbe24
0×0000000d (FINI) 0xb2054
0×00000004 (HASH) 0×80e8
0×00000005 (STRTAB) 0xa500
0×00000006 (SYMTAB) 0×8b70
0×0000000a (STRSZ) 3259 (bytes)
0×0000000b (SYMENT) 16 (bytes)
0×00000015 (DEBUG) 0×0
0×00000003 (PLTGOT) 0xda0cc
0×00000002 (PLTRELSZ) 3040 (bytes)
0×00000014 (PLTREL) REL
0×00000017 (JMPREL) 0xb244
0×00000011 (REL) 0xb1bc
0×00000012 (RELSZ) 136 (bytes)box shadow怎么设置
0×00000013 (RELENT) 8 (bytes)
0×00000000 (NULL) 0×0
从上⾯的结果中,我们可以看到,busybox这个程序使⽤到了libm.so.0和libc.so.0两个库⽂件,实际上这是2个符号链接,分别指向libc-0.9.28.so和libuClibc-0.9.28.so。将以上四个⽂件分别拷贝到lib⽬录下。按理说,这样应该就可以了,但是仍然⽆法正常运⾏。显⽰的错误信息和刚刚没加库之前⼀样。可能的原因有2种:⼀是库⽂件没有添加全,⼆是库⽂件没有正确被加载。根据readelf显⽰的结果应该
不是第⼀种原因。那么到底为什么没被正确加载呢?原来库⽂件的加载,还需要⼀个共享库加载器。到对应的⽂件ld-uClibc- 0.9.28.so和ld-uClibc.so.0添加到lib⽬录下后。运⾏正常。
8.2 终端登录⽤户验证功能添加
需要在etc⽬录下增加passwd、group和shadow(在编译busybox时如果不选择shadow功能将不需要这个⽂件)3个⽂件。
⽣成这3个⽂件的⽅法有:
Ø ⼿动⽣成,按照格式规范⾃⼰编写内容;
Ø 通过busybox提供的⼯具adderuser⾃动⽣成
8.2.1 ⼿动⽅式
⾸先我们介绍⼀下如何⼿动添加。以增加root⽤户为例,增加passwd⽂件,其内容为:
#cat passwd
root:x:0:0:root:/root:/bin/sh
同时,此时要确定root⽬录已经存在。
passwd⼀共由7个字段组成,6个冒号将其隔开。它们的含义分别为:
1 ⽤户名
2 是否有加密⼝令,x表⽰有,不填表⽰⽆,采⽤MD5、DES加密。
3 ⽤户ID
4 组ID
5 注释字段
6 登录⽬录
7 所使⽤的shell程序
7 所使⽤的shell程序
增加group⽂件,其内容为:
#cat group
root:x:0:
Group⼀共由4个字段组成,3个冒号将其隔开,它们的含义分别为:
1 组名
2 是否有加密⼝令,同passwd
3 组ID
4 指向各⽤户名指针的数组
由于busybox默认启动了shadow模式,因此需要增加shadow⽂件,其内容为:
#cat shadow
root:$1$3jZ93Mwq$oaeef6lWIuThavs8wD0Wh1:0:0:99999:7:::
shadow⼀共由9个字段组成,8个冒号将其隔开,它们的含义分别为:
1 ⽤户名
2 加密后的⼝令,若为空,表⽰该⽤户不需要⼝令即可登陆,若为*号,表⽰该账号被禁⽤。上⾯的表⽰的是123456加密后的⼝令。
3 从1970年1⽉1⽇⾄⼝令最近⼀次被修改的天数
4 ⼝令在多少天内不能被⽤户修改
5 ⼝令在多少天后必须被修改(0为没有修改过)
6 ⼝令过期多少天后⽤户账号被禁⽌
7 ⼝令在到期多少天内给⽤户发出警告
8 ⼝令⾃1970年1⽉1⽇被禁⽌的天数
9 保留域
这⾥强调⼀下shadow⽂件的由来。/etc/passwd⽂件对系统的所有⽤户都是可读的,这样的好处是每个⽤户都知道系统上有哪些⽤户,但缺点是其他⽤户的⼝令容易受到攻击,尤其是当⼝令较简单时。
所以⼀些linux系统中使⽤到了影⼦⼝令⽂件shadow,将⽤户的⼝令存储在另⼀个⽂件 /etc/shadow中,该⽂件只有根⽤户root可读,⼤⼤提⾼了安全性。
不过,采⽤这种⼿动添加⽂件的⽅法有⼀个缺陷,就是如果要为⽤户设置登陆⼝令的话,shadow⽂件中必须填写加密后的⼝令,⽽这个加密算法我们⼜不知道,即使知道,要经过转换后再添加,⽐较⿇烦。此时,不妨试⼀下第⼆种⽅法。
8.2.2 ⾃动⽅式
⾃动⽣成是使⽤了busybox提供的adduser⼯具和passwd⼯具。
在⽂件系统正常运⾏起来后,使⽤adduser命令,使⽤⽅法为:
#adduser root
然后就会在etc⽬录下⾃动⽣成passwd 、group和shadow3个⽂件。但是运⾏该命令后会打印出如下消息:
passwd:unknown uid 0
这表⽰不能为该⽤户设置密码,此时你会发现要passwd命令也⽆法使⽤。
解决的办法是,打开passwd⽂件,其内容为:
root:x:1000:1000: User…:/home/root:/bin/sh
将⽤户ID和组ID均更改为0
打开group⽂件,其内容为:
root:x:1000:
同样将组ID改为0
然后,passwd命令就可以正常使⽤了。这时为root⽤户设置⼝令:
#passwd root
根据提⽰输⼊密码。其中,root⽤户登陆后的⽬录可以⼿动进⾏更改。
8.3 telnetd功能添加
busybox默认已经添加了对telnetd和telnet功能的⽀持,只需要完成⼀些相关的设置⼯作就可以启动这2个功能了。
Ø 创建/dev/pts⽬录
Ø 在/etc/fstab中添加如下信息,挂载devpts⽂件系统
devpts /dev/pts devpts defaults 0 0
Ø 在/dev⽬录下增加ptmx设备⽂件:
#mknod ptmx c 5 2
Ø 在rcS⽂件中添加如下脚本,启动telnetd
if [ -x /usr/sbin/telnetd ] ;
then
telnetd&
fi
Ø 在/dev⽬录下增加null设备⽂件,否则上述脚本运⾏时会出错:提⽰不到null⽂件。
#mknod null c 1 3
此时,telnetd功能开机就可以启动了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论