
Linux系统的快速初始化。 Claudio Matsuoka从Eeepc FastInit进行了反向设计 - “充满青蛙DNA的差距……”

图1:有限引导Alpine Linux(HowTO)的屏幕截图。
功能包括:
/etc/rc.local支持/etc/network/interfacesinitctl top中的配置和监视sulogin的适当救援模式,用于受保护的维护外壳syslogd启动之前,登录到内核环缓冲区,请参阅推荐的Sysklogd项目,以完成日志记录集成以及如何使用logger从脚本中登录到内核环缓冲区专注于小型和嵌入式系统,尽管在服务器和桌面系统上也完全可以使用。有关工作的示例,请参阅带有以下Linux分布的教程的贡献/部分:
注意:对各种Linux发行版的支持并不意味着所有架构都可以轻松安装。捆绑的安装脚本是标准安装的示例,在AMD64(X86_64)系统上测试。自定义设置(例如,用于嵌入式系统)可以在以下任何基于构建根的示例中找到:Mylinux,Infix或Plain Br2-Finit-Demo。
此示例/etc/finit.conf也可以在/etc/finit.d中的多个.conf文件中拆分。可用但尚未启用,可以将服务放置在/etc/finit.d/available中,并由运营商使用Initctl工具启用。请参阅上述Linux发行版或Mylinux。
注意:从有限的v4.4开始,可以使用标准UNIX持续字符(
)分解.conf行,现在也支持尾随注释。后者意味着您需要逃避指令和描述(#)中使用的任何哈希。有关此信息和示例的更多信息,请参见finit.conf(5)手册或doc/config.md。
# Fallback if /etc/hostname is missing
host default
# Runlevel to start after bootstrap, 'S', default: 2
# runlevel 2
# Support for setting global environment variables, using foo=bar syntax
# be careful though with variables like PATH, SHELL, LOGNAME, etc.
# PATH=/usr/bin:/bin:/usr/sbin:/sbin
# Max file size for each log file: 100 kiB, rotate max 4 copies:
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
log size=100k count=4
# Services to be monitored and respawned as needed
service [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemon
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemon
service [S12345] < pid /syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
service [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab)
# The BusyBox ntpd does not use syslog when running in the foreground
# So we use this trick to redirect stdout/stderr to a log file. The
# log file is rotated with the above settings. The condition declares
# a dependency on a system default route (gateway) to be set. A single
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
service [2345] log:/var/log/ntpd.log <!net/route/default> ntpd -n -l -I eth0 -- NTP daemon
# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
service :80 [2345] merecat -n -p 80 /var/www -- Web server
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
# Alternative method instead of below runparts, can also use /etc/rc.local
# sysv [S] /etc/init.d/keyboard-setup -- Setting up preliminary keymap
# sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
# task [S] /etc/init.d/kbd -- Preparing console
# Hidden from boot progress, using empty `--` description
# sysv [S] /etc/init.d/keyboard-setup --
# sysv [S] /etc/init.d/acpid --
# task [S] /etc/init.d/kbd --
# Run start scripts from this directory
# runparts /etc/start.d
# Virtual consoles run BusyBox getty, keep kernel default speed
tty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait noclear
tty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait noclear
tty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear
# Use built-in getty for serial port and USB serial
# tty [12345] /dev/ttyAMA0 noclear nowait
# tty [12345] /dev/ttyUSB0 noclear
# Just give me a shell, I need to debug this embedded system!
# tty [12345] console noclear nologin service节以及task run和其他任务都在Doc/Config.md中全面描述。这是启动Unix守护程序所需的一些最常见组件的快速概述:
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | `---------- Optional description
| | | | | | `------------------ Daemon arguments
| | | | | `------------------------- Path to daemon
| | | | `---------------------------------------------------- Optional env. file
| | | `-------------------------------------------------------- Redirect output to log
| | `--------------------------------------------------------------- Optional conditions
| `---------------------------------------------------------------------- Optional Runlevels
`------------------------------------------------------------------------------ Monitored application
一些组件是可选的:runlevel(s),条件(S)和描述,使创建简单的启动脚本变得容易,并且对于更高级的用途也很可能:
service /usr/sbin/sshd -D
使用条件处理依赖项。最常见的条件之一是等待基本网络可用:
service <net/route/default> nginx -- High performance HTTP server
这是另一个示例,我们指示有限在syslogd正常启动之前不要启动busybox ntpd 。有限等待syslogd创建其PID文件,默认情况下/var/run/syslogd.pid 。
service [2345] log <!pid/syslogd> ntpd -n -N -p pool.ntp.org
service [S12345] syslogd -n -- Syslog daemon
请注意log关键字,BusyBox ntpd使用stderr在前景中运行时记录。使用log Finit将stdout + stderr重定向到系统日志守护程序,使用命令行logger(1)工具。
服务或任务可以列出多个依赖关系。在这里,我们等待两个syslogd启动并基本网络启动:
service [2345] log <pid/syslogd,net/route/default> ntpd -n -N -p pool.ntp.org
如果两种条件失败,例如网络丢失, ntpd会停止,并且一旦再次恢复, ntpd就会自动重新启动。
注意:确保守护程序不会像上面的openssh一样,不朝着控制tty(通常是-n或-f标志)或-D分离。如果它自行拆下,则无法监视它,而是尝试重新启动它。
过程监督
如果他们失败,请开始,监视和重新启动服务。
盖蒂
有限支持外部盖蒂,但还具有有限的内置盖蒂,对非常小的系统有用。盖蒂(Getty)设置了TTY并等待用户输入,然后再移交给/bin/login ,该bin /login负责处理实际的身份验证。
tty [12345] /dev/tty1 nowait linux
tty [12345] /dev/ttyAMA0 noclear vt100
tty [12345] /sbin/getty -L /dev/ttyAMA0 vt100
嵌入式系统的用户可能需要使用特殊@console设备启用自动串行控制台。无论天气如何,系统都使用ttyS0 , ttyAMA0 , ttyMXC0或其他任何东西。通过查询sysfs: /sys/class/tty/console/active来确定它。
tty [12345] @console linux noclear
请注意,可选的noclear , nowait和nologin Flags。后者是为了完全跳过登录过程。有关更多信息,请参见Doc/config.md。
跑步
可以提供对SYSV Init-style runlevels的支持,其最小风格与有限的其他所有内容相同。 [2345]语法可以应用于服务,任务,运行和TTY stanzas。
保留的跑步分别为0和6,停止和重新启动,就像SYSV Init一样。可以自由配置runlevel 1,但建议保留为系统单用户runlevel,因为有限不会在此处启动网络。从/etc/finit.conf中配置的runlevel NUM是Bootstrap之后的有限更改,除非在内核CMDLine上给出“单个”(或“ S”),在这种情况下,启动了Runlevel 1。
Runlevel S中的所有服务首先启动,其次是所需的Run Time Runlevel。可以使用run [S] cmd在Runlevel S中的运行任务序列。在运行时更改运行时,就像其他任何初始化一样,例如INIT 4 ,也使用更高级的intictl工具。
状况
如前所述,FITIT具有处理同步的高级依赖系统,称为条件。它可以通过多种方式使用;取决于另一个服务,网络可用性等。
对于嵌入式系统来说,一个非常酷的示例是,如果板在其设备树中编码某些功能,则运行某些脚本。在Bootstrap,我们运行以下ident脚本:
#! /bin/sh
conddir=/var/run/finit/cond/hw/model
dtmodel=/sys/firmware/devicetree/base/model
if ! test -e $dtmodel ; then
exit 0
fi
model= $( cat $dtmodel | tr " [A-Z] " " [a-z]- " )
mkdir -p $conddir && ln -s ../../reconf $conddir / $model如果存在设备树节点并且是字符串,则在启动其他脚本时,我们可以使用条件<hw/model/foo> 。这是一个示例:
run [S] /path/to/ident --
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
请注意用空描述的技巧,以隐藏对
ident的调用,以限制进度输出。
插件
插件可以将有限和钩子的功能扩展到引导过程的不同阶段和运行时。插件用C编写,并将其编译到动态库中,该库会自动通过启动时自动加载。一组基本的插件在plugins/目录中捆绑在一起。
功能:
扩展和功能与/sbin/init启动系统所需的内容无关紧要,该系统可作为一组插件可用,该插件将插入引导过程或响应各种I/O。
有关更多信息,请参见Doc/plugins.md。
自动重新加载
默认情况下,fitit monitors /etc/finit.d/和/etc/finit.d/enabled/注册.conf文件的任何更改。要激活一个更改,用户必须调用initctl reload ,该更改将重新加载所有修改的文件,停止所有删除服务,启动新的服务并重新启动任何修改后的服务。如果服务的命令行参数已更改,则该过程将终止,然后从更新的参数开始。如果尚未修改参数,并且该过程支持叹息,则该过程将获得叹息而不是终止并开始。
对于某些用例,调用initctl reload的额外步骤会创建一个不必要的开销,可以在构建时间使用以下方式删除:
configure --enable-auto-reload
cgroups
FITIT支持Cgroups V2,并带有以下默认组,其中服务和用户会话放在:
/sys/fs/cgroup
|-- init/ # cpu.weight:100
|-- system/ # cpu.weight:9800
`-- user/ # cpu.weight:100
有限的本身及其辅助脚本和服务放置在顶级叶节组init/中,这也是保留的。
所有运行/任务/服务/SYSV流程都放在system/中的子组中。每个子组的名称取自/etc/finit.d的相应.conf文件。
所有盖蒂/ TTY过程都放在自己的user/中的子组中。每个子组的名称取自用户名。
也存在第四组, root组。它也是保留的,主要用于RT任务。如果您有RT任务,则需要在他们的服务节中宣布这样的声明:
service [...] <...> cgroup.root /path/to/foo args -- description
或者
cgroup.root
service [...] <...> /path/to/foo args -- description
service [...] <...> /path/to/bar args -- description
有关更多信息,例如,如何配置每组限制,请参见Doc/Config.md。
initctl工具具有三个命令,可以帮助调试和优化CGROUP的设置和监视。有关详细信息,请参见ps , top和cgroup命令。
注意:不支持CGROUP,特别是版本2的系统将自动检测到。在此类系统上,以上功能在启动时会尽早禁用。
在启动结束时,当所有Bootstrap( S )任务和服务都启动但没有网络时,有限的命令在任何配置的runparts <DIR> Directory上呼叫其内置的运行parts(8)命令。在更改为配置的Runlevel(默认2)之前,这会发生。 (在从单用户模式更改之前,启用了网络。)
runparts /etc/rc.d/当所有服务启动时,runlevel更改后,请调用/etc/rc.local 。
rc.local不需要/etc/finit.conf中的配置节。如果它存在并且是可执行的shell脚本,则在调用HOOK_SYSTEM_UP之前,在启动的末尾将其调用。在Doc/插件中查看有关挂钩的更多信息。
不可能通过信号调用finit或在任何runparts或/etc/rc.local脚本中使用initctl 。这是因为有限是单线线,并且在Runlevel s结束时以阻止方式调用这些脚本,此时,事件循环尚未启动。
事件循环是围绕有限的整个过程,除了runlevel s外,它在许多设置中仍然是一个缓慢的游行,并带有一些钩子,并在外部脚本上封锁了呼叫。
但是,并非所有initctl命令都被禁止。支持命令:
inictl cond :仅在/run/finit/cond操作文件initctl enable/disable :启用run/task/service在从s到2的runlevel更改上激活initctl touch/show/create/delete/list : create ,只要使用非相互作用模式,请在Bootstrap之后直接在Runlevel更改中进行更改initctl -f reboot/poweroff/halt :提供-f标志用于强制直接内核命令示例:您可以在/etc/rc.local中设置usr/条件,并在Runlevel 2中具有服务/任务取决于其执行。
v1.8的Finit中包括对Runlevels的基本支持。默认情况下,列出的所有服务,任务,运行命令和TTY,而没有一组runlevels获取默认设置[234] 。启动后的默认运行级别为2。
FITIT支持Runlevels 0-9,并且S为Halt保留0,6重新启动和S仅在Bootstrap上运行。 Runlevel 1是单个用户级别,通常不启用网络。在有限的情况下,这更多是用户定义的策略。通常,仅使用runlevels 1-6,甚至更常见的是,仅使用默认的runlevel。
要为service , run命令, task或tty指定一组允许的运行级别,请将[NNN]添加到您的/etc/finit.conf ,如下:
service [S12345] syslogd -n -x -- System log daemon
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
service [S12345] <pid/syslogd> klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
在此示例中,Syslogd首先并行启动,然后使用常规的SYSV INIT脚本来调用ACPID。它使用运行命令调用,这意味着以下任务命令启动KBD脚本直到ACPID Init脚本完全完成后才调用。然后,键盘设置脚本与KloGD并行称为监视服务。
同样,任务和服务是并行启动的,而在列出的顺序中调用运行命令,并且直到运行命令完成后才启动后续命令。此外,任务和运行命令是在外壳中运行的,因此可以使用管道和重定向。
以下示例说明了这一点。引导程序任务和运行命令在完成后也将删除, initctl show不会列出它们。
task [S] echo "foo" | cat >/tmp/bar
run [S] echo "$HOME" >/tmp/secret
可以通过使用单个参数(例如init 5或使用initctl runlevel 5 )调用INIT在runlevels之间进行切换,均可以切换到Runlevel 5。更改Runlevels时,有限也会自动重新加载所有.conf Files中的所有/etc/finit.d/文件。因此,如果您想设置新的系统配置,请切换到Runlevel 1,更改系统中的所有配置文件,然后在/etc/finit.d中触摸所有.conf文件,然后再切换回上一个Runlevel,然后再次切换到上一个Runlevel-此方式既可以停止旧服务又可以为您启动任何新服务,而无需重新启动系统。
传统上,重新启动和停止UNIX系统是通过更改其跑步来完成的。有限提供其自己的工具提供: shutdown , reboot , poweroff和suspend ,以及下一节中详细介绍的initctl工具。
出于兼容原因,有限的原因是聆听与Busybox Init相同的信号集。这与SYSV Init不兼容100%,但显然是更常见的组合。有关更多详细信息,请参见DOC/SIGNALS.MD。
有限还将现代API实现以查询状态,并开始/停止服务,称为initctl 。与telinit不同,在给定命令完全完成之前, initctl工具不会返回。
Usage: initctl [OPTIONS] [COMMAND]
Options:
-b, --batch Batch mode, no screen size probing
-c, --create Create missing paths (and files) as needed
-f, --force Ignore missing files and arguments, never prompt
-h, --help This help text
-j, --json JSON output in 'status' and 'cond' commands
-1, --once Only one lap in commands like 'top'
-p, --plain Use plain table headings, no ctrl chars
-q, --quiet Silent, only return status of command
-t, --no-heading Skip table headings
-v, --verbose Verbose output
-V, --version Show program version
Commands:
debug Toggle Finit (daemon) debug
help This help text
version Show program version
ls | list List all .conf in /etc/finit.d
create <CONF> Create .conf in /etc/finit.d/available
delete <CONF> Delete .conf in /etc/finit.d/available
show <CONF> Show .conf in /etc/finit.d/available
edit <CONF> Edit .conf in /etc/finit.d/available
touch <CONF> Change .conf in /etc/finit.d/available
enable <CONF> Enable .conf in /etc/finit.d/available
disable <CONF> Disable .conf in /etc/finit.d/enabled
reload Reload *.conf in /etc/finit.d (activate changes)
cond set <COND> Set (assert) user-defined conditions +usr/COND
cond get <COND> Get status of user-defined condition, see $? and -v
cond clear <COND> Clear (deassert) user-defined conditions -usr/COND
cond status Show condition status, default cond command
cond dump [TYPE] Dump all, or a type of, conditions and their status
log [NAME] Show ten last Finit, or NAME, messages from syslog
start <NAME>[:ID] Start service by name, with optional ID
stop <NAME>[:ID] Stop/Pause a running service by name
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)
This allows restart of run/tasks that have already run
Note: Finit .conf file(s) are *not* reloaded!
restart <NAME>[:ID] Restart (stop/start) service by name
signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID
ident [NAME] Show matching identities for NAME, or all
status <NAME>[:ID] Show service status, by name
status Show status of services, default command
cgroup List cgroup config overview
ps List processes based on cgroups
top Show top-like listing based on cgroups
plugins List installed plugins
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
reboot Reboot system
halt Halt system
poweroff Halt and power off system
suspend Suspend system
utmp show Raw dump of UTMP/WTMP db
对于不支持SIGHUP服务,必须使用.conf文件中的<!>表示法来告诉Finit,以停止并在reload和runlevel更改上启动它。如果<>持有更多条件,这些条件也会影响维持服务的方式。
注意:即使有可能启动不属于当前运行时的服务,如果它们退出(崩溃),这些服务也不会自动重新出现。因此,如果跑步级为2,则下面的dropbear SSH服务如果被杀死或退出,则不会重新启动。
status命令是默认值,它显示了所有监视运行/任务/服务的快速概述。在这里,我们称为initctl -p ,适用于脚本和文档:
alpine:~# initctl -p
PID IDENT STATUS RUNLEVELS DESCRIPTION
======================================================================
1506 acpid running [---2345----] ACPI daemon
1509 crond running [---2345----] Cron daemon
1489 dropbear running [---2345----] Dropbear SSH daemon
1511 klogd running [S-12345----] Kernel log daemon
1512 ntpd running [---2345----] NTP daemon
1473 syslogd running [S-12345----] Syslog daemon
alpine:~# initctl -pv
PID IDENT STATUS RUNLEVELS COMMAND
======================================================================
1506 acpid running [---2345----] acpid -f
1509 crond running [---2345----] crond -f -S $CRON_OPTS
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
1473 syslogd running [S-12345----] syslogd -n
对于Alpine Linux, /etc/conf.d/ conf.d/读取了上述每个服务的环境变量。其他分布可能具有其他目录,例如,debian使用/etc/default/ 。
status命令采用可选NAME:ID参数。在这里,我们检查了dropbear的状态,该系统在此系统中只有一个实例:
alpine:~# initctl -p status dropbear
Status : running
Identity : dropbear
Description : Dropbear SSH daemon
Origin : /etc/finit.d/enabled/dropbear.conf
Environment : -/etc/conf.d/dropbear
Condition(s):
Command : dropbear -R -F $DROPBEAR_OPTS
PID file : !/run/dropbear.pid
PID : 1485
User : root
Group : root
Uptime : 2 hour 46 min 56 sec
Runlevels : [---2345----]
Memory : 1.2M
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|- 1485 dropbear -R -F
|- 2634 dropbear -R -F
|- 2635 ash
`- 2652 initctl -p status dropbear
Apr 8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgrounding
Apr 8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834
Apr 8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834
Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect received
Apr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576
Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
FITIT能够在带有UDEV和嵌入式系统的两个桌面/服务器系统上运行,通常随附BusyBox MDEV。某些系统今天具有SystemD-udeV或EudeV,而不是原始的UDEV,在运行时对所有系统的所有探针都有限,并且期望/dev/是使用devtmpfs的可写文件系统。如果需要,也可以在静态设置/dev运行。但是,同时安装UDEV和MDEV并不是一个好主意,这将导致无法预测的结果。
在BOOT FITIT调用mdev或udevd以填充/dev情况下,这是略有不同的,在使用UDEV的系统上,您可能需要在/etc/finit.conf中添加以下单发任务:
run [S] udevadm settle --timeout=120 -- Waiting for udev
FITIT具有内置的TTY Getty,但需要工作/bin/login或/bin/sh ,如果没有在/etc/finit.conf中配置tty。
对于完全操作的系统/var , /run和/tmp必须在/etc/fstab中正确设置,该设置在启动时迭代。
该项目基于Claudio Matsuoka的原始有限,该项目是根据Eeepc Fastinit的Syscall进行了反向设计的 - “充满青蛙DNA的间隙……”
有限是由Joachim Wiberg在Github开发和维护的。请提交错误报告,克隆它或发送“错误修复”和“提议扩展”请求。