Posted on 2005-12-24 21:09
YGB.Grushy 阅读(1511)
评论(0) 编辑 收藏 引用 所属分类:
Linux配置
无论如何,以下是系统启动必经的过程:
1,启动器(如grub)在硬盘上找到内核的镜像,把它导入内存中启动;
2,由内核初始化设备以及启动它们的驱动程序;
3,内核加载根文件系统(root filesystem);
4,内核启动初始化程序init;
5,由init设置一系列在配置文件中配置的进程;
6,最后init按顺序启动这些进程直至给出登录画面。
一,init
init没有什么特殊的,它也是一个跟其他应用程序差不多的程序,在/sbin里也能够找
的到。init的主要作用其实就是是有次序地启动或者关闭一些进程。
不同版本的init可能略有不同,不过大部分都是采用的unix V的风格,还有一些是采用
的BSD风格,这些其实都无所谓。
(1)运行级别(Runlevels)
linux系统中任何时刻都会有一些基本的进程在运行(跟废话一样)。机器的运行状态
可以用运行级别来描述,运行级别(Runlevels)有七种,用0到6表示。系统通常只运行
在一个runlevel下面。在关机的时候,init会把系统终端引导入另一个运行级别下,告
诉kernel进行关机操作,关闭系统服务等等。
理解runlevels的最好方法是看看init的配置文件:/etc/inittab,找到这一行:
id:5:initdefault:
这一行的意思是系统默认的运行级别为5,也就是图形操作界面。inittab文件里都
是这样形式的命令,主要分为4个部分:
*一个专门的标识符(很短的字符串,比如上面例子里的id)
*代表运行级别的数字
*init应该采取的动作(在上面的例子里这个action就是initdefault,即设置默认运
行级别为5)
*需要运行的命令(可选)
在上面的例子里,最后的可选命令是缺省的,既然是设置默认运行级别,也就没有
必要再在后面添加什么运行命令。再向下看inittab,可以看到:
15:5:wait:/etc/rc.d/rc 5
这一行非常重要,因为它是用来触发大部分的系统服务和配置的。这些系统服务以
及配置信息都保存在rc*.d和init.d目录中。上面的例子里init设置为在运行级别5下运
行/etc/rc.d/rc 5命令,采取的动作(action)是wait。整个一行的意思就是:如果进入
运行级别 5则运行rc 5命令,并且将一直等待(wait)到这个命令运行完毕后再做其他。
除了上面的initdefault,wait两个动作(action)以外,还有几个其他的action,尤其
是关于电源管理的,inittab(5)的手册页里都一一介绍了它们。一些比较重要的,经常
会遇到的有:
--respawn
respawn动作可以让init运行后面的命令,并且命令一旦停止运行respawn会再次执
行这个命令,也就是说循环运行后面的命令。在inittab配置文件里可以找到这样的命
令:
1:2345:respawn:/sbin/mingetty tty1
getty程序是用来给出登录提示符的,上面一行指示的是第一虚拟控制台,即按下
ALT+F1或者CONTROL-ALT-F1所进入的终端界面。respawn可以使终端提示符在登录以后
一直显示出来。
--ctrlaltdel
ctrlaltdel控制的是在系统文本终端下按下Ctrl+Alt+Del键所执行的操作,在大部
分系统里这个被设置为重新启动。
--sysinit
sysinit是init首先需要执行的动作,在选择运行级别之前就已经运行了。
(2)进程启动
现在是时候学习init如何启动系统服务了,在此之前仍然回到先前的inittab配置文
件的这一行:
15:5:wait:/etc/rc.d/rc 5
这短短的一行触发了很多的程序,rc的意思就是run commands,并且你会听说或者
看到很多朋友提及命令这个词(脚本,程序,服务等各种形式)。不过,这些命令究竟在
哪呢?
在runlevel 5中,命令一般会在/etc/rc.d/rc5.d或者/etc/rc5.d这两个目录下。同
理,runlevel 1的命令在rc1.d下,runlevel 2的在rc2.d下,依此类推。在rc5.d目录
下你能看到这些东西:
K01yum K35smb K74nscd S06cpuspeed
K02cups-config-daemon K35vncserver K74ntpd S08iptables
K02NetworkManager K35winbind K75netfs S10network
K02NetworkManagerDispatcher K50netdump K85mdmonitor S12syslog
K03rhnsd K50snmpd K85mdmpd S18auditd
K05saslauthd K50snmptrapd K86nfslock S26lm_sensors
K10cups K50vsftpd K87portmap S44acpid
K10psacct K66mDNSResponder K89named S50hsf
K15gpm K67nifd K89netplugd S90crond
K15httpd K68rpcidmapd K89rdisc S90xfs
K17iiim K69rpcgssd K90bluetooth S95anacron
K20nfs K69rpcsvcgssd K91isdn S95atd
K24irda K72autofs K94diskdump S97messagebus
K25sshd K73ypbind K96pcmcia S98haldaemon
K30sendmail K74apmd S05kudzu S99local
在这个运行级别的目录下的命令运行的时候,都是采用下面的模式:
s10sysklogd start
s12kerneld start
s15netstd_init start
s18netbase start
......
注意每一个运行命令,命令中的S表示这个命令是在系统启动的时候运行,而数字
(00到99)表示这个命令在所有rc中的顺序。这些rc*.d命令一般都是shell脚本,用来运
行/sbin和/usr/sbin中的程序。一般来说,通过观察脚本命令的组成就可以知道这个脚
本到底运行了哪个程序。
同样,我们也可以手工启动一些服务。比如,如果你想手工启动httpd服务程序,运
行s99httpd start就可以了。而且,你也可以非常简单地关闭某个服务,直接对rc*.d
目录下的命令使用stop参数:如s99httpd stop即可。
有一些rc*.d目录里有部分K开头的命令,意思就是kill。这样的话,rc运行命令就
是使用的stop参数而不是S所表示的start。这种情况一般出现在系统关机的时候,还是
比较容易理解的。
(3)添加删除服务
如果你想要添加删除或者配置rc*.d目录下的服务程序,那么就得先细看一下这个目
录里的文件了,使用ls -l命令将可以看到:
lrwxrwxrwx 1 root root 15 Aug 27 18:18 K03rhnsd -> ../init.d/rhnsd
lrwxrwxrwx 1 root root 15 Aug 27 09:39 K15httpd -> ../init.d/httpd
lrwxrwxrwx 1 root root 14 Oct 11 20:39 K17iiim -> ../init.d/iiim
lrwxrwxrwx 1 root root 13 Aug 27 09:39 K20nfs -> ../init.d/nfs
lrwxrwxrwx 1 root root 14 Aug 27 09:39 K24irda -> ../init.d/irda
lrwxrwxrwx 1 root root 14 Oct 11 20:39 K25sshd -> ../init.d/sshd
lrwxrwxrwx 1 root root 18 Aug 27 11:53 K30sendmail -> ../init.d/sendmail
lrwxrwxrwx 1 root root 13 Aug 27 09:40 K35smb -> ../init.d/smb
......
这个目录下的命令实质上就是一些链接,几乎都是指向init.d目录。从目录前面的
..可以推测,一般都是在/etc/init.d或者/etc/rc.d/init.d下。linux发行版包含这些
链接的目的其实就是为了使各个运行级别(runlevel)下启动脚本统一起来,除了可以使
系统的组织布局更简单一些没有什么特别的意义。
从当前的运行级别中去除某个init.d脚本命令而不让它运行,最容易想到的办法就
是在相应的rc*.d目录里删除链接(symbolic link),不可否认这的确可行,不过如果出
了什么差错的话那可就惨了,毕竟这些名字都不短,出了差错想重新添加链接名字很难
记清楚。所以,不要直接从rc*.d目录下删除链接,而是在前面加上一个下划线标记就
可以了:mvs99httpd_s99httpd。这样的话,在系统启动的时候,rc就会忽略_s99httpd
因为它不是S或K开头的,而且这样出了问题还可以非常直接的修复。
要添加一个服务,那么就需要在init.d目录里自己创建一个脚本,然后在rc*.d目录
里创建一个指向它的链接。不过,最简单的方法莫过于参照init.d目录里已经有的脚本
,然后予以修改即可。
添加服务的时候,需要注意的是应该给你的服务设定一个合适的启动顺序。如果你
自己添加的服务启动太早的话可能会无效,因为服务之间存在着一定的依赖关系。对于
一些非基本的服务,大部分系统管理员会比较倾向于使用90以后的顺序,那个时候大部
分系统服务已经启动完毕了。
linux的发行版本通常都自带了一个添加删除系统服务的命令。比如debian版本里的
update-rc.d命令;redhat里的chkconfig命令。相应的GUI程序可以让服务配置更加直
观,利于管理。
(4)控制init
有时候,我们可以稍稍设置一下init改变运行级别(runlevel),重新审视一下
inittab文件或者关闭一次系统。由于init是整个系统中第一个运行的进程,所以它的
ID号永远都为1。控制init可以用telinit命令,假设要转换到runlevel 3下:telinit
3
运行级别转换的时候,init会关闭所有那些没有被新的runlevel所定义的进程,因
此改变运行级别的时候要加以小心。当你需要添加或者去除inittab文件里的一些命令(
如respawn类的)时,需要通知init这些改变以使它重新读取一次inittab配置文件。一
些人通过kill -HUP 1来实现,这个方法适用于大部分unix版本的系统上,不过也可以
用上面的telinit命令:
telinit q
(5)关机
init同样也用来控制系统关机或者重新启动,通过shutdown命令可以实现关机操
作。要立即关闭计算机,可以使用shutdown -h now命令,h代表的意思就是halt,也就
是切断了电源,如果是重新启动,直接把h参数换成r就可以了:shutdown -r now
关机过程需要一些时间,这个过程中不应该手工切断电源或者按下reset键。上面的
例子里now参数表示的就是立即的意思,也有许多其他的参数可以选用,比如+n设定倒
计时时间,n就是你想要的时间,这些都可以通过man shutdown了解一下。
举例说明,要使系统10分钟后重新起动:shutdown -r +10
在linux系统里,shutdown命令会通知已经登录进来的用户它即将关机,不过意义不
大罢了。如果定义了倒计时关机,shutdown命令会生成一个/etc/nologin文件,这个文
件的存在能够阻止其他用户再进行登录操作,当然了,root用户除外。
在系统关机时,shutdown命令会告诉init程序转换到0运行级别,如果是重新启动则
转换到第6运行级别。当进入0或者6运行级别后,系统将会依照下面的顺序运行:
1,init关闭所有它能关闭的进程(转换到其他运行级别也一样)
2,rc0.d/rc6.d目录下的第一个命令开始运行,锁定系统文件为关机作准备
3,rc0.d/rc6.d目录下的第二个命令运行,卸载除根文件系统以外的所有文件系统(
如挂载的windows分区)
4,rc0.d/rc6.d中的命令将把根文件系统重新挂载为只读属性
5,rc0.d/rc6.d中的命令调用sync程序把缓存中的数据写入文件系统
6,最后的命令是重新启动或者关闭内核程序
二,启动加载程序
在kernel运行init程序之前,是启动加载程序启动了内核。有时候需要通过启动加
载程序来选择启动不同的内核甚至不同的操作系统,以及不同的启动模式,这种可选择
性在系统出现问题需要修复的时候显得特别有用。这种情况下,你可能就需要启动到单
用户模式(single-user mode)或者另一个可用内核下了。
系统加载程序把内核镜像导入到内存中,相当于把内核交到了CPU的手里。当然这个
过程是可以携带一些参数的,比如-s,表示启动到单用户模式,也可以启动到一个非默
认的运行级别下(如默认级别是启动到图形界面runlevel 5下,可以通过这个办法启动
到runlevel 3文本模式下)。
为了键入内核名称以及它们的可选参数,首先需要知道怎么才能看到启动提示符
(boot prompt)。幸运的是linux发行版本都带有自己的启动加载程序了。主要的有LILO
和GRUB,这里只选择介绍一下grub。
(1)GRUB
GRUB表示的意思是Grand Unified Bootloader,已经逐渐取代了LILO。GRUB有许多
很棒的特性,最重要的一点是它可以直接操作文件系统,读取文件而不需要加载内核。
GRUB有一个菜单界面可以让我们很容易的进行操作,选择。但这样又带来了一个问题,
就是当我们需要自己指定一些参数的时候就需要进入mini-shell了,在菜单界面下按下
c就可以得到这个提示符了:
grub>
假定我需要通过/boot/vmlinuz内核启动到/dev/hda3上的根文件系统。并且这个时
候系统已经混乱了,因此需要使用-s参数启动到单用户模式,在启动提示符后键入下面
的命令:
root(hd0,2)
kernel /boot/vmlinuz root=/dev/hda3 -s
boot
root(hd0,2)是设定GRUB将要启动的根分区,也就是内核所在的分区。hd0表示第一
块硬盘,2表示第三个分区(/dev/hda3)
kernel命令设定内核镜像以及它的参数值。/boot/vmlinuz指示的是(hd0,2)分区上
的镜像。由于kernel命令有时候会忽略上面的root,因此在后面总是要再定义一次
root=/dev/hda3
也可以用一行命令把上面的两行命令结合起来:
kernel (hd0,2)/boot/vmlinuz root=/dev/hda3 -s
最后一行的boot命令,就是告诉GRUB导入相应的内核镜像执行了。
(2)单用户模式与救援启动
有时候系统出现错误,系统管理员会采取的第一步措施就是启动至单用户模式。这
个时候系统只是快速启动到一个root shell下而不必启动那些不必要的服务。linux中
,single-user模式的运行级别为1,进入该模式需要root密码。
单用户模式下可以做的工作如下:
*系统崩溃后检查文件系统
*修改一些关键的配置文件,如/etc/fstab,/etc/passwd以及/etc/inittab等等
*通过先前的备份恢复系统
永远别指望在单用户模式下的操作还那么舒适,在里面需要自己动手设置终端模式(
键入TERM=linux)让全屏编辑器(如vi)可以工作,而且网络还不一定可用。当然,这些
都可以手工搞定,只是比较痛苦,呵呵!
单用户模式下的必要工作完成后可以试试退出shell看看系统是不是能够正常启动
了。最好是重新启动系统,而不是从单用户模式下通过init装入普通模式,因此这个似
乎不总是那么有用。
如果系统都无法进入单用户模式,可以试试内核参数-b来进入救援模式。这个模式
下并不像通常那样把文件系统挂载为读写模式,这就需要自己重新进行挂载。
如果足够背,把启动加载程序都损坏了或者干脆原来的内核没有用了,这时就需要
一些可启动CD来进入系统,这些可启动CD一般就是LIVE CD了。通过LIVE CD进入系统,
挂载原来的文件系统,修复GRUB或者重新编译新内核。