【嵌入式Linux基础】启动初始化程序

您所在的位置:网站首页 嵌入式linux中断启动 【嵌入式Linux基础】启动初始化程序

【嵌入式Linux基础】启动初始化程序

2023-11-20 03:02| 来源: 网络整理| 查看: 265

文章目录 内核启动后初始化程序简介BusyBox initBuildroot init 脚本 后记

内核启动后

 内核引导代码在initramfs中通过内核命令行中的root=指定的文件系统中去寻找根系统文件,并执行一个相应的程序。在默认情况下,对于initramfs这个程序是/init,对于常规文件系统,是/sbin/init程序。init程序具有root权限,且因为它是第一个运行的进程,所以其进程ID(PID)是1。如果init程序未能启动,则内核将会崩溃。

 init程序是所有其他进程的祖先。在这里,通过pstree命令可以看出,在大部分版本中,init通常是psmisc包中的一部分:

# pstree -gn init(1)-+-syslogd(63) |-klogd(66) |-dropbear(99) `-sh(100)---pstree(109)

 init程序的任务是接管系统并使之运行。它和运行shell脚本的shell命令一样简单。

在启动阶段,它启动守护进程,配置系统参数,以及负责让系统进入工作状态所需要做的配置操作。作为可选项,它可以启动其他守护进程,如在终端上的getty守护进程,该进程允许登录shell。接收那些因为直接父进程被终止,以及线程组中没有其他进程而形成的孤儿进程。它通过捕捉信号SIGCHLD并收集其返回值以防止它们成为僵尸进程,对init的直接子进程的终止进行响应。作为一个可选项,它重新启动那些已经终止的守护进程。它处理系统关机。

换句话说,init管理着系统从开机到关机的整个生命周期。

初始化程序简介

 在嵌入式设备中,你最有可能遇到三个初始化程序是BusyBox init、System V init 和 systemd。Buildroot默认只构建BusyBox init,你也可以选择构建所有三个初始化程序。Yocto项目默认构建System V init,当然其他两种也可以选择。

