[架构之路-32]:目标系统 - 系统软件 - Linux OS用户空间程序的启动关闭监管 -- init进程

Posted 文火冰糖的硅基工坊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[架构之路-32]:目标系统 - 系统软件 - Linux OS用户空间程序的启动关闭监管 -- init进程相关的知识,希望对你有一定的参考价值。

目录

第1章 Init进程的初始化总体流程

1.1 Linux根文件系统

1.2 Init机制systemD的区别

1.3.Init进程的初始化总体流程

第1步骤:init进程的位置的位置

第2步骤:利用/etc/inittab进行初始

2.1 格式

2.2 案例

第3步骤:利用/etc/rd.d/rc.sysinit进行初始化

第4步骤:利用/etc/rd.d/rc x 进行初始化

4.1 /etc/rd.d/rc.local

4.2 /etc/rd.d/rc.x

第5步骤:初始化shell终端/sbin/agetty ttyx 9600

第6步骤:图形模式与文字模式的切换方式

第7步骤:Linux 关机

结尾语


第1章 Init进程的初始化总体流程

1.1 Linux根文件系统

init进程对应的程序文件位于根文件系统中,init进程调用的脚本也位于跟文件系统中。

关于根文件系统的详细信息,请参看:

[架构之路-30]:目标系统 - 系统软件 - Linux OS根文件系统rootfs的概念、组成、制作以及用busybox制作根文件系统_文火冰糖的硅基工坊的博客-CSDN博客

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。

init和systemD都是Linux提供的在用户空间初始化Linux系统、初始化应用程序进程、管理应用程序进程的机制。init先与sysmteD的机制,关于他们的区分,请参看:

[架构之路-31]:目标系统 - 系统软件 - Linux OS 什么是Linux1号进程? init进程与systemD的比较?_文火冰糖的硅基工坊的博客-CSDN博客

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.sysinit 

它调用执行了/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进程自动重启这些进程。

以上是关于[架构之路-32]:目标系统 - 系统软件 - Linux OS用户空间程序的启动关闭监管 -- init进程的主要内容,如果未能解决你的问题,请参考以下文章

[架构之路-11]:目标系统 - 架构 - 嵌入式系统软件+硬件的基本通用架构

[架构之路-56]:目标系统 - 平台软件 - 总体架构概述

[架构之路-19]:目标系统 - 硬件平台 - 案例1 - 用单片机STM8/STM32搭建目标系统(以无线传感器LoRa终端为例)

[架构之路-28]:目标系统 - 系统软件 - Linux OS内核功能架构图解内核构建内核启动流程

[架构之路-18]:目标系统 - 硬件平台 - 案例1 - 单片机MCU STM32 芯片的工作原理与启动流程

[架构之路-25]:目标系统 - 系统软件 - bootloader uboot内存映射与启动流程