Chinaunix首页 | 论坛 | 博客
  • 博客访问: 357477
  • 博文数量: 127
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 333
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-27 14:44
个人简介

兴趣是最好的学习契机!

文章分类

全部博文(127)

文章存档

2017年(1)

2016年(3)

2015年(54)

2014年(58)

2013年(11)

我的朋友

分类: LINUX

2015-07-24 09:50:03

原文地址:第2章引导和关机 作者:zbhknightMJ

引导:
打开计算机时,计算机执行储存在ROM中的引导代码,这些代码反过来试图确定如何加载并启动内核。内核检测系统的硬件,然后产生系统的init进程,这个进程总是PID1.在出现登录符之前,系统必须检查并安装文件系统,而且系统的守护进程必须启动起来。这些步骤是init进程按照顺序运行的一系列shell脚本来管理。启动脚本由于他们的命名方式而经常称作“rc文件”(run command)

2.1
引导过程的步骤:(六个阶段)
1、加载并初始化内核
2、检测和配置设备
3、创建自发的系统进程
4、操作员干预(仅用于手工引导)
5、执行系统启动脚本
6、多用户操作

内核初始化:
linux神秘的内核本身就是一个程序,第一个引导任务就是把这个程序载入内存。内核的路径名称通常是/vmlinuz或者/boot/vmlinuz.

硬件配置:
内核的第一件任务就是检查机器的环境以确定机器有什么硬件,并检测设备的驱动程序。自己构建内核的时候,应该告诉内核有哪些设备。

系统进程:
自发进程的数量和特性随系统的不同而不同。linux上看不到有PID0进程。和进程init(一定是进程1)一起的就是几个内存和内核处理进程,一般包括kflushd、kupdate、kpiod和kswapd。这些中,只有init是真正完整的用户进程。其他的都是内核的一部分,为了调度或者结构上的原因而进行了装扮。

操作员干预:

执行启动脚本:

多用户操作:
为了在某个特定终端(包括控制台)上接受用户登录,必须有一个getty进程监听终端或者控制台。init进程直接生成这些getty进程,完成引导过程。


2.5
启动脚本:
经常在启动脚本执行一下任务:
1、设置计算机名称
2、设置时区
3、采用fdisk检查磁盘
4、安装系统的磁盘
5、从/temp目录删除旧文件
6、配置网络接口
7、启动守护进程和网络服务

init和运行级:
传统的init定义了7个运行级
1、0级是完全关闭系统的级别
2、1级或者S级代表单用户模式
3、2到5级是多用户级别
4、6级是重新引导reboot的级别

   0和6级是特殊的,系统实际上不能停留在这两个级别里。正常多用户级别是2或者3,经常将运行级5用于X windows的登录进程。
   单用户模式的1级,关闭所有的多用户和远程登录进程,并确保系统运行在最小软件组合模式下。
   事实上/etc/inittab文件告诉init定义了系统进入到每一级别时要运行的命令。init从0级开始,一级一级往上。
   为了把inittab文件的内容映射成为某种更加灵活的东西,linux系统实现了另一层现象,采用“改变运行级”脚本的形式(通常为/etc/init.d/rc),由inittab来调用。这一脚本接下来执行位于与运行级有关的目录下其他脚本,从而把系统带入到新的状态。
   启动脚本的主拷贝位于叫做/etc/init.d目录中。每个脚本负责一个守护进程或者系统的某个特定方面。这些脚本能够识别参数start和stop,大多数还识别restart。作为系统管理员,只要手动运行与之有关的init.d脚本就可以了。
   当主脚本把系统引入到一个新的运行级别时,它不是直接在init.d目录查找,而是查找叫做rc(level).d的目录,例如rc0.d,rc1.d。
   在典型情况下,这些rc(level).d目录中包含的符号链接连接到了init.d目录的脚本上。这些符号链接懂得名称都以S或者K开头,后跟一个数字以及该脚本所控制的服务名(例如:S34named)。当init从低的运行级别向高的过度的时候,它按照数字递增地运行所有以S开头的、带有start参数的脚本。当从高向低过渡时,按照数字递减地运行所有以K开头,带有stop参数的脚本。根据不同的系统,init可能只查看适合于新运行级的rc(level).d目录,或者可以也查看旧运行级的目录,以找到两者的不同之处。

亲自体验:
1、进入/etc/init.d,打开rc文件,如下:
#! /bin/sh
#
# rc
#
# Starts/stops services on runlevel changes.
#
# Optimization: A start script is not run when the service was already
# configured to run in the previous runlevel.  A stop script is not run
# when the the service was already configured not to run in the previous
# runlevel.
#
# Authors:
#     Miquel van Smoorenburg
#     Bruce Perens

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

# Un-comment the following for interactive debugging. Do not un-comment
# this for debugging a real boot process as no scripts will be executed.
# debug=echo

