转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 数据库 >> MySql >> 正文
剖析Linux系统启动过程(二)         ★★★★

剖析Linux系统启动过程(二)

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1624 更新时间:2009/4/22 20:45:08

各位是否曾经对电脑整个开机的流程感到好奇呢 ? 这一次 , 我们所要讨论的主题 , 就是 Linux 从开机的一瞬间到 login 为止 , 到底发生了什么事情 ?


想必各位都知道 , 在刚开机时 , 由于 80x86 的特性 , CS ( Code Segment )
这个寄存器中全部都放着 1 , 而 IP ( Instruction Pointer ) 这个寄存器中全部都放着 0 , 换句话说 , CS=FFFF 而 IP=0000 , 此时 , CPU 就依据CS 及 IP 的值 , 到 FFFF0H 去执行那个地方所放的指令 . 这时候 , 由于FFFF0H 已经到了高位址的顶端 , 所以 , FFFF0H 这个地方 , 总是会放一个JMP 指令 , 跳到比较低的位址 . 接著 , ROM BIOS 就会作一些检查的动作像内存 , 键盘 等...... 并在我们俗称的 UMB ( Upper Memory Block )
之中扫描 , 看看是否有合法的 ROM 存在 ( 比如 SCSI 卡上的 ROM ) .
假如有 , 就到里面去执行一些东西 , 执行完之后再继续刚才的行程 . 到了最后 , 读取硬盘上的第一个 sector . 在这里 , 我假设各位由硬盘启动
因此 , 就硬盘的构造而言 , 它的第一个 sector 称为 MBR ( Master Boot
Record ) . 因为一个 sector 是 512 bytes , 而 MBR 这 512 bytes 可分为两个部份 , 第一个部份为 Pre-Boot 区 , 占了 446 bytes ; 第二部份是Partition Table , 占了 66 bytes . Pre-Boot 区的作用之一 , 就是去看看那个 Partition 被标成 Active , 然後去读那个 Partition 的 Boot 区 .


在 Linux 的启动方面 , 一般人最常把 LILO 放在 MBR 或 Superblock假如你把 LILO 放在 MBR , 那很明显的 , 当读取到 MBR 的时候 , LILO就被执行 , 此时 , 你的屏幕上会出现 boot: 接着 , 就进行 Load Kernel 的动作 . 在另一方面来说 , 假如你把 LILO 安装在 Superblock , 通常你还会有一个管理开机的程序 , 也许是放在 MBR ( 像 OSBS ) 或者是放在一个单独的 Partition ( 像 OS/2 的 Boot Manager ) . 再由这个管理开机的程式去读取 LILO , 进而做 Load Kernel 的动作 .


好了 , 到了目前为止 , 我们已经讲到 Load Kernel 的动作 . Kernel 被load 到 memory 中之后 , 接着进行一连串 probe 周边的动作 , 像串口并口 , 软盘 , 声卡 , 硬盘 , 光驱 等 ...... 接着 mount rootpartition . 在这之后 , kernel 会起动 init 这个 process . init 这个 process 的 PID 为 1 , 它是所有 process 的祖先 .


接下来呢 ? 系统就开始执行 /rc.d/rc.S , 在这里 , 我们暂时打住 , 先对大概的 initialization script 执行的顺序作一个浏览 , 请看下面的流程 :
init[1]
rc.S begin <--- 目前我们已经讲到这里
rc.serial begin
rc.serial end
rc.S end
init[1] enter runlevel 5
rc.M begin
rc.inet1 begin
rc.inet1 end
rc.inet2 begin
rc.inet2 end
rc.font begin
rc.font end
rc.local begin
rc.local end
rc.M end
login


