- 23
- 10月
Initramfs是一个压缩过的cpio文件,可用于引导Linux系统、引导LIVECD、也可以 用于系统安装等。
本文介绍如何构建基于Busybox的Initramfs。
Busybox 是一个功能强大的工具集,包含了常用的Linux命令,在嵌入式设备上用得 比较多,因为体积小巧。当然,Busybox也可以用来引导Linux系统和LIVECD,不过 不能引导LVM卷,因为mdev识别不了。
1 Busybox
Busybox最新稳定版是1.22.1。
1.1 下载
$ wget http://busybox.net/downloads/busybox-1.22.1.tar.bz2
1.2 配置
$ tar xf busybox-1.22.1.tar.bz2
$ cd busybox-1.22.1
$ make defconfig
$ make menuconfig
执行 make menuconfig 之后,把下面几个选项选上:
Busybox Settings:- General Configuration -> Don't use /usr- General Configuration -> Show verbose applet usage messages- General Configuration -> Runtime SUID/SGID configuration via /etc/busybox.conf- Build Options -> Build BusyBox as a static binary (no shared libs)
注解
defconfig - set .config to largest generic configuration
就是最大化选用通用的功能
1.3 编译及安装
$ make
$ make install
执行 make install 之后,会生成一个 _install 目录,里面就是 编译后Busybox,包含 bin 、 sbin 、 及 linuxrc 软链接。这个目 录的内容可以直接复制到下面制作initramfs的目录。
警告
这里假设initramfs的根目录是 /tmp/initramfs/ 。
$ cp -r _install/* /tmp/initramfs/
到这里,编译Busybox的工作就算是完成了。
2 Initramfs
2.1 文件结构
经过上面的步骤之后,现在来看看initramfs根目录( /tmp/initramfs/ )的结 构,应该是这样子的:
├── bin
├── linuxrc -> bin/busybox
└── sbin
下面我们需要创建一个可执行文件 init ,这是一个Shell脚本。
2.2 init文件
init 起到承上启下的作用。内核加载完成之后,就会执行这个文件,在这个 文件,可以执行相关命令,最后挂载要启动的文件系统,并切换执行目标系统的 /sbin/init 文件,开始引导真实的Linux系统。
为了简单,这里直接贴出源代码,流程也相对比较简单。
#!/bin/sh
echo "Loading, please wait..."
export PATH="/bin:/sbin"
[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir --mode=0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
[ -d /mnt ] || mkdir /mnt
# Mount /proc and /sys:
mount -n proc /proc -t proc
mount -n sysfs /sys -t sysfs
# Note that this only becomes /dev on the real filesystem if udev's scripts
# are used; which they will be, but it's worth pointing out
#mount -t tmpfs -o mode=0755 udev /dev
[ -e /dev/console ] || mknod /dev/console c 5 1
[ -e /dev/null ] || mknod /dev/null c 1 3
echo /sbin/mdev >/proc/sys/kernel/hotplug
mdev -s
# Get real root device by LABEL or UUID
get_root() {
if [ ! -z "$LABEL" ]; then
ROOT=`blkid | sed -n "/$LABEL/p" | cut -d: -f 1`
fi
if [ ! -z "$UUID" ]; then
ROOT=`blkid | sed -n "/$UUID/p" | cut -d: -f 1`
fi
}
for x in $(cat /proc/cmdline); do
case $x in
init=*)
init=${x#init=}
;;
root=*)
ROOT=${x#root=}
case $ROOT in
LABEL=*)
LABEL=${ROOT#LABEL=}
;;
UUID=*)
UUID=${ROOT#UUID=}
;;
/dev/nfs)
[ -z "${BOOT}" ] && BOOT=nfs
;;
esac
;;
rootflags=*)
ROOTFLAGS="-o ${x#rootflags=}"
;;
rootfstype=*)
ROOTFSTYPE="${x#rootfstype=}"
;;
rootdelay=*)
ROOTDELAY="${x#rootdelay=}"
;;
resumedelay=*)
RESUMEDELAY="${x#resumedelay=}"
;;
loop=*)
LOOP="${x#loop=}"
;;
loopflags=*)
LOOPFLAGS="-o ${x#loopflags=}"
;;
loopfstype=*)
LOOPFSTYPE="${x#loopfstype=}"
;;
cryptopts=*)
cryptopts="${x#cryptopts=}"
;;
nfsroot=*)
NFSROOT="${x#nfsroot=}"
;;
netboot=*)
NETBOOT="${x#netboot=}"
;;
ip=*)
IPOPTS="${x#ip=}"
;;
boot=*)
BOOT=${x#boot=}
;;
resume=*)
RESUME="${x#resume=}"
;;
noresume)
NORESUME=y
;;
panic=*)
panic="${x#panic=}"
;;
quiet)
quiet=y
;;
ro)
readonly=y
;;
rw)
readonly=n
;;
debug)
debug=y
exec >/tmp/initramfs.debug 2>&1
set -x
;;
debug=*)
debug=y
set -x
;;
break=*)
break=${x#break=}
;;
break)
break=premount
;;
0|1|2|3|4|5|6)
RUNLEVEL=$x
;;
esac
done
for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16;
do
echo "Mounting the ROOT DEVICE (Time $t) ..."
get_root $ROOT
mount -o ro $ROOT /mnt
mountpoint -q /mnt && break
echo "Sleep 4s ..."
sleep 4
done
if [ -e /mnt/sbin/init ] ;
then
umount /proc
umount /sys
exec switch_root /mnt /sbin/init $RUNLEVEL
fi
/bin/sh -i
别忘记给 init 加上执行权限:
$ chmod +x init
现在文件结构应该是这样的:
├── bin
├── init
├── linuxrc -> bin/busybox
└── sbin
到这里,initramfs已经构建好了,下面进行打包及压缩。
注解
关于mdev的几点说明:
mdev不支持LVM卷
mdev支持USB设置热插拨,不过需要把HOTPLUG及USB_STORAGE支持及驱动编 译进内容,而不是编译成模块。
Bus options (PCI, PCMCIA, EISA, MCA, ISA) -> PCI Hotplug SupportDevice Drivers -> USB support
2.3 打包压缩
使用下面这个命令就可以完成打包压缩工作:
$ find . | cpio -o -H newc | gzip -9c > ../initrd.gz
现在, /tmp/initrd.gz 就是制作好的initramfs。