LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4672|回复: 23

LFS启动脚本分析,以及相关配置文件理解

[复制链接]
发表于 2005-11-15 13:10:52 | 显示全部楼层 |阅读模式
想围绕这个主题,写点东西(想写得细一些)
先开个帖子,其他的内容等写好了,再陆续发上来
请大家指教



下面这个图是我对LFS整个启动过程的理解

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2005-11-15 14:43:13 | 显示全部楼层

init进程---inittab文件的理解

我们知道在LFS的启动过程中,首先是进行内核的初始化,然后载入inittab文件,启动init进程,init进程主要完成一下功能:
1.装载文件系统;
2.加载系统模块;
3.加载硬件设备文件;
4.启用交换分区;
5.检查文件系统
6.设置时钟,控制台和网络配置
7.启动登录进程(登录进程再启动bash,或者桌面系统)

很明显,要了解linux的启动过程,首先必须理解inittab文件的含义,典型的LFS系统的inittab文件如下:

#Begin /etc/inittab

id:3:initdefault:

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

10:0:wait:/etc/rc.d/init.d/rc 0
11:1:wait:/etc/rc.d/init.d/rc 1
12:2:wait:/etc/rc.d/init.d/rc 2
13:3:wait:/etc/rc.d/init.d/rc 3
14:4:wait:/etc/rc.d/init.d/rc 4
15:5:wait:/etc/rc.d/init.d/rc 5
16:6:wait:/etc/rc.d/init.d/rc 6

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

1:2345:respawn:/sbin/agetty -I '\033(K' tty1 9600
2:2345:respawn:/sbin/agetty -I '\033(K' tty2 9600
3:2345:respawn:/sbin/agetty -I '\033(K' tty3 9600
4:2345:respawn:/sbin/agetty -I '\033(K' tty4 9600
5:2345:respawn:/sbin/agetty -I '\033(K' tty5 9600
6:2345:respawn:/sbin/agetty -I '\033(K' tty6 9600

# End /etc/inittab

通常讲,inittab文件由以下格式命令组成
id:runlevels:action:process
这里:
id:是由1-4个字符组成的标识
runlevels:表示运行的级别,总共有0-6共7种级别,不同的级别具有不同的意义
        0级-----表示停机
        1级-----单用户模式
        2级-----多用户,但没有网络文件系统
        3级-----完全的多用户模式
        4级-----没有使用
        5级-----X11,桌面系统
        6级-----重启动
action:表示,init进程启动该进程后,应该采取的动作,这些动作有许多,其中
        sysinit------表示该进程在应该在系统启动的时候运行,该进程忽略运行级别
        wait   ------表示init进程,等待该子进程的结束
        ctrlaltdel---系统收到SIGINT信好启动该进程
        respawn------表示该进程退出后,init进程将再次启动该进程
        想知道更多,请 man inittab
procese:需要启动的进程

然后我们来分析一下init进程的启动过程,当我们以无参数的形式启动init进程时(如果有参数,参数表示运行级别,例如init 0表示关机):
首先,获得当前默认的运行级别runlevel
     id:3:initdefault:
     表示当前的默认运行级别;
然后,启动初始化进程
     si::sysinit:/etc/rc.d/init.d/rc sysinit
     该初始化进程以参数sysinit,运行/etc/rc.d/init.d/rc脚本忽略运行级别
接着:启动具体运行级别的初始化
     l0:0:wait:/etc/rc.d/rc 0
     l1:1:wait:/etc/rc.d/rc 1
     l2:2:wait:/etc/rc.d/rc 2
     l3:3:wait:/etc/rc.d/rc 3
     l4:4:wait:/etc/rc.d/rc 4
     l5:5:wait:/etc/rc.d/rc 5
     l6:6:wait:/etc/rc.d/rc 6
     注意,不是以上的进程都会运行,而是根据当前运行的级别,选择其中一个相应的级别的进程运行,例如默认级别为3,这里只运行l3:3:wait:/etc/rc.d/rc 3(个人理解,有待进一步证实)
