Linux系统脚本分析之rc.sysinit

来源:互联网 发布:云计算培训大纲课程 编辑:程序博客网 时间:2024/06/16 18:55

Linux系统脚本分析之rc.sysinit

#!/bin/bash
#
# /etc/rc.d/rc.sysinit - run once at boot time

#

 

# Rerun ourselves through initlog                                                //通过 /sbin/initlog命令重新运行自己
if [ -z "$IN_INITLOG" -a -x /sbin/initlog ]; then                            //条件是 :如果 IN_INITLOG 变量的值不为空,且 /sbin/initlog可执行
    exec /sbin/initlog -r /etc/rc.d/rc.sysinit                                //调用 exec /sbin/initlog-r 是表示运行某个程序
fi

 

##############################################################################################################

 

HOSTNAME=`/bin/hostname`                            #取得主机名
HOSTTYPE=`uname -m`                                    #取得主机类型
unamer=`uname -r`                                          #取得内核的 release 版本(例如 2.4.9.30-8


eval version=`echo $unamer | awk -F '.' '{ print "(" $1 " " $2 ")" }'`            #取得版本号

 

if [ -f /etc/sysconfig/network ]; then                # 如果存在 /etc/sysconfig/network,则执行该文件。

    . /etc/sysconfig/network                             # network文件主要控制是否启用网络、默认网关、主机名
fi

if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then            #如果执行 network 文件后 HOSTNAME 为空或者为 "(none)"
    HOSTNAME=localhost                                                        #则将主机名设置为 "localhost"
fi

 

 

# Mount /proc and /sys (done here so volume labels can work with fsck)        #接下来是挂载 /proc  /sys ,这样 fsck才能使用卷标
mount -n -t proc /proc /proc                                                                      #  -n表示不写 /etc/mtab ,这在 /etc 所在的文件系统为只读时用。因为此时的/还是只读的
[ -d /proc/bus/usb ] && mount -n -t usbfs /proc/bus/usb /proc/bus/usb        #如果存在 /proc/bus/usb目录则把 /proc/bus/usb usbfs 挂载到 /proc/bus/usb
mount -n -t sysfs /sys /sys >/dev/null 2>&1                                                    #接下来就是把 /sys 目录以 sysfs 格式挂载到 /sys目录下

 

##############################################################################################################

 

. /etc/init.d/functions             #执行 /etc/init.d/functions文件,该文件提供了很多有用的函数,具体见 “functions脚本提供的函数一文

 

##############################################################################################################

 

# Check SELinux status                                                       
selinuxfs=`awk '/ selinuxfs / { print $2 }' /proc/mounts`        
SELINUX=                                                                                                    
if [ -n "$selinuxfs" ] && [ "`cat /proc/self/attr/current`" != "kernel" ]; then            
 if [ -r $selinuxfs/enforce ] ; then
  SELINUX=`cat $selinuxfs/enforce`
 else
  # assume enforcing if you can't read it
  SELINUX=1
 fi
fi

 

if [ -x /sbin/restorecon ] && LC_ALL=C fgrep -q " /dev " /proc/mounts ; then
 /sbin/restorecon  -R /dev 2>/dev/null
fi

 

disable_selinux() {
 echo "*** Warning -- SELinux is active"
 echo "*** Disabling security enforcement for system recovery."
 echo "*** Run 'setenforce 1' to reenable."
 echo "0" > $selinuxfs/enforce
}

 

relabel_selinux() {
    if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
 chvt 1
    fi
    echo "
         *** Warning -- SELinux relabel is required. ***
  *** Disabling security enforcement.         ***
  *** Relabeling could take a very long time, ***
  *** depending on file system size.          ***
  "
    echo "0" > $selinuxfs/enforce
    /sbin/fixfiles -F relabel > /dev/null 2>&1
    rm -f  /.autorelabel
    echo "*** Enabling security enforcement.         ***"
    echo $SELINUX > $selinuxfs/enforce
    if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
 chvt 8
    fi
}

 

##############################################################################################################

 

if [ "$HOSTTYPE" != "s390" -a "$HOSTTYPE" != "s390x" ]; then
  last=0
  for i in `LC_ALL=C grep '^[0-9].*respawn:/sbin/mingetty' /etc/inittab | sed 's/^.* tty\([0-9][0-9]*\).*/\1/g'`; do
        > /dev/tty$i
        last=$i
  done
  if [ $last -gt 0 ]; then
       > /dev/tty$((last+1))
       > /dev/tty$((last+2))
  fi
fi

 

##############################################################################################################

 

if [ "$CONSOLETYPE" = "vt" -a -x /sbin/setsysfont ]; then            #下面是设置屏幕的默认字体。如果 CONSOLETYPE变量的值为 vt  /sbin/setsysfont 命令可执行
   echo -n "Setting default font ($SYSFONT): "                            #打印 "setting deafault font xxxx " ,默认字体应该是 xxxx
   /sbin/setsysfont                                                                   #执行 /sbin/setsysfont
   if [ $? -eq 0 ]; then                                                                #如果上述命令执行返回的 exit status 0
      success                                                                                #则调用 success 函数(来自于 functions 脚本),记录一个成功的事件
   else
      failure                                                                                 #否则调用 failure 函数
   fi
   echo ; echo                                                
fi

 

##############################################################################################################

 

# Print a text banner.                                                                #下面部分是打印 "welcome to xxxxx"的标题栏


echo -en $"\t\tWelcome to "                                                      #打印 "<tab><tab>Welcom to",同时不换行
if LC_ALL=C fgrep -q "Red Hat" /etc/redhat-release ; then           # /etc/redhat-release文件中找出含有 "Red Hat"的行,如果找到
 [ "$BOOTUP" = "color" ] && echo -en "\\033[0;31m"                        #则变量 BOOTUP 的值为 color ,并设置输出字体输出红色 
 echo -en "Red Hat"                                                                    #同时打印 "Red Hat" ,接下来打印发行版本(产品)
 [ "$BOOTUP" = "color" ] && echo -en "\\033[0;39m"                        如果变量 BOOTUP 的值为 color 则设置输出字体为白色
 PRODUCT=`sed "s/Red Hat \(.*\) release.*/\1/" /etc/redhat-release`    # /etc/redhat-release中找出含有 "Red Hat"且后面若干字符,然后是 "release"的行,并截取中间部分给 PRODUCT

                                                                                                    

echo " $PRODUCT"                                                                            输出变量 PRODUCT 的值(白色)
elif LC_ALL=C fgrep -q "Fedora" /etc/redhat-release ; then             #如果/etc/redhat-release中没有 Red Hat 字符串,但有 Fedora ,则执行类似过程
 [ "$BOOTUP" = "color" ] && echo -en "\\033[0;31m"
 echo -en "Fedora"
 [ "$BOOTUP" = "color" ] && echo -en "\\033[0;39m"
 PRODUCT=`sed "s/Fedora \(.*\) release.*/\1/" /etc/redhat-release`
 echo " $PRODUCT"
else                                                                                            #如果 /etc/redhat-release中既没有含 Red Hat 也没有含 Fedora 的行,则
 PRODUCT=`sed "s/ release.*//g" /etc/redhat-release`                    #找到含有 ‘release' 的行,并把它前面的部分输出,作为 PRODUCT变量的值并输出
 echo "$PRODUCT"
fi

 

# 补充 :实际效果是 Red Hat两个字是红色,其他都是白色

##############################################################################################################


if [ "$PROMPT" != "no" ]; then                                                        #如果变量 PROMPT 的值不为 "no" (表示允许交互启动),则
 echo -en $"\t\tPress 'I' to enter interactive startup."                            #打印提示信息“Press I to enter interactive startup”,但此时按 I还未起作用
 echo    
fi

##############################################################################################################

# 注释 :下面部分是设置输出到 console的日志的详细级别

 

# Fix console loglevel                                                                  #设置控制台的日志级别
if [ -n "$LOGLEVEL" ]; then                                                            #如果 LOGLEVEL 变量的值不为空
 /bin/dmesg -n $LOGLEVEL                                                                #则执行 dmesg ,设置打印到 consoel 的日志的级别为 $LOGLEVEL
fi

 

##############################################################################################################

 

# 注释 :下面部分是启动 udev并加载 idescsinetworkaudio以及其他类型的设备的模块的部分

 

[ -x /sbin/start_udev ] && /sbin/start_udev                                    #如果 /sbin/start_udev可执行,则执行它,会在屏幕上显示 “Starting udev ... [OK]”

 

# Only read this once.
cmdline=$(cat /proc/cmdline)                                                        #读取 /proc/cmdline,这是内核启动的时的参数,赋予变量 cmdline

 

# Initialize hardware                                                                    # 下面初始化硬件
if [ -f /proc/sys/kernel/modprobe ]; then                                        #如果 /proc/sys/kernel/modprobe文件存在(该文件告诉内核用什么命令来加载模块),则
   if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then            #如果 $cmdline 变量的值含有 nomodules ,且存在 /proc/modules 文件,则
       sysctl -w kernel.modprobe="/sbin/modprobe" >/dev/null 2>&1            #使用 sysctl 设置 kernel.modprobe  /sbin/modprobe 命令
       sysctl -w kernel.hotplug="/sbin/hotplug" >/dev/null 2>&1                    #使用 sysctl 设置  kernel.hotplug  /sbin/hotplug 命令
   else                                                                                           #如果不存在 /proc/sys/kernel/modprobe文件,则                             
       # We used to set this to NULL, but that causes 'failed to exec' messages"    
       sysctl -w kernel.modprobe="/bin/true" >/dev/null 2>&1                #使用 sysctl 设置 kernel.modprobe  /bin/true
       sysctl -w kernel.hotplug="/bin/true" >/dev/null 2>&1                    # kernel.hotplug也一样
   fi
fi

 

##############################################################################################################

 

# 注释 :下面开始真正的加载各种类型的设备的驱动

 

# 首先是找出那些模块需要被加载,并把模块名按类分别放到 idescsinetworkaudioother 5个变量中

 

echo -n $"Initializing hardware... "                                                    #打印 "initalizing hardware.."(不换行),并开始初始化硬件

 

ide=""                                                                                              #下面这些变量都是为了存储的型号,格式为 " <module1> <module2> <module3> ..."           
scsi=""
network=""
audio=""
other=""
eval `kmodule | while read devtype mod ; do                                # kmodule 命令的输出一次读入两个变量 devtype (设备类型)和 mod(模块名)
 case "$devtype" in                                                                            # 根据 devtype做出适当的选择 
  "IDE") ide="$ide $mod"                                                                            #如果 devtype 的值为 IDE ,则把 mod 加入到现有的 ide变量的值中 
     echo "ide=\"$ide"\";;                                                                            #输出 "ide=" 然后是变量 ide 的值
  "SCSI") scsi="$scsi $mod"                                                                         # 如果 devtype的值为 SCSI ,则把 mod变量的值加入到 scsi 变量的值中
     echo "scsi=\"$scsi"\";;                                                                           #输出 "scsi=" 再输出 $scsi  
  "NETWORK") network="$network $mod"                                                    #下面的 NETWORK  AUDIO 也一样
     echo "network=\"$network"\";;
  "AUDIO") audio="$audio $mod"
     echo "audio=\"$audio"\";;
  *) other="$other $mod"                                                                            如果是属于 other类型的则把模块名 $mod 加入到 other变量的值列表中
     echo "other=\"$other"\";;
 esac
done`

 

load_module () {                    # 定义一个函数名为 load_module
 LC_ALL=C fgrep -xq "$1" /etc/hotplug/blacklist 2>/dev/null || modprobe $1 >/dev/null 2>&1        # /etc/hotplug/blacklist文件中查找是否有指定的模块,如果没有
}                                                                                                                                            #再用 modprobe 加载指定的模块

 

# IDE                                        #下面开始加载所有 IDE 类型的设备的模块
for module in $ide ; do                 #  ide变量中每次取出1个值,赋予变量 module 
 load_module $module                 #再用 load_module 函数加载它。如果该模块存在于 /etc/hotplug/blacklist,则不会被加载(因为存在于黑名单中)
done

 

# SCSI                                    # SCSI方面的比较特殊,除了加载 scsi变量中的模块外,还会从 modprobe -c (显示所有配置)中找出 scsi卡(hostadapter)的模块
for module in `/sbin/modprobe -c | awk '/^alias[[:space:]]+scsi_hostadapter[[:space:]]/ { print $3 }'` $scsi; do    modprobe -c 中找出所有scsi卡的模块别名,
 load_module $module             #并和 scsi 变量一起,通过 for 循环一一加载
done


load_module floppy                #然后加载 floppy 模块

 

echo -n $" storage"                #输出 "storage" ,表示存储方面的模块加载已经完成

 

# Network                            #接下来是加载网络设备模块


pushd /etc/sysconfig/network-scripts >/dev/null 2>&1        # pushd是一个 bash 的内建命令,把目录名放入目录堆栈的顶部,并进入指定目录
interfaces=`ls ifcfg* | LC_ALL=C egrep -v '(ifcfg-lo|:|rpmsave|rpmorig|rpmnew)' | \        #找出 network-scripts目录下所有 lscfg 开头的文件名,排除指定备份和loopback
            LC_ALL=C egrep -v '(~|\.bak)$' | \                                                                    #排除以 ~  .bask结尾的文件名
            LC_ALL=C egrep 'ifcfg-[A-Za-z0-9\._-]+$' | \                                                       #找出所有以 ifcfg- 开头,并以多个字母/数字结尾的文件名
     sed 's/^ifcfg-//g' |                                                                                                  #把前缀 ifcfg- 去掉,只留下后面的接口名
     sed 's/[0-9]/ &/' | LC_ALL=C sort -k 1,1 -k 2n | sed 's/ //'`                                        # 在数字前面加上空格,是类型和编号分离,便于sort 排序,然后再组合回去

                                                                                                                                 #目的是按顺序启动接口

for i in $interfaces ; do                                                                                                #对于在 $interfaces变量中的每个接口
 eval $(LC_ALL=C fgrep "DEVICE=" ifcfg-$i)                                                                     #从对应的文件 ifcfg-$i找出 DEVICE=
 load_module $DEVICE                                                                                                # 然后用 load_module加载它,注意,DEVICE=行可以是别名,例如 eth1.n7css
done
popd >/dev/null 2>&1                                                                                                # network-scripts从目录名堆栈中弹出,并返回原来的目录

                                                                                

for module in $network ; do                                                                                        # 剩下还有 network变量中的模块
 load_module $module                                                                                                #也一一加载
done

 

echo -n $" network"                                                                                                    #输出 network字符串,表示加载网络设备模块工作完毕

 

# Sound
for module in `/sbin/modprobe -c | awk '/^alias[[:space:]]+snd-card-[[:digit:]]+[[:space:]]/ { print $3 }'` $audio; do    #scsi一样,加载在 modprobe -c audio变量
 load_module $module                                                                                                                                          #中的模块
done

 

echo -n $" audio"                                                                                                        #输出 audio,表示声卡设备驱动加载完毕,一般会有多个驱动被加载        

 

# Everything else (duck and cover)                                                                             #剩下的就是 other类型的设备了
for module in $other ; do
 load_module $module                                                                                                #这个直接用 load_moudle函数加载了
done

 

echo -n $" done"                                                                                                        #输出 done表示完成
success                                                                                                                    #调用 success函数,记录该事件
echo

 

############################################################################################################## 

# 注释 :下面是启用 Software-RAID的检测

 

echo "raidautorun /dev/md0" | nash --quiet       #nash(小型脚本解释器)执行 "raidautorun /dev/md0"命令,对所有paritition ID 0xFD分区进行检查

##############################################################################################################

 

# Start the graphical boot, if necessary; /usr may not be mounted yet, so we            # 显示图形模式的启动画面,但由于 rhgb 命令在/usr 分区上,
# may have to do this again after mounting                                                            这时 /usr分区还没有被挂载,所以在挂载后重新做一遍这部分脚本
RHGB_STARTED=0           #初始化 RHGB_STARTED变量的值为 0,表示尚未启动。RHGBredhat graphical boot的含义,
mount -n /dev/pts         #挂载 /dev/pts,类型是 devpts,目的是获得 pty,这是一种伪文件系统

 