# Specify method used to enable concurrent init.d scripts.
# Valid options are 'none', 'startpar' and 'makefile'. To enable
# the concurrent boot option, the init.d script order must allow for
# concurrency.  This is not the case with the default boot sequence in
# Debian as of 2008-01-20.  Before enabling concurrency, one need to
# check the sequence values of all boot scripts, and make sure only
# scripts that can be started in parallel have the same sequence
# number, and that a scripts dependencies have a earlier sequence
# number. See the insserv package for a away to reorder the boot
# automatically to allow this.
CONCURRENCY=none

# Make sure the name survive changing the argument list
scriptname="$0"

umask 022

on_exit() {
    echo "error: '$scriptname' exited outside the expected code flow."
}
trap on_exit EXIT # Enable emergency handler

# Ignore CTRL-C only in this shell, so we can interrupt subprocesses.
trap ":" INT QUIT TSTP

# Set onlcr to avoid staircase effect.
stty onlcr 0>&1

# Functions for splash progress bars
if [ -e /lib/init/splash-functions-base ] ; then
    . /lib/init/splash-functions-base
else
    # Quiet down script if old initscripts version without /lib/init/splash-functions-base is used.
    splash_progress() { return 1; }
    splash_stop() { return 1; }
fi

# Now find out what the current and what the previous runlevel are.

runlevel=$RUNLEVEL
# Get first argument. Set new runlevel to this argument.
[ "$1" != "" ] && runlevel=$1
if [ "$runlevel" = "" ]
then
    echo "Usage: $scriptname " >&2
    exit 1
fi
previous=$PREVLEVEL
[ "$previous" = "" ] && previous=N

export runlevel previous

if [ -f /etc/default/rcS ] ; then
    . /etc/default/rcS
fi
export VERBOSE

if [ -f /lib/lsb/init-functions ] ; then
    . /lib/lsb/init-functions
else
    log_action_msg() { echo $@; }
    log_failure_msg() { echo $@; }
    log_warning_msg() { echo $@; }
fi

#
# Stub to do progress bar ticks (for splash programs) on startup
#
startup_progress() {
    # Avoid divide by zero if anyone moved xdm/kdm/gdm first in a runlevel.
    if [ 0 -eq "$num_steps" ] ; then return; fi

    step=$(($step + $step_change))
    progress=$(($step * $progress_size / $num_steps + $first_step))
    $debug splash_progress "$progress" || true
}

#
# Check if we are able to use make like booting.  It require the
# insserv package to be enabled. Boot concurrency also requires
# startpar to be installed.
#
if [ "none" != "$CONCURRENCY" ] ; then
    test -s /etc/init.d/.depend.boot  || CONCURRENCY="none"
    test -s /etc/init.d/.depend.start || CONCURRENCY="none"
    test -s /etc/init.d/.depend.stop  || CONCURRENCY="none"
    startpar -v      > /dev/null 2>&1 || CONCURRENCY="none"
fi

#
# Start script or program.
#
case "$CONCURRENCY" in
    startpar|shell) # shell is obsolete
        log_action_msg "Using startpar-style concurrent boot in runlevel $runlevel"
        startup() {
            action=$1
            shift
            scripts="$@"

            # Update progress bar counter and jump to the new position
            for script in $scripts ; do
                step=$(($step + $step_change))
            done

            [ -n "$scripts" ] && $debug startpar -a $action $scripts

            # Jump back one step to compencate for stepping one
            # time too many in the for loop.
            step=$(($step - $step_change))
            startup_progress
        }
        ;;
    makefile)
        log_action_msg "Using makefile-style concurrent boot in runlevel $runlevel"
        # The splash API is not handled with this CONCURRENCY mode
        startup() {
            eval "$(startpar -p 4 -t 20 -T 3 -M $1 -P $previous -R $runlevel)"

            if [ -n "$failed_service" ]
            then
                log_failure_msg "startpar: service(s) returned failure: $failed_service"
            fi

            if [ -n "$skipped_service" ]
            then
                log_warning_msg "startpar: service(s) skipped: $skipped_service"
            fi

            unset failed_service skipped_service
        }
        ;;
    none|*)
        startup() {
            action=$1
            shift
            scripts="$@"
            for script in $scripts ; do
                $debug "$script" $action
                startup_progress
            done
        }
        ;;
esac

# Check if the splash screen should be stopped before the given
# script.
is_splash_stop_scripts() {
    scriptname=$1
    case "$scriptname" in
        # killprocs is used in runlevel 1
        gdm|xdm|kdm|ltsp-client|ltsp-client-core|reboot|halt|killprocs)
            return 0
            ;;
    esac
    return 1
}

