Linux 启动顺序 添加开机启动服务 rc?.d rc.local init.d System run levels and init.d scripts

时间:2022-08-14 15:38:59

最近因Minecraft服务器开机启动的问题纠结了半天...所以没办法..只能自己研究下Linux的开机启动

刚开始网上查/etc/rc.local能实现开机自动运行脚本..但是不知道为啥..

后来偶然在rc?.d/README发现了玄机...再后来一直顺着README的方向看下去...终于明白了

Ubuntu 的 运行级别

  • 0 系统停机
  • 1 单用户或系统维护状态
  • 2~5 多用户
  • 6 重新启动
我们通常运行的2~5级别
/etc/rc2.d/README 摘要
The scripts in this directory are executed each time the system enters
this runlevel.


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


To disable a service in this runlevel, rename its script in this
directory so that the new name begins with a 'K' and a two-digit
number, and run 'update-rc.d script defaults' to reorder the scripts
according to dependencies.  A warning about the current runlevels
being enabled not matching the LSB header in the init.d script will be
printed.  To re-enable the service, rename the script back to its
original name beginning with 'S' and run update-rc.d again.


For a more information see /etc/init.d/README.

这个目录的脚本在系统进入这个运行级别的时候就被启动.

这些脚本全是目标位于/etc/init.d/的符号链接

S??XXX, S代表启动,K代表停止,??数字代表顺序
root@ubuntu:/etc/rc2.d# ll
total 20
drwxr-xr-x   2 root root  4096  7月 27 10:21 ./
drwxr-xr-x 131 root root 12288  7月 27 10:04 ../
-rw-r--r--   1 root root   677  6月  4  2013 README
lrwxrwxrwx   1 root root    20  7月 25 22:19 S20kerneloops -> ../init.d/kerneloops*
lrwxrwxrwx   1 root root    27  7月 25 22:19 S20speech-dispatcher -> ../init.d/speech-dispatcher*
lrwxrwxrwx   1 root root    15  7月 25 22:19 S50rsync -> ../init.d/rsync*
lrwxrwxrwx   1 root root    15  7月 25 22:19 S50saned -> ../init.d/saned*
lrwxrwxrwx   1 root root    19  7月 25 22:19 S70dns-clean -> ../init.d/dns-clean*
lrwxrwxrwx   1 root root    18  7月 25 22:19 S70pppd-dns -> ../init.d/pppd-dns*
lrwxrwxrwx   1 root root    14  7月 25 22:19 S75sudo -> ../init.d/sudo*
lrwxrwxrwx   1 root root    21  7月 25 22:19 S99grub-common -> ../init.d/grub-common*
lrwxrwxrwx   1 root root    18  7月 25 22:19 S99ondemand -> ../init.d/ondemand*
lrwxrwxrwx   1 root root    18  7月 25 22:19 S99rc.local -> ../init.d/rc.local*
可以看出S99rc.local 会启动 /etc/init.d/rc.local 且是最后执行的

来到/etc/init.d,查看README
Configuration of System V init under Debian GNU/Linux

Most Unix versions have a file here that describes how the scripts
in this directory work, and how the links in the /etc/rc?.d/ directories
influence system startup/shutdown.

For Debian, this information is contained in the policy manual, chapter
"System run levels and init.d scripts".  The Debian Policy Manual is
available at:

    http://www.debian.org/doc/debian-policy/#contents

The Debian Policy Manual is also available in the Debian package
"debian-policy".  When this package is installed, the policy manual can be
found in directory /usr/share/doc/debian-policy. If you have a browser
installed you can probably read it at

    file://localhost/usr/share/doc/debian-policy/

Some more detailed information can also be found in the files in the
/usr/share/doc/sysv-rc directory.

