mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68c7352108 | ||
|
|
0d40e43c4b | ||
|
|
9867fd82df | ||
|
|
1c941fdfbb | ||
|
|
0ba67a72f8 | ||
|
|
09b9e26b2d | ||
|
|
d25c1d5564 | ||
|
|
d4358ed3f7 | ||
|
|
cc6ffa35fc | ||
|
|
55e9cb2f58 | ||
|
|
2641256254 | ||
|
|
473116f603 | ||
|
|
e18d63df4a | ||
|
|
4b1b3f6913 | ||
|
|
f6da5e4136 | ||
|
|
d1d5d39144 | ||
|
|
754358113f | ||
|
|
c24207516d | ||
|
|
2a23bce78d | ||
|
|
a19b82ea5f | ||
|
|
ed9590aef1 | ||
|
|
25683221cc | ||
|
|
9cc9e3ddbb | ||
|
|
654f8aeb19 | ||
|
|
e349abb897 | ||
|
|
3027a6755f | ||
|
|
5404aa6037 | ||
|
|
a319e32438 | ||
|
|
2eaf57fc67 | ||
|
|
88ec4a55cb | ||
|
|
0acbc60ec1 | ||
|
|
4362971c6a | ||
|
|
94c0d1b833 | ||
|
|
1e795d4e16 | ||
|
|
93a027ca23 | ||
|
|
5f3958fab4 | ||
|
|
1351b708fe | ||
|
|
e867e039bb | ||
|
|
1d1087a3b3 | ||
|
|
e91f1ea1b2 | ||
|
|
55d16edadc | ||
|
|
b79245ddb3 | ||
|
|
e706300b6d | ||
|
|
d08cbd77aa | ||
|
|
b070ae73a4 | ||
|
|
2c30eef9a1 | ||
|
|
31cdc113fc | ||
|
|
f6f813498b | ||
|
|
4c8baaf7c0 | ||
|
|
57ca937f27 | ||
|
|
d13e39e345 | ||
|
|
f52c141062 | ||
|
|
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 |
+1
-1
@@ -45,7 +45,7 @@ script:
|
||||
- ./configure --prefix= --enable-static
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
- ./configure --prefix= --enable-x11-common-plugin --with-watchdog
|
||||
- ./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||
- cat config.log
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
|
||||
+91
-7
@@ -4,6 +4,95 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.1][UNRELEASED]
|
||||
-----------------
|
||||
|
||||
Bug fix release. Also disables handlers for `SIGINT` and `SIGPWR`, a
|
||||
new set of `sys` conditions are instead generated which can be used to
|
||||
trigger external programs.
|
||||
|
||||
### 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`
|
||||
* Disable default kernel ctrl-alt-delete handler and let Finit instead
|
||||
catch `SIGINT` from kernel to be able to perform a proper reboot.
|
||||
There is no default command for this, you need to set up a task that
|
||||
triggers on `<sys/key/ctrlaltdel>` to issue `initctl reboot`
|
||||
* Added keventd to provide `<sys/pwr/ac>` condition to Finit. keventd
|
||||
is currently only responsible for monitoring `/sys/class/power_supply`
|
||||
for changes to active AC mains power online status. Enable keventd
|
||||
with `configure --with-keventd`
|
||||
* For handling power fail events (from UPS and similar) a process may
|
||||
send `SIGPWR` to PID 1. Finit no longer redirects this to `SIGUSR1`
|
||||
(poweroff). There is no default command for this, you need to set up
|
||||
a task that triggers on `<sys/pwr/fail>` to issue `initctl poweroff`
|
||||
* Built-in Finit getty is now a standalone program
|
||||
* Default termios for TTYs now enable `IUTF8` on input
|
||||
* If `/bin/login` is not found, Finit now tries `sulogin` before it
|
||||
falls back to an unauthenticated `/bin/sh`
|
||||
* Dropped (broken) support for multiple consoles. Finit now follows
|
||||
the default console selected by the kernel, `/dev/console`
|
||||
* Finit no longer parses `/proc/cmdline` for its options. Instead all
|
||||
options are by default now read from `argv[]`, like a normal program,
|
||||
this is also what the kernel does by default. Please note, this may
|
||||
not work if your systems boots with an initramfs (ymmv), for such
|
||||
cases, see `configure --enable-kernel-cmdline`
|
||||
* The following plugins are now possible to disable (for containers):
|
||||
`rtc.so`, `urandom.so`, you may also want to disable `hotplug.so`.
|
||||
They are all enabled by default, as in Finit 4.0, but may be moved
|
||||
to external tools or entries in `finit.conf` in Finit 5.0
|
||||
|
||||
### Fixes
|
||||
* Stricter interface name validation in netlink plugin, modeled after
|
||||
the kernel. Suggested by Coverity Scan
|
||||
* Fix problem of re-registering a service as a task. Previously, if a
|
||||
fundamental change, like type, was made to an active service/run/task
|
||||
it did not take. Only possible workaround was to remove from config
|
||||
* initctl: drop warning when removing a non-existing usr condition
|
||||
* initctl: drop confusing `errno 0` when timing out waiting for reply
|
||||
* Ensure services in plugins and from Finit main belong to a cgroup
|
||||
* Ensure init top-level cgroup remains a leaf group
|
||||
* Fix tty parse error for detecting use of external getty
|
||||
* Fix default `name:` and `:ID` for tty's, e.g. `ttyS0` now gives
|
||||
`tty:S0` as expected. This was default for built-in getty already
|
||||
* Fix max username (32 chars) in bundled Finit getty
|
||||
* The `contrib/*/install.sh` scripts failed to run from tarball
|
||||
* Finit no longer forcibly mounts; `/dev`, `/proc`, or `/sys`, instead
|
||||
it checks first if they are already mounted (devtmpfs or container)
|
||||
* Fix `/etc/fstab` parser to properly check for 'ro' to not remount the
|
||||
root filesystem at boot. The wrong field was read, so a root mounted
|
||||
by an initramfs, or by lxc for a container, had their root remounted
|
||||
* 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. Here we also make sure to mount
|
||||
`/run/lock` as a tmpfs as well, with write perms for regular users,
|
||||
this prevents regular users from filling up `/run` and causing DoS.
|
||||
* 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.
|
||||
|
||||
* Fix #174: loss of log messages using combo of prio and facility, e.g.,
|
||||
`logit(LOG_CONSOLE | LOG_NOTICE, ...)`, by Jacques de Laval, Westermo
|
||||
* Fix #175: ensure Finit does not acquire a controlling TTY when checking
|
||||
if a device is a TTY before starting a getty. This fixes an old bug
|
||||
where Ctrl-C after logout from a shell could cause PID 1 to get SIGINT,
|
||||
which in turn could lead to a system reboot
|
||||
|
||||
|
||||
[4.0][] - 2021-04-26
|
||||
--------------------
|
||||
|
||||
@@ -875,7 +964,8 @@ Major bug fix release.
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.0...HEAD
|
||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||
@@ -907,9 +997,3 @@ Major bug fix release.
|
||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
|
||||
@@ -134,7 +134,7 @@ Some components are optional: runlevel(s), condition(s) and description,
|
||||
making it easy to create simple start scripts and still possible for more
|
||||
advanced uses as well:
|
||||
|
||||
service sshd -D
|
||||
service /usr/sbin/sshd -D
|
||||
|
||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||
the most common conditions is to wait for basic networking to become
|
||||
@@ -460,9 +460,6 @@ Commands:
|
||||
halt Halt system
|
||||
poweroff Halt and power off system
|
||||
suspend Suspend system
|
||||
|
||||
Bug report address: https://github.com/troglobit/finit/issues
|
||||
Project homepage: https://troglobit.com/finit.html
|
||||
```
|
||||
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
|
||||
+18
-2
@@ -1,4 +1,4 @@
|
||||
AC_INIT(Finit, 4.0, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_INIT(Finit, 4.1-rc2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -8,7 +8,7 @@ AC_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
contrib/Makefile
|
||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||
doc/Makefile
|
||||
plugins/Makefile
|
||||
@@ -52,6 +52,10 @@ AC_ARG_ENABLE(auto_reload,
|
||||
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||
enable_auto_reload=no])
|
||||
|
||||
AC_ARG_ENABLE(kernel_cmdline,
|
||||
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[
|
||||
enable_kernel_cmdline=no])
|
||||
|
||||
AC_ARG_ENABLE(redirect,
|
||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||
enable_redirect=yes])
|
||||
@@ -77,6 +81,8 @@ AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
AC_ARG_WITH(heading,
|
||||
@@ -111,6 +117,9 @@ AC_ARG_WITH(random-seed,
|
||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||
[random_seed=$withval], [random_seed=yes])
|
||||
|
||||
AC_ARG_WITH(keventd,
|
||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||
|
||||
AC_ARG_WITH(watchdog,
|
||||
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||
@@ -121,6 +130,9 @@ AC_ARG_WITH(watchdog,
|
||||
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||
|
||||
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
||||
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
||||
|
||||
AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||
|
||||
@@ -179,6 +191,8 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
AC_EXPAND_DIR(random_path, "$random_seed")
|
||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
||||
|
||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||
|
||||
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
AS_IF([test "x$watchdog" = "xyes"], [
|
||||
watchdog=/dev/watchdog])
|
||||
@@ -188,6 +202,7 @@ AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||
@@ -234,6 +249,7 @@ Behavior:
|
||||
Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Redirect output.......: $enable_redirect
|
||||
|
||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--with-heading="Alpine Linux 3.13"
|
||||
--with-heading="Alpine Linux" --with-keventd
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
|
||||
@@ -5,6 +5,22 @@
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ fi
|
||||
# Adjust base directory
|
||||
if [ -e alpine-release ]; then
|
||||
cd ../..
|
||||
elif [ ! -e autogen.sh ]; then
|
||||
elif [ ! -e configure.ac ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = finit.d grub.d
|
||||
SUBDIRS = finit.d
|
||||
docsdir := @docdir@/contrib/debian
|
||||
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -29,10 +29,10 @@ set up your system to run Finit:
|
||||
user@debian:~/finit$ contrib/debian/build.sh
|
||||
|
||||
However, since `/sbin/init` already exists on your system, the script
|
||||
creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
|
||||
where `init=/sbin/finit` is added to your kernel line. It is of course
|
||||
also possible to change the default init to Finit, if you do you can
|
||||
remove the custom Grub entry:
|
||||
creates another entry in your GRUB config by updating `$SUPPORTED_INITS`
|
||||
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find
|
||||
a (finit) entry in the "Advanced options for Debian GNU/Linux" section.
|
||||
It is of course also possible to change the default init to Finit:
|
||||
|
||||
user@debian:~/finit# cd /sbin
|
||||
user@debian:/sbin# sudo mv init oldinit
|
||||
@@ -51,7 +51,8 @@ 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.
|
||||
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!
|
||||
|
||||
@@ -25,7 +25,7 @@ echo
|
||||
--prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin \
|
||||
--enable-alsa-utils-plugin --with-keventd \
|
||||
--with-random-seed=/var/lib/urandom/random-seed \
|
||||
--with-heading="Debian GNU/Linux"
|
||||
|
||||
|
||||
@@ -5,6 +5,22 @@
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
SUBDIRS = available
|
||||
docsdir := @docdir@/contrib/debian/finit.d
|
||||
d_LINKS = console-setup.conf elogind.conf getty.conf \
|
||||
keyboard-setup.conf modules.conf rsyslogd.conf \
|
||||
sshd.conf
|
||||
d_LINKS = acpid.conf apparmor.conf avahi-demon.conf \
|
||||
bluetooth.conf console-setup.conf elogind.conf \
|
||||
getty.conf keyboard-setup.conf modules.conf \
|
||||
rsyslogd.conf sshd.conf
|
||||
|
||||
install-exec-hook:
|
||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||
docs_DATA = acpid.conf console-setup.conf elogind.conf getty.conf \
|
||||
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
|
||||
console-setup.conf elogind.conf getty.conf \
|
||||
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||
rsyslogd.conf sshd.conf syslogd.conf xdm.conf
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
|
||||
@@ -0,0 +1,2 @@
|
||||
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
|
||||
@@ -0,0 +1,3 @@
|
||||
# To ignore errors like "org.freedesktop.hostname1", update the env file with
|
||||
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
|
||||
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
|
||||
@@ -0,0 +1 @@
|
||||
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
|
||||
@@ -1,4 +1,7 @@
|
||||
# Consoles to start getty on when system is up
|
||||
tty [12345] /dev/tty1 linux noclear nowait
|
||||
tty [2345] /dev/tty2 linux noclear nowait
|
||||
tty [2345] /dev/tty3 linux noclear nowait
|
||||
tty [2345] /dev/tty2 linux nowait
|
||||
tty [2345] /dev/tty3 linux nowait
|
||||
tty [2345] /dev/tty4 linux nowait
|
||||
tty [2345] /dev/tty5 linux nowait
|
||||
tty [2345] /dev/tty6 linux nowait
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
exec tail -n +3 $0
|
||||
# This file provides an easy way to add custom menu entries. Simply type the
|
||||
# menu entries you want to add after this comment. Be careful not to change
|
||||
# the 'exec tail' line above.
|
||||
|
||||
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
|
||||
insmod gzio
|
||||
insmod part_msdos
|
||||
insmod ext2
|
||||
search --no-floppy --fs-uuid --set=root $BOOT
|
||||
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
|
||||
initrd /initrd.img
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
docsdir := @docdir@/contrib/debian/grub.d
|
||||
docs_DATA = 40_custom
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
@@ -11,7 +11,7 @@ fi
|
||||
grep -q Debian os-release 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
cd ../..
|
||||
elif [ ! -e autogen.sh ]; then
|
||||
elif [ ! -e configure.ac ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
|
||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||
echo "/etc/finit.conf - Finit configuration file"
|
||||
echo "/etc/finit.d/ - Finit services"
|
||||
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
|
||||
echo "/etc/grub.d/10_linux - Add Finit to Grub's SUPPORTED_INITS"
|
||||
echo
|
||||
read -p "Do you want to continue (y/N)? " yorn
|
||||
echo
|
||||
@@ -38,12 +38,18 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
cp -va finit.d /etc/
|
||||
|
||||
echo "*** Setting up a GRUB boot entry ..."
|
||||
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
|
||||
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
|
||||
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
||||
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
||||
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
|
||||
update-grub
|
||||
fn=/etc/grub.d/10_linux
|
||||
if [ -e $fn ]; then
|
||||
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then
|
||||
echo "Already installed, done."
|
||||
else
|
||||
echo "Adding Finit to list of SUPPORTED_INITS ..."
|
||||
sed -i 's/SUPPORTED_INITS="[^"]*/& finit:\/sbin\/finit/' $fn
|
||||
update-grub
|
||||
fi
|
||||
else
|
||||
echo "Cannot find $fn, you'll have to set up your bootloader on your own."
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "*** Done"
|
||||
|
||||
@@ -35,6 +35,14 @@ tty /dev/tty1
|
||||
tty /dev/tty2
|
||||
tty /dev/tty3
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
# Alternative method instead of runparts
|
||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
|
||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--with-heading="Void Linux"
|
||||
--with-heading="Void Linux" --with-keventd
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
|
||||
@@ -5,5 +5,22 @@
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
@@ -10,7 +10,7 @@ fi
|
||||
# Adjust base directory
|
||||
if [ -e xbps ]; then
|
||||
cd ../..
|
||||
elif [ ! -e autogen.sh ]; then
|
||||
elif [ ! -e configure.ac ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -26,12 +26,18 @@ Some of these are also registered in the issue tracker on GitHub.
|
||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||
`pimd` man pages ...
|
||||
|
||||
|
||||
Initctl
|
||||
-------
|
||||
|
||||
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
||||
|
||||
shutdown -h 03:35 "foobar was here"
|
||||
|
||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||
`initctl show --json`
|
||||
* Add support for `-s` to redirect all output to syslog, for scripting
|
||||
|
||||
|
||||
Init
|
||||
|
||||
+13
-8
@@ -53,6 +53,10 @@ Below are a few of the main switches to configure:
|
||||
built-ins (.o files) and all external libraries, except the C library
|
||||
will be linked statically.
|
||||
|
||||
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||
`/proc/cmdline`, this is not recommended since Finit may be running as the
|
||||
init for container apps that can see the host's `/proc` filesystem
|
||||
|
||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||
|
||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||
@@ -70,16 +74,17 @@ Example
|
||||
First, unpack the archive:
|
||||
|
||||
```shell
|
||||
$ tar xf finit-3.0.tar.xz
|
||||
$ cd finit-3.0/
|
||||
$ tar xf finit-4.1.tar.gz
|
||||
$ cd finit-4.1/
|
||||
```
|
||||
|
||||
Then configure, build and install:
|
||||
|
||||
```shell
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-heading="Alpine Linux 3.13" --with-hostname=alpine
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-keventd --with-watchdog \
|
||||
--with-heading="Alpine Linux" --with-hostname=alpine
|
||||
$ make
|
||||
.
|
||||
.
|
||||
@@ -87,13 +92,13 @@ $ make
|
||||
$ DESTDIR=/tmp/finit make install
|
||||
```
|
||||
|
||||
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
|
||||
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
|
||||
user's home directory, configured, built and installed to a temporary
|
||||
staging directory. The environment variable `DESTDIR` controls the
|
||||
destination directory when installing, very useful for building binary
|
||||
standalone packages.
|
||||
|
||||
Finit 3.0 and later can detect if it runs on an embedded system, or a
|
||||
Finit 4.1 and later can detect if it runs on an embedded system, or a
|
||||
system that use BusyBox tools instead of udev & C:o. On such systems
|
||||
`mdev` instead of `udev` is used. However, remember to also change the
|
||||
Linux config to:
|
||||
@@ -171,6 +176,6 @@ it only for debugging start up issues when Finit crashes.
|
||||
systems since they can potentially give a user root access.
|
||||
|
||||
|
||||
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
|
||||
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
@@ -6,6 +6,8 @@ passed on the Linux kernel command line. Not limited to Finit.
|
||||
|
||||
The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
|
||||
> **NOTE:** remember to use `--` to separate kernel parameters from
|
||||
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||
|
||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||
console until Finit starts up.
|
||||
|
||||
+13
-6
@@ -87,12 +87,15 @@ Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||
Built-in Conditions
|
||||
-------------------
|
||||
|
||||
Finit comes with a `pidfile` and `netlink` plugin. When enabled, the
|
||||
`pidfile` plugin watches `/var/run/` (recursively) for PID files created
|
||||
by the monitored services, and sets a corresponding condition in the
|
||||
`pid/` namespace. Similarily, the `netlink` plugin provides basic
|
||||
conditions for when an interface is brought up/down and when a default
|
||||
route (gateway) is set, in the `net/` namespace.
|
||||
Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
|
||||
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
|
||||
(recursively) for PID files created by the monitored services, and sets
|
||||
a corresponding condition in the `pid/` namespace. Similarily, the
|
||||
`netlink` plugin provides basic conditions for when an interface is
|
||||
brought up/down and when a default route (gateway) is set, in the `net/`
|
||||
namespace. The `sys` and `usr` plugins monitor are passive condition
|
||||
monitors where the action is provided by `keventd`, signal handlers,
|
||||
and in the case of `usr`, the end-user via the `initctl` tool
|
||||
|
||||
With the example listed above, finit does not start the `/sbin/netd`
|
||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||
@@ -111,6 +114,10 @@ Built-in conditions:
|
||||
- `net/<IFNAME>/exist`
|
||||
- `net/<IFNAME>/up`
|
||||
- `net/<IFNAME>/running`
|
||||
- `sys/pwr/ac`
|
||||
- `sys/pwr/fail`
|
||||
- `sys/key/ctrlaltdel`
|
||||
- `usr/foo`
|
||||
|
||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||
|
||||
@@ -26,6 +26,7 @@ Configuration
|
||||
* [/etc/finit.conf](#etcfinitconf)
|
||||
* [/etc/finit.d](#etcfinitd)
|
||||
* [Watchdog](#watchdog)
|
||||
* [keventd](#keventd)
|
||||
|
||||
|
||||
Introduction
|
||||
@@ -704,3 +705,19 @@ the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||
it at configure time.
|
||||
|
||||
[bootstrap]: bootstrap.md
|
||||
|
||||
|
||||
keventd
|
||||
-------
|
||||
|
||||
The kernel event daemon bundled with Finit is a simple uevent monitor
|
||||
for `/sys/class/power_supply`. It provides the `sys/pwr/ac` condition,
|
||||
which can be useful to prevent power hungry services like anacron to run
|
||||
when a laptop is only running on battery, for instance.
|
||||
|
||||
Since keventd is not an integral part of Finit yet it is not enabled by
|
||||
default. Enable it using `./configuure --with-keventd`. The bundled
|
||||
contrib build scripts for Debian, Alpine, and Void have this enabled.
|
||||
|
||||
This daemon is planned to be extended with monitoring of other uevents,
|
||||
patches and ideas are welcome in the issue tracker.
|
||||
|
||||
+17
-9
@@ -12,28 +12,36 @@ have been adopted:
|
||||
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
||||
*.conf files in `/etc/finit.d/`
|
||||
|
||||
This also restarts the API (initctl) socket, like SysV init and systemd
|
||||
does on USR1 with their FIFO/D-Bus.
|
||||
|
||||
|
||||
`SIGUSR1`
|
||||
---------
|
||||
|
||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||
processes, and unmounts all file systems. Then tells kernel to halt.
|
||||
Most people these days want `SIGUSR2` though.
|
||||
Since Finit 4.1 this signal causes Finit to restart its API (initctl)
|
||||
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus.
|
||||
|
||||
Finit <= 4.0 performed a system halt (like USR2 without power-off), but
|
||||
this caused compatibility problems with systemd and sysvinit on desktop
|
||||
systems. Hence, since Finit 4.1 it is no longer possible to halt a
|
||||
system with a signal.
|
||||
|
||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
||||
|
||||
`SIGUSR2`
|
||||
---------
|
||||
|
||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
|
||||
similar exists to actually do this. If the kernel fails power-off,
|
||||
Finit falls back to halt.
|
||||
|
||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||
processes, and unmounts all file systems. Then tells kernel to power
|
||||
off the system, if ACPI or similar exists to actually do this. If the
|
||||
kernel fails power-off, Finit falls back to halt.
|
||||
|
||||
SysV init N/A, systemd dumps its internal state to log.
|
||||
|
||||
`SIGTERM`
|
||||
---------
|
||||
|
||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
||||
Like `SIGUSR2`, but tell kernel to reboot the system when done.
|
||||
|
||||
SysV init N/A, systemd rexecutes itself.
|
||||
|
||||
|
||||
+22
-2
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c usr.c
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c pidfile.c procps.c sys.c tty.c usr.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -33,8 +33,20 @@ if BUILD_RESOLVCONF_PLUGIN
|
||||
libplug_la_SOURCES += resolvconf.c
|
||||
endif
|
||||
|
||||
if BUILD_RTC_PLUGIN
|
||||
libplug_la_SOURCES += rtc.c
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
libplug_la_SOURCES += urandom.c
|
||||
endif
|
||||
|
||||
if BUILD_X11_COMMON_PLUGIN
|
||||
libplug_la_SOURCES += x11-common.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la usr.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la pidfile.la procps.la sys.la tty.la usr.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
@@ -60,6 +72,14 @@ if BUILD_RESOLVCONF_PLUGIN
|
||||
pkglib_LTLIBRARIES += resolvconf.la
|
||||
endif
|
||||
|
||||
if BUILD_RTC_PLUGIN
|
||||
pkglib_LTLIBRARIES += rtc.la
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
pkglib_LTLIBRARIES += urandom.la
|
||||
endif
|
||||
|
||||
if BUILD_X11_COMMON_PLUGIN
|
||||
pkglib_LTLIBRARIES += x11-common.la
|
||||
endif
|
||||
|
||||
+12
-5
@@ -119,15 +119,16 @@ static void setup(void *arg)
|
||||
makedir("/var/lib/urandom",0755);
|
||||
if (fisdir("/run")) {
|
||||
_d("System with new /run tmpfs ...");
|
||||
makedir("/run/lock", 1777);
|
||||
if (!fisdir("/run/lock"))
|
||||
makedir("/run/lock", 1777);
|
||||
symlink("/run/lock", "/var/lock");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
|
||||
/* compat only, should really be set up by OS/dist */
|
||||
symlink("/run", "/var/run");
|
||||
symlink("/run", "/var/run");
|
||||
} else {
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
}
|
||||
makedir("/var/log", 0755);
|
||||
makedir("/var/mail", 0755);
|
||||
@@ -183,6 +184,12 @@ static void setup(void *arg)
|
||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
||||
|
||||
/* Debian has /run/sudo, ensure correct perms and SELinux label */
|
||||
mksubsys("/var/run/sudo", 0711, "root", "root");
|
||||
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
||||
if (whichp("restorecon"))
|
||||
run("restorecon /var/run/sudo /var/run/sudo/ts");
|
||||
|
||||
umask(prev);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ static void setup(void *arg)
|
||||
remove("/var/run/dbus/pid");
|
||||
|
||||
/* Register service with Finit */
|
||||
snprintf(line, sizeof(line), "[S12345789] @%s:%s %s %s -- %s",
|
||||
snprintf(line, sizeof(line), "[S12345789] cgroup.system @%s:%s %s %s -- %s",
|
||||
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||
_pe("Failed registering %s", DAEMON);
|
||||
|
||||
+3
-3
@@ -48,17 +48,17 @@ static void setup(void *arg)
|
||||
path = which("/lib/systemd/systemd-udevd");
|
||||
if (path) {
|
||||
/* Register udevd as a monitored service */
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] cgroup.system pid:udevd name:udevd log %s "
|
||||
"-- Device event managing daemon", path);
|
||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||
_pe("Failed registering %s", path);
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
|
||||
snprintf(cmd, sizeof(cmd), "cgroup.init :1 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t devices "
|
||||
"-- Requesting device events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
|
||||
snprintf(cmd, sizeof(cmd), "cgroup.init :2 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t subsystems "
|
||||
"-- Requesting subsystem events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||
#endif
|
||||
#define SERVICE_LINE \
|
||||
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
|
||||
static void load(void *arg)
|
||||
{
|
||||
@@ -71,8 +71,7 @@ static void load(void *arg)
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
||||
index, mod, mod, args, mod);
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
|
||||
index++;
|
||||
|
||||
+228
-42
@@ -30,31 +30,35 @@
|
||||
#include "cond.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
|
||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
||||
{
|
||||
if (!NLMSG_OK(nh, len))
|
||||
return 1;
|
||||
#define NL_BUFSZ 4096
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
||||
_d("Done with netlink messages.");
|
||||
return 1;
|
||||
}
|
||||
struct nl_request {
|
||||
struct nlmsghdr nh;
|
||||
union {
|
||||
struct rtmsg rtm;
|
||||
struct ifinfomsg ifi;
|
||||
};
|
||||
};
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
||||
_d("Netlink reports error.");
|
||||
return 1;
|
||||
}
|
||||
static int nl_defidx;
|
||||
static int nl_ifdown;
|
||||
static char *nl_buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
{
|
||||
char daddr[INET_ADDRSTRLEN];
|
||||
char gaddr[INET_ADDRSTRLEN];
|
||||
struct in_addr ind, ing;
|
||||
struct rtmsg *r;
|
||||
struct rtattr *a;
|
||||
int plen = 0;
|
||||
int dst = 0;
|
||||
int idx = 0;
|
||||
int gw = 0;
|
||||
int la;
|
||||
int gw = 0, dst = 0, mask = 0, idx = 0;
|
||||
|
||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||
_e("Packet too small or truncated!");
|
||||
@@ -80,8 +84,8 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
|
||||
case RTA_DST:
|
||||
dst = *((int *)data);
|
||||
mask = r->rtm_dst_len;
|
||||
//_d("MASK: 0x%04x", mask);
|
||||
plen = r->rtm_dst_len;
|
||||
//_d("Prefix LEN: 0x%04x", plen);
|
||||
break;
|
||||
|
||||
case RTA_OIF:
|
||||
@@ -93,11 +97,20 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
a = RTA_NEXT(a, la);
|
||||
}
|
||||
|
||||
if ((!dst && !mask) && (gw || idx)) {
|
||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
||||
ind.s_addr = dst;
|
||||
ing.s_addr = gw;
|
||||
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
||||
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
||||
_d("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
||||
|
||||
if ((!dst && !plen) && (gw || idx)) {
|
||||
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
||||
cond_clear("net/route/default");
|
||||
else
|
||||
nl_defidx = 0;
|
||||
} else {
|
||||
cond_set("net/route/default");
|
||||
nl_defidx = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,14 +130,14 @@ static int validate_ifname(const char *ifname)
|
||||
if (!ifname || !ifname[0])
|
||||
return 1;
|
||||
|
||||
if (strlen(ifname) >= IFNAMSIZ)
|
||||
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
|
||||
return 1;
|
||||
|
||||
if (strstr(ifname, ".."))
|
||||
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
|
||||
return 1;
|
||||
|
||||
while (*ifname) {
|
||||
if (*ifname == '/' || isspace(*ifname))
|
||||
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
|
||||
return 1;
|
||||
ifname++;
|
||||
}
|
||||
@@ -132,12 +145,25 @@ static int validate_ifname(const char *ifname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this interface was associated with the default route
|
||||
* previously, or if it's been removed. If so, trigger a recheck
|
||||
* of the system default route.
|
||||
*/
|
||||
static void nl_check_default(char *ifname)
|
||||
{
|
||||
int idx = (int)if_nametoindex(ifname);
|
||||
|
||||
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
|
||||
nl_ifdown = 1;
|
||||
}
|
||||
|
||||
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
{
|
||||
int la;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
struct rtattr *a;
|
||||
struct ifinfomsg *i;
|
||||
struct rtattr *a;
|
||||
int la;
|
||||
|
||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||
_e("Packet too small or truncated!");
|
||||
@@ -172,6 +198,8 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
net_cond_set(ifname, "exist", 1);
|
||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
|
||||
nl_check_default(ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
@@ -180,6 +208,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
net_cond_set(ifname, "exist", 0);
|
||||
net_cond_set(ifname, "up", 0);
|
||||
net_cond_set(ifname, "running", 0);
|
||||
nl_check_default(ifname);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
@@ -197,26 +226,176 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
}
|
||||
}
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
static int nl_parse(int sd)
|
||||
{
|
||||
static char buf[4096];
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
while (1) {
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
size_t l;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = recv(sd, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
if (errno != EINTR) /* Signal */
|
||||
_pe("recv()");
|
||||
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN: /* Nothing more right now. */
|
||||
return 0;
|
||||
|
||||
case EINTR: /* Signal */
|
||||
continue;
|
||||
|
||||
case ENOBUFS: /* netlink(7) */
|
||||
break;
|
||||
|
||||
default:
|
||||
_pe("recv()");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("recv %lld bytes", len);
|
||||
l = (size_t)len;
|
||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||
struct nlmsgerr *nle;
|
||||
|
||||
switch (nh->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
_d("Done with netlink messages.");
|
||||
return 0;
|
||||
|
||||
case NLMSG_ERROR:
|
||||
_d("Kernel netlink comm. error.");
|
||||
nle = NLMSG_DATA(nh);
|
||||
if (nle) {
|
||||
errno = -nle->error;
|
||||
_pe("Kernel netlink error %d", errno);
|
||||
}
|
||||
return -1;
|
||||
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
_d("Netlink route ...");
|
||||
nl_route(nh, len);
|
||||
break;
|
||||
|
||||
case RTM_NEWLINK:
|
||||
case RTM_DELLINK:
|
||||
_d("Netlink link ...");
|
||||
nl_link(nh, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int nl_request(int sd, unsigned int seq, int type)
|
||||
{
|
||||
struct nl_request *nlr = (struct nl_request *)nl_buf;
|
||||
|
||||
memset(nlr, 0, sizeof(struct nl_request));
|
||||
nlr->nh.nlmsg_type = type;
|
||||
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||
nlr->nh.nlmsg_seq = seq;
|
||||
nlr->nh.nlmsg_pid = 1;
|
||||
|
||||
switch (type) {
|
||||
case RTM_GETROUTE:
|
||||
_d("RTM_GETROUTE");
|
||||
nlr->rtm.rtm_family = AF_INET;
|
||||
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
break;
|
||||
|
||||
case RTM_GETLINK:
|
||||
_d("RTM_GETLINK");
|
||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
break;
|
||||
|
||||
default:
|
||||
_w("Cannot resync, unhandled message type %d", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
|
||||
return 1;
|
||||
|
||||
return nl_parse(sd);
|
||||
}
|
||||
|
||||
static void nl_resync_routes(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||
_pe("Failed netlink route request");
|
||||
}
|
||||
|
||||
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_request(sd, seq, RTM_GETLINK))
|
||||
_pe("Failed netlink link request");
|
||||
}
|
||||
|
||||
/*
|
||||
* We've potentially lost netlink events, let's resync with kernel.
|
||||
*/
|
||||
static void nl_resync(int all)
|
||||
{
|
||||
unsigned int seq = 0;
|
||||
int sd;
|
||||
|
||||
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
if (sd < 0) {
|
||||
_pe("netlink socket");
|
||||
return;
|
||||
}
|
||||
|
||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
||||
nl_route(nh, len);
|
||||
else
|
||||
nl_link(nh, len);
|
||||
if (all) {
|
||||
_d("============================ RESYNC =================================");
|
||||
/* this doesn't update condtions, and thus does not stop services */
|
||||
cond_deassert("net/");
|
||||
|
||||
nl_resync_ifaces(sd, seq++);
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
/* delayed update after we've corrected things */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
_d("=========================== RESYNCED ================================");
|
||||
} else
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
close(sd);
|
||||
}
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
{
|
||||
if (nl_parse(sd) < 0) {
|
||||
if (errno == ENOBUFS) { /* netlink(7) */
|
||||
_w("busy system, resynchronizing with kernel.");
|
||||
nl_resync(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux doesn't send route changes when interfaces go down, so
|
||||
* we need to check ourselves, e.g. for loss of default route.
|
||||
*/
|
||||
if (nl_ifdown) {
|
||||
_d("interface down, checking default route.");
|
||||
if (nl_defidx > 0) {
|
||||
nl_defidx = 0;
|
||||
nl_resync(0);
|
||||
if (nl_defidx <= 0) {
|
||||
cond_clear("net/route/default");
|
||||
nl_defidx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nl_ifdown = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,8 +415,8 @@ static plugin_t plugin = {
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
int sd;
|
||||
struct sockaddr_nl sa;
|
||||
int sd;
|
||||
|
||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sd < 0) {
|
||||
@@ -247,7 +426,7 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
|
||||
sa.nl_pid = getpid();
|
||||
|
||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
@@ -256,6 +435,13 @@ PLUGIN_INIT(plugin_init)
|
||||
return;
|
||||
}
|
||||
|
||||
nl_buf = malloc(NL_BUFSZ);
|
||||
if (!nl_buf) {
|
||||
_pe("malloc()");
|
||||
close(sd);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.io.fd = sd;
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/* 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 *cond;
|
||||
|
||||
cond = strstr(name, 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:
|
||||
*/
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* Setup random seed
|
||||
/* Setup and save random seed at boot/shutdown
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
.deps/*
|
||||
finit
|
||||
getty
|
||||
initctl
|
||||
keventd
|
||||
logit
|
||||
reboot
|
||||
sulogin
|
||||
|
||||
+19
-6
@@ -8,18 +8,31 @@ AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS = logit sulogin
|
||||
pkglibexec_PROGRAMS = getty logit sulogin
|
||||
if KEVENTD
|
||||
pkglibexec_PROGRAMS += keventd
|
||||
endif
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
getty_SOURCES = finit.h getty.c helpers.h logrotate.c stty.c utmp-api.c utmp-api.h
|
||||
getty_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
getty_CFLAGS += $(lite_CFLAGS)
|
||||
getty_LDADD = $(lite_LIBS)
|
||||
|
||||
keventd_SOURCES = keventd.c iwatch.c iwatch.h util.c util.h
|
||||
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
keventd_CFLAGS += $(lite_CFLAGS)
|
||||
keventd_LDADD = $(lite_LIBS)
|
||||
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
sulogin_LDADD = -lcrypt
|
||||
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
|
||||
logit_SOURCES = logit.c logrotate.c
|
||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
logit_CFLAGS += $(lite_CFLAGS)
|
||||
@@ -29,7 +42,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
cond.c cond-w.c cond.h \
|
||||
conf.c conf.h \
|
||||
exec.c finit.c finit.h \
|
||||
getty.c stty.c \
|
||||
stty.c \
|
||||
helpers.c helpers.h \
|
||||
iwatch.c iwatch.h \
|
||||
log.c log.h \
|
||||
|
||||
@@ -172,6 +172,9 @@ int cgroup_service(char *name, int pid, struct cgroup *cg)
|
||||
if (!strcmp(cg->name, "root"))
|
||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
|
||||
|
||||
if (!strcmp(cg->name, "init"))
|
||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/init/cgroup.procs");
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
|
||||
if (fisdir(path))
|
||||
group = cg->name;
|
||||
|
||||
+6
-2
@@ -67,6 +67,7 @@ int client_send(struct init_request *rq, ssize_t len)
|
||||
{
|
||||
struct pollfd pfd = { 0 };
|
||||
int sd, result = 255;
|
||||
int rc;
|
||||
|
||||
sd = client_connect();
|
||||
if (-1 == sd)
|
||||
@@ -86,8 +87,11 @@ int client_send(struct init_request *rq, ssize_t len)
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLIN;
|
||||
if (poll(&pfd, 1, 2000) <= 0) {
|
||||
warn("Timed out waiting for reply from Finit, errno %d", errno);
|
||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||
if (rc)
|
||||
warn("poll(), errno %d", errno);
|
||||
else
|
||||
warnx("Timed out waiting for reply from Finit.");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
+70
-18
@@ -163,7 +163,7 @@ int cond_set_path(const char *path, enum cond_state next)
|
||||
return next != prev;
|
||||
}
|
||||
|
||||
/* Should only be used by cond_set*(), cond_clear(), and usr plugin! */
|
||||
/* Should only be used by cond_set*(), cond_clear(), and usr/sys plugins! */
|
||||
void cond_update(const char *name)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
@@ -178,43 +178,73 @@ void cond_update(const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
void cond_set(const char *name)
|
||||
int cond_set_noupdate(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (string_compare(name, "nop"))
|
||||
return;
|
||||
return 1;
|
||||
|
||||
if (!cond_set_path(cond_path(name), COND_ON))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cond_set(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (cond_set_noupdate(name))
|
||||
return;
|
||||
|
||||
cond_update(name);
|
||||
}
|
||||
|
||||
void cond_set_oneshot(const char *name)
|
||||
int cond_set_oneshot_noupdate(const char *name)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
if (string_compare(name, "nop"))
|
||||
return;
|
||||
return 1;
|
||||
|
||||
path = cond_path(name);
|
||||
_d("%s => %s", name, path);
|
||||
|
||||
if (cond_checkpath(path))
|
||||
return 1;
|
||||
|
||||
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
|
||||
_pe("Failed creating onshot cond %s", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cond_set_oneshot(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (cond_set_oneshot_noupdate(name))
|
||||
return;
|
||||
|
||||
if (symlink(_PATH_RECONF, path) && errno != EEXIST)
|
||||
_pe("Failed creating onshot cond %s", name);
|
||||
cond_update(name);
|
||||
}
|
||||
|
||||
int cond_clear_noupdate(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (string_compare(name, "nop"))
|
||||
return 1;
|
||||
|
||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cond_clear(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (string_compare(name, "nop"))
|
||||
return;
|
||||
|
||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
||||
if (cond_clear_noupdate(name))
|
||||
return;
|
||||
|
||||
cond_update(name);
|
||||
@@ -227,7 +257,7 @@ void cond_reload(void)
|
||||
cond_bump_reconf();
|
||||
}
|
||||
|
||||
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||
static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw, int set)
|
||||
{
|
||||
char *nm;
|
||||
|
||||
@@ -239,25 +269,47 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
||||
|
||||
nm = strstr((char *)fpath, COND_BASE);
|
||||
if (!nm) {
|
||||
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
||||
_e("Incorrect condtion path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nm += strlen(COND_BASE);
|
||||
_d("Reasserting %s => %s", fpath, nm);
|
||||
cond_set(nm);
|
||||
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
||||
if (set)
|
||||
cond_set(nm);
|
||||
else
|
||||
cond_clear_noupdate(nm); /* important, see netlink plugin! */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||
{
|
||||
return do_assert(fpath, sb, tflg, ftw, 1);
|
||||
}
|
||||
|
||||
static int deassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||
{
|
||||
return do_assert(fpath, sb, tflg, ftw, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used only by netlink plugin atm.
|
||||
* type: is a one of pid/, net/, etc.
|
||||
*/
|
||||
void cond_reassert(const char *type)
|
||||
void cond_reassert(const char *pat)
|
||||
{
|
||||
_d("%s", type);
|
||||
nftw(cond_path(type), reassert, 20, FTW_DEPTH);
|
||||
_d("%s", pat);
|
||||
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used only by netlink plugin atm.
|
||||
*/
|
||||
void cond_deassert(const char *pat)
|
||||
{
|
||||
_d("%s", pat);
|
||||
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
||||
}
|
||||
|
||||
void cond_init(void)
|
||||
|
||||
+11
-2
@@ -5,12 +5,14 @@
|
||||
#include <svc.h>
|
||||
|
||||
#define COND_BASE "finit/cond"
|
||||
#define COND_USR "usr/"
|
||||
#define COND_PID "pid/"
|
||||
#define COND_SYS "sys/"
|
||||
#define COND_USR "usr/"
|
||||
|
||||
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||
#define _PATH_CONDPID _PATH_COND COND_PID
|
||||
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||
#define _PATH_RECONF _PATH_COND "reconf"
|
||||
|
||||
typedef enum cond_state {
|
||||
@@ -34,7 +36,14 @@ void cond_set (const char *name);
|
||||
void cond_set_oneshot (const char *name);
|
||||
void cond_clear (const char *name);
|
||||
void cond_reload (void);
|
||||
|
||||
int cond_set_noupdate (const char *name);
|
||||
int cond_set_oneshot_noupdate(const char *name);
|
||||
int cond_clear_noupdate(const char *name);
|
||||
|
||||
void cond_reassert (const char *pat);
|
||||
void cond_deassert (const char *pat);
|
||||
|
||||
void cond_init (void);
|
||||
|
||||
#endif /* FINIT_COND_H_ */
|
||||
|
||||
+29
-27
@@ -66,22 +66,6 @@ static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(c
|
||||
static int parse_conf(char *file, int is_rcsd);
|
||||
static void drop_changes(void);
|
||||
|
||||
static void hide_args(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* Hide command line arguments from ps (in particular for
|
||||
* forked children that don't execv()). This is an ugly
|
||||
* hack that only works on Linux.
|
||||
* https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/
|
||||
*/
|
||||
if (argc > 1) {
|
||||
char *arg_end;
|
||||
|
||||
arg_end = argv[argc-1] + strlen (argv[argc-1]);
|
||||
*arg_end = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
int get_bool(char *arg, int default_value)
|
||||
{
|
||||
if (!arg)
|
||||
@@ -145,24 +129,27 @@ static void parse_arg(char *arg)
|
||||
single = 1;
|
||||
}
|
||||
|
||||
void conf_parse_cmdline(int argc, char *argv[])
|
||||
#ifdef KERNEL_CMDLINE
|
||||
/*
|
||||
* Parse /proc/cmdline to find args for init. Don't use this!
|
||||
*
|
||||
* Instead, rely on the kernel to give Finit its arguments as
|
||||
* regular argc + argv[]. Only use this if the system you run
|
||||
* on has a broken initramfs system that cannot forward args
|
||||
* to Finit properly.
|
||||
*/
|
||||
static void parse_kernel_cmdline(void)
|
||||
{
|
||||
int dbg = 0;
|
||||
FILE *fp;
|
||||
char line[LINE_SIZE], *cmdline, *tok;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
parse_arg(argv[i]);
|
||||
|
||||
hide_args(argc, argv);
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/proc/cmdline", "r");
|
||||
if (!fp)
|
||||
goto done;
|
||||
return;
|
||||
|
||||
if (!fgets(line, sizeof(line), fp)) {
|
||||
fclose(fp);
|
||||
goto done;
|
||||
return;
|
||||
}
|
||||
|
||||
cmdline = chomp(line);
|
||||
@@ -173,8 +160,23 @@ void conf_parse_cmdline(int argc, char *argv[])
|
||||
parse_arg(tok);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
#else
|
||||
#define parse_kernel_cmdline()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Kernel gives us all non-kernel options on our cmdline
|
||||
*/
|
||||
void conf_parse_cmdline(int argc, char *argv[])
|
||||
{
|
||||
int dbg = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
parse_arg(argv[i]);
|
||||
|
||||
parse_kernel_cmdline();
|
||||
|
||||
done:
|
||||
log_init(dbg);
|
||||
}
|
||||
|
||||
|
||||
+37
-57
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
@@ -33,6 +34,7 @@
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
#include <lite/lite.h>
|
||||
#include <linux/vt.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
@@ -106,8 +108,6 @@ int run(char *cmd)
|
||||
if (0 == pid) {
|
||||
FILE *fp;
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
sig_unblock();
|
||||
setsid();
|
||||
|
||||
/* Always redirect stdio for run() */
|
||||
@@ -240,10 +240,8 @@ int exec_runtask(char *cmd, char *args[])
|
||||
|
||||
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct termios term;
|
||||
char name[80];
|
||||
int fd;
|
||||
int fd, dummy;
|
||||
|
||||
fd = open(tty, O_RDWR);
|
||||
if (fd < 0) {
|
||||
@@ -254,44 +252,18 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
|
||||
/*
|
||||
* Become session leader and set controlling TTY
|
||||
* to enable Ctrl-C and job control in shell.
|
||||
*/
|
||||
setsid();
|
||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
||||
logit(LOG_WARNING, "Failed TIOCSCTTY on %s: %s", tty, strerror(errno));
|
||||
/* Set default TERM, run_getty() below allows override */
|
||||
if (ioctl(fd, VT_OPENQRY, &dummy) == -1)
|
||||
setenv("TERM", "vt102", 1); /* likely a serial line */
|
||||
else
|
||||
setenv("TERM", "linux", 1);
|
||||
|
||||
/*
|
||||
* Reset to sane defaults in case of messup from prev. session
|
||||
*/
|
||||
stty(STDIN_FILENO, speed);
|
||||
|
||||
/*
|
||||
* Disable ISIG (INTR, QUIT, SUSP) before handing over to getty.
|
||||
* It is up to the getty process to allow them again.
|
||||
*/
|
||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
||||
term.c_lflag &= ~ISIG;
|
||||
term.c_cc[VEOF] = _POSIX_VDISABLE;
|
||||
term.c_cc[VINTR] = _POSIX_VDISABLE;
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
|
||||
}
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
sig_unblock();
|
||||
|
||||
/*
|
||||
* Ignore a few signals, needed to prevent Ctrl-C at login:
|
||||
* prompt and to prevent QUIT from dumping core.
|
||||
*/
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
stty(fd, speed);
|
||||
close(fd);
|
||||
|
||||
/* Set configured limits */
|
||||
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
||||
@@ -380,25 +352,7 @@ static int activate_console(int noclear, int nowait)
|
||||
* since /bin/login usually only disables ECHO until a password line has
|
||||
* been entered. Upon starting the user's $SHELL the ISIG flag is reset
|
||||
*/
|
||||
pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[])
|
||||
{
|
||||
speed_t speed;
|
||||
int rc = 1;
|
||||
|
||||
speed = stty_parse_speed(baud);
|
||||
prepare_tty(tty, speed, "tty", rlimit);
|
||||
if (activate_console(noclear, nowait)) {
|
||||
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
|
||||
rc = getty(tty, speed, term, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start external getty as defined by user in .conf file
|
||||
*/
|
||||
pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
|
||||
pid_t run_getty(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
@@ -414,6 +368,32 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sh(char *tty)
|
||||
{
|
||||
char *args[2] = {
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
char *arg0;
|
||||
size_t len;
|
||||
|
||||
/* The getty process is usually responsible for the UTMP login record */
|
||||
utmp_set_login(tty, NULL);
|
||||
|
||||
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
||||
len = strlen(_PATH_BSHELL) + 2;
|
||||
arg0 = malloc(len);
|
||||
if (!arg0)
|
||||
err(1, "Failed allocating memory");
|
||||
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
||||
args[0] = arg0;
|
||||
|
||||
/* Unblock signals inherited from parent */
|
||||
sig_unblock();
|
||||
|
||||
return execv(_PATH_BSHELL, args);
|
||||
}
|
||||
|
||||
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
+104
-3
@@ -149,6 +149,25 @@ static int fsck_all(void)
|
||||
}
|
||||
|
||||
#ifndef SYSROOT
|
||||
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
||||
static int fs_readonly_root(struct fstab *fs)
|
||||
{
|
||||
char *tok, *str;
|
||||
|
||||
if (!fs)
|
||||
return 1;
|
||||
|
||||
str = fs->fs_mntops;
|
||||
while ((tok = strtok(str, ","))) {
|
||||
if (!strcmp(tok, "ro"))
|
||||
return 1;
|
||||
|
||||
str = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fs_remount_root(int fsckerr)
|
||||
{
|
||||
struct fstab *fs;
|
||||
@@ -161,8 +180,7 @@ static void fs_remount_root(int fsckerr)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
||||
if (!fs || !strcmp(fs->fs_type, "ro"))
|
||||
if (fs_readonly_root(fs))
|
||||
goto out;
|
||||
|
||||
if (fsckerr)
|
||||
@@ -186,6 +204,69 @@ static void fs_remount_root(int fsckerr)
|
||||
}
|
||||
#endif /* SYSROOT */
|
||||
|
||||
/*
|
||||
* Opinionated file system setup. Checks for critical mount points and
|
||||
* mounts them as most users expect. All file systems are checked with
|
||||
* /proc/mounts before mounting.
|
||||
*
|
||||
* Embedded systems, and other people who want full control, can set up
|
||||
* their system with /etc/fstab, which is handled before this function
|
||||
* is called. For systems like Debian/Ubuntu, who only have / and swap
|
||||
* in their /etc/fstab, this function does all the magic necessary.
|
||||
*/
|
||||
static void fs_finalize(void)
|
||||
{
|
||||
/*
|
||||
* Some systems rely on us to both create /dev/shm and, to mount
|
||||
* a tmpfs there. Any system with dbus needs shared memory, so
|
||||
* mount it, unless its already mounted, but not if listed in
|
||||
* the /etc/fstab file already.
|
||||
*/
|
||||
if (!fismnt("/dev/shm")) {
|
||||
makedir("/dev/shm", 0777);
|
||||
mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
||||
}
|
||||
|
||||
/* Modern systems use /dev/pts */
|
||||
if (!fismnt("/dev/pts")) {
|
||||
char opts[32];
|
||||
int mode;
|
||||
int gid;
|
||||
|
||||
gid = getgroup("tty");
|
||||
if (gid == -1)
|
||||
gid = 0;
|
||||
|
||||
/* 0600 is default on Debian, use 0620 to get mesg y by default */
|
||||
mode = 0620;
|
||||
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
||||
|
||||
makedir("/dev/pts", 0755);
|
||||
mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modern systems use tmpfs for /run. Fallback to /var/run if
|
||||
* /run doesn't exist is handled by the bootmisc plugin. It
|
||||
* also sets up compat symlinks.
|
||||
*
|
||||
* The unconditional mount of /run/lock is for DoS prevention.
|
||||
* To override any of this behavior, add entries to /etc/fstab
|
||||
* for /run (and optionally /run/lock).
|
||||
*/
|
||||
if (fisdir("/run") && !fismnt("/run")) {
|
||||
mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||
|
||||
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
||||
makedir("/run/lock", 1777);
|
||||
mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
|
||||
}
|
||||
|
||||
/* Modern systems use tmpfs for /tmp */
|
||||
if (!fismnt("/tmp"))
|
||||
mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||
}
|
||||
|
||||
static void fs_mount(void)
|
||||
{
|
||||
if (!rescue)
|
||||
@@ -201,6 +282,9 @@ static void fs_mount(void)
|
||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||
|
||||
run("swapon -ea");
|
||||
|
||||
_d("Finalize, ensure common file systems are available ...");
|
||||
fs_finalize();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -229,6 +313,15 @@ static void fs_init(void)
|
||||
for (i = 0; i < NELEMS(fs); i++) {
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Check if already mounted, we may be running in a
|
||||
* container, or an initramfs ran before us. The
|
||||
* function fismnt() reliles on /proc/mounts being
|
||||
* unique for each chroot/container.
|
||||
*/
|
||||
if (fismnt(fs[i].file))
|
||||
continue;
|
||||
|
||||
rc = mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
||||
if (rc && errno != EBUSY)
|
||||
_pe("Failed mounting %s on %s", fs[i].spec, fs[i].file);
|
||||
@@ -459,6 +552,8 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
setenv("SHELL", _PATH_BSHELL, 1);
|
||||
setenv("LOGNAME", "root", 1);
|
||||
setenv("USER", "root", 1);
|
||||
|
||||
if (chdir("/"))
|
||||
_pe("Failed cd /");
|
||||
@@ -524,10 +619,16 @@ int main(int argc, char *argv[])
|
||||
* Start built-in watchdogd as soon as possible, if enabled
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
/*
|
||||
* Start kernel event daemon as soon as possible, if enabled
|
||||
*/
|
||||
if (whichp(FINIT_LIBPATH_ "/keventd"))
|
||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init " FINIT_LIBPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
||||
|
||||
/* Base FS up, enable standard SysV init signals */
|
||||
sig_setup(&loop);
|
||||
|
||||
|
||||
@@ -50,8 +50,10 @@
|
||||
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||
#endif
|
||||
|
||||
/* To use these, include config.h, or define FINIT_LIBPATH_ */
|
||||
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
|
||||
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
|
||||
#define _PATH_GETTY FINIT_LIBPATH_ "/getty"
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define LINE_SIZE 1024
|
||||
|
||||
+58
-65
@@ -21,20 +21,21 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
#include "helpers.h"
|
||||
#include "sig.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
#ifndef _PATH_LOGIN
|
||||
@@ -44,19 +45,14 @@
|
||||
/*
|
||||
* Read one character from stdin.
|
||||
*/
|
||||
static int readch(char *tty)
|
||||
static int readch(void)
|
||||
{
|
||||
int st;
|
||||
char ch1;
|
||||
int st;
|
||||
|
||||
st = read(STDIN_FILENO, &ch1, 1);
|
||||
if (st == 0) {
|
||||
dprint(STDOUT_FILENO, "\n", 0);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (st < 0)
|
||||
errx(1, "getty: %s: read error", tty);
|
||||
if (st <= 0)
|
||||
return -1;
|
||||
|
||||
return ch1 & 0xFF;
|
||||
}
|
||||
@@ -141,10 +137,10 @@ static void do_issue(char *tty)
|
||||
/*
|
||||
* Handle the process of a GETTY.
|
||||
*/
|
||||
static void do_getty(char *tty, char *name, size_t len)
|
||||
static int get_logname(char *tty, char *name, size_t len)
|
||||
{
|
||||
int ch;
|
||||
char *np;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* Display prompt.
|
||||
@@ -155,14 +151,9 @@ static void do_getty(char *tty, char *name, size_t len)
|
||||
do_issue(tty);
|
||||
|
||||
np = name;
|
||||
while ((ch = readch(tty)) != '\n') {
|
||||
if (ch == CTRL('U')) {
|
||||
while (np > name) {
|
||||
dprint(STDOUT_FILENO, "\b \b", 3);
|
||||
np--;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
while ((ch = readch()) != '\n') {
|
||||
if (ch < 0)
|
||||
return 1;
|
||||
|
||||
if (np < name + len)
|
||||
*np++ = ch;
|
||||
@@ -174,6 +165,7 @@ static void do_getty(char *tty, char *name, size_t len)
|
||||
}
|
||||
|
||||
name[len - 1] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -185,26 +177,27 @@ static int do_login(char *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
cgroup_user(name, 0);
|
||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||
|
||||
/*
|
||||
* Failed to exec login, should not happen on normal systems.
|
||||
* Try a starting a rescue shell instead.
|
||||
*
|
||||
* Note: Add /etc/securetty handling.
|
||||
*/
|
||||
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_BSHELL);
|
||||
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode))
|
||||
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode)) {
|
||||
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_SULOGIN);
|
||||
execl(_PATH_SULOGIN, _PATH_SULOGIN, NULL);
|
||||
|
||||
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_SULOGIN, _PATH_BSHELL);
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
||||
}
|
||||
|
||||
return 1; /* We shouldn't get here ... */
|
||||
}
|
||||
|
||||
int getty(char *tty, speed_t speed, char *term, char *user)
|
||||
static int getty(char *tty, speed_t speed, char *term, char *user)
|
||||
{
|
||||
const char cln[] = "\r\e[2K\n";
|
||||
char name[30];
|
||||
char name[33]; /* useradd(1) limit at 32 chars */
|
||||
|
||||
/*
|
||||
* Clean up tty name.
|
||||
@@ -212,15 +205,20 @@ int getty(char *tty, speed_t speed, char *term, char *user)
|
||||
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
|
||||
tty += 5;
|
||||
|
||||
/* Set up TTY, re-enabling ISIG et al. */
|
||||
stty(STDIN_FILENO, speed);
|
||||
dprint(STDERR_FILENO, cln, strlen(cln));
|
||||
|
||||
/* The getty process is responsible for the UTMP login record */
|
||||
utmp_set_login(tty, NULL);
|
||||
if (!user)
|
||||
do_getty(tty, name, sizeof(name));
|
||||
else
|
||||
|
||||
/* Replace "Please press enter ..." with login: */
|
||||
dprint(STDERR_FILENO, cln, strlen(cln));
|
||||
|
||||
restart:
|
||||
stty(STDIN_FILENO, speed);
|
||||
if (!user) {
|
||||
if (get_logname(tty, name, sizeof(name))) {
|
||||
sleep(5);
|
||||
goto restart;
|
||||
}
|
||||
} else
|
||||
strlcpy(name, user, sizeof(name));
|
||||
|
||||
if (term && term[0])
|
||||
@@ -229,42 +227,37 @@ int getty(char *tty, speed_t speed, char *term, char *user)
|
||||
return do_login(name);
|
||||
}
|
||||
|
||||
int sh(char *tty)
|
||||
static int usage(int rc)
|
||||
{
|
||||
struct termios term;
|
||||
char *args[2] = {
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
char *arg0;
|
||||
size_t len;
|
||||
warnx("usage: getty [-h?] tty [speed [term]]");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* The getty process is usually responsible for the UTMP login record */
|
||||
utmp_set_login(tty, NULL);
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *tty, *speed = "0", *term = NULL;
|
||||
int c;
|
||||
|
||||
/* Set up TTY, re-enabling ISIG et al. */
|
||||
stty(STDIN_FILENO, B0);
|
||||
|
||||
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
||||
len = strlen(_PATH_BSHELL) + 2;
|
||||
arg0 = malloc(len);
|
||||
if (!arg0)
|
||||
err(1, "Failed allocating memory");
|
||||
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
||||
args[0] = arg0;
|
||||
|
||||
/* Reenable Ctrl-D and Ctrl-C, and ... */
|
||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
||||
term.c_lflag |= ISIG;
|
||||
term.c_cc[VEOF] = CEOF;
|
||||
term.c_cc[VINTR] = CINTR;
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
|
||||
while ((c = getopt(argc, argv, "h?")) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
default:
|
||||
return usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ... unblock signals in general */
|
||||
sig_unblock();
|
||||
if (optind >= argc)
|
||||
return usage(1);
|
||||
|
||||
return execv(_PATH_BSHELL, args);
|
||||
tty = argv[optind++];
|
||||
if (optind < argc)
|
||||
speed = argv[optind++];
|
||||
if (optind < argc)
|
||||
term = argv[optind++];
|
||||
|
||||
return getty(tty, atoi(speed), term, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-83
@@ -68,92 +68,13 @@ static const char *status2[] = STATUS_CLASS;
|
||||
#define CHOOSE(x,y,z) z
|
||||
static const char *color[] = STATUS_CLASS;
|
||||
|
||||
/*
|
||||
* System consoles, can be given multiple times on the kernel cmdline.
|
||||
* We support only three currently. If none are given on the cmdline
|
||||
* we probe /sys/class/tty/console/active and use the first (default).
|
||||
*/
|
||||
#define MAX_CONS 3
|
||||
|
||||
static char *consoles[MAX_CONS];
|
||||
static int fds[MAX_CONS];
|
||||
static int num_cons = 0;
|
||||
|
||||
/*
|
||||
* System default console is always the first
|
||||
*/
|
||||
char *console(void)
|
||||
{
|
||||
return consoles[0];
|
||||
}
|
||||
|
||||
static void add_console(char *cons)
|
||||
{
|
||||
char path[80];
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
if (num_cons == NELEMS(fds)) {
|
||||
_e("too many consoles, max %d supported", NELEMS(fds));
|
||||
return;
|
||||
}
|
||||
|
||||
/* drop any options */
|
||||
ptr = strchr(cons, ',');
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
|
||||
if (!strncmp(cons, "/dev/", 5))
|
||||
cons += 5;
|
||||
|
||||
snprintf(path, sizeof(path), "/dev/%s", cons);
|
||||
|
||||
/* check for and skip duplicates */
|
||||
for (i = 0; i < num_cons; i++) {
|
||||
if (string_compare(path, consoles[i]))
|
||||
return;
|
||||
}
|
||||
|
||||
/* this requires we have /dev mounted && a device there */
|
||||
fds[num_cons] = open(path, O_WRONLY);
|
||||
if (fds[num_cons] < 0) {
|
||||
_pe("Failed opening console %s", path);
|
||||
return;
|
||||
}
|
||||
consoles[num_cons] = strdup(path);
|
||||
num_cons++;
|
||||
}
|
||||
|
||||
static void find_active_consoles(void)
|
||||
{
|
||||
char *cons, *ptr, *tok;
|
||||
char buf[512];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/sys/class/tty/console/active", "r");
|
||||
if (!fp) {
|
||||
fallback:
|
||||
_d("Using fallback /dev/console");
|
||||
add_console("console");
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = fgets(buf, sizeof(buf), fp);
|
||||
fclose(fp);
|
||||
if (!ptr)
|
||||
goto fallback;
|
||||
|
||||
cons = chomp(ptr);
|
||||
_d("Using these system consoles: %s", cons);
|
||||
while ((tok = strtok(cons, " \t"))) {
|
||||
cons = NULL;
|
||||
add_console(tok);
|
||||
}
|
||||
return _PATH_CONSOLE;
|
||||
}
|
||||
|
||||
void console_init(void)
|
||||
{
|
||||
find_active_consoles();
|
||||
ttinit();
|
||||
}
|
||||
|
||||
@@ -163,14 +84,12 @@ ssize_t cprintf(const char *fmt, ...)
|
||||
char buf[len < 256 ? 256 : len];
|
||||
size_t size;
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
va_start(ap, fmt);
|
||||
size = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
for (i = 0; i < num_cons; i++)
|
||||
dprint(fds[i], buf, size);
|
||||
dprint(STDERR_FILENO, buf, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
+2
-6
@@ -68,11 +68,8 @@ char *strip_line (char *line);
|
||||
void enable_progress (int onoff);
|
||||
void show_progress (pstyle_t style);
|
||||
|
||||
int getty (char *tty, speed_t speed, char *term, char *user);
|
||||
int sh (char *tty);
|
||||
|
||||
void stty (int fd, speed_t speed);
|
||||
speed_t stty_parse_speed(char *baud);
|
||||
void stty (int fd, speed_t speed);
|
||||
|
||||
void print_banner (const char *heading);
|
||||
void printv (const char *fmt, va_list ap);
|
||||
@@ -95,8 +92,7 @@ int complete (char *cmd, int pid);
|
||||
int run (char *cmd);
|
||||
int run_interactive (char *cmd, char *fmt, ...);
|
||||
int exec_runtask (char *cmd, char *args[]);
|
||||
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
|
||||
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||
int run_parts (char *dir, char *cmd);
|
||||
|
||||
|
||||
+2
-1
@@ -41,6 +41,7 @@
|
||||
#include "service.h"
|
||||
#include "cgutil.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
struct cmd {
|
||||
char *cmd;
|
||||
@@ -345,7 +346,7 @@ static int do_cond_act(char *arg, int creat)
|
||||
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
||||
err(1, "Failed asserting condition <%s>", &oneshot[off]);
|
||||
} else {
|
||||
if (erase(oneshot))
|
||||
if (erase(oneshot) && errno != ENOENT)
|
||||
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
|
||||
}
|
||||
|
||||
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
/* 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 <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.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 fgetline(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 (!fgetline(path, buf, sizeof(buf)) && is_ac(buf)) {
|
||||
num_ac++;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s/online", _PATH_SYSFS_PWR, nm);
|
||||
if (!fgetline(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");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
buf[len] = 0;
|
||||
|
||||
/* 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:
|
||||
*/
|
||||
@@ -104,7 +104,7 @@ void logit(int prio, const char *fmt, ...)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (prio > loglevel)
|
||||
if (LOG_PRI(prio) > loglevel)
|
||||
goto done;
|
||||
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
|
||||
+14
-5
@@ -98,29 +98,38 @@ static int logit(int level, char *buf, size_t len)
|
||||
|
||||
static int parse_prio(char *arg, int *f, int *l)
|
||||
{
|
||||
char *ptr;
|
||||
char *duparg = strdup(arg);
|
||||
char *ptr, *prio;
|
||||
|
||||
ptr = strchr(arg, '.');
|
||||
if (!duparg)
|
||||
prio = arg;
|
||||
else
|
||||
prio = duparg;
|
||||
|
||||
ptr = strchr(prio, '.');
|
||||
if (ptr) {
|
||||
*ptr++ = 0;
|
||||
|
||||
for (int i = 0; facilitynames[i].c_name; i++) {
|
||||
if (!strcmp(facilitynames[i].c_name, arg)) {
|
||||
if (!strcmp(facilitynames[i].c_name, prio)) {
|
||||
*f = facilitynames[i].c_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
arg = ptr;
|
||||
prio = ptr;
|
||||
}
|
||||
|
||||
for (int i = 0; prioritynames[i].c_name; i++) {
|
||||
if (!strcmp(prioritynames[i].c_name, arg)) {
|
||||
if (!strcmp(prioritynames[i].c_name, prio)) {
|
||||
*l = prioritynames[i].c_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (duparg != arg)
|
||||
free(duparg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ int reboot_main(int argc, char *argv[])
|
||||
|
||||
case CMD_HALT:
|
||||
if (do_halt(NULL))
|
||||
do_kill(SIGUSR1, msg);
|
||||
do_kill(SIGUSR2, msg);
|
||||
break;
|
||||
|
||||
case CMD_POWEROFF:
|
||||
|
||||
+36
-15
@@ -138,7 +138,7 @@ static int fredirect(const char *file)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(file, O_WRONLY | O_APPEND);
|
||||
fd = open(file, O_WRONLY | O_APPEND | O_NOCTTY);
|
||||
if (-1 != fd) {
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
@@ -564,10 +564,6 @@ static int service_start(svc_t *svc)
|
||||
}
|
||||
args[i] = NULL;
|
||||
|
||||
if (!svc_is_tty(svc))
|
||||
redirect(svc);
|
||||
sig_unblock();
|
||||
|
||||
/*
|
||||
* The setsid() call takes care to detach the process
|
||||
* from its controlling terminal, preventing daemons
|
||||
@@ -579,7 +575,13 @@ static int service_start(svc_t *svc)
|
||||
* to the console at boot, for debugging or similar,
|
||||
* have a look at redirect() and log.console instead.
|
||||
*/
|
||||
setsid();
|
||||
pid = setsid();
|
||||
if (pid < 1)
|
||||
logit(LOG_ERR, "failed setsid(), pid %d: %s", pid, strerror(errno));
|
||||
|
||||
if (!svc_is_tty(svc))
|
||||
redirect(svc);
|
||||
sig_unblock();
|
||||
|
||||
if (svc_is_runtask(svc))
|
||||
status = exec_runtask(args[0], &args[1]);
|
||||
@@ -700,6 +702,7 @@ static void service_cleanup(svc_t *svc)
|
||||
*/
|
||||
static int service_stop(svc_t *svc)
|
||||
{
|
||||
int do_progress = 1;
|
||||
int rc = 0;
|
||||
|
||||
if (!svc)
|
||||
@@ -724,7 +727,10 @@ static int service_stop(svc_t *svc)
|
||||
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
|
||||
if (runlevel != 1)
|
||||
if (!svc->desc[0])
|
||||
do_progress = 0;
|
||||
|
||||
if (runlevel != 1 && do_progress)
|
||||
print_desc("Stopping ", svc->desc);
|
||||
|
||||
if (!svc_is_sysv(svc)) {
|
||||
@@ -744,6 +750,7 @@ static int service_stop(svc_t *svc)
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case 0:
|
||||
setsid();
|
||||
redirect(svc);
|
||||
exec_runtask(svc->cmd, args);
|
||||
_exit(0);
|
||||
@@ -1120,6 +1127,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
char *pre_script = NULL, *post_script = NULL;
|
||||
struct tty tty = { 0 };
|
||||
char *dev = NULL;
|
||||
int respawn = 0;
|
||||
int levels = 0;
|
||||
int manual = 0;
|
||||
char *line;
|
||||
@@ -1179,6 +1187,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
name = cmd;
|
||||
else if (!strncasecmp(cmd, "manual:yes", 10))
|
||||
manual = 1;
|
||||
else if (!strncasecmp(cmd, "respawn", 7))
|
||||
respawn = 1;
|
||||
else if (!strncasecmp(cmd, "halt:", 5))
|
||||
halt = &cmd[5];
|
||||
else if (!strncasecmp(cmd, "kill:", 5))
|
||||
@@ -1221,7 +1231,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
len += strlen(tty.cmd);
|
||||
else
|
||||
len += 3;
|
||||
|
||||
len += tty.num + 1;
|
||||
for (i = 0; i < tty.num; i++)
|
||||
len += strlen(tty.args[i]) + 1;
|
||||
@@ -1230,7 +1239,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
if (!line)
|
||||
return errno;
|
||||
|
||||
snprintf(line, len, "%s", tty.cmd ?: "tty");
|
||||
snprintf(line, len, "%s", tty.cmd ? tty.cmd : "tty");
|
||||
for (i = 0; i < tty.num; i++) {
|
||||
strlcat(line, " ", len);
|
||||
strlcat(line, tty.args[i], len);
|
||||
@@ -1244,6 +1253,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
dev = tty_atcon();
|
||||
else
|
||||
dev = tty.dev;
|
||||
|
||||
/* tty's always respawn, never incr. restart_cnt */
|
||||
respawn = 1;
|
||||
next:
|
||||
svc = svc_find_by_tty(dev);
|
||||
} else
|
||||
@@ -1260,6 +1272,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
if (type == SVC_TYPE_SERVICE && manual)
|
||||
svc_stop(svc);
|
||||
} else {
|
||||
/* update type, may have changed from service -> task */
|
||||
svc->type = type;
|
||||
|
||||
/* e.g., if missing cmd or env before */
|
||||
svc_unblock(svc);
|
||||
}
|
||||
@@ -1308,12 +1323,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
|
||||
/* Create name:id tuple for identiy, e.g., tty:S0 */
|
||||
ptr = strrchr(svc->dev, '/');
|
||||
if (ptr) {
|
||||
if (ptr)
|
||||
ptr++;
|
||||
if (!strncmp(ptr, "tty", 3))
|
||||
ptr += 3;
|
||||
} else
|
||||
else
|
||||
ptr = svc->dev;
|
||||
if (!strncmp(ptr, "tty", 3))
|
||||
ptr += 3;
|
||||
if (!id || id[0] == 0)
|
||||
id = ptr;
|
||||
strlcpy(svc->name, "tty", sizeof(svc->name));
|
||||
@@ -1347,6 +1362,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
parse_env(svc, env);
|
||||
if (file)
|
||||
strlcpy(svc->file, file, sizeof(svc->file));
|
||||
if (respawn)
|
||||
svc->respawn = 1;
|
||||
|
||||
/* Set configured limits */
|
||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||
@@ -1567,11 +1584,15 @@ static void service_retry(svc_t *svc)
|
||||
char *restart_cnt = (char *)&svc->restart_cnt;
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
if (svc->respawn) {
|
||||
_d("%s crashed, respawning ...", svc->cmd);
|
||||
svc_unblock(svc);
|
||||
service_step(svc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (svc->state != SVC_HALTED_STATE ||
|
||||
svc->block != SVC_BLOCK_RESTARTING) {
|
||||
if (!svc_is_tty(svc))
|
||||
_d("%s not crashing anymore", svc->cmd);
|
||||
*restart_cnt = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -31,28 +31,31 @@
|
||||
* does on USR1 with their FIFO/D-Bus.
|
||||
*
|
||||
* SIGUSR1
|
||||
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
* processes, and unmounts all file systems. Then tells kernel to
|
||||
* halt. Most people these days want SIGUSR2 though.
|
||||
* Restarts API (initctl) socket, like SysV init and systemd does
|
||||
* on USR1 with their FIFO/D-Bus.
|
||||
*
|
||||
* (SysV init and systemd use this to re-open their FIFO/D-Bus.)
|
||||
* Finit <= 4.0 used to perform a system halt on USR1. This caused
|
||||
* some quite nasty problems on systems with both systemd/sysvinit
|
||||
* installed alongside finit. For compatibility reasons Finit 4.1
|
||||
* changed to partial SIGHUP (api_exit/init).
|
||||
*
|
||||
* SIGUSR2
|
||||
* Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
||||
* or similar exists to actually do this. If the kernel fails
|
||||
* power-off, Finit falls back to halt.
|
||||
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
* processes, and unmounts all file systems. Then tells kernel to
|
||||
* power-off the system, if ACPI or similar exists to actually do
|
||||
* this. If the kernel fails power-off, Finit falls back to halt.
|
||||
*
|
||||
* (SysV init N/A, systemd dumps its internal state to log.)
|
||||
*
|
||||
* SIGTERM
|
||||
* Like SIGUSR1, but tell kernel to reboot the system when done.
|
||||
* Like SIGUSR2, but tell kernel to reboot the system when done.
|
||||
*
|
||||
* (SysV init N/A, systemd rexecutes itself.)
|
||||
*
|
||||
* SIGINT
|
||||
* Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
|
||||
* SysV init and systemd default to reboot with `shutdown -r`.
|
||||
* Finit currently forwards this to SIGTERM.
|
||||
* Finit defaults to nothing but sets sys/key/ctrlaltdel condition.
|
||||
*
|
||||
* SIGWINCH
|
||||
* Sent from kernel when the KeyboardSignal key is pressed. Some
|
||||
@@ -63,7 +66,7 @@
|
||||
* Sent from a power daemon, like powstatd(8), on changes to the
|
||||
* UPS status. Traditionally SysV init read /etc/powerstatus and
|
||||
* acted on "OK", "FAIL", or "LOW" and then removed the file.
|
||||
* Finit currently forwards this to SIGUSR2.
|
||||
* Finit defaults to nothing but sets sys/pwr/fail condition.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
@@ -73,6 +76,7 @@
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "conf.h"
|
||||
#include "config.h"
|
||||
#include "helpers.h"
|
||||
@@ -308,7 +312,9 @@ static void sighup_cb(uev_t *w, void *arg, int events)
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGINT: Should generate <sys/key/ctrlaltdel> condition, for now reboot
|
||||
* SIGINT: generates <sys/key/ctrlaltdel> condition, which the sys.so
|
||||
* plugin picks up and tells Finit to start any service(s) or
|
||||
* task(s) associated with the condition.
|
||||
*/
|
||||
static void sigint_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
@@ -318,12 +324,27 @@ static void sigint_cb(uev_t *w, void *arg, int events)
|
||||
return;
|
||||
}
|
||||
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(6);
|
||||
cond_set_oneshot_noupdate("sys/key/ctrlaltdel");
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGUSR1: BusyBox style halt
|
||||
* SIGPWR: generates <sys/pwr/fail> condition, which the sys.so plugin
|
||||
* picks up and tells Finit to start any service(s) or task(s)
|
||||
* associated with the condition.
|
||||
*/
|
||||
static void sigpwr_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
_d("...");
|
||||
if (UEV_ERROR == events) {
|
||||
_e("Unrecoverable error in signal watcher");
|
||||
return;
|
||||
}
|
||||
|
||||
cond_set_oneshot_noupdate("sys/pwr/fail");
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGUSR1: SysV init/systemd API socket restart
|
||||
*/
|
||||
static void sigusr1_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
@@ -333,8 +354,9 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
|
||||
return;
|
||||
}
|
||||
|
||||
halt = SHUT_HALT;
|
||||
service_runlevel(0);
|
||||
/* Restart initctl API domain socket, similar to systemd/SysV init */
|
||||
api_exit();
|
||||
api_init(w->ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -517,13 +539,17 @@ void sig_setup(uev_ctx_t *ctx)
|
||||
erase(SYNC_SHUTDOWN);
|
||||
erase(SYNC_STOPPED);
|
||||
|
||||
/* Standard SysV init calls ctrl-alt-delete handler */
|
||||
/*
|
||||
* Standard SysV init calls ctrl-alt-delete handler
|
||||
* We need to disable kernel default so it sends us SIGINT
|
||||
*/
|
||||
reboot(RB_DISABLE_CAD);
|
||||
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
|
||||
|
||||
/* BusyBox init style signals for halt, power-off and reboot. */
|
||||
/* BusyBox/SysV init style signals for halt, power-off and reboot. */
|
||||
uev_signal_init(ctx, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
|
||||
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
|
||||
uev_signal_init(ctx, &sigpwr_watcher, sigusr2_cb, NULL, SIGPWR);
|
||||
uev_signal_init(ctx, &sigpwr_watcher, sigpwr_cb, NULL, SIGPWR);
|
||||
uev_signal_init(ctx, &sigterm_watcher, sigterm_cb, NULL, SIGTERM);
|
||||
|
||||
/* Some C APIs may need SIGALRM for implementing timers. */
|
||||
|
||||
+7
-5
@@ -27,7 +27,8 @@
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
|
||||
#include <helpers.h>
|
||||
#include "helpers.h"
|
||||
#include "sig.h"
|
||||
|
||||
/* B0 means; keep kernel default */
|
||||
speed_t stty_parse_speed(char *baud)
|
||||
@@ -90,6 +91,10 @@ speed_t stty_parse_speed(char *baud)
|
||||
void stty(int fd, speed_t speed)
|
||||
{
|
||||
struct termios term;
|
||||
struct sigaction sa;
|
||||
|
||||
/* Ignore SIGINT during login phase, /bin/login resets */
|
||||
IGNSIG(sa, SIGINT, SA_RESTART);
|
||||
|
||||
tcdrain(fd);
|
||||
if (tcgetattr(fd, &term))
|
||||
@@ -98,22 +103,19 @@ void stty(int fd, speed_t speed)
|
||||
if (speed != B0) {
|
||||
cfsetispeed(&term, speed);
|
||||
cfsetospeed(&term, speed);
|
||||
tcsetattr(fd, TCSAFLUSH, &term);
|
||||
}
|
||||
|
||||
/* Modem specific control flags */
|
||||
term.c_cflag &= ~(PARENB|PARODD|CSTOPB|CRTSCTS);
|
||||
term.c_cflag |= CS8|HUPCL|CREAD|CLOCAL;
|
||||
term.c_line = 0;
|
||||
tcsetattr(fd, TCSAFLUSH, &term);
|
||||
|
||||
/* Timeouts, minimum chars and default flags */
|
||||
term.c_cc[VTIME] = 0;
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_iflag = ICRNL|IXON|IXOFF;
|
||||
term.c_iflag = ICRNL|IXON|IXOFF|IUTF8;
|
||||
term.c_oflag = OPOST|ONLCR;
|
||||
term.c_lflag |= ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHOKE;
|
||||
tcsetattr(fd, TCSAFLUSH, &term);
|
||||
|
||||
/* Reset special characters to defaults */
|
||||
term.c_cc[VINTR] = CINTR;
|
||||
|
||||
@@ -127,6 +127,7 @@ typedef struct svc {
|
||||
|
||||
/* Counters */
|
||||
char once; /* run/task, (at least) once per runlevel */
|
||||
char respawn; /* ttys, or services with `respawn`, never increment restart_cnt */
|
||||
const char restart_cnt; /* Incremented for each restart by service monitor. */
|
||||
|
||||
union {
|
||||
|
||||
@@ -161,7 +161,7 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
||||
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 (whichp(cmd)) /* in $PATH? */
|
||||
tty->cmd = cmd;
|
||||
else
|
||||
tty->args[tty->num++] = cmd;
|
||||
@@ -221,6 +221,10 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
||||
_d("Registering %s getty on TTY %s at %s baud with term %s", tty->cmd ? "external" : "built-in",
|
||||
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
|
||||
|
||||
/* Built-in getty now comes as standalone program */
|
||||
if (!tty->cmd)
|
||||
tty->cmd = _PATH_GETTY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -229,7 +233,7 @@ int tty_exists(char *dev)
|
||||
struct termios c;
|
||||
int fd, rc;
|
||||
|
||||
fd = open(dev, O_RDWR);
|
||||
fd = open(dev, O_RDWR | O_NOCTTY);
|
||||
if (-1 == fd)
|
||||
return 0;
|
||||
|
||||
@@ -285,10 +289,7 @@ int tty_exec(svc_t *svc)
|
||||
return run_sh(dev, svc->noclear, svc->nowait, svc->rlimit);
|
||||
}
|
||||
|
||||
_d("%s: Starting %sgetty ...", dev, !svc->cmd ? "built-in " : "");
|
||||
if (!strcmp(svc->cmd, "tty"))
|
||||
return run_getty(dev, svc->baud, svc->term, svc->noclear, svc->nowait, svc->rlimit);
|
||||
|
||||
_d("%s: Starting %s ...", dev, svc->cmd);
|
||||
for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
||||
if (!svc->args[i][0])
|
||||
break;
|
||||
@@ -297,7 +298,7 @@ int tty_exec(svc_t *svc)
|
||||
}
|
||||
args[j++] = NULL;
|
||||
|
||||
return run_getty2(dev, svc->cmd, args, svc->noclear, svc->nowait, svc->rlimit);
|
||||
return run_getty(dev, svc->cmd, args, svc->noclear, svc->nowait, svc->rlimit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+41
-7
@@ -154,6 +154,35 @@ char *str(char *fmt, ...)
|
||||
return buf;
|
||||
}
|
||||
|
||||
int fnread(char *buf, size_t len, char *fmt, ...)
|
||||
{
|
||||
char path[256];
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(path, sizeof(path), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!buf || !len) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st))
|
||||
return -1;
|
||||
|
||||
return (ssize_t)st.st_size;
|
||||
}
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
len = fread(buf, sizeof(char), len, fp);
|
||||
fclose(fp);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int fnwrite(char *value, char *fmt, ...)
|
||||
{
|
||||
char path[256];
|
||||
@@ -185,14 +214,19 @@ int fnwrite(char *value, char *fmt, ...)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Also, there's no __MUSL__, so we cannot make a libc-specific #ifdef
|
||||
*/
|
||||
int has_utmp(void)
|
||||
int fngetint(char *path, int *val)
|
||||
{
|
||||
return strncmp(_PATH_UTMP, "/dev/null", 9);
|
||||
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;
|
||||
}
|
||||
|
||||
int strtobytes(char *arg)
|
||||
|
||||
+2
-1
@@ -50,9 +50,10 @@ extern char *prognm;
|
||||
char *progname (char *arg0);
|
||||
|
||||
char *str (char *fmt, ...);
|
||||
int fnread (char *buf, size_t len, char *fmt, ...);
|
||||
int fnwrite (char *value, char *fmt, ...);
|
||||
int fngetint (char *path, int *val);
|
||||
|
||||
int has_utmp (void);
|
||||
int strtobytes (char *arg);
|
||||
char *sig2str (int sig);
|
||||
char *code2str (int code);
|
||||
|
||||
@@ -42,6 +42,16 @@ int utmp_show (char *file);
|
||||
|
||||
void runlevel_set (int pre, int now);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Also, there's no __MUSL__, so we cannot make a libc-specific #ifdef
|
||||
*/
|
||||
static inline int has_utmp(void)
|
||||
{
|
||||
return strncmp(_PATH_UTMP, "/dev/null", 9);
|
||||
}
|
||||
|
||||
#endif /* FINIT_UTMP_API_H_ */
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user