if strstr "$cmdline" rhgb && [ "$BOOTUP" = "color" -a "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb ]; then        #如果内核启动参数 $cmdline含有 rhgb,且

                                                                                                                                                        # BOOTUP变量的值为 color,且 GRPAHICAL变量的值为 yes

                                                                                                                                                        #/usr/bin/rhgb 文件存在并可执行
   LC_MESSAGES= /usr/bin/rhgb                                                                                                            "/usr/sbin/rhgb"赋予变量 LC_MESSAGES
   RHGB_STARTED=1                                                                                                                            # RHGB_STARTED变量的值为1
fi

 

##############################################################################################################

# 注释 :下面部分是使用 sysctl设置内核的参数

 

# Configure kernel parameters                    
update_boot_stage RCkernelparam             # 调用 update_boot_stage函数,该函数由 /etc/rc.d/init.d/functions脚本定义,主要执行 "/usr/sbin/rhgb-client --update $1"
action $"Configuring kernel parameters: " sysctl -e -p /etc/sysctl.conf    #调用 action函数,执行 sysctl命令,它读取 /etc/sysctl.conf,同时输出 “Configuring kernel 

                                                                                                       # parameters”字符串,action函数也是由 /etc/rc.d/init.d/functions脚本定义

 

# 补充 :action函数的作用是把第一个参数 $1赋予变量 string并输出到屏幕,同时把该字符串也写入 /etc/rhgb/temp/rhgb-console

 

# 然后把 $1后面的部分作为命令交给 initlog执行,并根据结果调用 success或者 failure函数。而 success或者 failure函数又会根据结果输出 [ OK ]或者 [ FAILED ]

 

# 除了 successfailure函数外,functions脚本还定义了 passedwarnning函数,它们又分别调用 echo_passwd() 和echo_warnning()函数,

 

# 以输出 [ PASSED ][ WARNNING ]

 

############################################################################################################## 

# 注释 :下面设置系统的硬件时钟

# Set the system clock.                    #接下来设置系统时钟
update_boot_stage RCclock                #同样是告诉 update_boot_stage该事件(执行 /usr/bin/rhgb-client --update="$1"命令,这里 $1就是 "RCclock"
ARC=0                                                
SRM=0
UTC=0

 

if [ -f /etc/sysconfig/clock ]; then        #如果存在 /etc/sysconfig/clock则执行该文件
   . /etc/sysconfig/clock

 

   # convert old style clock config to new values
   if [ "${CLOCKMODE}" = "GMT" ]; then                        #如果变量 CLOCKMODE 为旧式的GMT 格式
      UTC=true                                                                #UTC变量的值为 ture 
   elif [ "${CLOCKMODE}" = "ARC" ]; then                    # 如果 CLOCKMODE的值是 ARC,则
      ARC=true                                                                # ARC的值为 true
   fi                                                                        # 如果 CLOCKMODE不等于 GMT或者 UTC,则 UTC的值等于 /etc/sysconfig/clock中的值,一般都是 false
fi                                                                            #如果 CLOCKMODE不等于 GMT后者 ARC,则 UTC的值为 0

 

CLOCKDEF=""                                                            # CLOCKDEF变量的值默认为空
CLOCKFLAGS="$CLOCKFLAGS --hctosys"                       #CLOCKFLAGS变量的值为原来的值(可能为空)加上 '--hctosys',表示把硬件时钟写入内核时钟

 

case "$UTC" in                                                          #根据 UTC变量的值进行选择                                             
    yes|true) CLOCKFLAGS="$CLOCKFLAGS --utc"             #如果 UTC的值为 yes或者 true,则变量CLOCKFLAGS 的值加上--utc ,表示采用UTC 时区
  CLOCKDEF="$CLOCKDEF (utc)" ;;                                    # 同时变量 CLOCKDEF的值加上 "(utc)"
    no|false) CLOCKFLAGS="$CLOCKFLAGS --localtime"     #如果变量 UTC的值为 false或者 no,则
  CLOCKDEF="$CLOCKDEF (localtime)" ;;                        # CLOCKDEF的值加上 "(localtime)"。由于安装 OS时没有选择UTCCLOCKDEF的值一般最后就是 (localtime)而已
esac
case "$ARC" in                                                          根据ARC 变量的值来选择              
    yes|true) CLOCKFLAGS="$CLOCKFLAGS --arc"            #如果是 yes或者 true,则 CLOCKFLAGS的值加上 --arcCLOCKDEF的值加上 '(arc)'
  CLOCKDEF="$CLOCKDEF (arc)" ;;                                #如果 ARC的值为 0,则 CLOCKFLAGSCLOCKDEF的值都不变
esac
case "$SRM" in                                                        # 如果 SRM的值是 yes或者 true,则 CLOCKFLAGS的值加上 "--srm"CLOCKDEF加上 "(srm)"
    yes|true) CLOCKFLAGS="$CLOCKFLAGS --srm"
  CLOCKDEF="$CLOCKDEF (srm)" ;;
esac

 

/sbin/hwclock $CLOCKFLAGS                    #执行 hwclock $CLOCKFLAGS命令,一般就是 /sbin/hwclock --hctosys

 

action $"Setting clock $CLOCKDEF: `date`" date        #并输出 "setting clock "$CLOCKDEF,并执行 date输出当前时间,然后输出 [ OK ]

##############################################################################################################

注释 :下面部分是设置 key map 

if [ "$CONSOLETYPE" = "vt" -a -x /bin/loadkeys ]; then            #接下来是设置 keymap,一般都是 us 
 KEYTABLE=                                                                        设置 KEYTABLEKEYMAP 
 KEYMAP=
 if [ -f /etc/sysconfig/console/default.kmap ]; then                假如存在/etc/sysconfig/console/default.kmap,则
  KEYMAP=/etc/sysconfig/console/default.kmap                            # KEYMAP 变量的值为/etc/sysconfig/console/default.kmap
 else                                                                                    否则
  if [ -f /etc/sysconfig/keyboard ]; then                                        #如果存在 /etc/sysconfig/keyboard文件,则执行它
    . /etc/sysconfig/keyboard                                                       #该文件设置 KEYTABLE变量的值,例如KEYTABLE="/usr/lib/kbd/keytables/us.map
  fi
  if [ -n "$KEYTABLE" -a -d "/lib/kbd/keymaps" ]; then             # 如果 KEYTABLE的值不为空,且存在 /lib/kbd/keymaps/目录,则
     KEYMAP="$KEYTABLE.map"                                                # KEYMAP的值为 KEYTABLE的值加上 ".map" 
  fi
 fi
 if [ -n "$KEYMAP" ]; then                                                                 #假如 KEYMAP变量的值不为空(间接表示 KEYTABLE不为空且存在 keymaps目录)
  # Since this takes in/output from stdin/out, we can't use initlog
  if [ -n "$KEYTABLE" ]; then                                                                    #KEYTABLE的值不为空
    echo -n $"Loading default keymap ($KEYTABLE): "                                     则输出"Loading default keymap xxxx"
  else
    echo -n $"Loading default keymap: "                                                    #否则只输出 Loading default keymap
  fi    
  loadkeys $KEYMAP < /dev/tty0 > /dev/tty0 2>/dev/null && \            #接下来用 loadkeys加载 $KEYMAP指定的键盘映射文件。
     success $"Loading default keymap" || failure $"Loading default keymap"        #如果成功则调用 success函数,否则调用 failure函数
  echo
 fi
fi

 

###############################################################################################################注释 :下面部分是设置主机名 

 

# Set the hostname.                                #接下来是设置主机名
update_boot_stage RChostname                #告诉 update_boot_stage函数该事件,以执行 /usr/sbin/rhgb-client --update RChostname命令
action $"Setting hostname ${HOSTNAME}: " hostname ${HOSTNAME}        #打印 "setting hostname xxxx"字符串,并执行 hostname ${HOSTNAME}设置主机名

                                                                 #  注意,HOSTNAME变量前面已经有过赋值的了,就是 `/bin/hostname`命令返回的值

 

##############################################################################################################

# 注释 :下面设置 ACPI部分

