免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3174 | 回复: 14
打印 上一主题 下一主题

[FreeBSD] [原创]试析FreeBSD 6.2 的rc脚本系统 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-05-06 13:09 |只看该作者 |倒序浏览
试析FreeBSD 6.2 的rc脚本系统

杜比环绕声


一、从mysql的启动脚本说起

配置mysql的时候,如果需要启动运行 mysql server,按照 mysql 手册上的说明,需要在 /etc/rc.conf 中,添加一条信息:

    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的启动脚本。具体的功能在脚本代码中注释!


  1. #!/bin/sh     
  2. #
  3. # $FreeBSD: ports/databases/mysql50-server/files/mysql-server.sh.in,v 1.3 2006/03/07 16:25:00 ale Exp $
  4. #

  5. #下面这部分文本描述了可以在rc.conf中设置、添加的启动条目,用来控制mysqlserver启动的一些具体细节。

  6. # PROVIDE: mysql
  7. # REQUIRE: LOGIN
  8. # KEYWORD: shutdown

  9. #
  10. # Add the following line to /etc/rc.conf to enable mysql:
  11. # mysql_enable (bool):        Set to "NO" by default.
  12. #                        Set it to "YES" to enable MySQL.
  13. # mysql_limits (bool):        Set to "NO" by default.
  14. #                        Set it to yes to run `limits -e -U mysql`
  15. #                        just before mysql starts.
  16. # mysql_dbdir (str):        Default to "/var/db/mysql"
  17. #                        Base database directory.
  18. # mysql_args (str):        Custom additional arguments to be passed
  19. #                        to mysqld_safe (default empty).
  20. #

  21. # 下面的这行代码非常重要,作用是在mysql-server的脚本代码中插入 /etc/rc.subr 文件的代码!
  22. # 在 /etc/rc.subr 文件中,提供了 mysql-server 调用的函数的实现,也提供了很多rc脚本系统中用到的函数。
  23. # mysql-server 中能够使用的 start,stop,restart,rcvar等参数的具体运作,也是在 /etc/rc.subr 中提供的。

  24. . /etc/rc.subr

  25. # 在 /etc/rc.subr 中,首先运行一些初始化命令,跟踪运行,执行了以下命令:

  26.     if [ -z "${_rc_subr_loaded}" ]; then

  27.     _rc_subr_loaded="YES"

  28.     SYSCTL="/sbin/sysctl"
  29.     SYSCTL_N="${SYSCTL} -n"
  30.     CMD_OSTYPE="${SYSCTL_N} kern.ostype"
  31.     OSTYPE=`${CMD_OSTYPE}`
  32.     ID="/usr/bin/id"
  33.     JID=`ps -p $$ -o jid=`
  34.     IDCMD="if [ -x $ID ]; then $ID -un; fi"

  35.     case ${OSTYPE} in
  36.     FreeBSD)
  37.         SYSCTL_W="${SYSCTL}"
  38.         ;;
  39.     NetBSD)
  40.         SYSCTL_W="${SYSCTL} -w"
  41.         ;;
  42.     esac


  43. # 定义name变量
  44. name="mysql"

  45. # 调用 /etc/rc.subr 文件中定义的 set_rcvar 函数
  46. # 函数的执行结果是给几个变量赋值
  47. rcvar=`set_rcvar`
  48.   
  49. # set_rcvar的执行结果

  50.     base_var=mysql
  51.     echo mysql_enable
  52.     rcvar=mysql_enable



  53. # 调用 /etc/rc.subr 文件中定义的 load_rc_config 函数,参数是 name 变量的值。
  54. # 这个函数会装载 /etc/defaults/rc.conf文件的内容,并且运行它,之后运行 /etc/rc.conf
  55. # 的内容,具体的作用就是按照这两个rc.conf的内容设置必要的变量,通过加载运行的顺序上看,因为 /etc/rc.conf运行在后
  56. # 所以 /etc/rc.conf 定义的变量会覆盖 /etc/defaults/rc.conf中定义的变量。

  57. load_rc_config $name


  58. # 定义一些变量
  59. : ${mysql_enable="NO"}
  60. : ${mysql_limits="NO"}
  61. : ${mysql_dbdir="/var/db/mysql"}
  62. : ${mysql_args=""}


  63. # 定义一些变量,通过这些变量,能够组合出mysqlserver启动的具体参数。涉及mysqlserver的一些具体工具的使用。

  64. mysql_user="mysql"                        # 启动用帐户
  65. mysql_limits_args="-e -U ${mysql_user}"   # 启动参数
  66. pidfile="${mysql_dbdir}/`/bin/hostname`.pid"   
  67. command="/usr/local/bin/mysqld_safe"      # 启动命令
  68. command_args="--defaults-extra-file=${mysql_dbdir}/my.cnf --user=${mysql_user} --datadir=${mysql_dbdir} --pid-file=${pidfile} ${mysql_args} > /dev/null &"
  69. procname="/usr/local/libexec/mysqld"

  70. start_precmd="${name}_prestart"      # 定义一个函数接口,关联到本脚本文件中定义的 mysql_prestart()函数

  71. mysql_install_db="/usr/local/bin/mysql_install_db"
  72. mysql_install_db_args="--ldata=${mysql_dbdir}"



  73. # 下面这个函数用来建立mysql数据苦,初始化授权表,并且建立一个test数据库
  74. mysql_create_auth_tables()
  75. {
  76.         eval $mysql_install_db $mysql_install_db_args >/dev/null
  77.         [ $? -eq 0 ] && chown -R ${mysql_user}:${mysql_user} ${mysql_dbdir}
  78. }


  79. # 下面这个函数用来定义程序启动前的一些动作。
  80. # 检查mysql数据库目录是否存在,如果没有存在,运行建立数据库,初始化授权表。

  81. mysql_prestart()
  82. {
  83.         if [ ! -d "${mysql_dbdir}/mysql/." ]; then
  84.                 mysql_create_auth_tables || return 1
  85.         fi
  86.         if checkyesno mysql_limits; then
  87.                 eval `/usr/bin/limits ${mysql_limits_args}` 2>/dev/null
  88.         else
  89.                 return 0
  90.         fi
  91. }


  92. # 下面的一行代码是运行 /etc/rc.subr 中的 run_rc_command 函数
  93. # 如果我们执行 /usr/local/etc/rc.d/mysql-server start
  94. # 那么执行的就是  run_rc_command "start"
  95. run_rc_command "$1"

  96. ######## 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)