上面的流程清楚的指出 , 在 rc.S 这个 shell script 中 , 会去执行 rc.serial接着再执行 rc.M , rc.M 中又包含了 rc.inet1 , rc.inet2 , rc.font , rc.local最后执行 login . 在下面的内容中 , 将为各位介绍这几个 shell script从下面开始 , 凡是每一列之前有一个 # 的 , 为原来 shell script 中的注释有两个 # 的 , 为笔者加上的注释 , 当然啦 , 没有任何 # 的为 shell script的内容 , 而对命令或内容的解释 , 一律都写在命令或内容的前面 .
首先由 rc.S 开始 :


***************************** rc.S********************************

#!/bin/sh
#
# /etc/rc
#
# These commands are executed at boot time by init(8).
# User customization should go in /etc/rc.local.

echo ''''======== rc.S is running ! System Initializing Now !!! ========''''
PATH=/sbin:/usr/sbin:/bin:/usr/bin


## 打开所有 swap ! 下面 /sbin/swapon -a 的意思是 : 使得 /etc/fstab 中被记录
## 成 swap 的 device 全部启动 .

/sbin/swapon -a
?

喔 ! 下面这个指令 update 就很重要了 , 它负责每隔一段固定的时间 ,就将buffer 中的资料 , 利用 sync 写回磁盘上 , 并将 superblock做update 的动作 . 使用 ps 这个指令看看有那些 process , 就可看到update 还有一个bdflush , 这两个 process 都是必然要存在的 , 可不要随便砍掉 , 要不然 , 万一系统 crash 了 , 那磁盘里面的资料就不是最新的了 ......


/sbin/update &
?

利用 echo -n >> 制造一个文件 , 并用 rm -f 这个档案来测试 root partition

是不是 read-only 或者是可读写

READWRITE=no
if echo -n >> "Testing filesystem status"; then
rm -f "Testing filesystem status"
READWRITE=yes
fi
?

假如 root partition 是 read-only 就作 fsck 的动作 , 假如不是 read-only

而是 read-write 的话 , 就做下面 else 之后的动作

if [ ! $READWRITE = yes ]; then
利用 fsck 做检查及修复文件系统的工作 , 后面接的两个参数 -A , -a .
-A 的意思是 : fsck 会依据 /etc/fstab 中的记录 , 去检查所有的文件系统 ; 而 -a 就是 auto 的意思 , 当 fsck 有修复的动作时 , 它不会问你问题 , 而直接修复 .

/sbin/fsck -A -a
?

假如 fsck 有 error , [ $? -gt 1 ] 括号里面的意思是 : 若上个命令的传回值大于 1 , 而上个命令就是 fsck . 让我们看看 fsck 的传回值 :
0 - No errors
1 - File system errors corrected
2 - File system errors corrected, system should 
be rebooted if file system was mounted 
4 - File system errors left uncorrected 
8 - Operational error 
16 - Usage or syntax error 
128 - Shared library error 
很明显的 , 若有任何错误产生的话 , 那 fsck 的传回值都大于 1 . 其实就我的观点认为 , 应该写成 if [ $? -ge 1 ] 比较好 . 既然有错呢 , 系统应该就要跳至单用户模式 , 在单用户模式中主要就是 /etc/rc.d/rc.K 中的两件事 : 关掉 swap 及 卸下所有的文件系统 , 而最后重新 login .  一般正常的情况下 , if 下面这一大段是不会执行的 , 而会跳至下面标有Normal 1  处

if [ $? -gt 1 ] ; then
echo
echo
echo "**************************************"
echo "fsck returned error code - REBOOT NOW!"
echo "**************************************"
echo
echo
/bin/login
fi


