yocto中的init manager

前言

根据前文Linux根文件系统挂载流程中的分析,内核通过调用根文件系统中的init程序跳转到用户空间,并对用户空间所需的基础框架进行初始化。类比于内核启动时,需要对各个功能模块进行初始化,当进入用户空间时,也需要启动各项服务来搭建基础的应用环境。对于不同的init系统管理器,服务启动的方式有所区别,下文主要对yocto中使用的sysVinit、busybox init和systemd进行介绍。

sysVinit

在sysvinit中,服务由shell脚本提供,并且不同的runlevel包含不同的shell脚本集合,可将系统启动到具有不同服务的用户模式。其中,所有能够提供服务的shell脚本都包含在/etc/init.d目录下,对目录下的shell脚本进行不同的组合便可以组成具有不同服务的用户模式,即runlevel,其结构映射如下所示:
yocto中的init manager_第1张图片
如上图,可以将包含所有shell脚本的/etc/init.d看作一个服务库,通过提取库中的不同服务并组合便可以定制不同的系统模式,而系统启动到哪种模式,由配置文件/etc/inittab指定,/etc/inittab文件的内容由多个指定格式的项所组成,每一项的格式规定如下:

label:runlevel:action:process
  • label:标识符,与各项唯一对应,限于1-4个字节。其中,包括如下几个默认标识符的定义:
    • id:缺省的init运行级别。无实际执行内容,只是向init程序指示系统需要启动到哪个runlevel对应的模式。
    • si:系统初始化时启动的进程,在进入任何一个runlevel之前都需执行。
    • ln:指定进程在哪个/哪些runlevel下运行,n为runlevel的值。
    • ca:当检测到Ctrl+Alt+Del时启动的进程。
  • runlevel:运行级别,进入指定运行级别时启动对应的进程,各运行级别定义如下:
    • 0:Halt,关闭系统
    • 1:单用户模式,root权限,需输入root口令,进入该模式之前关闭所有应用和服务。
    • 2:无网络多用户模式
    • 3:有网络多用户模式(控制台命令行)
    • 4:保留,可供用户自行定义
    • 5:xwindow图形界面模式(图形GUI)
    • 6:重启系统
    • S/s:单用户模式(初始化),当系统初次启动或者从多用户模式切换到单用户模式时,该进程首先被执行。
  • action:如何运行该进程,有效的运行方式定义如下:
    • boot:系统引导期间执行。
    • bootwait:系统引导期间执行,并且等待该进程运行结束,该参数用于多用户模式。
    • sysinit:初始化时执行(boot、bootwait之前),runlevel域被忽略。
    • initdefault:特定用于指定系统引导进入的runlevel级别,若该项不存在,将通过控制台向用户询问。
    • respawn:自启动进程,当进程被终止时自动重启。
    • once:指定进程只启动一次。
    • off:终止进程,当启动到指定运行级别中发现指定进程处于运行状态,则终止该进程。
    • wait:等待进程运行结束才启动下一进程。
    • ctrlaltdel:当检测到当检测到Ctrl+Alt+Del时启动的进程。
  • process:可执行程序,即待启动进程。

以一个具体的文件作为示例:

id:5:initdefault:					//默认的运行级别为5
si::sysinit:/etc/init.d/rcS			//系统初始化首先运行/etc/init.d/rcS脚本
~~:S:wait:/sbin/sulogin				//单用户模式需要运行sbin/sulogin脚本
l0:0:wait:/etc/init.d/rc 0			//执行/etc/init.d/rc 传入参数0,等待脚本执行完毕
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6

sysvinit系统启动流程:

  1. init程序首先解析/etc/inittab文件,获取需要进入的runlevel模式
  2. 执行初始化进程(action=sysinit),进入单用户模式(s)?;
  3. 进入runlevel模式(执行shell脚本集合)。

根据以上示例可以看出:系统默认启动到图形化多用户模式(runlevel 5);然后执行初始化的rcS脚本,该rcS脚本会启动单用户模式(S)的脚本集合;进入单用户模式,启动sulogin;进入多用户模式,启动/etc/init.d/rc脚本并输入参数5,该进程将执行属于runlevel=5的脚本集合。

每个runlevel的脚本集合存储在对应的/etc/rc$(runlevel).d目录下,该目录下所有的文件为/etc/init.d的符号链接。当init.d中的文件不存在时,runlevel对应目录下的文件将不复存在。在yocto项目中,符号链接在编译阶段,通过 update.rc映射产生,并且生成shell脚本的执行顺序。update.rc的示例如下:

