linux学习之系统启动过程

Published on Sep 28, 2016 ,3 min reading time

1.内核引导

操作系统接管硬件之后,首先读入/boot目录下的内核文件,本人使用ubuntu 15.10:

boot.png

2.启动初始化进程

没有这个进程,系统中任何进程都不会启动,从进程编号(pid)看出,init是第一个运行的程序:

ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 185192  5788 ?        Ss    3月03   0:10 /sbin/init splash

//各栏位意义,参考鸟哥私房菜
USER:该 process 属於哪个使用者帐号的?
PID :该 process 的程序识别码。
%CPU:该 process 使用掉的 CPU 资源百分比;
%MEM:该 process 所占用的实体内存百分比;
VSZ :该 process 使用掉的虚拟内存量 (Kbytes)
RSS :该 process 占用的固定的内存量 (Kbytes)
TTY :该 process 是在那个终端机上面运行,若与终端机无关则显示 ?,另外, tty1-tty6是本机上面的登陆者程序,若为 pts/0 等等的,则表示为由网络连接进主机的程序。
STAT:该程序目前的状态,状态显示与 ps -l 的 S 旗标相同 (R/S/T/Z)
START:该 process 被触发启动的时间;
TIME :该 process 实际使用 CPU 运行的时间。
COMMAND:该程序的实际命令为何?

所以第一个运行的程序是/sbin/init

3.运行级别

Linux中许多程序需要开机启动,称之为daemon(守护进程)init的进程的一大任务就是去运行这些开机启动的程序;那么linux怎么确定启动哪些程序呢?这就涉及到运行级别(runlevel),不同的运行级别启动不同的程序。

Linux系统有7个运行级别: 0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动 1:单用户工作状态,root权限,用于系统维护,禁止远程登陆 2:多用户状态(没有NFS) 3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式 4:系统未使用,保留 5:X11控制台,登陆后进入图形GUI模式 6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动

启动了init进程之后,其首先会读取/etc/inittab文件来进行初始化工作,就是查看运行级别,然后确定要启动的程序。

但这里要注意一个问题,现在的linux发行版本,主要有以下初始化方式,分别是sysvinit (System V initialization)、ubuntu的Upstart以及systemd,所以在ubuntu环境下,改用/etc/init/rc-sysinit.conf,以前的版本有可能是在/etc/event.d中。

所以在初始化的时候会读取rc-sysinit.conf并执行相关配置和脚本,其主要作用是设置系统默认runlevel(运行级别)。 下面是rc-sysinit.conf的代码:

# rc-sysinit - System V initialisation compatibility
#
# This task runs the old System V-style system initialisation scripts,
# and enters the default runlevel when finished.

description	"System V initialisation compatibility"
author		"Scott James Remnant <scott@netsplit.com>"

start on (filesystem and static-network-up) or failsafe-boot
stop on runlevel

# Default runlevel, this may be overriden on the kernel command-line
# or by faking an old /etc/inittab entry
env DEFAULT_RUNLEVEL=2      #默认运行级别为2

emits runlevel

# There can be no previous runlevel here, but there might be old
# information in /var/run/utmp that we pick up, and we don't want
# that.
#
# These override that
env RUNLEVEL=
env PREVLEVEL=

console output
env INIT_VERBOSE

task

