Compare commits

..
48 Commits
Author SHA1 Message Date
Joachim Wiberg 534d50c03a Fix diff link
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 16:09:27 +02:00
Joachim Wiberg 9a42883a96 Bump version to 4.1-rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 16:09:21 +02:00
Joachim Wiberg 7c77e2c2b6 Update with major bug fixes for 4.1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 15:25:03 +02:00
Joachim Wiberg ea8c46cd30 Fix #170: check for loss of default route when interfaces go down
This patch fixes the problem with Linux not sending netlink route change
notifications when interfaces for these routes goes down.  When an iface
goes down we now send a route request to the kernel and check the return
message, if no default route is found we deassert net/default/route.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 15:18:25 +02:00
Joachim Wiberg fead3b0671 configure.ac: drop grub Makefile.in generation
Not needed anymore.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 09:34:27 +02:00
Joachim Wiberg 081990b49e Update for upcoming v4.1 bug fix release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 03:50:12 +02:00
Joachim Wiberg 6b89f8c6db contrib: debian: update README with new grub setup
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 03:39:08 +02:00
Joachim Wiberg 373097040a contrib: debian: update install legend
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 03:03:30 +02:00
Joachim Wiberg a4ab75172c contrib: debian: use SUPPORTED_INITS instead of custom entry
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-03 01:53:09 +02:00
Joachim Wiberg 5cf9958957 contrib: debian: read parameters from /etc/default/grub
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-02 15:43:27 +02:00
Joachim Wiberg b137e08e84 contrib: fix install script to be able to run from tarball
The file autogen.sh is not included in tarballs.  Use configure.ac
instead to detect topdir.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-02 15:30:13 +02:00
Joachim Wiberg a1af8e8687 Follow-up to 4febd28: restore mount of /dev/shm et al for Debian
This patch restores parts of 4febd28, but in a more orderly fashion, in
order to get a standard Debian system to boot properly with X and tools.

The patch adds fs_finalize() which checks if /dev/sh/, /dev/pts, /run,
and /tmp have been mounted properly from /etc/fstab.  If not, then the
function makes sure to mount tmfps (or devpts) file systems as expected
by most modern systems.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-02 15:21:50 +02:00
Joachim Wiberg 53c7ddcb22 Change SIGUSR1 to be compatible with systemd and SysV init
This patch changes the behavior of SIGUSR1.  Previously USR1 could be
used to halt a running Finit system, similar to BusyBox init.  However,
compatibility with sysvinit and systemd has been deemed more important.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-02 14:48:49 +02:00
Joachim Wiberg 3872077ff1 plugins: netlink: stricter interface name validation
Coverity suggests validating against only a set of known characters.
However, the kernel allows just about all characters in an interface
name.  This version of valdiate_ifname() is blatantly stolen, more
or less, from linux/net/core/dev.c

 https://code.woboq.org/linux/linux/net/core/dev.c.html#1020

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-29 17:19:19 +02:00
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
42 changed files with 804 additions and 229 deletions
+68 -21
View File
@@ -4,12 +4,37 @@ Change Log
All relevant changes are documented in this file.
[4.0][UNRELEASED] - 2021-03-xx
------------------------------
[4.1][UNRELEASED]
-----------------
Bug fix release.
### Changes
* Change behavior on SIGUSR1 to be compatible with sysvinit and systemd.
Previously SIGUSR1 caused Finit to halt, like BusyBox init. This had
"interesting" side effects on Debian systems when coexisting with
sysvinit (upgrading/reinstalling causes scripts to `kill -USR1 1`)
* Change how `contrib/debian/install.sh` sets up a Grub boot entry for
finit. We now modify the $SUPPORTED_INITS variable in `10_linux`
### Fixes
* Stricter interface name validation in netlink plugin, modeled after
the kernel. Suggested by Coverity Scan
* The `contrib/*/install.sh` scripts failed to run from tarball
* Fix #170: detect loss of default route when interfaces go down. This
emulates the missing kernel netlink message to remove the condition
net/default/route to allow stopping dependent services
* Fix #171: restore automatic mount of `/dev/shm`, `/dev/pts`, `/run`
and `/tmp`, unless mounted already by `/etc/fstab`. This is what most
desktop systems expect PID 1 to do
[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 +49,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 +139,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 +158,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 +191,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 +801,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
@@ -847,7 +900,7 @@ Major bug fix release.
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.0...HEAD
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
@@ -879,9 +932,3 @@ Major bug fix release.
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
[libuEv]: https://github.com/troglobit/libuev
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+1
View File
@@ -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
+5 -22
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.1-rc1, 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])
@@ -8,7 +8,7 @@ AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile
contrib/Makefile
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
doc/Makefile
plugins/Makefile
@@ -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
+1 -1
View File
@@ -10,7 +10,7 @@ fi
# Adjust base directory
if [ -e alpine-release ]; then
cd ../..
elif [ ! -e autogen.sh ]; then
elif [ ! -e configure.ac ]; then
echo "*** Please run this script from the Finit base directory."
exit 1
fi
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS = finit.d grub.d
SUBDIRS = finit.d
docsdir := @docdir@/contrib/debian
docs_DATA = README.md finit.conf os-release build.sh install.sh
EXTRA_DIST = $(docs_DATA)
+19 -7
View File
@@ -20,29 +20,41 @@ 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:
user@debian:~/finit$ contrib/debian/build.sh
However, since `/sbin/init` already exists on your system, the script
creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
where `init=/sbin/finit` is added to your kernel line. It is of course
also possible to change the default init to Finit, if you do you can
remove the custom Grub entry:
creates another entry in your GRUB config by updating `$SUPPORTED_INITS`
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find
a (finit) entry in the "Advanced options for Debian GNU/Linux" section.
It is of course also possible to change the default init to Finit:
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. When you're happy, you can enable the lightdm.conf,
change the default runlevel to 3, and presto! you have a desktop again.
Have fun!
/Joachim ツ
+3 -2
View File
@@ -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
+3 -3
View File
@@ -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
-14
View File
@@ -1,14 +0,0 @@
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
insmod gzio
insmod part_msdos
insmod ext2
search --no-floppy --fs-uuid --set=root $BOOT
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
initrd /initrd.img
}
-3
View File
@@ -1,3 +0,0 @@
docsdir := @docdir@/contrib/debian/grub.d
docs_DATA = 40_custom
EXTRA_DIST = $(docs_DATA)
+14 -8
View File
@@ -11,7 +11,7 @@ fi
grep -q Debian os-release 2>/dev/null
if [ $? -eq 0 ]; then
cd ../..
elif [ ! -e autogen.sh ]; then
elif [ ! -e configure.ac ]; then
echo "*** Please run this script from the Finit base directory."
exit 1
fi
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
echo "/lib/finit/plugins/* - All enabled Finit plugins"
echo "/etc/finit.conf - Finit configuration file"
echo "/etc/finit.d/ - Finit services"
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
echo "/etc/grub.d/10_linux - Add Finit to Grub's SUPPORTED_INITS"
echo
read -p "Do you want to continue (y/N)? " yorn
echo
@@ -38,12 +38,18 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
cp -va finit.d /etc/
echo "*** Setting up a GRUB boot entry ..."
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
update-grub
fn=/etc/grub.d/10_linux
if [ -e $fn ]; then
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then
echo "Already installed, done."
else
echo "Adding Finit to list of SUPPORTED_INITS ..."
sed -i 's/SUPPORTED_INITS="[^"]*/& finit:\/sbin\/finit/' $fn
update-grub
fi
else
echo "Cannot find $fn, you'll have to set up your bootloader on your own."
fi
echo
echo "*** Done"
+1 -1
View File
@@ -10,7 +10,7 @@ fi
# Adjust base directory
if [ -e xbps ]; then
cd ../..
elif [ ! -e autogen.sh ]; then
elif [ ! -e configure.ac ]; then
echo "*** Please run this script from the Finit base directory."
exit 1
fi
+5 -3
View File
@@ -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
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
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
View File
@@ -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
+17 -9
View File
@@ -12,28 +12,36 @@ have been adopted:
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
*.conf files in `/etc/finit.d/`
This also restarts the API (initctl) socket, like SysV init and systemd
does on USR1 with their FIFO/D-Bus.
`SIGUSR1`
---------
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
processes, and unmounts all file systems. Then tells kernel to halt.
Most people these days want `SIGUSR2` though.
Since Finit 4.1 this signal causes Finit to restart its API (initctl)
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus.
Finit <= 4.0 performed a system halt (like USR2 without power-off), but
this caused compatibility problems with systemd and sysvinit on desktop
systems. Hence, since Finit 4.1 it is no longer possible to halt a
system with a signal.
SysV init and systemd use this to re-open their FIFO/D-Bus.
`SIGUSR2`
---------
Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
similar exists to actually do this. If the kernel fails power-off,
Finit falls back to halt.
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
processes, and unmounts all file systems. Then tells kernel to power
off the system, if ACPI or similar exists to actually do this. If the
kernel fails power-off, Finit falls back to halt.
SysV init N/A, systemd dumps its internal state to log.
`SIGTERM`
---------
Like `SIGUSR1`, but tell kernel to reboot the system when done.
Like `SIGUSR2`, but tell kernel to reboot the system when done.
SysV init N/A, systemd rexecutes itself.
+10
View File
@@ -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");
+5
View File
@@ -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);
+5
View File
@@ -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.
+108 -10
View File
@@ -31,6 +31,9 @@
#include "helpers.h"
#include "plugin.h"
static int ifdown = 0;
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
{
if (!NLMSG_OK(nh, len))
@@ -51,10 +54,16 @@ static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
{
char daddr[INET_ADDRSTRLEN];
char gaddr[INET_ADDRSTRLEN];
struct in_addr ind, ing;
struct rtmsg *r;
struct rtattr *a;
int plen = 0;
int dst = 0;
int idx = 0;
int gw = 0;
int la;
int gw = 0, dst = 0, mask = 0, idx = 0;
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
_e("Packet too small or truncated!");
@@ -80,8 +89,8 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
case RTA_DST:
dst = *((int *)data);
mask = r->rtm_dst_len;
//_d("MASK: 0x%04x", mask);
plen = r->rtm_dst_len;
//_d("Prefix LEN: 0x%04x", plen);
break;
case RTA_OIF:
@@ -93,7 +102,13 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
a = RTA_NEXT(a, la);
}
if ((!dst && !mask) && (gw || idx)) {
ind.s_addr = dst;
ing.s_addr = gw;
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
_d("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
if ((!dst && !plen) && (gw || idx)) {
if (nlmsg->nlmsg_type == RTM_DELROUTE)
cond_clear("net/route/default");
else
@@ -101,6 +116,36 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
}
}
static int nl_default(struct nlmsghdr *nlh, struct in_addr *dst, struct in_addr *gw)
{
struct in_addr nil = { 0 };
struct rtattr *a;
struct rtmsg *r;
int len;
r = (struct rtmsg *)NLMSG_DATA(nlh);
if ((r->rtm_family != AF_INET) || (r->rtm_table != RT_TABLE_MAIN))
return -1;
len = RTM_PAYLOAD(nlh);
for (a = RTM_RTA(r); RTA_OK(a, len); a = RTA_NEXT(a, len)) {
switch (a->rta_type) {
case RTA_GATEWAY:
memcpy(gw, RTA_DATA(a), sizeof(*gw));
break;
case RTA_DST:
memcpy(dst, RTA_DATA(a), sizeof(*dst));
break;
}
}
if (!memcmp(dst, &nil, sizeof(nil)) && memcmp(gw, &nil, sizeof(nil)))
return 0;
return 1;
}
static void net_cond_set(char *ifname, char *cond, int set)
{
char msg[MAX_ARG_LEN];
@@ -117,14 +162,14 @@ static int validate_ifname(const char *ifname)
if (!ifname || !ifname[0])
return 1;
if (strlen(ifname) >= IFNAMSIZ)
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
return 1;
if (strstr(ifname, ".."))
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
return 1;
while (*ifname) {
if (*ifname == '/' || isspace(*ifname))
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
return 1;
ifname++;
}
@@ -134,10 +179,10 @@ static int validate_ifname(const char *ifname)
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
{
int la;
char ifname[IFNAMSIZ + 1];
struct rtattr *a;
struct ifinfomsg *i;
struct rtattr *a;
int la;
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
_e("Packet too small or truncated!");
@@ -172,6 +217,8 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
net_cond_set(ifname, "exist", 1);
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
ifdown = 1;
break;
case RTM_DELLINK:
@@ -180,6 +227,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
net_cond_set(ifname, "exist", 0);
net_cond_set(ifname, "up", 0);
net_cond_set(ifname, "running", 0);
ifdown = 1;
break;
case RTM_NEWADDR:
@@ -211,6 +259,9 @@ static void nl_callback(void *arg, int sd, int events)
return;
}
/* check for interface changes -> loss of default route */
ifdown = 0;
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
@@ -218,6 +269,53 @@ static void nl_callback(void *arg, int sd, int events)
else
nl_link(nh, len);
}
/*
* Linux doesn't send route changes, when interfaces go down, so
* we need to check ourselves, e.g. for loss of default route.
*/
if (ifdown) {
unsigned int seq = 0;
int found = 0;
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sd < 0) {
_pe("netlink socket");
return;
}
memset(buf, 0, sizeof(buf));
nh = (struct nlmsghdr *)buf;
nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nh->nlmsg_type = RTM_GETROUTE;
nh->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
nh->nlmsg_seq = seq++;
nh->nlmsg_pid = 1;
if (send(sd, nh, nh->nlmsg_len, 0) < 0) {
_pe("Failed netlink route request");
close(sd);
return;
}
len = recv(sd, buf, sizeof(buf), 0);
close(sd);
for (; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
struct in_addr dst = { 0 };
struct in_addr gw = { 0 };
if (nl_default(nh, &dst, &gw))
continue;
_d("default via %s\n", inet_ntoa(gw));
found = 1;
}
/* We already get notification when adding default rt */
if (!found)
cond_clear("net/route/default");
}
}
static void nl_reconf(void *arg)
@@ -236,8 +334,8 @@ static plugin_t plugin = {
PLUGIN_INIT(plugin_init)
{
int sd;
struct sockaddr_nl sa;
int sd;
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sd < 0) {
+8
View File
@@ -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);
+10
View File
@@ -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;
+10
View File
@@ -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);
+5
View File
@@ -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);
+1
View File
@@ -3,6 +3,7 @@ finit
initctl
logit
reboot
sulogin
watchdogd
Makefile
Makefile.in
+6 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+59 -47
View File
@@ -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 */
@@ -185,6 +186,44 @@ static void fs_remount_root(int fsckerr)
}
#endif /* SYSROOT */
/*
* Opinionated file system setup. Checks for critical mount points and
* mounts them as most users expect. All file systems are checked with
* /proc/mounts before mounting.
*
* Embedded systems, and other people who want full control, can set up
* their system with /etc/fstab, which is handled before this function
* is called. For systems like Debian/Ubuntu, who only have / and swap
* in their /etc/fstab, this function does all the magic necessary.
*/
static void fs_finalize(void)
{
/*
* Some systems rely on us to both create /dev/shm and, to mount
* a tmpfs there. Any system with dbus needs shared memory, so
* mount it, unless its already mounted, but not if listed in
* the /etc/fstab file already.
*/
if (!fismnt("/dev/shm")) {
makedir("/dev/shm", 0777);
mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
}
/* Modern systems use /dev/pts */
if (!fismnt("/dev/pts")) {
makedir("/dev/pts", 0755);
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620,ptmxmode=0666");
}
/* Modern systems use tmpfs for /run */
if (!fismnt("/run"))
mount("tmpfs", "/run", "tmpfs", 0, "mode=0755,nosuid,nodev,noexec,relatime");
/* Modern systems use tmpfs for /tmp */
if (!fismnt("/tmp"))
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=0755,nosuid,nodev");
}
static void fs_mount(void)
{
if (!rescue)
@@ -200,6 +239,9 @@ static void fs_mount(void)
plugin_run_hooks(HOOK_MOUNT_POST);
run("swapon -ea");
_d("Finalize, ensure common file systems are available ...");
fs_finalize();
}
/*
@@ -234,48 +276,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 +504,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 +532,7 @@ int main(int argc, char *argv[])
/*
* Hello world.
*/
enable_progress(1); /* Allow progress, if enabled */
banner();
/*
@@ -552,7 +564,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
View File
@@ -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
View File
@@ -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
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);
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 -1
View File
@@ -206,7 +206,7 @@ int reboot_main(int argc, char *argv[])
case CMD_HALT:
if (do_halt(NULL))
do_kill(SIGUSR1, msg);
do_kill(SIGUSR2, msg);
break;
case CMD_POWEROFF:
+1 -2
View File
@@ -1,3 +1,2 @@
runlevel 1
hostname rescue
tty [12345] @console noclear nologin
tty [12345] rescue
+12 -5
View File
@@ -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;
+16 -12
View File
@@ -31,21 +31,24 @@
* does on USR1 with their FIFO/D-Bus.
*
* SIGUSR1
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
* processes, and unmounts all file systems. Then tells kernel to
* halt. Most people these days want SIGUSR2 though.
* Restarts API (initctl) socket, like SysV init and systemd does
* on USR1 with their FIFO/D-Bus.
*
* (SysV init and systemd use this to re-open their FIFO/D-Bus.)
* Finit <= 4.0 used to perform a system halt on USR1. This caused
* some quite nasty problems on systems with both systemd/sysvinit
* installed alongside finit. For compatibility reasons Finit 4.1
* changed to partial SIGHUP (api_exit/init).
*
* SIGUSR2
* Like SIGUSR1, but tell kernel to power-off the system, if ACPI
* or similar exists to actually do this. If the kernel fails
* power-off, Finit falls back to halt.
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
* processes, and unmounts all file systems. Then tells kernel to
* power-off the system, if ACPI or similar exists to actually do
* this. If the kernel fails power-off, Finit falls back to halt.
*
* (SysV init N/A, systemd dumps its internal state to log.)
*
* SIGTERM
* Like SIGUSR1, but tell kernel to reboot the system when done.
* Like SIGUSR2, but tell kernel to reboot the system when done.
*
* (SysV init N/A, systemd rexecutes itself.)
*
@@ -323,7 +326,7 @@ static void sigint_cb(uev_t *w, void *arg, int events)
}
/*
* SIGUSR1: BusyBox style halt
* SIGUSR1: SysV init/systemd API socket restart
*/
static void sigusr1_cb(uev_t *w, void *arg, int events)
{
@@ -333,8 +336,9 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
return;
}
halt = SHUT_HALT;
service_runlevel(0);
/* Restart initctl API domain socket, similar to systemd/SysV init */
api_exit();
api_init(w->ctx);
}
/*
@@ -520,7 +524,7 @@ void sig_setup(uev_ctx_t *ctx)
/* Standard SysV init calls ctrl-alt-delete handler */
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
/* BusyBox init style signals for halt, power-off and reboot. */
/* BusyBox/SysV init style signals for halt, power-off and reboot. */
uev_signal_init(ctx, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
uev_signal_init(ctx, &sigpwr_watcher, sigusr2_cb, NULL, SIGPWR);
+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;
/* this is valid for fallback (notty) shells */
/* rescue (notty) shells have no device node */
if (!dev)
return NULL;
+1
View File
@@ -149,6 +149,7 @@ typedef struct svc {
char nowait;
char nologin;
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"))
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);
}
/**
+1
View File
@@ -40,6 +40,7 @@ struct tty {
char nowait;
char nologin;
char notty;
char rescue;
};
char *tty_canonicalize (char *dev);