类别Busy Box initSystem V initsystemd复杂性低中高启动速度快慢中所需shellashash 或 bash无可执行程序数量0450(构建系统时的配置支持的C库任意任意glibc大小(MB)00.134(构建系统时的配置

systemd的50个可执行程序、34MB的大小都是基于Buildroot的配置。

一般来说,从BusyBox init到 systemd,灵活性和复杂性都会逐渐增加。

BusyBox init

 BusyBox 的 init 程序最小,它使用配置文件/etc/inittab来定义规则,在系统启动阶段控制程序启动,在关机阶段控制程序终止。通常情况下,实际工作是由shell脚本来完成的,而按照惯例,脚本会放置在/etc/init.d目录下。

 init 首先会读取配置文件/etc/inittab。配置文件包含了一个需要运行的程序列表,一行一个,格式如下:

::: id:指令所针对的控制终端action:运行该指令的条件,将在下面的段落展示program:待运行的程序

运行该指令的条件(action字段)的可填写的内容:

sysinit:在其他所有类型的操作之前,当初始化开始时,运行程序。respawn:运行指定程序,如果程序终止则重新启动。askfirst:与respawn相同,但是这个会向控制台输出“Please press Enter to activate this console”,并在按下Enter键时运行该程序。它用于在终端上启动一个交互式shell,且不提示输入用户名或密码。once:运行指定程序,如果该程序终止,不会尝试重新启动它。wait:运行指定程序,并等待其完成。restart:当init接收到信号SIGHUP时,这表明其应该重新载入inittab文件,此时运行指定程序。ctrlaltdel:当init接收到信号SIGINT时运行指定程序,这通常是由于用户在控制台按下了 Ctrl+Alt+Del 组合按键。shutdown:当init关闭时运行指定程序。

这是一个完整的实际使用的inittab文件

# /etc/inittab # # Copyright (C) 2001 Erik Andersen # # Note: BusyBox init doesn't support runlevels. The runlevels field is # completely ignored by BusyBox init. If you want runlevels, use # sysvinit. # # Format for each entry: ::: # # id == tty to run on, or empty for /dev/console # runlevels == ignored # action == one of sysinit, respawn, askfirst, wait, and once # process == program to run # Startup the system ::sysinit:/bin/mount -t proc proc /proc ::sysinit:/bin/mount -o remount,rw / ::sysinit:/bin/mkdir -p /dev/pts ::sysinit:/bin/mkdir -p /dev/shm ::sysinit:/bin/mount -a 2>/dev/null ::sysinit:/bin/hostname -F /etc/hostname # now run any rc scripts ::respawn:-/bin/sh ::sysinit:/etc/init.d/rcS # Put a getty on the serial port #ttyFIQ0::respawn:/sbin/getty -L ttyFIQ0 0 vt100 # GENERIC_SERIAL # Stuff to do for the 3-finger salute #::ctrlaltdel:/sbin/reboot # Stuff to do before rebooting ::shutdown:/etc/init.d/rcK ::shutdown:/sbin/swapoff -a ::shutdown:/bin/umount -a -r

/etc/inittab文件中字段的意义

action名称执行条件说明sysinit系统启动后最先执行只执行一次,init进程等待它结束后才继续执行其他动作wait系统执行完sysinit进程后只执行一次,init进程等待它结束才继续执行其他动作once系统执行完wait进程后只执行一次,init进程不等待它结束respawn启动完once进程后init进程检测发现子进程退出时,重新启动它askfirst启动完respawn进程后与respawn进程类型,不过init进程先输出“Please press Enter to activate this console”,等用户输入回车键之后才启动子进程。shutdown当系统关机时执行即重启、关闭系统命令时restartBusyBox中配置了CONFIG_FEATURE_USE_INITTAB,并且init进程接收到SIGHUP信号时先重新读取、解析/etc/inittab文件,再执行restart程序ctrlaltdel按下 Ctrl+Alt+Del 组合键时

以下是一个小例子,包括挂载的 proc 和 sysfs ,以及在串行接口运行 shell:

null::sysinit:/bin/mount -t proc proc /proc null::sysinit:/bin/mount -t sysfs sysfs /sys console::askfirst:-/bin/sh

 对于简单的项目,比如你只想启动少量的守护进程,或者是在串口终端启动一个登录shell,手写一个脚本也很容易。这种情况下,如果你创建一个简单的定制的嵌入式Linux是很合适的。然而,你会发现随着需要配置的事情不断增加,手写一个init脚本很快就会变得非常难以维护。

Buildroot init 脚本

  多年以来,Buildroot有效使用了BusyBox 的init程序。Buildroot在/etc/init.d目录中有两个脚本,名为 rcS 和 rcK 。第一个脚本 rcS 在开机时运行,并从一个大写S加两位数字开始遍历所有的脚步,并按数字顺序运行,这就是开始脚本。rcK 脚本在关机时运行,从一个大写K 加两位数字开始遍历所有的脚本,并按数字顺序运行,这就是结束脚本。

 以上的做法也是存在的,实际上更多做法是在目录/etc/init.d里面只有众多的S开头的启动脚本,在S开头的脚本里面通过传入的参数start或者stop来执行开机时的操作逻辑或者关机时的操作逻辑。

一个典型实际使用的rcS脚本:

#!/bin/sh # Start all init scripts in /etc/init.d # executing them in numerical order. # for i in /etc/init.d/S??* ;do # Ignore dangling symlinks (if any). [ ! -f "$i" ] && continue case "$i" in *.sh) # Source shell script for speed. ( trap - INT QUIT TSTP set start . $i ) ;; *) # No sh extension, so fork subprocess. $i start ;; esac done

一个典型实际使用的rcK脚本:

#!/bin/sh # Stop all init scripts in /etc/init.d # executing them in reversed numerical order. # for i in $(ls -r /etc/init.d/S??*) ;do # Ignore dangling symlinks (if any). [ ! -f "$i" ] && continue case "$i" in *.sh) # Source shell script for speed. ( trap - INT QUIT TSTP set stop . $i ) ;; *) # No sh extension, so fork subprocess. $i stop ;; esac done

一个典型实际使用的S开头的用于alsa系统启动的脚本: S04alsa.sh

#!/bin/sh # case "$1" in start) if [ -f "/etc/asound.state" ];then alsactl restore -f /etc/asound.state fi #enable spk echo 1 > /proc/rp_power/spk_on echo 0 > /proc/rp_power/spk_mute ;; stop) echo "not stop function" ;; *) echo "Usage: $0 {start|stop}" exit 1 ;; esac

在操作系统中,一般系统的服务都是以后台进程的方式存在,而且都会常驻系统中,直到关机才结束。这类服务也称Daemon,在Linux系统中就包含许多的Daemon。判断Daemon最简单的方法就是从名称上看。多数的Daemon都是由服务名称加上d。例如,在Linux操作系统中HTTP服务的Deamon就是httpd。

 通过这一套机制,Buildroot包能够很容易地提供自己的开始脚本和结束脚本,并利用两个数字编号影响这些脚本的运行顺序,使其按照应有的顺序执行,从而使系统成为可扩展的。

后记

其他的init程序比如:System V init 和 systemd,笔者也没有使用过,有兴趣可以去看《嵌入式Linux编程》【Chris Simmonds】这本书的【第9章 启动初始化程序】的9.4和9.5小节。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3