最后:
     初始完成以后,将启动6个控制终端:
     1:2345:respawn:/sbin/mingetty tty1
     2:2345:respawn:/sbin/mingetty tty2
     3:2345:respawn:/sbin/mingetty tty3
     4:2345:respawn:/sbin/mingetty tty4
     5:2345:respawn:/sbin/mingetty tty5
     6:2345:respawn:/sbin/mingetty tty6
     每个终端登出后,将会被自动启动.mingetty进程,实现用户的用户名和密码的检查,然后启动/bin/bash.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-11-15 14:44:37 | 显示全部楼层
个人理解,难免有误,大家指正
回复 支持 反对

使用道具 举报

发表于 2005-11-15 17:40:22 | 显示全部楼层
good! 支持!
学习ing....
回复 支持 反对

使用道具 举报

发表于 2005-11-15 19:11:32 | 显示全部楼层
《鸟哥的LINUX私房菜:基础学习篇》这本书对这个问题又非常详细的说明,强烈推荐这本书!
这本书使我少走了不少弯路!
http://www.china-pub.com/computers/common/info.asp?id=25691

一并推荐《鸟哥的LINUX私房菜:服务器架设篇》
http://www.china-pub.com/computers/common/info.asp?id=25842

其实在作者的网站:http://linux.vbird.org/ 上这些资源都是开放的,不过都是繁体的!
回复 支持 反对

使用道具 举报

发表于 2005-11-15 20:32:30 | 显示全部楼层
Post by lingice
《鸟哥的LINUX私房菜:基础学习篇》这本书对这个问题又非常详细的说明,强烈推荐这本书!
这本书使我少走了不少弯路!
http://www.china-pub.com/computers/common/info.asp?id=25691

一并推荐《鸟哥的LINUX私房菜:服务器架设篇》
http://www.china-pub.com/computers/common/info.asp?id=25842

其实在作者的网站:http://linux.vbird.org/ 上这些资源都是开放的,不过都是繁体的!
还有电子版可下,不错!不错!
回复 支持 反对

使用道具 举报

发表于 2005-11-16 00:55:25 | 显示全部楼层
Great! 兄弟的态度令人钦佩啊!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-11-16 10:04:49 | 显示全部楼层
Post by lingice
《鸟哥的LINUX私房菜:基础学习篇》这本书对这个问题又非常详细的说明,强烈推荐这本书!
这本书使我少走了不少弯路!
http://www.china-pub.com/computers/common/info.asp?id=25691

一并推荐《鸟哥的LINUX私房菜:服务器架设篇》
http://www.china-pub.com/computers/common/info.asp?id=25842

其实在作者的网站:http://linux.vbird.org/ 上这些资源都是开放的,不过都是繁体的!

谢谢兄台提供的资料

我想写这方面的东西,主要是觉得启动脚本对lfs的应用很重要
另外,有很多不懂的地方,想和大家共同探讨.

望指教!
(下面对脚本进行注释,顺便学习一下shell脚本)
回复 支持 反对

使用道具 举报

发表于 2005-11-16 12:13:58 | 显示全部楼层
对大家有帮助就行!

共同学习,一起进步!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-11-16 13:10:01 | 显示全部楼层

初始化rc文件注释

在《init进程---inittab文件》理解中,我们知道,系统首先根据:
                                                id:3:initdefault:
设置默认的运行等级,在man inittab中是这么说明initdefault的:"一个initdefault入口具体地说明了系统启动后应该进入的运行级别,如果默认值不存在,那么init进程将要求控制台输入一个运行级别。process被域忽略"。对wait的说明是:"当机器进入该等级时,该进程将被启动一次.并且init进程等待它的结束"。
    以上的说明是我认为,机器启动时,如果默认等级为3时,只有13:3:wait:/etc/rc.d/init.d/rc 3运行的理由,通过试验,确实如此.。