# Initialiaze ACPI bits
if [ -d /proc/acpi ]; then                                                                    #如果存在 /proc/acpi 目录,则
   for module in /lib/modules/$unamer/kernel/drivers/acpi/* ; do            #对于在 /lib/modules/<kernel-version>/kernel/drivers/acpi/目录下的所有模块文件
      insmod $module >/dev/null 2>&1                                                        #都用 insmod命令加载到内核中
   done
fi

 

 

###############################################################################################################注释 :下面是主要的部分,就是确认是否需要对 /文件系统进行 fsck 

if [ -f /fastboot ] || strstr "$cmdline" fastboot ; then      #接下来是看对 /系统进行 fsck的时候了。如果不存在 /fastboot文件则看 cmdline变量是否含有 fastboot字符串
 fastboot=yes                                                              #如果有,则 fastboot变量的值为 yes/fastboot是由 shutdown -f创建的,表示重启时不作 fsck
fi

 

if [ -f /fsckoptions ]; then                                            #如果存在 /fsckoptions文件,则把文件的内容赋予变量 fsckoptions变量
 fsckoptions=`cat /fsckoptions`
fi

 

if [ -f /forcefsck ] || strstr "$cmdline" forcefsck ; then        #如果不存在 /forcefsck文件,则检查 cmdline变量是否含有 forcefsck字符串,如果有
 fsckoptions="-f $fsckoptions"                                            #则在 fsckoptions的值前面加上 "-f"/forcefsck是由 shutdown -F创建的,强制 fsck
elif [ -f /.autofsck ]; then                                                 #如果存在 /.autofsck
      if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then        #  且文件/usr/bin/rhgb-clinet 可执行,且/usr/bin/rhgb 服务在运行(--pnig),则
           chvt 1                                                                                                #  切换到虚拟控制台#1 (主要是显示fsck 的信息用)
       fi
       echo $"Your system appears to have shut down uncleanly"                            # 并显示需要fsck 的信息“You system appears to have shut down uncleanly”
       AUTOFSCK_TIMEOUT=5                                                                              #设置超时时间为5
      [ -f /etc/sysconfig/autofsck ] && . /etc/sysconfig/autofsck                           #如果存在 /etc/sysconfig/autofsck 则执行它
      if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then                                                 #如果执行该文件后 AUTOFSCK_DEF_CHECK 变量的值为yes ,则
          AUTOFSCK_OPT=-f                                                                                        #变量 AUTOFSCK_OPT 的值为"-f"
      fi

 

      if [ "$PROMPT" != "no" ]; then                                                                //如果 PROMPT的值不为 no,则
        if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then                                                //AUTOFSCK_DEF_CHECK的值为 yes
           if /sbin/getkey -c $AUTOFSCK_TIMEOUT -m $"Press N within %d seconds to not force file system integrity check..." n ; then    //  执行getkey 命令,超时5秒,并

                                                                                                                                                                                       //提示5秒内按下 n 键可跳过fsck
              AUTOFSCK_OPT=        // 如果用户按下 n ,则AUTOFSCK_OPT 的值为空,表示取消自动fsck
           fi
        else                    // 如果 AUTOFSCK_DEF_CHECK 的值不为yes ,则提示5秒内按y可以强制 fsck
          if /sbin/getkey -c $AUTOFSCK_TIMEOUT -m $"Press Y within %d seconds to force file system integrity check..." y ; then        //同样是用 getkey捕捉 y
              AUTOFSCK_OPT=-f        // 如果用户按下了y 键,则AUTOFSCK_OPT 的值为"-f"
          fi
       fi
       echo
      else         //如果 PROMPT的值为 "no", 这是用户无法选择是否fsck 
        # PROMPT not allowed
        if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then                                                #取决于 AUTOFSCK_DEF_CHECK 变量的值,如果是yes ,则
          echo $"Forcing file system integrity check due to default setting"     # 提示由于默认的设置强制fsck 。可能是mount 次数达到限制,或者多长时间没有fsck 
        else                                            
          echo $"Not forcing file system integrity check due to default setting"            #如果 AUTOFSCK_DEF_CHECK的值为 no,则表示不做 fsck 
        fi
      fi
      fsckoptions="$AUTOFSCK_OPT $fsckoptions"
fi

 

# 注释 :注意!到这里为止并没有执行 fsck 操作,只是判断是否需要执行fsck 以及fsck 命令的选项

 

if [ "$BOOTUP" = "color" ]; then       #如果 BOOTUP的值为 color,则
 fsckoptions="-C $fsckoptions"            # -C表示显示 fsck进度信息
else                                              否则
 fsckoptions="-V $fsckoptions"            # -V表示显示 verbose信息
fi

 

if [ -f /etc/sysconfig/readonly-root ]; then            #如果存在 /etc/sysconfig/readonly-root,则
    . /etc/sysconfig/readonly-root                            #执行该文件

     

    if [ "$READONLY" = "yes" ]; then                            #如果 READONLY变量的值为 yes,则
        # Call rc.readonly to set up magic stuff needed for readonly root        #执行 /etc/rc.readonly脚本
        . /etc/rc.readonly
    fi
fi


#########################################################################################################################################################

# 注释 :下面开始判断 /文件系统的类型(是本地还是 nfs格式)。如果是nfs则不执行fsck ,否则继续


_RUN_QUOTACHECK=0                                            #初始化 RUN_QUOTACHECK的值为0.这里是作一个标记,因为后面的代码可能会导致重启。在这里做好标记

                                                                            #如果后面没有重启,就可以把 _RUN_QUOTACHECK设置为1
ROOTFSTYPE=`awk '/ \/ / && ($3 !~ /rootfs/) { print $3 }' /proc/mounts`        #/proc/mounts中找出 /文件系统的类型,并赋予变量 ROOTFSTYPE

# 注释 :下面用到 -z "$fastboot",如果有 /fastboot,则 fastboot的值为 yes, 所以就不合if 的条件,则跳过fsck 。这就是shutdown -f 快速启动的效果

 

if [ -z "$fastboot" -a "$READONLY" != "yes" -a "X$ROOTFSTYPE" != "Xnfs" -a "X$ROOTFSTYPE" != "Xnfs4" ]; then     #如果fastboot变量的值为空且  READONLY变量不为 yes

                                                                                                                                                                #/文件系统的类型不是 nfs或者 nfs4,则 

        STRING=$"Checking root filesystem"    初始化string 变量并输出"checking root filesystem" 
        echo $STRING

        rootdev=`awk '/ \/ / && ($3 !~ /rootfs/) {print $1}' /proc/mounts`        #/proc/mounts中找出 /文件系统所在的设备,并赋予 rootdev变量(例如 /dev/hdb2
         if [ -b /initrd/"$rootdev" ] ; then        #如果 /initrd/$rootdev 是一个block 设备
              rootdev=/initrd/"$rootdev"                    #rootdev就是 /initrd/rootdev 
         else                                                 #否则 rootdev就是 / ,正常情况应该是执行该步的,也就是rootdev 最终为 /
         rootdev=/                                       # rootdev的值为 /,因为 fsck支持用 LABELmount pointdevice name 来指定要检查的文件系统 
         fi

    

        # 注释 : 下面开始真正的fsck 操作

         if [ "${RHGB_STARTED}" != "0" -a -w /etc/rhgb/temp/rhgb-console ]; then        #如果 RHGB_STARTED不为0/etc/rhgb/tmp/rhgb-console 文件可写,则
              fsck -T -a $rootdev $fsckoptions > /etc/rhgb/temp/rhgb-console           #执行 fsck命令,-T表示不打印标题栏,-a表示自动修复错误,设备是 ,后面是选项

                                                                                                                      #且信息写入 /etc/rhgb/temp/rhgb-console
         else                                                                                                           #否则
              initlog -c "fsck -T -a $rootdev $fsckoptions"                                                        #调用 initlog执行 fsck ,信息直接输出到屏幕,fsck 命令本身都是一样的。
        fi                                                                                                                     
        rc=$?                                    fsck 的结果送给变量rc

        if [ "$rc" -eq "0" ]; then         # 如果 rc的值为0,表示fsck 成功通过
              success "$STRING"                    #则调用 success打印 "checking root fileysyes      [OK]"
          echo
        elif [ "$rc" -eq "1" ]; then        #如果 rc1,则打印 passed,表示有错误但修复
             passed "$STRING"                #这时调用的是 passed函数(由 /etc/rc.d/init.d/functions脚本定义,输出 "checking root filesystems     [ PASSED ]")
             echo
         elif [ "$rc" -eq "2" -o "$rc" -eq "3" ]; then         #如果 rc2(表示系统应该重启)或者为 3(为1+2 ,表示系统错误已修复,但需要重启)
              echo $"Unmounting file systems"                        #提示卸载 /文件系统
              umount -a                                                        #把所有卸载,当然 /除外
              mount -n -o remount,ro /                                  #/设备已 ro模式重新 mount
              echo $"Automatic reboot in progress."                #然后提示将要自动重启了
              reboot -f                                                        # 在这里执行 reboot -f,强制重启
          fi     #这个 fi是结束 "[ "$rc" -eq "0" ]; "
 
          # A return of 4 or higher means there were serious problems.    #如果 fsck返回的值大于4(不含44表示错误未修复),则表示/ 文件系统出现重大错误,无法继续
         if [ $rc -gt 1 ]; then    这里之所以用-gt 1 ,是因为如果前面返回2或者3就会自动重启了,如果执行到这里说明rc 的值必须至少大于等于4
             if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then    #如果 rhgb-client可执行且 rhgb服务在运行
                  chvt 1                 # 强制切换到 1#虚拟控制台
             fi

 

            failure "$STRING"        #调用 failure函数,打印 "checking root filesystem     [ FAILURE ]"
            echo
            echo
            echo $"*** An error occurred during the file system check."        # 提示fsck 过程出错
            echo $"*** Dropping you to a shell; the system will reboot"         #提示将进入紧急模式的 shell 
            echo $"*** when you leave the shell."                                       #当你退出该 shell时会自动重启

 

            str=$"(Repair filesystem)"        #设置紧急模式下的 shell提示符
            PS1="$str \# # "; export PS1     #  设置提示符变量PS1 "(Repair filesystem) <N> # " <N>表示当前是第几个命令
            [ "$SELINUX" = "1" ] && disable_selinux
            sulogin                                    #自动执行 sulogin,这不是 su,而是 single-user login的意思,自动进入单用户模式的 shell

        

                              #注意这里将进入一个交互式的 shell。只有你执行 exit命令,才会执行下面的代码,否则下面的代码根本不会被执行

 

            echo $"Unmounting file systems"    提示卸载文件系统
            umount -a                                    #卸载所有文件系统,/除外
            mount -n -o remount,ro /              # /ro模式挂载
            echo $"Automatic reboot in progress."        #提示将自动重启
            reboot -f                                    # 立即重启

         elif [ "$rc" -eq "1" ]; then                     # 如果rc 的值等于1,则表示错误修复完毕
            _RUN_QUOTACHECK=1                    如果上面的fsck 没有出错,自然就不会重启,所以这里把 _RUN_QUOTACHECK 的值设置为1,表示可以进行quotacheck

         fi   # 这个 fi 是结束" [ $rc -gt 1 ]; "                             

         if [ -f /.autofsck -a -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then    如果 rhgb-clinet可运行且 rhgb服务在运行
          chvt 8                                                                                                                    #则切换换 8#控制台,也就是图形
         fi
fi        # 这个 fi 是结束前面的”[ -z "$fastboot" -a "$READONLY" != "yes" -a "X$ROOTFSTYPE" != "Xnfs" -a "X$ROOTFSTYPE" != "Xnfs4" ]; “

 

       # 所以如果存在 /fastboot 文件,就直接跳转到这里

 

########################################################################################################################################################
# 注释 :在 initrd/linuxrc或者 /init脚本中会把初始/文件系统卸载掉,如果没有卸载完全,则在这里会重新做一次

 

# Unmount the initrd, if necessary                    #接下来是卸载 initrd初始/文件系统,一般 /init都会在结尾 umount /initrd/dev 
if LC_ALL=C fgrep -q /initrd /proc/mounts && ! LC_ALL=C fgrep -q /initrd/loopfs /proc/mounts ; then    #如果 /proc/mounts文件还有 /initrd/proc条目,

                                                                                                                                                     # 且不存在 /initrd/loops条目,则
   if [ -e /initrd/dev/.devfsd ]; then                                                                                                     #如果存在 /initrd/dev/.devfsd文件,则       
      umount /initrd/dev                                                                                                                            #卸载 /initrd/dev目录
   fi
   umount /initrd                                            #最后把整个 /initrd卸载
   /sbin/blockdev --flushbufs /dev/ram0 >/dev/null 2>&1    #最后用 blockdev --flushbs命令清除 /dev/ram0的内容,该社备就是被挂载为初始/
fi
########################################################################################################################################################                                                                               # 注释 :下面是对 /进行 quota检查,其他文件系统暂时不执行 quotacheck


# Possibly update quotas if fsck was run on /.                    #如果 fsck已经对 /进行了检查,则执行 quotacheck更新 quota情况
LC_ALL=C grep -E '[[:space:]]+/[[:space:]]+' /etc/fstab | \        #/etc/fstab中找出 /文件系统所在的行,并打印第4个字段(属性)
    awk '{ print $4 }' | \                                                           #这是属性字段
    LC_ALL=C fgrep -q quota                                                    #找出是否有 quota字符串,不管是 usrquota还是 grpquota
_ROOT_HAS_QUOTA=$?                                                    #把结果赋予 _ROOT_HAS_QUOTA变量
if [ "X$_RUN_QUOTACHECK" = "X1" -a \                             如果 x$_RUN_QUOTACHECK返回 X1,且
    "X$_ROOT_HAS_QUOTA" = "X0" -a \                                #   X$_ROOT_HAS_QUOTA返回 X0,则表示当前可以执行 quotacheck,且 /也启用了 quota 
    -x /sbin/quotacheck ]; then                                        #  如果存在quotacheck 命令   
 if [ -x /sbin/convertquota ]; then                                    如果存在convertquota 命令
     if [ -f /quota.user ]; then                                                #且存在 /quota.user
          action $"Converting old user quota files: " \                          # 并调用action 函数,打印提示信息,用convertquota 转换成v2 格式的aquota.user 文件
          /sbin/convertquota -u / && rm -f /quota.user                #然后删除 v1格式的/quota.user
     fi
     if [ -f /quota.group ]; then                                            #同样对 /quota.group转换成 v2格式的 aquota.group,并删除/quota.group 文件
          action $"Converting old group quota files: " \
          /sbin/convertquota -g / && rm -f /quota.group            #同样在转换后删除旧的 v1group quota文件
     fi
 fi
 action $"Checking root filesystem quotas: " /sbin/quotacheck -nug /        #然后执行 quotacheck -nug //文件系统进行检查,并打印提示信息
fi    # 这个 fi 是结束"[ "X$_RUN_QUOTACHECK" = "X1" -a "X$_ROOT_HAS_QUOTA" = "X0" -a -x /sbin/quotacheck ]; "

 

########################################################################################################################################################

# 注释 :下面这个部分是设置 ISA 设备的,不过由于现在基本没有ISA 设备了,所以可以跳过该部分,甚至可以在内核中指定不支持ISA

if [ -x /sbin/isapnp -a -f /etc/isapnp.conf -a ! -f /proc/isapnp ]; then        
    # check for arguments passed from kernel
    if ! strstr "$cmdline" nopnp ; then
 PNP=yes
    fi
    if [ -n "$PNP" ]; then
 action $"Setting up ISA PNP devices: " /sbin/isapnp /etc/isapnp.conf
    else
 action $"Skipping ISA PNP configuration at users request: " /bin/true
    fi
fi

######################################################################################################################################################## 

# Remount the root filesystem read-write.                                    #现在 /文件系统 fsck过了,可以按照 read-write的模式挂载了
update_boot_stage RCmountfs                                                      #告诉 rhgb服务器更新 RCmountfs服务的状态
state=`awk '/ \/ / && ($3 !~ /rootfs/) { print $4 }' /proc/mounts`    #/proc/mounts中找出 ' / '字符串并且第3个字段不等于'rootfs',则打印其第4个字段,赋予state
[ "$state" != "rw" -a "$READONLY" != "yes" ] && \                              #如果 state变量的值不为 'rw'READONLY变量的值为 yes ,则  
  action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw /        #-o remount -o rw重新挂载 /rw模式,并打印提示信息

######################################################################################################################################################## 

# 注释 :下面开始是 LVM2的部分了

# LVM2 initialization                                                                                        #下面部分是 LVM2 的初始化部分
if [ -x /sbin/lvm.static ]; then                                                                         # 如果存在 /sbin/lvm.static且可执行
    if ! LC_ALL=C fgrep -q "device-mapper" /proc/devices 2>/dev/null ; then        如果/proc/devices 文件不含有device-mapper ,则
         modprobe dm-mod >/dev/null 2>&1                                                                        #调用 modprobe加载 dm-mod 
    fi
    echo "mkdmnod" | /sbin/nash --quiet >/dev/null 2>&1                                    #并调用 nash执行 mkdmmod,不过是以 quiet 模式执行的
    [ -n "$SELINUX" ] && restorecon /dev/mapper/control >/dev/null 2>&1
    if [ -c /dev/mapper/control -a -x /sbin/lvm.static ]; then                                假如存在/dev/mapper/control 这个字符设备且/sbin/lvm.static 可执行,
         if /sbin/lvm.static vgscan --mknodes --ignorelockingfailure > /dev/null 2>&1 ; then        调用lvm.static 执行 vgscan扫描所有卷组(忽略锁错误)
             action $"Setting up Logical Volume Management:" /sbin/lvm.static vgchange -a y --ignorelockingfailure        #如果扫描到卷组,则调用 action函数,
         fi                                                                                                                                                      #打印提示信息,并执行 vgchange -ay激活全部卷组
    fi
fi


# LVM initialization                 #这是 LVM1的部分,因为系统可能同时存在 lVM1lvm2pv
if [ -f /etc/lvmtab ]; then        如果存在/etc/lvmtab 文件
    [ -e /proc/lvm ] || modprobe lvm-mod > /dev/null 2>&1    /proc/lvm 文件存在,如果没有则调用modprobe lvm-mod 加载lvm-mod ,注意模块名的不同
        if [ -e /proc/lvm -a -x /sbin/vgchange ]; then                #如果现在存在 /proc/lvm文件且 /sbin/vgchange可执行
             action $"Setting up Logical Volume Management:" /sbin/vgscan && /sbin/vgchange -a y    则调用action 打印提示信息,并执行vgchange -ay 激活它们
        fi
fi

 

######################################################################################################################################################## 

# Clean up SELinux labels
if [ -n "$SELINUX" ]; then
   for file in /etc/mtab /etc/ld.so.cache ; do
    [ -r $file ] && restorecon $file  >/dev/null 2>&1
   done
fi

######################################################################################################################################################## 

# Clear mtab                                                            #由于之前的 /etc/mtab并不准确,所以现在把它的内容清掉
(> /etc/mtab) &> /dev/null                                              #>/etc/mtab清空其内容  

 

# Remove stale backups
rm -f /etc/mtab~ /etc/mtab~~                                    #删除 /etc/mtab的备份文件

 

# Enter root, /proc and (potentially) /proc/bus/usb and devfs into mtab.        #root/proc/proc/bus/usbdevpts加入到 /etc/mtab
mount -f /                                                                    #  -f表示只更新 /etc/mtab,但不实际mount,因为这些文件系统在之前都挂载了,没有必要再挂载一次
mount -f /proc
mount -f /sys >/dev/null 2>&1
mount -f /dev/pts
[ -f /proc/bus/usb/devices ] && mount -f -t usbfs usbfs /proc/bus/usb  如果存在/proc/bus/usb/devices 文件,则用mount -f -t usbfs 挂载到/proc/bus/usb       
[ -e /dev/.devfsd ] && mount -f -t devfs devfs /dev         #如果存在 /dev/.devfsd,则同样挂载 devfs/dev

######################################################################################################################################################## 

# configure all zfcp (scsi over fibrechannel) devices before trying to mount them
# zfcpconf.sh exists only on mainframe
[ -x /sbin/zfcpconf.sh ] && /sbin/zfcpconf.sh

######################################################################################################################################################## 

# The root filesystem is now read-write, so we can now log        #由于之前的 /是只读的,所以通过 initlog来记录信息,现在可以通过 syslog
# via syslog() directly..
if [ -n "$IN_INITLOG" ]; then
    IN_INITLOG=                                                                            #如果 IN_INITLOG的值不为空则清空它
fi

 

if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then        如果内核启动参数含有"nomodules" ,且存在/proc/modules 文件,则
    USEMODULES=y                                                                            #USEMODULES设置为 y
fi

 

# Load modules (for backward compatibility with VARs)                
if [ -f /etc/rc.modules ]; then
 /etc/rc.modules
fi

 

 

######################################################################################################################################################## 

update_boot_stage RCraid                                        #下面部分是激活 RAID
if [ -f /etc/mdadm.conf ]; then                                #如果存在 /etc/mdadm.conf
    /sbin/mdadm -A -s                                                # mdadm -A表示 Assemble模式,-s则表示搜索 /etc/mdadm.conf 
fi

 

# 注释 :下面解决旧式的用 raid-tools建立的 software-raid

 

if [ -f /etc/raidtab ]; then                                        #如果存在旧式的 raidtools/etc/raidtab
    # Add raid devices
    [ -f /proc/mdstat ] || modprobe md >/dev/null 2>&1        #如果不存在 /proc/mdstat文件,则用 modprobe md先加载 md模块

    if [ -f /proc/mdstat ]; then
         echo -n $"Starting up RAID devices: "                             #并输出 "Starting up RAID devices:"

         rc=0                                                                           #先把 rc的值设置为0,如果有某个raid 激活失败,则rc 1

                                                                                          # rc 和下面的 RESULT不同,RESULT是每个 raid的激活状态,而 rc是全局的激活状态
         for i in `awk '{if ($1=="raiddev") print $2}' /etc/raidtab`     awk /etc/raidtab 中找出所有raiddev 行打印第2个字段也就是raid 的设备名

         do                                                                                    #针对每个 Software-raid执行下面的代码
                RAIDDEV=`basename $i`                                                把每个raid 设备的设备名(出去前面目录部分)赋予变量RAIDDEV
                RAIDSTAT=`LC_ALL=C grep "^$RAIDDEV : active" /proc/mdstat`            #如果 /proc/mdstat中表明该 RAID已经是 active的状态
                if [ -z "$RAIDSTAT" ]; then                                                                #如果状态为空,表明该 RAID并没有激活
                    # First scan the /etc/fstab for the "noauto"-flag
                    # for this device. If found, skip the initialization
                    # for it to avoid dropping to a shell on errors.
                    # If not, try raidstart...if that fails then
                    # fall back to raidadd, raidrun.  If that
                    # also fails, then we drop to a shell
                    RESULT=1                                                                                    先把RESULT 设置为1,表示false
                    INFSTAB=`LC_ALL=C grep -c "^$i" /etc/fstab`                                # 然后检查 /etc/fstab中是否有以指定的 md设备开头的行,结果赋予 INFSTAB
                    if [ $INFSTAB -eq 0 ] ; then                                                          如果 INFSTAB0,表示没有找到,也就是不希望自动我你挂载该raid 设备
                           RESULT=0                                                                                #则把 RESULT设置为0
                           RAIDDEV="$RAIDDEV(skipped)"                                                    #并在 RAIDDEV后面加上 (skipped),表示该设备跳过不激活它
                    fi
                    NOAUTO=`LC_ALL=C grep "^$i" /etc/fstab | LC_ALL=C fgrep -c "noauto"`    #如果该设备在 /etc/fstab 中但它的属性含有noauto 
                    if [ $NOAUTO -gt 0 ]; then                                                                            #则和上面不在 /etc/fstab一样处理
                           RESULT=0
                           RAIDDEV="$RAIDDEV(skipped)"
                    fi
                    if [ $RESULT -gt 0 -a -x /sbin/mdadm ]; then                                            #如果 /sbin/mdadm文件可执行,且尝试用 mdadm来激活它们
                            /sbin/mdadm -Ac partitions $i -m dev                                                    # mdadm将从 /proc/partitions文件读取并状态指定 raid($i)-m表示 minor 

                                                                                                                                     # number 就等于它刚才装配的 raid 设备名的数字部分
                            RESULT=$?                                                                                           #并把 mdadm的结果赋予 RESULT变量
                    fi
                    if [ $RESULT -gt 0 -a -x /sbin/raidstart ]; then                                            #如果 RESULT大于0,表示madm 命令失败,则尝试用/sbin/raidstart
                        /sbin/raidstart $i
                        RESULT=$?                                                                                    
                    fi
                    if [ $RESULT -gt 0 -a -x /sbin/raid0run ]; then                                             #如果 raidstart还是失败,则尝试用 raid0run
                        /sbin/raid0run $i
                        RESULT=$?
                    fi
                    if [ $RESULT -gt 0 -a -x /sbin/raidadd -a -x /sbin/raidrun ]; then                  #如果 raid0run失败则尝试用 raidadd然后用 raidrun 
                        /sbin/raidadd $i
                        /sbin/raidrun $i
                        RESULT=$?
                    fi
                    if [ $RESULT -gt 0 ]; then                                                                        如果还是失败,则 rc的值最终为1
                        rc=1
                   fi
                    echo -n "$RAIDDEV "                                                                                #输出当前操作的 raid设备名
                else            #这个 else是对应 ”if [ -z "$RAIDSTAT" ]; “的,因为可能内核集成了raid support ,自动激活raid
                       echo -n "$RAIDDEV "                                                                            如果 RAID的状态本来就是 active,则直接输出 raid 的名称
                fi
         done
 echo

 

 # A non-zero return means there were problems.                    #如果只要有一个 raid激活失败,则 rc的值就为1
 if [ $rc -gt 0 ]; then                                                                #如果 rc的值大于0,则表示有raid 激活失败
         if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then    则按照前面fsck 失败的情况,进入紧急模式
      chvt 1
  fi
  echo
  echo
  echo $"*** An error occurred during the RAID startup"
  echo $"*** Dropping you to a shell; the system will reboot"
  echo $"*** when you leave the shell."

 

  str=$"(RAID Repair)"                                                                            #只不过提示符有所不同而已,变成了 (RAID Repair) <N> #
  PS1="$str \# # "; export PS1
  [ "$SELINUX" = "1" ] && disable_selinux
  sulogin

 

  echo $"Unmounting file systems"
  umount -a
  mount -n -o remount,ro /
  echo $"Automatic reboot in progress."
  reboot -f


 fi        # 注释 ;这个 fi 是结束"if [ -f /etc/raidtab ];" 的,如果不存在 /etc/raidtab,则直接跳到这里

########################################################################################################################################################
 # LVM2 initialization, take 2                                                        #由于 LVMpv可能是建立在 RAID之上的,所以再次尝试扫描 vg并激活它们
 if [ -c /dev/mapper/control -a -x /sbin/lvm.static ]; then            # 步骤和前面的一样
  if /sbin/lvm.static vgscan > /dev/null 2>&1 ; then
   action $"Setting up Logical Volume Management:" /sbin/lvm.static vgscan --mknodes --ignorelockingfailure && /sbin/lvm.static vgchange -a y --ignorelockingfailure
  fi
 fi
 # LVM initialization, take 2 (it could be on top of RAID)
 if [ -e /proc/lvm -a -x /sbin/vgchange -a -f /etc/lvmtab ]; then
  action $"Setting up Logical Volume Management:" /sbin/vgscan && /sbin/vgchange -a y
 fi
    fi
fi

######################################################################################################################################################## 

# 注释 :下面对其他文件系统(/除外)的文件系统进行 fsck

_RUN_QUOTACHECK=0        #还是把 _RUN_QUOTACHECK变量的值设置为0
# Check filesystems            #检查其他文件系统
if [ -z "$fastboot" ]; then        #如果不存在 /etc/fastboot,则执行下面的脚本。可以看到 shutdown -r不仅影响 /fsck,也影响其他文件系统的 fsck
        STRING=$"Checking filesystems"        #打印提示信息
        echo $STRING
         if [ "${RHGB_STARTED}" != "0" -a -w /etc/rhgb/temp/rhgb-console ]; then
                  fsck -T -R -A -a $fsckoptions > /etc/rhgb/temp/rhgb-console                # -R表示跳过 /文件系统,其他选项和之前的一样
         else
                  initlog -c "fsck -T -R -A -a $fsckoptions"
         fi
         rc=$?
         if [ "$rc" -eq "0" ]; then                                    # 这部分和之前处理/文件系统的fsck 结果一样
           success "$STRING"
           echo
        elif [ "$rc" -eq "1" ]; then
           passed "$STRING"
           echo
        elif [ "$rc" -eq "2" -o "$rc" -eq "3" ]; then 
           echo $"Unmounting file systems"
           umount -a
           mount -n -o remount,ro /
           echo $"Automatic reboot in progress."
           reboot -f
        fi

 

         # A return of 4 or higher means there were serious problems.
         if [ $rc -gt 1 ]; then
             if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
                  chvt 1
             fi

 

             failure "$STRING"
             echo
             echo
             echo $"*** An error occurred during the file system check."
             echo $"*** Dropping you to a shell; the system will reboot"
             echo $"*** when you leave the shell."

 

             str=$"(Repair filesystem)"
             PS1="$str \# # "; export PS1
             [ "$SELINUX" = "1" ] && disable_selinux
             sulogin

 

             echo $"Unmounting file systems"
             umount -a
             mount -n -o remount,ro /
             echo $"Automatic reboot in progress."
             reboot -f
         elif [ "$rc" -eq "1" -a -x /sbin/quotacheck ]; then
             _RUN_QUOTACHECK=1                                        #如果   fsck修复成功,则 _RUN_QUOTACHECK的值修改为1,表示可以进行其他文件系统的quotacheck
         fi        这个 fi是结束  "if [ $rc -gt 1 ]; "
fi                #这个 fi是结束 ”if [ -z "$fastboot" ];“

 

######################################################################################################################################################## 

# Mount all other filesystems (except for NFS and /proc, which is already            #挂载除了 //proc/proc/bus/usbdevpts之外的文件系统
# mounted). Contrary to standard usage,
# filesystems are NOT unmounted in single user mode.
action $"Mounting local filesystems: " mount -a -t nonfs,nfs4,smbfs,ncpfs,cifs,gfs -O no_netdev    #挂载类型为 nonfsnfs4smbfsncptfscifsgfs的文件系统

                                                                                      #但条件是这些文件系统对应在 /etc/fstab中的属性字段没有 netdev属性

########################################################################################################################################################  

# Start the graphical boot, if necessary and not done yet.                #现在又再次检查是否可以启动图形启动界面
if strstr "$cmdline" rhgb && [ "$RHGB_STARTED" -eq 0 -a "$BOOTUP" = "color" -a "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb ]; then
   LC_MESSAGES= /usr/bin/rhgb
   RHGB_STARTED=1
fi

######################################################################################################################################################## 

# check remaining quotas other than root                                                            #/系统之外的文件系统进行 quota检查
if [ X"$_RUN_QUOTACHECK" = X1 -a -x /sbin/quotacheck ]; then                            #方法和之前对 /进行 quotachec一样
     if [ -x /sbin/convertquota ]; then
         # try to convert old quotas
         for mountpt in `awk '$4 ~ /quota/{print $2}' /etc/mtab` ; do
              if [ -f "$mountpt/quota.user" ]; then
                  action $"Converting old user quota files: " \
                  /sbin/convertquota -u $mountpt && \
                   rm -f $mountpt/quota.user
              fi
              if [ -f "$mountpt/quota.group" ]; then
                  action $"Converting old group quota files: " \
                  /sbin/convertquota -g $mountpt && \
                   rm -f $mountpt/quota.group
              fi
     done
 fi


 action $"Checking local filesystem quotas: " /sbin/quotacheck -aRnug                # quotachk -augRn表示对 /etc/fstab中除了 /之外,所有启用了 usrquotagrpquota 
fi                                                                                                                 #的文件系统都检查    

 

if [ -x /sbin/quotaon ]; then
    action $"Enabling local filesystem quotas: " /sbin/quotaon -aug                       #执行 quotaon启动 quota功能
fi

######################################################################################################################################################## 

#
# Check to see if SELinux requires a relabel
#
[ -n "$SELINUX" ] && [ -f /.autorelabel ] && relabel_selinux

######################################################################################################################################################## 

# Initialize pseudo-random number generator                                                    #初始化随机数生成器
if [ -f "/var/lib/random-seed" ]; then                                                                # 如果存在/var/lib/random-seed 文件,则
 cat /var/lib/random-seed > /dev/urandom                                                            #把它的内容送给 /dev/urandom
else                                                                                                                #否则
 touch /var/lib/random-seed                                                                                #创建该文件
fi
chmod 600 /var/lib/random-seed                                                                    # 修改该文件的权限为 600 rw-------
dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null           #/dev/urandom读入 512 kB并送给 /var/lib/random-seed 

 

# Use the hardware RNG to seed the entropy pool, if available
[ -x /sbin/rngd -a -f /dev/hw_random ] && rngd                                                #如果 /sbin/rngd可执行且存在 /dev/hw_random文件,则执行 rngd为加密池生成种子

 

 

######################################################################################################################################################## 

# Configure machine if necessary.                                                                #这部分允许你在启动时作一些配置(手工的)
if [ -f /.unconfigured ]; then                                                                        #如果存在 /.unconfigured文件
    if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then                    #rhgb-client可执行,rhgb服务在运行,则
         chvt 1                                                                                                                    #切换回 1#控制台
    fi

 

    if [ -x /usr/bin/system-config-keyboard ]; then                                               #如果 /usr/bin/sysconfig-keyboard可执行
         /usr/bin/system-config-keyboard                                                                    #则执行该命令
    fi
    if [ -x /usr/bin/passwd ]; then                                                                        #如果存在 /usr/bin/passwd,则
        /usr/bin/passwd root                                                                                        #执行 passwd root,修改 root密码
    fi
    if [ -x /usr/sbin/netconfig ]; then                                                                    #如果存在 /usr/sbin/netconfig,则
         /usr/sbin/netconfig                                                                                            执行 /usr/sbin/netconfig,重新配置网络
    fi
    if [ -x /usr/sbin/timeconfig ]; then                                                                    #如果存在 /usr/sbin/timeconfig,则
         /usr/sbin/timeconfig                                                                                            #执行 /usr/sbin/timeconfig重新配置时间和时区
    fi
    if [ -x /usr/sbin/authconfig ]; then                                                                    #如果存在 /usr/sbin/authconfig,则
         /usr/sbin/authconfig --nostart                                                                                #执行 /usr/sbin/authconfig --nostart重新配置 shadowLDAPkerberos
    fi
    if [ -x /usr/sbin/ntsysv ]; then                                                                            #如果存在 /usr/sbin/ntsysv,则
         /usr/sbin/ntsysv --level 35                                                                                    #执行 /usr/sbin/ntsysv --level 35对运行级别35下的服务启动进行配置
    fi

 

    # Reread in network configuration data.                                                              #重新读取 /etc/sysconfig/network文件
    if [ -f /etc/sysconfig/network ]; then                                                                  如果存在该文件就执行它         
         . /etc/sysconfig/network

 

         # Reset the hostname.
         action $"Resetting hostname ${HOSTNAME}: " hostname ${HOSTNAME}        #重新设置主机名,因为上面的 /etc/sysconfig/network被重新执行了
    fi

 

    rm -f /.unconfigured                                                                         # 删除 /.unconfigured

 

    if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then        切换回8# 控制台
         chvt 8
    fi
fi

 

# Clean out /.                                                                                        #下面把 /下的一些文件删除,包括 /fastboot/fsckoptions/forcefsck/.autofsck
rm -f /fastboot /fsckoptions /forcefsck /.autofsck /halt /poweroff &> /dev/null        # /halt/poweroff ,这样下次重启就会再次检测是否需要fsck

 

# Do we need (w|u)tmpx files? We don't set them up, but the sysadmin might...        # 正常情况下是需要/var/run/utmpx /var/log/wtmpx 文件
_NEED_XFILES=                                                                                                        #  _NEED_XFILES的值为空
[ -f /var/run/utmpx -o -f /var/log/wtmpx ] && _NEED_XFILES=1                                 # 如果存在其中之1个文件,就把_NEED_XFILES 的值设置为1

######################################################################################################################################################## 

# Clean up /var.  I'd use find, but /usr may not be mounted.            #现在清理 /var目录。
for afile in /var/lock/* /var/run/* ; do                                         # 对于在 /var/lock//var/run下的每个文件,执行下面的操作
 if [ -d "$afile" ]; then                                                                        #如果 $afile是一个目录,则
    case "$afile" in                                                                                    根据$afile 的值进行选择
  */news|*/mon) ;;                                                                                    #如果该目录的路径名是以 '/news'或者 '/mon'结尾则跳过它们不处理
  */sudo)  rm -f $afile/*/* ;;                                                                        #如果是以 '/sudo' 结尾,则用rm -rf 把该目录下面的所有子目录下的全部东西删除
  */vmware) rm -rf $afile/*/* ;;                                                                   #如果是以 '/vmware'结尾,则用 rm -fr把它下面的所有子目录下的内容全部删除
  */samba) rm -rf $afile/*/* ;;                                                                     # 如果是以 '/samba'结尾,也是同样操作
  *)  rm -f $afile/* ;;                                                                                  # 如果不是上面4种类型,则把该目录下的所有内容都删除,不仅包括子目录,也包括文件
    esac
 else                                                                                                # 如果 $afile是一个文件,不是目录,则
    rm -f $afile                                                                                            #删除该文件
 fi
done
rm -f /var/lib/rpm/__db* &> /dev/null                                            #删除 /var/lib/rpm/_db*

 

# 补充 :可以看到不要在 /var/run/var/lock下面放置有用的文件,否则启动时会被删除。

 

# 正常情况下 /var/run有如下内容 :

 

[root@mail run]# ls
acpid.socket=           dbus/           iptraf/         mysqld/     ptal-mlcd/    rpc.statd.pid  syslogd.pid
atd.pid                 dovecot/        klogd.pid       named/      ptal-printd/  saslauthd/     usb/
console/                dovecot-login/  mailman/        netreport/  pvm3/         sendmail.pid   utmp
crond.pid               gpm.pid         mdadm/          news/       quagga/       sm-client.pid  winbindd/
cups-config-daemon.pid  haldaemon.pid   mdmpd/          nscd/       radiusd/      sshd.pid       xfs.pid
cupsd.pid               iiim/           messagebus.pid  ppp/        radvd/        sudo/          xinetd.pid
[root@mail run]#

 

######################################################################################################################################################## 

# Reset pam_console permissions                                                                    #这里重置 pam_console的权限
[ -x /sbin/pam_console_apply ] && /sbin/pam_console_apply -r                        #如果 /sbin/pam_console_apply存在且可以执行,则执行 /sbin/pam_console_apply -r

                                                                                                                  # -r是表示 reset的意思,具体见 man pam_console_apply

########################################################################################################################################################

# 注意下面这段话,一直到后面的 "kill -TERM `/sbin/pidof getkey` >/dev/null 2>&1"才算结束,这一段放在 {}中的代码在 bash中被成为 command block

 

# 它可以把放在 {}中的多个命令当成1个命令来执行,这样可以对多个命令一次使用IO 重定向。

 

# 实际上,这部分是被放在后台运行的 ,因为它是以  {xxxxx}&的形式出现的

 

# 我们可以也可以用函数的形式来把下面的代码做成一个函数,不过command blocks 是一种简便的方式

 

{                                                                                                        # command block开始
# Clean up utmp/wtmp                                                                        #首先清空 utmpwtmp文件的内容
> /var/run/utmp                                                                                  #首先清空 /var/run/utmp文件
touch /var/log/wtmp                                                                          # 再用 touch创建 /var/log/wtmp文件
chgrp utmp /var/run/utmp /var/log/wtmp                                             #把这两个文件的组都改为 utmp
chmod 0664 /var/run/utmp /var/log/wtmp                                            #把这两个文件的权限改为 0664rw-rw-r--
if [ -n "$_NEED_XFILES" ]; then                                                               如果 _NEED_XFILES的值不为空
  > /var/run/utmpx                                                                                    #则清空  /var/log/umptx
  touch /var/log/wtmpx                                                                            # 创建 /var/log/wtmpx
  chgrp utmp /var/run/utmpx /var/log/wtmpx                                              #同样是修改 grouppermission
  chmod 0664 /var/run/utmpx /var/log/wtmpx
fi

 

 

 

# Clean up various /tmp bits                                                                        #解析来是清理 /tmp目录了
rm -f /tmp/.X*-lock /tmp/.lock.* /tmp/.gdm_socket /tmp/.s.PGSQL.*            #删除 /tmp下的一些隐藏文件
rm -rf /tmp/.X*-unix /tmp/.ICE-unix /tmp/.font-unix /tmp/hsperfdata_* \
       /tmp/kde-* /tmp/ksocket-* /tmp/mc-* /tmp/mcop-* /tmp/orbit-*  \
       /tmp/scrollkeeper-*  /tmp/ssh-*

# Make ICE directory                                                                                     #下面创建 ICE目录
mkdir -m 1777 -p /tmp/.ICE-unix >/dev/null 2>&1                                            #创建 /tmp/.ICE-unix/目录,权限为 1777sticky
chown root:root /tmp/.ICE-unix                                                                     #改为属于 root用户、root 组
[ -n "$SELINUX" ] && restorecon /tmp/.ICE-unix >/dev/null 2>&1        

               

 

# Start up swapping.                                               #下面是启动 swap空间
update_boot_stage RCswap                                    执行 rhgb-client --update RCswap
action $"Enabling swap space: " swapon -a -e            #启用所有 swap分区,并跳过那些不存在的 swap设备

# Set up binfmt_misc                                                                                    #设置 binfmt_misc
/bin/mount -t binfmt_misc none /proc/sys/fs/binfmt_misc > /dev/null 2>&1    # 挂载 binfmt_misc文件系统

 

# Initialize the serial ports.                                    #初始化串口
if [ -f /etc/rc.serial ]; then                                    #如果存在 /etc/rc.serial则执行该文件
 . /etc/rc.serial
fi

 

# If they asked for ide-scsi, load it
if strstr "$cmdline" ide-scsi ; then
 modprobe ide-cd >/dev/null 2>&1
 modprobe ide-scsi >/dev/null 2>&1
fi

 

# Turn on harddisk optimization                                                                                        #下面部分是用 hdparm命令对硬盘进行优化
# There is only one file /etc/sysconfig/harddisks for all disks                                                #默认是使用统一的优化参数文件 /etc/sysconfig/harddisks
# after installing the hdparm-RPM. If you need different hdparm parameters                         # 如果你想对针对不同的硬盘进行优化,把该文件拷贝并重新命名为
# for each of your disks, copy /etc/sysconfig/harddisks to                                                    # /etc/sysconfig/harddisk<hda~hdt>,并修改该文件
# /etc/sysconfig/harddiskhda (hdb, hdc...) and modify it.
# Each disk which has no special parameters will use the defaults.                                        #如果某个选项没有指定,则默认使用默认值
# Each non-disk which has no special parameters will be ignored.                                         

                                                                                                                                         #下面定义一个数组,名为 disk,共有21个元素
disk[0]=s;
disk[1]=hda;  disk[2]=hdb;  disk[3]=hdc;  disk[4]=hdd;
disk[5]=hde;  disk[6]=hdf;  disk[7]=hdg;  disk[8]=hdh;
disk[9]=hdi;  disk[10]=hdj; disk[11]=hdk; disk[12]=hdl;
disk[13]=hdm; disk[14]=hdn; disk[15]=hdo; disk[16]=hdp;
disk[17]=hdq; disk[18]=hdr; disk[19]=hds; disk[20]=hdt;
 
 
if [ -x /sbin/hdparm ]; then                                                                                     #如果存在 /sbin/hdparm且可执行,则
   for device in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do                            0-20 循环,每次把一个数字赋予device 变量
        unset MULTIPLE_IO USE_DMA EIDE_32BIT LOOKAHEAD EXTRA_PARAMS                         #首先把 MULTIPLE_IOUSE_DMAEIDE_32BITLOOKAHEAD

                                                                                                                                   # EXTRA_PARAMS 的值清空
        if [ -f /etc/sysconfig/harddisk${disk[$device]} ]; then                                              #如果存在 /etc/sysconfig/harddisk<hda~hdt>文件,则      
                . /etc/sysconfig/harddisk${disk[$device]}                                                                #执行该文件
                HDFLAGS[$device]=                                                                                                #HDFLAGS数组对应 $device的元素的值清空
                if [ -n "$MULTIPLE_IO" ]; then                                                                                  #如果 MULTIPLE_IO的值不为空,则
                    HDFLAGS[$device]="-q -m$MULTIPLE_IO"                                                                    # HDFLAGS数组对应该 deivce值的元素的值为 -q -m$MULTIPE_IO 
                fi
                if [ -n "$USE_DMA" ]; then                                                                                        如果USE_DMA 的值不为空,则
                    HDFLAGS[$device]="${HDFLAGS[$device]} -q -d$USE_DMA"                                        # HDFLAGS对应该 deivce值的元素的值再加上  -q -d$USE_DMA
                fi
                if [ -n "$EIDE_32BIT" ]; then                                                                                      #如果 EIDE_32BIT变量的值不为空,则
                    HDFLAGS[$device]="${HDFLAGS[$device]} -q -c$EIDE_32BIT"                                        # HDFLAGS 对应device 值的元素的值再加上-q -c$EIDE_32BIT
                fi    
                if [ -n "$LOOKAHEAD" ]; then                                                                                    #如果 LOOKAHEAD变量的值不为空,则
                    HDFLAGS[$device]="${HDFLAGS[$device]} -q -A$LOOKAHEAD"                                        # HDFLGAS对应 device值的元素的值加上 -q -A$LOOKAHEAD
                fi
                if [ -n "$EXTRA_PARAMS" ]; then                                                                                #如果 EXTRA_PARAMS 变量的值不为空,则
                    HDFLAGS[$device]="${HDFLAGS[$device]} $EXTRA_PARAMS"                                           # HDFLAGS对应 device值的元素的值加上 -q $EXTRA_PARAMS
                fi
        else                                                                                                                        如果不存在/etc/sysconfig/harddisk<hda~hdt>文件,则
                HDFLAGS[$device]="${HDFLAGS[0]}"                                                                            #统一使用 HDFLAGS[0]的值作为每个硬盘的优化参数值
        fi
        if [ -e "/proc/ide/${disk[$device]}/media" ]; then                                                      #如果存在 /proc/ide/<hda~hdt>/media文件,则
             hdmedia=`cat /proc/ide/${disk[$device]}/media`                                                    #则找出它的 media类型并赋予变俩功能 hdmedia
             if [ "$hdmedia" = "disk" -o -f "/etc/sysconfig/harddisk${disk[$device]}" ]; then        #如果 hdmedia的值是 "disk"或者存在 /etc/sysconfig/harddisk<hda-hdt>文件 
                  if [ -n "${HDFLAGS[$device]}" ]; then                                                                    #且对应硬盘的参数值不为空,则
                      action $"Setting hard drive parameters for ${disk[$device]}: "  /sbin/hdparm ${HDFLAGS[$device]} /dev/${disk[$device]}    #调用 action函数,
                  fi                                                                                                                                                                                    #执行 /sbin/hdparm命令,
             fi                                                                                                                                                                                        根据给定优化参数值进行优化
        fi
   done
fi            #注释 :这个 fi是结束 "if [ -x /sbin/hdparm ];"

 

# Boot time profiles. Yes, this should be somewhere else.                        
if [ -x /usr/sbin/system-config-network-cmd ]; then
  if strstr "$cmdline" netprofile= ; then
    for arg in $cmdline ; do
        if [ "${arg##netprofile=}" != "${arg}" ]; then
     /usr/sbin/system-config-network-cmd --profile ${arg##netprofile=}
        fi
    done
  fi
fi

 

# Now that we have all of our basic modules loaded and the kernel going,        #现在所有基础的模块都已经被加载,内核已经开始运行了。可以把这些信息导出了
# let's dump the syslog ring somewhere so we can find it later                        #这样在启动后可以重新查阅.

 

# 补充 :在第 125行,我们执行了 dmesg -n  $LOGLEVEL命令,把信息都写入 syslog了。

 

# 现在把它们从 syslog中导出来到文件中                                                                               


dmesg -s 131072 > /var/log/dmesg       #执行 dmesg -s 131072 > /var/log/dmesg文件,导出的内容是 131072字节。

                                                        #默认是 16392字节                                                                  

        

# create the crash indicator flag to warn on crashes, offer fsck with timeout        #在这里创建 /.autofsck ,如果系统在这里崩溃了,下次重启就会出现fsck 提示
touch /.autofsck &> /dev/null                    #touch命令创建 /.autofsck 。不过可以看到前面的第785 -786行 把/.autofsck 连同其他/fastboot 等都删除了

 

kill -TERM `/sbin/pidof getkey` >/dev/null 2>&1        #在这里才把 getkey命令杀死
} &                                                                        # command block结束

 

############################################################################################################################################################


if strstr "$cmdline" confirm ; then                                                #如果内核启动参数含有 "comfirm",则
 touch /var/run/confirm                                                                # 创建 /var/run/confirm文件
fi    
if [ "$PROMPT" != "no" ]; then                                                      如果PROMPT 变量的值不为no ,则
 /sbin/getkey i && touch /var/run/confirm                                    #调用 getkey等待用户输入 i,如果按下 i则创建 /var/run/confirm
fi
wait                                                                                            #一旦用户按下任意键,则跳过该行,继续执行下面的代码

 

if [ -x /sbin/redhat-support-check -a -f /var/lib/supportinfo ]; then        如果存在 /sbin/redhat-support-check且可执行,且存在 /var/lib/supportinfo 文件,则
 /sbin/redhat-support-check || {                                                                #执行该命令,如果不成功则输出”Normal startup will continue in 10 seconds“
   echo $"Normal startup will continue in 10 seconds."                                    #然后睡眠10秒钟
   sleep 10
}
fi

 

######################################################################################################################################################## 

# Let rhgb know that we're leaving rc.sysinit                                            #到这里 rc.sysinit就结束了。
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then            # 执行 rhgb-client --sysinit,告诉 rhgb服务器已经完成 rc.sysinit
    /usr/bin/rhgb-client --sysinit
fi

 

 

######################################################################################################################################################## 

 

 

Linux系统启动脚本分析之rc

#! /bin/bash
#
# rc            This file is responsible for starting/stopping                            #该脚本主要是用于在切换运行级别时启动/停止服务
#               services when the runlevel changes.
#
# Original Author:      
#               Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
#

 

# 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赋予 $13赋予 $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/functionsconfirm函数来处理该服务
  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                 #如果该服务 $sbusyshalt或者 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 \    #如果不是上面两个服务之一,且该服务脚本中有 daemonactionsuccessfailure等字符串,则
   || [ "$subsys" = "single" -o "$subsys" = "local" ]; then                      #或者服务为 single或者 local服务,则
  $i start                                                                                        #直接执行 <prog> start,这次不用 exec方式了
 else                                                                                           #如果都不是上面的 haltrebootsinglelocal服务,则
  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启动脚本分析之functions

# -*-Shell-script-*-
#
# functions This file contains functions to be used by most or all            #注释 :该脚本几乎被 /etc/init.d/下的所有脚本所调用,因为它包含了大量的
#  shell scripts in the /etc/init.d directory.                                          # 的基础函数。同时也被 /etc/rc.d/rc.sysinit ,例如successactionfailure等函数
#

 

TEXTDOMAIN=initscripts                #设置 TEXTDOMAIN变量

 

 

##########################################################################################################################################################

# Make sure umask is sane            #确保 root用户的 umask是正确的 022(也就是 rwxr-xr-x
umask 022

 

# Set up a default search path.                                        #设置默认的 PATH变量
PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"         #默认为 /sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin
export PATH                                                                  #导出为环境变量

 

# Get a sane screen width                                                #设置正确的屏幕宽度
[ -z "${COLUMNS:-}" ] && COLUMNS=80                                #如果 COLUMNS变量的值为空,则设置为 80(列)

 

[ -z "${CONSOLETYPE:-}" ] && CONSOLETYPE="`/sbin/consoletype`"            #如果 CONSOLETYPE为空则设置 CONSOLETYPE/sbin/consoletype命令返回的值

                                                                                                             #一般是 vt或者 ptyserial

##########################################################################################################################################################

if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then                            #如果存在 /etc/sysconfig/i18n NOLOCALE 变量的值为空,则
      . /etc/sysconfig/i18n                                                                                        #执行 /etc/sysconfig/i18n文件,取得 LANG变量的值
      if [ "$CONSOLETYPE" != "pty" ]; then                                                                    #如果当前 console类型不是 pty(远程登录),而是vt 或者serial ,则
          case "${LANG:-}" in                                                                                                    #根据 LANG的值作出选择
              ja_JP*|ko_KR*|zh_CN*|zh_TW*|bn_*|bd_*|pa_*|hi_*|ta_*|gu_*)                                        #如果 LANG 日文、中文简体、中文繁体、韩文等,则
                   export LC_MESSAGES=en_US                                                                                                LC_MESSAGES 设置为en_US
                   export LANG                                                                                                                       #同时导出为环境变量
                   ;;
              *)
                   export LANG                                                                                                                #如果是其他类型的语言,则直接导出 LANG
               ;    ;
         esac
      else                                                                                                                    #如果当前 conslepty                                                    
       [ -n "$LC_MESSAGES" ] && export LC_MESSAGES                                                        #且如果 LC_MESSAGES不为空,则直接导出 LC_MESSAGES 
       export LANG
  fi
fi

##########################################################################################################################################################

 

# 下面是设置 successfailurepassedwarning 4种情况下的字体颜色的

 

# Read in our configuration
if [ -z "${BOOTUP:-}" ]; then                                                #首先如果 BOOTUP 变量为空,则
  if [ -f /etc/sysconfig/init ]; then                                            #如果存在 /etc/sysconfig/init文件,执行 /etc/sysconfig/init文件
      . /etc/sysconfig/init
  else                                                                                    #否则我们就手工设置
    # This all seem confusing? Look in /etc/sysconfig/init,
    # or in /usr/doc/initscripts-*/sysconfig.txt
    BOOTUP=color                                                                        # 第一设置BOOTUP 变量,默认就是color
    RES_COL=60                                                                          # 第二设置设置在屏幕的第几列输出后面的"[ xxx ]" ,默认是第60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"                          # MOVE_TO_COL 是用于打印"OK" 或者"FAILED" ,或者"PASSED" ,或者 "WARNING" 之前的部分,不含"["
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"                             # SETCOLOR_SUCCESS 设置后面的字体都为绿色
    SETCOLOR_FAILURE="echo -en \\033[1;31m"                             # SETCOLOR_FAILURE 设置后面将要输出的字体都为红色
    SETCOLOR_WARNING="echo -en \\033[1;33m"                           # SETCOLOR_WARNING 设置后面将要输出的字体都为黄色
    SETCOLOR_NORMAL="echo -en \\033[0;39m"                              # SETCOLOR_NORMAL设置后面输出的字体都为白色(默认)
    LOGLEVEL=1
  fi

  if [ "$CONSOLETYPE" = "serial" ]; then                                        #如果是通过串口登录的,则全部取消彩色输出
      BOOTUP=serial
      MOVE_TO_COL=
      SETCOLOR_SUCCESS=
      SETCOLOR_FAILURE=
      SETCOLOR_WARNING=
      SETCOLOR_NORMAL=
  fi
