3、SysV Init启动脚本:/etc/init.d目录结构与rc脚本详解

聊到SysV Init,就绕不开/etc/init.d这个目录。说实话,我早期接触Linux时,对这个目录的第一印象就是——怎么这么多脚本?后来才明白,这其实是整个系统服务的“调度中心”。

今天我们就来把这个目录扒开看看。我会结合我多年维护服务器的经验,把里面的门道讲清楚。

3.1 /etc/init.d目录结构:服务的“家”

/etc/init.d里放的是什么?说白了,就是一个个服务启动脚本。每个服务对应一个脚本文件。比如sshdnetworkcrond,你都能在这里找到。

我习惯用ls -l /etc/init.d/看一眼,大概就知道这台机器上跑了哪些服务。嗯,这里有个小细节——这些脚本都是可执行的,权限通常是755。

核心要点:每个脚本必须支持startstoprestartstatus这四个基本参数。这是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脚本的工作流程其实不复杂:

  1. 读取当前运行级别(从/etc/inittab获取)
  2. 进入对应的/etc/rc.d/rcX.d目录(X是运行级别数字)
  3. 按顺序执行目录中的脚本链接

这里有个关键点——/etc/rc.d/rcX.d里存放的不是真正的脚本,而是指向/etc/init.d/的符号链接。为什么要这么做?我个人的理解是:

  • 避免重复:一个脚本可以在多个运行级别下使用
  • 方便管理:修改脚本本身,所有级别都生效
  • 控制顺序:通过文件名前缀控制启动/关闭顺序

小技巧:ls -l /etc/rc.d/rc3.d/看看,你会发现文件名都是S55sshdK25sshd这种格式。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这个库文件。它提供了daemonkillprocstatus等实用函数。嗯,这里要提醒你——千万别自己从头写,用现成的函数库能省很多事。

避坑指南:我曾经在写脚本时,忘了在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的惨痛经历,保证让你印象深刻。