开机自启动:从busybox到debian

需要在mint上设置opensips的开机自启动,翻了半天资料还是一知半解。最后在opensips的官方文档,查到用下面的语句,添加自启动成功。不过貌似还是会有启动不成功,没有仔细测试过。

update-rc.d opensips default 99

早上抽空看了下这个话题,粗略记录。

 

从kernel和busybox开始说起

那,咱尽量把故事给串起来。先说说kernel里面设计的init的执行过程,

1) 根据启动参数来执行init,“启动参数”包括initrd或initramfs里面的init,以及cmdline里面的init参数。

2) 如果未能成功init,则继续执行“/sbin/init”。

6) 如果失败,则继续寻找并执行“/etc/init”,“/bin/init”,“/bin/sh”等脚本,还是未能进入init,则报panic。

如果使用busybox的话,一般会把/sbin/init软连接到busybox去,让busybox来完成init工作。而我们知道busy的init基本是以来inittab完成的,inittab不存在的时候,它会去找rcS。下面是一个busybox inittab的例子。

# Executed on startup
::sysinit:/etc/rc.d/rc.sysinit
# Start an "askfirst" shell on the console (whatever that may be)
ttyS0::askfirst:/sbin/getty -L ttyS0 115200 vt100
# Stuff to do when restarting the init process
::restart:/sbin/init
# Run daemons
::wait:/usr/etc/rc.d/rc start
# Stuff to do before rebooting
::shutdown:/etc/rc.d/rc stop
::shutdown:/etc/rc.d/rc.stop
::shutdown:/bin/umount -a -r
null::respawn:/bin/infctld -m -c
null::respawn:/bin/lighttpd -D -f /etc/lighttpd.conf
null::respawn:/bin/dropbear -F -d /etc/persistent/dropbear_dss_host_key -r /etc/

针对这个inittab,根据busybox中各action的执行顺序,具体分析下busybox都做了什么:

1、先是执行sysinit,所以这里是新开了一个进程,执行/etc/rc.d/rc.sysinit;结束之前是不会往下执行的。

2、然后执行wait和once,再这里是/etc/rc.d/rc start,并等待它结束(termination)。

3、然后执行askfirst和respawn。askfirst是在ttys0打开调试口,然后等待我们敲入一个回车;respawn是启动了几个重要的程序。这两个action一直在监视自己启动的子进程是否退出,如果退出,重新启动他们。

 

debian里的init.d

这里猜测启动后init的过程和上面的一样,先对这里的init有个感官认识,

$ which init
/sbin/init
$ file /sbin/init
/sbin/init: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xb9aa33d2067c8a0f80336122dd6249758f61fdaa, stripped

man inittab描述,inittab本身是init命令的配置脚本;init提供了一个general的dispatcher。我们先看看inittab里面都有什么:

$ cat inittab
# /etc/inittab: init(8) configuration.
# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $

# The default runlevel.
id:2:initdefault:

# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS

# What to do in single-user mode.
~~:S:wait:/sbin/sulogin

# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.

l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin

# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

# Action on special keypress (ALT-UpArrow).
#kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."

# What to do when the power fails/returns.
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop

# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
#  <id>:<runlevels>:<action>:<process>
#
# Note that on most Debian systems tty7 is used by the X Window System,
# so if you want to add more getty's go ahead but skip tty7 if you run X.
#
1:2345:respawn:/sbin/getty --noclear 38400 tty1 
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6

# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100

# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3


#Spawn a getty on Raspberry Pi serial line
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

顺序分析下这个inittab:

1、显示sysinit,哈,这里的sysinit是执行/etc/init.d/rcS。然后我查看rcS发现,它事实上是执行了/etc/init.d/rc S。然后cat /etc/rcS.d/README,看到下面这段话:

The scripts in this directory whose names begin with an 'S' are executed once when booting the system, even when booting directly into single user mode.

The scripts are all symbolic links whose targets are located in /etc/init.d/ .

To disable a script in this directory, rename it so that it begins with a 'K' and run 'update-rc.d script defaults' to update the order using the script dependencies.

那,所以就是,这个目录下的软连接指向的脚本,都是要在系统init的一开始就要执行的。如果要disable某一项,重命名,把它名字里的S给改成K。

2、initdefault行定义了要执行的runlevel,init会根据它去决定执行具体的哪些脚本;最终是执行我们放在/etc/rc*run_level*.d文件夹里的软连接,如上一条,执行的是rcS.d下的脚本。