fi

 

##########################################################################################################################################################

if [ "${BOOTUP:-}" != "verbose" ]; then                    #如果 BOOTUP变量的值不为 verbose,则
   INITLOG_ARGS="-q"                                                    #INITLOG_ARGS的值设置为 -q(安静模式)
else                                                                    # 否则
   INITLOG_ARGS=                                                        # INITLOG_ARGS的值请空 
fi

##########################################################################################################################################################

# Check if $pid (could be plural) are running            #下面定义一个函数 checkpid(),目的是检查 /proc下是否存在指定的目录(例如 /proc/1/
checkpid() {                                                        # 如果有任意一个存在,则返回0
 local i

 

 for i in $* ; do
  [ -d "/proc/$i" ] && return 0
 done
 return 1                                                            # 如果给出的参数全部不存在对应的目录,则返回1
}
 

##########################################################################################################################################################

# A function to start a program.                            #下面定义最重要的一个函数,daemon函数,它的作用是启动某项服务。/etc/init.d/下的脚本的 start部分都会用到它
daemon() {
 # Test syntax.
 local gotbase= force=
 local base= user= nice= bg= pid=
 nicelevel=0
 while [ "$1" != "${1##[-+]}" ]; do                                        # daemon函数本身可以指定多个选项,例如 --check <value>--check=<value>
   case $1 in
     '')    echo $"$0: Usage: daemon [+/-nicelevel] {program}"    #也可以指定 nice
            return 1;;
     --check)
     base=$2
     gotbase="yes"
     shift 2
     ;;
     --check=?*)
         base=${1#--check=}
     gotbase="yes"
     shift
     ;;
     --user)                                                                        #也可以指定要以什么用户身份运行(--user <usr> , --user=<usr>)
     user=$2
     shift 2
     ;;
     --user=?*)
            user=${1#--user=}
     shift
     ;;
     --force)
         force="force"                                                            # --force表示强制运行
     shift
     ;;
     [-+][0-9]*)
         nice="nice -n $1"                                                        #如果 daemon的第一个参数是数字,则认为是 nice
            shift
     ;;
     *)     echo $"$0: Usage: daemon [+/-nicelevel] {program}"
            return 1;;
   esac
 done

 

        # Save basename.                                                        # basename就是从服务器的二进制程序的 full path中取出最后的部分
        [ -z "$gotbase" ] && base=${1##*/}                                        

 

        # See if it's already running. Look *only* at the pid file.    #检查该服务是否已经在运行。不过 daemon函数只查看 pid文件而已
 if [ -f /var/run/${base}.pid ]; then                                         #如果 /var/run下存在该服务的 pid文件,则
  local line p
  read line < /var/run/${base}.pid                                               #从该 pid文件每次读取一行,送给变量 line。注意 pid文件可能有多行,且不一定都是数字
  for p in $line ; do                                                                    # 对于line 变量的每个word 进行检查
   [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"                     #如果 p全部是数字,且存在 /proc/$p/目录,则认为该数字是一个 pid,把它加入到 pid变量
  done                                                                                       #到最后 pid变量的值可能是有多个由空格分隔的数字组成
 fi
 
 [ -n "${pid:-}" -a -z "${force:-}" ] && return                                  #如果 pid变量最终为空,则 force变量为空(不强制启动),则返回

 

 # make sure it doesn't core dump anywhere unless requested        #下面对该服务使用的资源作一些设置
 ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0} >/dev/null 2>&1          # ulimit是控制由该 shell启动的进程能够使用的资源,-Ssoft control的意思,-c是指最大的 core   

                                                                                                # dump文件大小,如果 DEAMON_COREFILE_LIMIT 为空,则默认为0
 
 # if they set NICELEVEL in /etc/sysconfig/foo, honor it                #如果存在 /etc/sysconfi/foo文件,且其中有 NICELEVEL变量则用它代替  daemon 后面的那个nice
 [ -n "$NICELEVEL" ] && nice="nice -n $NICELEVEL"                        #注意,这里的 nice赋值是用 nice -n <value>的格式,因为 nice 本身可以启动命令,用这个格式较方便
 
 # Echo daemon                                                                         #如果 BOOTUP的值为 verbose,则打印一个服务名
        [ "${BOOTUP:-}" = "verbose" -a -z "$LSB" ] && echo -n " $base"

 

 # And start it up.                                                                                        #下面是开始启动它了
 if [ -z "$user" ]; then                                                                                  #如果 user变量为空,则默认使用 root启动它
    $nice initlog $INITLOG_ARGS -c "$*"                                                                #执行 nice -n <nice_value> initlog -q -c "$*" 
 else                                                                                                         #如果指定了用户,则
    $nice initlog $INITLOG_ARGS -c "runuser -s /bin/bash - $user -c \"$*\""                #执行 nice -n <nice_value> initlog -q -c "runuser -s /bin/bash - <user> -c "$*"
 fi
 [ "$?" -eq 0 ] && success $"$base startup" || failure $"$base startup"                #如果上面的命令成功,则显示一个绿色的 [ OK ],否则显示 [ FAILURE ]
}

 