2、对于mysql-server这个脚本,如果没有在 /etc/rc.conf 中加入  mysql_enable="YES",并且在运行脚本时
没有使用[force][one]选项,start,stop,restart,status是没有运行结果的。

[force]的作用是强制  {rcvar} 有效,使得 mysql_enable="yes"临时有效

这样在 /etc/rc.conf 中不添加  mysql_enable="YES"的情况下,运行服务程序的管理,例如:

shell> /usr/local/etc/rc.d/mysql-server forcestart
shell> /usr/local/etc/rc.d/mysql-server forcerestart

rcvar参数是不需要上面的限制,因为rcvar参数的主要作用就是判断/etc/rc.conf 中是否有mysql_enable="YES"的设置。

[one]的作用和[force]类似,不同的是one 只是设置 {$rcvar}有效。

四、阶段性小结

通过上面的代码分析,以及参考更多的服务程序的rc脚本,大致可以理出rc脚本系统中服务程序管理的大致原理。

freebsd系统提供的 rc.subr 是整个rc脚本系统的核心,它提供了系统利用rc脚本管理服务程序的基石。

在这个基础上,实现了服务程序rc脚本的框架结构。定义了统一的运行规则。并且为服务程序诸如mysqlserver提供了很大的灵活性。

但rc.subr的作用不只如此,从rc.subr的代码可知,它提供的功能实际是架构起了FreeBSD整个系统的rc脚本系统。


五、系统启动自动运行服务程序的机制

前面提到,mysqlserver要实现随系统启动运行所要作的工作就是把 mysql_enable="YES"添加到 /etc/rc.conf之中即可。泛泛的理解是系统启动完内核后,在启动init之后有个rc脚本启动过程。而这些服务程序就是在这个过程中自动加载的。但具体的加载过程很少资料提到。本文在上面对mysql-server分析的基础上,试着分析一下rc脚本系统的启动原理。

