Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Fast init for Linux. Cookies included

License

NotificationsYou must be signed in to change notification settings

troglobit/finit

Repository files navigation

License BadgeGitHub StatusCoverity StatusFinit: Fast Init

Introduction

Fast init for Linux systems. Reverse engineered from theEeePCfastinit byClaudio Matsuoka — "gaps filled with frog DNA …"

Alpine screenshot
Figure 1: Screenshot of Finit bootingAlpine Linux (HowTo).

Features include:

  • Runlevels, defined per service
  • One-shot tasks, services (daemons), orSysV init start/stop scripts
  • Runparts and/etc/rc.local support
  • Process supervision similar tosystemd
  • Sourcing environment files
  • Conditions for network/process/custom dependencies
  • Readiness notification; PID files (native) for synchronizing systemstartup, support for systemdsd_notify(), ors6 style too
  • Limited support fortmpfiles.d(5) (no aging, attributes, or subvolumes)
  • Pre/Post script actions
  • Rudimentarytemplating support
  • Tooling to enable/disable services
  • Built-in getty
  • Built-in watchdog, with support for hand-over towatchdogd
  • Built-in support for Debian/BusyBox/etc/network/interfaces
  • Cgroups v2, both configuration and monitoring ininitctl top
  • Plugin support for customization
  • Proper rescue mode with bundledsulogin for protected maintenance shell
  • Integration withwatchdogd for full system supervision
  • Logging to kernel ring buffer beforesyslogd has started, see therecommendedsysklogd project for complete logging integrationand how to log to the kernel ring buffer from scripts usinglogger

Focus is on small and embedded systems, although Finit is fully usableon server and desktop systems as well. For working examples, see thecontrib/ section with tutorials for the following Linuxdistributions:

Note: support for various Linux distributions does not mean Finitinstalls easily on all architectures. The bundled install scripts areexamples for standard installations, tested on amd64 (x86_64) systems.Custom setups, e.g., for embedded systems, can be found in any of thefollowingBuildroot based examples:myLinux,Infix, or theplainbr2-finit-demo.

Example

This example/etc/finit.conf can also be split up in multiple.conffiles in/etc/finit.d. Available, but not yet enabled, services canbe placed in/etc/finit.d/available and enabled by an operator usingtheinitctl tool. See the above mentioned Linuxdistributions, ormyLinux.

Note: as of Finit v4.4, .conf lines can be broken up using thestandard UNIX continuation character (\), also trailing comments arenow supported. The latter means you need to escape any hashes used indirectives and descriptions (\#). For more on this and examples,see thefinit.conf(5) manual ordoc/config.md.

# Fallback if /etc/hostname is missinghost 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.gzlog size=100k count=4# Services to be monitored and respawned as neededservice [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemonservice [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS          -- System log daemonservice [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemonservice   [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 serverservice :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 speedtty [12345] /sbin/getty -L 0 /dev/tty1  linux nowait nocleartty [2345]  /sbin/getty -L 0 /dev/tty2  linux nowait nocleartty [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

Theservice stanza, as well astask,run and others are describedin full indoc/config.md. Here's a quick overview ofsome of the most common components needed to start a UNIX daemon:

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

Some components are optional: runlevel(s), condition(s) and description,making it easy to create simple start scripts and still possible for moreadvanced uses as well:

service /usr/sbin/sshd -D

Dependencies are handled usingconditions. One ofthe most common conditions is to wait for basic networking to becomeavailable:

service <net/route/default> nginx -- High performance HTTP server

Here is another example where we instruct Finit to not start BusyBoxntpd untilsyslogd has started properly. Finit waits forsyslogdto create its PID file, by default/var/run/syslogd.pid.

service [2345] log <!pid/syslogd> ntpd -n -N -p pool.ntp.orgservice [S12345] syslogd -n -- Syslog daemon

Notice thelog keyword, BusyBoxntpd usesstderr for logging whenrun in the foreground. Withlog Finit redirectsstdout +stderrto the system log daemon using the command linelogger(1) tool.

A service, or task, can have multiple dependencies listed. Here we waitforbothsyslogd to have started and basic networking to be up:

service [2345] log <pid/syslogd,net/route/default> ntpd -n -N -p pool.ntp.org

If either condition fails, e.g. loss of networking,ntpd is stoppedand as soon as it comes back up againntpd is restarted automatically.

Note: Make sure daemonsdo not fork and detach themselves from thecontrolling TTY, usually an-n or-f flag, or-D as in the caseof OpenSSH above. If it detaches itself, Finit cannot monitor it andwill instead try to restart it.

Features

Process Supervision

Start, monitor and restart services should they fail.

Getty

Finit supports external getty but also comes with a limited built-inGetty, useful for really small systems. A getty sets up the TTY andwaits for user input before handing over to/bin/login, which isresponsible for handling the actual authentication.

tty [12345] /dev/tty1    nowait  linuxtty [12345] /dev/ttyAMA0 noclear vt100tty [12345] /sbin/getty  -L /dev/ttyAMA0 vt100

Users of embedded systems may want to enable automatic serial consolewith the special@console device. This works regardless weather thesystem usesttyS0,ttyAMA0,ttyMXC0, or anything else. Finitfigures it out by querying sysfs:/sys/class/tty/console/active.

tty [12345] @console linux noclear

Notice the optionalnoclear,nowait, andnologin flags. Thelatter is for skipping the login process entirely. For more information,seedoc/config.md.

Runlevels

Support for SysV init-stylerunlevels is available, in the sameminimal style as everything else in Finit. The[2345] syntax can beapplied to service, task, run, and TTY stanzas.

Reserved runlevels are 0 and 6, halt and reboot, respectively just likeSysV init. Runlevel 1 can be configured freely, but is recommended tobe kept as the system single-user runlevel since Finit will not startnetworking here. The configuredrunlevel NUM from/etc/finit.confis what Finit changes to after bootstrap, unless 'single' (or 'S') isgiven on the kernel cmdline, in which case runlevel 1 is started.

All services in runlevel S) are started first, followed by the desiredrun-time runlevel. Run tasks in runlevel S can be started in sequenceby usingrun [S] cmd. Changing runlevels at runtime is done like anyother init, e.g.init 4, but also using the more advancedintictl tool.

