busybox:嵌入式开发中的瑞士军刀(提供嵌入式中linux中的各种小工具,小命令,比如像ls、pwd命令等),一般这个文件官方会给出,或者直接在网上找一份也是可以的,然后放到虚拟机中进行解压,配置编译。
BusyBox 的官方网站是:http://www.busybox.net/
我们下面就以busybox-1.24.1.tar.bz2为例来讲解一下 BusyBox 的编译安装过程。
注意:因为当你决定了用什么版本的交叉编译器来编译内核时,文件系统中的所有程序也要使用同样的交叉编译器来编译。
创建根文件系统目录:/home/lsm/workspace/x210
解压压缩包:tar -xjvf busybox-1.24.1.tar.bz2 .
(1) ARCH = arm
(2) CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
(1)Settings--->
Build Options--->
[*]Build BusyBox as a static binary(no shared libs)
(2)Settings--->
Library Tuning--->
[*]vi-style line editing commands
[*]Fancy shell prompts
(3)Linux Module Utilities--->
[ ]Simplified modutils
[*]depmod
[*]insmod
[*]lsmod
[*] Pretty output
[*] modinfo
[*]modprobe
[*] Blacklist support
[*]rmmod
(4)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
(1)make编译中遇到问题:sync.c:(.text.sync_main+0x78): undefined reference to `syncfs’。
这个错误很可能是gcc和当前busybox版本不兼容造成的,我们先尝试避开这个问题,禁用sync即可。
Coreutils --->
Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
[ ] sync
继续make,编译完成
修改安装目录:
Settings--->
Installation Options ("make install" behavior) --->
Destination path for 'make install'
make install安装完成
mkdir etc
touch etc/inittab
添加文件内容
#first:run the system script file
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:-/sbin/reboot
#umount all filesystem
::shutdown:/bin/umount -a -r
#restart init process
::restart:/sbin/init
(1)inittab的工作原理就是被/linuxrc(也就是busybox)执行时所调用起作用。
(2)inittab在/etc目录下,所以属于一个运行时配置文件,内容由文本组成。我们研究的重点是如何修改他。。
(3)我们的重点是inittab的格式究竟怎样的?我们看到一个inittab后怎么去分析这个inittab对启动的影响。
(4)inittab格式解析
1. # 注释(linux中的习惯性思维)
2. : 分隔符,每行代表一个独立的含义 ,分隔开各个部分。
3. / 目录
4:inittab内容是以行为单位的,行与行之间没有关联,每行都是一个独立的配置项,每一个配置项表示一个具体的含义。
5:每一行的配置项都是由3个冒号分隔开的4个配置值共同确定的。这四个配置值就是id:runlevels:action:process。值得注意 得是有些配置值可以空缺,空缺后冒号不能空缺,所以有时候会看到连续2个冒号。
6:每一行的配置项中4个配置值中最重要的是action和process,action是一个条件/状态,process是一个可被执行的程序的pathname。合起来的意思就是:当满足action的条件时就会执行process这个程序。理解inittab的关键就是明白“当满action的条件时就会执行process这个程序。” 去分析busybox的源代码就会发现,busybox最终会进入一个死循环,在这个死循环中去反复检查是否满足各个action的条件,如果某个action的条件满足就会去执行对应的process。
sysinit | 指定的进程在访问控制台之前执行,这样的条目仅用于对某些设备的初始化,目的是为了使init在这样的设备上向用户提问有关运行级别的问题,init需要等待进程运行结束后才继续 |
respawn | 如果process字段指定的进程不存在,就启动该进程,init不会等待处理结束,而是继续扫描inittab文件。当该进程被终止时,init将重新启动它。如果相应的进程已经存在,init就忽略该条目并继续扫描inittab文件 |
askfirst | 类似respawn,主要用途是减少系统上执行的终端应用程序的数量。它将会促使init在控制台上显示“Please press Enter to active this console”的信息,并在重新启动进程之前等待用户按下“enter”键 |
wait | 告诉init必须等到相应的进程执行完成之后才能继续执行 |
once | 启动进程,不会等待处理结束,而是继续处理下一条条目。当该进程被终止时,init不会重新启动它。从一个运行级别进入另一个运行级别时,如果相应的进程仍 在运行,init就不会重新启动该进程 |
ctratldel | 当按下Ctrl+Alt+Delete组合键时,执行相应的进程 |
shutdown | 当系统关机时,执行相应的进程 |
restart | 当init重新启动时,执行相应的进程,通常此处所执行的进程就是init本身 |
boot | 只在系统启动时,init才处理这条条目,启动相应的进程,并不等待处理结束就去处理下一条条目。当这样的进程终止时,也不会重新启动它 |
bootwait | 系统启动后,当第一次从单用户模式进入多用户模式时才处理该条目,init启动这样的进程,并且等待其处理结束才处理下一条条目,当该进程被终止时,也不重新启动它。 |
off | 如果相应的进程正在运行,那么就发出一个警告信号,等待数秒后,再发出信号SIGKILL强制终止该进程。如果相应的进程不存在就忽略该条目 |
initdefault | 指定一个默认的运行级别,如果指定了多个运行级别,其中最大的数字将是默认的运行级别。如果inittab文件没有包含该条目,在系统启动时会请求用户为其指定一个默认的运行级别 |
powerwait | 当初接接到断电的信号时,处理指定的进程,并且等到处理结束后才去检查其他的条目 |
powerfail | 当init接到断电的信 时,处理指定的进程,但是不等待该进程处理结束。 |
mkdir init.d
touch 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.88
1、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。
2、runlevel=
(1)runlevel也是一个shell变量,并且被导出为环境变量。
(2)runlevel这个环境变量到底有什么用?
linux操作系统自从开始启动至启动完毕需要经历几个不同的阶段,这几个阶段就叫做runlevel。例如init 0就是关机,init 6 就是重启。
Linux系统有7个运行级别(runlevel)
运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆
运行级别2:多用户状态(没有NFS)
运行级别3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式
运行级别4:系统未使用,保留
运行级别5:X11控制台,登陆后进入图形GUI模式
运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动
(3)runlevel=S表示将系统设置为单用户模式
3、umask=
(1)umask是linux的一个命令,作用是设置linux系统的umask值。
(2)umask值决定当前用户在创建文件时的默认权限。
4、mount -a
(1)mount命令是用来挂载文件系统的
(2)mount -a是挂载所有的应该被挂载的文件系统,在busybox中mount -a时busybox会去查找一个文件/etc/fstab文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统(包括了虚拟文件系统)
5、mdev
(1)mdev是udev的嵌入式简化版本,udev/mdev是用来配合linux驱动工作的一个应用层的软件,udev/mdev的工作就是配合linux驱动生成相应的/dev目录下的设备文件。
(2)在rcS文件中没有启动mdev的时候,/dev目录下启动后是空的;
在rcS文件中添加以下与mdev有关的2行配置项后,
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
再次启动系统后发现/dev目录下生成了很多的设备驱动文件。
(3)/dev目录下的设备驱动文件就是mdev生成的,这就是mdev的效果和意义。
6、hostname
(1)hostname是linux中的一个shell命令。hostname xxx执行后可以设置当前主机名为xxx ,直接hostname不加参数可以显示当前系统的主机名。
(2)/bin/hostname -F /etc/sysconfig/HOSTNAME
指定了一个主机名配置文件(这个文件一般文件名叫hostname或者HOSTNAME)
根据/bin/hostname -F /etc/sysconfig/HOSTNAME,在etc下创建sysconfig
在sysconfig/下创建 HOSTNAME,添加文件内容:linux
7、ifconfig
(1)有时候我们希望开机后进入命令行时ip地址就是一个指定的ip地址(譬如192.168.1.10),这时候就可以在rcS文件中
ifconfig eth0 192.168.1.10
(1)挂载时出错:
(2)原因是因为根文件系统中找不到挂载点。所谓挂载点就是我们要将目标文件系统(当然这里都是虚拟文件系统)挂载到当前文件系统中的某一个目录中,这个目录就是挂载点。
(3)解决方法就是在rootfs下分别创建它们
mkdir proc sys var tmp dev
(1)之前添加了/bin/hostname在/etc/sysconfig/HOSTNAME文件中定义了一个hostname(linux),实际效果是:命令行下hostname命令查到的host名字确实是linux。但是问题就是命令行的提示符是没有显示的。
(2)这个问题的解决就要靠profile文件。
在etc目录下创建profile文件,并添加如下内容
# Ash profile
# vim: syntax=sh
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h \W]\# '
PATH=$PATH
HOSTNAME=`/bin/hostname`
export USER LOGNAME PS1 PATH
(3)添加了之后的实验现象:命令行提示符前面显示:[@linux ]#
(1)因为我们之前intttab中有一个配置项 ::askfirst:-/bin/sh,这个配置项作用就是当系统启动后就去执行/bin/sh,执行这个就会出现命令行。因此我们这样的安排就会直接进入命令行而不会出现登录界面。
(2)我们要出现登录界面,就不能直接执行/bin/sh,而应该执行一个负责出现登录界面并且负责管理用户名和密码的一个程序,busybox中也集成了这个程序(就是/bin/login和/sbin/gettty),因此我们要在inittab中用/bin/login或者/sbin/getty去替代/bin/sh。在项目中最常见的用于登录的程序是/sbin/getty。
修改inittab文件:
#first:run the system script file
::sysinit:/etc/init.d/rcS
#::askfirst:-/bin/sh
s3c2410_serial0::respawn:/sbin/getty -L s3c2410_serial2 115200 vt100
::ctrlaltdel:-/sbin/reboot
#umount all filesystem
::shutdown:/bin/umount -a -r
#restart init process
::restart:/sbin/init
(1)linux系统中用来描述用户名和密码的文件是passwd和shadow文件,这两个文件都在etc目录下。passwd文件中存储的是用户的密码设置,shadow文件中存储的是加密后的密码。
(2)我们直接复制ubuntu系统中的/etc/passwd和/etc/shadow文件到当前制作的rootfs目录下,然后再做修改即可。
修改1:在rootfs文件夹下要为root用户创建一个root目录
mkdir root
修改2: vi etc/passwd 把其他非root用户的信息全删除
修改3:在passwd中把默认脚本改为sh(ubuntu中默认是bash,busybox不支持bash,支持sh)
修改4:vi etc/shadow ,把其他非root用户的信息全删除,并且把root用户的密码信息全部删除
(3)/etc/passwd和/etc/shadow修理好后,因为shadow中的加密口令被我们删除了是空的,则默认无密码直接登录。
因为shadow中的加密口令被我们删除了是空的,默认无密码直接登录。因此在登陆之后可以使用passwd root给root用户重新设置密码。
(1)在rootfs目录下创建lib目录
mkdir lib
(2)我们用的arm-2009q3这个交叉编译工具链的动态链接库在/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib目录下。
(3)把这些动态链接库复制到roots/lib目录下,复制时要注意参数用-rdf,主要目的就是符号链接复制过来还是符号链接。
cp lib/*so* /home/lsm/workspace/x210/rootfs/rootfs/lib/ -rdf
(4)使用strip工具去掉库中符号信息
动态链接库so文件中包含了调试符号信息,这些符号信息在运行时是没用的(调试时用的),这些符号会占用一定空间。在传统的嵌入式系统中flash空间是有限的,为了节省空间常常把这些符号信息去掉。这样节省空间并且不影响运行。进入rootfs/lib目录,执行命令:
arm-none-linux-gnueabi-strip *so*
实际操作后发现库文件由3.8M变成了3.0M,节省了0.8M的空间。