update-rc.d apache2 start 20 2 3 4 5 . stop 80 0 1 6 .

apache2为可执行程序的名称,start 20 2 3 4 5表示该服务在进入runlevel 2 3 4 5时需要执行,并在第20个启动。此时,update.rc将在runlevel 2 3 4 5中分别映射一个指向/etc/init.d/apache2的符号链接,名称均为S20apache2。stop 80 0 1 6表示在进入runlevel 0 1 6时需要禁止,并在第80个关闭。此时,update.rc将在runlevel 0 1 6 中分别映射一个指向/etc/init.d/apache2的符号链接,名称均为K80apache2。

sysvinit在进入对应runlevel时,根据/etc/init.d/rc可知,首先执行所有以K开头的脚本(传入脚本的参数为stop),然后执行所有以S开头的脚本(传入脚本的参数为start)。所有以K开头的脚本按照紧接着的数字,从小到大开始执行,相同数字的脚本按照创建顺序执行。同理,对于所有以S开头的脚本,其执行顺序遵循同样的规则。

busybox init

busybox是众多linux命令的一个工具集,根目录下的bin,sbin,usr和linuxrc通常就是Busybox。使用busybox时,kernel cmdline的init一般指向linuxrc,但是linuxrc最终还是会调用到/sbin/init这个真正的init进程。init进程的执行流如下:

  1. 为init进程设置信号处理进程
  2. 对控制台进行初始化
  3. 解析inittab文件,即etc/inittab,若无inittab文件,则采用默认的配置
  4. 执行/etc/init.d/rcS

busybox中/etc/inittab文件具有与sysvinit类似的格式,只是各字段定义有所区别:

id:runlevel_ignored:action:command
  • id:启动进程的控制终端,如shell终端
  • runlevel_ignored:该字段在busybox中被忽略,保持为空
  • action:进程启动方式,支持sysinit、wait、once、respawn、askfirst、ctratldel、shutdown和restart参数。系统启动期间,init进程首先启动sysinit、wait、once三类子进程,init进程会等待sysinit和wait进程结束,而不会等待once的进程结束,在系统正常运行期间,init程序启动respawn和askfirst两类子进程,并监视它们,在某个子进程退出时重新启动它。系统退出时,执行shutdown、restart和ctraltdel的三类子进程之一或全部。
  • command:可执行文件

由于busybox并不支持runlevel的概念,可以认为在busybox中只有一个runlevel,系统启动时自动跳转到该runlevel并执行启动脚本/etc/init.d/rcS。在yocto项目当中,通过配置/etc/inittab和/etc/init.d/rcS可以兼容sysvinit生成的脚本。

/etc/inittab文件
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mount -a

::sysinit:/etc/init.d/rcS

::ctrlaltdel:/sbin/reboot
::shutdown:/etc/init.d/rcK

init程序顺序执行含sysinit字段的进程,最后会调用etc/init.d/rcS(在没有inittab文件的情况下,init进程会默认查找rcS脚本文件并执行),通过设定/etc/init.d/rcS的内容如下,将自动启动所有在/etc/rcS.d和/etc/rc5.d中的脚本:

#!/bin/sh
for i in /etc/rcS.d/S??* /etc/rc5.d/S??* ;do					//查找etc/rcS.d和etc/rc5.d下所有以S开头的文件并执行
      case "$i" in
 	*.sh)
 	    # Source shell script for speed.
 	    (
 			trap - INT QUIT TSTP
 			set start
			. $i
 	    )
 	    ;;
 	*)
 	    $i start
 	    ;;
     esac
done

同理,可以设定/etc/init.d/rcK用于关闭所有的服务。

systemd

