1. 安装isolinux
$mkdir -p isolinux-test/isolinux
下面复制的文件从syslinux的源码目录中来,可能需要编译。
$cp core/isolinux.bin isolinux-test/isolinux
$cp com32/menu/menu.c32 isolinux-test/isolinux
$cat > isolinux.cfg <<EOF
>UI menu.c32
>label isolinux-test
> menu label isolinux-test
>EOF
$genisoimage -no-emul-boot -boot-info-table -boot-load-size 4 \
>-o isolinux-test.iso -b isolinux/isolinux.bin -c isolinux/boot.cat \
>isolinux-test
上面命令创建一个可以启动的ISO, -c参数是可选的,如果没有指定,那么将
在ISO的根目录下生成boot.catalog文件。
$qemu -M pc -cdrom isolinux-test.iso -boot d
应该可以看到虚拟机从光盘启动,并且显示了isolinux的启动菜单。
选择启动后会发现系统不能启动,这是因为没有可以启动的系统内核。
2. 安装可启动的Linux内核
isolinux做为一个bootloader,可以很方便的配置可以启动的内核。
$cp /boot/vmlinuz isolinux-test/isolinux
$cp /boot/initrd isolinux-test/isolinux
复制kernel和initramfs文件,这两个文件可以直接从系统/boot目录下获得,
注意内核架构应该和将要模拟的一致,这里我们模拟的是pc,在qemu中默
认为i686,如果kernel在编译时已经包含了正确的initramfs,那么可以不复
制相应的initramfs文件。现在,应该修改isolinux的配置文件,让其启动
kernel。
$cat >> isolinux-test/isolinux/isolinux.cfg <<EOF
> kernel vmlinuz
> append initrd=initrd root=CDLABEL=isolinux-test rootfstype=iso9660 ro
>EOF
然后,使用genisoimage创建ISO文件。
$genisoimage -no-emul-boot -boot-info-table -boot-load-size 4 \
>-o isolinux-test.iso -b isolinux/isolinux.bin -c isolinux/boot.cat \
>-V "isolinux-test" isolinux-test
最后,用qemu模拟虚拟机
$qemu -M pc -cdrom isolinux-test.iso -boot d
启动虚拟机后,可以看到虚拟机可以正常启动,但是最后由于没有可以挂载
的根文件系统,虚拟机进入initramfs提供的shell环境。
3. 创建可以运行的ISO系统
自己创建一个可以运行的ISO系统比较复杂,主要的复杂性在系统启动阶段,initramfs要能够正确的引导系统,分析ISO文件中的内容,正确的挂载文件系统,还要使根文件系统可写,这可以使用device mapper的snapshot和aufs等来实现。
4. 让ISO可以直接写入U盘启动
syslinux提供的isobybrid工具可以让ISO直接写入U盘进行启动,直接运行
$isohybrid image.iso即可。
5. linux-live和aufs
linux-live项目让Linux live CD/USB变得可写,可以存储用户数据,从而变得非常易用,linux-live只是一些列脚本,通过aufs来实现可写。基本思想是利用aufs可以将不同的文件系统分支挂载到同一地点,例如,ISO是只读的,如果将它和另一个可写的文件系统挂载在一起,那么对ISO的写入将会通过COW存储在另一个可写文件系统中。如果能够让挂载后的aufs成为Live CD/USB的根文件系统,那么表面上只读的Live CD/USB就变成了可以保存持久化数据的可写文件系统,许多Live CD都使用aufs和tmpfs来实现读写,但是由于tmpfs存储在内存中,所以一般的LiveCD不能将数据持久化,而Linux-Live的目标正是如此。这里有一个简单的aufs使用的例子,从aufs文档而来
$ mkdir /tmp/rw/tmp/aufs
# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs
在/tmp/aufs中可以读写文件,但是$HOME目录却没有任何改变,而在/tmp/rw目录下可以发现所做的修改。
另外,也有一些Live CD/USB使用device mapper来实现文件系统可写,使用device mapper的snapshot机制即可,例如MeeGo。
6. meego-netbook ISO分析
/isolinux/initrd/init
1. 创建和挂载虚拟文件系统,例如udev, devpts, proc, sysfs等,建立设备文件。
2. 检查/etc/fstab,获取根文件系统挂载信息,如果为/dev/root,则从启动参数中获取,这也就是isolinux.cfg中传递的root=CDLABEL="LABEL" rootfstype=iso9660信息,挂载的选项rootflags为空,即默认。
3. 分析根设备,添加一条udev规则,然后建立链接/dev/root指向真正的根设备。
4. 启动udevd守护进程,触发udev。
5. 判断是否为runlevel 1,如果是,则进入bash。
6. 挂载CDROM到/sysroot。
7. 查找CDROM上的根文件系统,然后losetup,将其挂载到/sysroot,由于根文件系统在CDROM中,所以是只读的,使用device mapper在内存中创建一个根文件系统的snapshot,然后将重新挂载到/sysroot,这时,根文件系统变得可写。所有的写入都通过COW机制发生在snapshot中。
8. 现在/sysroot就可读写了,设置locale和复制modprobe.conf,创建udev rules。最后重新挂载/sysroot为只读。这里不要疑惑,因为在进入根文件系统执行/sbin/init后,sysvinit然后才会将根文件系统挂载为可读写。
9. 杀死udevd然后chroot到根文件系统中并执行init程序。
10. 使用device mapper的snapshot机制让只读文件系统可写例子。
#mkdir /tmp/ISO
#mount -o loop meego-netbook-VERSION.img /tmp/ISO
#mkdir /tmp/squashfs
#mount -o loop /tmp/ISO/LiveOS/squashfs.img/tmp/squashfs
#mkdir /tmp/rootfs
#mount -o loop /tmp/squashfs/LiveOS/ext3fs.img/tmp/rootfs
#mount 可以看到mount包括如下几行输出。
/dev/loop0 on /tmp/ISO type iso9660 (rw)
/dev/loop1 on /tmp/squashfs type squashfs (ro)
/dev/loop2 on /tmp/rootfs type ext3 (ro)
尽管显示/tmp/ISO为rw,但是由于iso9660本身是一个只读文件系统,所以不可写。现在光盘中的根文件系统已经挂载到了/tmp/rootfs中,现在要让它变得可写。
#umount /tmp/rootfs
#losetup -f /tmp/squashfs/LiveOS/ext3fs.img
#dd if=/dev/zero of=/snapshot.disk bs=4k count=25000
#losetup -f /snapshot.disk
#echo "0 `blockdev --getsize /dev/loop2` snapshot /dev/loop2/dev/loop3 p 8" | dmsetup create rootfs-rw
在上面的命令中,/dev/loop2是ext3fs.img的loopback设备,/dev/loop3是/snapshot.disk的loopback设备,可以使用
#losetup -a来查看。
#mkdir /tmp/rootfs-rw
#mount /dev/mapper/rootfs-rw/tmp/rootfs-rw
#touch /tmp/rootfs-rw/test.file
可以看到,现在rootfs变成可写的了。