****************************** Normal 1 ************************** 
当 fsck 检查没有错误之后 , 就把 root partition 重新 mount 上来下面指令的参数有三个 , -w 代表mount 成可读写 , -n 代表把一个 file-system mount 上来 , 但不会把记录写到 /etc/mtab 中 , 在上次/etc/mtab介绍时有提到 , 当我们使用 mount 这个指令把一个 filesystem mount 上来的时候 , /etc/mtab 就会记录 ! 利用 -n 这个 option 可使得做 mount 的动 作, 却不会记录 . -o 后面可以接许多的选项 , 在这里 , 我们给它的选项是remount . remount 的意思是 : 重新 mount 一个已经被 mount 的filesystem这个选项通常被用来改变该 filesystem 的读写标志 ,尤其是把 filesystem 从 read-only 的状态 , 改变成 read-write 的状态 .

echo "Remounting root device with read-write enabled."
/sbin/mount -w -n -o remount /
?


在前面的情况中 , 都是 root partition 为 read-only 的状态下 , 所做的一些 工作 , 到了最后一个指令 /sbin/mount -w -n -o remount / , 才把 root partition mount 成 read-write . 各位有没有看到前面那行 : 

 if [ ! $READWRITE = yes ]; then ..... 下面这个 else 就是与这个 if 对应
也就是说 , 前面那个 if 的区块中 , 所作的工作都是在 root partition 为
read-only 的条件成立下所作的事 , 那很明显的 , 下面这个 else 就是 root 
partition 为 read-write 的条件下所作的工作 . 假如你的 root partition为 read-writeable 的话 , 那么系统就会显示下面的信息 . cat << EOF 所作的 事 , 就是把 EOF 之前的信息全部显示在屏幕上 :

我想 , 下面的信息写得很明显了 , 它说 : 你的 root partition 被 mount 成 read-write , 没有办法检查 , 要使检查的动作能够顺利的进行 , 你必须把 root partition mount 成 read-only ! 那要怎么做呢 ? 很容易 , 只要利用

rdev -R / 1 就可以了 ......


else
cat << EOF


