mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
81
Commits
4.0-rc4
...
debian-fixes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40042da8ff | ||
|
|
c251304146 | ||
|
|
c047e37a79 | ||
|
|
d2c57447f0 | ||
|
|
79e9dabc11 | ||
|
|
b04dc4d457 | ||
|
|
f86e7810be | ||
|
|
2018c82ea1 | ||
|
|
c27f3603e6 | ||
|
|
6f82b806ad | ||
|
|
cbb8935660 | ||
|
|
21ebbb942f | ||
|
|
988ecd95e3 | ||
|
|
3f3e70c686 | ||
|
|
073b040981 | ||
|
|
b1a058ccdd | ||
|
|
cbc7b8c3c7 | ||
|
|
13340e4200 | ||
|
|
0076c1f218 | ||
|
|
6fc71b7528 | ||
|
|
b42f1e99e2 | ||
|
|
afd6ad06a6 | ||
|
|
ea0bfaa2f3 | ||
|
|
5c3ec176c2 | ||
|
|
40425ee9ec | ||
|
|
424db825a3 | ||
|
|
b9cc4cd629 | ||
|
|
243b8f025b | ||
|
|
6c60b67588 | ||
|
|
910bb13711 | ||
|
|
add55cfc2a | ||
|
|
565820325b | ||
|
|
6bb4d67d92 | ||
|
|
534d50c03a | ||
|
|
9a42883a96 | ||
|
|
7c77e2c2b6 | ||
|
|
ea8c46cd30 | ||
|
|
fead3b0671 | ||
|
|
081990b49e | ||
|
|
6b89f8c6db | ||
|
|
373097040a | ||
|
|
a4ab75172c | ||
|
|
5cf9958957 | ||
|
|
b137e08e84 | ||
|
|
a1af8e8687 | ||
|
|
53c7ddcb22 | ||
|
|
3872077ff1 | ||
|
|
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 |
+78
-21
@@ -4,12 +4,47 @@ 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
|
||||
* Fix #173: netlink plugin runs out of socket buffer space;
|
||||
|
||||
finit[1]: nl_callback():recv(): No buffer space available
|
||||
|
||||
Fixed by adding support for resync with kernel on `ENOBUFS`. See
|
||||
netlink(7) for details. As a spin-off the plugin now supports any
|
||||
number of interfaces and routes on a system. On resync, the following
|
||||
message is now logged, as a warning:
|
||||
|
||||
finit[1]: nl_callback():busy system, resynchronizing with kernel.
|
||||
|
||||
|
||||
[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 +59,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 +149,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 +168,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 +201,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 +811,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 +910,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 +942,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:
|
||||
-->
|
||||
|
||||
@@ -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
|
||||
@@ -133,7 +134,7 @@ Some components are optional: runlevel(s), condition(s) and description,
|
||||
making it easy to create simple start scripts and still possible for more
|
||||
advanced uses as well:
|
||||
|
||||
service sshd -D
|
||||
service /usr/sbin/sshd -D
|
||||
|
||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||
the most common conditions is to wait for basic networking to become
|
||||
@@ -459,9 +460,6 @@ Commands:
|
||||
halt Halt system
|
||||
poweroff Halt and power off system
|
||||
suspend Suspend system
|
||||
|
||||
Bug report address: https://github.com/troglobit/finit/issues
|
||||
Project homepage: https://troglobit.com/finit.html
|
||||
```
|
||||
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
|
||||
+5
-22
@@ -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
|
||||
|
||||
@@ -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,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)
|
||||
|
||||
@@ -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 ツ
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
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 = acpid.conf apparmor.conf avahi-demon.conf \
|
||||
bluetooth.conf 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,7 @@
|
||||
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 apparmor.conf avahi-daemon.conf bluetooth.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 @@
|
||||
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
|
||||
@@ -0,0 +1,2 @@
|
||||
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
|
||||
@@ -0,0 +1,3 @@
|
||||
# To ignore errors like "org.freedesktop.hostname1", update the env file with
|
||||
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
|
||||
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
|
||||
@@ -0,0 +1 @@
|
||||
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
|
||||
@@ -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
|
||||
@@ -1,4 +1,7 @@
|
||||
# Consoles to start getty on when system is up
|
||||
tty [12345] /dev/tty1 linux noclear nowait
|
||||
tty [2345] /dev/tty2 linux noclear nowait
|
||||
tty [2345] /dev/tty3 linux noclear nowait
|
||||
tty [2345] /dev/tty2 linux nowait
|
||||
tty [2345] /dev/tty3 linux nowait
|
||||
tty [2345] /dev/tty4 linux nowait
|
||||
tty [2345] /dev/tty5 linux nowait
|
||||
tty [2345] /dev/tty6 linux nowait
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
docsdir := @docdir@/contrib/debian/grub.d
|
||||
docs_DATA = 40_custom
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,12 +26,18 @@ Some of these are also registered in the issue tracker on GitHub.
|
||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||
`pimd` man pages ...
|
||||
|
||||
|
||||
Initctl
|
||||
-------
|
||||
|
||||
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
||||
|
||||
shutdown -h 03:35 "foobar was here"
|
||||
|
||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||
`initctl show --json`
|
||||
* Add support for `-s` to redirect all output to syslog, for scripting
|
||||
|
||||
|
||||
Init
|
||||
|
||||
+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
|
||||
|
||||
+17
-9
@@ -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.
|
||||
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c usr.c
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c sys.c tty.c urandom.c usr.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -34,7 +34,7 @@ libplug_la_SOURCES += resolvconf.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la usr.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la sys.la tty.la urandom.la usr.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
|
||||
@@ -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");
|
||||
|
||||
+12
-5
@@ -119,15 +119,16 @@ static void setup(void *arg)
|
||||
makedir("/var/lib/urandom",0755);
|
||||
if (fisdir("/run")) {
|
||||
_d("System with new /run tmpfs ...");
|
||||
makedir("/run/lock", 1777);
|
||||
if (!fisdir("/run/lock"))
|
||||
makedir("/run/lock", 1777);
|
||||
symlink("/run/lock", "/var/lock");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
|
||||
/* compat only, should really be set up by OS/dist */
|
||||
symlink("/run", "/var/run");
|
||||
symlink("/run", "/var/run");
|
||||
} else {
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
}
|
||||
makedir("/var/log", 0755);
|
||||
makedir("/var/mail", 0755);
|
||||
@@ -183,6 +184,12 @@ static void setup(void *arg)
|
||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
||||
|
||||
/* Debian has /run/sudo, ensure correct perms and SELinux label */
|
||||
mksubsys("/var/run/sudo", 0711, "root", "root");
|
||||
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
||||
if (whichp("restorecon"))
|
||||
run("restorecon /var/run/sudo /var/run/sudo/ts");
|
||||
|
||||
umask(prev);
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -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);
|
||||
@@ -59,7 +64,7 @@ static void setup(void *arg)
|
||||
remove("/var/run/dbus/pid");
|
||||
|
||||
/* Register service with Finit */
|
||||
snprintf(line, sizeof(line), "[S12345789] @%s:%s %s %s -- %s",
|
||||
snprintf(line, sizeof(line), "[S12345789] cgroup.system @%s:%s %s %s -- %s",
|
||||
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||
_pe("Failed registering %s", DAEMON);
|
||||
|
||||
+8
-3
@@ -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.
|
||||
@@ -43,17 +48,17 @@ static void setup(void *arg)
|
||||
path = which("/lib/systemd/systemd-udevd");
|
||||
if (path) {
|
||||
/* Register udevd as a monitored service */
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] cgroup.system pid:udevd name:udevd log %s "
|
||||
"-- Device event managing daemon", path);
|
||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||
_pe("Failed registering %s", path);
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
|
||||
snprintf(cmd, sizeof(cmd), "cgroup.init :1 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t devices "
|
||||
"-- Requesting device events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
|
||||
snprintf(cmd, sizeof(cmd), "cgroup.init :2 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t subsystems "
|
||||
"-- Requesting subsystem events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||
#endif
|
||||
#define SERVICE_LINE \
|
||||
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
|
||||
static void load(void *arg)
|
||||
{
|
||||
@@ -71,8 +71,7 @@ static void load(void *arg)
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
||||
index, mod, mod, args, mod);
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
|
||||
index++;
|
||||
|
||||
+227
-42
@@ -30,31 +30,35 @@
|
||||
#include "cond.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
|
||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
||||
{
|
||||
if (!NLMSG_OK(nh, len))
|
||||
return 1;
|
||||
#define NL_BUFSZ 4096
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
||||
_d("Done with netlink messages.");
|
||||
return 1;
|
||||
}
|
||||
struct nl_request {
|
||||
struct nlmsghdr nh;
|
||||
union {
|
||||
struct rtmsg rtm;
|
||||
struct ifinfomsg ifi;
|
||||
};
|
||||
};
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
||||
_d("Netlink reports error.");
|
||||
return 1;
|
||||
}
|
||||
static int nl_defidx;
|
||||
static int nl_ifdown;
|
||||
static char *nl_buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 +84,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,11 +97,20 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
a = RTA_NEXT(a, la);
|
||||
}
|
||||
|
||||
if ((!dst && !mask) && (gw || idx)) {
|
||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
||||
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
|
||||
nl_defidx = 0;
|
||||
} else {
|
||||
cond_set("net/route/default");
|
||||
nl_defidx = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,14 +130,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++;
|
||||
}
|
||||
@@ -132,12 +145,25 @@ static int validate_ifname(const char *ifname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this interface was associated with the default route
|
||||
* previously, or if it's been removed. If so, trigger a recheck
|
||||
* of the system default route.
|
||||
*/
|
||||
static void nl_check_default(char *ifname)
|
||||
{
|
||||
int idx = (int)if_nametoindex(ifname);
|
||||
|
||||
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
|
||||
nl_ifdown = 1;
|
||||
}
|
||||
|
||||
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 +198,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))
|
||||
nl_check_default(ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
@@ -180,6 +208,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);
|
||||
nl_check_default(ifname);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
@@ -197,26 +226,175 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
}
|
||||
}
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
static int nl_parse(int sd)
|
||||
{
|
||||
static char buf[4096];
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
while (1) {
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = recv(sd, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
if (errno != EINTR) /* Signal */
|
||||
_pe("recv()");
|
||||
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN: /* Nothing more right now. */
|
||||
return 0;
|
||||
|
||||
case EINTR: /* Signal */
|
||||
continue;
|
||||
|
||||
case ENOBUFS: /* netlink(7) */
|
||||
break;
|
||||
|
||||
default:
|
||||
_pe("recv()");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("recv %lld bytes", len);
|
||||
|
||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
struct nlmsgerr *nle;
|
||||
|
||||
switch (nh->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
_d("Done with netlink messages.");
|
||||
return 0;
|
||||
|
||||
case NLMSG_ERROR:
|
||||
_d("Kernel netlink comm. error.");
|
||||
nle = NLMSG_DATA(nh);
|
||||
if (nle) {
|
||||
errno = -nle->error;
|
||||
_pe("Kernel netlink error %d", errno);
|
||||
}
|
||||
return -1;
|
||||
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
_d("Netlink route ...");
|
||||
nl_route(nh, len);
|
||||
break;
|
||||
|
||||
case RTM_NEWLINK:
|
||||
case RTM_DELLINK:
|
||||
_d("Netlink link ...");
|
||||
nl_link(nh, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int nl_request(int sd, unsigned int seq, int type)
|
||||
{
|
||||
struct nl_request *nlr = (struct nl_request *)nl_buf;
|
||||
|
||||
memset(nlr, 0, sizeof(struct nl_request));
|
||||
nlr->nh.nlmsg_type = type;
|
||||
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||
nlr->nh.nlmsg_seq = seq;
|
||||
nlr->nh.nlmsg_pid = 1;
|
||||
|
||||
switch (type) {
|
||||
case RTM_GETROUTE:
|
||||
_d("RTM_GETROUTE");
|
||||
nlr->rtm.rtm_family = AF_INET;
|
||||
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
break;
|
||||
|
||||
case RTM_GETLINK:
|
||||
_d("RTM_GETLINK");
|
||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
break;
|
||||
|
||||
default:
|
||||
_w("Cannot resync, unhandled message type %d", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
|
||||
return 1;
|
||||
|
||||
return nl_parse(sd);
|
||||
}
|
||||
|
||||
static void nl_resync_routes(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||
_pe("Failed netlink route request");
|
||||
}
|
||||
|
||||
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_request(sd, seq, RTM_GETLINK))
|
||||
_pe("Failed netlink link request");
|
||||
}
|
||||
|
||||
/*
|
||||
* We've potentially lost netlink events, let's resync with kernel.
|
||||
*/
|
||||
static void nl_resync(int all)
|
||||
{
|
||||
unsigned int seq = 0;
|
||||
int sd;
|
||||
|
||||
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
if (sd < 0) {
|
||||
_pe("netlink socket");
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
nl_route(nh, len);
|
||||
else
|
||||
nl_link(nh, len);
|
||||
if (all) {
|
||||
_d("============================ RESYNC =================================");
|
||||
/* this doesn't update condtions, and thus does not stop services */
|
||||
cond_deassert("net/");
|
||||
|
||||
nl_resync_ifaces(sd, seq++);
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
/* delayed update after we've corrected things */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
_d("=========================== RESYNCED ================================");
|
||||
} else
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
close(sd);
|
||||
}
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
{
|
||||
if (nl_parse(sd) < 0) {
|
||||
if (errno == ENOBUFS) { /* netlink(7) */
|
||||
_w("busy system, resynchronizing with kernel.");
|
||||
nl_resync(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux doesn't send route changes when interfaces go down, so
|
||||
* we need to check ourselves, e.g. for loss of default route.
|
||||
*/
|
||||
if (nl_ifdown) {
|
||||
_d("interface down, checking default route.");
|
||||
if (nl_defidx > 0) {
|
||||
nl_defidx = 0;
|
||||
nl_resync(0);
|
||||
if (nl_defidx <= 0) {
|
||||
cond_clear("net/route/default");
|
||||
nl_defidx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nl_ifdown = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,8 +414,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) {
|
||||
@@ -247,7 +425,7 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
|
||||
sa.nl_pid = getpid();
|
||||
|
||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
@@ -256,6 +434,13 @@ PLUGIN_INIT(plugin_init)
|
||||
return;
|
||||
}
|
||||
|
||||
nl_buf = malloc(NL_BUFSZ);
|
||||
if (!nl_buf) {
|
||||
_pe("malloc()");
|
||||
close(sd);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.io.fd = sd;
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/* System condtion event monitor for the Finit condition engine
|
||||
*
|
||||
* 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 <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <glob.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "pid.h"
|
||||
#include "plugin.h"
|
||||
#include "iwatch.h"
|
||||
|
||||
static struct iwatch iw_sys;
|
||||
|
||||
|
||||
static int sys_add_path(struct iwatch *iw, char *path)
|
||||
{
|
||||
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||
}
|
||||
|
||||
static void sys_update_conds(char *dir, char *name, uint32_t mask)
|
||||
{
|
||||
char fn[PATH_MAX];
|
||||
char *cond;
|
||||
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
cond = strstr(fn, COND_BASE);
|
||||
if (!cond)
|
||||
return;
|
||||
|
||||
cond += strlen(COND_BASE) + 1;
|
||||
_d("cond: %s set: %d", cond, mask & IN_CREATE ? 1 : 0);
|
||||
cond_update(cond);
|
||||
}
|
||||
|
||||
/* synthesize events in case of new run dirs */
|
||||
static void sys_scandir(struct iwatch *iw, char *dir, int len)
|
||||
{
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
char path[len + 6];
|
||||
int rc;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/*", dir);
|
||||
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||
if (rc && rc != GLOB_NOMATCH)
|
||||
return;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
_d("scan found %s", gl.gl_pathv[i]);
|
||||
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
/*
|
||||
* create/remove sub-directory in monitored directory
|
||||
*/
|
||||
static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
||||
{
|
||||
char path[strlen(dir) + strlen(name) + 2];
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
paste(path, sizeof(path), dir, name);
|
||||
_d("path: %s", path);
|
||||
|
||||
iwp = iwatch_find_by_path(iw, path);
|
||||
|
||||
if (mask & IN_CREATE) {
|
||||
if (!iwp) {
|
||||
if (!sys_add_path(iw, path))
|
||||
sys_scandir(iw, path, sizeof(path));
|
||||
}
|
||||
} else if (mask & IN_DELETE) {
|
||||
if (iwp)
|
||||
iwatch_del(&iw_sys, iwp);
|
||||
}
|
||||
}
|
||||
|
||||
static void sys_callback(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
_pe("invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
/* Find base path for this event */
|
||||
iwp = iwatch_find_by_wd(&iw_sys, ev->wd);
|
||||
if (!iwp)
|
||||
continue;
|
||||
|
||||
if (ev->mask & IN_ISDIR) {
|
||||
sys_handle_dir(&iw_sys, iwp->path, ev->name, ev->mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||
sys_update_conds(iwp->path, ev->name, ev->mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void sys_init(void *arg)
|
||||
{
|
||||
char sysdir[MAX_ARG_LEN];
|
||||
char *path;
|
||||
|
||||
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
path = realpath(_PATH_CONDSYS, NULL);
|
||||
if (!path) {
|
||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||
iwatch_exit(&iw_sys);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = iwatch_init(&iw_sys);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
plugin.io.fd = fd;
|
||||
plugin.io.cb = sys_callback;
|
||||
plugin.io.flags = PLUGIN_IO_READ;
|
||||
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_sys);
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -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);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
.deps/*
|
||||
finit
|
||||
initctl
|
||||
keventd
|
||||
logit
|
||||
reboot
|
||||
sulogin
|
||||
watchdogd
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
+13
-8
@@ -8,21 +8,26 @@ AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS =
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
pkglibexec_PROGRAMS = keventd logit sulogin
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
|
||||
if LOGIT
|
||||
pkglibexec_PROGRAMS += logit
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
keventd_SOURCES = keventd.c iwatch.c iwatch.h util.c util.h
|
||||
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
keventd_LDADD = $(lite_LIBS)
|
||||
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
sulogin_LDADD = -lcrypt
|
||||
|
||||
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 +52,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)
|
||||
|
||||
@@ -172,6 +172,9 @@ int cgroup_service(char *name, int pid, struct cgroup *cg)
|
||||
if (!strcmp(cg->name, "root"))
|
||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
|
||||
|
||||
if (!strcmp(cg->name, "init"))
|
||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/init/cgroup.procs");
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
|
||||
if (fisdir(path))
|
||||
group = cg->name;
|
||||
|
||||
+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;
|
||||
}
|
||||
}
|
||||
|
||||
+52
-12
@@ -163,7 +163,7 @@ int cond_set_path(const char *path, enum cond_state next)
|
||||
return next != prev;
|
||||
}
|
||||
|
||||
/* Should only be used by cond_set*(), cond_clear(), and usr plugin! */
|
||||
/* Should only be used by cond_set*(), cond_clear(), and usr/sys plugins! */
|
||||
void cond_update(const char *name)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
@@ -178,13 +178,22 @@ void cond_update(const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
void cond_set(const char *name)
|
||||
int cond_set_noupdate(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (string_compare(name, "nop"))
|
||||
return;
|
||||
return 1;
|
||||
|
||||
if (!cond_set_path(cond_path(name), COND_ON))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cond_set(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (cond_set_noupdate(name))
|
||||
return;
|
||||
|
||||
cond_update(name);
|
||||
@@ -208,13 +217,22 @@ void cond_set_oneshot(const char *name)
|
||||
cond_update(name);
|
||||
}
|
||||
|
||||
void cond_clear(const char *name)
|
||||
int cond_clear_noupdate(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (string_compare(name, "nop"))
|
||||
return;
|
||||
return 1;
|
||||
|
||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cond_clear(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (cond_clear_noupdate(name))
|
||||
return;
|
||||
|
||||
cond_update(name);
|
||||
@@ -227,7 +245,7 @@ void cond_reload(void)
|
||||
cond_bump_reconf();
|
||||
}
|
||||
|
||||
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||
static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw, int set)
|
||||
{
|
||||
char *nm;
|
||||
|
||||
@@ -239,25 +257,47 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
||||
|
||||
nm = strstr((char *)fpath, COND_BASE);
|
||||
if (!nm) {
|
||||
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
||||
_e("Incorrect condtion path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nm += strlen(COND_BASE);
|
||||
_d("Reasserting %s => %s", fpath, nm);
|
||||
cond_set(nm);
|
||||
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
||||
if (set)
|
||||
cond_set(nm);
|
||||
else
|
||||
cond_clear_noupdate(nm); /* important, see netlink plugin! */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||
{
|
||||
return do_assert(fpath, sb, tflg, ftw, 1);
|
||||
}
|
||||
|
||||
static int deassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||
{
|
||||
return do_assert(fpath, sb, tflg, ftw, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used only by netlink plugin atm.
|
||||
* type: is a one of pid/, net/, etc.
|
||||
*/
|
||||
void cond_reassert(const char *type)
|
||||
void cond_reassert(const char *pat)
|
||||
{
|
||||
_d("%s", type);
|
||||
nftw(cond_path(type), reassert, 20, FTW_DEPTH);
|
||||
_d("%s", pat);
|
||||
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used only by netlink plugin atm.
|
||||
*/
|
||||
void cond_deassert(const char *pat)
|
||||
{
|
||||
_d("%s", pat);
|
||||
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
||||
}
|
||||
|
||||
void cond_init(void)
|
||||
|
||||
+10
-2
@@ -5,12 +5,14 @@
|
||||
#include <svc.h>
|
||||
|
||||
#define COND_BASE "finit/cond"
|
||||
#define COND_USR "usr/"
|
||||
#define COND_PID "pid/"
|
||||
#define COND_SYS "sys/"
|
||||
#define COND_USR "usr/"
|
||||
|
||||
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||
#define _PATH_CONDPID _PATH_COND COND_PID
|
||||
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||
#define _PATH_RECONF _PATH_COND "reconf"
|
||||
|
||||
typedef enum cond_state {
|
||||
@@ -34,7 +36,13 @@ void cond_set (const char *name);
|
||||
void cond_set_oneshot (const char *name);
|
||||
void cond_clear (const char *name);
|
||||
void cond_reload (void);
|
||||
|
||||
int cond_set_noupdate (const char *name);
|
||||
int cond_clear_noupdate(const char *name);
|
||||
|
||||
void cond_reassert (const char *pat);
|
||||
void cond_deassert (const char *pat);
|
||||
|
||||
void cond_init (void);
|
||||
|
||||
#endif /* FINIT_COND_H_ */
|
||||
|
||||
+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);
|
||||
|
||||
+91
-48
@@ -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,69 @@ 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")) {
|
||||
char opts[32];
|
||||
int mode;
|
||||
int gid;
|
||||
|
||||
gid = getgroup("tty");
|
||||
if (gid == -1)
|
||||
gid = 0;
|
||||
|
||||
/* 0600 is default on Debian, use 0620 to get mesg y by default */
|
||||
mode = 0620;
|
||||
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
||||
|
||||
makedir("/dev/pts", 0755);
|
||||
mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modern systems use tmpfs for /run. Fallback to /var/run if
|
||||
* /run doesn't exist is handled by the bootmisc plugin. It
|
||||
* also sets up compat symlinks.
|
||||
*
|
||||
* The unconditional mount of /run/lock is for DoS prevention.
|
||||
* To override any of this behavior, add entries to /etc/fstab
|
||||
* for /run (and optionally /run/lock).
|
||||
*/
|
||||
if (fisdir("/run") && !fismnt("/run")) {
|
||||
mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||
|
||||
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
||||
makedir("/run/lock", 1777);
|
||||
mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
|
||||
}
|
||||
|
||||
/* Modern systems use tmpfs for /tmp */
|
||||
if (!fismnt("/tmp"))
|
||||
mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||
}
|
||||
|
||||
static void fs_mount(void)
|
||||
{
|
||||
if (!rescue)
|
||||
@@ -200,6 +264,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 +301,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 +529,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 +557,7 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* Hello world.
|
||||
*/
|
||||
enable_progress(1); /* Allow progress, if enabled */
|
||||
banner();
|
||||
|
||||
/*
|
||||
@@ -552,11 +589,17 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* Start built-in watchdogd as soon as possible, if enabled
|
||||
*/
|
||||
if (which(FINIT_LIBPATH_ "/watchdogd")) {
|
||||
service_register(SVC_TYPE_SERVICE, "[123456789] name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||
wdog = svc_find_by_nameid("watchdog", "finit");
|
||||
}
|
||||
|
||||
/*
|
||||
* Start kernel event daemon as soon as possible, if enabled
|
||||
*/
|
||||
if (whichp(FINIT_LIBPATH_ "/keventd"))
|
||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init " FINIT_LIBPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
||||
|
||||
/* Base FS up, enable standard SysV init signals */
|
||||
sig_setup(&loop);
|
||||
|
||||
|
||||
+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.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -345,7 +345,7 @@ static int do_cond_act(char *arg, int creat)
|
||||
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
||||
err(1, "Failed asserting condition <%s>", &oneshot[off]);
|
||||
} else {
|
||||
if (erase(oneshot))
|
||||
if (erase(oneshot) && errno != ENOENT)
|
||||
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
|
||||
}
|
||||
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
/* Listens to kernel events like AC power status and manages sys/ conditions
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "lite/lite.h"
|
||||
|
||||
#include "cond.h"
|
||||
#include "pid.h"
|
||||
#include "util.h"
|
||||
|
||||
#define _PATH_SYSFS_PWR "/sys/class/power_supply"
|
||||
|
||||
static int num_ac_online;
|
||||
static int num_ac;
|
||||
|
||||
int debug; /* debug in other modules as well */
|
||||
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (!debug)
|
||||
vsyslog(prio, fmt, ap);
|
||||
else {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
#define panic(fmt, args...) { logit(LOG_CRIT, fmt ":%s", ##args, strerror(errno)); exit(1); }
|
||||
#define warn(fmt, args...) { logit(LOG_WARNING, fmt ":%s", ##args, strerror(errno)); }
|
||||
|
||||
static void sys_cond(char *cond, int set)
|
||||
{
|
||||
char oneshot[256];
|
||||
|
||||
snprintf(oneshot, sizeof(oneshot), "%s/%s", _PATH_CONDSYS, cond);
|
||||
if (set) {
|
||||
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
||||
warn("failed asserting sys/%s", cond);
|
||||
} else {
|
||||
if (erase(oneshot) && errno != ENOENT)
|
||||
warn("failed asserting sys/%s", cond);
|
||||
}
|
||||
}
|
||||
|
||||
static int fgetln(char *path, char *buf, size_t len)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
if (!fgets(buf, len, fp)) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
chomp(buf);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_online(char *online)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (!online)
|
||||
return 0;
|
||||
|
||||
val = atoi(online);
|
||||
logit(LOG_INFO, "AC %s", val ? "connected" : "disconnected");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int is_ac(char *type)
|
||||
{
|
||||
char *types[] = {
|
||||
"Mains",
|
||||
"USB",
|
||||
"BrickID",
|
||||
"Wireless",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; types[i]; i++) {
|
||||
if (!strncmp(type, types[i], strlen(types[i])))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
struct dirent **d = NULL;
|
||||
char *cond_dirs[] = {
|
||||
_PATH_CONDSYS,
|
||||
_PATH_CONDSYS "/pwr",
|
||||
};
|
||||
char path[384];
|
||||
int i, n;
|
||||
|
||||
for (i = 0; i < (int)NELEMS(cond_dirs); i++) {
|
||||
if (mkpath(cond_dirs[i], 0755) && errno != EEXIST) {
|
||||
_pe("Failed creating %s condition directory, %s", COND_SYS,
|
||||
cond_dirs[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
n = scandir(_PATH_SYSFS_PWR, &d, NULL, alphasort);
|
||||
for (i = 0; i < n; i++) {
|
||||
char *nm = d[i]->d_name;
|
||||
char buf[10];
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s/type", _PATH_SYSFS_PWR, nm);
|
||||
if (!fgetln(path, buf, sizeof(buf)) && is_ac(buf)) {
|
||||
num_ac++;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s/online", _PATH_SYSFS_PWR, nm);
|
||||
if (!fgetln(path, buf, sizeof(buf))) {
|
||||
if (check_online(buf))
|
||||
num_ac_online++;
|
||||
}
|
||||
}
|
||||
free(d[i]);
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
free(d);
|
||||
|
||||
/* if any power_supply is online, or none can be found */
|
||||
if (num_ac == 0 || num_ac_online > 0)
|
||||
sys_cond("pwr/ac", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Started by Finit as soon as possible when base filesystem is up,
|
||||
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
||||
* now we should have /sys/class/power_supply/ available for probing.
|
||||
* If none is found we assert /sys/pwr/ac condition anyway, this is what
|
||||
* systemd does (ConditionACPower) and also makes most sense.
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_nl nls = { 0 };
|
||||
struct pollfd pfd;
|
||||
char buf[1024];
|
||||
|
||||
if (argc > 1) {
|
||||
if (!strcmp(argv[1], "-d"))
|
||||
debug = 1;
|
||||
}
|
||||
|
||||
if (!debug) {
|
||||
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(LOG_NOTICE));
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
pfd.events = POLLIN;
|
||||
pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (pfd.fd == -1)
|
||||
panic("failed creating netlink socket");
|
||||
|
||||
nls.nl_family = AF_NETLINK;
|
||||
nls.nl_pid = 0;
|
||||
nls.nl_groups = -1;
|
||||
if (bind(pfd.fd, (void *)&nls, sizeof(struct sockaddr_nl)))
|
||||
panic("bind failed");
|
||||
|
||||
logit(LOG_DEBUG, "Waiting for events ...");
|
||||
while (-1 != poll(&pfd, 1, -1)) {
|
||||
char *path = NULL;
|
||||
int ac = 0;
|
||||
int i, len;
|
||||
|
||||
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case ENOBUFS:
|
||||
warn("lost events");
|
||||
continue;
|
||||
default:
|
||||
panic("unhandled");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip libusb events, focus on kernel events/changes */
|
||||
if (strncmp(buf, "change@", 7))
|
||||
continue;
|
||||
|
||||
/* XXX: currently limited to monitoring this subsystem */
|
||||
if (!strstr(buf, "power_supply"))
|
||||
continue;
|
||||
|
||||
i = 0;
|
||||
while (i < len) {
|
||||
char *line = buf + i;
|
||||
|
||||
logit(LOG_DEBUG, "%s", line);
|
||||
if (!strncmp(line, "DEVPATH=", 8)) {
|
||||
path = &line[8];
|
||||
logit(LOG_DEBUG, "Got path %s", path);
|
||||
} else if (!strncmp(line, "POWER_SUPPLY_TYPE=", 18)) {
|
||||
ac = is_ac(&line[18]);
|
||||
} else if (!strncmp(line, "POWER_SUPPLY_ONLINE=", 20) && ac) {
|
||||
if (check_online(&line[20])) {
|
||||
if (!num_ac_online)
|
||||
sys_cond("pwr/ac", 1);
|
||||
num_ac_online++;
|
||||
} else {
|
||||
if (num_ac_online > 0)
|
||||
num_ac_online--;
|
||||
if (!num_ac_online)
|
||||
sys_cond("pwr/ac", 0);
|
||||
}
|
||||
}
|
||||
|
||||
i += strlen(line) + 1;
|
||||
}
|
||||
}
|
||||
close(pfd.fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+1
-1
@@ -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
@@ -1,3 +1,2 @@
|
||||
runlevel 1
|
||||
hostname rescue
|
||||
tty [12345] @console noclear nologin
|
||||
tty [12345] rescue
|
||||
|
||||
+15
-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);
|
||||
@@ -1254,6 +1260,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
if (type == SVC_TYPE_SERVICE && manual)
|
||||
svc_stop(svc);
|
||||
} else {
|
||||
/* update type, may have changed from service -> task */
|
||||
svc->type = type;
|
||||
|
||||
/* e.g., if missing cmd or env before */
|
||||
svc_unblock(svc);
|
||||
}
|
||||
@@ -1295,6 +1304,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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -517,10 +521,14 @@ void sig_setup(uev_ctx_t *ctx)
|
||||
erase(SYNC_SHUTDOWN);
|
||||
erase(SYNC_STOPPED);
|
||||
|
||||
/* Standard SysV init calls ctrl-alt-delete handler */
|
||||
/*
|
||||
* Standard SysV init calls ctrl-alt-delete handler
|
||||
* We need to disable kernel default so it sends us SIGINT
|
||||
*/
|
||||
reboot(RB_DISABLE_CAD);
|
||||
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
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ struct tty {
|
||||
char nowait;
|
||||
char nologin;
|
||||
char notty;
|
||||
char rescue;
|
||||
};
|
||||
|
||||
char *tty_canonicalize (char *dev);
|
||||
|
||||
+44
@@ -154,6 +154,35 @@ char *str(char *fmt, ...)
|
||||
return buf;
|
||||
}
|
||||
|
||||
int fnread(char *buf, size_t len, char *fmt, ...)
|
||||
{
|
||||
char path[256];
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(path, sizeof(path), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!buf || !len) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st))
|
||||
return -1;
|
||||
|
||||
return (ssize_t)st.st_size;
|
||||
}
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
len = fread(buf, sizeof(char), len, fp);
|
||||
fclose(fp);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int fnwrite(char *value, char *fmt, ...)
|
||||
{
|
||||
char path[256];
|
||||
@@ -185,6 +214,21 @@ int fnwrite(char *value, char *fmt, ...)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int fngetint(char *path, int *val)
|
||||
{
|
||||
char buf[10];
|
||||
|
||||
if (fnread(buf, sizeof(buf), path) <= 0)
|
||||
return -1;
|
||||
|
||||
errno = 0;
|
||||
*val = strtoul(chomp(buf), NULL, 0);
|
||||
if (errno)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* musl libc default to /dev/null/utmp and /dev/null/wtmp, respectively.
|
||||
* See https://www.openwall.com/lists/musl/2012/03/04/4 for reasoning.
|
||||
|
||||
@@ -50,7 +50,9 @@ extern char *prognm;
|
||||
char *progname (char *arg0);
|
||||
|
||||
char *str (char *fmt, ...);
|
||||
int fnread (char *buf, size_t len, char *fmt, ...);
|
||||
int fnwrite (char *value, char *fmt, ...);
|
||||
int fngetint (char *path, int *val);
|
||||
|
||||
int has_utmp (void);
|
||||
int strtobytes (char *arg);
|
||||
|
||||
Reference in New Issue
Block a user