一、从mysql的启动脚本说起
mysql_enable="YES"
这样在重新启动系统的时候,就可以自动运行 mysqlserver.
如果需要运行时,停止 mysqlserver 或者重新启动 mysqlserver,可以使用下面的命令:
停止mysqlserver: shell>/usr/local/etc/rc.d/mysql-server stop
重新启动mysqlserver: shell>/usr/local/etc/rc.d/mysql-server restart
其实无论是mysqlserver还是apache等系统服务,都可以利用上面提到的参数“stop“,”restart“等进行程序维护
这属于FreeBSD系统rc脚本系统的具体应用。
FreeBSD的rc脚本系统在服务程序的管理上,主要是体现在 /etc/rc.d 和 /usr/local/etc/rc.d 这两个目录下的可执行脚本,系统级别的服务程序的脚本大都安装在 /etc/rc.d目录下,而用户级别的服务程序的脚本都安装在 /usr/local/etc/rc.d 目录下。如 mysql server 在安装的时候会在 /usr/local/etc/rc.d目录下安装一个 mysql-server 的脚本文件。
服务程序的管理,其实运行的就是对应的脚本文件。如上面举例的停止服务,重新启动服务,运行的都是mysql-server脚本。
二、mysql-server 启动脚本的说明
下面的脚本代码是freebsd 6.2中mysqlserver 5.0的启动脚本。具体的功能在脚本代码中注释!
#!/bin/sh
#
# $FreeBSD: ports/databases/mysql50-server/files/mysql-server.sh.in,v 1.3 2006/03/07 16:25:00 ale Exp $
#
# PROVIDE: mysql
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# mysql_enable (bool): Set to "NO" by default.
# Set it to "YES" to enable MySQL.
# mysql_limits (bool): Set to "NO" by default.
# Set it to yes to run `limits -e -U mysql`
# just before mysql starts.
# mysql_dbdir (str): Default to "/var/db/mysql"
# Base database directory.
# mysql_args (str): Custom additional arguments to be passed
# to mysqld_safe (default empty).
#
# 下面的这行代码非常重要,作用是在mysql-server的脚本代码中插入 /etc/rc.subr 文件的代码!
# 在 /etc/rc.subr 文件中,提供了 mysql-server 调用的函数的实现,也提供了很多rc脚本系统中用到的函数。
# mysql-server 中能够使用的 start,stop,restart,rcvar等参数的具体运作,也是在 /etc/rc.subr 中提供的。
. /etc/rc.subr
# 在 /etc/rc.subr 中,首先运行一些初始化命令,跟踪运行,执行了以下命令:
if [ -z "${_rc_subr_loaded}" ]; then
_rc_subr_loaded="YES"
SYSCTL="/sbin/sysctl"
SYSCTL_N="${SYSCTL} -n"
CMD_OSTYPE="${SYSCTL_N} kern.ostype"
OSTYPE=`${CMD_OSTYPE}`
ID="/usr/bin/id"
JID=`ps -p $$ -o jid=`
IDCMD="if [ -x $ID ]; then $ID -un; fi"
case ${OSTYPE} in
FreeBSD)
SYSCTL_W="${SYSCTL}"
;;
NetBSD)
SYSCTL_W="${SYSCTL} -w"
;;
esac
# 定义name变量
name="mysql"
# 调用 /etc/rc.subr 文件中定义的 set_rcvar 函数
# 函数的执行结果是给几个变量赋值
rcvar=`set_rcvar`
# set_rcvar的执行结果
base_var=mysql
echo mysql_enable
rcvar=mysql_enable
# 调用 /etc/rc.subr 文件中定义的 load_rc_config 函数,参数是 name 变量的值。
load_rc_config $name
# 定义一些变量
: ${mysql_enable="NO"}
: ${mysql_limits="NO"}
: ${mysql_dbdir="/var/db/mysql"}
: ${mysql_args=""}
# 定义一些变量,通过这些变量,能够组合出mysqlserver启动的具体参数。涉及mysqlserver的一些具体工具的使用。
mysql_user="mysql" # 启动用帐户
mysql_limits_args="-e -U ${mysql_user}" # 启动参数
pidfile="${mysql_dbdir}/`/bin/hostname`.pid"
command="/usr/local/bin/mysqld_safe" # 启动命令
procname="/usr/local/libexec/mysqld"
start_precmd="${name}_prestart" # 定义一个函数接口,关联到本脚本文件中定义的 mysql_prestart()函数
mysql_install_db="/usr/local/bin/mysql_install_db"
mysql_install_db_args="--ldata=${mysql_dbdir}"
# 下面这个函数用来建立mysql数据苦,初始化授权表,并且建立一个test数据库
mysql_create_auth_tables()
{
eval $mysql_install_db $mysql_install_db_args >/dev/null
[ $? -eq 0 ] && chown -R ${mysql_user}:${mysql_user} ${mysql_dbdir}
}
# 下面这个函数用来定义程序启动前的一些动作。
# 检查mysql数据库目录是否存在,如果没有存在,运行建立数据库,初始化授权表。
mysql_prestart()
{
if [ ! -d "${mysql_dbdir}/mysql/." ]; then
mysql_create_auth_tables || return 1
fi
if checkyesno mysql_limits; then
eval `/usr/bin/limits ${mysql_limits_args}` 2>/dev/null
else
return 0
fi
}
# 下面的一行代码是运行 /etc/rc.subr 中的 run_rc_command 函数
# 如果我们执行 /usr/local/etc/rc.d/mysql-server start
# 那么执行的就是 run_rc_command "start"
run_rc_command "$1"
######## mysql-server 脚本到此结束
余下运行的都是根据本脚本运行过程中定义的各种变量来执行 /etc/rc.subr 中的run_rc_command 函数。
三、/etc/rc.subr中的run_rc_command 函数
这个函数中提供了很多参数的处理过程,诸如start,stop,restart,rcvar,pull等过程。
也提供了可选参数fast,force,one的具体执行代码。具体的代码就不作解释了,
如果这些参数的处理过程没有在服务程序的脚本中进行定义,那么运行的就是函数中定义的处理过程。
通过脚本分析获知使用rc脚本系统中一些细节。
1、如果运行具体服务程序的rc脚本没有带参数,rc_rc_command会打印出帮助信息
Usage: ./mysql-server [fast|force|one](start|stop|restart|rcvar|status|poll)
没有使用[force][one]选项,start,stop,restart,status是没有运行结果的。
[force]的作用是强制 {rcvar} 有效,使得 mysql_enable="yes"临时有效
shell> /usr/local/etc/rc.d/mysql-server forcestart
shell> /usr/local/etc/rc.d/mysql-server forcerestart
[one]的作用和[force]类似,不同的是one 只是设置 {$rcvar}有效。
四、阶段性小结
通过上面的代码分析,以及参考更多的服务程序的rc脚本,大致可以理出rc脚本系统中服务程序管理的大致原理。
freebsd系统提供的 rc.subr 是整个rc脚本系统的核心,它提供了系统利用rc脚本管理服务程序的基石。
在这个基础上,实现了服务程序rc脚本的框架结构。定义了统一的运行规则。并且为服务程序诸如mysqlserver提供了很大的灵活性。
但rc.subr的作用不只如此,从rc.subr的代码可知,它提供的功能实际是架构起了FreeBSD整个系统的rc脚本系统。
五、系统启动自动运行服务程序的机制
1、rc脚本系统什么时候启动
按照《FreeBSD操作系统设计与实现》中的说法,rc脚本系统是在加载完系统内核,出现freebsd启动模式选择界面,选择运行方式,启动init之后开始运行。在多用户模式启动系统的情况下,init首先产生一个shell,默认的是 /bin/sh,所有的rc脚本都是用这个shell来解释执行。
选择不同的启动模式会导致下面的变量被赋值:
_boot
如果系统是自动运行,_boot=faststart
如果系统不是自动运行,_boot=start
这个变量的值会影响到后续的启动过程
2、rc脚本系统的始祖 /etc/rc
# 初始化设置
stty status '^T'
# Set shell to ignore SIGINT (2), but not children;
# shell catches SIGQUIT (3) and returns to single user.
#
trap : 2
trap "echo 'Boot interrupted'; exit 1" 3
HOME=/
PATH=/sbin:/bin:/usr/sbin:/usr/bin
export HOME PATH
# 设置 _boot 变量的值
if [ "$1" = autoboot ]; then
autoboot=yes
_boot="faststart"
rc_fast=yes # run_rc_command(): do fast booting
else
autoboot=no
_boot="start"
fi
dlv=`/sbin/sysctl -n vfs.nfs.diskless_valid 2> /dev/null`
if [ ${dlv:=0} -ne 0 -o -f /etc/diskless ]; then
sh /etc/rc.initdiskless
fi
# Run these after determining whether we are booting diskless in order
# to minimize the number of files that are needed on a diskless system,
# and to make the configuration file variables available to rc itself.
# 包含 /etc/rc.subr,又见到“rc.subr“的踪迹 :-)
. /etc/rc.subr
# 显示提示信息,表示开始启动系统rc脚本
echo "Loading configuration files."
# 调用 /etc/rc.subr 中的 load_rc_confg 参数是 XXX
# 调用 /etc/rc.subr 文件中定义的 load_rc_config 函数,参数是 name 变量的值。
load_rc_config 'XXX'
skip="-s nostart"
# jailed相关,目前还不太了解
if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
skip="$skip -s nojail"
if [ "$early_late_divider" = "mountcritlocal" ]; then
early_late_divider=NETWORKING
fi
fi
# Do a first pass to get everything up to $early_late_divider so that
# we can do a second pass that includes $local_startup directories
#
# rcorder根据这些脚本文件的关联进行排序,为后面的循环加载 /etc/rc.d/目录下脚本文件作准备
files=`rcorder ${skip} /etc/rc.d/* 2>/dev/null`
# 进入一个循环,对排序后的脚本文件,使用 _boot 变量的值(start,faststart)运行每一个rc脚本
# 跟踪这个循环,可知服务程序的加载顺序。
for _rc_elem in ${files}; do
run_rc_script ${_rc_elem} ${_boot}
case "$_rc_elem" in
*/${early_late_divider}) break ;;
esac
done
unset files local_rc
# Now that disks are mounted, for each dir in $local_startup
# search for init scripts that use the new rc.d semantics.
# 参数是 _boot变量的值(start,faststart)
case ${local_startup} in
[Nn][Oo] | '') ;;
*) find_local_scripts_new ;;
esac
files=`rcorder ${skip} /etc/rc.d/* ${local_rc} 2>/dev/null`
_skip_early=1
for _rc_elem in ${files}; do
case "$_skip_early" in
1) case "$_rc_elem" in
*/${early_late_divider}) _skip_early=0 ;;
esac
continue
;;
esac
run_rc_script ${_rc_elem} ${_boot}
done
echo ''
date
exit 0
3、小结:
FreeBSD系统提供的rc脚本系统由以下的部分组成
shell
/etc/rc
/etc/rc.d/
/usr/local/etc/rc.d/
整个rc脚本系统的核心是 /etc/rc.subr 和 rcorder 组成,籍由这个机制,很多的系统功能都是通过rc脚本运行起来的,例如 login 等等
《freebsd操作系统设计与实现》中文版中所提到的reorder应该就是rcorder,估计是排版错误。
系统启动时自动运行特定的服务程序的大致流程是:
通过/etc/rc.subr提供的函数,使用 faststart或者start参数运行诸如 mysql-server这样的脚本,启动相关服务
六、FreeBSD的rc脚本系统总结
通过跟踪整个rc脚本系统的运作,给我一个特殊的印象,一个不太恰当的比喻,rc脚本系统相当于系统内核和具体服务程序的黏合剂和管理中枢。有了rc脚本系统,磁盘检查,用户登录等等服务才得以在系统中运行。