阅读Linux源代码,无疑是深入学?fn)Linux的最好方法。在本文对Linux启动q程的介l中Q我们也试从源代码的视角来更深入的剖析Linux的启动过E,所以其中也单涉?qing)到部分相关的Linux?iframe marginwidth="0" marginheight="0" src="http://images.chinabyte.com/adjs/iframe-pip/y-software-pip.html" align="right" scrolling="no" width="360" frameborder="0" height="300">代码QLinux启动q部分的源码主要使用的是C语言Q也涉及(qing)C(jin)量的汇~。而启动过E中也执行了(jin)大量的shell(主要是bash shell)所写脚本。ؓ(f)?jin)方便读者阅读,W者将整个Linux启动q程分成以下几个部分逐一介绍Q大家可以参考下图:(x)
当用h开PC的电(sh)源,BIOS开(g)Q按BIOS中设|的启动讑֤(通常是硬?启动Q接着启动讑֤上安装的引导E序lilo 或grub开始引导LinuxQLinux首先q行内核的引|接下来执行initE序QinitE序调用?jin)rc.sysinit和rc{程 序,rc.sysinit和rc当完成系l初始化和运行服务的d后,q回initQinit启动?jin)mingetty后,打开?jin)终端供用户dpȝQ用? d成功后进入了(jin)ShellQ这样就完成?jin)从开机到d的整个启动过E?/p>
W一部分Q内核的引导(核内引导)
Red Hat9.0可以使用lilo或grub{引?a class="bluekey" target="_blank">E序开 始引导LinuxpȝQ当引导E序成功完成引导d后,Linux从它们手中接了(jin)CPU的控制权Q然后CPU开始执行Linux的核?j)映象代码,开? ?jin)Linux启动q程。这里用了(jin)几个汇编E序来引导LinuxQ这一步泛?qing)到Linux源代码树(wi)中的“arch/i386/boot”下的q几个文 Ӟ(x)bootsect.S、setup.S、video.S{?/p>
其中bootsect.S是生成引导扇区的汇编源码Q它完成加蝲动作后直接蟩转到setup.S的程序入口。setup.S的主要功能就是将p? l参敎ͼ包括内存、磁盘等Q由BIOSq回Q拷贝到特别内存?sh),以便以后q些参数被保护模式下的代码来d。此外,setup.Sq将video.S中的 代码包含q来Q检和讄昄器和昄模式。最后,setup.S系l{换到保护模式Qƈ跌{?0x100000?/p>
那么0x100000q个内存地址中存攄是什么代码?而这些代码又是从何而来的呢Q?/p>
0x100000q个内存地址存放的是解压后的内核Q因为Red Hat提供的内核包含了(jin)众多驱动? 功能而显得比较大Q所以在内核~译中用了(jin)“makebzImage”方式Q从而生成压~过的内核,在RedHat中内核常常被命名为vmlinuzQ在 Linux的最初引DE中Q是通过"arch/i386/boot/compressed/"中的head.S利用misc.c中定义的 decompress_kernel()函数Q将内核vmlinuz解压?x100000的?/p>
当CPU跛_0x100000Ӟ执?arch/i386/kernel/head.S"中的startup_32Q它也是vmlinux 的入口,然后p转到start_kernel()中去?jin)。start_kernel()?init/main.c"中的定义的函 敎ͼstart_kernel()中调用了(jin)一pd初始化函敎ͼ以完成kernel本n的设|。start_kernel()函数中,做了(jin)大量的工作来建立 基本的Linux核心(j)环境。如果顺利执行完start_kernel()Q则基本的Linux核心(j)环境已经建立h?jin)?/p>
在start_kernel()的最后,通过调用init()函数Q系l创建第一个核?j)线E,启动?jin)initq程。而核?j)线Einit()主要 是来q行一些外讑ֈ始化的工作的Q包括调用do_basic_setup()完成外设?qing)其驱动E序的加载和初始化。ƈ完成文gpȝ初始化和root文gp? l的安装?/p>
当do_basic_setup()函数q回init()Qinit()又打开?dev/console讑֤Q重定向三个标准的输入输出文? stdin、stdout和stderr到控制台Q最后,搜烦(ch)文gpȝ中的initE序Q或者由init=命o(h)行参数指定的E序Q,q? execve()pȝ调用加蝲执行initE序。到此init()函数l束Q内核的引导部分也到此结束了(jin)Q?/p>
W二部分Q运行init
init的进E号?Q从q一点就能看出,initq程是系l所有进E的L(fng)QLinux在完成核内引g后,开始运行initE序Q。initE序需要读取配|文?etc/inittab。inittab是一个不可执行的文本文gQ它有若q行指o(h)所l成。在Redhatpȝ中,inittab的内容如下所C??#8220;###"开始的中注释ؓ(f)W者增加的)Q?/p>
#
# inittab This file describes how the INIT process should set up
# the system in a certain run-level.
#
# Author: Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
# Modified for RHS Linux by Marc Ewing and Donnie Barnes
#
# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not havenetworking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
###表示当前~省q行U别?(initdefault)Q?br />
id:5:initdefault:
###启动时自动执?etc/rc.d/rc.sysinit脚本(sysinit)
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
###当运行别ؓ(f)5Ӟ?为参数运?etc/rc.d/rc脚本Qinit等待其q回(wait)
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
###在启动过E中允许按CTRL-ALT-DELETE重启pȝ
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly.
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
###????U别上以ttyX为参数执?sbin/mingettyE序Q打开ttyXl端用于用户dQ?br />
###如果q程退出则再次q行mingettyE序(respawn)
# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
###?U别上运行xdmE序Q提供xdm囑Ş方式d界面Qƈ在退出时重新执行(respawn)
# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm -nodaemon
以上面的inittab文gZQ来说明一下inittab的格式。其中以#开始的行是注释行,除了(jin)注释行之外,每一行都有以下格式:(x)
id:runlevel:action:process
对上面各的详细解释如下Q?/p>
1. id
id是指入口标识W,它是一个字W串Q对于getty或mingetty{其他loginE序,要求id与tty的编L(fng)同,否则gettyE序不能正常工作?/p>
2. runlevel
runlevel是init所处于的运行别的标识Q一般?Q?以及(qing)S或s???q行U别被系l保留:(x)其中0作ؓ(f)shutdown? 作,1作ؓ(f)重启臛_用户模式Q?为重启;S和s意义相同Q表C单用户模式Q且无需inittab文gQ因此也不在inittab中出玎ͼ实际上,q入单用 h式时Qinit直接在控制台Q?dev/consoleQ上q行/sbin/sulogin。在一般的pȝ实现中,都用了(jin)2???几个U别Q? 在Redhatpȝ中,2表示无NFS支持的多用户模式Q?表示完全多用h式(也是最常用的别)(j)Q?保留l用戯定义Q?表示XDM囑Şd方式? 7Q?U别也是可以使用的,传统的Unixpȝ没有定义q几个别。runlevel可以是ƈ列的多个|以匹配多个运行别,对大多数action? _(d)仅当runlevel与当前运行别匹配成功才?x)执行?/p>
3. action
action是描q其后的process的运行方式的。action可取的值包括:(x)initdefault、sysinit、boot、bootwait{:(x)
initdefault是一个特D的action|用于标识~省的启动别;当init由核?j)激zM后,它将dinittab中的 initdefault,取得其中的runlevelQƈ作ؓ(f)当前的运行别。如果没有inittab文gQ或者其中没有initdefault ,init在控制Ch输入runlevel?/p>
sysinit、boot、bootwait{action在pȝ启动时无条gq行Q而忽略其中的runlevel?/p>
其余的actionQ不含initdefaultQ都与某个runlevel相关。各个action的定义在inittab的man手册中有详细的描q?/p>
4. process
process为具体的执行E序。程序后面可以带参数?/p>
W三部分Q系l初始化
在init的配|文件中有这么一行:(x)
si::sysinit:/etc/rc.d/rc.sysinit
它调用执行了(jin)/etc/rc.d/rc.sysinitQ而rc.sysinit是一个bash shell的脚本,它主要是完成一些系l初始化的工作,rc.sysinit是每一个运行别都要首先运行的重要脚本。它主要完成的工作有Q激zM换分区,(g)查磁盘,加蝲g模块以及(qing)其它一些需要优先执行Q务?/p>
rc.sysinitU有850多行Q但是每个单一的功能还是比较简单,而且带有注释Q徏议有兴趣的用户可以自行阅读自己机器上的该文gQ以?jin)解pȝ初始化所详细情况。由于此文g较长Q所以不在本文中列出来,也不做具体的介绍?/p>
当rc.sysinitE序执行完毕后,返回initl箋(hu)下一步?/p>
W四部分Q启动对应运行别的守护q程
在rc.sysinit执行后,返回initl箋(hu)其它的动作,通常接下来会(x)执行?etc/rc.d/rcE序。以q行U别3ZQinit执行配|文件inittab中的以下q行Q?/p>
l5:5:wait:/etc/rc.d/rc 5
q一行表CZ5为参数运?etc/rc.d/rcQ?etc/rc.d/rc是一个Shell脚本Q它接受5作ؓ(f)参数Q去执行/etc /rc.d/rc5.d/目录下的所有的rc启动脚本Q?etc/rc.d/rc5.d/目录中的q些启动脚本实际上都是一些链接文Ӟ而不是真正的rc 启动脚本Q真正的rc启动脚本实际上都是放?etc/rc.d/init.d/目录下。而这些rc启动脚本有着cM的用法,它们一般能接受start? stop、restart、status{参数?/p>
/etc/rc.d/rc5.d/中的rc启动脚本通常是K或S开头的链接文gQ对于以以S开头的启动脚本Q将以start参数来运行。而如? 发现存在相应的脚本也存在K打头的链接,而且已经处于q行态了(jin)(?var/lock/subsys/下的文g作ؓ(f)标志)Q则首先以stop为参数停? q些已经启动?jin)的守护q程Q然后再重新q行。这样做是ؓ(f)?jin)保证是当init改变q行U别Ӟ所有相关的守护q程都将重启?/p>
至于在每个运行中将q行哪些守护q程Q用户可以通过chkconfig或setup中的"System Services"来自行设定。常见的守护q程有:(x)
amdQ自动安装NFS守护q程
apmd:高甉|理守护q程
arpwatchQ记录日志ƈ构徏一个在LAN接口上看到的以太|地址和IP地址Ҏ(gu)据库
autofsQ自动安装管理进EautomountQ与NFS相关Q依赖于NIS
crondQLinux下的计划d的守护进E?br />
namedQDNS服务?br />
netfsQ安装NFS、Samba和NetWare|络文gpȝ
networkQ激zd配置|络接口的脚本程?br />
nfsQ打开NFS服务
portmapQRPC portmap理器,它管理基于RPC服务的连?br />
sendmailQ邮件服务器sendmail
smbQSamba文g׃n/打印服务
syslogQ一个让pȝ引导时v动syslog和klogdpȝ日志守候进E的脚本
xfsQX Window字型服务器,为本地和q程X服务器提供字型集
XinetdQ支持多U网l服务的核心(j)守护q程Q可以管理wuftp、sshd、telnet{服?/p>
q些守护q程也启动完成了(jin)QrcE序也就执行完了(jin)Q然后又返回initl箋(hu)下一步?/p>
W五部分Q徏立终?
rc执行完毕后,q回init。这时基本系l环境已l设|好?jin),各种守护q程也已l启动了(jin)。init接下来会(x)打开6个终端,以便用户dpȝ。通过按Alt+Fn(n对应1-6)可以在这6个终端中切换。在inittab中的以下6行就是定义了(jin)6个终端:(x)
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
从上面可以看出在2???的运行别中都将以respawn方式q行mingettyE序QmingettyE序能打开l端、设|模式。同时它?x)显CZ个文本登录界面,q个界面是我们l常看到的登录界面,在这个登录界面中?x)提C用戯入用户名Q而用戯入的用户作为参ClloginE序来验证用L(fng)w䆾?/p>
W六部分Q登录系l,启动完成
对于q行U别?的图形方式用h_(d)他们的登录是通过一个图形化的登录界面。登录成功后可以直接q入KDE、Gnome{窗口管理器。而本文主要讲的还是文本方式登录的情况Q?/p>
当我们看到mingetty的登录界面时Q我们就可以输入用户名和密码来登录系l了(jin)?br />
Linux的̎号验证程序是
loginQlogin?x)接收mingetty传来的用户名作ؓ(f)用户名参数。然后login?x)对用户名进行分析?x)如果用户名不是rootQ且存在/etc
/nologin文gQlogin输出nologin文g的内容,然后退出。这通常用来pȝl护旉止非root用户d。只?etc
/securetty中登C(jin)的终端才允许root用户dQ如果不存在q个文gQ则root可以在Q何终端上d?etc/usertty文g用于?
用户作出附加讉K限制Q如果不存在q个文gQ则没有其他限制?/p>
在分析完用户名后Qlogin搜?etc/passwd以及(qing)/etc/shadow来验证密码以?qing)设|̎L(fng)其它信息Q比如:(x)ȝ录是什么、用何Ushell。如果没有指定主目录Q将默认为根目录Q如果没有指定shellQ将默认?bin/bash?/p>
loginE序成功后,?x)向对应的终端在输出最q一ơ登录的信息(?var/log/lastlog中有记录)Qƈ(g)查用h否有新邮?? /usr/spool/mail/的对应用户名目录?。然后开始设|各U环境变量:(x)对于bash来说Q系l首先寻?etc/profile脚本文gQ? q执行它Q然后如果用L(fng)ȝ录中存在.bash_profile文gQ就执行它,在这些文件中又可能调用了(jin)其它配置文gQ所有的配置文g执行后后Q各U? 环境变量也设好了(jin)Q这时会(x)出现大家熟?zhn)的命令行提示W,到此整个启动q程q束了(jin)?/p>
希望通过上面对Linux启动q程的剖析能帮助那些x(chng)入学?fn)Linux用户建立一个相关Linux启动q程的清晰概念,q而可以进一步研ILinux接下来是如何工作的?/p>
noauto
option).device /mount-point fstype options dumpfreq passno
A device name (which should exist), as explained in Section 18.2.
A directory (which should exist), on which to mount the file system.
The file system type to pass to mount(8). The default FreeBSD file system is ufs.
Either rw
for read-write file systems, or ro
for read-only file systems, followed by any other options that
may be needed. A common option is noauto
for file systems not
normally mounted during the boot sequence. Other options are listed in the mount(8) manual
page.
This is used by dump(8) to determine which file systems require dumping. If the field is missing, a value of zero is assumed.
This determines the order in which file systems should be checked. File systems that should be skipped should have their passno set to zero. The root file system (which needs to be checked before everything else) should have its passno set to one, and other file systems' passno should be set to values greater than one. If more than one file systems have the same passno then fsck(8) will attempt to check file systems in parallel if possible.
Consult the fstab(5) manual page for more information on the format of the /etc/fstab file and the options it contains.
The mount(8) command is what is ultimately used to mount file systems.
In its most basic form, you use:
There are plenty of options, as mentioned in the mount(8) manual page, but the most common are:
Mount Options
-a
Mount all the file systems listed in /etc/fstab. Except
those marked as “noauto”, excluded by the -t
flag, or those that are already mounted.
-d
Do everything except for the actual mount system call. This option is useful in
conjunction with the -v
flag to determine what mount(8) is actually
trying to do.
-f
Force the mount of an unclean file system (dangerous), or forces the revocation of write access when downgrading a file system's mount status from read-write to read-only.
-r
Mount the file system read-only. This is identical to using the ro
(rdonly
for FreeBSD versions older
than 5.2) argument to the -o
option.
-t
fstypeMount the given file system as the given file system type, or mount only file systems
of the given type, if given the -a
option.
“ufs” is the default file system type.
-u
Update mount options on the file system.
-v
Be verbose.
-w
Mount the file system read-write.
The -o
option takes a comma-separated list of the options,
including the following:
Do not allow execution of binaries on this file system. This is also a useful security option.
Do not interpret setuid or setgid flags on the file system. This is also a useful security option.