文章目录
- 使用工具:
- 前提 :
- 步骤:
- 三 附openssh和dropdear的移植配置如下:
- 四 ERROR
- Kernel panic - not syncing: No init found.
- [ end Kernel panic - not syncing: Requested init /init failed (error -2).
- mount: mounting proc on /proc failed: No such file or directory
- Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
- inetd: ***/***: unknown service
- dropbear,ssh认证通过,登不上账户,除下外没有其它提示信息.
- dropbear,ssh无法免密登录.
使用工具:
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 prefixbusybox里也自带了很多小工具,比如命令自动补齐,ls时文件着色等等都可以自己依需要裁剪。使用默认配置就好,如果要用inetd启动telnetd服务,记得不要勾选Networking Utilities —> [ ] Support standalone telnetd (not inetd only) 。
-
编译 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 debug home anzyelay@ubuntu:myrootfs$ ls -rt bin linuxrc sbin usr var tmp sys proc lib etc dev debug home 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下
首先查找必须库:使用命令readelf -d bin/busybox | grep NEEDED
得到如下信息0x00000001 (NEEDED) 共享库:[libm.so.6] 0x00000001 (NEEDED) 共享库:[libresolv.so.2] 0x00000001 (NEEDED) 共享库:[libc.so.6]
在自己的交叉编译库中寻找这几个库拷贝过来,还要再加上必须的加载库ld-*.so,这样就能保证可以正常启动,但要正常跑其它程序比如inetd,还要拷贝其它库,否则会出现诸如inetd: telnet/tcp: unknown service的错误(在/ect/inetd.conf,/ect/services都配置正确的情况下)。
如下命令。(注:不要全部复过来。其中的.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$ 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
devtmpfs /dev devtmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /var tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
debugfs /debug debugfs defaults 0 0 -
说明 :
- file system :需要挂载的文件系统的所在设备或分区,如果是nfs类则写成:serverIP:/共享目录
注: tmpfs 是一个临时文件系统,驻留于你的交换分区或是内存中(取决于你的使用情况)。使用它可以提高文件访问速度,并能保证重启时会自动清除这些文件。 - mount point :设备挂载目录,需要挂载的文件系统的挂载点
- type :要挂载设备或是分区的文件系统类型
- options:挂载参数(noauto,auto、user、exec、ro、rw)对于大多数系统使用"defaults"就可以4. options:挂载参数(noauto,auto、user、exec、ro、rw)对于大多数系统使用"defaults"就可以
- dump:是否提供备份功能,0为不备份,1为要备份 dump:是否提供备份功能,0为不备份,1为要备份
- pass:是否开机时对文件系统进行检查,该字段被fsck命令用来决定在启动时需要被扫描的文件系统的顺序,根文件系统"/“对应该字段的值应该为1,其他文件系统应该为2。若该文件系统无需在启动时扫描,则设置该字段为0pass:是否开机时对文件系统进行检查,该字段被fsck命令用来决定在启动时需要被扫描的文件系统的顺序,根文件系统”/"对应该字段的值应该为1,其他文件系统应该为2。若该文件系统无需在启动时扫描,则设置该字段为0
- file system :需要挂载的文件系统的所在设备或分区,如果是nfs类则写成:serverIP:/共享目录
-
-
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 #telnet使用此文件系统
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
inetd
/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添加如下:HOSTNAME=`/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
-
新建root用户及组别
先touch /etc/passwd /etc/group
,然后在"/etc/passwd"中加入root:x:0:0:root:/root:/bin/sh
此时命令行提示符立马显示如下信息了:
[root@anzyelay.com:/etc]#
x表示没有密码,不过一般密码也是保存在shadow中,这里不安全.- etc/passwd字段说明:
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell
- etc/group字段说明:
组名:口令:组标识号:组内用户列表
如果需要组别信息可以新建"/etc/group",手动写该文件或直接在开发板上用命令addgroup加入也可用addusr -D -h /usr_home -u 0 usr group
一次性新建好级别用户,如下:[root@bst:/etc]#addgroup root addgroup: /etc/group: No such file or directory [root@bst:/etc]#touch group [root@bst:/etc]#addgroup root [root@bst:/etc]#cat group root:x:1000:
- etc/passwd字段说明:
-
-
配置网络项,允许telnet tftp等.
busybox中可用inetd来启动各项网络服务,切记在busybox配置项中去掉Support standalone telnetd (not inetd only),否则telnet无效,单独运行则可.
inetd需要在/etc中配置两个文件,/etc/inetd.conf 和 /etc/services,可以查看examples中的例程说明.
示例:# <service_name> <sock_type> <proto> <flags> <user> <server_path> <args> telnet stream tcp nowait root telnetd telnetd tftp dgram udp wait root tftpd tftpd -c /tftpboot ftp stream tcp nowait root ftpd ftpd -w -t60 /home ssh stream tcp nowait root dropbear dropbear -B -i -r /etc/rsa_key
inetd 会从inetd.conf 配置项中取得service_name/proto,然后以此到services中取得对应端口号,运行对应服务.要想使用ssh,scp等,需要移植dropbear,或openssh.
dropbear启动参数使用-R参数可在第一次需要时自动生成rsa_key,需要在etc中事先创建dropdear目录。
OK ,初步的根文件系统的移植至些结束,如果要加其它功能移植方法类似,加入依赖库文件,可执行文件,弄好配置文档就OK。触摸屏校准移植在下篇文章中在记录了。下面是错误记录
三 附openssh和dropdear的移植配置如下:
/usr/bin/bash
#first make zlib
export CC=arm-linux-gcc
./configure --prefix=/opt/arm_lib
make && make install
#then make ssl
./Configure linux-armv4 no-asm --prefix=/opt/arm_lib
make && make install
#make openssh(need zlib ssl)
./configure --host=arm-linux --with-zlib=/opt/arm_lib --prefix=/opt/arm_lib
#make dropbear(need zlib)
./configure --host=arm-linux --with-zlib=/opt/arm_lib/ --prefix=/opt/arm_lib/
四 ERROR
-
Kernel panic - not syncing: No init found.
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进程。
-
[ end Kernel panic - not syncing: Requested init /init failed (error -2).
根目录下的是linuxrc,这里启动用的是init,直接
mv linuxrc init
即可 -
mount: mounting proc on /proc failed: No such file or directory
没有proc目录,在目录下mkdir一个就行了。
-
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居然出错.如下
,明明有这个头文件,就是出错,查不出来了, 给跪了,这嵌入式移植真麻烦.安心用厂家提供的编译器吧…
单独执行inet出错如下:
inetd: telnet/tcp: unknown service
inetd: tftp/udp: unknown service
inetd: ftp/tcp: unknown service
inetd: ssh/tcp: unknown service
这是因为inetd取不到对应的端口号,1.查看是否有**/etc/services ** 文件,2.查看是否缺失动态库libnss*.so
[325] Jul 04 20:31:54 Failed loading /etc/dropbear/dropbear_dss_host_key
[325] Jul 04 20:31:54 Not backgrounding
[326] Jul 04 20:31:56 Child connection from 192.168.2.126:59054
[326] Jul 04 20:31:56 /root must be owned by user or root, and not writable by others
[326] Jul 04 20:31:58 Password auth succeeded for 'root' from 192.168.2.126:59054
[326] Jul 04 20:32:04 syslogin_perform_logout: logout(pts/0) returned an error: No such fiy
[326] Jul 04 20:32:04 Exit (root): Disconnect received
查找一翻,是passwd里的账户错误,对应账户没有创建对应的目录.