3、接下来是wait、respawn等这些。

事实上,它和上面busybox的init不同之处,就在于它多出runlevel;同时,我们想要启动的脚本都添加了软连接到rc*run_level*.d文件夹下,不同runlevel下,会去用wait这一action依次去执行相应目录下的所有脚本。

突然醒悟,原来这里的rc是runlevel changes的意思。

 

新的upstart

debian相关话题:http://refspecs.linuxfoundation.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/tocsysinit.html

upstart是新的管理开机自启动程式的方法。ubuntu的文档说,从6.1开始,他们就在用这种新方法管理开机自启动了。而且upstart和上面的init过程是不冲突的:

1、upstart相关的文件夹是/etc/init。他们本身只是为了支持service方式存在的。

2、/etc/init.d里面存放着真正的启动脚本,是sysinit和upstart共用的。事实上,很多服务,在执行servie myservice start时,只是打印了一个“使用 service方式启动”,其余的工作还是由init.d下的脚本完成的。

3、我们可以通过修改/etc/default里面的一些配置文件,来实现对sysint或者upstart的控制。

4、/etc/init/rc-init.conf控制着upstart的行为,手动配置;updata-rc.d则是对传统的sysinit进行配置,改变rc.d下面的文件等。

当我们需要想upstart添加或删除一个service时,我们需要:

1、upstart没有runlevel的概念,在这里,所有的都是由‘依赖关系’驱动的事件。添加一个service意味着需要往/etc/init里面添加一个config文件,同时,有需要的话,可以在/etc/default文件夹添加一个配置文件。

2、需要移除一个service时,如果在/etc/default没有配置文件,那么直接编辑/etc/init/下相应的配置文件即可。

一些重要的upstart用到的工具:

Controlling Services - interchangeable with the "service" command

initctl - can use in place of "service" with the commands bellow. Run initctl help.

start - start a service

stop - stop a service

reload - sends a SIGHUP signal to running process

restart - restarts a service without reloading its job config file

status - requests status of service

Rebooting and Powering off the system

halt - shutdown the system then power off

poweroff - shutdown the system then power off

reboot - reboot the system

shutdown - bring the system down

Misc Upstart Commands - you generally don't use these directly

init - Upstart process management daemon 

runlevel - Backward compatibility with traditional runlevels

telinit - Backward compatibility with traditional runlevels

upstart-udev-bridge - Bridge between upstart and udev

 下面是一个service的config脚本,更详细的可以参考《upstart cookbook》,或者是查看man 5 init:

# myservice - myservice job file

description "my service description"
author "Me <myself@i.com>"

# Stanzas
#
# Stanzas control when and how a process is started and stopped
# See a list of stanzas here: http://upstart.ubuntu.com/wiki/Stanzas#respawn

# When to start the service
start on runlevel [2345]

# When to stop the service
stop on runlevel [016]

# Automatically restart process if crashed
respawn

# Essentially lets upstart know the process will detach itself to the background
expect fork

# Run before process
pre-start script
    [ -d /var/run/myservice ] || mkdir -p /var/run/myservice
    echo "Put bash code here"
end script

# Start the process
exec myprocess

 it's time to go to bed :)

 

最新的systemd

systemd之所以叫这个名字,很大程度上是因为它名字里有个d,sorry,我说的是它是严重依赖于D-bus的。

有人说以后的linux distribution基本都会用systemd了,理由之一是sysinit是从unix继承来的,理由之二是sysinit已经统治很久了,理由之三是sysinit做了很多多余的事,理由之四是sysinit依赖shell进而影响了效率。。。sysinit应用还是很广的,取代也不会是一两天的事情,但是了解下极有前途的新秀也不错。

它是替代了init哦!init不只是sysV-style或者是BSD-style,还有其它改进的版本;我们上面介绍到的就是sysV-style,两者最大区别是,sysV有runlevel的概念,而且是遵照inittab行事。

好吧,翻了一下,还了解到,这个机制是仿照MAC OS里面launchd来的。貌似是个比较复杂的话题,那就改天再深入研究吧。

 

参考文档:

1、ubuntu bootup howto,https://help.ubuntu.com/community/UbuntuBootupHowto

2、inittab,http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.files%2Fdoc%2Faixfiles%2Finittab.htm

3、systemd,http://freedesktop.org/wiki/Software/systemd/

posted @ 2013-07-30 00:18  Biiigfish  阅读(7274)  评论(0编辑  收藏