wq1977 发表于 2004-12-10 17:10:26

也来谈LiveCD的制作

经过几天的研究,写了几页豆腐,如今也来这里酸一酸,因为贴图不太方便,所以只在这里摘录前面一截,感兴趣的朋友可以下载附件中的pdf文档观看,谢谢.

另外,在这里下PDF版本:

http://mypretty.nease.net/livecd/LiveCD_Study.pdf

看的会舒服点,呵呵.

前言—为什么要写这篇文档.
整整三天的时间,为了搞清楚linux的启动机制,回过头来看看,一切似乎非常的简单. 可是当这样的事情要由一个人独立的没有任何基础的去研究的时候,就会走很多的弯路.经过这充实的三天,我知道了一些原先不知道或者不清楚的事,我对linux系统的认识又清晰的许多.
现在,假定你还不知道我已经知道的那些,你不必象我一样,通过Google和反复的修改脚本,反复的制作光盘,反复的重启来搞清楚这些,你只需要读我写的这篇文档. 按照文中所说的步骤(这些步骤非常的清晰,所使用的东西也随手可得),你便可以很快的回答以下这些问题:
关于用Grub制作启动光盘的知识.
关于制作Initrd的知识.
制作一个什么都不能做的LiveCD.
其它的一些我有提到但是忘记了写在这里的知识.
如果你喜欢Linux,如果你觉得这篇文档能让你知道了一些你以前不知道并且想知道的,或者仅仅是因为个人感情的原因对作者投以支持的目光,作者便会觉得如坐春风了,这就是写这篇文档的目的.
当然,作者是从一无所知到现在的略有所知,所以肯定会有理解偏颇甚至错误的地方,在大方那里难免被贻笑,也请大家鸡蛋不要仍的太多,但是绝对欢迎批评指正,免的误导更多的人,小弟的罪过就大了.
好了,废话说太多了,赶紧启动你的FedoraCore3吧.
制作Grub启动光盘
LiveCD首先是一个可以自启动的光盘,通常现有的LivdCD使用的都是ISOLinux1 的技术,其实使用Grub也可以制作可以启动的光盘.以下片断参考自Grub的Info文档:
$ mkdir iso# 新建一个iso目录,这将作为LiveCD的镜像目录.
$ mkdir -p iso/boot/grub #在iso目录中创建boot/grub子目录,这其实和你的FedoraCore3的/boot结构是一样的.
$ cp /usr/share/grub/i386-redhat/stage2_eltorito iso/boot/grub #i386-redhat这个目录名字可能不同.2
$ mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \
   -boot-load-size 4 -boot-info-table -o teach.iso iso#制作以iso目录为镜像目录的启动光盘.3
现在生成了teach.iso文件,打开Vmware,新建一个linux虚拟机,将光盘指定成新生成的teach.iso,如下图所示:
启动这个VirtualMachine, 在系统自检的时候摁F2进入Bios,修改成从光盘启动
,如下图所示
摁F10存盘退出后重新启动, 启动结果如下图所示:
系统已经启动到grub提示符的状态, 这时候我们可以输入后续grub命令来启动系统.

Ok,让我们重新回到FedoraCore3, 拷贝我们需要的文件到iso,以便我们的LiveCD可以走的更远:
$cp /boot/vmlinuz-2.6.9-1.667 iso/boot/   #拷贝系统内核到iso的boot目录
$ mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \
   -boot-load-size 4 -boot-info-table -o teach.iso iso#重新生成我们的iso文件

现在重新启动我们的VirtualMachine,在Grub提示符下依次敲入如下命令:
grub> root (cd)
grub> kernel /boot/vmlinuz-2.6.9-1.667
grub> boot
如下图所示:
没错,我们的liveCD又往前走了很多,可以看到kernel被启动,很多的提示信息,不过在kernel启动的最后,出现了错误:
这是因为kernel启动到最后,找不到init程序,也找不到root文件系统导致.接下来,我们要制作 initrd.img这个虚拟镜像文件了.

在制作initrd.img之前,我们不妨先在iso/boot/grub目录下创建一个grub.conf(按照grub的手册,这个文件好像应该叫做menu.lst)文件,以避免我们每次重新启动liveCD的时候都要输出一堆grub命令. 参考/boot/grub/grub.conf.
grub.conf 的文件内容可以如下所示(As your wish):
#grub.conf start *********************************
default 0
timeout 1
hiddenmenu
title LiLiHome
      root (cd)
      kernel /boot/vmlinuz-2.6.9-1.667 quiet
