在提及Unix System-V Init之前,让我们想一想Windows的安全模式与Android的不同启动模式。
①在Windows启动的时候,可以按下F8,然后选择“安全模式”启动,而安全模式启动又分为带有网络和不适用网络的安全启动。显然,以不同的安全模式启动,系统在初始化时做的事情也不一样,带有网络的安全模式需要额外的初始化网卡等工作。我不了解Windows加载器(bootloader)是如何将不同启动模式的信息(bootmode)告诉Windows的,但是显然他们有约定一种方式来传递信息。或许是类似于u-boot总的bootargs,或许是在磁盘某个特殊的位置写下了对应的信息。
②经常刷机或者对Android启动熟悉的同学,应该知道Android有几种不同的启动模式,例如:recovery mode、 fastmode。不同的启动模式作用各不相同,例如fastmode一般用于烧写Image。Android或者由Android系统更改的OS,启动模式一般都是由u-boot(bootloader)通过bootargs传递给内核,或者是在Flash中设置Flag。在Android的init程序(第一个被启动的应用程序,可能由init=来指定)启动后根据标志位或者Flasg启动不同的程序,或者使用uramdisk中不同的init.*.rc文件,从而达到不同bootmode下启动不同service,做不同设置的功能。
对于Linux/Unix系统,对于服务器,或许在它正常运行的时候不应该启动X(GUI),对于桌面Destop则需要启动X,因此不同的bootmode的需求一样存在;Unix SystemV的Init使用runlevel来决定启动不同的程序。符合LBS 4.1.0的系统不同的runlevel的约定如下表(来源于Wikipedia Runlevel词条):
ID | Name | Description |
---|---|---|
0 | Halt | Shuts down the system. |
1 | Single-user Mode | Mode for administrative tasks.[2][2] |
2 | Multi-user Mode | Does not configure network interfaces and does not export networks services.[3] |
3 | Multi-user Mode with Networking | Starts the system normally.[4] |
4 | Not used/User-definable | For special purposes. |
5 | Start the system normally with appropriate display manager. ( with GUI ) | Same as runlevel 3 + display manager. |
6 | Reboot | Reboots the system. |
七个Runlevel,可以按类分为:
对于前面提到的不启动GUI的Server,很可能的runlevel很可能为3,而一个desktop系统则很可能是5。
Unix SystemV 的init的执行过程按照如下:
对于/etc/inittab中的runlevel设定,一般形如:
# The default runlevel. id:5:initdefault:
其中id:5指定了runlevel为5。
①例如一个使用Yocto编译出来的rootfs中,runlevel=6的etc/rc6.d文件夹中软连接文件列表如下:
$ ls rc6.d/ -l | awk -F' ' '{print $9 $10 $11}' K10dropbear->../init.d/dropbear K19avahi-daemon->../init.d/avahi-daemon K20apmd->../init.d/apmd K20dbus-1->../init.d/dbus-1 K20hwclock.sh->../init.d/hwclock.sh K20psplash.sh->../init.d/psplash.sh K20syslog->../init.d/syslog K20weston->../init.d/weston K21rc.pvr->../init.d/rc.pvr K22ofono->../init.d/ofono K31alsa-state->../init.d/alsa-state K60rpcbind->../init.d/rpcbind K64neard->../init.d/neard K80networking->../init.d/networking S20sendsigs->../init.d/sendsigs S25save-rtc.sh->../init.d/save-rtc.sh S30urandom->../init.d/urandom S31umountnfs.sh->../init.d/umountnfs.sh S40umountfs->../init.d/umountfs S90reboot->../init.d/reboot
②例如,一个使用Yocto编译出来的Rootfs中,runlevel=0的etc/rc6.d文件夹文件列表如下:
$ ls rc0.d/ -l | awk -F' ' '{print $9 $10 $11}' K10dropbear->../init.d/dropbear K19avahi-daemon->../init.d/avahi-daemon K20apmd->../init.d/apmd K20dbus-1->../init.d/dbus-1 K20hwclock.sh->../init.d/hwclock.sh K20psplash.sh->../init.d/psplash.sh K20syslog->../init.d/syslog K20weston->../init.d/weston K21rc.pvr->../init.d/rc.pvr K22ofono->../init.d/ofono K31alsa-state->../init.d/alsa-state K60rpcbind->../init.d/rpcbind K64neard->../init.d/neard K80networking->../init.d/networking S20sendsigs->../init.d/sendsigs S25save-rtc.sh->../init.d/save-rtc.sh S30urandom->../init.d/urandom S31umountnfs.sh->../init.d/umountnfs.sh S40umountfs->../init.d/umountfs S90halt->../init.d/halt
从①②例子中可以看到如下特征:
其中:
在①中,runlevel=6,所以是restart模式,根据优先级,可以知道先是停止dropbear服务,然后发送restart信号通知(需要从/etc/init.d/sendsig从看出),最后是reboot。
在②中,runlevel=6,所以是restart模式,根据优先级,可以知道先是停止dropbear服务,然后发送restart信号通知(需要从/etc/init.d/sendsig从看出),最后是halt。
另外有一个图片可以很好的表示启动解析执行文件顺序:
图片来源于washington.edu
图中的黑实线表示目录层次结构,虚线表示软连接,而带阴影的曲线表示的是启动过程中所解析和执行了的文件。
要在系统的时候启动一个程序,只需要在/etc/init.d中添加一个service,并能够根据传进来的参数(例如start、stop、restart,对于启动时start)做出相应的处理即可。然后再根据程序需要在哪个runlevel下面自动运行,在对应的rcX.d中的建立一个名字正确(S/K + Priority)软链接指向service。
参考:
[1] Boot to runlevel 3
[2] Change Runlevels at Boot time
[3] The init process and init.rc
[4] Starting Your Software Automatically on Boot
如果文章有格式问题,请移步:http://www.hexiongjun.com/?p=103
转载请注明出处。作者:TonyHo hexiongjun.com