Ubuntu启动流程学习笔记(Upstart事件机制)

Debian启动系统维护者们说,现在的Debian Sysvinit启动系统因为其不可靠性,将会逐渐被upstart代替。
UpStart: 基于事件的启动系统
Sysvinit:基于结果的启动系统

SysVinit守护进程(sysvinit软件包)是一个基于运行级别的系统,它使用运行级别(单用户、多用户以及其他更多级别)和链接(位于/etc /rc?.d目录中,分别链接到/etc/init.d中的init脚本)来启动和关闭系统服务。Upstart init守护进程(upstart软件包)则是基于事件的系统,它使用事件来启动和关闭系统服务。


几个很重要的定义:
event: 事件, 是指系统状态的一种改变,这种改变会被通知给init进程。举例来说,boot loader会触发startup事件,系统进入runlevel 2的时候会触发runlevel 2事件,某个文件系统被挂载时会触发path-mounted事件, USB设备的插拔也都会产生相应的事件。这些时间会被通知给init进程,然后init进程来决定系统如何处理这些事件。
job: 作业,一项作业是init进程读入的一系列指令。你可以使用initctl start或initctl stop命令来开始或停止某项作业,这是调用作业的一种方式。另一种方式是当系统被告知发生什么事件event后,运行该事件所对应的作业。可用sudo initctl list命令列出所有系统作业的运行状态。
task: 任务, a job that performs its work and returns to a waiting state when it is done. 中文是一种完成指定工作后进去等待状态的作业。
service: 服务,a job that does not normally terminate by itself. 举个例子来说, gettys 是以服务来实现的。 init进程监视所有服务,并在服务失败的时候重启服务。

/etc/event.d目录下是所有init进程读取的job(作业)定义。该目录下的每个文件都定义了一个job(作业),和对应该作业的事件。这和windows下的消息机制有些类似。在这里新建一个文件myjob:
$cat /etc/event.d/myjob
start on hithere
script
    echo  "Hi there, here I am!" > /tmp/myjob.out
    date >> /tmp/myjob.out
end script
这个文件定义了一个作业,在作业在收到hithere事件后触发。该作业运行时将"Hi there, here I am!"和系统时间打印到/tmp/myjob.out
我们可以使用sudo initctl emit hithere来触发hithere事件,从而导致这项作业的执行.
 $ sudo initctl emit hithere
hithere
myjob (start) waiting
myjob (start) starting
myjob (start) pre-start
myjob (start) spawned, process 8918
myjob (start) post-start, (main) process 8918
myjob (start) running, process 8918
myjob (stop) running
myjob (stop) stopping
myjob (stop) killed
myjob (stop) post-stop
myjob (stop) waiting
$ cat /tmp/myjob.out
Hi there, here I am!
Mon Oct 26 23:44:29 CST 2009
$ sudo initctl list myjob
myjob (stop) waiting
这个例子演示了事件如何触发作业的运行机制。

在明白事件机制后,我们来看一下ubuntu是怎么利用事件机制来进行启动的。
init启动后读入event.d中的所有作业定义,看其中的一个
$ cat /etc/event.d/rc2
# rc2 - runlevel 2 compatibility
#
# This task runs the old sysv-rc runlevel 2 ("multi-user") scripts. It
# is usually started by the telinit compatibility wrapper.
start on runlevel 2
stop on runlevel [!2]
console output
script
    set $(runlevel --set 2 || true)
    if [ "$1" != "unknown" ]; then
        PREVLEVEL=$1
         RUNLEVEL=$2
        export PREVLEVEL RUNLEVEL
    fi

    exec /etc/init.d/rc 2
end script
看前两行和倒数第二行,
前两行意思:这里用的前面所说的事件机制,当runlevel为2的时候,系统运行script中的语句
倒数第二行:调用/etc/init.d/rc,传入参数只有一个2
接下来看/etc/init.d/rc文件, 这个文件很长,
cat /etc/init.d/rc
#! /bin/sh
#
# rc
#
# Starts/stops services on runlevel changes.
...
# Is there an rc directory for this new runlevel?
if [ -d /etc/rc$runlevel.d ]
then
...
    # First, run the KILL scripts.
    if [ "$previous" != N ]
    then
        ...
        for s in /etc/rc$runlevel.d/K*
        ...
    # Now run the START scripts for this runlevel.
    for s in /etc/rc$runlevel.d/S*
    ...
...
这里只简短摘取其中一些重要的地方,/etc/init.d/rc文件会根据系统运行级别runlevel来查找文件夹/etc/rc$runlevel.d, 如果runlevel=2, 则查找/etc/rc2.d文件夹, 并运行其中的
/etc/rc$runlevel.d/K* 和 /etc/rc$runlevel.d/S*
脚本。K代表Stop, S代表Start, K*即需要停止的服务等,S*即需要开始运行的服务等,
查看/etc/rc2.d目录下的文件:
$ls -l /etc/rc2.d
total 4
-rw-r--r-- 1 root root 556 2008-04-19 13:05 README
lrwxrwxrwx 1 root root  19 2009-10-12 09:54 S01policykit -> ../init.d/policykit
lrwxrwxrwx 1 root root  17 2009-10-12 09:54 S05vbesave -> ../init.d/vbesave
lrwxrwxrwx 1 root root  15 2009-10-12 09:54 S10acpid -> ../init.d/acpid
lrwxrwxrwx 1 root root  25 2009-10-12 09:54 S10powernowd.early -> ../init.d/powernowd.early
lrwxrwxrwx 1 root root  18 2009-10-12 09:54 S10sysklogd -> ../init.d/sysklogd
lrwxrwxrwx 1 root root  34 2009-10-12 09:54 S10xserver-xorg-input-wacom -> ../init.d/xserver-xorg-input-wacom
...
可以看出/etc/rc2.d下面的文件全都是链接到/etc/init.d目录下的服务程序, 而以S开头的链接名表示以Start参数来执行对应的服务程序,以K开头的链接名表示以Stop参数来执行对应的服务程序。而S和K后面的数字代表启动顺序或关闭顺序。S01policykit会在S05vbesave之前执行,因为01<05。这些细节都在/etc/init.d/rc中实现。


/etc/rcn.d目录中的每一个链接均指向/etc/init.d目录中的一个文件。

/etc/rc.local
当系统启动的时候,在将其他init脚本执行完毕之后,系统就会执行/etc/rc.local文件。可以将用来定制系统的命令放在 rc.local文件中。虽然可以将任何你想要的命令添加到文件中,但是最好还是让这些命令在后台运行。这样一来,如果有些命令挂起,它们不会终止引导进程。

下面是Upstart大致的一个启动过程:
1,内核启动init
2,init找到/etc/event.d/rc-default文件,确定默认的运行级别(X)
3,触发相应的runlevel事件,开始运行/etc/event.d/rcX
4,rcX运行/etc/init.d/rc,传入参数X
5,/etc/init.d/rc脚本进行一系列设置,最后运行相应的/etc/rcX.d/中的脚本
6,/etc/rcX.d/中的脚本按事先设定的优先级依次启动,直至最后给出登录画面(启动X服务器和GDM)

你可能感兴趣的:(Debian,list,ubuntu,脚本,service,作业)