#grub.conf end *********************************
这个文件告诉grub,启动的时候默认启动第一个title, 等待时间是1秒钟,不要显示选择菜单,第一个Title的名字是LiLiHome(^_^,as your wish),依次执行的命令是 root ...和kernel ...,其中quiet参数告诉kernel启动的时候不要显示那一堆无所谓的信息,我只是个初级的fans,对这些输出并不关心.
重新制作我们的iso文件,不会再出现grub提示符,而是直接启动指定的kernel了.

我们以后还会回来修改grub.conf的,现在,让我们先来做initrd.img吧.

制作Initrd.img
为什么要制作initrd,img? 我们的这个initrd.img要完成什么功能?
Initrd可以让kernel分成两个步骤启动,第一个步骤加载一个比较小的kernel,其中可能不包括在编译kernel的时候编译成module的那些模块,第二个步骤中可以加载这些模块并且完成一些最小系统的初始化.Linux的文档是这么说的.不过我们的initrd只是帮我们完成一个小任务,找到光盘.
以下的这些操作中的一部分需要你拥有root权限,所以,现在我们最好su一把,让我们自己变成root.
$ su #输入密码,变成root(牛气的root)
# mkdir initrd #创建一个initrd的目录,我们会把initrd.img挂载到这个目录
# dd if=/dev/zero of=initrd.img bs=400k count=10 #创建一个4M的initrd.img
# /sbin/mke2fs -F -m0 initrd.img   # 将initrd.img初始化成ex2文件系统
# mount -o loop initrd.imginitrd# 将initrd.img挂载到initrd上
# mkdir initrd/dev                        #在initrd目录(也就是initrd.img文件)中创建/dev目录
# mknod initrd/dev/console c 5 1    # 增加一个控制台节点1. 事实上,需要.

initrd作为kenerl的出口,可以是一个普通的ex2文件系统的压缩文件(并非一定如此),kernel会寻找initrd中的linuxrc文件(这个文件一定要是可以执行的,可以是shell脚本),然后执行它.

下面的工作,我们会增加initrd.img的核心部分,不过不要着急,在这之前让我们先修改我们的grub.conf2文件,增加需要的内容,按照linux文件,如果要使用initrd.img,grub.conf应该这样修改:
grub.conf 的文件内容可以如下所示(As your wish):
#grub.conf start *********************************
default 0
timeout 1
hiddenmenu
title LiLiHome
      root (cd)
      kernel /boot/vmlinuz quiet root=/dev/ram0 rwinit=/linuxrc
      initrd /boot/initrd.img
#grub.conf end *********************************
这其中除了quiet参数你可以随便以外,别的最好不要修改,尽管有些参数不是必须的.
好了,我们来往initrd.img里面增加内容吧:
# mkdir initrd/bin   # 增加bin目录
# cp /bin/bash initrd/bin/ #要运行脚本,当然需要bash(任何一个shell包括busybox3都可以)
# ldd /bin/bash#看看我们的bash需要哪些动态链接库
      libtermcap.so.2 => /lib/libtermcap.so.2 (0x005b1000)
      libdl.so.2 => /lib/libdl.so.2 (0x004c0000)
      libc.so.6 => /lib/tls/libc.so.6 (0x00372000)
      /lib/ld-linux.so.2 (0x00359000)
# mkdir initrd/lib #看来我们需要lib目录了
# ls -l /lib/libtermcap.so.2#看看我们需要的第一个动态链接库是不是个链接
        lrwxrwxrwx1 root root 24 12?9 14:10 /lib/libtermcap.so.2 -> /lib/libtermcap.so.2.0.8
# cp /lib/libtermcap.so.2.0.8 initrd/lib/#果然是个链接,要拷贝真正的文件而不是一个符号哦.
# cd initrd/lib
# ln -s libtermcap.so.2.0.8 libtermcap.so.2#当然符号还是要建的.
......   # 依次操作后面的几个库吧.

好,假定你读到这里的时候,所有需要的库已经拷贝到lib目录了,我们需要检验一下新的bash能不能够运行.
# /usr/sbin/chroot initrd bash   #试着执行一下拷贝过去的bash,注意要chroot
bash-3.00#    #出现了提示符,说明需要的库我们都拷贝全了.
bash-3.00# exit#退回到原来的提示符下
# cd initrd/bin   # 去initrd的bin目录
# ln -s bash sh   # 建立 sh符号链接到bash.
好了,我们来测试一下我们的initrd.img. 退回到initrd的上一级目录.
# vi initrd/linuxrc#我们来建立一个linuxrc
        #!/bin/sh
        echo 'Hellow World!'
        sh