script
    # Check for default runlevel in /etc/inittab
    if [ -r /etc/inittab ]
    then
	eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="\1";/p' /etc/inittab || true)"
    fi

    # Check kernel command-line for typical arguments
    for ARG in $(cat /proc/cmdline)
    do
	case "${ARG}" in
	-b|emergency)
	    # Emergency shell
	    [ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin
	    ;;
	[0123456sS])
	    # Override runlevel
	    DEFAULT_RUNLEVEL="${ARG}"
	    ;;
	-s|single)
	    # Single user mode
	    [ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S
	    ;;
	esac
    done

    # Run the system initialisation scripts
    [ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS

    # Switch into the default runlevel
    telinit "${DEFAULT_RUNLEVEL}"    #调用telinit进入设置的runlevel
end script```
通过代码可以看出其会检测是否存在/etc/inittab,说明该系统下也支持`sysvinit (System V initialization)`初始化方式,然后其设定的默认运行级别是2。
终端输入命令`runlevel`会返回当前运行级别,本机返回`N 2`;再看倒数第二行,`telinit "${DEFAULT_RUNLEVEL}" `调用了telinit进入了设定的runlevel。
再来看看当前目录下的rc.conf文件:
​``` shell
# rc - System V runlevel compatibility
#
# This task runs the old System V-style rc script when changing between
# runlevels.

description	"System V runlevel compatibility"
author		"Scott James Remnant <scott@netsplit.com>"

emits deconfiguring-networking
emits unmounted-remote-filesystems

start on runlevel [0123456]
stop on runlevel [!$RUNLEVEL]#这里$RUNLEVEL=2,表示非2就不启动

export RUNLEVEL
export PREVLEVEL

console output
env INIT_VERBOSE

task

script
if [ "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" -o "$RUNLEVEL" = "6" ]; then
    status plymouth-shutdown 2>/dev/null >/dev/null && start wait-for-state WAITER=rc WAIT_FOR=plymouth-shutdown || :
fi
/etc/init.d/rc $RUNLEVEL
end script

由代码/etc/init.d/rc $RUNLEVEL可看出/etc/init.d/rc接受参数$RUNLEVEL来调用/etc/rc${runlevel}.d/下的脚本,这里以/etc/rc2.d为例,列出该目录下的文件:

ls -l /etc/rc2.d
总用量 4
-rw-r--r-- 1 root root 677  6月 15  2015 README
lrwxrwxrwx 1 root root  21  3月 23 21:03 S05loadcpufreq -> ../init.d/loadcpufreq
lrwxrwxrwx 1 root root  17  3月 23 21:03 S16openvpn -> ../init.d/openvpn
lrwxrwxrwx 1 root root  22  3月 23 21:03 S19cpufrequtils -> ../init.d/cpufrequtils
lrwxrwxrwx 1 root root  17  3月 23 21:03 S20hddtemp -> ../init.d/hddtemp
lrwxrwxrwx 1 root root  20  3月 23 21:03 S20kerneloops -> ../init.d/kerneloops
lrwxrwxrwx 1 root root  20  3月 23 21:03 S20mintsystem -> ../init.d/mintsystem
lrwxrwxrwx 1 root root  15  3月 23 21:03 S20rsync -> ../init.d/rsync
lrwxrwxrwx 1 root root  27  3月 23 21:03 S20speech-dispatcher -> ../init.d/speech-dispatcher
lrwxrwxrwx 1 root root  32  3月 23 21:03 S20virtualbox-guest-utils -> ../init.d/virtualbox-guest-utils
lrwxrwxrwx 1 root root  15  3月 23 21:03 S50saned -> ../init.d/saned
lrwxrwxrwx 1 root root  19  3月 23 21:03 S70dns-clean -> ../init.d/dns-clean
lrwxrwxrwx 1 root root  18  3月 23 21:03 S70pppd-dns -> ../init.d/pppd-dns
lrwxrwxrwx 1 root root  17  3月 25 22:51 S91apache2 -> ../init.d/apache2
lrwxrwxrwx 1 root root  21  3月 23 21:03 S99grub-common -> ../init.d/grub-common
lrwxrwxrwx 1 root root  18  3月 23 21:03 S99ondemand -> ../init.d/ondemand
lrwxrwxrwx 1 root root  19  3月 24 00:03 S99prltoolsd -> ../init.d/prltoolsd
lrwxrwxrwx 1 root root  18  3月 23 21:03 S99rc.local -> ../init.d/rc.local

该目录下的文件名的命名形式都是字母S+两位数字+程序名,S表示start,如果是K,就表示kill,两位数字表示处理顺序,越小越早处理,如果数字相同,就按照字母顺序进行启动。 从中还可以看出这些文件的真正目录都在/etc/init.d目录下,这是为了防止在不同的运行级别下启动相同的程序,这样设置为链接提供了很大的方便。 后面执行login程序进行登录。 暂时over,以后对代码进行更加详细的说明。