#! /bin/bash
#
# rc This file is responsible for starting/stopping # 该脚本主要是用于在切换运行级别时启动/停止服务
# services when the runlevel changes.
#
# Original Author:
# Miquel van Smoorenburg, <
[email protected]
>
#
# check a file to be a correct runlevel script # 下面的 check_runlevel 不是检查当前运行级别的意思,而是检查符号连接对应的 target 是否真正存在
# 避免出现无效链接的情况
check_runlevel ()
{
# Check if the file exists at all. # -x 可以测试该 symbol link ($1)的 target 是否可执行,如果不是则返回1
[ -x "$1" ] || return 1
# Reject backup files and files generated by rpm. # 如果可以执行,还要检查该脚本是否是备份或者升级 rpm 后留下来的。
case "$1" in # 根据 $1 的值进行选择
*.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig) # 如果是以 .rpmsave ,。rpmorig、.rpmnew ,~ ,.orig 结尾的,则
return 1 # 返回 1
;;
esac
return 0 # 如果 target 存在且可执行,又不是备份文件,则返回 0
}
# Now find out what the current and what the previous runlevel are. # 找出当前和前一个运行级别
argv1="$1" # 把目标新运行级别 $1 赋予给 argv1 变量
set `/sbin/runlevel` # 运行 runlevel 命令,把值送给 set 命令,set 默认会把 N 赋予 $1 ,3 赋予 $2
runlevel=$2 # 把 $2 送给 runlevel 变量
previous=$1 # 把 $1 送给 previous 变量
export runlevel previous # 导出这两个变量
# 补充 :注意不要混淆这里的 两个 $1 ,前者是保存新的运行级别,后者是由 set $(runlevel)设置的 $1
. /etc/init.d/functions # 重要部分 :执行 /etc/init.d/functions
##########################################################################################################################################################
# 注释 :下面根据是否进入交互来打印不同的标题栏,后面还会用到 /var/run/confirm 文件的。
# See if we want to be in user confirmation mode # 确认是否处于 confirm 模式,也就是要求用户确认是否启动服务
if [ "$previous" = "N" ]; then # 如果前一个运行级别是 N ,表示没有改变过运行级别
if [ -f /var/run/confirm ]; then # 如果存在 /var/run/confirm 文件(由 rc.sysinit 创建,前提是 $cmdline 有 confirm
# 或者用户按下了 i 键
echo $"Entering interactive startup" # 则打印 "Enterinig interactive setup" 提示信息
else # 如果不存在 /var/run/confirm 文件,则
echo $"Entering non-interactive startup" # 打印 "Entering non-interactive startup" 表示用户在下来的过程中无法干涉
fi
fi
# Get first argument. Set new runlevel to this argument. # 将新运行级别变量赋予变量 runlevel 。
[ -n "$argv1" ] && runlevel="$argv1" # 补充 :这里实际上可以在上面直接把 $1 赋予 runlevel ,因为后面并不
# 需要知道当前的运行级别
# 补充 :一旦机器重启,previous level 总是为 N ,除非你执行了类似 telinit 1 这样的命令,previous level 才会是3或者5
# Is there an rc directory for this new runlevel? # 检查指定的新运行级别是否有对应的 rc 目录?
[ -d /etc/rc$runlevel.d ] || exit 0 # 如果存在这个目录就继续,否则返回 0
###########################################################################################################################################################
# 注释 :下面开始执行新 runlevel 的 rc 目录中那些以 K 开头的脚本
# First, run the KILL scripts.
for i in /etc/rc$runlevel.d/K* ; do # 对于在 /etc/rc<new-level>.d/ 目录下的每个以 K 开头的文件
check_runlevel "$i" || continue # 首先用 check_runlevel 检查符号连接的有效性
# 如果是无效地,则跳过它继续处理下一个符号链接(服务)
# Check if the subsystem is already up. # 下面检查某项服务 $(i) 是否是已经激活的
subsys=${i#/etc/rc$runlevel.d/K??} # 从符号连接名中取出真正的服务名,也就是K<0-9><0-9> 后面的部分
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] / # 如果在 /var/lock/subsys 中有同样名称的文件或者 <prog>.init 文件,
|| continue # 则执行后面的脚本,如果没有则表示服务停止,无须执行下面的代码
# 补充 :从上面 subsys 变量的赋值中可以看出系统最多只能有 99 个服务,如果是100的话,则 subsys 的值将不正确(会留有一个数字)
# 例如 K100nfs ,经过上面的赋值后,subsys 会变成 0nfs ,而不是 nfs ,这样可能就无法杀死当前运行的 nfsd 进程了
# Bring the subsystem down. # 把服务停止
if egrep -q "(killproc |action )" $i ; then # 如果脚本中含有 killprog 或者 action
$i stop # 直接用 <prog> stop 的方式停止它们
else # 如果找不到这两个字符串,则
action $"Stopping $subsys: " $i stop # 用 action 函数,打印 "Stopping <prog> :" ,然后执行 <prog> stop
fi
done # 这样先把每个以 K 开头的脚本都执行完
# 补充 :上面搜索 killproc 或者 action 字符串的目的可能是因为 :如果某个脚本不使用 /etc/init.d/functions ,则在停止服务时可能不会
# 显示相关信息,所以先用 action 打印该字符串(stopping xxx),然后再执行 <prog> stop (可能在 <prog> 脚本中的 stop 部分不一定给出
# 相关的提示信息;如果 <prog> 脚本是含有 killproc 或者 action ,则 killproc 自动会调用 success()或者 failure()函数输出提示信息
# Now run the START scripts. # 在上面的 Kill 脚本都执行完后,就执行以 S 开头的脚本了。
for i in /etc/rc$runlevel.d/S* ; do # 首先对于 /etc/rc<new-level>.d/ 目录下的 S 开头的每个文件,都执行下面的代码
check_runlevel "$i" || continue # check_runlevel 确保存在 target ,否则跳过该服务
# Check if the subsystem is already up. # 检查该服务是否已经启动,如果启动就跳过下面代码处理下一个服务
subsys=${i#/etc/rc$runlevel.d/S??}
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] /
&& continue
# If we're in confirmation mode, get user confirmation # 启动服务可以是 confirm 模式,也就是按y启动、按n不启动,按c恢复到非交互模式
if [ -f /var/run/confirm ]; then # 首 先查询是否有 /var/run/confirm 文件存在。
confirm $subsys # 如果存在,就使用 /etc/init.d/functions 的 confirm 函数来处理该服务
test $? = 1 && continue # 按y返回0,按n返回1,按c返回2;如果是1的话表示不启动该服务,所以跳过后面代码
fi
# 如果是y或者c则启动。但 c 会取消 continue 模式
update_boot_stage "$subsys" # 调用 update_boot_stage ,执行 rhgb-clinet --update "$subsys"
# Bring the subsystem up. # 现在可以激活该服务了。注意,上面 confirm $subsys 只是确认是否启动而已,并为真正启动
if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then # 如果该服务 $sbusys 是 halt 或者 reboot 服务,则
export LC_ALL=C # 把 LC_ALL 设置为 C
exec $i start # 执行 exec $i start ,也就是用 halt start 或者 reboot start 代替当前进程,注意 exec 的使用
fi
if egrep -q "(daemon |action |success |failure )" $i 2>/dev/null / # 如果不是上面两个服务之一,且该服务脚本中有 daemon、action、success、failure 等字符串,则
|| [ "$subsys" = "single" -o "$subsys" = "local" ]; then # 或者服务为 single 或者 local 服务,则
$i start # 直接执行 <prog> start ,这次不用 exec 方式了
else # 如果都不是上面的 halt、reboot、single、local 服务,则
action $"Starting $subsys: " $i start # 用 action 打印一个 "starting xxx" 的信息,然后执行 $i start 启动该服务
fi
done # 就用这样的方式对每个 S 开头的脚本都处理一次
###########################################################################################################################################################
rm -f /var/run/confirm # 最后删除 /var/run/confirm 文件,实际上如果上面在启动某个某个服务按下c,则该文件就被删除了
###########################################################################################################################################################
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
/usr/bin/rhgb-client --quit # 执行 rhgb-client --quit ,--quit 就是告诉 rhgb 服务器(/usr/sbin/rhgb)退出
fi