1、rc脚本系统什么时候启动

按照《FreeBSD操作系统设计与实现》中的说法,rc脚本系统是在加载完系统内核,出现freebsd启动模式选择界面,选择运行方式,启动init之后开始运行。在多用户模式启动系统的情况下,init首先产生一个shell,默认的是 /bin/sh,所有的rc脚本都是用这个shell来解释执行。

选择不同的启动模式会导致下面的变量被赋值:

_boot  

如果系统是自动运行,_boot=faststart

如果系统不是自动运行,_boot=start

这个变量的值会影响到后续的启动过程

2、rc脚本系统的始祖 /etc/rc

  1. # 初始化设置
  2. stty status '^T'

  3. # Set shell to ignore SIGINT (2), but not children;
  4. # shell catches SIGQUIT (3) and returns to single user.
  5. #
  6. trap : 2
  7. trap "echo 'Boot interrupted'; exit 1" 3

  8. HOME=/
  9. PATH=/sbin:/bin:/usr/sbin:/usr/bin
  10. export HOME PATH


  11. # 设置 _boot 变量的值
  12. if [ "$1" = autoboot ]; then
  13.         autoboot=yes
  14.         _boot="faststart"
  15.         rc_fast=yes        # run_rc_command(): do fast booting
  16. else
  17.         autoboot=no
  18.         _boot="start"
  19. fi

  20. dlv=`/sbin/sysctl -n vfs.nfs.diskless_valid 2> /dev/null`
  21. if [ ${dlv:=0} -ne 0 -o -f /etc/diskless ]; then
  22.         sh /etc/rc.initdiskless
  23. fi

  24. # Run these after determining whether we are booting diskless in order
  25. # to minimize the number of files that are needed on a diskless system,
  26. # and to make the configuration file variables available to rc itself.


  27. # 包含 /etc/rc.subr,又见到“rc.subr“的踪迹 :-)
  28. . /etc/rc.subr


  29. # 显示提示信息,表示开始启动系统rc脚本
  30. echo "Loading configuration files."

  31. # 调用 /etc/rc.subr 中的 load_rc_confg  参数是 XXX
  32. # 调用 /etc/rc.subr 文件中定义的 load_rc_config 函数,参数是 name 变量的值。
  33. # 这个函数会装载 /etc/defaults/rc.conf文件的内容,并且运行它,之后运行 /etc/rc.conf
  34. # 的内容,具体的作用就是按照这两个rc.conf的内容设置必要的变量,通过加载运行的顺序上看,因为 /etc/rc.conf运行在后
  35. # 所以 /etc/rc.conf 定义的变量会覆盖 /etc/defaults/rc.conf中定义的变量。
  36. load_rc_config 'XXX'

  37. skip="-s nostart"

  38. # jailed相关,目前还不太了解
  39. if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
  40.         skip="$skip -s nojail"
  41.         if [ "$early_late_divider" = "mountcritlocal" ]; then
  42.                 early_late_divider=NETWORKING
  43.         fi
  44. fi

  45. # Do a first pass to get everything up to $early_late_divider so that
  46. # we can do a second pass that includes $local_startup directories
  47. #


  48. # 用rcorder这个工具程序按照/etc/defaults/rc.conf /etc/rc.conf中的变量定义访问 /etc/rc.d/目录下的所需文件
  49. # rcorder根据这些脚本文件的关联进行排序,为后面的循环加载 /etc/rc.d/目录下脚本文件作准备

  50. files=`rcorder ${skip} /etc/rc.d/* 2>/dev/null`



  51. # 进入一个循环,对排序后的脚本文件,使用 _boot 变量的值(start,faststart)运行每一个rc脚本
  52. # 跟踪这个循环,可知服务程序的加载顺序。
  53. for _rc_elem in ${files}; do
  54.         run_rc_script ${_rc_elem} ${_boot}

  55.         case "$_rc_elem" in
  56.         */${early_late_divider})        break ;;
  57.         esac
  58. done

  59. unset files local_rc

  60. # Now that disks are mounted, for each dir in $local_startup
  61. # search for init scripts that use the new rc.d semantics.
  62. # 当分区加载成功后,搜索 /usr/local/etc/rc.d目录下的文件,根据 /etc/rc.conf中的具体设置,运行对应的脚本文件。
  63. # 参数是 _boot变量的值(start,faststart)

  64. case ${local_startup} in
  65. [Nn][Oo] | '') ;;
  66. *)        find_local_scripts_new ;;
  67. esac

  68. files=`rcorder ${skip} /etc/rc.d/* ${local_rc} 2>/dev/null`
  69. _skip_early=1
  70. for _rc_elem in ${files}; do
  71.         case "$_skip_early" in
  72.         1)        case "$_rc_elem" in
  73.                 */${early_late_divider})        _skip_early=0 ;;
  74.                 esac
  75.                 continue
  76.                 ;;
  77.         esac

  78.         run_rc_script ${_rc_elem} ${_boot}
  79. done

  80. echo ''
  81. date
  82. exit 0
