# 其实计算机的关闭也就是运行级别的切换;
# init进程监控运行级别是否改变。
# 如果运行级别改变了,init进程就会触发 /etc/rc.d/rc 脚本运行。
# rc 脚本作用是:
# 1、如果当前计算机运行有,在当前运行级别
# (correctrunlevel )/etc/rc.d/rc$runlevel.d/目录下以K开头的服务。就关闭。
# 2、开启当前运行级别(correct runlevel )/etc/rc.d/rc$runlevel.d/目录下# 以S开头的服务
#这样就实现了,不同运行级别的所允许启动、禁止启动的服务的控制。
#如果当前运行级别(correct runlevel )/etc/rc.d/rc$runlevel.d/目录下以S开头的#服务脚本有:half 就会关闭计算机。
#[root@node2 rc.d]# ll rc0.d/S*
lrwxrwxrwx 1 root root 17 Apr 5 00:13 rc0.d/S00killall ->../init.d/killall
lrwxrwxrwx 1 root root 14 Apr 5 00:13 rc0.d/S01halt -> ../init.d/halt
# 会先执行kill脚本再执行halt脚本。
# 其实系统管理员发出【shutdown】命令,就是通知 init 进程,运行级别改变了。
[root@node2 ~]# man shutdown
.....shutdown does its job by signalling the init process, asking it to change the runlevel.
......
# 进程init的配置文件/etc/inittab 定义等级切换时动作
[root@node2 ~]# vim /etc/inittab
l0:0:wait:/etc/rc.d/rc 0 # 在开机时,或改变运行等级时都会执行
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
# 这些行表示在系统的运行级别每次发生变化时都就当运行一次rc程序(/etc/rc.d/rc脚本),
# 而且init应当将一个包含运行级别号(0~~6)的单字符参数传递给rc程序。
# 会监控主机的运行等级的变化,如运行等级变化了就会调用:/etc/rc.d/rc 脚本
# 假如当前主机的运行等级是:
[root@node2 bin]# runlevel
N 3
# 作用命令init 发出关闭程序信号使用:
[root@node2 bin]# init 0
# init进程发现运行等级改变就会按照配置文件inittab中的 l0:0:wait:/etc/rc.d/rc # 0执行相关操作。
[root@node2 ~]# vim /etc/rc.d/rc
#! /bin/bash
#
# rc This file is responsible for starting/stopping
# services when the runlevel changes.
#
# Original Author:
# Miquel van Smoorenburg,
#
set -m
###################################################################
#该函数是检查当前运行级别的脚本条件:
# 1、该脚本必须有可运行权限;
# 2、不属于函数is_ignored_file 中指定的类型
# check a file to be a correct runlevel script
check_runlevel ()
{
# Check if the file exists at all.
[ -x "$1" ] || return 1
is_ignored_file "$1" && return 1 # 调用函数检查文件类型。
return 0
}
# Now find out what the current and what the previous runlevel are.
argv1="$1" #记录:运行级别改变时,init进程触发运行rc脚本时传递的参数。
set `/sbin/runlevel` # 记录当前主机的运行级别
runlevel=$2
previous=$1
export runlevel previous
. /etc/init.d/functions
# See if we want to be in user confirmation mode
if [ "$previous" = "N" ]; then
if [ -f /var/run/confirm ]; then
echo $"Entering interactive startup"
else
echo $"Entering non-interactive startup"
fi
fi
# Get first argument. Set new runlevel to this argument.
[ -n "$argv1" ] && runlevel="$argv1"
#如果进程init监控到运行级别改变时,触发运行rc脚本时传递了参数,
#就把该参数当作当前主机的运行级别
# Is there an rc directory for this new runlevel?
#判断运行级别在/etc/目录下是否的对应目录,如果没有就直接退出。
#这也可判断传递的运行参数是否正确
[ -d /etc/rc$runlevel.d ] || exit 0
####################################################################
#给/etc/rc.d/rc$runlevel.d目录下的K开头的脚本传递:stop 以实现关闭该运行级别不
#启动的服务
# First, run the KILL scripts.
for i in /etc/rc$runlevel.d/K* ; do
check_runlevel "$i" || continue
#调用函数check_runlevel检查脚本,如果去一个服务的启动脚本就往下执行,
#否则退出当前循环执行下一次循环
########################如果 $i 是一个服务的启动脚本,判断该脚本(以K开头的脚本)#在运行级别切换之前是否已经启动。
#因为通过脚本启动服务后(如:service httpd start 或 httpd start),
#都会在/var/lock/subsys/目录下创建一个以启动脚本命名的文件
#也正是通过判断/var/lock/subsys/目录下有没有该服务脚本对应的文件,
#来确定该服务是否启动的。
# Check if the subsystem is already up.
subsys=${i#/etc/rc$runlevel.d/K??}
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] \
|| continue
# Bring the subsystem down.
#关闭当前运行级别设置不启动的服务(运行级别切换之前启动的服务,
#但是该服务在当前运行级别是设置不启动的),
if LC_ALL=C egrep -q "^..*init.d/functions" $i ; then
$i stop
else
action $"Stopping $subsys: " $i stop
fi
done
############### 启动当前运行级别设置启动的服务#####################################################################
# Now run the START scripts.
for i in /etc/rc$runlevel.d/S* ; do
check_runlevel "$i" || continue
# 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
#如果运行级别切换之前,已经启动了该服务就直接退出。
#防止一个服务启动两次。目录/var/lock/subsys/下锁文件的作用。
# If we're in confirmation mode, get user confirmation
if [ -f /var/run/confirm ]; then
confirm $subsys
test $? = 1 && continue
fi
#如果当前运行级别下(/etc/rc.d/rc$runlevel.d)的half脚本是S开头的
#就会运行该脚本,该脚本是关闭计算机的,
update_boot_stage "$subsys"
# Bring the subsystem up.
if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then
export LC_ALL=C
exec $i start
fi
if LC_ALL=C egrep -q "^..*init.d/functions" $i \
|| [ "$subsys" = "single" -o "$subsys" = "local" ]; then
$i start
else
action $"Starting $subsys: " $i start
fi
done
rm -f /var/run/confirm
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
/usr/bin/rhgb-client --quit
fi