--浅析Linux的启动过程
制作及测试环境: FedoraCore3 Vmware 4.5.1 Build 7568 in WinXp
内容目录
第一章 前言—为什么要写这篇文档. ................................................................................................. 1 第二章 制作Grub启动光盘 ............................................................................................................... 1 第三章 制作Initrd.img ........................................................................................................................ 6 第四章 制作LiveCD镜像目录......................................................................................................... 11 第五章 开始而不是结束 ................................................................................................................... 11 第六章 参考文档............................................................................................................................... 11 第七章 附录 ...................................................................................................................................... 11
第1章 前言—为什么要写这篇文档.
整整三天的时间,为了搞清楚linux的启动机制,回过头来看看,一切似乎非常的简单. 可是当这样的事情要由一个人的没有任何基础的去研究的时候,就会走很多的弯路.经过这充实的三天,我知道了一些原先不知道或者不清楚的事,我对linux系统的认识又清晰的许多.
现在,假定你还不知道我已经知道的那些,你不必象我一样,通过Google和反复的修改脚本,反复的制作光盘,反复的重启来搞清楚这些,你只需要读我写的这篇文档. 按照文中所说的步骤(这些步骤非常的清晰,所使用的东西也随手可得),你便可以很快的回答以下这些问题: 关于用Grub制作启动光盘的知识. 关于制作Initrd的知识.
制作一个什么都不能做的LiveCD.
其它的一些我有提到但是忘记了写在这里的知识.
如果你喜欢Linux,如果你觉得这篇文档能让你知道了一些你以前不知道并且想知道的,或者仅仅是因为个人感情的原因对作者投以支持的目光,作者便会觉得如坐春风了,这就是写这篇文档的目的.
当然,作者是从一无所知到现在的略有所知,所以肯定会有理解偏颇甚至错误的地方,在大方那里难免被贻笑,也请大家鸡蛋不要仍的太多,但是绝对欢迎批评指正,免的误导更多的人,小弟的罪过就大了.
好了,废话说太多了,赶紧启动你的FedoraCore3吧.
第2章 制作Grub启动光盘
LiveCD首先是一个可以自启动的光盘,通常现有的LivdCD使用的都是ISOLinux1 的技术,其实使用Grub也可以制作可以启动的光盘.以下片断参考自Grub的Info文档:
1 http://syslinux.zytor.com/iso.php
$ 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,如下图所示:
2 找不到stage2_eltorito 吗?它一定在你的FedoraCore3安装光盘的某一个RPM包中,找找看.不过你不应该找不到的.
3 怎么,又找不到 mkisofs吗? 天哪,它一定在你的FedoraCore3安装光盘的某一个RPM包里,或者你可以上网找呀,拜托不要再问这种问题了.
启动这个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吧.
第3章 制作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.img initrd # 将initrd.img挂载到initrd上 # mkdir initrd/dev
initrd作为kenerl的出口,可以是一个普通的ex2文件系统的压缩文件(并非一定如此),kernel会寻找initrd中的linuxrc文件(这个文件一定要是可以执行的,可以是shell脚本),然后执行它.
下面的工作,我们会增加initrd.img的核心部分,不过不要着急,在这之前让我们先修改我们的grub.conf5文件,增加需要的内容,按照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 rw init=/linuxrc initrd /boot/initrd.img
4 当然不是非这样做不可,可是为什么不呢,反正又没有什么坏处------参见Linux的文档. 5 你不知道这是什么文件吗?天哪,难道你是倒着看的吗?
#在initrd目录(也就是initrd.img文件)中创建/dev目录
# mknod initrd/dev/console c 5 1 # 增加一个控制台节点4. 事实上,需要.
#grub.conf end *********************************
这其中除了quiet参数你可以随便以外,别的最好不要修改,尽管有些参数不是必须的. 好了,我们来往initrd.img里面增加内容吧: # mkdir initrd/bin # 增加bin目录
# cp /bin/bash initrd/bin/ #要运行脚本,当然需要bash(任何一个shell包括busybox6都可以) # 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 #看看我们需要的第一个动态链接库是不是个链接
lrwxrwxrwx 1 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,那么拷贝吧
6 http://www.busybox.net/
# 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文件
好了,重新启动虚拟机,看看现在的情况怎么样:
Hi,朋友,你一切都还好吧.我已经快把自己搞崩溃了,所幸挺到了现在,不过,我们还有一段不短的路要走.
看看现在的initrd.img的目录结构:
现在我们可以知道,initrd.img也是一个小的linux系统,我们可以把我们想要拷贝的程序及其库拷贝进去,然后使用根目录下的linuxrc来调度就可以了.
接下来,我们要完善linuxrc脚本,通过使用udev挂载我们的iso文件. 因为毕竟ramdisk7有大小,默认的kernel启动支持的ramdisk的大小是4M, 而无论我们要做的东西是什么,4M都是远远不够的.
此处申明,下文讲述的脚本文件修改自gentoo的安装文件,希望不会有人因此找我的麻烦.
为了寻找cdrom,我们要做的核心,是通过udev8这个模块,将系统中所有存在的光驱映射到
/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目录找到
7 Sorry,忘了说了,我们一直在用ramdisk,虽然你不曾感觉,看看grub.conf,就会知道initrd.img挂载哪里. 8 http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
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/lib lib 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的主目录.
第4章 制作LiveCD镜像目录
前面说过,通过initrd.img,我们可以成功的把LiveCD挂载到某个目录上,然后我们便可以访问LiveCD上的任何数据,例如我们可以直接在LiveCD上建立类linux的结构,包括基本的
bin,sbindev,lib等等目录,把需要的文件拷贝到LiveCD上(如果你喜欢并且空间允许,你甚至可以把你的整个FedoraCore3拷贝到LiveCD上去),你也可以建立别的文件系统的镜像文件,比如你可以把需要的目录结构压缩在另外一个iso文件中,把这个iso文件存放在你的LiveCD上,等到你的LiveCD被挂载以后,你可以继续挂载LiveCD中的这个文件,然后映射新的文件系统,或者将其拷贝到硬盘或者内存上再挂载以提高效率. 这里简单起见,我采用的是第一种方式,直接在LiveCD上建立目录结构(这可能是最差劲的方法).
在上面initrd.img运行的最后,调用/sbin/init执行真正的初始化进程.这是一个标准的init程序,它读取/etc/inittab进行系统的初始化.inittab文件大概的格式如下:
id:5:initdefault: #表明系统默认运行级别为5
si::sysinit:/etc/rc.d/rc.sysinit #任何级别的初始化都应改最先运行这个脚本 ...... #后面定义了各个运行级别依次运行的脚本文件 sh
我们只是Demo一个什么都不能做的LiveCD,所以更改rc.sysinit为:
第5章 开始而不是结束
好了,这个文档到这里结束了,但是这只是整个linux系统的开始,才刚刚开始看到init.更艰苦的路还在后面.
第6章 参考文档
/usr/src/linux/Documentation/initrd.txt man udev info grub
gentoo//install-x86-minimal-2004.3.iso/isolinux/gentoo.igz
第7章 附录
Initrd.img文件清单:
initrd:
bin dev etc lib linuxrc lost+found proc sbin sys initrd/bin:
bash cat chmod cp echo ln mkdir mknod mount mv rm sh umount initrd/dev:
console null zero initrd/etc:
fstab mtab udev
initrd/etc/udev:
permissions.d rules.d scripts udev.conf initrd/etc/udev/permissions.d: 50-udev.permissions initrd/etc/udev/rules.d: 50-udev.rules initrd/etc/udev/scripts: ide-devfs.sh initrd/lib:
ld-linux.so.2 libdl-2.3.3.so libproc-3.2.3.so tls
libacl.so.1 libdl.so.2 libselinux.so.1 libattr.so.1 libncursesw.so.5.4 libtermcap.so.2 initrd/lib/tls:
libc-2.3.3.so libc.so.6 libpthread.so.0 librt.so.1 initrd/lost+found: initrd/proc: initrd/sbin:
chroot pivot_root udev initrd/sys:
linuxrc文件内容:
#!/bin/sh
echo 'Hellow World!'
PATH=/usr/sbin:/usr/bin:/sbin:/bin BACK_UP=\"\\033[1K\\033[0G\" NORMAL=\"\\033[0m\" WARN=\"\\033[33;1m\" BAD=\"\\033[31;1m\" BOLD=\"\\033[1m\" GOOD=\"\\033[32;1m\"
REAL_ROOT=''
backup() {
echo -ne \"\\033[0G\\033[0K\" }
kill_devfsd() {
killall devfsd > /dev/null 2>&1 }
runUdev() {
export ACTION=add export UDEV_NO_SLEEP=1 export UDEV_NO_DEVD=1
# Add block devices and their partitions to /dev, # using information from /sys, and only those # devices (since other are not needed for boot).
# We also do VC's for keymap support.
for x in block/* do done
for x in class/tty do done cd /
unset -v ACTION DEVPATH UDEV_NO_SLEEP
for y in ${x}/* do done
if [ -f \"${y}/dev\" ] then fi
export DEVPATH=\"/${y}\" /sbin/udev class
export DEVPATH=\"/${x}\" /sbin/udev class for y in ${x}/* do done
if [ -f \"${y}/dev\" ] then fi
export DEVPATH=\"/${y}\" /sbin/udev block
export DEVPATH=\"/${x}\" /sbin/udev block
}
findcdmount() { if [ \"$#\" -gt \"0\" ] then fi }
mount -o remount,rw / mount -t proc proc /proc
[ -n \"$QUIET\" ] && echo '0' > /proc/sys/kernel/printk
mkdir /newroot
mount -t tmpfs tmpfs /newroot
mkdir /newroot/dev /newroot/mnt /newroot/mnt/cdrom /newroot/mnt/livecd /newroot/tmp /newroot/tmp/.initrd /newroot/mnt/gentoo /newroot/sys
mount -t sysfs none /sys cd /sys kill_devfsd
echo 'Checking your hardware, please wait...' runUdev
mv /dev/* /newroot/dev
findcdmount /newroot/dev/cdroms/*
[ \"${REAL_ROOT}\" = '' ] && findcdmount /newroot/dev/ide/cd/*
done
if [ \"${REAL_ROOT}\" != \"\" ] then fi
echo -e \"${GOOD}>>${NORMAL} CD medium found on ${x}\" if [ \"$?\" = '0' ] then fi
REAL_ROOT=\"${x}\" break
for x in $* do
echo -e \"${GOOD}>>${NORMAL} Attempting to mount CD:- ${x}\" mount ${x} /newroot/mnt/livecd -t iso9660 -r > /dev/null 2>&1
[ \"${REAL_ROOT}\" = '' ] && findcdmount /newroot/dev/sr0
if [ \"${REAL_ROOT}\" = '' ] then # Undo stuff
umount /newroot/dev 2>/dev/null umount /newroot/sys 2>/dev/null umount /sys 2>/dev/null umount /newroot rm -rf /newroot/*
echo 'Could not find CD to boot, something else needed!' sh fi
cd /newroot
echo -e \"${GOOD}>>${NORMAL}${BOLD} Filling filesystem...${NORMAL}\" ln -s mnt/livecd/bin bin ln -s mnt/livecd/sbin sbin ln -s mnt/livecd/lib lib ln -s mnt/livecd/lib lib 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)
[ ! -e /newroot/dev/console ] && mknod /newroot/dev/console c 5 1 echo -ne \"${GOOD}>>${NORMAL}${BOLD} Booting\"
cd /newroot
pivot_root . tmp/.initrd echo -n '.'
umount /tmp/.initrd/proc || echo \"*: Failed to unmount the initrd /proc!\" umount /dev 2>/dev/null
mount -n --move /tmp/.initrd/dev dev 2>/dev/null
rm /tmp/.initrd/dev -rf || '*: Failed to remove the initrd /dev!'
umount /sys 2>/dev/null
umount /tmp/.initrd/sys 2>/dev/null echo -n '.'
exec 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 echo 'A fatal error has probably occured since /sbin/init did not' echo 'boot correctly. Trying to open a shell...' echo exec /bin/bash exec /bin/sh exec /bin/ash exec sh CallMeAt: http://mypretty.nease.net email: rujingli@163.com http://mypretty.nease.net/livecd/LiveCD_Study.sxw http://mypretty.nease.net/livecd/LiveCD_Study.pdf http://mypretty.nease.net/livecd/gift.rar http://mypretty.nease.net/livecd/doc Download This Document and the gift.iso at Online View at:
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务