# Is there an rc directory for this new runlevel?
if [ -d /etc/rc$runlevel.d ]
then
    # Find out where in the progress bar the initramfs got to.
    PROGRESS_STATE=0
    if [ -f /dev/.initramfs/progress_state ]; then
        . /dev/.initramfs/progress_state
    fi

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

    case "$runlevel" in
        0|6)
            ACTION=stop
            # Count down from 0 to -100 and use the entire bar
            first_step=0
            progress_size=100
            step_change=-1
            ;;
        S)
            ACTION=start
            # Begin where the initramfs left off and use 2/3
            # of the remaining space
            first_step=$PROGRESS_STATE
            progress_size=$(($progress_size * 2))
            step_change=1
            ;;
        *)
            ACTION=start
            # Begin where rcS left off and use the final 1/3 of
            # the space (by leaving progress_size unchanged)
            first_step=$(($progress_size * 2 + $PROGRESS_STATE))
            step_change=1
            ;;
    esac

    # Count the number of scripts we need to run
    # (for progress bars)
    num_steps=0
    for s in /etc/rc$runlevel.d/[SK]*; do
        if is_splash_stop_scripts "${s##/etc/rc$runlevel.d/S??}" ; then
            break
        fi
        num_steps=$(($num_steps + 1))
    done
    step=0

    if [ makefile = "$CONCURRENCY" ]
    then
        [ "$previous" != N ] && startup stop
    # First, run the KILL scripts.
    elif [ "$previous" != N ]
    then
        # Run all scripts with the same level in parallel
        CURLEVEL=""
        for s in /etc/rc$runlevel.d/K*
        do
            # Extract order value from symlink
            level=${s#/etc/rc$runlevel.d/K}
            level=${level%%[a-zA-Z]*}
            if [ "$level" = "$CURLEVEL" ]
            then
                continue
            fi
            CURLEVEL=$level
            SCRIPTS=""
            for i in /etc/rc$runlevel.d/K$level*
            do
                # Check if the script is there.
                [ ! -f $i ] && continue

                #
                # Find stop script in previous runlevel but
                # no start script there.
                #
                suffix=${i#/etc/rc$runlevel.d/K[0-9][0-9]}
                previous_stop=/etc/rc$previous.d/K[0-9][0-9]$suffix
                previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix
                #
                # If there is a stop script in the previous level
                # and _no_ start script there, we don't
                # have to re-stop the service.
                #
                [ -f $previous_stop ] && [ ! -f $previous_start ] && continue

                # Stop the service.
                SCRIPTS="$SCRIPTS $i"
                if is_splash_stop_scripts "$suffix" ; then
                    $debug splash_stop || true
                fi
            done
            startup stop $SCRIPTS
        done
    fi

    if [ makefile = "$CONCURRENCY" ]
    then
        if [ S = "$runlevel" ]
        then
            startup boot
        else
            startup $ACTION
        fi
    else
        # Now run the START scripts for this runlevel.
        # Run all scripts with the same level in parallel
        CURLEVEL=""
        for s in /etc/rc$runlevel.d/S*
        do
            # Extract order value from symlink
            level=${s#/etc/rc$runlevel.d/S}
            level=${level%%[a-zA-Z]*}
            if [ "$level" = "$CURLEVEL" ]
            then
                continue
            fi
            CURLEVEL=$level
            SCRIPTS=""
            for i in /etc/rc$runlevel.d/S$level*
            do
                [ ! -f $i ] && continue

                suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]}
                if [ "$previous" != N ]
                then
                    #
                    # Find start script in previous runlevel and
                    # stop script in this runlevel.
                    #
                    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.
                    #
                    if [ start = "$ACTION" ] ; then
                        [ -f $previous_start ] && [ ! -f $stop ] && continue
                    else
                        # Workaround for the special
                        # handling of runlevels 0 and 6.
                        previous_stop=/etc/rc$previous.d/K[0-9][0-9]$suffix
                        #
                        # If there is a stop script in the previous level
                        # and _no_ start script there, we don't
                        # have to re-stop the service.
                        #
                        [ -f $previous_stop ] && [ ! -f $previous_start ] && continue
                    fi

                fi
                SCRIPTS="$SCRIPTS $i"
                if is_splash_stop_scripts "$suffix" ; then
                    $debug splash_stop || true
                fi
            done
            startup $ACTION $SCRIPTS
        done
    fi
fi

trap - EXIT # Disable emergency handler

exit 0
好长好长阿!!!!!!
2、进入/etc,查看文件夹,ls,可以看到rc0.d rc1.d之类的文件夹
3、进入这些文件夹,果然看到很多以S和K开头的文件
4、ls -l可以看到全部是符号链接,指向目录/etc/init.d下的脚本,牛!!!
5、注意,这些脚本的配置文件全部放在目录/etc/init下,里面都是*.conf


2.6
重新引导和关机:
shutdown
halt
reboot

telinit:改变init的运行级
可以使用telinit直接init进入特定的运行级,例如:
telinit 1
让系统进入单用户模式

习题:
1、编写一个启动脚本,启动名为“foo”的守护进程(/usr/local/sbin/foo),它是一项网络服务。说明如何把它融入系统,在引导时刻自动启动

2、如果一个系统处于运行级4,运行命令telinit 1之后,init会采取那些步骤?命令的最终结果将会是什么?
http://blog.chinaunix.net/u3/113700/showart.php?id=2234683
http://blog.chinaunix.net/u3/113700/showart.php?id=2234684

阅读(799) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~