下面以web服务器的启动脚本为例分析在Redhat Linux系统中如何使Daemon进程在系统重启时自动运行。对于其他的系统(如Suse),将在以后补充(可以预计只会有很少的区别)。
1、 设置过程
1.1 首先需要一个启动脚本,假设为httpd,这个脚本必须放置在/etc/rc.d/init/目录下。而且属性设为0755,即(-rwxr-xr-x),UID/GID都设为ROOT,即0。
1.2 然后,Linux系统有七个运行级别,运行级别可以通过runlevel来设置,在/etc/inittab中有详细的说明:
# Default runlevel. The runlevels used by RHS 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:
这里把缺省级别设为5,也就是系统起来后直接进入Xwindows登陆界面,并且是多用户、使用网络的模式。在/etc/rc.d目录下对应于每个运行级别有一个存放Daemon运行脚本的目录rc0.d~rc6.d。我们需要在必要的目录下为httpd脚本建立软连接。软连接最好遵守系统的命名规则。
# ln -s /etc/rc.d/init.d/sshd /etc/rc.d/rc2.d/S55sshd
# ln -s /etc/rc.d/init.d/sshd /etc/rc.d/rc3.d/S55sshd
# ln -s /etc/rc.d/init.d/sshd /etc/rc.d/rc5.d/S55sshd
以上三条命令建立了符号链接,从而保证在 Red Hat Linux 的网络有效前启动安全Shell服务SSHD。某种网络服务的名称应该类似于 SXXnetwork,其中“S”表示系统启动(Start)是运行该服务的脚本,而 "XX" 指定了该服务的启动次序。请选择一个其他启动脚本内未指定的合适的"XX"。类似的,在网络服务关闭后也应该停止SSHD,因此需要建立相应的符号连接。这样的符号链接的命名于启动脚本类似,为KXXnetwork,其中“K”表示不运行或者杀死(KILL),“XX”表示序号,这个序号与启动脚本对于的序号往往不相同。该例子中,网络接口关闭位于脚本 K90network,这里选择SSHD脚本链接为 K25sshd。
# ln -s /etc/rc.d/init.d/sshd /etc/rc.d/rc0.d/K25sshd
# ln -s /etc/rc.d/init.d/sshd /etc/rc.d/rc1.d/K25sshd
# ln -s /etc/rc.d/init.d/sshd /etc/rc.d/rc6.d/K25sshd
设置好这些,重启系统就可以发现你指定的Daemon进程起来了,有类似下面的输出:
Start FOOD … [OK]
Note:事实上,这些软连接不要手动去建立,有一条命令chkconfig可以帮你完成,下面是它的manual手册,你可以通过man 8 chkconfig查看。
NAME
chkconfig - updates and queries runlevel information for
system services
SYNOPSIS
chkconfig --list [name]
chkconfig --add name
chkconfig --del name
chkconfig [--level levels] name <on|off|reset>
chkconfig [--level levels] name
DESCRIPTION
chkconfig provides a simple command-line tool for main
taining the /etc/rc[0-6].d directory hierarchy by reliev
ing system administrators of the task of directly manipu
lating the numerous symbolic links in those directories.
This implementation of chkconfig was inspired by the chk
config command present in the IRIX operating system.
Rather than maintaining configuration information outside
of the /etc/rc[0-6].d hierarchy, however, this version
directly manages the symlinks in /etc/rc[0-6].d. This
leaves all of the configuration information regarding what
services init starts in a single location.
chkconfig has five distinct functions: adding new services
for management, removing services from management, listing
the current startup information for services, changing the
startup information for services, and checking the startup
state of a particular service.
When chkconfig is run without any options, it displays
usage information. If only a service name is given, it
checks to see if the service is configured to be started
in the current runlevel. If it is, chkconfig returns true;
otherwise it returns false. The --level option may be used
to have chkconfig query an alternative runlevel rather
than the current one.
If one of on, off, or reset is specified after the service
name, chkconfig changes the startup information for the
specified service. The on and off flags cause the service
to be started or stopped, respectively, in the runlevels
being changed. The reset flag resets the startup informa
tion for the service to whatever is specified in the init
script in question.
By default, the on and off options affect only runlevels
3, 4, and 5, while reset affects all of the runlevels.
The --level option may be used to specify which runlevels
are affected.
Note that for every service, each runlevel has either a
to 7. For example, --level 35 specifies runlevels 3
and 5.
--add name
This option adds a new service for management by
chkconfig. When a new service is added, chkconfig
ensures that the service has either a start or a
kill entry in every runlevel. If any runlevel is
missing such an entry, chkconfig creates the appro
priate entry as specified by the default values in
the init script.
--del name
The service is removed from chkconfig management,
and any symbolic links in /etc/rc[0-6].d which per
tain to it are removed.
--list name
This option lists all of the services which chkcon
fig knows about, and whether they are stopped or
started in each runlevel. If name is specified,
information in only display about service name.
RUNLEVEL FILES
Each service which should be manageable by chkconfig needs
two or more commented lines added to its init.d script.
The first line tells chkconfig what runlevels the service
should be started in by default, as well as the start and
stop priority levels. If the service should not, by
default, be started in any runlevels, a - should be used
in place of the runlevels list. The second line contains
a description for the service, and may be extended across
multiple lines with backslash continuation.
For example, random.init has these three lines:
# chkconfig: 2345 20 80
# description: Saves and restores system entropy pool for \
# higher quality random number generation.
This says that the random script should be started in lev
els 2, 3, 4, and 5, that its start priority should be 20,
and that its stop priority should be 80. You should be
able to figure out what the description says; the \ causes
the line to be continued. The extra space in front of the
line is ignored.
SEE ALSO
init(8) ntsysv(8) tksysv(8)
AUTHOR
Erik Troan <ewt@redhat.com>
注意上面的runlevel files段!
要是用chkconfig,你应该在你的脚本中遵循一定的约束。下面有详细的说明。
2、 脚本分析
下面分析关键的东东,也就是对应Daemon服务的脚本。这里以httpd为例。
#!/bin/bash <== 这也是一个普通的shell脚本而已:)
#
# Startup script for the Apache Web Server
#
# chkconfig: - 85 15 ç 这里就是告诉chkconfig的参数了!有三个参数,‘-’表示在所有的levels都不运行。一般情况,第一个参数指出涉及哪几个level,第二个参数是start时的序号,第三个参数是kill时的序号。
# description: Apache is a World Wide Web server. It is used to serve \
# HTML files and CGI.
# processname: httpd
# pidfile: /var/run/httpd.pid
# config: /etc/httpd/conf/httpd.conf
ç 对于注释部分,最好是按照这种方式编写!
# Source function library.
. /etc/rc.d/init.d/functions <== 通过‘.’命令引用公共函数:functions中定义了很多公共函数和公共变量,基本上每一个daemon脚本都必须在第一行加入这行命令。
if [ -f /etc/sysconfig/httpd ]; then
. /etc/sysconfig/httpd
<== 有些设置可以放在/etc/sysconfig/目录下对应的文件中,这里的文件往往只是定义一些配置变量,下面是/etc/sysconfig/syslog:
# Options to syslogd
# -m 0 disables 'MARK' messages.
# -r enables logging from remote machines
# -x disables DNS lookups on messages recieved with -r
# See syslogd(8) for more details
SYSLOGD_OPTIONS="-m 0"
# Options to klogd
# -2 prints all kernel oops messages twice; once for klogd to decode, and
# once for processing with 'ksymoops'
# -x disables all klogd processing of oops messages entirely
# See klogd(8) for more details
KLOGD_OPTIONS="-x"
通过点命令引用这个文件,上面定义的变量在运行本脚本的shell子进程中就是可见的!因为点命令是不打开新的子sh进程运行的。
fi
# This will prevent initlog from swallowing up a pass-phrase prompt if
# mod_ssl needs a pass-phrase from the user.
INITLOG_ARGS=""
# Set HTTPD=/usr/sbin/httpd.worker in /etc/sysconfig/httpd to use a server
# with the thread-based "worker" MPM; BE WARNED that some modules may not
# work correctly with a thread-based MPM; notably PHP will refuse to start.
# Path to the apachectl script, server binary, and short-form for messages.
apachectl=/usr/sbin/apachectl
httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
RETVAL=0
# check for 1.3 configuration <== 你可以加入自己的shell函数。
check13 () {
CONFFILE=/etc/httpd/conf/httpd.conf
GONE="(ServerType|BindAddress|Port|AddModule|ClearModuleList|"
GONE="${GONE}AgentLog|RefererLog|RefererIgnore|FancyIndexing|"
GONE="${GONE}AccessConfig|ResourceConfig)"
if grep -Eiq "^[[:space:]]*($GONE)" $CONFFILE; then
echo
echo 1>&2 " Apache 1.3 configuration directives found"
echo 1>&2 " please read /usr/share/doc/httpd-2.0.40/migration.html"
failure "Apache 1.3 config directives test"
echo
exit 1
fi
}
# The semantics of these two functions differ from the way apachectl does
# things -- attempting to start while running is a failure, and shutdown
# when not running is also a failure. So we just do it the way init scripts
# are expected to behave here.
start() {
echo -n $"Starting $prog: "
check13 || exit 1
daemon $httpd $OPTIONS <== daemon来自/etc/rc.d/functions!如果不需要的话,你也可以不使用这些shell函数。
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch /var/lock/subsys/httpd
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $httpd ç killproc来自/etc/rc.d/functions!
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f /var/lock/subsys/httpd /var/run/httpd.pid
}
reload() {
echo -n $"Reloading $prog: "
check13 || exit 1
killproc $httpd ?HUP
RETVAL=$?
echo
}
# See how we were called. <== 调用的模式!关键代码在上面定义的shell函数中!
case "$1" in
start)
start <== 要求是start,则调用start函数,下面类似。
;; <== 相当于break;
stop)
stop
;;
status)
status $httpd
RETVAL=$? <== ‘$?’表示上一条命令的返回值。
;;
restart)
stop
start
;;
condrestart)
if [ -f /var/run/httpd.pid ] ; then
stop
start
fi
;;
reload)
reload
;;
graceful|help|configtest|fullstatus)
$apachectl $@
RETVAL=$?
;;
*)
echo $"Usage: $prog {start|stop|restart|condrestart|reload|status|fullstatus|graceful|help|configtest}"
exit 1
esac <== 可以不要有这么多选项,一般情况只需要有start|stop|restart|status就可以了。
exit $RETVAL