init进程
1.1 Linux根文件系统
init进程对应的程序文件位于根文件系统中,init进程调用的脚本也位于跟文件系统中。
关于根文件系统的详细信息,请参看:
1.2 Init机制systemD的区别
Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段:
- 内核的引导。
- 运行 init。
- 系统初始化。
- 建立终端 。
- 用户登录系统。
init程序的类型:
- SysV:**init**, CentOS 5之前, 配置文件: /etc/inittab。
- Upstart:init,CentOS 6, 配置文件: /etc/inittab, /etc/init/*.conf。
- Systemd:**systemd**, CentOS 7,配置文件: /usr/lib/systemd/system、 /etc/systemd/system。
1.3.Init进程的初始化总体流程
进程0:内核idle进程
进程1:init进程
进程2:shell进程
进程n:其他进程。
如下的这张图,是X86 Linux的初始化流程,嵌入式Linux是该流程的简化。
本文以X86 Linxu为描述对象。
位于根文件系统的init进程,负责根据etc目录中的各种配置文件,在用户空间对Linux系统进行初始化。
第1步骤:init进程的位置的位置
init 进程是系统所有进程的起点,你可以把它比拟成系统所有进程的老祖宗,没有这个进程,系统中任何进程都不会启动。
init 程序首先是需要读取配置文件 /etc/inittab。
try_to_run_init_process("/linuxrc") => 嵌入式Linux
try_to_run_init_process("/sbin/init")
try_to_run_init_process("/etc/init")
try_to_run_init_process("/bin/init")
try_to_run_init_process("/bin/sh")
第2步骤:利用/etc/inittab进行初始
许多程序需要开机启动。它们在Windows叫做"服务"(service),在Linux就叫做"守护进程"(daemon)。
init进程的一大任务,就是去运行这些开机启动的程序。
但是,不同的场合需要启动不同的程序,比如用作服务器时,需要启动Apache,用作桌面就不需要。
Linux允许为不同的场合,分配不同的开机启动程序,这就叫做"运行级别"(runlevel)。也就是说,启动时根据"运行级别",确定要运行哪些程序。
inittab为linux初始化文件系统时init初始化程序用到的 配置文件。
这个文件负责设置init初始化程序初始化脚本在哪里;每个运行级初始化时运行的命令; 开机、关机、重启对应的命令;各运行级登录时所运行的命令。
实际上,inittab定义的是:如何启动Linux的各种脚本。
2.1 格式
id:runlevels:action:process 其中某些部分可以为空
(1)id:指定指派给进程的用户标识
1~2个字符,配置行的唯一标识,在配置文件中不能重复。
(2)runlevels:指定进程运行等级
配置行适用的运行级别,在这里可填入多个运行级别,比如12345或者35等
Linux系统有7个运行级别(runlevel):
- 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
- 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登录
- 运行级别2:多用户状态(没有NFS)
- 运行级别3:完全的多用户状态(有NFS),登录后进入控制台命令行模式
- 运行级别4:系统未使用,保留
- 运行级别5:X11控制台,登录后进入图形GUI模式
- 运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动
备注:
所谓的运行等级,是指Linux不同的启动类型,包括关机、重启、正常单用户启动、多用户启动等。
不同的启动类型:
有些待执行的脚本在所有的情形下都需要执行。
有些待执行的脚本在不同的情形下是不相同的。如下:rc x脚本。
(4)process
指定所要执行的shell命令或进程。
(3)action:指定init进行如何管理进程
init有如下几种行为, init行为:
行为 | 描述 |
---|---|
respawn | 启动并监视第4项指定的process,若process终止则自动重启该进程 |
wait | 执行第4项指定的process,并等待它执行完毕 |
once | 执行第4项指定的process,启动后,无需等待进程的执行完毕,init进程也不会监控该进程。 |
boot | 不论在哪个执行等级,系统重新启动时都会运行第4项指定的process。 |
bootwait | 不论在哪个执行等级,系统启动时都会运行第4项指定的process,且一直等它执行完备 |
off | 关闭任何动作,相当于忽略该配置行 |
ondemand | 进入ondemand执行等级时,执行第4项指定的process |
initdefault | 系统启动后进入的执行等级,该行不需要指定process |
sysinit | 不论在哪个执行等级,系统会在执行boot 及bootwait之前执行第4项指定的process |
powerwait | 当系统的供电不足时执行第4项指定的 process,且一直等它执行完毕 |
powerokwait | 当系统的供电恢复正常时执行第4项指定的process,且一直等它执行完毕 |
powerfailnow | 当系统的供电严重不足时执行第4项指定的process |
ctrlaltdel | 当用户按下【Ctrl+Alt+Del】时执行的进程 |
kbrequest | 当用户按下特殊的组合键时执行第4项指定的process,此组合键需在keymaps文件定义 |
2.2 案例
# Begin /etc/inittab
id:3:initdefault: =》默认为执行等级3,具有网络功能的多用户字符界面。
si::sysinit:/etc/rc.d/init.d/rc.sysinit =》所有级别都执行的进程rc sysinit
l0:0:wait:/etc/rc.d/init.d/rc 0 =》不同的启动等级,执行不同的rc x。
l1:1:wait:/etc/rc.d/init.d/rc 1 =》 当运行级别改变时,负责启动/停止各种服务。
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6 =》不同的启动等级,执行不同的rc x。
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now =》当用户按下【Ctrl+Alt+Del】时执行的进程
su:S016:once:/sbin/sulogin
1:2345:respawn:/sbin/agetty tty1 9600 =》监控tty进程,若process终止则自动重启该进程
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600
# End /etc/inittab
第3步骤:利用/etc/rd.d/rc.sysinit进行初始化
在init的配置文件中有这么一行:
si::sysinit:/etc/rc.d/rc.sysinit1.
它调用执行了/etc/rc.d/rc.sysinit,而rc.sysinit是一个bash shell的脚本,它主要是完成一些系统初始化的工作,rc.sysinit是每一个运行级别都要首先运行的重要脚本。
它主要完成的工作有:激活交换分区,检查磁盘,加载硬件模块以及其它一些需要优先执行任务。
(1)主要功能
- HOSTNAME=
/bin/hostname
# 取得主机名 - HOSTTYPE=
uname -m
# 取得主机类型 - unamer=
uname -r
# 取得内核的 release 版本 - /etc/sysconfig/network # network 文件主要控制是否启用网络、默认网关、主机名
- HOSTNAME=localhost # 则将主机名设置为 "localhost"
- mount -n -t proc /proc /proc
- [ -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 脚本提供的函数”一文
备注:
/proc、sysfs等RAM文件系统在此时给mount起来,就可参看内核的信息了。
(2)示例
#!/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
}
第4步骤:利用/etc/rd.d/rc x 进行初始化
4.1 /etc/rd.d/rc.local
(1) 主要功能
- 启动根文件系统中的httpd服务
- 其他
(2) 示例
[root@localhost ~]# vi /etc/rc.d/rc.local
#!/bin/sh
#This script will be executed after all the other init scripts.
#You can put your own initialization stuff in here if you don’t
#want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
#默认会touch这个文件,每次系统启动时都会touch这个文件,这个文件的修改时间就是系统的启动时间
#写入想要启动系统并运行的语句
#例1:
/etc/rc.d/init.d/httpd start
#如果写入RPM包安装的apache服务的启动命令,apache服务就会在开机时自动启动
#例2:
[ -f /usr/local/gse/proxy/bin/gsectl ] && /usr/local/gse/proxy/bin/gsectl start > /var/log/gse_start.log 2>&1
#某系统的开机自启设置
4.2 /etc/rd.d/rc.x
l5:5:wait:/etc/rc.d/rc 5
这一行表示以5为参数运行/etc/rc.d/rc
/etc/rc.d/rc是一个Shell脚本,它接受5作为参数,去执行/etc/rc.d/rc5.d/目录下的所有的rc启动脚本,/etc/rc.d/rc5.d/目录中的这些启动脚本实际上都是一些连接文件,而不是真正的rc启动脚本,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。
而这些rc启动脚本有着类似的用法,它们一般能接受start、stop、restart、status等参数。
/etc/rc.d/rc5.d/中的rc启动脚本通常是K或S开头的连接文件,对于以 S 开头的启动脚本,将以start参数来运行。
而如果发现存在相应的脚本也存在K打头的连接,而且已经处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先以stop为参数停止这些已经启动了的守护进程,然后再重新运行。
这样做是为了保证是当init改变运行级别时,所有相关的守护进程都将重启。
至于在每个运行级中将运行哪些守护进程,用户可以通过chkconfig或setup中的"System Services"来自行设定。
第5步骤:初始化shell终端/sbin/agetty ttyx 9600
一般来说,用户的登录方式有三种:
- (1)命令行登录
- (2)ssh登录
- (3)图形界面登录
对于运行级别为5的图形方式用户来说,他们的登录是通过一个图形化的登录界面。登录成功后可以直接进入 KDE、Gnome 等窗口管理器。
而本小结主要讲的还是文本方式登录的情况:当我们看到mingetty的登录界面时,我们就可以输入用户名和密码来登录系统了。
Linux 的账号验证程序是 login,login 会接收 mingetty 传来的用户名作为用户名参数。
然后 login 会对用户名进行分析:如果用户名不是 root,且存在 /etc/nologin 文件,login 将输出 nologin 文件的内容,然后退出。
这通常用来系统维护时防止非root用户登录。只有/etc/securetty中登记了的终端才允许 root 用户登录,如果不存在这个文件,则 root 用户可以在任何终端上登录。
/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。
第6步骤:图形模式与文字模式的切换方式
Linux预设提供了六个命令窗口终端机让我们来登录。
默认我们登录的就是第一个窗口,也就是tty1,这个六个窗口分别为tty1,tty2 … tty6,你可以按下Ctrl + Alt + F1 ~ F6 来切换它们。
如果你安装了图形界面,默认情况下是进入图形界面的,此时你就可以按Ctrl + Alt + F1 ~ F6来进入其中一个命令窗口界面。
当你进入命令窗口界面后再返回图形界面只要按下Ctrl + Alt + F7 就回来了。
如果你用的vmware 虚拟机,命令窗口切换的快捷键为 Alt + Space + F1~F6. 如果你在图形界面下请按Alt + Shift + Ctrl + F1~F6 切换至命令窗口。
第7步骤:Linux 关机
在linux领域内大多用在服务器上,很少遇到关机的操作。毕竟服务器上跑一个服务是永无止境的,除非特殊情况下,不得已才会关机。
正确的关机流程为:sync > shutdown > reboot > halt
关机指令为:shutdown ,你可以man shutdown 来看一下帮助文档。
例如,你可以运行如下命令关机:
sync 将数据由内存同步到硬盘中。
shutdown 关机指令,你可以man shutdown 来看一下帮助文档。例如你可以运行如下命令关机:
shutdown –h 10 ‘This server will shutdown after 10 mins’ 这个命令告诉大家,计算机将在10分钟后关机,并且会显示在登陆用户的当前屏幕中。
shutdown –h now 立马关机
shutdown –h 20:25 系统会在今天20:25关机
shutdown –h +10 十分钟后关机
shutdown –r now 系统立马重启
shutdown –r +10 系统十分钟后重启
reboot 就是重启,等同于 shutdown –r now
halt 关闭系统,等同于shutdown –h now 和 poweroff
不管是重启系统还是关闭系统,首先要运行 sync 命令,把内存中的数据写到磁盘中。
关机的命令有 shutdown –h now halt poweroff 、init 0 ,
重启系统的命令有 shutdown –r now 、reboot 、init 6。
备注:
Linux系统有7个运行级别(runlevel):
运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登录
运行级别2:多用户状态(没有NFS)
运行级别3:完全的多用户状态(有NFS),登录后进入控制台命令行模式
运行级别4:系统未使用,保留
运行级别5:X11控制台,登录后进入图形GUI模式
运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动
结尾语
init进程是Linux在用户空间启动根文件系统中程序(脚本和可执行程序)的一种机制。
(1)它离不开根文件系统这个物理载体
(2)同时它还要考虑各种适应性,以适应各种不同的场合
(3)负责启动Linux在用户空间根文件系统中的程序
(4)复杂监控和管理需要由init进程监控和管理的进程,在需要的时候,由init进程自动重启这些进程。