mirror of
https://github.com/troglobit/finit.git
synced 2026-10-13 10:14:47 +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.
|
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
|
This release became v4.0, and not v3.2, because of incompatible changes
|
||||||
to service conditions. There are other significant changes as well, so
|
to service conditions. There are other significant changes as well, so
|
||||||
make sure to read the whole changelog when upgrading.
|
make sure to read the whole change log when upgrading.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* The stand-alone `reboot` tool has been replaced with a symlink to
|
* The stand-alone `reboot` tool has been replaced with a symlink to
|
||||||
@@ -24,28 +59,47 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Removed built-in inetd super server. If you need this functionality,
|
* Removed built-in inetd super server. If you need this functionality,
|
||||||
use an external inetd, like xinetd, instead. A pull request for a
|
use an external inetd, like xinetd, instead. A pull request for a
|
||||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||||
* Incompatible `configure` script changes, i.e., you must give proper
|
* Incompatible `configure` script changes, i.e., no guessing `--prefix`
|
||||||
path arguments to the script, no more guessing just GNU defaults.
|
and other paths. Also, many options have been changed, renamed, or
|
||||||
There are examples in the documentation and the `contrib/` section
|
flipped defaults, or even dropped altogether. There are examples in
|
||||||
* Change service conditions from the non-obvious `<svc/path/to/foo>` to
|
the documentation and the `contrib/` section
|
||||||
`<pid/foo:id>`. This to hopefully make it clear that one service's
|
* Service conditions change from the non-obvious `<svc/path/to/foo>` to
|
||||||
'pid:!foo' pidfile is another service's `<pid/foo>` condition
|
`<pid/foo:id>`. Not only does this give simpler internal semantics,
|
||||||
* Initial support for cgroups, every service now runs in its own cgroup
|
it hopefully also makes it clear that one service's `pid:!foo` pidfile
|
||||||
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
is another service's `<pid/foo>` condition, issue #143
|
||||||
|
* Initial support for cgroups v2:
|
||||||
|
- services runs in a cgroup named after their respective *.conf file
|
||||||
|
- top-level groups are; init, user, and system
|
||||||
|
- all top-level groups can be configured from finit *.conf files
|
||||||
|
- each service can tweak the cgroup settings
|
||||||
|
- Use `initctl [top|ps|cgroup]` commands to inspect runtime state
|
||||||
|
- https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||||
* Major refactor of Finit's `main()` function to be able to start the
|
* Major refactor of Finit's `main()` function to be able to start the
|
||||||
event loop earlier. This also facilitated factoring out functionality
|
event loop earlier. This also facilitated factoring out functionality
|
||||||
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
||||||
various distro packed udevd and other hotplugging tools
|
various distro packed udevd and other hotplugging tools
|
||||||
|
* A proper rescue mode has been added. It is started extremely early
|
||||||
|
and is protected with a bundled `suslogin`. Exiting rescue mode now
|
||||||
|
brings up the system as a normal boot, as one expects
|
||||||
* Support for `sysv` start/stop scripts as well as monitoring forking
|
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||||
services, stared using `sysv` or `service` stanza
|
services, stared using `sysv` or `service` stanza
|
||||||
* Support for custom `kill:DELAY`, default 3 sec.
|
* Support for custom `kill:DELAY`, default 3 sec.
|
||||||
* Support for custom `halt:SIGNAL`, default SIGTERM
|
* Support for custom `halt:SIGNAL`, default SIGTERM
|
||||||
|
* Support for `pre:script` and `post:script`, allows for setup and
|
||||||
|
teardown/cleanup before and after a service runs, issue #129
|
||||||
|
* Support for `env:file` in `/etc/default/foo` or `/etc/conf.d/foo`, see
|
||||||
|
the contrib section for examples that utilize this feature. Variables
|
||||||
|
expanded from env files, and the env files themselves, are tracked for
|
||||||
|
changes to see if a service .conf file is "dirty" and needs restart on
|
||||||
|
`initctl reload`
|
||||||
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
||||||
useful with new `sysv` or `service` which fork to background
|
useful with new `sysv` or `service` which fork to background
|
||||||
* Support starting run/task/services without absolute path, trust `$PATH`
|
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||||
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
||||||
builds and work around issue with massively parallel builds
|
builds and work around issue with massively parallel builds
|
||||||
* Add support for `@console` also for external getty
|
* Support for `@console` also for external getty
|
||||||
|
* Support for `notty` option to built-in getty, for board bring-up
|
||||||
|
* Support for `rescue` option to built-in getty, for rescue shells
|
||||||
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||||
* Prefer udev to handle `/dev/` if mdev is also available
|
* Prefer udev to handle `/dev/` if mdev is also available
|
||||||
* Redirect dbus daemon output to syslog
|
* Redirect dbus daemon output to syslog
|
||||||
@@ -95,6 +149,8 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Always append `:ID` qualifier to conditions if set for a service
|
* Always append `:ID` qualifier to conditions if set for a service
|
||||||
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
||||||
officially only supported for use by the `initctl` tool
|
officially only supported for use by the `initctl` tool
|
||||||
|
* The IPC socket now uses `SOCK_SEQPACKET` instead of `SOCK_STREAM`.
|
||||||
|
Recommend using watchdogd v3.4, or later, which support this
|
||||||
* Improved support for modern `/etc/network/interfaces`, which has
|
* Improved support for modern `/etc/network/interfaces`, which has
|
||||||
include statements. No more native `ifup` of individual interfaces,
|
include statements. No more native `ifup` of individual interfaces,
|
||||||
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
||||||
@@ -112,16 +168,21 @@ make sure to read the whole changelog when upgrading.
|
|||||||
that do not have a watchdog
|
that do not have a watchdog
|
||||||
* Fix #100: Early condition handling may not work if `/var/run` does
|
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||||
not yet exist (symlink to `/run`). Added compat layer for access
|
not yet exist (symlink to `/run`). Added compat layer for access
|
||||||
|
* Fix #101: Built-in inetd removed
|
||||||
|
* Fix #102: Start built-in watchdogd as a regular service
|
||||||
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||||
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||||
Fixed by Jonas Johansson, Westermo
|
Fixed by Jonas Johansson, Westermo
|
||||||
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||||
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #110: automatic modprobe of RTC devices, built-in hwclock
|
||||||
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||||
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||||
fixed by Jacques de Laval, Westermo
|
fixed by Jacques de Laval, Westermo
|
||||||
* Fix #124: Lingering processes in process group when session leader
|
* Fix #124: Lingering processes in process group when session leader
|
||||||
exits. E.g., lingering `logit` processes when parent dies
|
exits. E.g., lingering `logit` processes when parent dies
|
||||||
|
* Fix #127: Show all runparts scripts as they start, like rc.local, fixed
|
||||||
|
by Jacques de Laval, Westermo
|
||||||
* Fix service name matching, e.g. for condition handling, may match with
|
* Fix service name matching, e.g. for condition handling, may match with
|
||||||
wrong service, by Jonas Holmberg, Westermo
|
wrong service, by Jonas Holmberg, Westermo
|
||||||
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||||
@@ -140,6 +201,8 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Provide service description for built-in watchdog daemon
|
* Provide service description for built-in watchdog daemon
|
||||||
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
||||||
* Drop the '%m' GNUism, for compat with older musl libc
|
* Drop the '%m' GNUism, for compat with older musl libc
|
||||||
|
* Fix #139: call `tzset()` on `initctl reload` to activate system
|
||||||
|
timezone changes (for logging)
|
||||||
|
|
||||||
|
|
||||||
[3.1][] - 2018-01-23
|
[3.1][] - 2018-01-23
|
||||||
@@ -748,14 +811,14 @@ Major bug fix release.
|
|||||||
* Makefile fixes for installation, paths encoded wrong
|
* Makefile fixes for installation, paths encoded wrong
|
||||||
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
||||||
* Default install is now to `/sbin/finit` and `/usr/`
|
* Default install is now to `/sbin/finit` and `/usr/`
|
||||||
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
|
* Note change in `$PLUGIN_DIR` environment variable to `$plugindir`
|
||||||
|
|
||||||
|
|
||||||
[1.2][] - 2012-09-27
|
[1.2][] - 2012-09-27
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Update README with section on building and enviroment variables
|
* Update README with section on building and environment variables
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
* Fix installation paths encoded in finit binary
|
* Fix installation paths encoded in finit binary
|
||||||
@@ -847,7 +910,7 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial 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
|
[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.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[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
|
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
[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`
|
* Built-in support for Debian/BusyBox `/etc/network/interfaces`
|
||||||
* Cgroups v2, both configuration and monitoring in `initctl top`
|
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||||
* Plugin support for customization
|
* Plugin support for customization
|
||||||
|
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||||
|
|
||||||
Focus is on small and embedded systems, although Finit is fully usable
|
Focus is on small and embedded systems, although Finit is fully usable
|
||||||
on server and desktop systems as well. For working examples, see the
|
on server and desktop systems as well. For working examples, see the
|
||||||
@@ -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
|
making it easy to create simple start scripts and still possible for more
|
||||||
advanced uses as well:
|
advanced uses as well:
|
||||||
|
|
||||||
service sshd -D
|
service /usr/sbin/sshd -D
|
||||||
|
|
||||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||||
the most common conditions is to wait for basic networking to become
|
the most common conditions is to wait for basic networking to become
|
||||||
@@ -459,9 +460,6 @@ Commands:
|
|||||||
halt Halt system
|
halt Halt system
|
||||||
poweroff Halt and power off system
|
poweroff Halt and power off system
|
||||||
suspend Suspend 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
|
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)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
@@ -8,7 +8,7 @@ AC_CONFIG_HEADER([config.h])
|
|||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/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
|
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
@@ -48,11 +48,6 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
|||||||
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# Check for configured Finit features
|
||||||
AC_ARG_ENABLE(emergency_shell,
|
|
||||||
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
|
||||||
Use only for debugging very early boot problems with Finit]),,[
|
|
||||||
enable_emergency_shell=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(auto_reload,
|
AC_ARG_ENABLE(auto_reload,
|
||||||
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||||
enable_auto_reload=no])
|
enable_auto_reload=no])
|
||||||
@@ -61,10 +56,6 @@ AC_ARG_ENABLE(redirect,
|
|||||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||||
enable_redirect=yes])
|
enable_redirect=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(logit,
|
|
||||||
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
|
||||||
enable_logit=yes])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(logrotate,
|
AC_ARG_ENABLE(logrotate,
|
||||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||||
enable_logrotate=yes])
|
enable_logrotate=yes])
|
||||||
@@ -122,14 +113,11 @@ AC_ARG_WITH(random-seed,
|
|||||||
|
|
||||||
AC_ARG_WITH(watchdog,
|
AC_ARG_WITH(watchdog,
|
||||||
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||||
[watchdog=$withval],[watchdog=])
|
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
# Create config.h from selected features and fallback defaults
|
# Create config.h from selected features and fallback defaults
|
||||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
|
||||||
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||||
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||||
|
|
||||||
@@ -137,9 +125,6 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
|
|||||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||||
|
|
||||||
### Disable features ###########################################################################
|
### Disable features ###########################################################################
|
||||||
AS_IF([test "x$enable_logit" != "xno"], [
|
|
||||||
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||||
|
|
||||||
@@ -198,12 +183,12 @@ AS_IF([test "x$with_watchdog" != "xno"], [
|
|||||||
AS_IF([test "x$watchdog" = "xyes"], [
|
AS_IF([test "x$watchdog" = "xyes"], [
|
||||||
watchdog=/dev/watchdog])
|
watchdog=/dev/watchdog])
|
||||||
with_watchdog=yes
|
with_watchdog=yes
|
||||||
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])])
|
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||||
|
watchdog=])
|
||||||
|
|
||||||
# Control build with automake flags
|
# Control build with automake flags
|
||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||||
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
|
||||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
|
||||||
@@ -251,8 +236,6 @@ Optional features:
|
|||||||
Install contrib/......: $enable_contrib
|
Install contrib/......: $enable_contrib
|
||||||
Built-in watchdogd....: $with_watchdog $watchdog
|
Built-in watchdogd....: $with_watchdog $watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
Scripting tool logit..: $enable_logit
|
|
||||||
Emergency shell.......: $enable_emergency_shell
|
|
||||||
Redirect output.......: $enable_redirect
|
Redirect output.......: $enable_redirect
|
||||||
Default hostname......: $hostname
|
Default hostname......: $hostname
|
||||||
Default runlevel......: $runlevel
|
Default runlevel......: $runlevel
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fi
|
|||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
if [ -e alpine-release ]; then
|
if [ -e alpine-release ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = finit.d grub.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/debian
|
docsdir := @docdir@/contrib/debian
|
||||||
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -20,29 +20,41 @@ tools pre-systemd work as intended.
|
|||||||
|
|
||||||
root@debian:~# apt install initscripts console-setup
|
root@debian:~# apt install initscripts console-setup
|
||||||
|
|
||||||
|
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
|
||||||
|
> the main section of Debian. So just install the -dev packages :)
|
||||||
|
|
||||||
The following script can then be used to configure, build, install and
|
The following script can then be used to configure, build, install and
|
||||||
set up your system to run Finit:
|
set up your system to run Finit:
|
||||||
|
|
||||||
user@debian:~/finit$ contrib/debian/build.sh
|
user@debian:~/finit$ contrib/debian/build.sh
|
||||||
|
|
||||||
However, since `/sbin/init` already exists on your system, the script
|
However, since `/sbin/init` already exists on your system, the script
|
||||||
creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
|
creates another entry in your GRUB config by updating `$SUPPORTED_INITS`
|
||||||
where `init=/sbin/finit` is added to your kernel line. It is of course
|
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find
|
||||||
also possible to change the default init to Finit, if you do you can
|
a (finit) entry in the "Advanced options for Debian GNU/Linux" section.
|
||||||
remove the custom Grub entry:
|
It is of course also possible to change the default init to Finit:
|
||||||
|
|
||||||
user@debian:~/finit# cd /sbin
|
user@debian:~/finit# cd /sbin
|
||||||
user@debian:/sbin# sudo rm init
|
user@debian:/sbin# sudo mv init oldinit
|
||||||
user@debian:/sbin# sudo ln -s finit init
|
user@debian:/sbin# sudo ln -s finit init
|
||||||
|
|
||||||
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
||||||
`/etc/finit.d/*.conf` files. The build + install script above provides
|
`/etc/finit.d/*.conf` files. The build + install script above provides
|
||||||
a few sample `.conf` files. See `initctl list` after boot for a list of
|
a few sample `.conf` files. See `initctl ls` after boot for a list of
|
||||||
enabled and available services.
|
enabled and available services, you can then use `enable` and `disable`
|
||||||
|
comands to `initctl`, followed by `reload` to activate your changes.
|
||||||
|
|
||||||
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
||||||
and initialization like keyboard language etc.
|
and initialization like keyboard language etc.
|
||||||
|
|
||||||
|
If you want to use the X Window system, `sudo apt install elogind`
|
||||||
|
(Bullseye and later). Followed by `initctl reload` (enabled by default)
|
||||||
|
and logout/login again. The elogind daemon ensures a regular non-root
|
||||||
|
user can start and interact with an X session, otherwise keyboard and
|
||||||
|
mouse won't work. 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!
|
Have fun!
|
||||||
/Joachim ツ
|
/Joachim ツ
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
SUBDIRS = available
|
SUBDIRS = available
|
||||||
docsdir := @docdir@/contrib/debian/finit.d
|
docsdir := @docdir@/contrib/debian/finit.d
|
||||||
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
d_LINKS = acpid.conf apparmor.conf avahi-demon.conf \
|
||||||
modules.conf rsyslogd.conf sshd.conf
|
bluetooth.conf console-setup.conf elogind.conf \
|
||||||
|
getty.conf keyboard-setup.conf modules.conf \
|
||||||
|
rsyslogd.conf sshd.conf
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
docsdir := @docdir@/contrib/debian/finit.d/available
|
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||||
docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \
|
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
|
||||||
lightdm.conf modules.conf rsyslogd.conf sntpd.conf \
|
console-setup.conf elogind.conf getty.conf \
|
||||||
sshd.conf syslogd.conf xdm.conf
|
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||||
|
rsyslogd.conf sshd.conf syslogd.conf xdm.conf
|
||||||
EXTRA_DIST = $(docs_DATA)
|
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
|
# Consoles to start getty on when system is up
|
||||||
tty [12345] /dev/tty1 linux noclear nowait
|
tty [12345] /dev/tty1 linux noclear nowait
|
||||||
tty [2345] /dev/tty2 linux noclear nowait
|
tty [2345] /dev/tty2 linux nowait
|
||||||
tty [2345] /dev/tty3 linux noclear 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
|
grep -q Debian os-release 2>/dev/null
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
|
|||||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||||
echo "/etc/finit.conf - Finit configuration file"
|
echo "/etc/finit.conf - Finit configuration file"
|
||||||
echo "/etc/finit.d/ - Finit services"
|
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
|
echo
|
||||||
read -p "Do you want to continue (y/N)? " yorn
|
read -p "Do you want to continue (y/N)? " yorn
|
||||||
echo
|
echo
|
||||||
@@ -38,12 +38,18 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
|||||||
cp -va finit.d /etc/
|
cp -va finit.d /etc/
|
||||||
|
|
||||||
echo "*** Setting up a GRUB boot entry ..."
|
echo "*** Setting up a GRUB boot entry ..."
|
||||||
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
|
fn=/etc/grub.d/10_linux
|
||||||
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
|
if [ -e $fn ]; then
|
||||||
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/'`
|
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then
|
||||||
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/'`
|
echo "Already installed, done."
|
||||||
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
|
else
|
||||||
update-grub
|
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
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fi
|
|||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
if [ -e xbps ]; then
|
if [ -e xbps ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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.
|
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||||
`pimd` man pages ...
|
`pimd` man pages ...
|
||||||
|
|
||||||
|
|
||||||
|
Initctl
|
||||||
|
-------
|
||||||
|
|
||||||
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
||||||
|
|
||||||
shutdown -h 03:35 "foobar was here"
|
shutdown -h 03:35 "foobar was here"
|
||||||
|
|
||||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
`initctl show --json`
|
`initctl show --json`
|
||||||
|
* Add support for `-s` to redirect all output to syslog, for scripting
|
||||||
|
|
||||||
|
|
||||||
Init
|
Init
|
||||||
|
|||||||
+5
-3
@@ -9,9 +9,11 @@ Bootstrap
|
|||||||
6. Load all `.so` plugins
|
6. Load all `.so` plugins
|
||||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||||
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
9. Parse `/etc/finit.conf`
|
||||||
10. Start built-in watchdog, if enabled
|
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||||
11. Set hostname
|
means any WDT that requires a kernel module need to be either
|
||||||
|
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
||||||
|
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
||||||
|
|||||||
+7
-5
@@ -30,10 +30,12 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||||
errors.
|
errors.
|
||||||
|
|
||||||
* `rescue`: Start Finit rescue mode; no network, no `fsck` of file
|
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||||
systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The
|
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||||
configuration is read from `/lib/finit/rescue.conf`, and can be
|
you will be given a root login to a maintenance shell. However, if
|
||||||
modified by the operator.
|
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
||||||
|
the system booted in a limited fallback mode. See [config.md][]
|
||||||
|
for more information.
|
||||||
|
|
||||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
||||||
debug problems with the regular runlevel. All services and TTYs in
|
debug problems with the regular runlevel. All services and TTYs in
|
||||||
@@ -42,5 +44,5 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
|
|
||||||
For more on kernel boot paramaters, see the man page [bootparam(7)][].
|
For more on kernel boot paramaters, see the man page [bootparam(7)][].
|
||||||
|
|
||||||
|
[config.md][]: config.md#rescue-mode
|
||||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||||
|
|||||||
+123
-21
@@ -21,9 +21,11 @@ Configuration
|
|||||||
* [TTYs and Consoles](#ttys-and-consoles)
|
* [TTYs and Consoles](#ttys-and-consoles)
|
||||||
* [Non-privileged Services](#non-privileged-services)
|
* [Non-privileged Services](#non-privileged-services)
|
||||||
* [Redirecting Output](#redirecting-output)
|
* [Redirecting Output](#redirecting-output)
|
||||||
|
* [Rescue Mode](#rescue-mode)
|
||||||
* [Limitations](#limitations)
|
* [Limitations](#limitations)
|
||||||
* [/etc/finit.conf](#etcfinitconf)
|
* [/etc/finit.conf](#etcfinitconf)
|
||||||
* [/etc/finit.d](#etcfinitd)
|
* [/etc/finit.d](#etcfinitd)
|
||||||
|
* [Watchdog](#watchdog)
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
@@ -37,8 +39,8 @@ Linux distributions -- each package can provide its own "script" file.
|
|||||||
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
||||||
|
|
||||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
||||||
and some directives are only available at bootstrap, runlevel `S`, see
|
and some directives are only available at [bootstrap][], runlevel `S`,
|
||||||
the section [Limitations](#limitations) below for details.
|
see the section [Limitations](#limitations) below for details.
|
||||||
|
|
||||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
||||||
@@ -203,7 +205,7 @@ the contents of that file is used.
|
|||||||
|
|
||||||
Deprecated. We recommend using `/etc/hostname` instead.
|
Deprecated. We recommend using `/etc/hostname` instead.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Kernel Modules
|
### Kernel Modules
|
||||||
@@ -221,7 +223,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
|||||||
|
|
||||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Networking
|
### Networking
|
||||||
@@ -234,7 +236,7 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
|||||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Resource Limits
|
### Resource Limits
|
||||||
@@ -268,13 +270,13 @@ stanzas can share the same rlimits if they are in the same .conf.
|
|||||||
|
|
||||||
**Syntax:** `runlevel <N>`
|
**Syntax:** `runlevel <N>`
|
||||||
|
|
||||||
Defines the system runlevel to go to after bootstrap (S) has completed.
|
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||||
N is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||||
halt.
|
halt.
|
||||||
|
|
||||||
Default: 2
|
Default: 2
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### One-shot Commands (sequence)
|
### One-shot Commands (sequence)
|
||||||
@@ -426,7 +428,7 @@ SIGKILLed, this can be adjusted using the above `kill:SEC` syntax.
|
|||||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||||
files, or scripts, in the directory are called, in alphabetic order.
|
files, or scripts, in the directory are called, in alphabetic order.
|
||||||
The scripts in this directory are executed at the very end of runlevel
|
The scripts in this directory are executed at the very end of runlevel
|
||||||
`S`, bootstrap.
|
`S`, [bootstrap][].
|
||||||
|
|
||||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
||||||
is a dependency order between the scripts. Symlinks to existing
|
is a dependency order between the scripts. Symlinks to existing
|
||||||
@@ -436,7 +438,9 @@ Similar to the `/etc/rc.local` shell script, make sure that all your
|
|||||||
services and programs either terminate or start in the background or
|
services and programs either terminate or start in the background or
|
||||||
you will block Finit.
|
you will block Finit.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
|
||||||
|
|
||||||
### Including Finit Configs
|
### Including Finit Configs
|
||||||
@@ -465,6 +469,7 @@ size limit is reached.
|
|||||||
|
|
||||||
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||||
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
|
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
|
||||||
|
`tty [LVLS] <COND> [notty] [rescue]`
|
||||||
|
|
||||||
The first variant of this option uses the built-in getty on the given
|
The first variant of this option uses the built-in getty on the given
|
||||||
TTY device DEV, in the given runlevels. The DEV may be the special
|
TTY device DEV, in the given runlevels. The DEV may be the special
|
||||||
@@ -484,8 +489,17 @@ The default baud rate is 0, i.e., keep kernel default.
|
|||||||
The second `tty` syntax variant is for using an external getty, like
|
The second `tty` syntax variant is for using an external getty, like
|
||||||
agetty or the BusyBox getty.
|
agetty or the BusyBox getty.
|
||||||
|
|
||||||
By default both variants *clear* the TTY and *wait* for the user to
|
The third variant is for board bringup and the `rescue` boot mode. No
|
||||||
press enter before starting getty.
|
device node is required in this variant, the same output that the kernel
|
||||||
|
uses is reused for stdio. If the `rescue` option is omitted, a shell is
|
||||||
|
started (`nologin`, `noclear`, and `nowait` are implied), if the rescue
|
||||||
|
option is set the bundled `/libexec/finit/sulogin` is started to present
|
||||||
|
a bare-bones root login prompt. If the root (uid:0, gid:0) user does
|
||||||
|
not have a password set, no rescue is possible. For more information,
|
||||||
|
see the [Rescue Mode](#rescue-mode) section.
|
||||||
|
|
||||||
|
By default, the first two syntax variants *clear* the TTY and *wait* for
|
||||||
|
the user to press enter before starting getty.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
@@ -522,10 +536,11 @@ can be omitted to keep the kernel default.
|
|||||||
|
|
||||||
tty [12345] @console noclear vt220
|
tty [12345] @console noclear vt220
|
||||||
|
|
||||||
On really bare bones systems Finit can give you a shell prompt as
|
On really bare bones systems, or for board bringup, Finit can give you a
|
||||||
soon as bootstrap is done, without opening any device node:
|
shell prompt as soon as [bootstrap][] is done, without opening any
|
||||||
|
device node:
|
||||||
|
|
||||||
tty [12345789] notty noclear
|
tty [12345789] notty
|
||||||
|
|
||||||
This should of course not be enabled on production systems. Because it
|
This should of course not be enabled on production systems. Because it
|
||||||
may give a user root access without having to log in. However, for
|
may give a user root access without having to log in. However, for
|
||||||
@@ -581,6 +596,59 @@ Log rotation is controlled using the global `log` setting.
|
|||||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
|
|
||||||
|
Rescue Mode
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Finit supports a rescue mode which is activated by the `rescue` option
|
||||||
|
on the kernel command line. See [cmdline docs](cmdline.md) for how to
|
||||||
|
activate it.
|
||||||
|
|
||||||
|
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||||
|
|
||||||
|
|
||||||
|
### Traditional
|
||||||
|
|
||||||
|
This is what most users expect. A very early maintenance login prompt,
|
||||||
|
served by the bundled `/libexec/finit/sulogin` program, or the standard
|
||||||
|
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
|
||||||
|
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
|
||||||
|
rescue mode is ended and the system boots up normally.
|
||||||
|
|
||||||
|
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
|
||||||
|
> __the account is locked__, the user is presented with a password-less
|
||||||
|
> `"Press enter to enter maintenance mode."`, prompt which opens up a
|
||||||
|
> root shell.
|
||||||
|
|
||||||
|
|
||||||
|
### Fallback
|
||||||
|
|
||||||
|
If no `sulogin` program is found, Finit tries to bring up as much of its
|
||||||
|
own functionality as possible, yet limiting many aspects, meaning; no
|
||||||
|
network, no `fsck` of file systems in `/etc/fstab`, no `/etc/rc.local`,
|
||||||
|
no `runparts`, and most plugins are skipped (except those that provide
|
||||||
|
functionality for the condition subsystem).
|
||||||
|
|
||||||
|
Instead of reading `/etc/finit.conf` et al, system configuration is read
|
||||||
|
from `/lib/finit/rescue.conf`, which can be freely modified by the
|
||||||
|
system administrator.
|
||||||
|
|
||||||
|
The bundled default `rescue.conf` contains nothing more than:
|
||||||
|
|
||||||
|
runlevel 1
|
||||||
|
tty [12345] rescue
|
||||||
|
|
||||||
|
The `tty` has the `rescue` option set, which works similar to the board
|
||||||
|
bring-up tty option `notty`. The major difference being that `sulogin`
|
||||||
|
is started to query for root/admin password. If `sulogin` is not found,
|
||||||
|
`rescue` behaves like `notty` and gives a plain root shell prompt.
|
||||||
|
|
||||||
|
If Finit cannot find `/lib/finit/rescue.conf` it defaults to:
|
||||||
|
|
||||||
|
tty [12345] rescue
|
||||||
|
|
||||||
|
There is no way to exit the *fallback* rescue mode.
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@@ -590,15 +658,49 @@ from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
|
|||||||
|
|
||||||
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
||||||
Today it is mainly used for bootstrap settings like system hostname,
|
Today it is mainly used for bootstrap settings like system hostname,
|
||||||
network bringup and system shutdown. These can now also be set in any
|
early module loading for watchdogd, network bringup and system shutdown.
|
||||||
`.conf` file in `/etc/finit.d`.
|
These can now also be set in any `.conf` file in `/etc/finit.d`.
|
||||||
|
|
||||||
There is, however, nothing preventing you from having all configuration
|
There is, however, nothing preventing you from having all configuration
|
||||||
settings in `/etc/finit.conf`.
|
settings in `/etc/finit.conf`.
|
||||||
|
|
||||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
> **Note:** The `/etc/finit.d` directory was previously the default
|
||||||
> Finit `runparts` directory. Finit no longer has a default
|
> Finit [runparts](#run-parts-scripts) directory. Finit no
|
||||||
> `runparts`, make sure to update your setup, or the finit
|
> longer has a default `runparts`, make sure to update your
|
||||||
> configuration, accordingly.
|
> setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
|
||||||
|
Watchdog
|
||||||
|
--------
|
||||||
|
|
||||||
|
When built `--with-watchdog` a separate service is built and installed
|
||||||
|
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
|
||||||
|
device node exists, Finit will start it and treat it as the elected
|
||||||
|
watchdog service to delegate its reboot to. See [bootstrap][] for
|
||||||
|
details. This delegation is to ensure that the system is rebooted by a
|
||||||
|
hardware watchdog timer -- on many embedded systems this is crucial to
|
||||||
|
ensure all circuits on the board are properly reset for the next boot,
|
||||||
|
in effect ensuring the system works the same after both a power-on and
|
||||||
|
reboot event.
|
||||||
|
|
||||||
|
The delegation is performed at the very last steps of system shutdown,
|
||||||
|
if reboot has been selected and an elected watchdog is known, first a
|
||||||
|
`SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when
|
||||||
|
the necessary steps of preparing the system for shutdown (umount etc.)
|
||||||
|
are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a
|
||||||
|
10 sec timeout loop waiting for the WDT to reset the board. If a reset
|
||||||
|
is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)`
|
||||||
|
which tells the kernel to do the reboot.
|
||||||
|
|
||||||
|
An external watchdog service can also be used. The more advanced cousin
|
||||||
|
[watchdogd](https://github.com/troglobit/watchdogd/) is the recommended
|
||||||
|
option here. It can register itself with Finit using the same IPC as
|
||||||
|
`initctl`. If the bundled watchdogd is running a hand-over takes place,
|
||||||
|
so it's safe to have both services installed on a system. For the
|
||||||
|
hand-over to work it requires that the WDT driver supports the safe exit
|
||||||
|
functionality where `"V"` is written to the device before closing the
|
||||||
|
device descriptor. If the kernel driver has been built without this,
|
||||||
|
the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||||
|
it at configure time.
|
||||||
|
|
||||||
|
[bootstrap]: bootstrap.md
|
||||||
|
|||||||
+16
-8
@@ -12,28 +12,36 @@ have been adopted:
|
|||||||
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
||||||
*.conf files in `/etc/finit.d/`
|
*.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`
|
`SIGUSR1`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
Since Finit 4.1 this signal causes Finit to restart its API (initctl)
|
||||||
processes, and unmounts all file systems. Then tells kernel to halt.
|
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus.
|
||||||
Most people these days want `SIGUSR2` though.
|
|
||||||
|
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`
|
`SIGUSR2`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
|
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||||
similar exists to actually do this. If the kernel fails power-off,
|
processes, and unmounts all file systems. Then tells kernel to power
|
||||||
Finit falls back to halt.
|
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.
|
SysV init N/A, systemd dumps its internal state to log.
|
||||||
|
|
||||||
`SIGTERM`
|
`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.
|
SysV init N/A, systemd rexecutes itself.
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
|||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
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
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -34,7 +34,7 @@ libplug_la_SOURCES += resolvconf.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
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
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
|
|||||||
@@ -30,6 +30,11 @@
|
|||||||
|
|
||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Saving sound settings ...");
|
_d("Saving sound settings ...");
|
||||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||||
@@ -38,6 +43,11 @@ static void save(void *arg)
|
|||||||
|
|
||||||
static void restore(void *arg)
|
static void restore(void *arg)
|
||||||
{
|
{
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Restoring sound settings ...");
|
_d("Restoring sound settings ...");
|
||||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||||
|
|||||||
+12
-5
@@ -119,15 +119,16 @@ static void setup(void *arg)
|
|||||||
makedir("/var/lib/urandom",0755);
|
makedir("/var/lib/urandom",0755);
|
||||||
if (fisdir("/run")) {
|
if (fisdir("/run")) {
|
||||||
_d("System with new /run tmpfs ...");
|
_d("System with new /run tmpfs ...");
|
||||||
makedir("/run/lock", 1777);
|
if (!fisdir("/run/lock"))
|
||||||
|
makedir("/run/lock", 1777);
|
||||||
symlink("/run/lock", "/var/lock");
|
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 */
|
/* compat only, should really be set up by OS/dist */
|
||||||
symlink("/run", "/var/run");
|
symlink("/run", "/var/run");
|
||||||
} else {
|
} else {
|
||||||
makedir("/var/lock", 1777);
|
makedir("/var/lock", 1777);
|
||||||
makedir("/var/run", 0755);
|
makedir("/var/run", 0755);
|
||||||
}
|
}
|
||||||
makedir("/var/log", 0755);
|
makedir("/var/log", 0755);
|
||||||
makedir("/var/mail", 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 */
|
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
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);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -43,6 +43,11 @@ static void setup(void *arg)
|
|||||||
mode_t prev;
|
mode_t prev;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
_d("Skipping plugin, %s is not installed.", DAEMON);
|
_d("Skipping plugin, %s is not installed.", DAEMON);
|
||||||
@@ -59,7 +64,7 @@ static void setup(void *arg)
|
|||||||
remove("/var/run/dbus/pid");
|
remove("/var/run/dbus/pid");
|
||||||
|
|
||||||
/* Register service with Finit */
|
/* 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);
|
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
_pe("Failed registering %s", DAEMON);
|
||||||
|
|||||||
+8
-3
@@ -34,6 +34,11 @@ static void setup(void *arg)
|
|||||||
char cmd[256];
|
char cmd[256];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
* Populate /dev and prepare for runtime events from kernel.
|
||||||
* Prefer udev if mdev is also available on the system.
|
* Prefer udev if mdev is also available on the system.
|
||||||
@@ -43,17 +48,17 @@ static void setup(void *arg)
|
|||||||
path = which("/lib/systemd/systemd-udevd");
|
path = which("/lib/systemd/systemd-udevd");
|
||||||
if (path) {
|
if (path) {
|
||||||
/* Register udevd as a monitored service */
|
/* 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);
|
"-- Device event managing daemon", path);
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||||
_pe("Failed registering %s", path);
|
_pe("Failed registering %s", path);
|
||||||
} else {
|
} 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 "
|
"udevadm trigger -c add -t devices "
|
||||||
"-- Requesting device events");
|
"-- Requesting device events");
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
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 "
|
"udevadm trigger -c add -t subsystems "
|
||||||
"-- Requesting subsystem events");
|
"-- Requesting subsystem events");
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||||
#endif
|
#endif
|
||||||
#define SERVICE_LINE \
|
#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)
|
static void load(void *arg)
|
||||||
{
|
{
|
||||||
@@ -71,8 +71,7 @@ static void load(void *arg)
|
|||||||
|
|
||||||
mod = strtok_r(mod, " ", &args);
|
mod = strtok_r(mod, " ", &args);
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
|
||||||
index, mod, mod, args, mod);
|
|
||||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
|
|||||||
+227
-42
@@ -30,31 +30,35 @@
|
|||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
#define NL_BUFSZ 4096
|
||||||
{
|
|
||||||
if (!NLMSG_OK(nh, len))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
struct nl_request {
|
||||||
_d("Done with netlink messages.");
|
struct nlmsghdr nh;
|
||||||
return 1;
|
union {
|
||||||
}
|
struct rtmsg rtm;
|
||||||
|
struct ifinfomsg ifi;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
static int nl_defidx;
|
||||||
_d("Netlink reports error.");
|
static int nl_ifdown;
|
||||||
return 1;
|
static char *nl_buf;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||||
{
|
{
|
||||||
|
char daddr[INET_ADDRSTRLEN];
|
||||||
|
char gaddr[INET_ADDRSTRLEN];
|
||||||
|
struct in_addr ind, ing;
|
||||||
struct rtmsg *r;
|
struct rtmsg *r;
|
||||||
struct rtattr *a;
|
struct rtattr *a;
|
||||||
|
int plen = 0;
|
||||||
|
int dst = 0;
|
||||||
|
int idx = 0;
|
||||||
|
int gw = 0;
|
||||||
int la;
|
int la;
|
||||||
int gw = 0, dst = 0, mask = 0, idx = 0;
|
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||||
_e("Packet too small or truncated!");
|
_e("Packet too small or truncated!");
|
||||||
@@ -80,8 +84,8 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
|
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
dst = *((int *)data);
|
dst = *((int *)data);
|
||||||
mask = r->rtm_dst_len;
|
plen = r->rtm_dst_len;
|
||||||
//_d("MASK: 0x%04x", mask);
|
//_d("Prefix LEN: 0x%04x", plen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_OIF:
|
case RTA_OIF:
|
||||||
@@ -93,11 +97,20 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
a = RTA_NEXT(a, la);
|
a = RTA_NEXT(a, la);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!dst && !mask) && (gw || idx)) {
|
ind.s_addr = dst;
|
||||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
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");
|
cond_clear("net/route/default");
|
||||||
else
|
nl_defidx = 0;
|
||||||
|
} else {
|
||||||
cond_set("net/route/default");
|
cond_set("net/route/default");
|
||||||
|
nl_defidx = idx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,14 +130,14 @@ static int validate_ifname(const char *ifname)
|
|||||||
if (!ifname || !ifname[0])
|
if (!ifname || !ifname[0])
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strlen(ifname) >= IFNAMSIZ)
|
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strstr(ifname, ".."))
|
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
while (*ifname) {
|
while (*ifname) {
|
||||||
if (*ifname == '/' || isspace(*ifname))
|
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
|
||||||
return 1;
|
return 1;
|
||||||
ifname++;
|
ifname++;
|
||||||
}
|
}
|
||||||
@@ -132,12 +145,25 @@ static int validate_ifname(const char *ifname)
|
|||||||
return 0;
|
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)
|
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||||
{
|
{
|
||||||
int la;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
char ifname[IFNAMSIZ + 1];
|
||||||
struct rtattr *a;
|
|
||||||
struct ifinfomsg *i;
|
struct ifinfomsg *i;
|
||||||
|
struct rtattr *a;
|
||||||
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||||
_e("Packet too small or truncated!");
|
_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, "exist", 1);
|
||||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
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;
|
break;
|
||||||
|
|
||||||
case RTM_DELLINK:
|
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, "exist", 0);
|
||||||
net_cond_set(ifname, "up", 0);
|
net_cond_set(ifname, "up", 0);
|
||||||
net_cond_set(ifname, "running", 0);
|
net_cond_set(ifname, "running", 0);
|
||||||
|
nl_check_default(ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
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];
|
while (1) {
|
||||||
struct nlmsghdr *nh;
|
struct nlmsghdr *nh;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||||
len = recv(sd, buf, sizeof(buf), 0);
|
switch (errno) {
|
||||||
if (len < 0) {
|
case EAGAIN: /* Nothing more right now. */
|
||||||
if (errno != EINTR) /* Signal */
|
return 0;
|
||||||
_pe("recv()");
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
if (all) {
|
||||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
_d("============================ RESYNC =================================");
|
||||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
/* this doesn't update condtions, and thus does not stop services */
|
||||||
nl_route(nh, len);
|
cond_deassert("net/");
|
||||||
else
|
|
||||||
nl_link(nh, len);
|
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)
|
PLUGIN_INIT(plugin_init)
|
||||||
{
|
{
|
||||||
int sd;
|
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
|
int sd;
|
||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
@@ -247,7 +425,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.nl_family = AF_NETLINK;
|
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();
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||||
@@ -256,6 +434,13 @@ PLUGIN_INIT(plugin_init)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nl_buf = malloc(NL_BUFSZ);
|
||||||
|
if (!nl_buf) {
|
||||||
|
_pe("malloc()");
|
||||||
|
close(sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
plugin.io.fd = sd;
|
plugin.io.fd = sd;
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
|
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
@@ -31,6 +34,11 @@ static void setup(void *arg)
|
|||||||
glob_t gl;
|
glob_t gl;
|
||||||
char buf[160];
|
char buf[160];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ static void rtc_save(void *arg)
|
|||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
@@ -121,6 +126,11 @@ static void rtc_restore(void *arg)
|
|||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
+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)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fexist(RANDOMSEED)) {
|
if (!fexist(RANDOMSEED)) {
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
@@ -71,6 +76,11 @@ static void save(void *arg)
|
|||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
prev = umask(077);
|
prev = umask(077);
|
||||||
|
|
||||||
print_desc("Saving random seed", NULL);
|
print_desc("Saving random seed", NULL);
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ static void setup(void *arg)
|
|||||||
int fd;
|
int fd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
prev = umask(0);
|
prev = umask(0);
|
||||||
|
|
||||||
makedir("/var/run/console", 01777);
|
makedir("/var/run/console", 01777);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
.deps/*
|
.deps/*
|
||||||
finit
|
finit
|
||||||
initctl
|
initctl
|
||||||
|
keventd
|
||||||
logit
|
logit
|
||||||
reboot
|
reboot
|
||||||
|
sulogin
|
||||||
watchdogd
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
|||||||
+13
-8
@@ -8,21 +8,26 @@ AM_LDFLAGS = -export-dynamic
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
sbin_PROGRAMS = finit initctl
|
sbin_PROGRAMS = finit initctl
|
||||||
pkglibexec_PROGRAMS =
|
pkglibexec_PROGRAMS = keventd logit sulogin
|
||||||
finit_pkglibdir = $(pkglibdir)
|
|
||||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
|
||||||
|
|
||||||
if WATCHDOGD
|
if WATCHDOGD
|
||||||
pkglibexec_PROGRAMS += watchdogd
|
pkglibexec_PROGRAMS += watchdogd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if LOGIT
|
finit_pkglibdir = $(pkglibdir)
|
||||||
pkglibexec_PROGRAMS += logit
|
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_SOURCES = logit.c logrotate.c
|
||||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
logit_CFLAGS += $(lite_CFLAGS)
|
logit_CFLAGS += $(lite_CFLAGS)
|
||||||
logit_LDADD = $(lite_LIBS)
|
logit_LDADD = $(lite_LIBS)
|
||||||
endif
|
|
||||||
|
|
||||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
@@ -47,7 +52,7 @@ if LOGROTATE
|
|||||||
finit_SOURCES += logrotate.c
|
finit_SOURCES += logrotate.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h
|
pkginclude_HEADERS = cgroup.h cond.h finit.h helpers.h log.h plugin.h svc.h
|
||||||
|
|
||||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
|
|||||||
@@ -172,6 +172,9 @@ int cgroup_service(char *name, int pid, struct cgroup *cg)
|
|||||||
if (!strcmp(cg->name, "root"))
|
if (!strcmp(cg->name, "root"))
|
||||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
|
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);
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
|
||||||
if (fisdir(path))
|
if (fisdir(path))
|
||||||
group = cg->name;
|
group = cg->name;
|
||||||
|
|||||||
+1
-1
@@ -580,7 +580,7 @@ static void key(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
warnx("Got char 0x%02x", ch);
|
dbg("Got char 0x%02x", ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-12
@@ -163,7 +163,7 @@ int cond_set_path(const char *path, enum cond_state next)
|
|||||||
return next != prev;
|
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)
|
void cond_update(const char *name)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
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);
|
_d("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return;
|
return 1;
|
||||||
|
|
||||||
if (!cond_set_path(cond_path(name), COND_ON))
|
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;
|
return;
|
||||||
|
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
@@ -208,13 +217,22 @@ void cond_set_oneshot(const char *name)
|
|||||||
cond_update(name);
|
cond_update(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cond_clear(const char *name)
|
int cond_clear_noupdate(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return;
|
return 1;
|
||||||
|
|
||||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
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;
|
return;
|
||||||
|
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
@@ -227,7 +245,7 @@ void cond_reload(void)
|
|||||||
cond_bump_reconf();
|
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;
|
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);
|
nm = strstr((char *)fpath, COND_BASE);
|
||||||
if (!nm) {
|
if (!nm) {
|
||||||
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
_e("Incorrect condtion path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nm += strlen(COND_BASE);
|
nm += strlen(COND_BASE);
|
||||||
_d("Reasserting %s => %s", fpath, nm);
|
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
||||||
cond_set(nm);
|
if (set)
|
||||||
|
cond_set(nm);
|
||||||
|
else
|
||||||
|
cond_clear_noupdate(nm); /* important, see netlink plugin! */
|
||||||
|
|
||||||
return 0;
|
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.
|
* Used only by netlink plugin atm.
|
||||||
* type: is a one of pid/, net/, etc.
|
* type: is a one of pid/, net/, etc.
|
||||||
*/
|
*/
|
||||||
void cond_reassert(const char *type)
|
void cond_reassert(const char *pat)
|
||||||
{
|
{
|
||||||
_d("%s", type);
|
_d("%s", pat);
|
||||||
nftw(cond_path(type), reassert, 20, FTW_DEPTH);
|
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)
|
void cond_init(void)
|
||||||
|
|||||||
+10
-2
@@ -5,12 +5,14 @@
|
|||||||
#include <svc.h>
|
#include <svc.h>
|
||||||
|
|
||||||
#define COND_BASE "finit/cond"
|
#define COND_BASE "finit/cond"
|
||||||
#define COND_USR "usr/"
|
|
||||||
#define COND_PID "pid/"
|
#define COND_PID "pid/"
|
||||||
|
#define COND_SYS "sys/"
|
||||||
|
#define COND_USR "usr/"
|
||||||
|
|
||||||
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
|
||||||
#define _PATH_CONDPID _PATH_COND COND_PID
|
#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"
|
#define _PATH_RECONF _PATH_COND "reconf"
|
||||||
|
|
||||||
typedef enum cond_state {
|
typedef enum cond_state {
|
||||||
@@ -34,7 +36,13 @@ void cond_set (const char *name);
|
|||||||
void cond_set_oneshot (const char *name);
|
void cond_set_oneshot (const char *name);
|
||||||
void cond_clear (const char *name);
|
void cond_clear (const char *name);
|
||||||
void cond_reload (void);
|
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_reassert (const char *pat);
|
||||||
|
void cond_deassert (const char *pat);
|
||||||
|
|
||||||
void cond_init (void);
|
void cond_init (void);
|
||||||
|
|
||||||
#endif /* FINIT_COND_H_ */
|
#endif /* FINIT_COND_H_ */
|
||||||
|
|||||||
+1
-1
@@ -672,7 +672,7 @@ int conf_reload(void)
|
|||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
int rc;
|
int rc;
|
||||||
char line[80] = "tty [12345] @console noclear nologin";
|
char line[80] = "tty [12345] rescue";
|
||||||
|
|
||||||
/* If rescue.conf is missing, fall back to a root shell */
|
/* If rescue.conf is missing, fall back to a root shell */
|
||||||
rc = parse_conf(RESCUE_CONF, 0);
|
rc = parse_conf(RESCUE_CONF, 0);
|
||||||
|
|||||||
+91
-48
@@ -52,6 +52,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
#include "watchdog.h"
|
||||||
|
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = 0; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
@@ -185,6 +186,69 @@ static void fs_remount_root(int fsckerr)
|
|||||||
}
|
}
|
||||||
#endif /* SYSROOT */
|
#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)
|
static void fs_mount(void)
|
||||||
{
|
{
|
||||||
if (!rescue)
|
if (!rescue)
|
||||||
@@ -200,6 +264,9 @@ static void fs_mount(void)
|
|||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
run("swapon -ea");
|
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
|
* Handle bootstrap transition to configured runlevel, start TTYs
|
||||||
@@ -504,13 +529,24 @@ int main(int argc, char *argv[])
|
|||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
_pe("Failed cd /");
|
_pe("Failed cd /");
|
||||||
|
|
||||||
/* Allow progress, if enabled */
|
|
||||||
enable_progress(1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of emergency.
|
* In case of emergency.
|
||||||
*/
|
*/
|
||||||
emergency_shell();
|
if (rescue) {
|
||||||
|
char *sulogin[] = {
|
||||||
|
_PATH_SULOGIN,
|
||||||
|
"sulogin",
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(sulogin); i++) {
|
||||||
|
if (systemf(sulogin[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rescue = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load plugins early, the first hook is in banner(), so we
|
* Load plugins early, the first hook is in banner(), so we
|
||||||
@@ -521,6 +557,7 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Hello world.
|
* Hello world.
|
||||||
*/
|
*/
|
||||||
|
enable_progress(1); /* Allow progress, if enabled */
|
||||||
banner();
|
banner();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -552,11 +589,17 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Start built-in watchdogd as soon as possible, if enabled
|
* Start built-in watchdogd as soon as possible, if enabled
|
||||||
*/
|
*/
|
||||||
if (which(FINIT_LIBPATH_ "/watchdogd")) {
|
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
||||||
service_register(SVC_TYPE_SERVICE, "[123456789] name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||||
wdog = svc_find_by_nameid("watchdog", "finit");
|
wdog = svc_find_by_nameid("watchdog", "finit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
/* Base FS up, enable standard SysV init signals */
|
||||||
sig_setup(&loop);
|
sig_setup(&loop);
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -50,7 +50,8 @@
|
|||||||
#define FINIT_CGPATH "/sys/fs/cgroup"
|
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOGIT_PATH FINIT_LIBPATH_ "/logit"
|
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
|
||||||
|
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
|
|||||||
+2
-2
@@ -189,8 +189,8 @@ static int do_login(char *name)
|
|||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failed to exec login, should be impossible. Try a starting a
|
* Failed to exec login, should not happen on normal systems.
|
||||||
* fallback shell instead.
|
* Try a starting a rescue shell instead.
|
||||||
*
|
*
|
||||||
* Note: Add /etc/securetty handling.
|
* Note: Add /etc/securetty handling.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
-1
@@ -345,7 +345,7 @@ static int do_cond_act(char *arg, int creat)
|
|||||||
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
||||||
err(1, "Failed asserting condition <%s>", &oneshot[off]);
|
err(1, "Failed asserting condition <%s>", &oneshot[off]);
|
||||||
} else {
|
} else {
|
||||||
if (erase(oneshot))
|
if (erase(oneshot) && errno != ENOENT)
|
||||||
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
|
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);
|
wd = inotify_add_watch(iw->fd, path, IWATCH_MASK | mask);
|
||||||
if (wd < 0) {
|
if (wd < 0) {
|
||||||
if (errno != EEXIST)
|
switch (errno) {
|
||||||
|
case EEXIST:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EINVAL:
|
||||||
|
/*
|
||||||
|
* some older kernels, notably 4.19, don't like
|
||||||
|
* inotify on top-level cgroups in cgroup v2
|
||||||
|
*/
|
||||||
|
if (!strncmp(path, "/sys/fs/cgroup", 14))
|
||||||
|
break; /* ignore error */
|
||||||
|
/* fallthrough */
|
||||||
|
|
||||||
|
default:
|
||||||
_pe("Failed adding watcher for %s", path);
|
_pe("Failed adding watcher for %s", path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
free(path);
|
free(path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
+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:
|
case CMD_HALT:
|
||||||
if (do_halt(NULL))
|
if (do_halt(NULL))
|
||||||
do_kill(SIGUSR1, msg);
|
do_kill(SIGUSR2, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_POWEROFF:
|
case CMD_POWEROFF:
|
||||||
|
|||||||
+1
-2
@@ -1,3 +1,2 @@
|
|||||||
runlevel 1
|
runlevel 1
|
||||||
hostname rescue
|
tty [12345] rescue
|
||||||
tty [12345] @console noclear nologin
|
|
||||||
|
|||||||
+15
-5
@@ -206,8 +206,8 @@ static int lredirect(svc_t *svc)
|
|||||||
/* Reset signals */
|
/* Reset signals */
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
|
|
||||||
if (!whichp(LOGIT_PATH)) {
|
if (!whichp(_PATH_LOGIT)) {
|
||||||
logit(LOG_INFO, LOGIT_PATH " missing, using syslog for %s instead", svc->name);
|
logit(LOG_INFO, _PATH_LOGIT " missing, using syslog for %s instead", svc->name);
|
||||||
fallback_logger(tag, prio);
|
fallback_logger(tag, prio);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
@@ -218,7 +218,7 @@ static int lredirect(svc_t *svc)
|
|||||||
snprintf(sz, sizeof(sz), "%d", logfile_size_max);
|
snprintf(sz, sizeof(sz), "%d", logfile_size_max);
|
||||||
snprintf(num, sizeof(num), "%d", logfile_count_max);
|
snprintf(num, sizeof(num), "%d", logfile_count_max);
|
||||||
|
|
||||||
execlp(LOGIT_PATH, "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
|
execlp(_PATH_LOGIT, "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ static int lredirect(svc_t *svc)
|
|||||||
if (svc->log.prio[0])
|
if (svc->log.prio[0])
|
||||||
prio = svc->log.prio;
|
prio = svc->log.prio;
|
||||||
|
|
||||||
execlp(LOGIT_PATH, "logit", "-t", tag, "-p", prio, NULL);
|
execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, NULL);
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +466,7 @@ static int service_start(svc_t *svc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svc_is_tty(svc)) {
|
if (svc_is_tty(svc) && !svc->notty) {
|
||||||
char *dev = tty_canonicalize(svc->dev);
|
char *dev = tty_canonicalize(svc->dev);
|
||||||
|
|
||||||
if (!dev || !tty_exists(dev)) {
|
if (!dev || !tty_exists(dev)) {
|
||||||
@@ -1044,6 +1044,12 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check also for changes to /etc/default/foo, because this
|
||||||
|
* also constitutes changes to command line args.
|
||||||
|
*/
|
||||||
|
diff += conf_changed(svc_getenv(svc));
|
||||||
|
|
||||||
if (diff)
|
if (diff)
|
||||||
_d("Modified args for %s detected", cmd);
|
_d("Modified args for %s detected", cmd);
|
||||||
svc->args_dirty = (diff > 0);
|
svc->args_dirty = (diff > 0);
|
||||||
@@ -1254,6 +1260,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
if (type == SVC_TYPE_SERVICE && manual)
|
if (type == SVC_TYPE_SERVICE && manual)
|
||||||
svc_stop(svc);
|
svc_stop(svc);
|
||||||
} else {
|
} else {
|
||||||
|
/* update type, may have changed from service -> task */
|
||||||
|
svc->type = type;
|
||||||
|
|
||||||
/* e.g., if missing cmd or env before */
|
/* e.g., if missing cmd or env before */
|
||||||
svc_unblock(svc);
|
svc_unblock(svc);
|
||||||
}
|
}
|
||||||
@@ -1295,6 +1304,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
svc->nowait = tty.nowait;
|
svc->nowait = tty.nowait;
|
||||||
svc->nologin = tty.nologin;
|
svc->nologin = tty.nologin;
|
||||||
svc->notty = tty.notty;
|
svc->notty = tty.notty;
|
||||||
|
svc->rescue = tty.rescue;
|
||||||
|
|
||||||
/* TTYs cannot be redirected */
|
/* TTYs cannot be redirected */
|
||||||
log = NULL;
|
log = NULL;
|
||||||
|
|||||||
@@ -31,21 +31,24 @@
|
|||||||
* does on USR1 with their FIFO/D-Bus.
|
* does on USR1 with their FIFO/D-Bus.
|
||||||
*
|
*
|
||||||
* SIGUSR1
|
* SIGUSR1
|
||||||
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
* Restarts API (initctl) socket, like SysV init and systemd does
|
||||||
* processes, and unmounts all file systems. Then tells kernel to
|
* on USR1 with their FIFO/D-Bus.
|
||||||
* halt. Most people these days want SIGUSR2 though.
|
|
||||||
*
|
*
|
||||||
* (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
|
* SIGUSR2
|
||||||
* Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||||
* or similar exists to actually do this. If the kernel fails
|
* processes, and unmounts all file systems. Then tells kernel to
|
||||||
* power-off, Finit falls back to halt.
|
* 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.)
|
* (SysV init N/A, systemd dumps its internal state to log.)
|
||||||
*
|
*
|
||||||
* SIGTERM
|
* 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.)
|
* (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)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
halt = SHUT_HALT;
|
/* Restart initctl API domain socket, similar to systemd/SysV init */
|
||||||
service_runlevel(0);
|
api_exit();
|
||||||
|
api_init(w->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -517,10 +521,14 @@ void sig_setup(uev_ctx_t *ctx)
|
|||||||
erase(SYNC_SHUTDOWN);
|
erase(SYNC_SHUTDOWN);
|
||||||
erase(SYNC_STOPPED);
|
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);
|
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, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
|
||||||
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
|
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
|
||||||
uev_signal_init(ctx, &sigpwr_watcher, sigusr2_cb, NULL, SIGPWR);
|
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;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
/* this is valid for fallback (notty) shells */
|
/* rescue (notty) shells have no device node */
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ typedef struct svc {
|
|||||||
char nowait;
|
char nowait;
|
||||||
char nologin;
|
char nologin;
|
||||||
char notty;
|
char notty;
|
||||||
|
char rescue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,9 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
|||||||
else if (!strcmp(cmd, "nologin"))
|
else if (!strcmp(cmd, "nologin"))
|
||||||
tty->nologin = 1;
|
tty->nologin = 1;
|
||||||
else if (!strcmp(cmd, "notty"))
|
else if (!strcmp(cmd, "notty"))
|
||||||
tty->notty = 1; /* for fallback shell */
|
tty->notty = 1; /* for board bringup */
|
||||||
|
else if (!strcmp(cmd, "rescue"))
|
||||||
|
tty->rescue = 1; /* for rescue shells */
|
||||||
else if (!access(cmd, X_OK))
|
else if (!access(cmd, X_OK))
|
||||||
tty->cmd = cmd;
|
tty->cmd = cmd;
|
||||||
else
|
else
|
||||||
@@ -167,6 +169,10 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
|||||||
cmd = strtok(NULL, " \t");
|
cmd = strtok(NULL, " \t");
|
||||||
} while (cmd && tty->num < NELEMS(tty->args));
|
} while (cmd && tty->num < NELEMS(tty->args));
|
||||||
|
|
||||||
|
/* rescue shells are always notty */
|
||||||
|
if (tty->rescue)
|
||||||
|
tty->notty = 1;
|
||||||
|
|
||||||
/* skip /dev probe, we just want a bríngup shell */
|
/* skip /dev probe, we just want a bríngup shell */
|
||||||
if (tty->notty)
|
if (tty->notty)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -220,27 +226,38 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
|||||||
|
|
||||||
int tty_exists(char *dev)
|
int tty_exists(char *dev)
|
||||||
{
|
{
|
||||||
int fd, result;
|
|
||||||
struct termios c;
|
struct termios c;
|
||||||
|
int fd, rc;
|
||||||
|
|
||||||
fd = open(dev, O_RDWR);
|
fd = open(dev, O_RDWR);
|
||||||
if (-1 == fd)
|
if (-1 == fd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* XXX: Add check for errno == EIO? */
|
/* XXX: Add check for errno == EIO? */
|
||||||
result = tcgetattr(fd, &c);
|
rc = tcgetattr(fd, &c);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
return result == 0;
|
return rc == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tty_exec(svc_t *tty)
|
int tty_exec(svc_t *svc)
|
||||||
{
|
{
|
||||||
char *args[MAX_NUM_SVC_ARGS];
|
char *args[MAX_NUM_SVC_ARGS];
|
||||||
char *dev;
|
char *dev;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (tty->notty) {
|
/* try to protect system with sulogin, fall back to root shell */
|
||||||
|
if (svc->notty) {
|
||||||
|
if (svc->rescue) {
|
||||||
|
/* check if bundled one is available */
|
||||||
|
if (whichp(_PATH_SULOGIN))
|
||||||
|
return execl(_PATH_SULOGIN, _PATH_SULOGIN, NULL);
|
||||||
|
|
||||||
|
/* util-linux or busybox, no args for compat */
|
||||||
|
if (whichp("sulogin"))
|
||||||
|
return execlp("sulogin", "sulogin", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Become session leader and set controlling TTY
|
* Become session leader and set controlling TTY
|
||||||
* to enable Ctrl-C and job control in shell.
|
* to enable Ctrl-C and job control in shell.
|
||||||
@@ -249,12 +266,12 @@ int tty_exec(svc_t *tty)
|
|||||||
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
|
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
|
||||||
|
|
||||||
prctl(PR_SET_NAME, "finitsh", 0, 0, 0);
|
prctl(PR_SET_NAME, "finitsh", 0, 0, 0);
|
||||||
return execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
return execl(_PATH_BSHELL, "-sh", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = tty_canonicalize(tty->dev);
|
dev = tty_canonicalize(svc->dev);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
_d("%s: Cannot find TTY device: %s", tty->dev, strerror(errno));
|
_d("%s: Cannot find TTY device: %s", svc->dev, strerror(errno));
|
||||||
return EX_CONFIG;
|
return EX_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,24 +280,24 @@ int tty_exec(svc_t *tty)
|
|||||||
return EX_OSFILE;
|
return EX_OSFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tty->nologin) {
|
if (svc->nologin) {
|
||||||
_d("%s: Starting /bin/sh ...", dev);
|
_d("%s: Starting /bin/sh ...", dev);
|
||||||
return run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
|
return run_sh(dev, svc->noclear, svc->nowait, svc->rlimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("%s: Starting %sgetty ...", dev, !tty->cmd ? "built-in " : "");
|
_d("%s: Starting %sgetty ...", dev, !svc->cmd ? "built-in " : "");
|
||||||
if (!strcmp(tty->cmd, "tty"))
|
if (!strcmp(svc->cmd, "tty"))
|
||||||
return run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
return run_getty(dev, svc->baud, svc->term, svc->noclear, svc->nowait, svc->rlimit);
|
||||||
|
|
||||||
for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
||||||
if (!tty->args[i][0])
|
if (!svc->args[i][0])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
args[j++] = tty->args[i];
|
args[j++] = svc->args[i];
|
||||||
}
|
}
|
||||||
args[j++] = NULL;
|
args[j++] = NULL;
|
||||||
|
|
||||||
return run_getty2(dev, tty->cmd, args, tty->noclear, tty->nowait, tty->rlimit);
|
return run_getty2(dev, svc->cmd, args, svc->noclear, svc->nowait, svc->rlimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ struct tty {
|
|||||||
char nowait;
|
char nowait;
|
||||||
char nologin;
|
char nologin;
|
||||||
char notty;
|
char notty;
|
||||||
|
char rescue;
|
||||||
};
|
};
|
||||||
|
|
||||||
char *tty_canonicalize (char *dev);
|
char *tty_canonicalize (char *dev);
|
||||||
|
|||||||
+44
@@ -154,6 +154,35 @@ char *str(char *fmt, ...)
|
|||||||
return buf;
|
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, ...)
|
int fnwrite(char *value, char *fmt, ...)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
@@ -185,6 +214,21 @@ int fnwrite(char *value, char *fmt, ...)
|
|||||||
return rc;
|
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.
|
* 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.
|
* 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 *progname (char *arg0);
|
||||||
|
|
||||||
char *str (char *fmt, ...);
|
char *str (char *fmt, ...);
|
||||||
|
int fnread (char *buf, size_t len, char *fmt, ...);
|
||||||
int fnwrite (char *value, char *fmt, ...);
|
int fnwrite (char *value, char *fmt, ...);
|
||||||
|
int fngetint (char *path, int *val);
|
||||||
|
|
||||||
int has_utmp (void);
|
int has_utmp (void);
|
||||||
int strtobytes (char *arg);
|
int strtobytes (char *arg);
|
||||||
|
|||||||
Reference in New Issue
Block a user