Linux系统启动脚本分析之rc

#! /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

你可能感兴趣的:(linux,职场,RC,休闲)