Debian Policy dictates that /etc/init.d/*.sh scripts must work properly
大多数的Unix版本在这里的文件描述了这个文件夹的脚本怎样工作 --- (额,这句貌似在说README,废话么)
 ...xxx.xxx..xxx一堆跟前面的README重复的话
粘一下(字很小,建议查看源网站):
9.3 System run levels and init.d scripts

9.3.1 Introduction

The /etc/init.d directory contains the scripts executed by init at boot time and when the init state (or "runlevel") is changed (see init(8)).

There are at least two different, yet functionally equivalent, ways of handling these scripts. For the sake of simplicity, this document describes only the symbolic link method. However, it must not be assumed by maintainer scripts that this method is being used, and any automated manipulation of the various runlevel behaviors by maintainer scripts must be performed using update-rc.d as described below and not by manually installing or removing symlinks. For information on the implementation details of the other method, implemented in the file-rc package, please refer to the documentation of that package.

These scripts are referenced by symbolic links in the /etc/rcn.d directories. When changing runlevels, init looks in the directory /etc/rcn.d for the scripts it should execute, where n is the runlevel that is being changed to, or S for the boot-up scripts.

The names of the links all have the form Smmscript or Kmmscript where mm is a two-digit number and script is the name of the script (this should be the same as the name of the actual script in /etc/init.d).

When init changes runlevel first the targets of the links whose names start with a K are executed, each with the single argument stop, followed by the scripts prefixed with an S, each with the single argument start. (The links are those in the /etc/rcn.d directory corresponding to the new runlevel.) The K links are responsible for killing services and the S link for starting services upon entering the runlevel.

For example, if we are changing from runlevel 2 to runlevel 3, init will first execute all of the K prefixed scripts it finds in /etc/rc3.d, and then all of the S prefixed scripts in that directory. The links starting with K will cause the referred-to file to be executed with an argument of stop, and the S links with an argument of start.

The two-digit number mm is used to determine the order in which to run the scripts: low-numbered links have their scripts run first. For example, the K20 scripts will be executed before the K30 scripts. This is used when a certain service must be started before another. For example, the name server bind might need to be started before the news server inn so that inn can set up its access lists. In this case, the script that starts bind would have a lower number than the script that starts inn so that it runs first:

     /etc/rc2.d/S17bind
     /etc/rc2.d/S70inn
The two runlevels 0 (halt) and 6 (reboot) are slightly different. In these runlevels, the links with an S prefix are still called after those with a K prefix, but they too are called with the single argument stop.

9.3.2 Writing the scripts

Packages that include daemons for system services should place scripts in /etc/init.d to start or stop services at boot time or during a change of runlevel. These scripts should be named /etc/init.d/package, and they should accept one argument, saying what to do:

start
start the service,

stop
stop the service,

restart
stop and restart the service if it's already running, otherwise start the service

reload
cause the configuration of the service to be reloaded without actually stopping and restarting the service,

force-reload
cause the configuration to be reloaded if the service supports this, otherwise restart the service.

The start, stop, restart, and force-reload options should be supported by all scripts in /etc/init.d, the reload option is optional.

The init.d scripts must ensure that they will behave sensibly (i.e., returning success and not starting multiple copies of a service) if invoked with start when the service is already running, or with stop when it isn't, and that they don't kill unfortunately-named user processes. The best way to achieve this is usually to use start-stop-daemon with the --oknodo option.

Be careful of using set -e in init.d scripts. Writing correct init.d scripts requires accepting various error exit statuses when daemons are already running or already stopped without aborting the init.d script, and common init.d function libraries are not safe to call with set -e in effect[81]. For init.d scripts, it's often easier to not use set -e and instead check the result of each command separately.

If a service reloads its configuration automatically (as in the case of cron, for example), the reload option of the init.d script should behave as if the configuration has been reloaded successfully.

The /etc/init.d scripts must be treated as configuration files, either (if they are present in the package, that is, in the .deb file) by marking them as conffiles, or, (if they do not exist in the .deb) by managing them correctly in the maintainer scripts (see Configuration files, Section 10.7). This is important since we want to give the local system administrator the chance to adapt the scripts to the local system, e.g., to disable a service without de-installing the package, or to specify some special command line options when starting a service, while making sure their changes aren't lost during the next package upgrade.

These scripts should not fail obscurely when the configuration files remain but the package has been removed, as configuration files remain on the system after the package has been removed. Only when dpkg is executed with the --purge option will configuration files be removed. In particular, as the /etc/init.d/package script itself is usually a conffile, it will remain on the system if the package is removed but not purged. Therefore, you should include a test statement at the top of the script, like this:

     test -f program-executed-later-in-script || exit 0
Often there are some variables in the init.d scripts whose values control the behavior of the scripts, and which a system administrator is likely to want to change. As the scripts themselves are frequently conffiles, modifying them requires that the administrator merge in their changes each time the package is upgraded and the conffile changes. To ease the burden on the system administrator, such configurable values should not be placed directly in the script. Instead, they should be placed in a file in /etc/default, which typically will have the same base name as the init.d script. This extra file should be sourced by the script when the script runs. It must contain only variable settings and comments in SUSv3 sh format. It may either be a conffile or a configuration file maintained by the package maintainer scripts. See Configuration files, Section 10.7 for more details.

To ensure that vital configurable values are always available, the init.d script should set default values for each of the shell variables it uses, either before sourcing the /etc/default/ file or afterwards using something like the : ${VAR:=default} syntax. Also, the init.d script must behave sensibly and not fail if the /etc/default file is deleted.

Files and directories under /run, including ones referred to via the compatibility paths /var/run and /var/lock, are normally stored on a temporary filesystem and are normally not persistent across a reboot. The init.d scripts must handle this correctly. This will typically mean creating any required subdirectories dynamically when the init.d script is run. See /run and /run/lock, Section 9.1.4 for more information.

9.3.3 Interfacing with the initscript system

Maintainers should use the abstraction layer provided by the update-rc.d and invoke-rc.d programs to deal with initscripts in their packages' scripts such as postinst, prerm and postrm.

Directly managing the /etc/rc?.d links and directly invoking the /etc/init.d/ initscripts should be done only by packages providing the initscript subsystem (such as sysv-rc and file-rc).

9.3.3.1 Managing the links

The program update-rc.d is provided for package maintainers to arrange for the proper creation and removal of /etc/rcn.d symbolic links, or their functional equivalent if another method is being used. This may be used by maintainers in their packages' postinst and postrm scripts.

You must not include any /etc/rcn.d symbolic links in the actual archive or manually create or remove the symbolic links in maintainer scripts; you must use the update-rc.d program instead. (The former will fail if an alternative method of maintaining runlevel information is being used.) You must not include the /etc/rcn.d directories themselves in the archive either. (Only the sysvinit package may do so.)

By default update-rc.d will start services in each of the multi-user state runlevels (2, 3, 4, and 5) and stop them in the halt runlevel (0), the single-user runlevel (1) and the reboot runlevel (6). The system administrator will have the opportunity to customize runlevels by simply adding, moving, or removing the symbolic links in /etc/rcn.d if symbolic links are being used, or by modifying /etc/runlevel.conf if the file-rc method is being used.

To get the default behavior for your package, put in your postinst script

     		update-rc.d package defaults
and in your postrm

     		if [ "$1" = purge ]; then
     		update-rc.d package remove
     		fi
. Note that if your package changes runlevels or priority, you may have to remove and recreate the links, since otherwise the old links may persist. Refer to the documentation of update-rc.d.

This will use a default sequence number of 20. If it does not matter when or in which order the init.d script is run, use this default. If it does, then you should talk to the maintainer of the sysvinit package or post to debian-devel, and they will help you choose a number.

For more information about using update-rc.d, please consult its man page update-rc.d(8).

9.3.3.2 Running initscripts

The program invoke-rc.d is provided to make it easier for package maintainers to properly invoke an initscript, obeying runlevel and other locally-defined constraints that might limit a package's right to start, stop and otherwise manage services. This program may be used by maintainers in their packages' scripts.

The package maintainer scripts must use invoke-rc.d to invoke the /etc/init.d/* initscripts, instead of calling them directly.

By default, invoke-rc.d will pass any action requests (start, stop, reload, restart...) to the /etc/init.d script, filtering out requests to start or restart a service out of its intended runlevels.

Most packages will simply need to change:

     /etc/init.d/<package>
     	      <action>
in their postinst and prerm scripts to:

     	if which invoke-rc.d >/dev/null 2>&1; then
     		invoke-rc.d package <action>
     	else
     		/etc/init.d/package <action>
     	fi
A package should register its initscript services using update-rc.d before it tries to invoke them using invoke-rc.d. Invocation of unregistered services may fail.

For more information about using invoke-rc.d, please consult its man page invoke-rc.d(8).

9.3.4 Boot-time initialization

There used to be another directory, /etc/rc.boot, which contained scripts which were run once per machine boot. This has been deprecated in favour of links from /etc/rcS.d to files in /etc/init.d as described in Introduction, Section 9.3.1. Packages must not place files in /etc/rc.boot.

9.3.5 Example

An example on which you can base your /etc/init.d scripts is found in /etc/init.d/skeleton.
翻译如下:

介绍
/etc/init.d目录包含着当运行级别改变时在boot时启动的脚本(不是重点)
有两点不同...一堆废话夹中间...出于易读考虑,这篇文档只描述符号链接方法.xxx xxx...
不同运行级别的自动化操作必须用update-rc.d来安装或者删除符号链接.
然后...K代表停止,S代表执行,数字代表顺序(前面已说过)

写脚本
包含系统服务daemon(后台程序)的packages(包)应该把脚本放在/etc/init.d来开启和停止服务at boot time 或者 during  a change of runlevel,
这些脚本应该被命名为/etc/init.d/package,他们应该接受这些参数
start
start the service,
stop
stop the service,
restart
stop and restart the service if it's already running, otherwise start the service
reload
cause the configuration of the service to be reloaded without actually stopping and restarting the service,
force-reload
cause the configuration to be reloaded if the service supports this, otherwise restart the service.

在init.d里面的脚本都应该支持这些参数.
管理链接(重要)
By default update-rc.d will start services in each of the multi-user state runlevels (2, 3, 4, and 5) and stop them in the halt runlevel (0), the single-user runlevel (1) and the reboot runlevel (6). 
默认update-rc.d会在多人运行级别(2,3,4,5)和在停止级别(halt level(0)),单人级别(1)开启服务 命令!:
update-rc.d package defaults 添加链接
and in your postrm 在你的发出的移除命令中
if [ "$1" = purge ]; then
     		update-rc.d package remove
     		fi
可以看出 update-rc.d package remove是移除链接 参数-f代表强制(如果init.d没有该脚本)
init.d脚本例子:
An example on which you can base your /etc/init.d scripts is found in /etc/init.d/skeleton.
---------------- 另外我知道的 比如 /etc/init.d/mysqld start 可以写为 service mysqld start
============================================rc.local实现开机启动脚本原理================================================

root@ubuntu:/etc/rc2.d# ll
total 20
drwxr-xr-x   2 root root  4096  7月 27 10:21 ./
drwxr-xr-x 131 root root 12288  7月 27 10:04 ../
-rw-r--r--   1 root root   677  6月  4  2013 README
lrwxrwxrwx   1 root root    20  7月 25 22:19 S20kerneloops -> ../init.d/kerneloops*
lrwxrwxrwx   1 root root    27  7月 25 22:19 S20speech-dispatcher -> ../init.d/speech-dispatcher*
lrwxrwxrwx   1 root root    15  7月 25 22:19 S50rsync -> ../init.d/rsync*
lrwxrwxrwx   1 root root    15  7月 25 22:19 S50saned -> ../init.d/saned*
lrwxrwxrwx   1 root root    19  7月 25 22:19 S70dns-clean -> ../init.d/dns-clean*
lrwxrwxrwx   1 root root    18  7月 25 22:19 S70pppd-dns -> ../init.d/pppd-dns*
lrwxrwxrwx   1 root root    14  7月 25 22:19 S75sudo -> ../init.d/sudo*
lrwxrwxrwx   1 root root    21  7月 25 22:19 S99grub-common -> ../init.d/grub-common*
lrwxrwxrwx   1 root root    18  7月 25 22:19 S99ondemand -> ../init.d/ondemand*
lrwxrwxrwx   1 root root    18  7月 25 22:19 S99rc.local -> ../init.d/rc.local*

有了上部分的理论基础, 从上面S99rc.local可看出,系统会在开机时启动/etc/init.d/rc.local 看看/etc/init.d/rc.local有什么东西
#! /bin/sh
### BEGIN INIT INFO
# Provides:          rc.local
# Required-Start:    $all
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:
# Short-Description: Run /etc/rc.local if it exist
### END INIT INFO


PATH=/sbin:/usr/sbin:/bin:/usr/bin

. /lib/init/vars.sh
. /lib/lsb/init-functions

do_start() {
        if [ -x /etc/rc.local ]; then
                [ "$VERBOSE" != no ] && log_begin_msg "Running local boot scripts (/etc/rc.local)"
                /etc/rc.local
                ES=$?
                [ "$VERBOSE" != no ] && log_end_msg $ES
                return $ES
        fi


case "$1" in
    start)
        do_start
        ;;
    restart|reload|force-reload)
        echo "Error: argument '$1' not supported" >&2
        exit 3
        ;;
    stop)
        ;;
    *)
        echo "Usage: $0 start|stop" >&2
        exit 3
        ;;
esac

可以看出,/etc/init.d/rc.local会执行/etc/rc.local这个脚本里面的内容,也难怪在/etc/rc.local添加脚本会顺利的执行