mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e85c4f3d1 | ||
|
|
2531102623 | ||
|
|
33deada6f0 | ||
|
|
9d1506bb7e | ||
|
|
c3f115c9ec | ||
|
|
430d402b14 | ||
|
|
e011dac98b | ||
|
|
42b84d1ccb | ||
|
|
288105eac7 | ||
|
|
842b522e68 | ||
|
|
e6f36974c8 | ||
|
|
679b4df881 | ||
|
|
666cae6f49 | ||
|
|
be2ac1d1b1 | ||
|
|
266e5b30eb | ||
|
|
4e5d06b580 | ||
|
|
fe334135ce | ||
|
|
aef10fb5e7 | ||
|
|
86707c1f0b | ||
|
|
a28d5b3c09 | ||
|
|
550ae9c784 | ||
|
|
cd5b91680a | ||
|
|
221ab20898 | ||
|
|
96534789db | ||
|
|
26128dd788 | ||
|
|
799e992542 | ||
|
|
fa524eec60 | ||
|
|
6dced29b49 | ||
|
|
2ea613a42b | ||
|
|
985df20519 | ||
|
|
f6161b9be9 | ||
|
|
25c5014d3c | ||
|
|
b8b7b53d96 | ||
|
|
7707c4b8e6 |
+42
-14
@@ -4,12 +4,12 @@ Change Log
|
||||
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
|
||||
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
|
||||
* 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,
|
||||
use an external inetd, like xinetd, instead. A pull request for a
|
||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||
* Incompatible `configure` script changes, i.e., you must give proper
|
||||
path arguments to the script, no more guessing just GNU defaults.
|
||||
There are examples in the documentation and the `contrib/` section
|
||||
* Change service conditions from the non-obvious `<svc/path/to/foo>` to
|
||||
`<pid/foo:id>`. This to hopefully make it clear that one service's
|
||||
'pid:!foo' pidfile is another service's `<pid/foo>` condition
|
||||
* Initial support for cgroups, every service now runs in its own cgroup
|
||||
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||
* Incompatible `configure` script changes, i.e., no guessing `--prefix`
|
||||
and other paths. Also, many options have been changed, renamed, or
|
||||
flipped defaults, or even dropped altogether. There are examples in
|
||||
the documentation and the `contrib/` section
|
||||
* Service conditions change from the non-obvious `<svc/path/to/foo>` to
|
||||
`<pid/foo:id>`. Not only does this give simpler internal semantics,
|
||||
it hopefully also makes it clear that one service's `pid:!foo` pidfile
|
||||
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
|
||||
event loop earlier. This also facilitated factoring out functionality
|
||||
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
||||
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
|
||||
services, stared using `sysv` or `service` stanza
|
||||
* Support for custom `kill:DELAY`, default 3 sec.
|
||||
* 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`,
|
||||
useful with new `sysv` or `service` which fork to background
|
||||
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
||||
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`
|
||||
* Prefer udev to handle `/dev/` if mdev is also available
|
||||
* 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
|
||||
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
||||
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
|
||||
include statements. No more native `ifup` of individual interfaces,
|
||||
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
|
||||
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||
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 #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||
Fixed by Jonas Johansson, Westermo
|
||||
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||
* 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 #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||
fixed by Jacques de Laval, Westermo
|
||||
* Fix #124: Lingering processes in process group when session leader
|
||||
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
|
||||
wrong service, by Jonas Holmberg, Westermo
|
||||
* 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
|
||||
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
||||
* 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
|
||||
@@ -748,14 +776,14 @@ Major bug fix release.
|
||||
* Makefile fixes for installation, paths encoded wrong
|
||||
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
||||
* 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
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Update README with section on building and enviroment variables
|
||||
* Update README with section on building and environment variables
|
||||
|
||||
### Fixes
|
||||
* Fix installation paths encoded in finit binary
|
||||
|
||||
@@ -44,6 +44,7 @@ Features include:
|
||||
* Built-in support for Debian/BusyBox `/etc/network/interfaces`
|
||||
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||
* 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
|
||||
on server and desktop systems as well. For working examples, see the
|
||||
|
||||
+4
-21
@@ -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)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -48,11 +48,6 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
||||
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
||||
|
||||
# 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,
|
||||
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||
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]),,[
|
||||
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,
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||
enable_logrotate=yes])
|
||||
@@ -122,14 +113,11 @@ AC_ARG_WITH(random-seed,
|
||||
|
||||
AC_ARG_WITH(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 ###########################################################################
|
||||
|
||||
# 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"], [
|
||||
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])])
|
||||
|
||||
### 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"], [
|
||||
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"], [
|
||||
watchdog=/dev/watchdog])
|
||||
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
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
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(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||
|
||||
@@ -251,8 +236,6 @@ Optional features:
|
||||
Install contrib/......: $enable_contrib
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Scripting tool logit..: $enable_logit
|
||||
Emergency shell.......: $enable_emergency_shell
|
||||
Redirect output.......: $enable_redirect
|
||||
Default hostname......: $hostname
|
||||
Default runlevel......: $runlevel
|
||||
|
||||
@@ -20,6 +20,9 @@ tools pre-systemd work as intended.
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
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
|
||||
|
||||
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
||||
`/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
|
||||
enabled and available services.
|
||||
a few sample `.conf` files. See `initctl ls` after boot for a list of
|
||||
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
|
||||
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!
|
||||
/Joachim ツ
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
SUBDIRS = available
|
||||
docsdir := @docdir@/contrib/debian/finit.d
|
||||
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
||||
modules.conf rsyslogd.conf sshd.conf
|
||||
d_LINKS = console-setup.conf elogind.conf getty.conf \
|
||||
keyboard-setup.conf modules.conf rsyslogd.conf \
|
||||
sshd.conf
|
||||
|
||||
install-exec-hook:
|
||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||
docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \
|
||||
lightdm.conf modules.conf rsyslogd.conf sntpd.conf \
|
||||
sshd.conf syslogd.conf xdm.conf
|
||||
docs_DATA = acpid.conf console-setup.conf elogind.conf getty.conf \
|
||||
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||
rsyslogd.conf sshd.conf syslogd.conf xdm.conf
|
||||
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
@@ -9,9 +9,11 @@ Bootstrap
|
||||
6. Load all `.so` plugins
|
||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
||||
10. Start built-in watchdog, if enabled
|
||||
11. Set hostname
|
||||
9. Parse `/etc/finit.conf`
|
||||
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||
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`
|
||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
||||
|
||||
+7
-5
@@ -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
|
||||
errors.
|
||||
|
||||
* `rescue`: Start Finit rescue mode; no network, no `fsck` of file
|
||||
systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The
|
||||
configuration is read from `/lib/finit/rescue.conf`, and can be
|
||||
modified by the operator.
|
||||
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||
you will be given a root login to a maintenance shell. However, if
|
||||
`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
|
||||
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)][].
|
||||
|
||||
|
||||
[config.md][]: config.md#rescue-mode
|
||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||
|
||||
+125
-23
@@ -21,9 +21,11 @@ Configuration
|
||||
* [TTYs and Consoles](#ttys-and-consoles)
|
||||
* [Non-privileged Services](#non-privileged-services)
|
||||
* [Redirecting Output](#redirecting-output)
|
||||
* [Rescue Mode](#rescue-mode)
|
||||
* [Limitations](#limitations)
|
||||
* [/etc/finit.conf](#etcfinitconf)
|
||||
* [/etc/finit.d](#etcfinitd)
|
||||
* [Watchdog](#watchdog)
|
||||
|
||||
|
||||
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
|
||||
|
||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
||||
and some directives are only available at bootstrap, runlevel `S`, see
|
||||
the section [Limitations](#limitations) below for details.
|
||||
and some directives are only available at [bootstrap][], runlevel `S`,
|
||||
see the section [Limitations](#limitations) below for details.
|
||||
|
||||
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
|
||||
@@ -203,7 +205,7 @@ the contents of that file is used.
|
||||
|
||||
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
|
||||
@@ -221,7 +223,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||
|
||||
$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
|
||||
@@ -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
|
||||
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
|
||||
@@ -268,13 +270,13 @@ stanzas can share the same rlimits if they are in the same .conf.
|
||||
|
||||
**Syntax:** `runlevel <N>`
|
||||
|
||||
Defines the system runlevel to go to after bootstrap (S) has completed.
|
||||
N is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
halt.
|
||||
|
||||
Default: 2
|
||||
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
|
||||
|
||||
### 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
|
||||
files, or scripts, in the directory are called, in alphabetic order.
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -464,7 +468,8 @@ size limit is reached.
|
||||
### TTYs and Consoles
|
||||
|
||||
**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
|
||||
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
|
||||
agetty or the BusyBox getty.
|
||||
|
||||
By default both variants *clear* the TTY and *wait* for the user to
|
||||
press enter before starting getty.
|
||||
|
||||
The third variant is for board bringup and the `rescue` boot mode. No
|
||||
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:**
|
||||
|
||||
@@ -522,10 +536,11 @@ can be omitted to keep the kernel default.
|
||||
|
||||
tty [12345] @console noclear vt220
|
||||
|
||||
On really bare bones systems Finit can give you a shell prompt as
|
||||
soon as bootstrap is done, without opening any device node:
|
||||
On really bare bones systems, or for board bringup, Finit can give you a
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
-----------
|
||||
|
||||
@@ -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.
|
||||
Today it is mainly used for bootstrap settings like system hostname,
|
||||
network bringup and system shutdown. These can now also be set in any
|
||||
`.conf` file in `/etc/finit.d`.
|
||||
early module loading for watchdogd, network bringup and system shutdown.
|
||||
These can now also be set in any `.conf` file in `/etc/finit.d`.
|
||||
|
||||
There is, however, nothing preventing you from having all configuration
|
||||
settings in `/etc/finit.conf`.
|
||||
|
||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
||||
> Finit `runparts` directory. Finit no longer has a default
|
||||
> `runparts`, make sure to update your setup, or the finit
|
||||
> configuration, accordingly.
|
||||
> Finit [runparts](#run-parts-scripts) directory. Finit no
|
||||
> longer has a default `runparts`, make sure to update your
|
||||
> 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
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
|
||||
static void save(void *arg)
|
||||
{
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (whichp(ALSACTL)) {
|
||||
_d("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)
|
||||
{
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (whichp(ALSACTL)) {
|
||||
_d("Restoring sound settings ...");
|
||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||
|
||||
@@ -43,6 +43,11 @@ static void setup(void *arg)
|
||||
mode_t prev;
|
||||
char *cmd;
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = which(DAEMON);
|
||||
if (!cmd) {
|
||||
_d("Skipping plugin, %s is not installed.", DAEMON);
|
||||
|
||||
@@ -34,6 +34,11 @@ static void setup(void *arg)
|
||||
char cmd[256];
|
||||
char *path;
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate /dev and prepare for runtime events from kernel.
|
||||
* Prefer udev if mdev is also available on the system.
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
|
||||
#include <glob.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *arg)
|
||||
@@ -31,6 +34,11 @@ static void setup(void *arg)
|
||||
glob_t gl;
|
||||
char buf[160];
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
|
||||
@@ -84,6 +84,11 @@ static void rtc_save(void *arg)
|
||||
int fd, rc = 0;
|
||||
char tz[128];
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0)
|
||||
return;
|
||||
@@ -121,6 +126,11 @@ static void rtc_restore(void *arg)
|
||||
int fd, rc = 0;
|
||||
char tz[128];
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
static void setup(void *arg)
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fexist(RANDOMSEED)) {
|
||||
int ret = 1;
|
||||
mode_t prev;
|
||||
@@ -71,6 +76,11 @@ static void save(void *arg)
|
||||
#ifdef RANDOMSEED
|
||||
mode_t prev;
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
prev = umask(077);
|
||||
|
||||
print_desc("Saving random seed", NULL);
|
||||
|
||||
@@ -39,6 +39,11 @@ static void setup(void *arg)
|
||||
int fd;
|
||||
#endif
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
prev = umask(0);
|
||||
|
||||
makedir("/var/run/console", 01777);
|
||||
|
||||
@@ -3,6 +3,7 @@ finit
|
||||
initctl
|
||||
logit
|
||||
reboot
|
||||
sulogin
|
||||
watchdogd
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
+6
-5
@@ -8,21 +8,22 @@ AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS =
|
||||
pkglibexec_PROGRAMS = logit sulogin
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
sulogin_LDADD = -lcrypt
|
||||
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
|
||||
if LOGIT
|
||||
pkglibexec_PROGRAMS += logit
|
||||
logit_SOURCES = logit.c logrotate.c
|
||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
logit_CFLAGS += $(lite_CFLAGS)
|
||||
logit_LDADD = $(lite_LIBS)
|
||||
endif
|
||||
|
||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
cond.c cond-w.c cond.h \
|
||||
@@ -47,7 +48,7 @@ if LOGROTATE
|
||||
finit_SOURCES += logrotate.c
|
||||
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 += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
|
||||
+1
-1
@@ -580,7 +580,7 @@ static void key(uev_t *w, void *arg, int events)
|
||||
break;
|
||||
|
||||
default:
|
||||
warnx("Got char 0x%02x", ch);
|
||||
dbg("Got char 0x%02x", ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -672,7 +672,7 @@ int conf_reload(void)
|
||||
|
||||
if (rescue) {
|
||||
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 */
|
||||
rc = parse_conf(RESCUE_CONF, 0);
|
||||
|
||||
+18
-47
@@ -52,6 +52,7 @@
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
#include "schedule.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
int runlevel = 0; /* Bootstrap 'S' */
|
||||
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
|
||||
@@ -504,13 +463,24 @@ int main(int argc, char *argv[])
|
||||
if (chdir("/"))
|
||||
_pe("Failed cd /");
|
||||
|
||||
/* Allow progress, if enabled */
|
||||
enable_progress(1);
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -521,6 +491,7 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* Hello world.
|
||||
*/
|
||||
enable_progress(1); /* Allow progress, if enabled */
|
||||
banner();
|
||||
|
||||
/*
|
||||
@@ -552,7 +523,7 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* 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);
|
||||
wdog = svc_find_by_nameid("watchdog", "finit");
|
||||
}
|
||||
|
||||
+2
-1
@@ -50,7 +50,8 @@
|
||||
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||
#endif
|
||||
|
||||
#define LOGIT_PATH FINIT_LIBPATH_ "/logit"
|
||||
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
|
||||
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define LINE_SIZE 1024
|
||||
|
||||
+2
-2
@@ -189,8 +189,8 @@ static int do_login(char *name)
|
||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||
|
||||
/*
|
||||
* Failed to exec login, should be impossible. Try a starting a
|
||||
* fallback shell instead.
|
||||
* Failed to exec login, should not happen on normal systems.
|
||||
* Try a starting a rescue shell instead.
|
||||
*
|
||||
* Note: Add /etc/securetty handling.
|
||||
*/
|
||||
|
||||
+17
-1
@@ -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);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,3 +1,2 @@
|
||||
runlevel 1
|
||||
hostname rescue
|
||||
tty [12345] @console noclear nologin
|
||||
tty [12345] rescue
|
||||
|
||||
+12
-5
@@ -206,8 +206,8 @@ static int lredirect(svc_t *svc)
|
||||
/* Reset signals */
|
||||
sig_unblock();
|
||||
|
||||
if (!whichp(LOGIT_PATH)) {
|
||||
logit(LOG_INFO, LOGIT_PATH " missing, using syslog for %s instead", svc->name);
|
||||
if (!whichp(_PATH_LOGIT)) {
|
||||
logit(LOG_INFO, _PATH_LOGIT " missing, using syslog for %s instead", svc->name);
|
||||
fallback_logger(tag, prio);
|
||||
_exit(0);
|
||||
}
|
||||
@@ -218,7 +218,7 @@ static int lredirect(svc_t *svc)
|
||||
snprintf(sz, sizeof(sz), "%d", logfile_size_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);
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ static int lredirect(svc_t *svc)
|
||||
if (svc->log.prio[0])
|
||||
prio = svc->log.prio;
|
||||
|
||||
execlp(LOGIT_PATH, "logit", "-t", tag, "-p", prio, NULL);
|
||||
execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, NULL);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@ static int service_start(svc_t *svc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (svc_is_tty(svc)) {
|
||||
if (svc_is_tty(svc) && !svc->notty) {
|
||||
char *dev = tty_canonicalize(svc->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)
|
||||
_d("Modified args for %s detected", cmd);
|
||||
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->nologin = tty.nologin;
|
||||
svc->notty = tty.notty;
|
||||
svc->rescue = tty.rescue;
|
||||
|
||||
/* TTYs cannot be redirected */
|
||||
log = NULL;
|
||||
|
||||
+213
@@ -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:
|
||||
*/
|
||||
@@ -433,7 +433,7 @@ svc_t *svc_find_by_tty(char *dev)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
/* this is valid for fallback (notty) shells */
|
||||
/* rescue (notty) shells have no device node */
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@ typedef struct svc {
|
||||
char nowait;
|
||||
char nologin;
|
||||
char notty;
|
||||
char rescue;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -158,7 +158,9 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
||||
else if (!strcmp(cmd, "nologin"))
|
||||
tty->nologin = 1;
|
||||
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))
|
||||
tty->cmd = cmd;
|
||||
else
|
||||
@@ -167,6 +169,10 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
||||
cmd = strtok(NULL, " \t");
|
||||
} 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 */
|
||||
if (tty->notty)
|
||||
return 0;
|
||||
@@ -220,27 +226,38 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
||||
|
||||
int tty_exists(char *dev)
|
||||
{
|
||||
int fd, result;
|
||||
struct termios c;
|
||||
int fd, rc;
|
||||
|
||||
fd = open(dev, O_RDWR);
|
||||
if (-1 == fd)
|
||||
return 0;
|
||||
|
||||
/* XXX: Add check for errno == EIO? */
|
||||
result = tcgetattr(fd, &c);
|
||||
rc = tcgetattr(fd, &c);
|
||||
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 *dev;
|
||||
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
|
||||
* to enable Ctrl-C and job control in shell.
|
||||
@@ -249,12 +266,12 @@ int tty_exec(svc_t *tty)
|
||||
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
|
||||
|
||||
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) {
|
||||
_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;
|
||||
}
|
||||
|
||||
@@ -263,24 +280,24 @@ int tty_exec(svc_t *tty)
|
||||
return EX_OSFILE;
|
||||
}
|
||||
|
||||
if (tty->nologin) {
|
||||
if (svc->nologin) {
|
||||
_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 " : "");
|
||||
if (!strcmp(tty->cmd, "tty"))
|
||||
return run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
||||
_d("%s: Starting %sgetty ...", dev, !svc->cmd ? "built-in " : "");
|
||||
if (!strcmp(svc->cmd, "tty"))
|
||||
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++) {
|
||||
if (!tty->args[i][0])
|
||||
if (!svc->args[i][0])
|
||||
break;
|
||||
|
||||
args[j++] = tty->args[i];
|
||||
args[j++] = svc->args[i];
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user