Compare commits

...
34 Commits
Author SHA1 Message Date
Joachim Wiberg 9e85c4f3d1 Bump version for v4.0 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-26 01:01:20 +02:00
Joachim Wiberg 2531102623 sulogin: ensure Ctrl-D returns OK(0) also for pwd login prompt
sulogin should return OK (exit code 0) when the user presses Ctrl-D,
regardless of the prompt shown.  Otherwise Finit may look for another
sulogin to run straight after this one.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-26 00:59:01 +02:00
Joachim Wiberg 33deada6f0 README: mention new rescue mode in feature list overview
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-26 00:52:40 +02:00
Joachim Wiberg 9d1506bb7e Revert "Travis-CI: disable clang for coverity scan run"
This reverts commit e011dac98b.
2021-04-26 00:45:57 +02:00
Joachim Wiberg c3f115c9ec sulogin: fix build issue
Keyboard suddenly lost CapsLock -> Ctrl remapping ...

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-26 00:39:39 +02:00
Joachim Wiberg 430d402b14 sulogin: check for Ctrl-D also if no pwd to abort and continue boot
Signed-off-by: Joachim Wiberg <joachim.nilsson@westermo.se>
2021-04-26 00:25:24 +02:00
Joachim Wiberg e011dac98b Travis-CI: disable clang for coverity scan run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 23:57:41 +02:00
Joachim Wiberg 42b84d1ccb Update ChangeLog for v4.0 GA
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 23:57:02 +02:00
Joachim Wiberg 288105eac7 sulogin: must fflush() prompt on Alpine Linux (musl libc)
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 23:14:05 +02:00
Joachim Wiberg 842b522e68 Drop --disable-logit configure option, no longer in $PATH
Simplify build system.

The logit tool is, as of v4.0, installed into /libexec/finit/logit and
thus not part of the system $PATH.  If a sysadmin or distro wants to
remove it from the system it's entirely possible since Finit always
checks for logit availability before attempting to use it.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 22:53:34 +02:00
Joachim Wiberg e6f36974c8 Document all facets of rescue mode; traditional and fallback
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 22:46:43 +02:00
Joachim Wiberg 679b4df881 Fallback rescue mode handling
Before 4e5d06b the only way to go into rescue mode was to skip certain
steps and then attempt to load /lib/finit/rescue.conf.  After 4e5d06b
we keep the old handling as a fallback in case early sulogin fails.

The new tty option 'rescue' is added, which recue.conf is updated with.
This option implies notty mode and will try sulogin (again) before it
falls back to start /bin/sh as a login shell.

The reason we keep this is to be able to handle all possible use-cases
and also allow sysadmins to set up the behavior that fits their needs.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 22:10:42 +02:00
Joachim Wiberg 666cae6f49 service_start(): allow notty TTYs without device to start
A notty TTY can be declared with or without a device, it requires none.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 22:09:07 +02:00
Joachim Wiberg be2ac1d1b1 sulogin: handle no password and locked account (treated as no pwd)
This patch does two things:

 1. A system with a root account that has no password is now
    allowed to login without password, as one expects.
 2. A systems with a locked root account, is treated as (1).

The latter of the two may very well turn out to be a really bad idea.
Much angst have been poured into it, yet the end decision is to allow
access.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 21:43:39 +02:00
Joachim Wiberg 266e5b30eb Drop all mention of old fallback shell from comments
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 21:43:16 +02:00
Joachim Wiberg 4e5d06b580 Replace experimental emergency shell with actual rescue mode
Most major init systems have a way to start a rescue shell.  This is
usally started when the string `rescue` is read from the kernel's
command line.

The traditional Finit way of handling this has been to skip certain
phases of the standard boot, skip /etc/finit.conf et al, and go for a
/lib/finit/rescue.conf instead.  This pratice has been imroved over
the last few commits with a sulogin.  However, there was no way to
resume boot, like most other init systems offer.

This patch implements a very simple rescue mode, utilizing the new
sulogin, replacing the old (and experimental) emergency shell.  If
Ctrl-D is pressed at the maintenance login prompt the boot is now
resumed.  The same goes for exit/Ctrl-D from the maintenace shell.

The preferred sulogin is the bundled /libexec/finit/sulogin, but
if that isn't installed, the first one in $PATH is used.  If no
sulogin at all is found, Finit proceeds as before this patch, to
skip certains steps and go for a /lib/finit/rescue.conf.  Hence,
al steps can be controlled by an administrator.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 21:32:35 +02:00
Joachim Wiberg fe334135ce Fix small memory leak, use whichp() to query, not which()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 19:47:15 +02:00
Joachim Wiberg aef10fb5e7 Revert "Travis-CI: disable clang for coverity scan run"
This reverts commit 550ae9c784.
2021-04-25 19:47:04 +02:00
Joachim Wiberg 86707c1f0b sulogin: minor refactor, splice out sh() as separate function
- splice out sh() as a separate function
 - make sh() session leader and set controlling TTY (TIOCSCTTY)
   to make it a proper login shell with Ctrl-C functionality
 - simplify call to execl()

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 19:28:03 +02:00
Joachim Wiberg a28d5b3c09 sulogin: fix minor issue found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-25 19:27:42 +02:00
Joachim Wiberg 550ae9c784 Travis-CI: disable clang for coverity scan run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 20:45:44 +02:00
Joachim Wiberg cd5b91680a sulogin: home cooked version, can be built -static
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 20:43:54 +02:00
Joachim Wiberg 221ab20898 tty: add basic security, call sulogin in rescue mode (notty)
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 20:27:26 +02:00
Joachim Wiberg 96534789db Minor, rename LOGIT_PATH -> _PATH_LOGIT for consistency
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 20:26:52 +02:00
Joachim Wiberg 26128dd788 plugins: skip plugin in rescue mode
These plugins should not run in rescue mode, because the system may be
in a very bad state and we do not want to make the situation any worse
than it already is.

Essentially, only services in rescue.conf should run in rescue mode.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 19:46:43 +02:00
Joachim Wiberg 799e992542 tty: minor, rename local variables for consistency
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 10:33:58 +02:00
Joachim Wiberg fa524eec60 contrib: debian: add elogind.conf and update recommendations
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 10:33:57 +02:00
Joachim Wiberg 6dced29b49 Add another constraint for the built-in watchdog, device exists
- Check if watchdogd *and* `WDT_DEVNODE` exists before registering the
   built-in watchdogd at boot
 - Update bootstrap.md with this additional constraint
 - Update config.md with references to bootstrap and the new constraint

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 10:33:57 +02:00
Joachim Wiberg 2ea613a42b Make sure built-in watchdog is disabled by default
Omitting --without-watchdog caused the watchdog to be enabled.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 09:43:27 +02:00
Joachim Wiberg 985df20519 cgroup: don't warn on cgroup.events EINVAL for top-level groups
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 07:42:31 +02:00
Joachim Wiberg f6161b9be9 doc: Add blurb on bundled vs external watchdog, handover and reset
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-24 07:41:46 +02:00
Joachim Wiberg 25c5014d3c Also check env: file for changes to detect svc->args_dirty
This patch fixes an issue where services that support SIGHUP are not
properly stop/started on changes to their command line arguments.

