3、SysV Init启动脚本:/etc/init.d目录结构与rc脚本详解
聊到SysV Init,就绕不开/etc/init.d这个目录。说实话,我早期接触Linux时,对这个目录的第一印象就是——怎么这么多脚本?后来才明白,这其实是整个系统服务的“调度中心”。
今天我们就来把这个目录扒开看看。我会结合我多年维护服务器的经验,把里面的门道讲清楚。
3.1 /etc/init.d目录结构:服务的“家”
/etc/init.d里放的是什么?说白了,就是一个个服务启动脚本。每个服务对应一个脚本文件。比如sshd、network、crond,你都能在这里找到。
我习惯用ls -l /etc/init.d/看一眼,大概就知道这台机器上跑了哪些服务。嗯,这里有个小细节——这些脚本都是可执行的,权限通常是755。
核心要点:每个脚本必须支持start、stop、restart、status这四个基本参数。这是SysV Init的约定,也是行业惯例。
举个例子,看看/etc/init.d/sshd的头部:
#!/bin/sh
#
# sshd Start up the OpenSSH server daemon
#
# chkconfig: 2345 55 25
# description: SSH is a protocol for secure remote shell access.
# processname: sshd
# config: /etc/ssh/ssh_host_key
# config: /etc/ssh/ssh_host_dsa_key
# pidfile: /var/run/sshd.pid
注意看chkconfig: 2345 55 25这一行。它定义了三个关键信息:
- 运行级别:2345,表示在级别2、3、4、5下启动
- 启动优先级:55,数字越小越早启动
- 关闭优先级:25,数字越小越早关闭
我曾经在项目中遇到过一个问题:某台服务器重启后,NFS服务总是挂不上。排查了半天,发现是NFS的启动优先级设得太晚,网络还没准备好它就启动了。后来把优先级从80改到20,问题就解决了。你想想看,优先级这东西,真不能乱设。
3.2 rc脚本:启动流程的“指挥家”
有了脚本,谁来调用它们?答案是rc脚本。它位于/etc/rc.d/rc,是整个启动流程的调度核心。
rc脚本的工作流程其实不复杂:
- 读取当前运行级别(从
/etc/inittab获取) - 进入对应的
/etc/rc.d/rcX.d目录(X是运行级别数字) - 按顺序执行目录中的脚本链接
这里有个关键点——/etc/rc.d/rcX.d里存放的不是真正的脚本,而是指向/etc/init.d/的符号链接。为什么要这么做?我个人的理解是:
- 避免重复:一个脚本可以在多个运行级别下使用
- 方便管理:修改脚本本身,所有级别都生效
- 控制顺序:通过文件名前缀控制启动/关闭顺序
小技巧:用ls -l /etc/rc.d/rc3.d/看看,你会发现文件名都是S55sshd或K25sshd这种格式。S表示启动(Start),K表示关闭(Kill),后面的数字就是优先级。
3.3 脚本编写规范:自己动手写一个
光看不练假把式。我建议你试着写一个简单的init脚本。下面是我常用的模板:
#!/bin/bash
#
# mydaemon A simple daemon example
#
# chkconfig: 345 70 30
# description: My custom daemon service
# processname: mydaemon
# pidfile: /var/run/mydaemon.pid
# Source function library
. /etc/rc.d/init.d/functions
start() {
echo -n "Starting mydaemon: "
daemon /usr/local/bin/mydaemon
RETVAL=$?
echo
return $RETVAL
}
stop() {
echo -n "Stopping mydaemon: "
killproc mydaemon
RETVAL=$?
echo
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status mydaemon
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
esac
exit $RETVAL
注意看,我引用了/etc/rc.d/init.d/functions这个库文件。它提供了daemon、killproc、status等实用函数。嗯,这里要提醒你——千万别自己从头写,用现成的函数库能省很多事。
避坑指南:我曾经在写脚本时,忘了在stop()函数里检查PID文件是否存在。结果服务没启动时执行stop,脚本直接报错退出。后来我加了个判断:[ -f /var/run/mydaemon.pid ] || exit 0,问题就解决了。
3.4 运行级别与rcX.d目录的对应关系
SysV Init有7个运行级别,每个级别对应一个目录。我整理了一张表,方便你对照:
| 运行级别 | 对应目录 | 用途说明 |
|---|---|---|
| 0 | /etc/rc.d/rc0.d | 关机(halt) |
| 1 | /etc/rc.d/rc1.d | 单用户模式(维护模式) |
| 2 | /etc/rc.d/rc2.d | 多用户模式(无网络) |
| 3 | /etc/rc.d/rc3.d | 完整多用户模式(有网络) |
| 4 | /etc/rc.d/rc4.d | 用户自定义 |
| 5 | /etc/rc.d/rc5.d | 多用户模式(图形界面) |
| 6 | /etc/rc.d/rc6.d | 重启(reboot) |
你可能会问:为什么要有这么多级别?其实是为了灵活性。比如服务器通常运行在级别3,桌面系统用级别5。我维护过一台数据库服务器,就只用了级别3,连图形界面都没装,省资源。
3.5 chkconfig工具:管理服务的“瑞士军刀”
手动创建符号链接太麻烦,所以有了chkconfig。这个工具能帮你自动管理/etc/rc.d/rcX.d/里的链接。
常用命令:
# 查看所有服务的启动状态
chkconfig --list
# 添加一个服务到启动项
chkconfig --add sshd
# 设置sshd在级别3和5下启动
chkconfig --level 35 sshd on
# 删除服务
chkconfig --del sshd
我记得有一次,新来的同事手动在rc3.d里创建了链接,结果文件名写错了,服务死活起不来。我过去一看,S55sshd写成了S55sshd_,多了一个下划线。用chkconfig就不会出这种低级错误。
核心总结:SysV Init的启动脚本体系,本质上就是/etc/init.d/里的脚本 + /etc/rc.d/rcX.d/里的符号链接 + rc脚本的调度逻辑。理解了这个三角关系,你就掌握了SysV Init的精髓。
好了,关于/etc/init.d目录结构和rc脚本,今天就聊到这里。下一章我们会深入分析/etc/inittab文件,看看init进程是如何决定进入哪个运行级别的。到时候我会分享一个我当年调试inittab的惨痛经历,保证让你印象深刻。