Conditions

As mentioned previously, Finit has an advanced dependency system tohandle synchronization, calledconditions. It canbe used in many ways; depend on another service, network availability,etc.

Onereally cool example useful for embedded systems is to run certainscripts if a board has a certain feature encoded in its device tree. Atbootstrap we run the followingident script:

#!/bin/shconddir=/var/run/finit/cond/hw/modeldtmodel=/sys/firmware/devicetree/base/modelif!test -e$dtmodel;thenexit 0fimodel=$(cat$dtmodel| tr"[A-Z]""[a-z]-")mkdir -p$conddir&& ln -s ../../reconf$conddir/$model

Provided the device tree node exists, and is a string, we can then usethe condition<hw/model/foo> when starting other scripts. Here is anexample:

run  [S]                /path/to/ident    --task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board

Notice the trick with an empty description to hide the call toidentin the Finit progress output.

Plugins

Plugins canextend the functionality of Finit andhook into thedifferent stages of the boot process and at runtime. Plugins arewritten in C and compiled into a dynamic library loaded automatically byfinit at boot. A basic set of plugins are bundled in theplugins/directory.

Capabilities:

  • Hooks
    Hook into the boot at predefined points to extend Finit
  • I/O
    Listen to external events and control Finit behavior/services

Extensions and functionality not purely related to what an/sbin/initneeds to start a system are available as a set of plugins that eitherhook into the boot process or respond to various I/O.

For more information, seedoc/plugins.md.

Automatic Reload

By default, Finit monitors/etc/finit.d/ and/etc/finit.d/enabled/registering any changes to.conf files. To activate a change the usermust callinitctl reload, which reloads all modified files, stops anyremoved services, starts new ones, and restarts any modified ones. If thecommand line arguments of a service have changed, the process will beterminated and then started again with the updated arguments. If the argumentshave not been modified and the process supports SIGHUP, the process willreceive a SIGHUP rather than being terminated and started.

For some use-cases the extra step of callinginitctl reload creates anunnecessary overhead, which can be removed at build-time using:

configure --enable-auto-reload

Cgroups

Finit supports cgroups v2 and comes with the following default groups inwhich services and user sessions are placed in:

 /sys/fs/cgroup   |-- init/               # cpu.weight:100   |-- system/             # cpu.weight:9800   `-- user/               # cpu.weight:100

Finit itself and its helper scripts and services are placed in thetop-level leaf-node groupinit/, which also isreserved.

All run/task/service/sysv processes are placed in their own sub-groupinsystem/. The name of each sub-group is taken from the respective.conf file from/etc/finit.d.