A change to a service's env: file, e.g. /etc/default/foo for service
foo, must also be counted as a change to the foo args.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-23 17:12:59 +02:00
Joachim Wiberg b8b7b53d96 External plugins require exporting cgroup.h, svc.h needs it
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-20 01:48:03 +02:00
Joachim Wiberg 7707c4b8e6 initctl: only show key capture in debug mode
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-19 15:56:39 +02:00
32 changed files with 572 additions and 157 deletions
+42 -14
View File
@@ -4,12 +4,12 @@ Change Log
All relevant changes are documented in this file. All relevant changes are documented in this file.
[4.0][UNRELEASED] - 2021-03-xx [4.0][] - 2021-04-26
------------------------------ --------------------
This release became v4.0, and not v3.2, because of incompatible changes This release became v4.0, and not v3.2, because of incompatible changes
to service conditions. There are other significant changes as well, so to service conditions. There are other significant changes as well, so
make sure to read the whole changelog when upgrading. make sure to read the whole change log when upgrading.
### Changes ### Changes
* The stand-alone `reboot` tool has been replaced with a symlink to * The stand-alone `reboot` tool has been replaced with a symlink to
@@ -24,28 +24,47 @@ make sure to read the whole changelog when upgrading.
* Removed built-in inetd super server. If you need this functionality, * Removed built-in inetd super server. If you need this functionality,
use an external inetd, like xinetd, instead. A pull request for a use an external inetd, like xinetd, instead. A pull request for a
stand-alone inetd, like watchdogd and getty, is most welcome! stand-alone inetd, like watchdogd and getty, is most welcome!
* Incompatible `configure` script changes, i.e., you must give proper * Incompatible `configure` script changes, i.e., no guessing `--prefix`
path arguments to the script, no more guessing just GNU defaults. and other paths. Also, many options have been changed, renamed, or
There are examples in the documentation and the `contrib/` section flipped defaults, or even dropped altogether. There are examples in
* Change service conditions from the non-obvious `<svc/path/to/foo>` to the documentation and the `contrib/` section
`<pid/foo:id>`. This to hopefully make it clear that one service's * Service conditions change from the non-obvious `<svc/path/to/foo>` to
'pid:!foo' pidfile is another service's `<pid/foo>` condition `<pid/foo:id>`. Not only does this give simpler internal semantics,
* Initial support for cgroups, every service now runs in its own cgroup it hopefully also makes it clear that one service's `pid:!foo` pidfile
https://twitter.com/b0rk/status/1214341831049252870?s=20 is another service's `<pid/foo>` condition, issue #143
* Initial support for cgroups v2:
- services runs in a cgroup named after their respective *.conf file
- top-level groups are; init, user, and system
- all top-level groups can be configured from finit *.conf files
- each service can tweak the cgroup settings
- Use `initctl [top|ps|cgroup]` commands to inspect runtime state
- https://twitter.com/b0rk/status/1214341831049252870?s=20
* Major refactor of Finit's `main()` function to be able to start the * Major refactor of Finit's `main()` function to be able to start the
event loop earlier. This also facilitated factoring out functionality event loop earlier. This also facilitated factoring out functionality
previously hard-coded in Finit, e.g., starting the bundled watchdogd, previously hard-coded in Finit, e.g., starting the bundled watchdogd,
various distro packed udevd and other hotplugging tools various distro packed udevd and other hotplugging tools
* A proper rescue mode has been added. It is started extremely early
and is protected with a bundled `suslogin`. Exiting rescue mode now
brings up the system as a normal boot, as one expects
* Support for `sysv` start/stop scripts as well as monitoring forking * Support for `sysv` start/stop scripts as well as monitoring forking
services, stared using `sysv` or `service` stanza services, stared using `sysv` or `service` stanza
* Support for custom `kill:DELAY`, default 3 sec. * Support for custom `kill:DELAY`, default 3 sec.
* Support for custom `halt:SIGNAL`, default SIGTERM * Support for custom `halt:SIGNAL`, default SIGTERM
* Support for `pre:script` and `post:script`, allows for setup and
teardown/cleanup before and after a service runs, issue #129
* Support for `env:file` in `/etc/default/foo` or `/etc/conf.d/foo`, see
the contrib section for examples that utilize this feature. Variables
expanded from env files, and the env files themselves, are tracked for
changes to see if a service .conf file is "dirty" and needs restart on
`initctl reload`
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`, * Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
useful with new `sysv` or `service` which fork to background useful with new `sysv` or `service` which fork to background
* Support starting run/task/services without absolute path, trust `$PATH` * Support starting run/task/services without absolute path, trust `$PATH`
* Add support for `--disable-doc` and `--disable-contrib` to speed up * Add support for `--disable-doc` and `--disable-contrib` to speed up
builds and work around issue with massively parallel builds builds and work around issue with massively parallel builds
* Add support for `@console` also for external getty * Support for `@console` also for external getty
* Support for `notty` option to built-in getty, for board bring-up
* Support for `rescue` option to built-in getty, for rescue shells
* Add `-b`, batch mode, for non-interactive use to `initctl` * Add `-b`, batch mode, for non-interactive use to `initctl`
* Prefer udev to handle `/dev/` if mdev is also available * Prefer udev to handle `/dev/` if mdev is also available
* Redirect dbus daemon output to syslog * Redirect dbus daemon output to syslog
@@ -95,6 +114,8 @@ make sure to read the whole changelog when upgrading.
* Always append `:ID` qualifier to conditions if set for a service * Always append `:ID` qualifier to conditions if set for a service
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket` * The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
officially only supported for use by the `initctl` tool officially only supported for use by the `initctl` tool
* The IPC socket now uses `SOCK_SEQPACKET` instead of `SOCK_STREAM`.
Recommend using watchdogd v3.4, or later, which support this
* Improved support for modern `/etc/network/interfaces`, which has * Improved support for modern `/etc/network/interfaces`, which has
include statements. No more native `ifup` of individual interfaces, include statements. No more native `ifup` of individual interfaces,
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
@@ -112,16 +133,21 @@ make sure to read the whole changelog when upgrading.
that do not have a watchdog that do not have a watchdog
* Fix #100: Early condition handling may not work if `/var/run` does * Fix #100: Early condition handling may not work if `/var/run` does
not yet exist (symlink to `/run`). Added compat layer for access not yet exist (symlink to `/run`). Added compat layer for access
* Fix #101: Built-in inetd removed
* Fix #102: Start built-in watchdogd as a regular service
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY, * Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6 * Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
Fixed by Jonas Johansson, Westermo Fixed by Jonas Johansson, Westermo
* Fix #109: Support for PID files in sub-directories to `/var/run` * Fix #109: Support for PID files in sub-directories to `/var/run`
* Handle rename of PID files, by Robert Andersson, Atlas Copco * Handle rename of PID files, by Robert Andersson, Atlas Copco
* Fix #110: automatic modprobe of RTC devices, built-in hwclock
* Fix #120: Redirect `stdin` to `/dev/null` for services by default * Fix #120: Redirect `stdin` to `/dev/null` for services by default
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep, * Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
fixed by Jacques de Laval, Westermo fixed by Jacques de Laval, Westermo
* Fix #124: Lingering processes in process group when session leader * Fix #124: Lingering processes in process group when session leader
exits. E.g., lingering `logit` processes when parent dies exits. E.g., lingering `logit` processes when parent dies
* Fix #127: Show all runparts scripts as they start, like rc.local, fixed
by Jacques de Laval, Westermo
* Fix service name matching, e.g. for condition handling, may match with * Fix service name matching, e.g. for condition handling, may match with
wrong service, by Jonas Holmberg, Westermo wrong service, by Jonas Holmberg, Westermo
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard * Run all run-parts scripts using `/bin/sh -c foo` just like the standard
@@ -140,6 +166,8 @@ make sure to read the whole changelog when upgrading.
* Provide service description for built-in watchdog daemon * Provide service description for built-in watchdog daemon
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system * Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
* Drop the '%m' GNUism, for compat with older musl libc * Drop the '%m' GNUism, for compat with older musl libc
* Fix #139: call `tzset()` on `initctl reload` to activate system
timezone changes (for logging)
[3.1][] - 2018-01-23 [3.1][] - 2018-01-23
@@ -748,14 +776,14 @@ Major bug fix release.
* Makefile fixes for installation, paths encoded wrong * Makefile fixes for installation, paths encoded wrong
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip * Strip binaries + .so files, support for `$(CROSS)` toolchain strip
* Default install is now to `/sbin/finit` and `/usr/` * Default install is now to `/sbin/finit` and `/usr/`
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir` * Note change in `$PLUGIN_DIR` environment variable to `$plugindir`
[1.2][] - 2012-09-27 [1.2][] - 2012-09-27
-------------------- --------------------
### Changes ### Changes
* Update README with section on building and enviroment variables * Update README with section on building and environment variables
### Fixes ### Fixes
* Fix installation paths encoded in finit binary * Fix installation paths encoded in finit binary
+1
View File
@@ -44,6 +44,7 @@ Features include:
* Built-in support for Debian/BusyBox `/etc/network/interfaces` * Built-in support for Debian/BusyBox `/etc/network/interfaces`
* Cgroups v2, both configuration and monitoring in `initctl top` * Cgroups v2, both configuration and monitoring in `initctl top`
* Plugin support for customization * Plugin support for customization
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
Focus is on small and embedded systems, although Finit is fully usable Focus is on small and embedded systems, although Finit is fully usable
on server and desktop systems as well. For working examples, see the on server and desktop systems as well. For working examples, see the
+4 -21
View File
@@ -1,4 +1,4 @@
AC_INIT(Finit, 4.0-rc4, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html) AC_INIT(Finit, 4.0, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
AC_CONFIG_AUX_DIR(aux) AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects]) AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
@@ -48,11 +48,6 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
PKG_CHECK_MODULES([lite], [libite >= 2.2.0]) PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
# Check for configured Finit features # Check for configured Finit features
AC_ARG_ENABLE(emergency_shell,
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
Use only for debugging very early boot problems with Finit]),,[
enable_emergency_shell=no])
AC_ARG_ENABLE(auto_reload, AC_ARG_ENABLE(auto_reload,
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[ AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
enable_auto_reload=no]) enable_auto_reload=no])
@@ -61,10 +56,6 @@ AC_ARG_ENABLE(redirect,
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[ AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
enable_redirect=yes]) enable_redirect=yes])
AC_ARG_ENABLE(logit,
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
enable_logit=yes])
AC_ARG_ENABLE(logrotate, AC_ARG_ENABLE(logrotate,
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[ AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
enable_logrotate=yes]) enable_logrotate=yes])
@@ -122,14 +113,11 @@ AC_ARG_WITH(random-seed,
AC_ARG_WITH(watchdog, AC_ARG_WITH(watchdog,
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]), AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
[watchdog=$withval],[watchdog=]) [watchdog=$withval], [with_watchdog=no watchdog=])
### Enable features ########################################################################### ### Enable features ###########################################################################
# Create config.h from selected features and fallback defaults # Create config.h from selected features and fallback defaults
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
AS_IF([test "x$enable_auto_reload" = "xyes"], [ AS_IF([test "x$enable_auto_reload" = "xyes"], [
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])]) AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
@@ -137,9 +125,6 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])]) AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
### Disable features ########################################################################### ### Disable features ###########################################################################
AS_IF([test "x$enable_logit" != "xno"], [
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
AS_IF([test "x$enable_logrotate" != "xno"], [ AS_IF([test "x$enable_logrotate" != "xno"], [
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])]) AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
@@ -198,12 +183,12 @@ AS_IF([test "x$with_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [ AS_IF([test "x$watchdog" = "xyes"], [
watchdog=/dev/watchdog]) watchdog=/dev/watchdog])
with_watchdog=yes with_watchdog=yes
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])]) AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
watchdog=])
# Control build with automake flags # Control build with automake flags
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"]) AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"]) AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"]) AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"]) AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
@@ -251,8 +236,6 @@ Optional features:
Install contrib/......: $enable_contrib Install contrib/......: $enable_contrib
Built-in watchdogd....: $with_watchdog $watchdog Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate Built-in logrotate....: $enable_logrotate
Scripting tool logit..: $enable_logit
Emergency shell.......: $enable_emergency_shell
Redirect output.......: $enable_redirect Redirect output.......: $enable_redirect
Default hostname......: $hostname Default hostname......: $hostname
Default runlevel......: $runlevel Default runlevel......: $runlevel
+14 -3
View File
@@ -20,6 +20,9 @@ tools pre-systemd work as intended.
root@debian:~# apt install initscripts console-setup root@debian:~# apt install initscripts console-setup
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
> the main section of Debian. So just install the -dev packages :)
The following script can then be used to configure, build, install and The following script can then be used to configure, build, install and
set up your system to run Finit: set up your system to run Finit:
@@ -32,17 +35,25 @@ also possible to change the default init to Finit, if you do you can
remove the custom Grub entry: remove the custom Grub entry:
user@debian:~/finit# cd /sbin user@debian:~/finit# cd /sbin
user@debian:/sbin# sudo rm init user@debian:/sbin# sudo mv init oldinit
user@debian:/sbin# sudo ln -s finit init user@debian:/sbin# sudo ln -s finit init
Before rebooting, check the default [/etc/finit.conf](finit.conf) and Before rebooting, check the default [/etc/finit.conf](finit.conf) and
`/etc/finit.d/*.conf` files. The build + install script above provides `/etc/finit.d/*.conf` files. The build + install script above provides
a few sample `.conf` files. See `initctl list` after boot for a list of a few sample `.conf` files. See `initctl ls` after boot for a list of
enabled and available services. enabled and available services, you can then use `enable` and `disable`
comands to `initctl`, followed by `reload` to activate your changes.
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
and initialization like keyboard language etc. and initialization like keyboard language etc.
If you want to use the X Window system, `sudo apt install elogind`
(Bullseye and later). Followed by `initctl reload` (enabled by default)
and logout/login again. The elogind daemon ensures a regular non-root
user can start and interact with an X session, otherwise keyboard and
mouse won't work.
Have fun! Have fun!
/Joachim ツ /Joachim ツ
+3 -2
View File
@@ -1,7 +1,8 @@
SUBDIRS = available SUBDIRS = available
docsdir := @docdir@/contrib/debian/finit.d docsdir := @docdir@/contrib/debian/finit.d
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \ d_LINKS = console-setup.conf elogind.conf getty.conf \
modules.conf rsyslogd.conf sshd.conf keyboard-setup.conf modules.conf rsyslogd.conf \
sshd.conf
install-exec-hook: install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available @$(MKDIR_P) $(DESTDIR)$(docsdir)/available
+3 -3
View File
@@ -1,5 +1,5 @@
docsdir := @docdir@/contrib/debian/finit.d/available docsdir := @docdir@/contrib/debian/finit.d/available
docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \ docs_DATA = acpid.conf console-setup.conf elogind.conf getty.conf \
lightdm.conf modules.conf rsyslogd.conf sntpd.conf \ keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
sshd.conf syslogd.conf xdm.conf rsyslogd.conf sshd.conf syslogd.conf xdm.conf
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
@@ -0,0 +1,4 @@
# On some systems, bootstrap can be really quick and cause elogind
# to not start before a user has managed to log in. To prevent
# this, add <pid/elogind> as condition to your TTYs in getty.conf
service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
+5 -3
View File
@@ -9,9 +9,11 @@ Bootstrap
6. Load all `.so` plugins 6. Load all `.so` plugins
7. Call `fsck` on file systems listed in `/etc/fstab` 7. Call `fsck` on file systems listed in `/etc/fstab`
8. Populate `/dev` using either udev or mdev, depending on system type 8. Populate `/dev` using either udev or mdev, depending on system type
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files 9. Parse `/etc/finit.conf`
10. Start built-in watchdog, if enabled 10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
11. Set hostname means any WDT that requires a kernel module need to be either
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
11. Load all `/etc/finit.d/*.conf` files and set hostname
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro` 12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
13. Call 1st level hooks, `HOOK_ROOTFS_UP` 13. Call 1st level hooks, `HOOK_ROOTFS_UP`
14. Mount all file systems listed in `/etc/fstab` and swap, if available 14. Mount all file systems listed in `/etc/fstab` and swap, if available
+7 -5
View File
@@ -30,10 +30,12 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
* `quiet`: Suppress kernel logging to console, except for warnings and * `quiet`: Suppress kernel logging to console, except for warnings and
errors. errors.
* `rescue`: Start Finit rescue mode; no network, no `fsck` of file * `rescue`: Start rescue/maintenance mode. If your system comes with
systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The the bundled `sulogin` program (Finit, or from util-linux/Busybox),
configuration is read from `/lib/finit/rescue.conf`, and can be you will be given a root login to a maintenance shell. However, if
modified by the operator. `sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
the system booted in a limited fallback mode. See [config.md][]
for more information.
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to * `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
debug problems with the regular runlevel. All services and TTYs in debug problems with the regular runlevel. All services and TTYs in
@@ -42,5 +44,5 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
For more on kernel boot paramaters, see the man page [bootparam(7)][]. For more on kernel boot paramaters, see the man page [bootparam(7)][].
[config.md][]: config.md#rescue-mode
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html [bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
+125 -23
View File
@@ -21,9 +21,11 @@ Configuration
* [TTYs and Consoles](#ttys-and-consoles) * [TTYs and Consoles](#ttys-and-consoles)
* [Non-privileged Services](#non-privileged-services) * [Non-privileged Services](#non-privileged-services)
* [Redirecting Output](#redirecting-output) * [Redirecting Output](#redirecting-output)
* [Rescue Mode](#rescue-mode)
* [Limitations](#limitations) * [Limitations](#limitations)
* [/etc/finit.conf](#etcfinitconf) * [/etc/finit.conf](#etcfinitconf)
* [/etc/finit.d](#etcfinitd) * [/etc/finit.d](#etcfinitd)
* [Watchdog](#watchdog)
Introduction Introduction
@@ -37,8 +39,8 @@ Linux distributions -- each package can provide its own "script" file.
- `/etc/finit.d/*.conf`: snippets, usually one service per file - `/etc/finit.d/*.conf`: snippets, usually one service per file
Not all configuration directives are available in `/etc/finit.d/*.conf` Not all configuration directives are available in `/etc/finit.d/*.conf`
and some directives are only available at bootstrap, runlevel `S`, see and some directives are only available at [bootstrap][], runlevel `S`,
the section [Limitations](#limitations) below for details. see the section [Limitations](#limitations) below for details.
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
@@ -203,7 +205,7 @@ the contents of that file is used.
Deprecated. We recommend using `/etc/hostname` instead. Deprecated. We recommend using `/etc/hostname` instead.
> **Note:** only read and executed in runlevel S (bootstrap). > **Note:** only read and executed in runlevel S ([bootstrap][]).
### Kernel Modules ### Kernel Modules
@@ -221,7 +223,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS" $MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
> **Note:** only read and executed in runlevel S (bootstrap). > **Note:** only read and executed in runlevel S ([bootstrap][]).
### Networking ### Networking
@@ -234,7 +236,7 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
or `/etc/network/interfaces` if you have a system with `ifupdown`, like or `/etc/network/interfaces` if you have a system with `ifupdown`, like
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system. Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
> **Note:** only read and executed in runlevel S (bootstrap). > **Note:** only read and executed in runlevel S ([bootstrap][]).
### Resource Limits ### Resource Limits
@@ -268,13 +270,13 @@ stanzas can share the same rlimits if they are in the same .conf.
**Syntax:** `runlevel <N>` **Syntax:** `runlevel <N>`
Defines the system runlevel to go to after bootstrap (S) has completed. The system runlevel to go to after [bootstrap][] (S) has completed. `N`
N is the runlevel number 0-9, where 6 is reserved for reboot and 0 for is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
halt. halt.
Default: 2 Default: 2
> **Note:** only read and executed in runlevel S (bootstrap). > **Note:** only read and executed in runlevel S ([bootstrap][]).
### One-shot Commands (sequence) ### One-shot Commands (sequence)
@@ -426,7 +428,7 @@ SIGKILLed, this can be adjusted using the above `kill:SEC` syntax.
Call [run-parts(8)][] on `DIR` to run start scripts. All executable Call [run-parts(8)][] on `DIR` to run start scripts. All executable
files, or scripts, in the directory are called, in alphabetic order. files, or scripts, in the directory are called, in alphabetic order.
The scripts in this directory are executed at the very end of runlevel The scripts in this directory are executed at the very end of runlevel
`S`, bootstrap. `S`, [bootstrap][].
It can be beneficial to use `S01name`, `S02othername`, etc. if there It can be beneficial to use `S01name`, `S02othername`, etc. if there
is a dependency order between the scripts. Symlinks to existing is a dependency order between the scripts. Symlinks to existing
@@ -436,7 +438,9 @@ Similar to the `/etc/rc.local` shell script, make sure that all your
services and programs either terminate or start in the background or services and programs either terminate or start in the background or
you will block Finit. you will block Finit.
> **Note:** only read and executed in runlevel S (bootstrap). > **Note:** only read and executed in runlevel S ([bootstrap][]).
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
### Including Finit Configs ### Including Finit Configs
@@ -464,7 +468,8 @@ size limit is reached.
### TTYs and Consoles ### TTYs and Consoles
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]` **Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]` `tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
`tty [LVLS] <COND> [notty] [rescue]`
The first variant of this option uses the built-in getty on the given The first variant of this option uses the built-in getty on the given
TTY device DEV, in the given runlevels. The DEV may be the special TTY device DEV, in the given runlevels. The DEV may be the special
@@ -483,9 +488,18 @@ The default baud rate is 0, i.e., keep kernel default.
The second `tty` syntax variant is for using an external getty, like The second `tty` syntax variant is for using an external getty, like
agetty or the BusyBox getty. agetty or the BusyBox getty.
By default both variants *clear* the TTY and *wait* for the user to The third variant is for board bringup and the `rescue` boot mode. No
press enter before starting getty. device node is required in this variant, the same output that the kernel
uses is reused for stdio. If the `rescue` option is omitted, a shell is
started (`nologin`, `noclear`, and `nowait` are implied), if the rescue
option is set the bundled `/libexec/finit/sulogin` is started to present
a bare-bones root login prompt. If the root (uid:0, gid:0) user does
not have a password set, no rescue is possible. For more information,
see the [Rescue Mode](#rescue-mode) section.
By default, the first two syntax variants *clear* the TTY and *wait* for
the user to press enter before starting getty.
**Example:** **Example:**
@@ -522,10 +536,11 @@ can be omitted to keep the kernel default.
tty [12345] @console noclear vt220 tty [12345] @console noclear vt220
On really bare bones systems Finit can give you a shell prompt as On really bare bones systems, or for board bringup, Finit can give you a
soon as bootstrap is done, without opening any device node: shell prompt as soon as [bootstrap][] is done, without opening any
device node:
tty [12345789] notty noclear tty [12345789] notty
This should of course not be enabled on production systems. Because it This should of course not be enabled on production systems. Because it
may give a user root access without having to log in. However, for may give a user root access without having to log in. However, for
@@ -581,6 +596,59 @@ Log rotation is controlled using the global `log` setting.
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
Rescue Mode
-----------
Finit supports a rescue mode which is activated by the `rescue` option
on the kernel command line. See [cmdline docs](cmdline.md) for how to
activate it.
The rescue mode comes in two flavors; *traditional* and *fallback*.
### Traditional
This is what most users expect. A very early maintenance login prompt,
served by the bundled `/libexec/finit/sulogin` program, or the standard
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
rescue mode is ended and the system boots up normally.
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
> __the account is locked__, the user is presented with a password-less
> `"Press enter to enter maintenance mode."`, prompt which opens up a
> root shell.
### Fallback
If no `sulogin` program is found, Finit tries to bring up as much of its
own functionality as possible, yet limiting many aspects, meaning; no
network, no `fsck` of file systems in `/etc/fstab`, no `/etc/rc.local`,
no `runparts`, and most plugins are skipped (except those that provide
functionality for the condition subsystem).
Instead of reading `/etc/finit.conf` et al, system configuration is read
from `/lib/finit/rescue.conf`, which can be freely modified by the
system administrator.
The bundled default `rescue.conf` contains nothing more than:
runlevel 1
tty [12345] rescue
The `tty` has the `rescue` option set, which works similar to the board
bring-up tty option `notty`. The major difference being that `sulogin`
is started to query for root/admin password. If `sulogin` is not found,
`rescue` behaves like `notty` and gives a plain root shell prompt.
If Finit cannot find `/lib/finit/rescue.conf` it defaults to:
tty [12345] rescue
There is no way to exit the *fallback* rescue mode.
Limitations Limitations
----------- -----------
@@ -590,15 +658,49 @@ from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
Originally, `/etc/finit.conf` was the only way to set up a Finit system. Originally, `/etc/finit.conf` was the only way to set up a Finit system.
Today it is mainly used for bootstrap settings like system hostname, Today it is mainly used for bootstrap settings like system hostname,
network bringup and system shutdown. These can now also be set in any early module loading for watchdogd, network bringup and system shutdown.
`.conf` file in `/etc/finit.d`. These can now also be set in any `.conf` file in `/etc/finit.d`.
There is, however, nothing preventing you from having all configuration There is, however, nothing preventing you from having all configuration
settings in `/etc/finit.conf`. settings in `/etc/finit.conf`.
> **Note:** The `/etc/finit.d` directory was previously the default > **Note:** The `/etc/finit.d` directory was previously the default
> Finit `runparts` directory. Finit no longer has a default > Finit [runparts](#run-parts-scripts) directory. Finit no
> `runparts`, make sure to update your setup, or the finit > longer has a default `runparts`, make sure to update your
> configuration, accordingly. > setup, or the finit configuration, accordingly.
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
Watchdog
--------
When built `--with-watchdog` a separate service is built and installed
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
device node exists, Finit will start it and treat it as the elected
watchdog service to delegate its reboot to. See [bootstrap][] for
details. This delegation is to ensure that the system is rebooted by a
hardware watchdog timer -- on many embedded systems this is crucial to
ensure all circuits on the board are properly reset for the next boot,
in effect ensuring the system works the same after both a power-on and
reboot event.
The delegation is performed at the very last steps of system shutdown,
if reboot has been selected and an elected watchdog is known, first a
`SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when
the necessary steps of preparing the system for shutdown (umount etc.)
are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a
10 sec timeout loop waiting for the WDT to reset the board. If a reset
is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)`
which tells the kernel to do the reboot.
An external watchdog service can also be used. The more advanced cousin
[watchdogd](https://github.com/troglobit/watchdogd/) is the recommended
option here. It can register itself with Finit using the same IPC as
`initctl`. If the bundled watchdogd is running a hand-over takes place,
so it's safe to have both services installed on a system. For the
hand-over to work it requires that the WDT driver supports the safe exit
functionality where `"V"` is written to the device before closing the
device descriptor. If the kernel driver has been built without this,
the only option is to remove `/libexec/finit/watchdogd` or build without
it at configure time.
[bootstrap]: bootstrap.md
+10
View File
@@ -30,6 +30,11 @@
static void save(void *arg) static void save(void *arg)
{ {
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
if (whichp(ALSACTL)) { if (whichp(ALSACTL)) {
_d("Saving sound settings ..."); _d("Saving sound settings ...");
run_interactive(ALSACTL " -g store", "Saving sound settings"); run_interactive(ALSACTL " -g store", "Saving sound settings");
@@ -38,6 +43,11 @@ static void save(void *arg)
static void restore(void *arg) static void restore(void *arg)
{ {
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
if (whichp(ALSACTL)) { if (whichp(ALSACTL)) {
_d("Restoring sound settings ..."); _d("Restoring sound settings ...");
run_interactive(ALSACTL " -g restore", "Restoring sound settings"); run_interactive(ALSACTL " -g restore", "Restoring sound settings");
+5
View File
@@ -43,6 +43,11 @@ static void setup(void *arg)
mode_t prev; mode_t prev;
char *cmd; char *cmd;
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
cmd = which(DAEMON); cmd = which(DAEMON);
if (!cmd) { if (!cmd) {
_d("Skipping plugin, %s is not installed.", DAEMON); _d("Skipping plugin, %s is not installed.", DAEMON);
+5
View File
@@ -34,6 +34,11 @@ static void setup(void *arg)
char cmd[256]; char cmd[256];
char *path; char *path;
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
/* /*
* Populate /dev and prepare for runtime events from kernel. * Populate /dev and prepare for runtime events from kernel.
* Prefer udev if mdev is also available on the system. * Prefer udev if mdev is also available on the system.
+8
View File
@@ -23,6 +23,9 @@
#include <glob.h> #include <glob.h>
#include <lite/lite.h> #include <lite/lite.h>
#include "finit.h"
#include "helpers.h"
#include "plugin.h" #include "plugin.h"
static void setup(void *arg) static void setup(void *arg)
@@ -31,6 +34,11 @@ static void setup(void *arg)
glob_t gl; glob_t gl;
char buf[160]; char buf[160];
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
glob("/run/sysctl.d/*.conf", 0, NULL, &gl); glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl); glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl); glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
+10
View File
@@ -84,6 +84,11 @@ static void rtc_save(void *arg)
int fd, rc = 0; int fd, rc = 0;
char tz[128]; char tz[128];
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
fd = rtc_open(); fd = rtc_open();
if (fd < 0) if (fd < 0)
return; return;
@@ -121,6 +126,11 @@ static void rtc_restore(void *arg)
int fd, rc = 0; int fd, rc = 0;
char tz[128]; char tz[128];
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
fd = rtc_open(); fd = rtc_open();
if (fd < 0) if (fd < 0)
return; return;
+10
View File
@@ -35,6 +35,11 @@
static void setup(void *arg) static void setup(void *arg)
{ {
#ifdef RANDOMSEED #ifdef RANDOMSEED
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
if (!fexist(RANDOMSEED)) { if (!fexist(RANDOMSEED)) {
int ret = 1; int ret = 1;
mode_t prev; mode_t prev;
@@ -71,6 +76,11 @@ static void save(void *arg)
#ifdef RANDOMSEED #ifdef RANDOMSEED
mode_t prev; mode_t prev;
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
prev = umask(077); prev = umask(077);
print_desc("Saving random seed", NULL); print_desc("Saving random seed", NULL);
+5
View File
@@ -39,6 +39,11 @@ static void setup(void *arg)
int fd; int fd;
#endif #endif
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
prev = umask(0); prev = umask(0);
makedir("/var/run/console", 01777); makedir("/var/run/console", 01777);
+1
View File
@@ -3,6 +3,7 @@ finit
initctl initctl
logit logit
reboot reboot
sulogin
watchdogd watchdogd
Makefile Makefile
Makefile.in Makefile.in
+6 -5
View File
@@ -8,21 +8,22 @@ AM_LDFLAGS = -export-dynamic
endif endif
sbin_PROGRAMS = finit initctl sbin_PROGRAMS = finit initctl
pkglibexec_PROGRAMS = pkglibexec_PROGRAMS = logit sulogin
finit_pkglibdir = $(pkglibdir) finit_pkglibdir = $(pkglibdir)
finit_pkglib_SCRIPTS = rescue.conf sample.conf finit_pkglib_SCRIPTS = rescue.conf sample.conf
sulogin_SOURCES = sulogin.c
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
sulogin_LDADD = -lcrypt
if WATCHDOGD if WATCHDOGD
pkglibexec_PROGRAMS += watchdogd pkglibexec_PROGRAMS += watchdogd
endif endif
if LOGIT
pkglibexec_PROGRAMS += logit
logit_SOURCES = logit.c logrotate.c logit_SOURCES = logit.c logrotate.c
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
logit_CFLAGS += $(lite_CFLAGS) logit_CFLAGS += $(lite_CFLAGS)
logit_LDADD = $(lite_LIBS) logit_LDADD = $(lite_LIBS)
endif
finit_SOURCES = api.c cgroup.c cgroup.h \ finit_SOURCES = api.c cgroup.c cgroup.h \
cond.c cond-w.c cond.h \ cond.c cond-w.c cond.h \
@@ -47,7 +48,7 @@ if LOGROTATE
finit_SOURCES += logrotate.c finit_SOURCES += logrotate.c
endif endif
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h pkginclude_HEADERS = cgroup.h cond.h finit.h helpers.h log.h plugin.h svc.h
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS) finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
+1 -1
View File
@@ -580,7 +580,7 @@ static void key(uev_t *w, void *arg, int events)
break; break;
default: default:
warnx("Got char 0x%02x", ch); dbg("Got char 0x%02x", ch);
break; break;
} }
} }
+1 -1
View File
@@ -672,7 +672,7 @@ int conf_reload(void)
if (rescue) { if (rescue) {
int rc; int rc;
char line[80] = "tty [12345] @console noclear nologin"; char line[80] = "tty [12345] rescue";
/* If rescue.conf is missing, fall back to a root shell */ /* If rescue.conf is missing, fall back to a root shell */
rc = parse_conf(RESCUE_CONF, 0); rc = parse_conf(RESCUE_CONF, 0);
+18 -47
View File
@@ -52,6 +52,7 @@
#include "util.h" #include "util.h"
#include "utmp-api.h" #include "utmp-api.h"
#include "schedule.h" #include "schedule.h"
#include "watchdog.h"
int runlevel = 0; /* Bootstrap 'S' */ int runlevel = 0; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */ int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
@@ -234,48 +235,6 @@ static void fs_init(void)
} }
} }
/*
* If everything goes south we can use this to give the operator an
* emergency shell to debug the problem -- Finit should not crash!
*
* Note: Only use this for debugging a new Finit setup, don't use
* this in production since it gives a root shell to anyone
* if Finit crashes.
*
* This emergency shell steps in to prevent "Aieee, PID 1 crashed"
* messages from the kernel, which usually results in a reboot, so
* that the operator instead can debug the problem.
*/
static void emergency_shell(void)
{
#ifdef EMERGENCY_SHELL
pid_t pid;
pid = fork();
if (pid) {
while (1) {
pid_t id;
/* Reap 'em (prevents Zombies) */
id = waitpid(-1, NULL, WNOHANG);
if (id == pid)
break;
}
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
fprintf(stderr, "=> To debug, add 'debug' to the kernel command line.\n\n");
/*
* Become session leader and set controlling TTY
* to enable Ctrl-C and job control in shell.
*/
setsid();
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
}
#endif /* EMERGENCY_SHELL */
}
/* /*
* Handle bootstrap transition to configured runlevel, start TTYs * Handle bootstrap transition to configured runlevel, start TTYs
@@ -504,13 +463,24 @@ int main(int argc, char *argv[])
if (chdir("/")) if (chdir("/"))
_pe("Failed cd /"); _pe("Failed cd /");
/* Allow progress, if enabled */
enable_progress(1);
/* /*
* In case of emergency. * In case of emergency.
*/ */
emergency_shell(); if (rescue) {
char *sulogin[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(sulogin); i++) {
if (systemf(sulogin[i]))
continue;
rescue = 0;
break;
}
}
/* /*
* Load plugins early, the first hook is in banner(), so we * Load plugins early, the first hook is in banner(), so we
@@ -521,6 +491,7 @@ int main(int argc, char *argv[])
/* /*
* Hello world. * Hello world.
*/ */
enable_progress(1); /* Allow progress, if enabled */
banner(); banner();
/* /*
@@ -552,7 +523,7 @@ int main(int argc, char *argv[])
/* /*
* Start built-in watchdogd as soon as possible, if enabled * Start built-in watchdogd as soon as possible, if enabled
*/ */
if (which(FINIT_LIBPATH_ "/watchdogd")) { if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
service_register(SVC_TYPE_SERVICE, "[123456789] name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL); service_register(SVC_TYPE_SERVICE, "[123456789] name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
wdog = svc_find_by_nameid("watchdog", "finit"); wdog = svc_find_by_nameid("watchdog", "finit");
} }
+2 -1
View File
@@ -50,7 +50,8 @@
#define FINIT_CGPATH "/sys/fs/cgroup" #define FINIT_CGPATH "/sys/fs/cgroup"
#endif #endif
#define LOGIT_PATH FINIT_LIBPATH_ "/logit" #define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
#define CMD_SIZE 256 #define CMD_SIZE 256
#define LINE_SIZE 1024 #define LINE_SIZE 1024
+2 -2
View File
@@ -189,8 +189,8 @@ static int do_login(char *name)
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL); execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
/* /*
* Failed to exec login, should be impossible. Try a starting a * Failed to exec login, should not happen on normal systems.
* fallback shell instead. * Try a starting a rescue shell instead.
* *
* Note: Add /etc/securetty handling. * Note: Add /etc/securetty handling.
*/ */
+17 -1
View File
@@ -94,8 +94,24 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
wd = inotify_add_watch(iw->fd, path, IWATCH_MASK | mask); wd = inotify_add_watch(iw->fd, path, IWATCH_MASK | mask);
if (wd < 0) { if (wd < 0) {
if (errno != EEXIST) switch (errno) {
case EEXIST:
break;
case EINVAL:
/*
* some older kernels, notably 4.19, don't like
* inotify on top-level cgroups in cgroup v2
*/
if (!strncmp(path, "/sys/fs/cgroup", 14))
break; /* ignore error */
/* fallthrough */
default:
_pe("Failed adding watcher for %s", path); _pe("Failed adding watcher for %s", path);
break;
}
free(path); free(path);
return -1; return -1;
} }
+1 -2
View File
@@ -1,3 +1,2 @@
runlevel 1 runlevel 1
hostname rescue tty [12345] rescue
tty [12345] @console noclear nologin
+12 -5
View File
@@ -206,8 +206,8 @@ static int lredirect(svc_t *svc)
/* Reset signals */ /* Reset signals */
sig_unblock(); sig_unblock();
if (!whichp(LOGIT_PATH)) { if (!whichp(_PATH_LOGIT)) {
logit(LOG_INFO, LOGIT_PATH " missing, using syslog for %s instead", svc->name); logit(LOG_INFO, _PATH_LOGIT " missing, using syslog for %s instead", svc->name);
fallback_logger(tag, prio); fallback_logger(tag, prio);
_exit(0); _exit(0);
} }
@@ -218,7 +218,7 @@ static int lredirect(svc_t *svc)
snprintf(sz, sizeof(sz), "%d", logfile_size_max); snprintf(sz, sizeof(sz), "%d", logfile_size_max);
snprintf(num, sizeof(num), "%d", logfile_count_max); snprintf(num, sizeof(num), "%d", logfile_count_max);
execlp(LOGIT_PATH, "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL); execlp(_PATH_LOGIT, "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
_exit(1); _exit(1);
} }
@@ -227,7 +227,7 @@ static int lredirect(svc_t *svc)
if (svc->log.prio[0]) if (svc->log.prio[0])
prio = svc->log.prio; prio = svc->log.prio;
execlp(LOGIT_PATH, "logit", "-t", tag, "-p", prio, NULL); execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, NULL);
_exit(1); _exit(1);
} }
@@ -466,7 +466,7 @@ static int service_start(svc_t *svc)
return 1; return 1;
} }
if (svc_is_tty(svc)) { if (svc_is_tty(svc) && !svc->notty) {
char *dev = tty_canonicalize(svc->dev); char *dev = tty_canonicalize(svc->dev);
if (!dev || !tty_exists(dev)) { if (!dev || !tty_exists(dev)) {
@@ -1044,6 +1044,12 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
} }
} }
/*
* Check also for changes to /etc/default/foo, because this
* also constitutes changes to command line args.
*/
diff += conf_changed(svc_getenv(svc));
if (diff) if (diff)
_d("Modified args for %s detected", cmd); _d("Modified args for %s detected", cmd);
svc->args_dirty = (diff > 0); svc->args_dirty = (diff > 0);
@@ -1295,6 +1301,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
svc->nowait = tty.nowait; svc->nowait = tty.nowait;
svc->nologin = tty.nologin; svc->nologin = tty.nologin;
svc->notty = tty.notty; svc->notty = tty.notty;
svc->rescue = tty.rescue;
/* TTYs cannot be redirected */ /* TTYs cannot be redirected */
log = NULL; log = NULL;
+213
View File
@@ -0,0 +1,213 @@
/* poor man's sulogin, may be statically linked
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <crypt.h>
#include <err.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* getpwnam() cannot be used when statically linked */
static int get_passwd(struct passwd *pw)
{
char *ptr, *tmp;
char buf[256];
FILE *fp;
fp = fopen("/etc/passwd", "r");
if (!fp)
return 1;
while ((tmp = fgets(buf, sizeof(buf), fp))) {
if (!strstr(buf, ":0:0:"))
continue; /* not uid 0 */
ptr = strsep(&tmp, ":");
if (!ptr)
break;
pw->pw_name = strdup(ptr);
ptr = strsep(&tmp, ":");
if (!ptr)
break;
/* x : password in /etc/shadow, see passwd(5) */
if (ptr[0] != 'x')
pw->pw_passwd = strdup(ptr);
break; /* done, check it */
}
fclose(fp);
if (!pw->pw_name)
return 1; /* no uid 0 here */
if (pw->pw_passwd)
return 0; /* passwd in passwd */
fp = fopen("/etc/shadow", "r");
if (!fp) {
if (pw->pw_name)
free(pw->pw_name);
return 1;
}
while ((tmp = fgets(buf, sizeof(buf), fp))) {
ptr = strsep(&tmp, ":");
if (!ptr)
break;
if (!strcmp(tmp, pw->pw_name))
continue;
ptr = strsep(&tmp, ":");
if (!ptr)
break;
pw->pw_passwd = strdup(ptr);
break;
}
fclose(fp);
if (!pw->pw_passwd) {
if (pw->pw_name)
free(pw->pw_name);
return 1; /* nopass => nologin */
}
return 0; /* passwd in shadow */
}
static void freepw(struct passwd *pw)
{
if (pw->pw_passwd) {
free(pw->pw_passwd);
pw->pw_passwd = NULL;
}
free(pw->pw_name);
}
static int sh(void)
{
/*
* Become session leader and set controlling TTY
* to enable Ctrl-C and job control in shell.
*/
setsid();
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
setenv("PS1", "# ", 1);
return execl(_PATH_BSHELL, "-sh", NULL);
}
int main(void)
{
struct termios old, raw;
struct passwd pw = { 0 };
int rc = 1, ch;
if (get_passwd(&pw))
err(1, "reading credentials for UID 0");
switch (pw.pw_passwd[0]) {
case '*': case '!': /* login disabled, allow */
printf("The %s account is locked, allowing entry.\n", pw.pw_name);
/* fallthrough */
case 0: /* no password at all? */
printf("Press enter for maintenance (Ctrl-D to continue) ");
fflush(stdout);
ch = getchar();
if (ch == 4 || ch == EOF) { /* Ctrl-D */
rc = 0;
goto done;
}
goto nopass;
case '$': /* md5/shaN or similar, original DES not supported */
break;
default:
break;
}
if (tcgetattr(1, &old) < 0)
goto done; /* failed reading tty */
raw = old;
raw.c_lflag &= ~ICANON;
raw.c_lflag &= ~ECHO;
raw.c_cc[VMIN] = 1;
raw.c_cc[VTIME] = 0;
if (tcsetattr(1, TCSANOW, &raw) < 0) {
tcsetattr(1, TCSANOW, &old);
goto done; /* failed setting raw/pw mode */
}
while (1) {
char pwd[256]; /* reasonable max? */
size_t i = 0;
char *passwd;
printf("Give %s password for maintenance (Ctrl-D to continue): ", pw.pw_name);
fflush(stdout);
do {
ch = getchar();
if (ch == '\n' || ch == '\r')
break;
if (ch == 4 || ch == EOF) { /* Ctrl-D */
rc = 0;
goto exit;
}
pwd[i++] = ch;
} while (i + 1 < sizeof(pwd));
pwd[i] = 0;
puts("");
passwd = crypt(pwd, pw.pw_passwd);
if (passwd && !strcmp(passwd, pw.pw_passwd)) {
tcsetattr(1, TCSANOW, &old); /* restore tty */
nopass:
freepw(&pw);
return sh();
}
}
exit:
tcsetattr(1, TCSANOW, &old); /* restore tty */
puts("");
done:
freepw(&pw);
return rc;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+1 -1
View File
@@ -433,7 +433,7 @@ svc_t *svc_find_by_tty(char *dev)
{ {
svc_t *svc, *iter = NULL; svc_t *svc, *iter = NULL;
/* this is valid for fallback (notty) shells */ /* rescue (notty) shells have no device node */
if (!dev) if (!dev)
return NULL; return NULL;
+1
View File
@@ -149,6 +149,7 @@ typedef struct svc {
char nowait; char nowait;
char nologin; char nologin;
char notty; char notty;
char rescue;
}; };
}; };
+34 -17
View File
@@ -158,7 +158,9 @@ int tty_parse_args(char *cmd, struct tty *tty)
else if (!strcmp(cmd, "nologin")) else if (!strcmp(cmd, "nologin"))
tty->nologin = 1; tty->nologin = 1;
else if (!strcmp(cmd, "notty")) else if (!strcmp(cmd, "notty"))
tty->notty = 1; /* for fallback shell */ tty->notty = 1; /* for board bringup */
else if (!strcmp(cmd, "rescue"))
tty->rescue = 1; /* for rescue shells */
else if (!access(cmd, X_OK)) else if (!access(cmd, X_OK))
tty->cmd = cmd; tty->cmd = cmd;
else else
@@ -167,6 +169,10 @@ int tty_parse_args(char *cmd, struct tty *tty)
cmd = strtok(NULL, " \t"); cmd = strtok(NULL, " \t");
} while (cmd && tty->num < NELEMS(tty->args)); } while (cmd && tty->num < NELEMS(tty->args));
/* rescue shells are always notty */
if (tty->rescue)
tty->notty = 1;
/* skip /dev probe, we just want a bríngup shell */ /* skip /dev probe, we just want a bríngup shell */
if (tty->notty) if (tty->notty)
return 0; return 0;
@@ -220,27 +226,38 @@ int tty_parse_args(char *cmd, struct tty *tty)
int tty_exists(char *dev) int tty_exists(char *dev)
{ {
int fd, result;
struct termios c; struct termios c;
int fd, rc;
fd = open(dev, O_RDWR); fd = open(dev, O_RDWR);
if (-1 == fd) if (-1 == fd)
return 0; return 0;
/* XXX: Add check for errno == EIO? */ /* XXX: Add check for errno == EIO? */
result = tcgetattr(fd, &c); rc = tcgetattr(fd, &c);
close(fd); close(fd);
return result == 0; return rc == 0;
} }
int tty_exec(svc_t *tty) int tty_exec(svc_t *svc)
{ {
char *args[MAX_NUM_SVC_ARGS]; char *args[MAX_NUM_SVC_ARGS];
char *dev; char *dev;
int i, j; int i, j;
if (tty->notty) { /* try to protect system with sulogin, fall back to root shell */
if (svc->notty) {
if (svc->rescue) {
/* check if bundled one is available */
if (whichp(_PATH_SULOGIN))
return execl(_PATH_SULOGIN, _PATH_SULOGIN, NULL);
/* util-linux or busybox, no args for compat */
if (whichp("sulogin"))
return execlp("sulogin", "sulogin", NULL);
}
/* /*
* Become session leader and set controlling TTY * Become session leader and set controlling TTY
* to enable Ctrl-C and job control in shell. * to enable Ctrl-C and job control in shell.
@@ -249,12 +266,12 @@ int tty_exec(svc_t *tty)
ioctl(STDIN_FILENO, TIOCSCTTY, 1); ioctl(STDIN_FILENO, TIOCSCTTY, 1);
prctl(PR_SET_NAME, "finitsh", 0, 0, 0); prctl(PR_SET_NAME, "finitsh", 0, 0, 0);
return execl(_PATH_BSHELL, _PATH_BSHELL, NULL); return execl(_PATH_BSHELL, "-sh", NULL);
} }
dev = tty_canonicalize(tty->dev); dev = tty_canonicalize(svc->dev);
if (!dev) { if (!dev) {
_d("%s: Cannot find TTY device: %s", tty->dev, strerror(errno)); _d("%s: Cannot find TTY device: %s", svc->dev, strerror(errno));
return EX_CONFIG; return EX_CONFIG;
} }
@@ -263,24 +280,24 @@ int tty_exec(svc_t *tty)
return EX_OSFILE; return EX_OSFILE;
} }
if (tty->nologin) { if (svc->nologin) {
_d("%s: Starting /bin/sh ...", dev); _d("%s: Starting /bin/sh ...", dev);
return run_sh(dev, tty->noclear, tty->nowait, tty->rlimit); return run_sh(dev, svc->noclear, svc->nowait, svc->rlimit);
} }
_d("%s: Starting %sgetty ...", dev, !tty->cmd ? "built-in " : ""); _d("%s: Starting %sgetty ...", dev, !svc->cmd ? "built-in " : "");
if (!strcmp(tty->cmd, "tty")) if (!strcmp(svc->cmd, "tty"))
return run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit); return run_getty(dev, svc->baud, svc->term, svc->noclear, svc->nowait, svc->rlimit);
for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) { for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) {
if (!tty->args[i][0]) if (!svc->args[i][0])
break; break;
args[j++] = tty->args[i]; args[j++] = svc->args[i];
} }
args[j++] = NULL; args[j++] = NULL;
return run_getty2(dev, tty->cmd, args, tty->noclear, tty->nowait, tty->rlimit); return run_getty2(dev, svc->cmd, args, svc->noclear, svc->nowait, svc->rlimit);
} }
/** /**
+1
View File
@@ -40,6 +40,7 @@ struct tty {
char nowait; char nowait;
char nologin; char nologin;
char notty; char notty;
char rescue;
}; };
char *tty_canonicalize (char *dev); char *tty_canonicalize (char *dev);