# chmod a+x initrd/linuxrc#给予linuxrc可执行属性
# cp /bin/echo initrd/bin/   #既然我们的linuxrc中用到了echo,那么拷贝吧
# ldd /bin/echo        #看看echo需要的库我们都有吗?
      libc.so.6 => /lib/tls/libc.so.6 (0x00372000)
      /lib/ld-linux.so.2 (0x00359000)
...... #如果有我们没有的,拷贝之.

好了现在我们的initrd已经不是一个空空的文件了.我们试一下它可不可以执行.
先确定你的grub.conf已经修改.然后
# umount initrd                #确保
# cp initrd.img iso/boot/
# gzip -9 iso/boot/initrd.img
# mv iso/boot/initrd.img.gz iso/boot/initrd.img
# mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \
   -boot-load-size 4 -boot-info-table -o teach.iso iso#重新生成我们的iso文件

好了,重新启动虚拟机,看看现在的情况怎么样:
看看现在的initrd.img的目录结构:


现在我们可以知道,initrd.img也是一个小的linux系统,我们可以把我们想要拷贝的程序及其库拷贝进去,然后使用根目录下的linuxrc来调度就可以了.

接下来,我们要完善linuxrc脚本,通过使用udev挂载我们的iso文件. 因为毕竟ramdisk1有大小限制,默认的kernel启动支持的ramdisk的大小是4M, 而无论我们要做的东西是什么,4M都是远远不够的.
此处申明,下文讲述的脚本文件修改自gentoo的安装文件,希望不会有人因此找我的麻烦.

为了寻找cdrom,我们要做的核心,是通过udev2这个模块,将系统中所有存在的光驱映射到/dev/cdroms/目录下,分别命名为cdrom0,cdrom1...,然后我们将依次挂载这些光驱设备,直到找到我们自己的liveCD:
mount -t sysfs none /sys               
cd /sys
kill_devfsd
echo 'Checking your hardware, please wait...'
runUdev
mv /dev/* /newroot/dev
findcdmount /newroot/dev/cdroms/*
关于udev的细节请读者自行参阅相关的资料,我也只能大概的说,udev通过/sys目录找到kernel发现的硬件以及相关的信息,将其转换成特定字段的值,然后通过udev的配置文件指定的宏,在指定的位置生成(或者删掉)指向这个硬件的节点文件.所以,如上面引用的脚本所示,使用udev之前要先挂载sys目录,删除老的devfsd,对每个sys中的设备尝试匹配他自己的配置脚本, 然后使用mv命令将发现的放置与/dev的设备移动到新的dev目录,然后依次尝试挂载光驱.
你可以通过man udev或者info udev获得更多关于udev的知识.
在成功挂载上LiveCD以后,就可以建立由根目录到liveCD的链接,这时候我们大概会重建整个文件系统,新建一个newroot目录,然后将liveCD中的bin,sbin,lib,boot,usr,opt目录符号链接到当前的newroot目录,将liveCD中的etc root home var这些目录拷贝到newroot目录(这些目录可能会进行写操作),然后更改根目录,根据initrd.txt卸载initrd的相关目录,参考:
ln -s mnt/livecd/bin bin
ln -s mnt/livecd/sbin sbin
ln -s mnt/livecd/lib lib
ln -s mnt/livecd/lib64 lib64
ln -s mnt/livecd/boot boot
ln -s mnt/livecd/usr usr
ln -s mnt/livecd/opt opt
mkdir initrd proc
chmod 1777 tmp
(cd /newroot/mnt/livecd; cp -a etc root home var /newroot)
pivot_root . tmp/.initrd
exec chroot . /bin/sh <<- EOF
        umount /tmp/.initrd || echo "*: Failed to unmount the initrd!"
        /sbin/blockdev --flushbufs /dev/ram0 >/dev/null 2>&1
        exec /sbin/init ${REAL_INIT}
EOF
好了关于initrd就说这么多了.希望对你有些帮助.接下来大概看看LiveCD的主目录.

bigcat00 发表于 2004-12-10 17:21:57

没啦?? :shock:
页: [1]
查看完整版本: 也来谈LiveCD的制作