复制代码


3、小结:

FreeBSD系统提供的rc脚本系统由以下的部分组成

shell
/etc/rc
/etc/defaults/rc.conf
/etc/rc.conf
/etc/rc.d/
/usr/local/etc/rc.d/

整个rc脚本系统的核心是 /etc/rc.subr 和 rcorder 组成,籍由这个机制,很多的系统功能都是通过rc脚本运行起来的,例如 login 等等

《freebsd操作系统设计与实现》中文版中所提到的reorder应该就是rcorder,估计是排版错误。

系统启动时自动运行特定的服务程序的大致流程是:

由 /etc/rc 脚本运行 /etc/rc.conf ,对应的 mysql_enable="YES"所起的作用就是设置rcvar变量

通过/etc/rc.subr提供的函数,使用 faststart或者start参数运行诸如 mysql-server这样的脚本,启动相关服务


六、FreeBSD的rc脚本系统总结

通过跟踪整个rc脚本系统的运作,给我一个特殊的印象,一个不太恰当的比喻,rc脚本系统相当于系统内核和具体服务程序的黏合剂和管理中枢。有了rc脚本系统,磁盘检查,用户登录等等服务才得以在系统中运行。

[ 本帖最后由 杜比环绕声 于 2007-5-8 23:45 编辑 ]

论坛徽章:
2
丑牛
日期:2013-09-29 09:47:222015七夕节徽章
日期:2015-08-21 11:06:17
2 [报告]
发表于 2007-05-06 15:40 |只看该作者
原帖由 harbinbeer 于 2007-5-6 14:11 发表
论坛表情符号挺讨厌的,不用code套起来也够懒的

现在没了,呵呵,发的时候可以选择不用的

论坛徽章:
0
3 [报告]
发表于 2007-05-06 15:48 |只看该作者
谢谢啦!我是在kate中输入的,行和段的控制不太熟悉,以后注意!!!

论坛徽章:
0
4 [报告]
发表于 2007-05-06 18:47 |只看该作者
FreeBSD的rc脚本系统在服务程序的管理上,主要是体现在 /etc/rc.d 和 /usr/local/etc/rc.d 这两个目录下的可执行脚本,系统级别的服务程序的脚本大都安装在 /etc/rc.d目录下,而用户级别的服务程序的脚本都安装在 /usr/local/etc/rc.d 目录下。

这是望文生义吧
手册的说法是:
在 rc.d 出现之前, 应用程序会把一个简单的启动脚本放到 /usr/local/etc/rc.d 目录中,这个目录中的脚本会被系统初始化脚本读取。

  尽管很多人已经花费了相当多的时间来把旧的配置方式融入到新系统中,仍然有许多第三方软件需要把脚本放到上面提到的目录中。 是否使用 rc.d 会对这些脚本的执行带来一些变化。 在 FreeBSD 5.1 之前采用的是旧式的配置, 当然, 绝大多数情况下, 新式的脚本也会工作的很好。

论坛徽章:
0
5 [报告]
发表于 2007-05-06 19:00 |只看该作者
我在文中所说的“系统级别的服务程序”指的是Freebsd系统运行所说的程序,也就是系统自带的,用户安装的服务程序安装大都使用 /usr/local 这个前缀,诸如apache,mysql,如果默认安装的话,rc脚本都是放在/usr/local/etc/rc.d/ 目录下。