All getty/tty processes are placed in their own sub-group inuser/.The name of each sub-group is taken from the username.

A fourth group also exists, theroot group. It is alsoreserved andprimarily intended for RT tasks. If you have RT tasks they need to bedeclared as such in their service stanza like this:

service [...] <...> cgroup.root /path/to/foo args -- description

or

cgroup.rootservice [...] <...> /path/to/foo args -- descriptionservice [...] <...> /path/to/bar args -- description

Seedoc/config.md for more information, e.g.,how to configure per-group limits.

Theinitctl tool has three commands to help debug and optimize thesetup and monitoring of cgroups. See theps,top, andcgroupcommands for details.

Note: systems that do not support cgroups, specifically version 2,are automatically detected. On such systems the above functionalityis disabled early at boot.

Runparts & /etc/rc.local

At the end of the boot, when all bootstrap (S) tasks and services havestarted, but not networking, Finit calls its built-inrun-parts(8)command on any configuredrunparts <DIR> directory. This happens justbefore changing to the configured runlevel (default 2). (Networking isenabled just prior to changing from single user mode.)

runparts /etc/rc.d/

Right after the runlevel change when all services have started properly,/etc/rc.local is called.

No configuration stanza in/etc/finit.conf is required forrc.local.If it exists and is an executable shell script Finit calls it at the veryend of the boot, before calling theHOOK_SYSTEM_UP. See more on hooksindoc/plugins.md.

Limitations

It is not possible to call Finit via signals or useinitctl in anyrunparts or/etc/rc.local script. This because Finit is singlethreaded and is calling these scripts in a blocking fashion at the endof runlevel S, at which point the event loop has not yet been started.

The event loop is the whole thing which Finit is built around, exceptfor runlevel S, which remains a slow procession through a lot of set up,with a few hooks and blocking call outs to external scripts.

However, not allinitctl commands are prohibited. Supported commands:

  • inictl cond: only operate of files in/run/finit/cond
  • initctl enable/disable: enabled run/task/service is activated onthe runlevel change from S to 2
  • initctl touch/show/create/delete/list:create, provided thenon-interactive mode is used, again changes take effect in therunlevel change directly after bootstrap
  • initctl -f reboot/poweroff/halt: provided the-f flag is used toforce direct kernel commands

Example: you can set ausr/ condition in/etc/rc.local and havea service/task in runlevel 2 depend on it to execute.

Runlevels

Basic support forrunlevels is included in Finit from v1.8. Bydefault all services, tasks, run commands and TTYs listed without a setof runlevels get a default set[234] assigned. The default runlevelafter boot is 2.

Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 rebootand S for services to only run at bootstrap. Runlevel 1 is the singleuser level, where usually no networking is enabled. In Finit this ismore of a policy for the user to define. Normally only runlevels 1-6are used, and even more commonly, only the default runlevel is used.

To specify an allowed set of runlevels for aservice,run command,task, ortty, add[NNN] to your/etc/finit.conf, like this:

service [S12345] syslogd -n -x             -- System log daemonrun     [S]      /etc/init.d/acpid start   -- Starting ACPI Daemontask    [S]      /etc/init.d/kbd start     -- Preparing consoleservice [S12345] <pid/syslogd> klogd -n -x -- Kernel log daemontty     [12345]  /dev/tty1tty     [2]      /dev/tty2tty     [2]      /dev/tty3tty     [2]      /dev/tty4tty     [2]      /dev/tty5tty     [2]      /dev/tty6

In this example syslogd is first started, in parallel, and then acpid iscalled using a conventional SysV init script. It is called with the runcommand, meaning the following task command to start the kbd script isnot called until the acpid init script has fully completed. Then thekeyboard setup script is called in parallel with klogd as a monitoredservice.

Again, tasks and services are started in parallel, while run commandsare called in the order listed and subsequent commands are not starteduntil a run command has completed. Also, task and run commands are runin a shell, so pipes and redirects can be used.

The following examples illustrate this. Bootstrap task and run commandsare also removed when they have completed,initctl show will not listthem.

task [S] echo "foo" | cat >/tmp/barrun  [S] echo "$HOME" >/tmp/secret