系统初始化过程中,最重要的一个初始化脚本是/etc/rc.d/init.d/rc,可以看到所有的初始化都是通过给rc传递不同的参数而进行的.现在我们来分析rc脚本:

#!/bin/sh
# Begin $rc_base/init.d/rc - Main Run Level Control Script
# Based on rc script from LFS-3.1 and earlier.
# Rewritten by Gerard Beekmans  - gerard@linuxfromscratch.org

. /etc/sysconfig/rc
#载入/etc/sysconfig/rc,该文件声明了一些变量,内容如下
#rc_base=/etc/rc.d
#rc_functions=$rc_base/init.d/functions
#network_devices=/etc/sysconfig/network-devices

. $rc_functions
#包含一些基本的shell函数,这些函数在/etc/rc.d/init.d/functions中
#以后可以直接引用其中的函数

# This sets a few default terminal options.

stty sane
#man stty 改变和显示终端行的设置
#这个地方具体不明白

# These 3 signals will not cause our script to exit

trap "" INT QUIT TSTP
#trap命令设置信号的处理方式
#把INT QUIT TSTP的处理方式设为空,忽略这些信号的处理

[ "$1" != "" ] && runlevel=$1
#如果参数不为空,那么把该参数赋给runlevel
#比如/etc/rc.d/init.d/rc sysinit  那么runlevel=sysinit
#而/etc/rc.d/init.d/rc 0  那么runlevel=0

if [ "$runlevel" = "" ]
then
        echo "Usage: $0 <runlevel>" >&2
        exit 1
fi
#如果runlevel为空,则退出脚本(各位可以改动inittab试验一下)

previous=$PREVLEVEL
[ "$previous" = "" ] && previous=N
#把前一个运行的级别赋给previous
#如果前一个运行级别为空,则让它等于N
#这里主要是考虑到机器运行等级的改变,如果机器刚开始运行,那么前一个等级为为空
#没有找到PREVLEVEL的定义

if [ ! -d $rc_base/rc$runlevel.d ]
then
        echo "$rc_base/rc$runlevel.d does not exist"
        exit 1
fi
#判断目录/etc/rc.d/rc$runlevel.d,是否存在,如果不存在,那么退出
#其实就是判断rcsysinit.d ,rc0-6.d是否存在

# Attempt to stop all service started by previous runlevel,
# and killed in this runlevel

if [ "$previous" != "N" ]
#如果前一个运行等级不为N,也就是说不是刚开机,是机器运行等级的切换
#如果是刚开机,下面的不会运行
then
        for i in $(ls -v $rc_base/rc$runlevel.d/K* 2> /dev/null)
                #列/etc/rc.d/rc$runlevel.d目录下所有以K开头的脚本,对于其中的每个脚本做一下的操作
        #对于runlevel=0,为/etc/rc.d/rc0.d/K80network  /etc/rc.d/rc0.d/K90sysklogd
        do

                check_script_status
                                #首先调用functions中的函数check_script_status,检查脚本的状态
                                #check_script_status()
                                # {
                        #   if [ ! -f $i ]; then
                #           echo "$i is not a valid symlink"
                #           continue
                               #   fi
                                #   if [ ! -x $i ]; then
                #         echo "$i is not executable, skipping"
                #         continue
                               #    fi
                                # }
                                #作用是明显的,先检查是否存在,再判断是否可执行       

                suffix=${i#$rc_base/rc$runlevel.d/K[0-9][0-9]}
                                #这是一个字符串的模式匹配,i#$rc_base/rc$runlevel.d/K[0-9][0-9]表示对i从字符串的开头
                                #进行匹配,找到匹配最小rc_base/rc$runlevel.d/K[0-9][0-9],删除匹配部分,返回
                                #例如/etc/rc.d/rc0.d/K80network,那么这里删除/etc/rc.d/rc0.d/K80,suffic=network

                prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix
                                #赋给prev_start为前一个运行级别的目录下的S开头的文件
                                #如果suffix=network,那么
                                #prev_start=/etc/rc.d/rc$previous.d/S[0-9][0-9]network
                                #其中[0-9]表示集合匹配,也就是0-9之间的任何一个数字都匹配

                sysinit_start=$rc_base/rcsysinit.d/S[0-9][0-9]$suffix
                                #同上不过这里是rcsysinit.d目录下的

                if [ "$runlevel" != "0" ] && [ "$runlevel" != "6" ]
                                #如果不是关机(运行级别为0),或者重新启动(运行级别为6),那么做以下的action
                then
                        if [ ! -f $prev_start ] && [ ! -f $sysinit_start ]
                                                #如果前一个运行级别下,该服务(也就是i)不存在,而且在rcsysinit.d中也不存在,那么打印以下提示
                        then
                                echo -n -e $WARNING
                                echo "$i can't be executed because it was"
                                echo "not started in the previous runlevel ($previous)"
                                echo -n -e $NORMAL
                                continue
                                                                #其中WARING,.NORMAL在funtions中定义
                                                                #重新开始循环
                                                                #这部分好像没有被执行过,不过你去删除几个/etc/rc.d/init.d下的文件,就不一定了
                        fi
                fi
                $i stop
                                #以参数stop运行脚本,比如如果i是/etc/rc.d/rc0.d/K80network,那么就是停止网络了

                error_value=$?
                                # $? 表示上一个命令的返回值,如果上一条命令成功执行,则返回0,否则返回的是1-255之间的数

                if [ "$error_value" != "0" ]
                then
                        print_error_msg
                fi
                                #如果服务停止不成功,调用functions中的函数print_error_msg打印错误信息,可以看一下打印些什么
        done
fi

#Start all functions in this runlevel
for i in $( ls -v $rc_base/rc$runlevel.d/S* 2> /dev/null)
#列/etc/rc.d/rc$runlevel.d目录下所有以S开头的脚本,对于其中的每个脚本做一下的操作
#对于runlevel=sysinit,为
#/etc/rc.d/rcsysinit.d/S00mountkernfs
#/etc/rc.d/rcsysinit.d/S05modules
#/etc/rc.d/rcsysinit.d/S10udev
#/etc/rc.d/rcsysinit.d/S20swap
#/etc/rc.d/rcsysinit.d/S30checkfs
#/etc/rc.d/rcsysinit.d/S40mountfs
#/etc/rc.d/rcsysinit.d/S50cleanfs
#/etc/rc.d/rcsysinit.d/S60setclock
#/etc/rc.d/rcsysinit.d/S70console
#/etc/rc.d/rcsysinit.d/S80localnet    好多啊!

do
        if [ "$previous" != "N" ]
                #如果是运行级别的切换,而不是刚开机;刚开机不做以下action
        then
                suffix=${i#$rc_base/rc$runlevel.d/S[0-9][0-9]}
                                #同上,取后缀,比如runlevel=sysinit,则依次取mountkernfs modules udev swap checkfs mountfs cleanfs setclock console localnet
                stop=$rc_base/rc$runlevel.d/K[0-9][0-9]$suffix
                                #找到相应以K开头的文件
                prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix
                                #前一个运行等级目录下相应的文件
                [ -f $prev_start ] && [ ! -f $stop ] && continue
                                #如果前一个运行级别中该项服务存在,而且,当前运行级别中该项服务不需要停止,那么continue
                                #其实就是说,如果一项服务前一个运行级别已经开启,而且当前运行级别不需要关闭,那么就没有必要重新开启该项服务了
                                #直接检查下一项服务
        fi

        check_script_status
                #同样,检查一下脚本状态

        case $runlevel in
                0|6) $i stop    ;;
                                #如果是要关机或者重新启动,那么关闭该项服务,以stop为参数,运行该脚本
                *)   $i start   ;;
                                #其他的级别,那么开启服务,以start为参数
        esac

        error_value=$?
                #获得返回值

        if [ "$error_value" != "0" ]
        then
                print_error_msg
        fi
                #如果运行错误,打印错误提示信息
done

# End $rc_base/init.d/rc
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表