##########################################################################################################################################################

 

# A function to stop a program.                                #下面定义另外一个很重要的函数 killproc/etc/init.d/下面的脚本的 stop部分都会用到它
killproc() {
 RC=0                                                                    # RC是最终返回的值,初始化为 0
 # Test syntax.
 if [ "$#" -eq 0 ]; then                                            # killproc函数的语法格式是 killproc <service> [<signal>],例如 killproc sm-client 9
  echo $"Usage: killproc {program} [signal]"              
  return 1
 fi

 

 notset=0                                                             # noset是用于检查用户是否指定了 kill要使用的信号
 # check for second arg to be kill level                  
 if [ -n "$2" ]; then                                                #如果 $2不为空,则表示用户有设定信号,则
  killlevel=$2                                                            #$2 的值赋予killlevel 变量
 else                                                                    #否则
  notset=1                                                                # notset变量的值为1,同时killlevel '-9' KILL信号)
  killlevel="-9"
 fi

 

# 补充 :注意,并不是说用户没有指定信号地停止某项服务时,就会立即用kill -9 这样的方式强制杀死,而是先用TERM 信号,然后再用KILL

 

        # Save basename.
        base=${1##*/}                                                # basename就是得出服务的名称

 

        # Find pid.
 pid=                                                                    pid 变量的值清空。注意,不是指pid 变量的值等于下面脚本的执行结果,要看清楚
 if [ -f /var/run/${base}.pid ]; then                        # 下面和上面的 daemon函数一样找出 pid 
    local line p
    read line < /var/run/${base}.pid
    for p in $line ; do
       [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"
    done
 fi
 if [ -z "$pid" ]; then                                                #不过和 daemon不同的是,一旦 pid 为空不会直接return 而是尝试用pid 命令再次查找
  pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || \            # -o是用于忽略某个 pid-o $$是忽略当前 shellpid-o $PPID是忽略 shellpid
   pidof -o $$ -o $PPID -o %PPID -x $base`                   # -o %PPID是忽略 pidof命令的父进程,要查询的进程是 $1 (fullpath)或者 $base 
 fi

 

 # Kill it.                                                            
  if [ -n "${pid:-}" ] ; then                                        #如果 pid的值最终不为空,则
    [ "$BOOTUP" = "verbose" -a -z "$LSB" ] && echo -n "$base "    #BOOTUP的值为 verbose,且 LSB变量不为空,则打印一个服务名

    if [ "$notset" -eq "1" ] ; then                                        #如果 notset变量不为1,表示用户没有指定信号,则
         if checkpid $pid 2>&1; then                                        调用checkpid  $pid 检查是否在/proc/ 下存在进程目录,如果有
              # TERM first, then KILL if not dead                            #先尝试用 TERM信息,不行再用 KILL信号
              kill -TERM $pid >/dev/null 2>&1                                #执行 kill -TERM $pid
              usleep 100000                                                          # usleepsleep一样,不过单位是百万分之1秒。这里休眠1
              if checkpid $pid && sleep 1 &&                                #如果 checkpid $pid 还是查到有/proc/<pid>/ 目录存在,则表示还没有杀死,继续等待1
                 checkpid $pid && sleep 3 &&                                #如果1秒后用checkpid 检查还是有,则再等待3秒;
                 checkpid $pid ; then                                            #如果还是没有杀死,则用 KILL信号
                        kill -KILL $pid >/dev/null 2>&1                            执行kill -KILL 杀死它
                        usleep 100000                                                    #等待1秒种
              fi
    fi
    checkpid $pid                                                             # 再次检查pid 目录       
    RC=$?                                                                         #并把结果返回给 RC,这就算是 killproc的最后状态了
    [ "$RC" -eq 0 ] && failure $"$base shutdown" || success $"$base shutdown"    #如果 RC的值为0,则表示kill -9没有杀死了进程,则调用 failure函数,否则调用 success 
    RC=$((! $RC))
  

    # use specified level only                                            #上面都是在没有指定信号的情况的,下面是用户指定了信号的。例如 restart)或者reload)部
    else    #这个 else是针对 if [ "$notset" -eq "1" ] 
       if checkpid $pid; then                                             #如果检查到进程存在,则
            kill $killlevel $pid >/dev/null 2>&1                            #执行kill命令,但使用指定的信号$killlevel
            RC=$?                                                                    # 并把状态值返回给变量 RC
            [ "$RC" -eq 0 ] && success $"$base $killlevel" || failure $"$base $killlevel"    #如果 RC0则表示成功,调用success;否则调用failure 函数
       fi
  fi
 else      # 这个 else 是针对if [ -n "${pid:-}" ]  的,也就是说没有 pid文件,pidof命令也没有找到 pid,则
     failure $"$base shutdown"                #调用 failure函数,表示停止服务失败
     RC=1                                             #同时 RC的值为1
 fi

 

 # Remove pid file if any.                    #根据具体情况可能需要删除 pid文件
 if [ "$notset" = "1" ]; then                    #如果 notset不为1,也就是用户没有指定信号的情况
            rm -f /var/run/$base.pid            #自动删除 /var/run下的 pid文件
 fi
 return $RC                                        #并把 RC作为 exit status返回
}

 

# 补充 :自所以删除 pid文件只针对 notset1的情况,是因为 -HUP信号(重读配置),并不杀死进程,所以不能删除它的 pid文件

 

# 例如下面 :

 

[root@mail init.d]# ps -ef |grep xinetd
root      2635     1  0 12:25 ?        00:00:00 xinetd -stayalive -pidfile /var/run/xinetd.pid
[root@mail init.d]# ./xinetd reload
Reloading configuration:                                   [  OK  ]
[root@mail init.d]# ps -ef |grep xinetd
root      2635     1  0 12:25 ?        00:00:00 xinetd -stayalive -pidfile /var/run/xinetd.pid
root      3927  3412  0 16:43 pts/0    00:00:00 grep xinetd
[root@mail init.d]#

 

可以看到 pid reload后并没有变

 

##########################################################################################################################################################

# A function to find the pid of a program. Looks *only* at the pidfile        #下面的 pidfileofproc函数和 checkpid类似,但不执行 pidof命令,只查询 pid文件
pidfileofproc() {
 local base=${1##*/}
 
 # Test syntax.
 if [ "$#" = 0 ] ; then
  echo $"Usage: pidfileofproc {program}"
  return 1
 fi

 

 # First try "/var/run/*.pid" files
 if [ -f /var/run/$base.pid ] ; then
         local line p pid=
    read line < /var/run/$base.pid
    for p in $line ; do
         [ -z "${p//[0-9]/}" -a -d /proc/$p ] && pid="$pid $p"
    done
         if [ -n "$pid" ]; then
                 echo $pid
                 return 0
         fi
 fi
}

##########################################################################################################################################################

# A function to find the pid of a program.                        #下面的 pidofproc函数和上面的 pidfileofproc函数类似,但多了一步 pidof命令
pidofproc() {
 base=${1##*/}

 

 # Test syntax.
 if [ "$#" = 0 ]; then
  echo $"Usage: pidofproc {program}"
  return 1
 fi

 

 # First try "/var/run/*.pid" files
 if [ -f /var/run/$base.pid ]; then
         local line p pid=
  read line < /var/run/$base.pid
  for p in $line ; do
         [ -z "${p//[0-9]/}" -a -d /proc/$p ] && pid="$pid $p"
  done
         if [ -n "$pid" ]; then
                 echo $pid
                 return 0
         fi
 fi
 pidof -o $$ -o $PPID -o %PPID -x $1 || \
  pidof -o $$ -o $PPID -o %PPID -x $base
}

##########################################################################################################################################################

status() {                                                                  #注释 :下面的 status函数是判断服务的状态,总共有4
 local base=${1##*/}
 local pid

 

 # Test syntax.
 if [ "$#" = 0 ] ; then
  echo $"Usage: status {program}"
  return 1
 fi

 

 # First try "pidof"                                                        #同样是查找 pid先。直接使用 pidof命令
 pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || \                
      pidof -o $$ -o $PPID -o %PPID -x ${base}`
 if [ -n "$pid" ]; then                                                    #如果 pid变量的值不为空,则表示找到进程,
         echo $"${base} (pid $pid) is running..."                 #则打印 "xxx (pid nnn) is running " ,
         return 0                                                             # 并返回0
 fi

 

 # Next try "/var/run/*.pid" files                                    如果pidof 命令没有找到,则尝试从pid 文件找
 if [ -f /var/run/${base}.pid ] ; then
         read pid < /var/run/${base}.pid
         if [ -n "$pid" ]; then                                                如果pidof 命令找不到,但从pid 文件找到了pid ,则
                 echo $"${base} dead but pid file exists"                #打印 "xxx dead but pid file exists"
                 return 1                                                            # 并返回 1
         fi
 fi
 # See if /var/lock/subsys/${base} exists                            #如果 pidof命令和 pid文件都没有找到 pid,则
 if [ -f /var/lock/subsys/${base} ]; then                              #如果在 /var/lock/subsys下存在对应的文件,则
  echo $"${base} dead but subsys locked"                                #打印 “xxxx dead but subsys locked”
  return 2                                                                            #并返回 2
 fi
 echo $"${base} is stopped"                                                #如果 pidof 命令、pidf文件都没有找到pid,且没有别锁,则打印 “xxx is stopped
 return 3                                                                           #并返回3
}

##########################################################################################################################################################

 

# 注释 :下面的 echo_xxx函数就是真正在屏幕上打印 [ ok ][ PASSED ][ FAILURE ][ WARNING ] 的部分了

 

echo_success() {                                                                    # 下面是echo_success 部分
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL                            #首先是打印 “[”之前的空格
  echo -n "[  "                                                                        # 然后打印 "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS                    #设置字体为红色
  echo -n $"OK"                                                                      # 打印 OK
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL                    # 返回字体为白色
  echo -n "  ]"                                                                         #打印 "]"    
  echo -ne "\r"                                                                        换行。
  return 0                                                                               #返回 0,其他一律返回1

 

 

echo_failure() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo -n $"FAILED"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

 

echo_passed() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo -n $"PASSED"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

 

echo_warning() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo -n $"WARNING"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

##########################################################################################################################################################

# Inform the graphical boot of our current state
update_boot_stage() {
  if [ "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb-client ]; then
    /usr/bin/rhgb-client --update="$1"
  fi
  return 0
}

##########################################################################################################################################################

# Log that something succeeded                                                
success() {                                                                                                # success函数除了打印 [ xxx ]之外,还会使用 initlog记录信息
  if [ -z "${IN_INITLOG:-}" ]; then
     initlog $INITLOG_ARGS -n $0 -s "$1" -e 1                                                   # -n--name的意思,-s--string -e--event1表示完全成功
  else
     # silly hack to avoid EPIPE killing rc.sysinit
     trap "" SIGPIPE
     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21
     trap - SIGPIPE
  fi
  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_success
  return 0
}

 

# Log that something failed
failure() {
  rc=$?
  if [ -z "${IN_INITLOG:-}" ]; then
     initlog $INITLOG_ARGS -n $0 -s "$1" -e 2                                                    # failure的话 --event是失败
  else
     trap "" SIGPIPE
     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 2" >&21
     trap - SIGPIPE
  fi
  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_failure
  [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
  return $rc
}

 

# Log that something passed, but may have had errors. Useful for fsck
passed() {
  rc=$?
  if [ -z "${IN_INITLOG:-}" ]; then
     initlog $INITLOG_ARGS -n $0 -s "$1" -e 1                                                 # passed的话 --event还是1
  else
     trap "" SIGPIPE
     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21
     trap - SIGPIPE
  fi
  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_passed
  return $rc

 

# Log a warning
warning() {
  rc=$?
  if [ -z "${IN_INITLOG:-}" ]; then
     initlog $INITLOG_ARGS -n $0 -s "$1" -e 1                                                # warning的话 --event也是 1
  else
     trap "" SIGPIPE
     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21
     trap - SIGPIPE
  fi
  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_warning
  return $rc

##########################################################################################################################################################

# Run some action. Log its output.                                                        # action函数是另外一个最重要的函数,它的作用是打印某个提示信息并执行给定命令
tion() {
  STRING=$1
  echo -n "$STRING "
  if [ "${RHGB_STARTED}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
      echo -n "$STRING " > /etc/rhgb/temp/rhgb-console
  fi
  shift
  initlog $INITLOG_ARGS -c "$*" && success $"$STRING" || failure $"$STRING"
  rc=$?
  echo
  if [ "${RHGB_STARTED}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
      if [ "$rc" = "0" ]; then
       echo_success > /etc/rhgb/temp/rhgb-console
      else
        echo_failed > /etc/rhgb/temp/rhgb-console
 [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
      fi
      echo
  fi
  return $rc
}

##########################################################################################################################################################

# returns OK if $1 contains $2                        # strstr函数是判断 $1字符串是否含有 $2字符串,是则返回0,否则返回1
() {
  [ "${1#*$2*}" = "$1" ] && return 1
  return 0
}

##########################################################################################################################################################

# Confirm whether we really want to run this service                                       # confirm函数是用于交互式的启动服务
nfirm() {
  [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
  while : ; do 
    echo -n $"Start service $1 (Y)es/(N)o/(C)ontinue? [Y] "                                   #会打印一个提示信息
    read answer
    if strstr $"yY" "$answer" || [ "$answer" = "" ] ; then                                          #如果 answer变量是 y或者 Y
        return 0                                                                                                                #返回 0(但未真正启动)
    elif strstr $"cC" "$answer" ; then                                                                    #如果 answer或者C ,则
        rm -f /var/run/confirm                                                                                          #删除 /var/run/confirm文件                           
        [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=no
        return 2                                                                                                                #返回2
   elif strstr $"nN" "$answer" ; then                                                                      #如果 answern或者 N,则
  return 1                                                                                                                       #直接返回1
     fi
  done
}

 

Linux系统开机过程详细分析

各位是否曾经对电脑整个开机的流程感到好奇呢 ? 这一次 , 我们所要讨论的 
主题 , 就是 Linux 从开机的一瞬间到 login 为止 , 到底发生了什么事情 ? 


想必各位都知道 , 在刚开机时 , 由于 80x86 的特性 , CS ( Code Segment ) 
这个寄存器中全部都放着 1 ,  IP ( Instruction Pointer ) 这个寄存器 
中全部都放着 0 , 换句话说 , CS=FFFF  IP=0000 , 此时 , CPU 就依据 
CS  IP 的值 ,  FFFF0H 去执行那个地方所放的指令 . 这时候 , 由于 
FFFF0H 已经到了高位址的顶端 , 所以 , FFFF0H 这个地方 , 总是会放一个 
JMP 指令 , 跳到比较低的位址 . 接著 , ROM BIOS 就会作一些检查的动作 
像内存 , 键盘 ...... 并在我们俗称的 UMB ( Upper Memory Block ) 
之中扫描 , 看看是否有合法的 ROM 存在 ( 比如 SCSI 卡上的 ROM ) . 
假如有 , 就到里面去执行一些东西 , 执行完之后再继续刚才的行程 . 到了 
最后 , 读取硬盘上的第一个 sector . 在这里 , 我假设各位由硬盘启动 
因此 , 就硬盘的构造而言 , 它的第一个 sector 称为 MBR ( Master Boot 
Record ) . 因为一个 sector  512 bytes ,  MBR  512 bytes 可分 
为两个部份 , 第一个部份为 Pre-Boot  , 占了 446 bytes ; 第二部份 
 Partition Table , 占了 66 bytes . Pre-Boot 区的作用之一 , 就是 
去看看那个 Partition 被标成 Active , 然後去读那个 Partition  Boot 
 . 


 Linux 的启动方面 , 一般人最常把 LILO 放在 MBR  Superblock 
假如你把 LILO 放在 MBR , 那很明显的 , 当读取到 MBR 的时候 , LILO 
就被执行 , 此时 , 你的屏幕上会出现 boot: 接着 , 就进行 Load Kernel 
的动作 . 在另一方面来说 , 假如你把 LILO 安装在 Superblock , 通常你 
还会有一个管理开机的程序 , 也许是放在 MBR (  OSBS ) 或者是放在一 
个单独的 Partition (  OS/2  Boot Manager ) . 再由这个管理开机 
的程式去读取 LILO , 进而做 Load Kernel 的动作 . 


好了 , 到了目前为止 , 我们已经讲到 Load Kernel 的动作 . Kernel  
load  memory 中之后 , 接着进行一连串 probe 周边的动作 , 像串口 
并口 , 软盘 , 声卡 , 硬盘 , 光驱  ...... 接着 mount root 
partition . 在这之后 , kernel 会起动 init 这个 process . init  
 process  PID  1 , 它是所有 process 的祖先 . 


接下来呢 ? 系统就开始执行 /rc.d/rc.S , 在这里 , 我们暂时打住 , 
先对大概的 initialization script 执行的顺序作一个浏览 , 请看下面 
的流程 : 


init[1] 
rc.S begin <--- 目前我们已经讲到这里 
rc.serial begin 
rc.serial end 
rc.S end 
init[1] enter runlevel 5 
rc.M begin 
rc.inet1 begin 
rc.inet1 end 
rc.inet2 begin 
rc.inet2 end 
rc.font begin 
rc.font end 
rc.local begin 
rc.local end 
rc.M end 
login 


上面的流程清楚的指出 ,  rc.S 这个 shell script  , 会去执行 rc.serial 
接着再执行 rc.M , rc.M 中又包含了 rc.inet1 , rc.inet2 , rc.font , rc.local 
最后执行 login . 在下面的内容中 , 将为各位介绍这几个 shell script 
从下面开始 , 凡是每一列之前有一个 #  , 为原来 shell script 中的注释 
有两个 #  , 为笔者加上的注释 , 当然啦 , 没有任何 # 的为 shell script 
的内容 , 而对命令或内容的解释 , 一律都写在命令或内容的前面 . 
首先由 rc.S 开始 : 


***************************** rc.S ********************************** 


#!/bin/sh 

# /etc/rc 

# These commands are executed at boot time by init(8). 
# User customization should go in /etc/rc.local. 


echo '======== rc.S is running ! System Initializing Now !!! ========' 
PATH=/sbin:/usr/sbin:/bin:/usr/bin 


## 打开所有 swap ! 下面 /sbin/swapon -a 的意思是 : 使得 /etc/fstab 中被记录 
##  swap  device 全部启动 . 


/sbin/swapon -a 



##  ! 下面这个指令 update 就很重要了 , 它负责每隔一段固定的时间 , 就将 
## buffer 中的资料 , 利用 sync 写回磁盘上 , 并将 superblock  update 
## 的动作 . 使用 ps 这个指令看看有那些 process , 就可看到 update 还有一个 
## bdflush , 这两个 process 都是必然要存在的 , 可不要随便砍掉 , 要不然 , 
## 万一系统 crash  , 那磁盘里面的资料就不是最新的了 ...... 


/sbin/update & 



## 利用 echo -n >;>; 制造一个文件 , 并用 rm -f 这个档案来测试 root partition 
## 是不是 read-only 或者是可读写 


READWRITE=no 
if echo -n >;>; "Testing filesystem status"; then 
rm -f "Testing filesystem status" 
READWRITE=yes 
fi 



## 假如 root partition  read-only 就作 fsck 的动作 , 假如不是 read-only 
## 而是 read-write 的话 , 就做下面 else 之后的动作 


if [ ! $READWRITE = yes ]; then 
## 利用 fsck 做检查及修复文件系统的工作 , 后面接的两个参数 -A , -a . 
## -A 的意思是 : fsck 会依据 /etc/fstab 中的记录 , 去检查所有的文件 
## 系统 ;  -a 就是 auto 的意思 ,  fsck 有修复的动作时 , 它不会问 
## 你问题 , 而直接修复 . 


/sbin/fsck -A -a 



## 假如 fsck  error , [ $? -gt 1 ] 括号里面的意思是 : 若上个命令的 
## 传回值大于 1 , 而上个命令就是 fsck . 让我们看看 fsck 的传回值 : 
## 0 - No errors 
## 1 - File system errors corrected 
## 2 - File system errors corrected, system should 
## be rebooted if file system was mounted 
## 4 - File system errors left uncorrected 
## 8 - Operational error 
## 16 - Usage or syntax error 
## 128 - Shared library error 
## 很明显的 , 若有任何错误产生的话 ,  fsck 的传回值都大于 1 . 其实 
## 就我的观点认为 , 应该写成 if [ $? -ge 1 ] 比较好 . 既然有错呢 , 系统 
## 应该就要跳至单用户模式 , 在单用户模式中主要就是 /etc/rc.d/rc.K 
## 中的两件事 : 关掉 swap  卸下所有的文件系统 , 而最后重新 login . 
## 一般正常的情况下 , if 下面这一大段是不会执行的 , 而会跳至下面 
## 标有 ************************* Normal 1 *************************  


if [ $? -gt 1 ] ; then 
echo 
echo 
echo "**************************************" 
echo "fsck returned error code - REBOOT NOW!" 
echo "**************************************" 
echo 
echo 
/bin/login 
fi 


## ****************************** Normal 1 ************************** 
##  fsck 检查没有错误之后 , 就把 root partition 重新 mount 上来 
## 下面指令的参数有三个 , -w 代表mount 成可读写 , -n 代表把一个 file- 
## system mount 上来 , 但不会把记录写到 /etc/mtab  , 在上次对 /etc/mtab 
## 介绍时有提到 , 当我们使用 mount 这个指令把一个 filesystem mount 上来 
## 的时候 , /etc/mtab 就会记录 ! 利用 -n 这个 option 可使得做 mount 的动 
##  , 却不会记录 . -o 后面可以接许多的选项 , 在这里 , 我们给它的选项是 
## remount . remount 的意思是 : 重新 mount 一个已经被 mount  filesystem 
## 这个选项通常被用来改变该 filesystem 的读写标志 ,尤其是把 filesystem 
##  read-only 的状态 , 改变成 read-write 的状态 . 


echo "Remounting root device with read-write enabled." 
/sbin/mount -w -n -o remount / 



## 在前面的情况中 , 都是 root partition  read-only 的状态下 , 所做的一些 
## 工作 , 到了最后一个指令 /sbin/mount -w -n -o remount / , 才把 root 
## partition mount  read-write . 各位有没有看到前面那行 : 
## if [ ! $READWRITE = yes ]; then ..... 下面这个 else 就是与这个 if 对应 
## 也就是说 , 前面那个 if 的区块中 , 所作的工作都是在 root partition  
## read-only 的条件成立下所作的事 , 那很明显的 , 下面这个 else 就是 root 
## partition  read-write 的条件下所作的工作 . 假如你的 root partition 
##  read-writeable 的话 , 那么系统就会显示下面的信息 . cat << EOF 所作的 
##  , 就是把 EOF 之前的信息全部显示在屏幕上 : 
## 我想 , 下面的信息写得很明显了 , 它说 : 你的 root partition  mount  
## read-write , 没有办法检查 , 要使检查的动作能够顺利的进行 , 你必须把 
## root partition mount  read-only ! 那要怎么做呢 ? 很容易 , 只要利用 
## rdev -R / 1 就可以了 ...... 


else 
cat << EOF 


*** Root partition has already been mounted read-write. Cannot check! 
For filesystem checking to work properly, your system must initially mount 
the root partition as read only. Please modify your kernel with 'rdev' so 
that 
it does this. If you're booting with LILO, type: 
rdev -R /vmlinuz 1 
(^^^^^^^^ ... or whatever your kernel name is.) 


If you boot from a kernel on a floppy disk, put it in the drive and type: 
rdev -R /dev/fd0 1 


This will fix the problem *AND* eliminate this annoying message. :^) 


EOF 



## 下面这个指令没什么好说的 , 就是暂停 10 秒钟 ,  user 能够有充足的 
## 时间看完上面的信息 


sleep 10 
fi 



## 删除 /etc/mtab /etc/nologin /etc/utmp 


/bin/rm -f /etc/mtab* /etc/nologin /etc/utmp 



## 制造 /etc/utmp , 这是一个很典型制造空文件的写法 . /dev/null 这个 node 
## 蛮有趣的 , 在某一方面来说 , 它有点像是一个 " 黑洞 " . 怎么说呢 ? 
## 各位可以试试看下面的指令 ls >;>; /dev/null , 当你使用这个指令之后会 
## 发生什么事呢 ? 什么也没发生 , 而且 ls 的输出就好像被丢到黑洞里 ,  
## 影无踪了 . 那也许你会想 : 那这有什么用 ? 我的回答是 : 的确没有什么 
## 很大的用处 , 但当你想抑制输出的信息时 , 你就会用得到了 . 


cat /dev/null >;>; /etc/utmp 



## 依据 fstab ( filesystem table ) 中的描述 , 自动的挂上文件系统 
## 但此时因为 TCP/IP 还没有设定 , 故不用 NFS 


echo 'Mount Filesystem !!!' 
/sbin/mount -avt nonfs 



## 设定系统的时钟 . 下面这几行所做的事就是 : 看看 /sbin/clock 这个文件是 
## 不是可执行的 , 假如可以执行 , 就把 CMOS 中的时间设定为系统的时间 . 


if [ -x /sbin/clock ]; then 
echo 'Set System Clock' 
/sbin/clock -s 
fi 



## 下面的四行若没有 mark , 则每次开机 issue  motd 都会被改变 , 这应该 
## 可算是 FAQ 级的问题了 ...... 因为我有自己设计的 issue  motd , 所以 
## 下面的四行前面都有 # , 被注释掉 . 
## 假如你要有自己的设定 , 下面一定都要 mark 起来 


#echo >; /etc/issue 
#echo Welcome to Linux /bin/uname -a | /bin/cut -d\ -f3. >;>; /etc/issue 
#echo >;>; /etc/issue 
#echo "/bin/uname -a | /bin/cut -d\ -f1,3. (Posix)." >; /etc/motd 



## 接下来 , 将执行 rc.serial , 顾名思义 , rc.serial 是作串口设定的工作 
##  rc.serial  , 内容虽然也是很简单 , 但并不像 rc.S 那样直接 . 换句话 
##  , 读者至少要 " 稍微 " 懂一点 shell programming , 所以说呢 , 假如 
## 还不会 shell programming 的读者呢 , 都应该赶快去找一本书来看一下 ,  
## 这篇文章的结尾 , 我会提出一些书单 , 各位可以去找找这几本书 ...... 


/bin/sh /etc/rc.d/rc.serial 
echo '================= rc.S is finish NOW !!! =========================' 




到了这里 , rc.S 的最後一步 , 是去执行 rc.serial . 大家可以看一看 
/rc.d/rc.serial . 好像很长的样子 , 但实际上呢 , 各位必然发现到了 , 这个 
shell script 大部份指令的前面都有一个 '#'  , 这代表着 , 这些指令完全 
不会被执行 . 所以呢 , 真正有用的只不过寥寥十几行吧 ! 在另一方面来说 , 
假如你是用网卡连上网络 ,  rc.serial 对你并没有什么大用处 . 



**************************** rc.serial ****************************** 


#!/bin/sh 

# /etc/rc.serial 
# Initializes the serial ports on your system 

# Version 2.01 


echo '======================= rc.serial is begin !!! =====================' 
cd /dev 


## 下面三行中的前两行是设定一些变量 , 由于在这个 shell script  , 需要 
## 用到 /bin/setserial -b 这个指令 , 或是需要用到所有以 cua 开头的 node 
## 的次数太多了 , 因此 , 把它们设定为一个变量 , 是一个不错的方法 . 尤其 
## PORTS=`echo cua? cua??` 这是一个聪明的写法 , 那为什么不写成 PORT= 
## `echo cua*`  ? 各位可以在 /dev 下分别使用这两个指令 , 观察输出到底 
## 有什么不同 ...... 


SETSERIAL="/bin/setserial -b" 
PORTS=`echo cua? cua??` 
echo -n "Configuring serial ports...." 



## 下面这行 , 没有学过 shell programming 的人很可能会看不懂 , 不过没有 
## 关系 , 这行中的 ${SETSERIAL} 会被换成 /bin/setserial -b ,  ${PORTS} 
## 会被换成 cua0 cua1 cua2 ....... cua31 , 所以整句翻译就是 : 
## /bin/setserial -b -W cua0 cua1 cua2 cua3 cua4 cua5 cua6 ...... cua31 
## 那这行指令到底在做什么呢 ? 其实只是在做中断侦测的工作 . 


${SETSERIAL} -W ${PORTS} 



## 各位看到下面原来的注释了吧 . 当你有一些特殊的卡时 , 你可以把相对应部 
## 份前面的 '#' 去掉 , 以便能做自动设定的工作 . 其实呢 , 这种情况实在 
## 不多 , 大部份人的设备都差不了多少 , 说到关于串口 , 差异就更少了 . 

# AUTOMATIC CONFIGURATION 

# Uncomment the appropriate lines below to enable auto-configuration 
# of a particular board. Or comment them out to disable them.... 




## 好了 , 这下我们又多了一个变量 : AUTO_IRQ , 这在下面会用到 . 


AUTO_IRQ=auto_irq 



## 下面几行非常整齐 , 它们可以分别被换成 : 
## /bin/setserial -b /dev/cua? auto_irq skip_test autoconfig 
## setserial 说穿了也没什么 , 这个指令可以让你对 serial port 做设定及回报 
## 的动作 ,  IRQ , I/O port 啦等等的事情 . 一般的情况下 , 大家的电脑中 
## 通常只有 COM1-COM4 , 但假如你想增加新的 port ,  setserial 就派上用 
## 场了 . 


# These are the standard COM1 through COM4 devices 

# If you have an internal modeme with a Rockwell Chipset, add a "skip_test" 
# to the /dev/cua3 line below. (It's not added by default because it will 
# screw up people with 8514 displays). 

${SETSERIAL} /dev/cua0 ${AUTO_IRQ} skip_test autoconfig 
${SETSERIAL} /dev/cua1 ${AUTO_IRQ} skip_test autoconfig 
${SETSERIAL} /dev/cua2 ${AUTO_IRQ} skip_test autoconfig 
${SETSERIAL} /dev/cua3 ${AUTO_IRQ} autoconfig 


# These are for the first AST Fourport board (base address 0x1A0) 

${SETSERIAL} /dev/cua4 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua5 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua6 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua7 ${AUTO_IRQ} autoconfig 


# These are for the second AST Fourport board (base address 0x2A0) 

${SETSERIAL} /dev/cua8 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua9 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua10 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua11 ${AUTO_IRQ} autoconfig 



## 从这里以下 , 我省略了一大段 , 因为这一大段都是支持特殊的卡 


# These are the 3rd and 4th ports on the Accent Async board. 

#${SETSERIAL} /dev/cua12 ${AUTO_IRQ} autoconfig 
#${SETSERIAL} /dev/cua13 ${AUTO_IRQ} autoconfig 














## 好了 , 我们跳掉了一大段 , 直到这里 . 各位看到下面的注解了 . 
## 假如你想用手动的方法指定 IRQ , I/O port , 及指定 chip 的型号 
## 那你可以拿掉下面对应那行前面的 '#' 并作适当的修改 , 比如说 
## 你用的是比较新的 16550  16550A , 而不是 16450 , 那你就可以 
## 在下面用手动的方法指定 . 实际上 ,  autoconfig  autoirq 
## 的选项就可以了 , 没有必要用手动的方式 . 除非侦测不到 . 


############################################################### 

# MANUAL CONFIGURATION 

# If you want to do manual configuration of one or more of your 
# serial ports, uncomment and modify the relevant lines. 

############################################################### 


# These are the standard COM1 through COM4 devices 

#${SETSERIAL} /dev/cua0 uart 16450 port 0x3F8 irq 4 
#${SETSERIAL} /dev/cua1 uart 16450 port 0x2F8 irq 3 
#${SETSERIAL} /dev/cua2 uart 16450 port 0x3E8 irq 4 
#${SETSERIAL} /dev/cua3 uart 16450 port 0x2E8 irq 3 












## Ok , 到此 , rc.S  rc.serial 已经结束 , 因为截稿时间的关系 , rc.M 
## rc.inet1 , rc.inet2 , rc.font , rc.local 将在以后为各位介绍 . 


echo "done." 
${SETSERIAL} -bg ${PORTS} 


echo ' ====================== rc.serial is complete !!! ===================' 




关于 Shell Programming 的书单 : 


Title: The Unix C Shell Field Guide 
Authors: Gail Anderson and Paul Anderson 
Publisher: Prentice Hall 
Edition: 1986 
ISBN: 0-13-937468-X 


这本是 C-Shell  Bible , 想学 C-Shell 的人 , 可以去看这本书 . 



Title: Unix Shell Programming 
Authors: Stephen Kochan and Patrick Wood 
Publisher: Hayden 
Edition: 1990 
ISBN: 0-672-48448-X 


 ! 这本书以 Bourne Shell 为主 , 内容深入浅出 , 读者很容易就可以了解 
这本书的内容 , 进而掌握 Bourne Shell 的精髓 . 此外 , 这本书也有提到 
Korn Shell , 大体上来说 , 是一本值得看的好书 . 



*如何联系作者 : 


E-Mail Address : jhhsu@csie.nctu.edu.tw 
u8217017@cc.nctu.edu.tw 


Dormitory : 交通大学十舍 317R 


.. 




Linux 开机程序之研讨 
CCCA 资工86 许景华 


在上次的介绍中 , 我们已经看完了 rc.S  rc.serial 这两个 shell script . 
现在 , 我们将把剩下的 shell script 再作一个介绍 . 
首先还是看看全部的流程 : 



init[1] 
rc.S begin 
rc.serial begin 
rc.serial end 
rc.S end <-- 上一次我们说明到这里 
init[1] enter runlevel 5 
rc.M begin 
rc.inet1 begin 
rc.inet1 end 
rc.inet2 begin 
rc.inet2 end 
rc.font begin 
rc.font end 
rc.local begin 
rc.local end 
rc.M end 
login 



这次主要的部份可分为两项 : 因为 init 将会去读取 inittab , 所以 inittab 
将被列为第一部份的重点 , 而第二部份就是 rc.M , rc.font , rc.local 
这几个 shell script 的说明 . ( rc.inet1 , rc.inet2 这两个关于网络的 
shell script 将在以后单独说明 ) 
好了 , 我们先从 inittab 看起吧 ! 看看上面的流程 , 在第一行 : init[1] 
也就是 init 这个 process 被启动之后 , 它会去读取 /etc/inittab 这个文件 
以完成系统的启动 . 从这里 , 我们看到了 LINUX 的确融合了 SVR4  SunOS 
的一些特性 , inittab 这个文件 ,  SunOS 系统中是不存在的 , 但是它却是 
SVR4 典型的文件 . init 这个 process 会依据 /etc/inittab 中所记载的内容 
进入不同的 run-level 并启动不同的 process . 所以 inittab 的重要性 
可见一斑 . 那什么叫 run-level  ? 所谓 run-level 就是系统中定义了许多 
不同的 level , 而系统会随著 level 的不同而去启动不同的资源 . 
现在就让我们来看一下 /etc/inittab 中的内容 : 
 /etc/inittab 这个文件中 , 每一列是一个进入点 , 假如我们仔细观察每一列 
的话 , 那我们就会很容易的发现 , /etc/inittab 的每一列可以被 " : " 这个 
字符分成好几个栏位 . 这几个栏位的格式如下 : 


id:runlevels:action:process 


而它们代表的意义分别如下 : 


id : 由两个独特的字符所组成的辨示符号 , 在比较新的 UNIX 系统中 , 已不 
受只能有两个字符的限制 . 


runlevels : 指出下面一个栏位中的 action 以及 下下个栏位中的 process 
会在那些 runlevel 中被执行 . 这一栏的合法值有 0,1,2...6 
以及 S . 而在正常的启动程序之后 , Superuser 可以使用 
telinit 这个指令来改变系统的 runlevel . 又因为在 LINUX  
, runlevel 的预设值是 5 ( 等一下就会看到 ) 所以 , 只有 
那些每一列中 runlevel 那栏有 5 这个值的 , 后面的 process 
才会被启动 . 所以 , 我们就可以想像的到 : " 由于系统的 
runlevel 不同 , 所起动的 process 也不尽相同 , 所以系统 
起动的资源在每个不同的 runlevel 就会有差异存在 . 


action : 这个栏位有一点复杂 , 在这个栏位中记录着 init 在启动相对应的 
process  ,  process 所采取的动作 , 而合法的动作有下面几项


initdefault : 指出系统在启动时 , 预设进入的 run-level  , 
比如说 , 我们可以在 /etc/inittab 中找到下面这 
一列 : id:3:initdefault: 
很明显的 , 系统将在启动时 , 进入 runlevel  3 
的模式 . 当然 , 你可以把 3 改成 4 试试看 ,  
果你改成了 4 , 那将会执行 /etc/rc.d/rc.4 ,  
就是 run xdm . xdm 在以后有机会的话 , 将为各 
位介绍 ...... 


sysinit : 在系统起动时 , 这个 process 会被执行 . 而所有 process 
前的 action 中有 boot  bootwait  process ,  
须等到这些 action  sysinit  process 执行完之后 
它们才能够执行 . 


wait : 在起动一个 process 之后 , 若要再起动另一个 process ,  
必需等到这个 process 结束之后才能继续 . 


respawn : 代表这个 process 即使在结束之后 , 也会重新被启动 , 
最典型的例子就是 getty (  LINUX 中为 agetty ) . 
看看下面的循环 : 


-- getty -->; login -->; shell -->; logout -- 
^ |??????????????????????????????????????? | 
? |<---------------------------------------| 


即使在 getty 结束之后 , 它也会重新被启动 . 


ctrlaltdel : 想必有人会以键盘上的 Ctrl , Alt ,  Del 这三个 
键来达到使系统 shutdown 的目的 , 现在我们果然在 
/etc/inittab 中看到了这一列 : 


ca::ctrlaltdel:/sbin/shutdown -t3 -rf now 


所以说 , 当我们按下这三个键的时候 , init 会收到 
SIGINT 这个 signal , 接着就执行 shutdown 的动作 
不过 , 我们最好不要养成按 Ctrl-Alt-Del 来使系统 
shutdown 的习惯 , 尤其在单用户多任务的操作系统 ,  
OS/2 , 甚至 Windows 95 , shutdown 几乎都是标准 
的关机程序了 , 更何况是多用户多任务的 LINUX , 所以 , 
shutdown 这个指令是一定要熟悉的 . 


除了上面的几个 action 之外 , 另外还有一些合法的 action , 但这 
 action 并不需要太注意 , 要用的时候再利用 man init 去查询就 
可以了 . 


process : 这一栏中可以是 shell script 或是可执行的程序 . 


好了 , 当我们了解 /etc/inittab 中每一栏的意义之后 , 要看懂 /etc/inittab 
就是一件轻松愉快的工作了 .  /etc/inittab 档中 , 我们可以看到下面这一段 


c1:12345:respawn:/sbin/agetty 38400 tty1 
c2:12345:respawn:/sbin/agetty 38400 tty2 
c3:45:respawn:/sbin/agetty 38400 tty3 
c4:45:respawn:/sbin/agetty 38400 tty4 
c5:45:respawn:/sbin/agetty 38400 tty5 
c6:456:respawn:/sbin/agetty 38400 tty6 


简单来说 , 系统在起动之后会制造出六个虚拟的 console . 我想大家应该有试过 
 Ctrl-Alt + F1 - F6 可在这六个 console 之间切换 ; 若你使用 XWindows  
想暂时回到 console 下时 , 可用 Ctrl-Alt + F1 - F6 这三个键来选择 , 若想 
回到 XWindows 下时 , 只要以 Ctrl-Alt-F7 就可以回到 XWindows 下了 . 基本 
 , 对於 memory 比较少的人 , 可以不要开那么多的虚拟 console , 那么就可 
以去掉上面的几列 . 还有 , 在前面我们也提过 , 可以把预设的 runlevel  5 
改成 6 , 对於 beginner 来说 , 系统一启动完就直接进入 XWindows 也许是一个 
不错的设定方法 ...... 


介绍完 /etc/inittab 之后 , 我们接着看 rc.M ! 由前面的流程当中 , 我们看到 
rc.M 中又包含了四个 shell script , 其中 rc.inet1  rc.inet2 是有关于网络 
的设定 ; rc.font 是作字体的设定 ,  rc.local 中可以放一些想要起动的 
daemon . 


我们现在就来看看 rc.M , 依照往例 , 前面有两个 "#" 的为加上去的注释 . 
只有一个 "#" 的为原来的注释 : 


#!/bin/sh 

# rc.M This file is executed by init(8) when the system is being 
# initialized for one of the "multi user" run levels (i.e. 
# levels 1 through 6). It usually does mounting of file 
# systems et al. 

# Version: @(#)/etc/rc.d/rc.M 2.02 02/26/93 

# Author: Fred N. van Kempen, 
# Heavily modified by Patrick Volkerding 



## 显示进入多用户模式 


echo "Going multiuser..." 



## 下面一列的意思是 : 假如你在文字模式的 console  , 15分钟内都没有动作 
## 的话 , 屏幕就会自动暗下来 , 简单的说 , 就是 screen saver 的功能 . 


/bin/setterm -blank 15 



## 执行 crond 这个 daemon . 不用说 , crond 在系统中扮演了很重要的角色 , 
## 它负责每过一段时间后 , 就去看看 /var/spool/cron/crontabs 中有那些 file 
## 要运行 , 这些 file 往往有一个固定的时间 , 比如说 : 每个月的 1  ,  
## 天凌晨等 ...... 我们可以用平常的编辑器编好一个文件 , 里面的格式如下 : 
## 
##     星期 命令 
## 
## 举例来说 , 59 23 31 12 * /etc/wall happy_new_year 
## 在每年的 12  31 号晚上 11  59  会对每个系统上的 user 送出 
## happy_new_year 中的内容 
## 
## 接着我们可以利用 crontab <文件名>; 这个指令来把此文件放到 
## /var/spool/cron/crontabs我们可以看看 /var/spool/cron/crontab  
## 有一个 root 的文件 , 看看里面的内容 : 
## 
## 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/lib/atrun 
## 
## 所以各位看到了 , 在前两期提到的 at 命令是五分钟才被 run 一次的 
## 
## 再举一个简单的例子好了 : 我们先用一般的文本编辑器造出一个名为 crontest 
## 的档案 , 内容如下 : 
## 
## 5 * * * * ls -la ~/ >;>; ~/hehehaha 
## 
## 接着 , 我们键入下面的命令 : crontab crontest 
## 此时 , 从内容得知 , 每五分钟 crond 就会执行 ls -la , 把你 home directory 
## 的内容加入 hehehaha 这个文件中 . 
## 
## 当然啦 ! 这个例子简直是毫无意义可言 :) 但是 , 大家既然知道了基本原理 , 
## 利用 crontab , at 这些指令 , 就可以简化一些系统管理的动作 , 同时在执行 
## 一些工作时 , 也会比较有弹性 . 


/usr/sbin/crond -l10 >;>;/var/adm/cron 2>;&1 



## 假如 /etc/HOSTNAME 不能读取的话 , 就把 darkstar.frop.org 当成 HOSTNAME 
## 中的内容 . 老实说 , 下面这三列去掉也不打紧 ...... 


if [ ! -r /etc/HOSTNAME ]; then 
echo "darkstar.frop.org" >; /etc/HOSTNAME 
fi 



## 下面从 if  fi 夹起来的部份 , 主要就是在执行 rc.inet1 , rc.inet2 .  
## 些都是网络设定的工作 , 尤其是 rc.inet2 , 启动了一大堆 daemon , 这部份 
## 要牵扯到的东西太多了 .  subnet  netmask  ...... 类似这种观念 , 
## 都不是三言两语就可以玩完的 , 所以就留待以后再说 . 


if [ -x /etc/rc.d/rc.inet1 ]; 
then 
/bin/hostname `cat /etc/HOSTNAME | cut -f1 -d .` 
/bin/sh /etc/rc.d/rc.inet1 
/bin/sh /etc/rc.d/rc.inet2 
else 
/sbin/hostname_notcp `cat /etc/HOSTNAME | cut -f1 -d .` 
/usr/sbin/syslogd 
/usr/sbin/klogd 
/usr/sbin/lpd 
fi 



## 在某些资源独占的情况下 , 一些应用程序往往会制造出 lock 文件 . 假如这些 
## lock 文件在重新开机以后还是存在的话 , 那就很不好了 . 所以 , 下面就是在 
## 作这些删除 lock 文件的动作 , 并把一些输出的信息丢到 /dev/null  . 
## 在上一期的内容中 , 我们就有提到 /dev/null  , 也有提到抑制信息输出的 
## 方法 . 现在我们果然看到了一个实例 ...... 


/bin/rm -f /var/spool/locks/* /var/spool/uucp/LCK..* /tmp/.X*lock 1>; /dev/null 2>; /dev/null 



## 假如你有玩 hunt 这个 game 的话 , 那在 /tmp 下会有一个 socket 类型的文件 
## 我们要把它删除之后才能开始另一个 game ...... 


if [ -r /tmp/hunt -o -r /tmp/hunt.stats ]; then 
echo "Removing your stale hunt sockets from /tmp..." 
/bin/rm -f /tmp/hunt* 
fi 



## 设定 share library  link  cache . 这个指令只有 Superuser 才能使用 
##  , 它也相当的重要 . 万一你的 /etc/ld.so.cache 很不幸的 corrupt  , 
## 那我们也可以利用这个指令来让它重新 link , 先删除 /etc/ld.so.cache , 
## 再以 ldconfig -v 重新制造就可以了 . 


/sbin/ldconfig 



## 起动 sendmail daemon , 并且让它 15 分钟就去看一看 spool , 处理收发信件 


if [ -x /usr/sbin/sendmail ]; then 
echo "Starting sendmail daemon (/usr/sbin/sendmail -bd -q 15m)..." 
/usr/sbin/sendmail -bd -q 15m 
fi 



## 假如 /etc/rc.d/rc.font 是可读的话 , 就执行 rc.font 这个 shell script , 
## 而这个 shell script 主要是设定 text mode 下屏幕的字体 


if [ -r /etc/rc.d/rc.font ]; then 
/etc/rc.d/rc.font 
fi 



## 在系统管理中 , 我们常常把一些 local 的东西另外放在一个地方 , 这样才不 
## 会与原来的东西混淆 . 同时 , 因为 local 的东西更新版本的速度总是也比较 
##  , 在这种情况下 , 常常会变动的东西也可以放在 local 的区域中 , 这样 
## 管理起来比较方便 . 也许各位也注意到了 : 为什么会有 /usr/bin  
## /usr/local/bin 之分 . 就个人认为 , 像自己 compile 出来的东西 , 假如 
## 觉得还不错 , 就可以把它放在 /usr/local/bin , 因为它是新增的 , 所以我 
## 把它放在 /usr/local/bin . 当然啦 , 这只是个人喜好罢了 , 你要放那里 
## 都是可以的 , 只要找得到 , 易于使用及管理就好 . 
## 同样的 , 若我们要起动一些新增的 daemon  shell script , 那放在 
## 是不错的选择 . 
## 下面一列就是去执行 rc.local 中的设定 , 通常是一些 daemon 或是 shell 
## script 


/etc/rc.d/rc.local 



# All done. 



到这里 , rc.M 已经结束了 , 我们来看看从 rc.M 之中执行的 rc.font  


rc.local ...... 


下面是 rc.font 的内容 : 


#!/bin/sh 

# This selects your default screen font from among the ones in 
# /usr/lib/kbd/consolefonts. 



## 我想下面这一列的命令非常明显了 , 就是设定 console 中的字体 , 你可以 
## 改成自己喜欢的字体 . 或者你也可以利用 fontconfig 这个指令来改变 . 


setfont /usr/lib/kbd/consolefonts/default8x16 




看完了 rc.font  , 我们来看看 rc.local 的内容 . 我所要说的是 : rc.local 


毕竟是自己设定的区域 , 所以每个人的可能都不一样 , 就我而言 , 因为我多 run 


了一些 daemon , 所以与大家的可能不太相同 . 所以 , rc.local 作参考就可以了


下面是我的 rc.local : 


#! /bin/sh 
# Put any local setup commands in here 
# Running selection 



## lpd 是控制打印机的 daemon , 要想在 LINUX 下用打印机 , 这个 daemon 必需 
## 要被起动 , 此外还要修改 /etc/printcap . 详细的情况要去看 PRINT-HOWTO 


echo -n "lpd" 
/etc/lpd 



## httpd 就是 WWW server  daemon . 想必大家都用过 Mosaic , Netscape  
## 的浏览器 . 但假如我们想建立自己的 WWW server , httpd 必须要执行 . 


echo -n " httpd" 
/usr/local/etc/httpd/src/httpd 



##  WWW 的时代还没来临以前 , gopher 可说是具有最方便的信息索引功能 , 即使 
## 到了现在 , gopher 仍然占有一席之地 , 在这里 , 因为我有建立自己的 gopher 
## server , 所以 gopherd 必需被起动 . 


echo -n " gopherd" 
/usr/local/sbin/gopherd -u nobody 



## 下面这个指令是 mouse  console 下做 cut & paste 


echo -n "Running selection..." 
selection -t ms & 
echo ' '

本文出自51CTO.COM技术博客

Linux系统开机过程解释笔记

说实话,偶以前一直看不起开机启动的,按下电源然后出去溜一圈回来就可以用,何必考虑这个过程呢.不过,后来发觉学习linux如果没过这个的话,对以后的学习会产生很大的障碍.因此,赶紧多学习几遍.网上开机描述linux开机过程的比较多.不过,自己不默写一遍,在脑海里过一遍,往往也只能了解个大概,处于难得糊涂的状态.为了达到剑既是我,我既是剑的人剑合一的境界.赶紧温习一遍.

总结一下,linux的开机整个流程.

1.       1:启动电源后,主机第一步先做的就是查询BIOS(全称:basic input/output system 基本输入输出系统)信息.了解整个系统的硬件状态,CPU,内存,显卡,网卡等.,这一步windows算和它是一家.不分彼此.

2.       2: 接下来,就是主机读取MBR(硬盘的第一个扇区)里的boot loader.这个可是重点哦,据说troubleshooting里就会考这点,给个坏了的loader,叫你修正.windows不支持linux的分区格式.所以,windowsboot.ini是查不到linux的系统的.一般我装系统都是先装windows再装linux,然后用grub来做boot loader.两个字:省心!因为linux不像windows那么小气.grub可是支持windows分区格式的哦.

3.      3: 接上一步,主机读取boot loader,会读取里面的信息,知道谁跟谁是待在哪,假如主机想进入linux系统,读取到linux核心是在/boot文件目录中后,将此核心加载到内存中.开始了接下来的分析启动之旅.

4.        4: OK,第一个运行程序是谁?就是/sbin/init程序.不信,就用top程序看下,是不是PID1的就是这个东东,,可是万物之祖啊,我简称它是女娲娘娘(不喜欢亚当夏娃).

5.       5: init首先查找启动等级(run-level).因为启动等级不同,其运行脚本(也就是服务)会不同.默认的等级有以下几项:
0 - halt (系统直接关机)
1 - single user mode (单人模式,用于系统维护时使用)
2 - Multi-user, without NFS (类似3模式,不过少了NFS服务)
3 - Full multi-user mode (完整模式,不过,是文本模式)
4 - unused (系统保留功能)
5 - X11 (3模式类似,不过,X终端显示)
6 - reboot (重新开机)
(不要选择04,6否则,进步了系统的) 

6.       6:  OK.系统知道自己的启动等级后,接下来,不是去启动服务,而是,先设置好主机运行环境.读取的文件是/etc/rc.d/rc.sysinit文件.那究竟要设置哪些环境呢? 

1. 设置网络环境/etc/sysconfig/network,如主机名,网关,IP,DNS. 

2. 挂载/proc.此文件是个特殊文件,大小为0,因为它是在内存当中.里面东东最好别删. 

3. 根据内核在开机时的结果/proc/sys/kernel/modprobe.开始进行周边设备的侦测. 

4. 载入用户自定义的模块/etc/sysconfig/modules/*.modules 

5. 读取/etc/sysctl.conf文件对内核进行设定. 

6. 设定时间,终端字体,硬盘LVMRAID功能,fsck进行磁盘检测. 

7. 将开机状况记录到/var/log/dmesg.(可以用命令dmesg查看结果)

7.       7: OK,接下来,就是启动系统服务了,不同的run-level会有不同的服务启动./etc/rc.d目录中,不同的level会有不同的目录.如启动3模式,会有个rc3.d目录,里面就保存着服务.其中,S(start)开头的表明开机启动,K(kill)开头的表明开机不启动.数字表示启动顺序.数字越小,启动越早.
注意,他们都是连接到etc/rc.d/init.d/目录中的相关文件.所以,想手工启动某一服务,可以用"/etc/rc.d/init.d/某个服务start"启动哦.相反,我们也可以把某个服务ln(链接命令)到不同run-level的目录中.记得打上S或者K+数字哦. 

8.       8: 读取服务后,主机会读取/etc/rc.d/rc.local文件.所以,如果需要什么开机启动的话,可以写个脚本或命令到这里面来.就不用像上面那么麻烦.以后删除也方便.

        OK,经过一番长途跋涉后,系统终于可以安心的开启shell.把控制权交到我们手上了.我们可以为所欲为了.最好,养成好习惯,平时不要用root用户登陆.上次我就一不小心错输了poweroff.那可是网关服务器啊.全公司人都上不了网啊.还好跟他们已经热乎了.只是

linux系统脚本的常见启动顺序

由于相关变量定义不同, 所以以下启动顺序仅供参考

Redhat Redflag centos fc linux系统里面脚本的启动

先后:
第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端
rc.sysinit
rc.d(里面的脚本)
rc.local
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/etc/bashrc
/root/.bashrc
/root/.bash_profile

Suse Linux sles server or Desktop 10

第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端 /etc/init.d/boot 里面包括:
. /etc/rc.status
./etc/sysconfig/boot
./etc/init.d/boot.d下面的脚本
./etc/init.d/boot.local
rc X.d(里面的脚本)
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/root/.bashrc
/root/.profile
先后:
第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端
rc.sysinit
rc.d(里面的脚本)
rc.local
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/etc/bashrc
/root/.bashrc
/root/.bash_profile

Suse Linux sles server or Desktop 10

第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端 /etc/init.d/boot 里面包括:
. /etc/rc.status
./etc/sysconfig/boot
./etc/init.d/boot.d下面的脚本
./etc/init.d/boot.local
rc X.d(里面的脚本)
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/root/.bashrc
/root/.profile
先后:
第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端
rc.sysinit
rc.d(里面的脚本)
rc.local
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/etc/bashrc
/root/.bashrc
/root/.bash_profile

Suse Linux sles server or Desktop 10

第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端 /etc/init.d/boot 里面包括:
. /etc/rc.status
./etc/sysconfig/boot
./etc/init.d/boot.d下面的脚本
./etc/init.d/boot.local
rc X.d(里面的脚本)
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/root/.bashrc
/root/.profile

 

本文出自51CTO.COM技术博客

第一步:通过/boot/vm进行启动vmlinuz
第二步:init /etc/inittab
第三步:启动相应的脚本,并且打开终端
rc.sysinit
rc.d(里面的脚本)
rc.local
第四步:启动login登录界面login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的
/etc/profile.d/file
/etc/profile
/etc/bashrc
/root/.bashrc
/root/.bash_profile

0 0