*** Root partition has already been mounted read-write. Cannot check!
For filesystem checking to work properly, your system must initially mount
the root partition as read only. Please modify your kernel with ''''rdev'''' so
that
it does this. If you''''re booting with LILO, type:
rdev -R /vmlinuz 1
(^^^^^^^^ ... or whatever your kernel name is.)


If you boot from a kernel on a floppy disk, put it in the drive and type:
rdev -R /dev/fd0 1


This will fix the problem *AND* eliminate this annoying message. :^)


EOF
?


下面这个指令没什么好说的 , 就是暂停 10 秒钟 , 让 user 能够有充足的
时间看完上面的信息


sleep 10
fi
?


删除 /etc/mtab /etc/nologin /etc/utmp


/bin/rm -f /etc/mtab* /etc/nologin /etc/utmp
?

制造 /etc/utmp , 这是一个很典型制造空文件的写法 . /dev/null 这个 node
蛮有趣的 , 在某一方面来说 , 它有点像是一个 " 黑洞 " . 怎么说呢?各位可以试试看下面的指令 ls >> /dev/null , 当你使用这个指令之后会发生什么事呢 ? 什么也没发生 , 而且 ls 的输出就好像被丢到黑洞里 , 无影无踪了 . 那也许你会想 : 那这有什么用 ? 我的回答是 : 的确没有什么很大的用处 , 但当你想抑制输出的信息时 , 你就会用得到了 .


cat /dev/null >> /etc/utmp
?


依据 fstab ( filesystem table ) 中的描述 , 自动的挂上文件系统但此时因为 TCP/IP 还没有设定 , 故不用 NFS


echo ''''Mount Filesystem !!!''''
/sbin/mount -avt nonfs
?


设定系统的时钟 . 下面这几行所做的事就是 : 看看 /sbin/clock 这个文件是不是可执行的 , 假如可以执行 , 就把 CMOS 中的时间设定为系统的时间 .


if [ -x /sbin/clock ]; then
echo ''''Set System Clock''''
/sbin/clock -s
fi
?


下面的四行若没有 mark , 则每次开机 issue 及 motd 都会被改变 , 这应该可算是 FAQ 级的问题了 ...... 因为我有自己设计的 issue 及 motd , 所以下面的四行前面都有 # , 被注释掉 . 假如你要有自己的设定 , 下面一定都要 mark 起来


#echo > /etc/issue
#echo Welcome to Linux /bin/uname -a | /bin/cut -d\ -f3. >> /etc/issue
#echo >> /etc/issue
#echo "/bin/uname -a | /bin/cut -d\ -f1,3. (Posix)." > /etc/motd
?


接下来 , 将执行 rc.serial , 顾名思义 , rc.serial 是作串口设定的工作在 rc.serial 中 , 内容虽然也是很简单 , 但并不像 rc.S 那样直接 . 换句话说 , 读者至少要 " 稍微 " 懂一点 shell programming , 所以说呢 , 假如还不会 shell programming 的读者呢 , 都应该赶快去找一本书来看一下 , 在这篇文章的结尾 , 我会提出一些书单 , 各位可以去找找这几本书 ......


/bin/sh /etc/rc.d/rc.serial
echo ''''============== rc.S is finish NOW !!! =================''''
?
?


到了这里 , rc.S 的最後一步 , 是去执行 rc.serial . 大家可以看一看/rc.d/rc.serial . 好像很长的样子 , 但实际上呢 , 各位必然发现到了 , 这个shell script 大部份指令的前面都有一个 ''''#'''' 号 , 这代表着 , 这些指令完全不会被执行 . 所以呢 , 真正有用的只不过寥寥十几行吧 ! 在另一方面来说 , 假如你是用网卡连上网络 , 那 rc.serial 对你并没有什么大用处.
?


**************************** rc.serial **************************


#!/bin/sh
#
# /etc/rc.serial
# Initializes the serial ports on your system
#
# Version 2.01


echo ''''================= rc.serial is begin !!! ================''''
cd /dev


下面三行中的前两行是设定一些变量 , 由于在这个 shell script 中 , 需要 用到 /bin/setserial -b 这个指令 , 或是需要用到所有以 cua 开头的 node的次数太多了 , 因此 , 把它们设定为一个变量 , 是一个不错的方法 . 尤其 PORTS=`echo cua? cua??` 这是一个聪明的写法 , 那为什么不写成 PORT= `echo cua*` 呢 ? 各位可以在 /dev 下分别使用这两个指令 , 观察输出到底有什么不同 ......


SETSERIAL="/bin/setserial -b"
PORTS=`echo cua? cua??`
echo -n "Configuring serial ports...."
?


下面这行 , 没有学过 shell programming 的人很可能会看不懂 , 不过没有关系 , 这行中的 ${SETSERIAL} 会被换成 /bin/setserial -b , 而${PORTS} 会被换成 cua0 cua1 cua2 ....... cua31 , 所以整句翻译就是:/bin/setserial -b -W cua0 cua1 cua2 cua3 cua4 cua5 cua6 ...... cua31那这行指令到底在做什么呢 ? 其实只是在做中断侦测的工作.


${SETSERIAL} -W ${PORTS}
?


各位看到下面原来的注释了吧 . 当你有一些特殊的卡时 , 你可以把相对应部份前面的 ''''#'''' 去掉 , 以便能做自动设定的工作 . 其实呢 , 这种情况实在不多 , 大部份人的设备都差不了多少 , 说到关于串口 , 差异就更少了 .
#
# AUTOMATIC CONFIGURATION
#
# Uncomment the appropriate lines below to enable auto-configuration
# of a particular board. Or comment them out to disable them....
#
?


## 好了 , 这下我们又多了一个变量 : AUTO_IRQ , 这在下面会用到 .


AUTO_IRQ=auto_irq
?


## 下面几行非常整齐 , 它们可以分别被换成 :
## /bin/setserial -b /dev/

[1] [2] [3]  下一页


没有相关教程
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · Sql Server  · MySql
    · Access  · ORACLE
    · SyBase  · 其他
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台