在freebsd 6.2系统中,/etc/rc.d  和 /usr/local/etc/rc.d 的分类使用比较清晰了!

论坛徽章:
0
6 [报告]
发表于 2007-05-06 20:08 |只看该作者

我照手册 中规中矩地写了如下的脚本:
1 #!/bin/sh
      2 #
      3 #PROVIDEdm
      4 #
      5 xdm_enable=${xdm_enable-"NO"}
      6 xdm_flags=${xdm_flags-""}
      7 xdm_pidfile=${xdm_pidfile-"/var/run/xdm.pid"}
      8
      9 . /etc/rc.subr
     10
     11 name="xdm"
     12 rcvar=`set_rcvar`
     13 command="/usr/X11R6/bin/xdm"
     14
     15 load_rc_config $name
     16
     17 pidfile="${xdm_pidfile}"
     18
     19 start_cmd="echo \"Starting ${name}.\"; /usr/bin/nice -5 ${command} ${xdm
     19 _flags} ${command_args}"
     20
     21 run_rc_command "$1"
命名为xdm.sh 放在 /usr/local/etc/rc.d 可以启动xdm 去掉.sh就不可以
为什么会这样?
好奇怪!

论坛徽章:
0
7 [报告]
发表于 2007-05-08 19:18 |只看该作者
强烈建议这样的内容来的更多些

论坛徽章:
0
8 [报告]
发表于 2007-05-08 23:43 |只看该作者
原帖由 坏坏小少 于 2007-5-6 20:08 发表
:em06::em06::em06:
我照手册 中规中矩地写了如下的脚本:
1 #!/bin/sh
      2 #
      3 #PROVIDE:xdm
      4 #
      5 xdm_enable=${xdm_enable-"NO"}
      6 xdm_flags=${xdm_flags-&qu ...


能把“不运行的提示”贴一下么!

rc脚本运行有几个必要的条件,诸如rc脚本要有可执行权限,是否在/etc/rc.conf中设置enable,以及运行命令目录是否给出,是否是绝对路径,如果是下面这样运行

shell>xdm

我想可能运行的是/usr/X11R6/bin目录下的xdm了,不给参数,它什么也不做!

如果没有在/etc/rc.conf中设置enable,下面的命令的运行也是没有结果的

shell>/usr/local/etc/rc.d/xdm start

可以试试下面的命令

shell>/usr/local/etc/rc.d/xdm forcestart

论坛徽章:
0
9 [报告]
发表于 2007-05-09 12:43 |只看该作者
1.不运行 无提示
就到了 login:
2.脚本有可执行权限
3.手动执行
  1. shell>xdm
复制代码

可以运行 /usr/X11R6/bin/xdm
4.至于/etc/rc.conf中设置enable.....
实际的情形是:
             a:脚本放在/etc/rc.d
                   如果命名为 xdm.sh 无论有无enable xdm可以启动!
                   如果命名为xdm 就需要enable才可以启动 没有就不可以
             b:脚本放在/usr/local/etc/rc.d
                   如果命名为 xdm.sh  就需要enable才可以启动 没有就不可以
                   如果命名为xdm 无论有无enable xdm都不可以启动

论坛徽章:
0
10 [报告]
发表于 2007-05-09 15:07 |只看该作者
我试着运行了xdm脚本,报错

重新修改了一下


  1. #!/bin/sh
  2. #
  3. #PROVIDE: xdm
  4. #
  5. : ${xdm_enable="NO"}
  6. : ${xdm_flags=""}
  7. : ${xdm_pidfile="/var/run/xdm.pid"}

  8. . /etc/rc.subr

  9. name="xdm"
  10. rcvar=`set_rcvar`
  11. command="/usr/X11R6/bin/xdm"

  12. load_rc_config $name

  13. pidfile="${xdm_pidfile}"

  14. start_cmd="echo \"Starting ${name}.\";/usr/bin/nice -5 ${command} ${xdm_flags} ${command_args}"

  15. run_rc_command "$1"

复制代码



shell> cd /usr/local/etc/rc.d
shell> ./xdm forcestart


XDM可以正常运行!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP