Mandrake9.0的启动过程(从init开始)(二)

发表于:2007-07-04来源:作者:点击数: 标签:
在内核引导结束并启动/sbin/init之后,系统就转入用户态的运行。在这之后创建的一切进程,都是在用户态进行。这里先要讲清楚一个概念:就是init进程虽然是从内核开始的,即在前面所讲的init/main.c中的init()函数在启动后就已经是一个核心线程,但在转到执行

  在内核引导结束并启动/sbin/init之后,系统就转入用户态的运行。在这之后创建的一切进程,都是在用户态进行。这里先要讲清楚一个概念:就是init进程虽然是从内核开始的,即在前面所讲的init/main.c中的init()函数在启动后就已经是一个核心线程,但在转到执行/sbin/init之后,内核中的init()就变成了/sbin/init程序,状态也转变成了用户态,也就是说核心线程变成了一个普通的进程。这样一来,内核中的init函数实际上只是init进程的入口,它在执行execve("/sbin/init",argv_init,envp_init)时改变成为一个普通的用户进程。这就是exec系列函数替换进程映像的变身大法,只要你学过unix环境下的多进程编程,应该都能理解这一点。
  除此之外,它们的代码来源也有差别,内核中的init()函数的源代码在/init/main.c中,是内核的一部分。而/sbin/init程序的源代码是sysvinit软件包的一部分,可以从ftp://ftp.cistron.nl/pub/people/miq...程序,如:halt, init, killall5, last, lastb (链接至 last), mesg, pidof (链接至 killall5), poweroff (链接至 halt), reboot (链接至 halt), runlevel, shutdown, sulogin, telinit (链接至 init), utmpdump 和 wall等等。对于启动过程而言,这里最重要的就是init程序。它启动之后,要完成很多任务:检查文件系统,启动各种后台服务进程,最后为每个终端和虚拟控制台启动一个getty进程供用户登录。由于所有其它用户进程都是由init派生的,因此它又是其它一切用户进程的父进程。
  init进程启动后,就要按照/etc/inittab的内容进程系统设置。下面就是manfrake9.0的inittab内容:
  #
  # inittab This file describes how the INIT process should set up
  # the system in a certain run-level.
  #
  # Author: Miquel van Smoorenburg, .net.org>
  # Modified for RHS Linux by Marc Ewing and Donnie Barnes
  #
  # Default runlevel. The runlevels used by Mandrake Linux 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 have networking)
  # 3 - Full multiuser mode
  # 4 - unused
  # 5 - X11
  # 6 - reboot (Do NOT set initdefault to this)
  #
  id:5:initdefault:
  # 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
  l5:5:wait:/etc/rc.d/rc 5
  l6:6:wait:/etc/rc.d/rc 6
  # Things to run in every runlevel.
  ud:nce:/sbin/update
  # 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:owerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
  # If power was restored before the shutdown kicked in, cancel it.
  pr:12345owerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
  # 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
  从中可以看到,inittab的每一行由四个字段组成。分别是:
  id:runlevels:actionrocess
  id:是每一行的标识符,长度一般为2个字符而且在整个inittab中必须唯一。对于getty或其他login程序项,要求id与tty的编号相同,否则getty程序将不能正常工作。
  runlevels:指定运行级别,一般使用0-6以及S或s。运行级别是指init进程的整个系统的一个运行状态,它定义了系统所提供的服务,常见的运行级别如下:0,系统终止;1,单用户模式;3没有网络文件系统支持的多用户模式;4,保留;5,启动到Xwindow;6,重新启动,S和s意义相同,表示单用户模式且无需inittab文件,因此也不必在inittab中出现,实际上,进入单用户模式时,init直接在控制台(/dev/console)上运行/sbin/sulogin。实际上,7-9的运行级别也是可以使用的,只是传统的Unix系统没有定义这几个级别。级别可以是并列的多个值,以匹配多个运行级别,对大多数action来说,仅当runlevel与当前运行级别匹配成功才会执行。。
  action:指出的是init程序执行process命令的方式。initdefault是一个特殊的action值,用于标识缺省的运行级别。当init进程由核心启动后,它将读取inittab中的initdefault项,取得其中的运行级别,并作为当前的运行级别。如果没有inittab文件,或者其中没有initdefault项,init将在控制台上请求输入运行级别。respawn 在进入相应runlevel时执行,如果该进程结束,init会再起一个进程执行同样的命令。once在进入有runlevels指定的运行级别时运行并且只执行一次。wait的执行效果和once一样,但init会等待该命令结束。ctrlaltdel指定在用户按下Ctrl-Alt-Del时执行的命令。powerfail 在系统接收到掉电信号时启动相关进程。powerwait 和powerfail一样,在系统接收到掉电信号时启动相关进程,并等待进程终止,在进程终止前不做任何其它操作。off 若该项相关进程已经存在则强行终止,否则忽略。sysinit、boot、bootwait等action将在系统启动时无条件运行,而忽略其中的运行级别,其中sysinit 指定需要运行的第一个程序(或脚本),boot将在sysinit之后执行,bootwait的执行效果和boot一样,但init会等待该命令结束,其余的action(不含initdefault)都与某个运行级别相关,可以在inittab的man手册中找到各个action的定义的详细描述。
  process:给出每行要执行的命令。
  知道inittab的字段意义以后,我们来看一下inittab的结构。inittab的第一行是设定系统的运行级别,如下所示:
  id:5:initdefault:
  从以上的介绍中可以知道,系统的运行级别是5,也就是系统启动时自动进入xwindow。接着进行系统初始化:
  si::sysinit:/etc/rc.d/rc.sysinit
  这样init进程就会执行/etc/rc.d/rc.sysinit。这个脚本最常见的动作就是激活交换分区,检查磁盘,加载硬件模块,这些动作无论哪个运行级别都是需要优先执行的。只有在rc.sysinit执行完以后init进程才会执行其他的boot或bootwait动作。如果没有boot或bootwait动作,init进程就接着执行下面的内容:
  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
  l5:5:wait:/etc/rc.d/rc 5
  l6:6:wait:/etc/rc.d/rc 6
  这里,系统将会根据运行级别选择要执行的命令。从前面我们已经知道系统的运行级别是5,所以实际上只有这一行被执行了:
  l5:5:wait:/etc/rc.d/rc 5
  这一行的最后是以参数5运行/etc/rc.d/rc,实际上就是运行/etc/rc.d/rc3.d下的所有程序(或脚本)。用ls命令查看/etc/rc.d/rc3.d目录,如下:
  [kj501@c4 kj501]$ ls /etc/rc.d/rc3.d/
  K09dm@ S16ypserv@ S56rawdevices@ S90crond@
  K55routed@ S17alsa@ S56xinetd@ S90postgresql@
  K90mysql@ S18sound@ S60cups@ S91smb@
  S01usb@ S20random@ S60nfs@ S92lisa@
  S03iptables@ S20xfs@ S60rwhod@ S95innd@
  S05harddrake@ S25netfs@ S66yppasswdd@ S95kheader@
  S10network@ S26apmd@ S75keytable@ S99devfsd@
  S11portmap@ S26ypxfrd@ S80postfix@ S99hamboot@
  S12syslog@ S40atd@ S85httpd@ S99linuxconf@
  S13partmon@ S40saslauthd@ S85numlock@ S99local@
  S14nfslock@ S55named@ S85proftpd@
  S15gpm@ S55sshd@ S89internet@
  这些文件都是一些系统服务程序,以“S”打头的文件用来在进入运行级别5时启动服务进程,以“K”打头的文件用来在系统关闭,离开运行级别5之前终止服务进程。后面的数字大小决定执行的先后次序,对于以”K“打头的服务进程,按照从高到低的顺序执行,对于以”S“打头的服务进程,按照从低到高的顺序执行。如果用ls -l 查看这些文件,就会发现它们大部分都是到/etc/rc.d/init.d目录下各个shell脚本的符号链接,而且这些脚本一般能接受start、stop、restart、status等参数,在启动时以start参数启动以“S”打头的脚本链接,如果存在一个同样的脚本链接但是以”K“打头,也会先执行以”K“打头的脚本链接,然后再执行以”S“打头的脚本链接,以保证这个服务进程是重新启动的。要注意在这些脚本的最后,都有一个S99local@的链接,这个链接是链接到/etc/rc.d/rc.local,而不是象其它脚本链接一样链接到/etc/rc.d/init.d下。可以在这个rc.local加入一些每个运行级别都要执行但又必须在系统服务进程启动后才能执行的命令,比如说对一些系统服务程序的参数设置。执行这些脚本之后,下面就要执行一个在每个运行级别都要执行的命令:
  ud:nce:/sbin/update
  这句话表明每一个运行级别都要运行命令update,此程序每隔30秒把内存缓冲区的内容回写一次,称为"同步",以防止系统崩溃或突然掉电造成的数据丢失和损坏。在这条命令之后,系统要设置一个陷阱,处理Ctrl-Alt-Del三个键同时按下时的执行动作。
  ca::ctrlaltdel:/sbin/shutdown -t3 -r now
  这样,当用户按下Ctrl-Alt-Del时,系统就会执行/sbin/shutdown -t3 -r now这个命令重新启动系统。如果你要使Ctrl-Alt-Del失效,在这一行的前面加上一个”#“,也就是把它注释掉就行了。
  再往下,我们可以看到这一行:
  pf:owerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
  这是处理在突然断电时系统执行的命令的。要让系统执行这个命令,你需要有UPS的支持并要启动powerd服务进程。与此相对应,如果在shutdown命令还没有执行完成时,电源又重新恢复正常,则系统会执行下面的命令中止shutdown命令:
  pr:12345owerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
  最后,系统要执行下列的命令,产生6个控制台:
  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
  这些操作都是通过getty进行的。mingetty是getty的简化,不能处理串口操作。getty的功能一般包括: 打开终端线,并设置模式;输出登录界面及提示,接受用户名的输入;以该用户名作为login的参数,加载login程序等等。缺省的登录提示记录在/etc/issue文件中,但每次启动,一般都会由rc.local脚本根据系统环境重新生成。大家可以看到,在第二个字段上(也就是runlevel字段)并列有几个运行级别2345,这表明系统只有在2345运行级别时才会启动这些进程。respawn的意思在前面已经介绍过,这里就不说了。在产生这六个控制台后,每一个控制台都会出现login:提示符,系统的启动过程也就到此结束了,此时只要输入你的用户名和口令,你就开始正常地使用linux了。
  
  

原文转自:http://www.ltesting.net