BSD中实用的rc.d脚本编程

Yar Tikhiy

$FreeBSD: doc/zh_CN.GB2312/articles/rc-scripting/article.sgml,v 1.1 2008/11/17 08:00:30 loader Exp $

  初学者可能会发现,通过正式的文档资料, 根据实际情况在 BSD 的 rc.d 框架上进行实用的 rc.d 脚本编程比较困难。 在本文中,我们采用一些复杂性不断增加的典型案例, 来展示适合每个案例的 rc.d 特性, 并探讨它们如何运行工作的。 这一测验将为大家进一步学习设计有效的 rc.d 应用程序提供了有价值的参考。


目录
1 简介
2 任务描述
3 虚拟的脚本
4 可配置的虚拟脚本
5 启动并停止简单守护进程
6 启动并停止高级守护进程
7 链接脚本到 rc.d 框架
8 给予 rc.d 脚本更多的灵活性
9 进一步阅读

1 简介

  历史上 BSD 曾有过一个单独整体的启动脚本, /etc/rc。 该脚本在系统启动的时候被 init(8) 程序所引导,并执行所有多用户操作所需求的用户级任务: 检查并挂载文件系统,设置网络,启动守护进程,等等。 在每个系统中实际的任务列表也并不相同; 管理员需要根据需求自定义这样的任务列表。在一些非常规的情况中, 还必须修改 /etc/rc 文件, 一些真正的黑客乐此不疲。

  整体单独脚本启动方法的真正问题是它没有提供对从 /etc/rc 启动的单个组件的控制。 拿一个例子来说吧,/etc/rc 不能够重新启动一个单独的守护进程。 系统管理员不得不手动找出守护进程,并杀掉它, 等待它真正退出后,再通过 /etc/rc 浏览得到该守护进程的标识,最终输入全部的命令行来再次启动守护进程。 如果重新启动的服务包括不止一个的守护进程或者需要更多的动作的话, 该任务将变得更加困难并容易出错。简而言之, 单个整体脚本在实现我们这样的目的上是不及格的: 让系统管理员的生活更加轻松。

  再后来,为了将最重要的一些子系统单独划分开来, 人们试着从 /etc/rc 文件中分离出来一些部分。 总所周知的例子就是用来启动联网的 /etc/netstart 文件。它容许从单用户模式访问网络, 但由于它的部分代码需要和一些与联网基本无任何关系的动作交互, 所以它并没有能够完美地结合到自启动的进程中。那便是为何 /etc/netstart 被演变成 /etc/rc.network 的原因了。 后者不再是一个普通的脚本;它包括了庞大的,由 /etc/rc 在不同的系统启动等级中调用的凌乱的 sh(1) 函数。然而,当启动任务变得多样化以及历经更改, “类模块化” 方法变得比曾有的整体 /etc/rc 更加的缓慢费事。

  由于没有一个干净和易于设计的框架, 启动脚本不得不拼命来满足飞速开发中基于 BSD 的操作系统的需求。 它变得清晰并经过许多必须的步骤最终变成一个具有细密性和扩展性的 rc 系统。BSD rc.d 就这样诞生了。Luke Mewburn 和 NetBSD 社区是公认的 rc.d 之父。再之后它被引入到了 FreeBSD 中。 它的名字引用为系统单独的服务脚本的位置,也就是 /etc/rc.d下面的那些脚本。 之后我们将学习到更多关于 rc.d 系统的组件并看看单个脚本是如何被调用的。

  BSD rc.d 背后的基本理念是 良好 的模块性和代码重用。 良好 的模块性意味着每个基本 “服务” 就象系统守护进程或原始启动任务那样, 通过它们所拥有的能够启动该服务的 sh(1) 脚本,来停止服务, 重载服务,检查服务的状态。具体的动作由脚本的命令行参数所决定。 /etc/rc 脚本仍然掌管着系统的启动, 但现在它仅仅是使用 start 参数来一个个调用那些小的脚本。 这易于使用正在运行中具有同样设定的脚本的 stop 参数来很好地执行停止任务,这是被 /etc/rc.shutdown 脚本所完成的。注意这是多么接近地遵循了 Unix 的哲学: 拥有一组小的专用的工具,每个工具尽可能好地完成自己的任务。 代码重用 意味着所有的通用操作由 /etc/rc.subr 中的一些 sh(1) 函数所实现。 现在的一个典型的脚本只需要寥寥几行的 sh(1) 代码。最终, rcorder(8) 成为了 rc.d 框架中重要的一部分, 它用来帮助 /etc/rc 根据小脚本之间的相互依赖关系并有顺序地运行它们。它同样帮助 /etc/rc.shutdown 做类似的事情, 因为正确的关闭次序是相对于启动的次序的。

  BSD rc.d 的设计在 Luke Mewburn 的原文 中有描述, 以及 rc.d 组件也被充分详细地记录在各自的 联机手册 中。然而, 它可能没能清晰展现给一个 rc.d 新手如何将无数的块和片关联起来以为具体的任务创建一个好样式的脚本。 因此本文将试着用不同的方式来描述 rc.d。 它将展示出应该用在许多典型情况中的那些特性,并阐述了为何是这样。 注意这并不是一篇 how-to 文档,因为我们的目的不是给出现成的配方, 而是在展示一些简单的进入 rc.d 的范围的门道。 本文也不是相关联机手册的替代品。 阅读本文时不要忘记参考联机手册以获取更正规完整的文档。

  理解本文是有一些先决条件的。首先,你应当熟悉 sh(1) 脚本变成语言以掌握 rc.d, 还有,你应当知系统是如何执行用户级的启动和停止任务,这些在 rc(8) 中都有所描述。

  本文关注的是 rc.d 的 FreeBSD 分支。 然而,它可能对 NetBSD 的开发者也同样有用,因为 BSD rc.d 的两个分支不只是共享了同样的设计, 还保留了对脚本编写者都可见的类似观点。

本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.