Switching between runlevels can be done by calling init with a singleargument, e.g.init 5, or usinginitctl runlevel 5, bothswitch to runlevel 5. When changing runlevels Finit also automaticallyreloads all.conf files in the/etc/finit.d/ directory. So if youwant to set a new system config, switch to runlevel 1, change all configfiles in the system, and touch all.conf files in/etc/finit.dbefore switching back to the previous runlevel again — that way Finitcan both stop old services and start any new ones for you, withoutrebooting the system.

Rebooting & Halting

Traditionally, rebooting and halting a UNIX system is done by changingits runlevel. Finit comes with its own tooling providing:shutdown,reboot,poweroff, andsuspend, but also theinitctl tool,detailed in the next section.

For compatibility reasons Finit listens to the same set of signals asBusyBox init. This is not 100% compatible with SysV init, but clearlythe more common combination for Finit. For more details, seedoc/signals.md.

Commands & Status

Finit also implements a modern API to query status, and start/stopservices, calledinitctl. Unliketelinit theinitctl tool doesnot return until the given command has fully completed.

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 versionCommands:  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

For servicesnot supportingSIGHUP the<!> notation in the .conffile must be used to tell Finit to stop and start it onreload andrunlevel changes. If<> holds moreconditions,these will also affect how a service is maintained.

Note: even though it is possible to start services not belonging inthe current runlevel these services will not be respawned automaticallyby Finit if they exit (crash). Hence, if the runlevel is 2, the belowDropbear SSH service will not be restarted if it is killed or exits.

Thestatus command is the default, it displays a quick overview of allmonitored run/task/services. Here we callinitctl -p, suitable forscripting and documentation:

alpine:~# initctl -pPID   IDENT     STATUS   RUNLEVELS     DESCRIPTION======================================================================1506  acpid     running  [---2345----] ACPI daemon1509  crond     running  [---2345----] Cron daemon1489  dropbear  running  [---2345----] Dropbear SSH daemon1511  klogd     running  [S-12345----] Kernel log daemon1512  ntpd      running  [---2345----] NTP daemon1473  syslogd   running  [S-12345----] Syslog daemonalpine:~# initctl -pvPID   IDENT     STATUS   RUNLEVELS     COMMAND======================================================================1506  acpid     running  [---2345----] acpid -f1509  crond     running  [---2345----] crond -f -S $CRON_OPTS1489  dropbear  running  [---2345----] dropbear -R -F $DROPBEAR_OPTS1511  klogd     running  [S-12345----] klogd -n $KLOGD_OPTS1512  ntpd      running  [---2345----] ntpd -n $NTPD_OPTS1473  syslogd   running  [S-12345----] syslogd -n

The environment variables to each of the services above are read from,in the case of Alpine Linux,/etc/conf.d/. Other distributions mayhave other directories, e.g., Debian use/etc/default/.

Thestatus command takes an optionalNAME:ID argument. Here wecheck the status ofdropbear, which only has one instance in thissystem:

alpine:~# initctl -p status dropbear     Status : running   Identity : dropbearDescription : Dropbear SSH daemon     Origin : /etc/finit.d/enabled/dropbear.confEnvironment : -/etc/conf.d/dropbearCondition(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 dropbearApr  8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgroundingApr  8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834Apr  8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834Apr  8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect receivedApr  8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576Apr  8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576

Requirements

Finit is capable of running on both desktop/server systems with udev andembedded systems that usually come with BusyBox mdev. Some systems havesystemd-udev or eudev today instead of the original udev, Finit probesfor all of them at runtime and expects/dev/ to be a writable filesystem usingdevtmpfs. It is also possible to run on a statically setup/dev if needed. It is however not a good idea to have both udevand mdev installed at the same time, this will lead to unpredictableresults.

At boot Finit calls eithermdev orudevd to populate/dev, this isdone slightly differently and on systems with udev you might want to addthe following one-shot task early in your/etc/finit.conf:

run [S] udevadm settle --timeout=120 -- Waiting for udev

Finit has a built-in Getty for TTYs, but requires a working/bin/loginor/bin/sh, if no TTYs are configured in/etc/finit.conf.

For a fully operational system/var,/run and/tmp must be set upproperly in/etc/fstab -- which is iterated over at boot.

Origin & References

This project is based on theoriginal finit byClaudio Matsuokawhich was reverse engineered from syscalls of theEeePC fastinit —"gaps filled with frog DNA …"

Finit is developed and maintained byJoachim Wiberg atGitHub.Please file bug reports, clone it, or send pull requests for bug fixesand proposed extensions.


[8]ページ先頭

©2009-2025 Movatter.jp