不同于sysvinit和busybox init的服务启动方式,systemd通过解析unit配置文件启动对应的服务,每一个unit中包含启动对应服务的方式、依赖项等信息。根据服务的类型,systemd将服务归为以下几类:

  • service:后台服务进程。
  • socker:封装文件系统或网络中的一个套接字,支持AF_INET,AF_INET6,AF_UNIX,还支持FIFIO。每一个socket unit需对应一个service unit。
  • device:封装linux设备树中的一个设备。如果该设备遵循udev rules,则该设备将在systemd中被抽象为一个device unit,并且在udev中设置的属性可以作为配置该unit依赖项的根据。
  • mount:挂载点(挂载目录)。systemd监控所有挂载点的状态,并且指示其挂载和卸载过程。此外,systemd兼容/etc/fstab对文件系统进行挂载。
  • automount:自动挂载点(挂载目录)。每一个automount unit对应一个mount unit,当挂载目录可用时,该目录即被按照automount unit中所设定的格式自动挂载。
  • target:unit集合,本身并不实现具体服务,只是封装对其他unit的索引,类似于sysV中runlevel对应的脚本集合,用于进入特定的系统模式。
  • snapshot:用于保存服务的状态或回滚,主要用于两种情形:暂停当前服务切换到emergency shell之后,恢复到service被暂停时的状态;服务被挂起之前关闭服务,之后重启到关闭前的状态。

systemd通过unit配置文件指明应调用哪个程序开启/关闭该服务,并指定该服务与其他服务之间的依赖关系。不像sysvinit中通过数字大小指定程序的运行顺序,systemd中通过before/after、require、wants、RequiredBy/WantedBy关键词来指定服务间的依赖关系。几个常用的描述依赖的名词解释如下:

  • before/after:表示在某个服务的之前/之后运行。
  • requires:表示在启动该项服务之前必须启动的服务列表,当需求的服务没有全部被成功启动时,该项服务便会启动失败。
  • wants:与requires功能一样,只是此时为弱依赖,即使其依赖的服务没有被成功启动,本服务也可以正常启动。
  • RequiredBy/WantedBy:与requires和wants对应,表示本服务被某项其他服务所依赖。

一个service unit的示例如下:

	[UNIT]
	Description=My custom service
	Requires=network.target								//在本服务启动之前,需先启动network.target
	
	[SERVICE]
	Type=simple
	ExecStart=/usr/bin/sleep infinity					//启动服务时执行的命令和参数
	
	[INSTALL]
	WantedBy=multi-user.target							//定义该服务在multi-user.target中启动

UNIT字段描述该项服务的基本信息以及配置与其他服务之间的依赖关系;SERVICE字段只有service unit才有,用于提供执行服务的指令;INSTALL字段主要用于定义启动的时机,是否开机启动 。

systemd中的/sbin/init程序为指向/usr/lib/systemd/systemd的一个符号链接,运行该init程序将执行systemd的初始化流程,使能default.target包含的所有服务,default.target类似于sysVinit中的默认runlevel,为一个服务集合,并由unit单元中的依赖关系所定义。systemd中的target和sysvinit中的runlevel存在如下对应关系:

	0			poweroff.target
	1、s		rescue.target
	2、3、4		multi-usr.target
	5			graphical.target
	6			reboot.target
	emergency	emergency.target

与sysVinit不同的是,graphical.target依赖于multi-user.target,即graphical.target包含multi-user.target的服务集合。服务通过sysctrl enable命令,自动将该服务映射到WantBy=所指向的target服务集合中,而当target被设置为default target时,该服务将在systemd启动时便开启。target的服务集合保存在/etc/systemd/system/**.target/wants目录下,目录下为存储在/etc/systemd/system/和/usr/lib/systemd/system/目录下服务unit的符号链接。即此时提供的服务库有两个(etc和usr),当两个库中包含同一各服务的unit单元时,/etc/目录下的unit 具有更高的优先级,即lib路径下的unit不会被解析,systemd中target的映射如下:
yocto中的init manager_第2张图片
systemd通过systemd-sysv-generator可以兼容sysvinit中的shell脚本。systemd-sysv-generator通过识别shell脚本的LSB头部信息,建立服务间的依赖关系并转化成unit单元。此外,systemd同样兼容/etc/fstab对文件系统的挂载方式,通过systemd-fstab-generator读取/etc/fstab配置文件,并将其中的每一条挂载项转换为systemd的本地unit,fstab中的auto标识会使systemd将其转换而成的service添加到local-fs.target或remote-fs.target的依赖中,使其在系统启动时自动挂载,而noauto则不会。对于同一挂载点,/etc/fstab的优先级低于/etc/目录下的.mount unit但是高于/usr/lib/目录下.mount unit。

systemd不支持sysV的服务在early boot阶段运行,都在basic.target之后运行。如果同一个服务在多个源中都有配置,如/etc/systemd/system/avahi.service和/etc/init.d/avahi,此时则忽略sysVinit中的服务,采用systemd本地的服务。

systemd支持模板机制,例如提供一个[email protected]的模板,根据该模板可以被实例化为[email protected]等。这个@后面的参数可以被service中的内容所继承。

sysvinit和systemd的服务生成过程对应如下,其添加服务的过程类似:在服务库中添加文件;通过工具/配置文件指定依赖关系,并添加到指定用户模式的服务集合中。

yocto中的init manager_第3张图片

yocto的init manager

根据core-image.bbclass,保证发行版正常启动的根文件系统包括如下几个packagegroup的内容:

CORE_IMAGE_BASE_INSTALL = '\
     packagegroup-core-boot \
     packagegroup-base-extended \
    \
    ${CORE_IMAGE_EXTRA_INSTALL} \
     '

其中,packagegroup-core-boot.bb的部分内容如下:

VIRTUAL-RUNTIME_dev_manager ?= "udev"
VIRTUAL-RUNTIME_login_manager ?= "busybox"
VIRTUAL-RUNTIME_init_manager ?= "sysvinit"
VIRTUAL-RUNTIME_initscripts ?= "initscripts"
VIRTUAL-RUNTIME_keymaps ?= "keymaps"

EFI_PROVIDER ??= "grub-efi"

SYSVINIT_SCRIPTS = "${@bb.utils.contains('MACHINE_FEATURES', 'rtc', '${VIRTUAL-RUNTIME_base-utils-hwclock}', '', d)} \
                    modutils-initscripts \
                    init-ifupdown \
                    ${VIRTUAL-RUNTIME_initscripts} \
                   "

RDEPENDS_${PN} = "\
    base-files \
    base-passwd \
    ${VIRTUAL-RUNTIME_base-utils} \
    ${@bb.utils.contains("DISTRO_FEATURES", "sysvinit", "${SYSVINIT_SCRIPTS}", "", d)} \
    ${@bb.utils.contains("MACHINE_FEATURES", "keyboard", "${VIRTUAL-RUNTIME_keymaps}", "", d)} \
    ${@bb.utils.contains("MACHINE_FEATURES", "efi", "${EFI_PROVIDER} kernel", "", d)} \
    netbase \
    ${VIRTUAL-RUNTIME_login_manager} \
    ${VIRTUAL-RUNTIME_init_manager} \
    ${VIRTUAL-RUNTIME_dev_manager} \
    ${VIRTUAL-RUNTIME_update-alternatives} \
    ${MACHINE_ESSENTIAL_EXTRA_RDEPENDS}"

RRECOMMENDS_${PN} = "\
    ${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS}"

由上可知,packagegroup至少包括base-files、base-passwd、VIRTUAL-RUNTIME_base-utils、VIRTUAL-RUNTIME_login_manager、VIRTUAL-RUNTIME_init_manager、VIRTUAL-RUNTIME_dev_manager、VIRTUAL-RUNTIME_update-alternatives几个package的内容。其中,具有RUNTIME_RUNTIME前缀的package可通过重写指定。如用户可以根据不同的发行版需求同的init manger:

VIRTUAL-RUNTIME_init_manager = 

当init_manager选择sysvinit时,还需要安装initscripts package,该package包括init.d目录下shell脚本的安装:

VIRTUAL-RUNTIME_initscripts =

当需要往开机自启动中添加自己的服务时,无论对于sysvinit还是systemd,首先需要向服务库中添加自己的服务(init.d中的shell脚本,systemd/system中的unit单元),然后将服务添加到默认启动的服务集合当中并指定执行的顺序/依赖(sysvinit 通过update.rc,systemd中通过uint配置和systemdctrl 实现),yocto中存在update.rc和systemd的类来实现对应的功能。

sysVinit添加服务

对于sysVinit而言,需要在.bb文件中inherit update.rc:

inherit update.rc
INITSCRIPT_PACKAGES ?=	"${PN}"						#服务存在的package,默认为bb文件的name
INITSCRIPT_NAME =	“first”							#服务的名称
INITSCRIPT_PARAMS = "defaults 97"					#服务的启动/关闭的顺序和所属runlevel

当需要在同一个.bb文件中安装多个服务时,可以将服务置于不同的package中,并利用关键词分别对这些服务指定运行顺序,分别在${PN}和${PN}-second两个package中存在一个服务时,如下配置:

FILES_${PN}-second	=	“ \
	${sysconfdir}/init.d/second.sh
”

INITSCRIPT_PACKAGES =	“${PN} ${PN}-second”							
INITSCRIPT_NAME_${PN} =	“first.sh”							
INITSCRIPT_PARAMS = 	"defaults 97"										//对first进行映射
INITSCRIPT_NAME_${PN}-second =	“second.sh”							
INITSCRIPT_PARAMS${PN}-second = 	"start 20 2 3 4 5 . stop 80 0 1 6 ."	//对second进行映射

.bb文件生成package时通过do_install过程实现的,默认package的名称为${PN},内容为本.bb文件do_install任务所有安装到根文件系统目录下的文件,当将do_install中的文件指定到特定的package中时,${PN}中将不再包含对应的内容,即先打包其他的package,最后剩余的统一打包到${PN}。如下,${PN}中的内容就是除了${PN}-second中的first文件。

do_install () {
    install -d ${D}${sysconfdir}/init.d
    install -m 0755 ${THISDIR}/files/${MACHINE}/script/first ${D}/${sysconfdir}/init.d/first
	install -m 0755 ${THISDIR}/files/${MACHINE}/script/second ${D}/${sysconfdir}/init.d/second

    install -d ${D}${systemd_unitdir}/system/
    install -m 0644 ${THISDIR}/files/${MACHINE}/script/first.service ${D}${systemd_unitdir}/system
	install -m 0644 ${THISDIR}/files/${MACHINE}/script/second.service ${D}${systemd_unitdir}/system
}

FILES_${PN}-second ="\
	${D}/${sysconfdir}/init.d/second
	${D}${systemd_unitdir}/system/second.service
"

INITSCRIPT_PACKAGES += "${PN}-second"

systemd

对于systemd而言,则需要inherit systemd:

inherit systemd
SYSTEMD_PACKAGES ?= "${PN}"
SYSTEMD_SERVICE = “first.service”								//提供服务unit配置文件

当需要在同一个.bb文件中提供多个服务时,可以采用与sysvinit中同样的方式,即将不同的service分别安装到不同的package中。但是systemd的依赖关系存在于各自的unit单元中,并不一定需要为每个service单独一个package,而是可以按如下方式指定:

inherit systemd
SYSTEMD_PACKAGES ?= "${PN}"
SYSTEMD_SERVICE_${PN} = “first.service second.service”

由于在systemd中包含如下默认配置,因此所有通过上述关键词声明的服务都将在开机时自动启动:

SYSTEMD_AUTO_ENABLE  ??= “enable”

上述语句相当于调用systemctl enable xx.service。当不想让服务开机自启动时,可以在.bb文件中显示的失能该功能,在需要的时候通过手动调用systmctl命令启动:

SYSTEMD_AUTO_ENABLE  = “disable”

当然,无论是sysvinit还是systemd,开机自启动能够成立的前提是:在do_install task中已将对应的服务放置到的/etc/init.d目录下或者在etc/systemd/system目录下了

sysVinit和systemd兼容

yocto中可以根据需要建立多个发行版,并根据DISTRO变量自动切换使用不同的initmanager,为了在同一个.bb文件中兼容两种init manager的格式,可以将sysvinit和systemd需要包含的文件同时包含到一个package,当在distro配置文件中选择使用其中一个而失能另一个init manager时,bitbake会自动删除package中不需要的文件(失能的init manager安装到package中的文件):

inherit update.rc systemd
FILES_${PN}-second	=	“ \
	${sysconfdir}/init.d/second.sh
	${D}${systemd_unitdir}/system/second.service
”

INITSCRIPT_PACKAGES =	“${PN} ${PN}-second”							
INITSCRIPT_NAME_${PN} =	“first.sh”							
INITSCRIPT_PARAMS = 	"defaults 97"
INITSCRIPT_NAME_${PN}-second =	“second.sh”							
INITSCRIPT_PARAMS${PN}-second = 	"start 20 2 3 4 5 . stop 80 0 1 6 ."

SYSTEMD_PACKAGES =	“${PN} ${PN}-second”	
SYSTEMD_SERVICE_${PN} =	“${PN} ${PN}-second”	
SYSTEMD_SERVICE_${PN}-second ="second.service"

distro配置文件中一般默认的init manager为sysvinit,当需要选用systemd时,应该添加systemd到DISTRO_FEATURE项中:

DISTRO_FEATURES_append = " systemd"

当使能systemd并且删除sysvinit中包含的文件时,通过如下关键词进行配置:

DISTRO_FEATURES_BACKFILL_CONSIDERED +=	“sysvinit”

删除失能的init manager包含的文件由systemd.bbclass实现:

python rm_systemd_unitdir (){
    import shutil
    if not bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d):							#没有使能systemd,使能了sysvinit时		
        systemd_unitdir = oe.path.join(d.getVar("D"), d.getVar('systemd_unitdir'))
        if os.path.exists(systemd_unitdir):
            shutil.rmtree(systemd_unitdir)
        systemd_libdir = os.path.dirname(systemd_unitdir)
        if (os.path.exists(systemd_libdir) and not os.listdir(systemd_libdir)):
            os.rmdir(systemd_libdir)
}
do_install[postfuncs] += "rm_systemd_unitdir "														#安装之后立即执行该函数

python rm_sysvinit_initddir (){
    import shutil
    sysv_initddir = oe.path.join(d.getVar("D"), (d.getVar('INIT_D_DIR') or "/etc/init.d"))

    if bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d) and \						#使能了systemd并失能了sysvinit时
        not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d) and \
        os.path.exists(sysv_initddir):
        systemd_system_unitdir = oe.path.join(d.getVar("D"), d.getVar('systemd_system_unitdir'))

        # If systemd_system_unitdir contains anything, delete sysv_initddir
        if (os.path.exists(systemd_system_unitdir) and os.listdir(systemd_system_unitdir)):
            shutil.rmtree(sysv_initddir)
}
do_install[postfuncs] += "rm_sysvinit_initddir "

systemd各task的执行顺序如下,添加服务时可以根据该执行顺序指定添加服务的依赖关系:

local-fs-pre.target
         |
         v
(various mounts and   (various swap   (various cryptsetup
 fsck services...)     devices...)        devices...)       (various low-level   (various low-level
         |                  |                  |             services: udevd,     API VFS mounts:
         v                  v                  v             tmpfiles, random     mqueue, configfs,
  local-fs.target      swap.target     cryptsetup.target    seed, sysctl, ...)      debugfs, ...)
         |                  |                  |                    |                    |
         \__________________|_________________ | ___________________|____________________/
                                              \|/
                                               v
                                        sysinit.target
                                               |
          ____________________________________/|\________________________________________
         /                  |                  |                    |                    \
         |                  |                  |                    |                    |
         v                  v                  |                    v                    v
     (various           (various               |                (various          rescue.service
    timers...)          paths...)              |               sockets...)               |
         |                  |                  |                    |                    v
         v                  v                  |                    v              rescue.target
   timers.target      paths.target             |             sockets.target
         |                  |                  |                    |
         v                  \_________________ | ___________________/
                                              \|/
                                               v
                                         basic.target
                                               |
          ____________________________________/|                                 emergency.service
         /                  |                  |                                         |
         |                  |                  |                                         v
         v                  v                  v                                 emergency.target
     display-        (various system    (various system
 manager.service         services           services)
         |             required for            |
         |            graphical UIs)           v
         |                  |           multi-user.target
         |                  |                  |
         \_________________ | _________________/
                           \|/
                            v
                  graphical.target

参考

sysvinit:
https://blog.csdn.net/ranran0224/article/details/61196466
https://blog.csdn.net/wince_lover/article/details/52503405
https://www.ibm.com/developerworks/cn/linux/l-lpic1-v3-101-3/index.html
sysvinit源码分析
update-rc.d更新linux系统启动项
https://manpages.debian.org/testing/sysvinit-core/init.8.en.html

busybox init
https://blog.csdn.net/shanzhizi/article/details/39082495
http://blog.chinaaet.com/weiqi7777/p/5100052805
https://blog.csdn.net/s651665496/article/details/50773073

systemd
http://0pointer.de/blog/projects/systemd.html
http://www.wowotech.net/linux_application/why-systemd.html
https://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html
https://fedoraproject.org/wiki/Systemd/zh-cn
http://www.jinbuguo.com/systemd/systemd.service.html
https://unix.stackexchange.com/questions/233468/how-does-systemd-use-etc-init-d-scripts/233581#233581
https://www.cnblogs.com/sparkdev/p/8472711.html
http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html
https://www.linuxidc.com/Linux/2015-05/117640.htm

你可能感兴趣的:(yocto,Linux)