您的位置:首页 > 运维架构 > Linux

linux 文件系统sysvinit 流程分析

2016-09-21 14:25 851 查看
参考网上许多的教程。

然后有一下相关的笔记:

kernel 在挂载完文件系统后,会执行第一个进程init

这个进程的PID为1

这个进程是所有进程的父进程

init 进程,首先要去读取inittab中的数据,根据这里面的数据去执行相关的初始化。

在inittab 可以指定默认的运行级别

  

id:5:initdefault:


还会规定第一个执行的程序

si::sysinit:/etc/init.d/rcS


//指定单用户模式
~~:S:wait:/sbin/sulogin


在TI的板子上还规定终端的显示的开关

0:2345:respawn:/sbin/getty 115200 ttyO0


这里提到,他规定下一个执行的是/etc/init.d/rcS

在/etc/init.d/rcS 内又做了哪些工作呢?

PATH=/sbin:/bin:/usr/sbin:/usr/bin                                 //设置环境变量
runlevel=S                                                                      //设置运行级别
prevlevel=N
umask 022                                                                       //设置默认权限补码
export PATH runlevel prevlevel                                          //对外发布这些变量


trap ":" INT QUIT TSTP
//这里话的含义是忽略ctrl + c中断信号


exec /etc/init.d/rc S    //运行/etc/init.d/rc    并加一个参数S


下面进入rc文件分析

# rc        This file is responsible for starting/stopping
#       services when the runlevel changes.

//在文件一开始,就说明了这个文件是当运行级别改变就要更改相关的服务


//设置终端,将 CR 字符映射为 NL 字符,避免阶梯效应
stty onlcr 0>&1


# Get first argument. Set new runlevel to this argument.
[ "$1" != "" ] && runlevel=$1
if [ "$runlevel" = "" ]
then
echo "Usage: $0 <runlevel>" >&2
exit 1
fi
//如果没有获取到运行级别就退出


previous=$PREVLEVEL
[ "$previous" = "" ] && previous=N

//传入参数是S的话,则$runleve=S $previous=N
export runlevel previous


//若$runlevel=“S”,即检查rcS.d是否为目录。
if [ -d /etc/rc$runlevel.d ]
then
//rcS.d是目录
PROGRESS_STATE=0

//Split the remaining portion of the progress bar into thirds
progress_size=$(((100 - $PROGRESS_STATE) / 3))//progress_size = 100/3 =33

case "$runlevel" in//runlevel=S
0|6)
first_step=-100
progress_size=100
step_change=1
;;
S)
//Begin where the initramfs left off and use 2/3of the remaining space
first_step=$PROGRESS_STATE ///progress_size = 100/3 =33
progress_size=$(($progress_size * 2))//progress_size=66
step_change=1
;;
*)
//Begin where rcS left off and use the final 1/3 ofthe space (by leaving progress_size unchanged)
first_step=$(($progress_size * 2 + $PROGRESS_STATE))
step_change=1
;;
esac


num_steps=0
for s in /etc/rc$runlevel.d/[SK]*; //s取/etc/rcS.d目录下以S或K开头的文件名
do
//这句话的含义去掉变量s中所有的/etc/rcS.d/S??的部分
//例:s=/etc/rc$runlevel.d/S10checkroot,那么去掉/etc/rc$runlevel.d/K??部分后,s为checkroot
case "${s##/etc/rc$runlevel.d/S??}" in
gdm|xdm|kdm|reboot|halt)//若s剩下的文件名中为这五个则跳出for语句
break
;;
esac
num_steps=$(($num_steps + 1))//num_steps递加,表示查找到此目录下/etc/rcS.d有多少个脚本
done//for语句结束


step=0
# First, run the KILL scripts.       首先运行KILL
if [ $previous != N ]                                    //由于previous = N ,所以一下不执行
then
for i in /etc/rc$runlevel.d/K[0-9][0-9]*
do
# Check if the script is there.
[ ! -f $i ] && continue

# Stop the service.
startup $i stop
done
fi


# Now run the START scripts for this runlevel.
for i in /etc/rc$runlevel.d/S*
do
[ ! -f $i ] && continue

if [ $previous != N ] && [ $previous != S ]     //由于previous为N所以跳过
then
#
# Find start script in previous runlevel and
# stop script in this runlevel.
#
suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]}
stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffix
previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix
#
# If there is a start script in the previous level
# and _no_ stop script in this level, we don't
# have to re-start the service.
#
[ -f $previous_start ] && [ ! -f $stop ] && continue
fi
case "$runlevel" in
0|6)
startup $i stop
;;
*)
startup $i start            //然后启动了相关的服务   运行在文件前面定义的 startup 函数
;;
esac
done
fi


startup函数有如下定义:

#
# Start script or program.
#
startup() {
# Handle verbosity
[ "$VERBOSE" = very ] && echo "INIT: Running $@..."

case "$1" in             //判断第一个参数,如果是一个脚本,执行第一个
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
scriptname=$1
shift                               //shift 命令每执行一次,变量的个数($#)减一,而变                    量值提前一位
. $scriptname                  //在执行第一个参数
)
;;
*)                            //如果不是一个脚本,那么认为是一个服务
"$@"
;;
esac
startup_progress             //再运行前一个函数
}


startup_progress 函数详解

startup_progress() {
step=$(($step + $step_change))
if [ "$num_steps" != "0" ]; then
progress=$((($step * $progress_size / $num_steps) + $first_step))
else
progress=$progress_size
fi
#echo "PROGRESS is $progress $runlevel $first_step + ($step of $num_steps) $step_change $progress_size"
#if type psplash-write >/dev/null 2>&1; then
#    TMPDIR=/mnt/.psplash psplash-write "PROGRESS $progress" || true
#fi
if [ -e /mnt/.psplash/psplash_fifo ]; then
echo "PROGRESS $progress" > /mnt/.psplash/psplash_fifo
fi
echo progress over...
}


最后,执行qt.sh

#Uncomment to cause psplash to exit manually, otherwise it exits when it sees a VC switch
if [ "x$runlevel" != "xS" ] && [ ! -x /etc/init.d/xserver-nodm ]; then
. /etc/init.d/qt.sh
#    if type psplash-write >/dev/null 2>&1; then
#        TMPDIR=/mnt/.psplash psplash-write "QUIT" || true
#       umount /mnt/.psplash
#    fi
fi


参考:
http://www.cnblogs.com/cnland/archive/2013/03/26/2981967.html https://wiki.archlinux.org/index.php/Arch_boot_process_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#Init_.E6.B5.81.E7.A8.8B http://blog.chinaunix.net/uid-17188120-id-4073497.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: