mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f3f140a09 | ||
|
|
10c24b1674 | ||
|
|
2b4f89ecd1 | ||
|
|
c42a6f2869 | ||
|
|
89bb609a7e | ||
|
|
da6298aecd | ||
|
|
576318cc29 | ||
|
|
0d7d331ad4 | ||
|
|
c886ecb5cc | ||
|
|
304a096877 | ||
|
|
064c7682fc | ||
|
|
58239b897b | ||
|
|
5281d82e80 | ||
|
|
5ff28c4dc6 | ||
|
|
f2218836af | ||
|
|
fbb3779d17 | ||
|
|
68f44f7a97 | ||
|
|
50e587f447 | ||
|
|
fb4c560196 | ||
|
|
8b5fa5eeaa | ||
|
|
88ec21e9cc | ||
|
|
84adec4006 | ||
|
|
19b2b2a279 | ||
|
|
e4163b7221 | ||
|
|
eaef302420 | ||
|
|
d5738da307 | ||
|
|
c9f930c7ad | ||
|
|
e2ee372b5d | ||
|
|
7ff7f93364 | ||
|
|
d5a95760ef | ||
|
|
24d1425b74 | ||
|
|
43d9e25ba7 | ||
|
|
f27998ae4f | ||
|
|
c8e0b6b9ef | ||
|
|
f7e8fccb2f | ||
|
|
7bbccb1213 |
+37
-2
@@ -4,7 +4,7 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.5][] - 2023-10-04
|
||||
[4.5][] - 2023-10-30
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
@@ -22,7 +22,7 @@ All relevant changes are documented in this file.
|
||||
- Improved logging on failure to `execvp()` a run/task/service, now
|
||||
with `errno`, e.g., "No such file or directory" when the command
|
||||
is missing from `$PATH`
|
||||
- Add support for Bash completion to `initctl`, issue #360
|
||||
- Add Bash completion support for `initctl`, configurable, issue #360
|
||||
- Handle absolute path to `initctl [enable|disable]`, not supported
|
||||
- Update `finit.conf(5)` man page with the recommended directory
|
||||
hierarchy in `/etc/finit.d/`
|
||||
@@ -43,6 +43,18 @@ All relevant changes are documented in this file.
|
||||
- Plugins and bundled services: dbus, keventd, watchdogd, and runparts,
|
||||
are now loaded *after* all services in `/lib/finit/system/`. A new
|
||||
runtime-only path (for inspection) in `/run/finit/system/` is used
|
||||
- Redirect `log*` output to console when `finit.debug` is enabled
|
||||
- Assert `<int/container>` condition if we detect running in container
|
||||
- Add support for mdev's netlink daemon mode, issue #367
|
||||
- Add support for mdevd in `10-hotplug.conf`, preferred over plain mdev
|
||||
- Disable modprobe plugin by default, udevd and mdev/mdevd loads modules
|
||||
- Update documentation for run/task shell limitations, issue #376
|
||||
- Update documentation regarding automount of `/run` and `/tmp`
|
||||
- Update plugin documentation, add section about limited tmpfiles.d(5) support
|
||||
- Skip registering service when `if:!name` matches a known service.
|
||||
This allows conditional loading of alternative services, e.g. if udevd
|
||||
is already loaded we do not need mdevd
|
||||
- Drop `doc/bootstrap.md`, inaccurate and confusing to users
|
||||
|
||||
### Fixes
|
||||
- Fix #227: believed to have been fixed in v4.3, the root cause was
|
||||
@@ -64,12 +76,35 @@ All relevant changes are documented in this file.
|
||||
at bootstrap is now saved in `/run/finit/conf.order` for inspection,
|
||||
`/run/finit/exec.order` shows the start order of each process
|
||||
- Fix #372: lost `udevadm` calls due to overloading
|
||||
- Adjust final `udevadm settle` timeout: 5 -> 30 sec
|
||||
- Fixed dbus plugin, the function that located `<pidfile> ...` in the
|
||||
`dbus/system.conf` caused spurious line breaks which led to the
|
||||
service not being loaded properly
|
||||
- The `runparts` executor now skips backup files (`foo~`)
|
||||
- The `runparts` stanza now properly appends ` start` to scripts that
|
||||
start with `S[0-9]+`. This has been broken for a very long time.
|
||||
- Fix #377: expand service `env:file` variables, allow constructs like:
|
||||
|
||||
RUNDIR=/var/run/somesvc
|
||||
DAEMON_ARGS=--workdir $RUNDIR --other-args...
|
||||
- Fix #378: warn on console if run/task times out during bootstrap
|
||||
- Fix #378: add run/task support for `<!>` to allow transition from
|
||||
bootstrap to multi-user runlevel even though task has not run yet.
|
||||
- Fix #382: do not clear `<service/foo/STATE>` conditions on reload.
|
||||
Introduced back in v4.3-rc2, 82cc10be8, the support for automatic
|
||||
service conditions have had a weird and unintended behavior. Any
|
||||
change in state (see `doc/svc-machine.png`) caused Finit to clear
|
||||
out *all* previously acquired service conditions.
|
||||
|
||||
However, when moving between RUNNING and PAUSED states, a service
|
||||
should not have its conditions cleared. The PAUSED state, seen
|
||||
also by all conditions moving to FLUX, is only temporary while an
|
||||
`initctl reload` is processed. If a service has no changes to be
|
||||
applied it will move back to RUNNING.
|
||||
|
||||
Also, we cannot clear the service conditions because other run/task
|
||||
or services may depend on it and clearing them would cause Finit to
|
||||
`SIGTERM` these processes (since they are no longer eligible to run).
|
||||
|
||||
|
||||
[4.4][] - 2023-05-15
|
||||
|
||||
+8
-3
@@ -10,6 +10,10 @@ if DOC
|
||||
SUBDIRS += doc
|
||||
endif
|
||||
|
||||
if BASH
|
||||
bashdir = $(BASH_DIR)
|
||||
dist_bash_DATA = initctl
|
||||
endif
|
||||
# Compat hook
|
||||
install-dev:
|
||||
@make -C src install-pkgincludeHEADERS
|
||||
@@ -30,6 +34,7 @@ release: distcheck
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-watchdog --with-keventd --with-fstab=/etc/fstab
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-watchdog --with-keventd --with-fstab=/etc/fstab \
|
||||
--with-bash-completion-dir=no
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
||||
* [Runlevels](#runlevels)
|
||||
* [Syntax](doc/config.md#syntax)
|
||||
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||
@@ -391,8 +390,7 @@ Right after the runlevel change when all services have started properly,
|
||||
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
||||
If it exists and is an executable shell script Finit calls it at the very
|
||||
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
||||
in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
||||
in [doc/bootstrap.md](doc/bootstrap.md).
|
||||
in [doc/plugins.md](doc/plugins.md#hooks).
|
||||
|
||||
|
||||
### Limitations
|
||||
|
||||
+29
-9
@@ -1,4 +1,4 @@
|
||||
AC_INIT([Finit], [4.5-rc5], [https://github.com/troglobit/finit/issues],
|
||||
AC_INIT([Finit], [4.5], [https://github.com/troglobit/finit/issues],
|
||||
[finit], [https://troglobit.com/projects/finit/])
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
@@ -15,10 +15,10 @@ AC_CONFIG_FILES([Makefile
|
||||
man/Makefile
|
||||
plugins/Makefile
|
||||
src/Makefile
|
||||
system/Makefile
|
||||
tmpfiles.d/Makefile
|
||||
system/Makefile system/10-hotplug.conf
|
||||
test/test.env test/Makefile
|
||||
test/lib/Makefile test/src/Makefile])
|
||||
test/lib/Makefile test/src/Makefile
|
||||
tmpfiles.d/Makefile])
|
||||
|
||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||
#m4_include([m4/plugin.m4])
|
||||
@@ -94,18 +94,22 @@ AC_ARG_ENABLE(all_plugins,
|
||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
|
||||
AC_PLUGIN([modprobe], [no], [Coldplug modules using modalias magic])
|
||||
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([hook-scripts], [no], [Trigger script execution from hook points])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([hotplug], [yes], [Start udevd or mdev kernel event datamon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
AC_ARG_WITH([bash-completion-dir],
|
||||
AS_HELP_STRING([--with-bash-completion-dir[=PATH]], [Directory to install Bash completion, default: auto]),
|
||||
[bash_dir=$withval], [bash_dir=yes])
|
||||
|
||||
AC_ARG_WITH(fstab,
|
||||
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
|
||||
[fstab=$withval], [fstab=yes])
|
||||
@@ -196,6 +200,12 @@ AS_IF([test "x$enable_rescue" != "xno"], [
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$bash_dir" = "xyes"], [
|
||||
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
|
||||
[BASH_DIR="$(pkg-config --variable=completionsdir bash-completion)"],
|
||||
[BASH_DIR="$datadir/bash-completion/completions"])], [
|
||||
BASH_DIR="$bash_dir"])
|
||||
|
||||
AS_IF([test "x$with_fstab" != "xno"], [
|
||||
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
|
||||
AC_EXPAND_DIR(fstab_path, "$fstab")
|
||||
@@ -285,20 +295,26 @@ AS_IF([test "x$with_plugin_path" != "xno"], [
|
||||
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
||||
|
||||
# Workaround for as-of-yet unreleased runstatedir support, planned for
|
||||
# autoconf 2.70, which some major distros have backported.
|
||||
AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run")
|
||||
AC_SUBST(runstatedir)
|
||||
|
||||
# Override default libdir, used for plugins and rescue.conf
|
||||
pkglibdir=$libdir/finit
|
||||
AC_SUBST(pkglibexecdir)
|
||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "/run/finit/system", [Finit runtime dynamic system services])
|
||||
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$runstatedir/finit/system", [Finit runtime dynamic system services])
|
||||
|
||||
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
||||
AC_SUBST(plugin_path)
|
||||
@@ -321,6 +337,9 @@ AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf")
|
||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||
|
||||
AC_EXPAND_DIR(bash_completion_dir, "$BASH_DIR")
|
||||
AC_SUBST(BASH_DIR, "$bash_completion_dir")
|
||||
|
||||
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||
|
||||
@@ -357,6 +376,7 @@ Behavior:
|
||||
Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Bash completion.......: $bash_completion_dir
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in sulogin......: $with_sulogin $sulogin
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
Bootstrap
|
||||
=========
|
||||
|
||||
0. Get bearings, disable kernel logs, initialize TTY and print banner,
|
||||
unless `HOOK_BANNER` is defined, then call that instead
|
||||
1. Prepare emergency shell, if enabled
|
||||
2. Set up initial signal handlers
|
||||
3. Set up default $PATH early
|
||||
4. Mount `/proc` and `/sys`
|
||||
5. Check kernel command line for `debug` to figure out log level
|
||||
6. Load all `.so` plugins
|
||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||
9. Parse `/etc/finit.conf`
|
||||
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||
means any WDT that requires a kernel module need to be either
|
||||
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
||||
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
||||
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
||||
of error, `HOOK_MOUNT_POST` is called
|
||||
15. Enable SysV init signals
|
||||
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
||||
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
||||
18. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
|
||||
et al. (Supports all locations that SysV init does.), handled by
|
||||
`procps` plugin
|
||||
19. Start all 'S' runlevel tasks and services
|
||||
20. Bring up loopback interface and all `/etc/network/interfaces`, if
|
||||
the `.conf` setting `network <SCRIPT>` is set, it is called instead
|
||||
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
|
||||
22. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
||||
23. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
|
||||
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
|
||||
(re)loaded and new services, tasks, and blocking run commands are
|
||||
started. Provided they are allowed in the new runlevel and all of
|
||||
their conditions, if any, are set.
|
||||
24. Call 4th level hooks, `HOOK_SVC_UP`
|
||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||
27. Start all configured TTYs
|
||||
|
||||
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
||||
`/etc/finit.d/*.conf` are started.
|
||||
|
||||
Notice the seven hook points that are called at various point in the
|
||||
bootstrap process. This is where plugins can extend the boot in any
|
||||
way they please. There are other hook points available, for more on
|
||||
this, see [plugins.md](plugins.md).
|
||||
|
||||
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
||||
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
||||
well before all 'S' runlevel tasks are started. This could be used with
|
||||
system images that are created read-only and all configuration is stored
|
||||
on external media.
|
||||
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
@@ -27,6 +27,16 @@ specified separated by comma. Multiple conditions are logically AND'ed
|
||||
during evaluation, i.e. all conditions must be satisfied in order for a
|
||||
service to run.
|
||||
|
||||
A special syntax, using a leading `!` in run/task/service conditions,
|
||||
denote if a:
|
||||
|
||||
- service does not support `SIGHUP`
|
||||
- run/task should not block runlevel changes (i.e., bootstrap)
|
||||
|
||||
Finit guarantees by default that all run/tasks run (at least) once
|
||||
per runlevel. For most tasks this is a good default, for example
|
||||
checking SSH host keys or loading keymap. However, for conditions
|
||||
that are unlikely to happen it is not. (See example below.)
|
||||
|
||||
### Example
|
||||
|
||||
@@ -41,6 +51,19 @@ being created, i.e., the service's default readiness notification.
|
||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
||||
will also stop or restart.
|
||||
|
||||
Another example is `dropbear`, it does not support `SIGHUP`, but we can
|
||||
also see optional sourcing of arguments from an environment file:
|
||||
|
||||
service [2345789] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
|
||||
|
||||
Finally, the weird "block runlevel changes" example. Here we see what
|
||||
happens when Finit receives `SIGPWR`, sent from a power daemon like
|
||||
[powstatd(8)][]. A condition is asserted and a user can set up their
|
||||
own task to act on it. We do not want this task to block Finit from
|
||||
moving to the next runlevel after bootstrap, so we set `<!>`:
|
||||
|
||||
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
|
||||
|
||||
|
||||
Triggering
|
||||
----------
|
||||
@@ -260,3 +283,5 @@ Therefore, any plugin that supplies Finit with conditions must ensure
|
||||
that their state is updated after each reconfiguration. This can be
|
||||
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
|
||||
to do this, see `plugins/pidfile.c`.
|
||||
|
||||
[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html
|
||||
|
||||
+40
-37
@@ -174,18 +174,22 @@ layout, as specified in the [FHS][]:
|
||||
|- spool/
|
||||
`- tmp/
|
||||
|
||||
Finit starts (very early) by mounting `/dev`, `/proc/`, and `/sys`,
|
||||
unless they (i.e., `/dev`) are already mounted. When all plugins and
|
||||
other, core Finit functions, have been set up, all relevant filesystems
|
||||
(`PASS > 0`) are checked and mounted from the selected `fstab`, either
|
||||
Finit starts by mounting the critical file systems `/dev`, `/proc/`, and
|
||||
`/sys`, unless they are already mounted. When all plugins and other,
|
||||
core Finit functions, have been set up, all relevant filesystems (where
|
||||
`PASS > 0`) are checked and mounted from the selected `fstab`, either
|
||||
the default `/etc/fstab`, or any custom one selected from the command
|
||||
line, or at build time.
|
||||
|
||||
Any file system not listed `fstab` are automatically mounted by Finit,
|
||||
as listed above, provided their respective mount point exists.
|
||||
To provide a smooth ride, file system not listed in the given `fstab`,
|
||||
e.g. `/tmp` and `/run`, are automatically mounted by Finit, as listed
|
||||
above, provided their respective mount point exists.
|
||||
|
||||
With all filesystems mounted, Finit calls `swapon`.
|
||||
|
||||
> **Tip:** to see what happens when all filesystems are mounted, have a
|
||||
> look at the [`bootmisc.so` plugin](plugins.md).
|
||||
|
||||
At shutdown, and after having stopped all services and other lingering
|
||||
processes have been killed, filesystems are unmounted in the reverse
|
||||
order, and `swapoff` is called.
|
||||
@@ -202,12 +206,13 @@ order, and `swapoff` is called.
|
||||
- ` 0`: shutdown
|
||||
|
||||
Runlevels are declared per service/run/task/sysv command. Starting in
|
||||
runlevel S ([bootStrap](bootstrap.md)), usually only for tasks supposed
|
||||
to run once at boot, and services like `syslogd`, which you need to
|
||||
start and run throughout the whole time your system is up. Before `S`
|
||||
is started, however, Finit performs a lot of housekeeping tasks like
|
||||
mounting all filesystems, calling `fsck` if needed, and making sure the
|
||||
everything is OK.
|
||||
runlevel S (bootStrap), usually only for tasks supposed to run once at
|
||||
boot, and services like `syslogd`, which you need to start and run
|
||||
throughout the whole time your system is up.
|
||||
|
||||
Before `S` is started, however, Finit performs a lot of housekeeping
|
||||
tasks like mounting all filesystems, calling `fsck` if needed, and
|
||||
making sure the everything is OK.
|
||||
|
||||
task [S] /lib/console-setup/console-setup.sh
|
||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||
@@ -520,7 +525,7 @@ following directives:
|
||||
|
||||
|
||||
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
|
||||
> and some directives are only available at [bootstrap][], runlevel `S`,
|
||||
> and some directives are only available at bootstrap, runlevel `S`,
|
||||
> see [Limitations](#limitations) below for details.
|
||||
|
||||
|
||||
@@ -533,7 +538,7 @@ the contents of that file is used.
|
||||
|
||||
Deprecated. We recommend using `/etc/hostname` instead.
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Kernel Modules
|
||||
@@ -551,7 +556,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||
|
||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Networking
|
||||
@@ -564,7 +569,7 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Alternate finit.d/
|
||||
@@ -619,7 +624,7 @@ stanzas can share the same rlimits if they are in the same .conf.
|
||||
|
||||
**Syntax:** `runlevel <N>`
|
||||
|
||||
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||
The system runlevel to go to after bootstrap (S) has completed. `N`
|
||||
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
halt.
|
||||
|
||||
@@ -628,7 +633,7 @@ Finit disables networking in this mode.
|
||||
|
||||
*Default:* 2
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### One-shot Commands (sequence)
|
||||
@@ -668,11 +673,14 @@ also the `--quiet` and `--batch` options.
|
||||
|
||||
One-shot like 'run', but starts in parallel with the next command.
|
||||
|
||||
Both `run` and `task` commands are run in a shell, so pipes and
|
||||
redirects can be freely used:
|
||||
Both `run` and `task` commands are run in a shell, so basic pipes and
|
||||
redirects can be used:
|
||||
|
||||
task [s] echo "foo" | cat >/tmp/bar
|
||||
|
||||
Please note, `;`, `&&`, `||`, and similar are *not supported*. Any
|
||||
non-trivial constructs are better placed in a separate shell script.
|
||||
|
||||
|
||||
### SysV Init Scripts
|
||||
|
||||
@@ -963,9 +971,8 @@ previous stanza can also be written as:
|
||||
**Syntax:** `runparts [progress] [sysv] <DIR>`
|
||||
|
||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||
files, or scripts, in the directory are called, in alphabetic order.
|
||||
The scripts in this directory are executed at the very end of runlevel
|
||||
`S`, [bootstrap][].
|
||||
files in the directory are called, in alphabetic order. The scripts in
|
||||
this directory are executed at the very end of runlevel `S`.
|
||||
|
||||
A common use-case for runparts scripts is to create and enable/disable
|
||||
services, which Finit will then apply when changing runlevel from S to
|
||||
@@ -990,10 +997,9 @@ before continuing. None of them can issue commands to start, stop, or
|
||||
restart other services. Also, ensure all your services and programs
|
||||
either terminate or start in the background or you will block Finit.
|
||||
|
||||
> **Note:** `runparts` scrips are only read and executed in runlevel S
|
||||
> ([bootstrap][]). See [hook scripts](plugins.md#hooks) for other ways
|
||||
> to run scripts at certain points during the complete lifetime of the
|
||||
> system.
|
||||
> **Note:** `runparts` scrips are only read and executed in runlevel S.
|
||||
> See [hook scripts](plugins.md#hooks) for other ways to run scripts at
|
||||
> certain points during the complete lifetime of the system.
|
||||
|
||||
**Recommendations:**
|
||||
|
||||
@@ -1106,8 +1112,8 @@ can be omitted to keep the kernel default.
|
||||
tty [12345] @console noclear vt220
|
||||
|
||||
On really bare bones systems, or for board bringup, Finit can give you a
|
||||
shell prompt as soon as [bootstrap][] is done, without opening any
|
||||
device node:
|
||||
shell prompt as soon as bootstrap is done, without opening any device
|
||||
node:
|
||||
|
||||
tty [12345789] notty
|
||||
|
||||
@@ -1342,12 +1348,11 @@ Watchdog
|
||||
When built `--with-watchdog` a separate service is built and installed
|
||||
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
|
||||
device node exists, Finit will start it and treat it as the elected
|
||||
watchdog service to delegate its reboot to. See [bootstrap][] for
|
||||
details. This delegation is to ensure that the system is rebooted by a
|
||||
hardware watchdog timer -- on many embedded systems this is crucial to
|
||||
ensure all circuits on the board are properly reset for the next boot,
|
||||
in effect ensuring the system works the same after both a power-on and
|
||||
reboot event.
|
||||
watchdog service to delegate its reboot to. This delegation is to
|
||||
ensure that the system is rebooted by a hardware watchdog timer -- on
|
||||
many embedded systems this is crucial to ensure all circuits on the
|
||||
board are properly reset for the next boot, in effect ensuring the
|
||||
system works the same after both a power-on and reboot event.
|
||||
|
||||
The delegation is performed at the very last steps of system shutdown,
|
||||
if reboot has been selected and an elected watchdog is known, first a
|
||||
@@ -1369,8 +1374,6 @@ device descriptor. If the kernel driver has been built without this,
|
||||
the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||
it at configure time.
|
||||
|
||||
[bootstrap]: bootstrap.md
|
||||
|
||||
|
||||
keventd
|
||||
-------
|
||||
|
||||
+17
-5
@@ -28,9 +28,16 @@ For your convenience a set of *optional* plugins are available:
|
||||
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
|
||||
file systems must be writable for this plugin to work.
|
||||
|
||||
Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
|
||||
disks and `/dev` is usually a `devtmpfs`. This must be defined in the
|
||||
`/etc/fstab` file and in the Linux kernel config.
|
||||
This plugin is a wrapper for the [tmpfiles.d(5)][] implementation that
|
||||
Finit has. Capable but limited: no aging, attributes, or subvolumes.
|
||||
|
||||
By default, `/lib/finit/tmpfiles.d` carries all the default .conf
|
||||
files distributed with Finit. It is read first but can be overridden
|
||||
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
|
||||
|
||||
> **Note:** On an embedded system both `/var` and `/run` can be `tmpfs`
|
||||
> RAM disks and `/dev` is usually a `devtmpfs`. This must be defined
|
||||
> in the `/etc/fstab` file and in the Linux kernel config.
|
||||
|
||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||
_Optional plugin._
|
||||
@@ -50,8 +57,11 @@ For your convenience a set of *optional* plugins are available:
|
||||
customized at build-time using the `--with-hook-scripts-path=PATH`
|
||||
argument to `configure`.
|
||||
|
||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||
available. Enabled by default.
|
||||
* *hotplug.so*: Replaced with `/lib/finit/system/10-hotplug.conf`, which
|
||||
checks for `udevd` and `mdev` at boot. This file can be overridden by a
|
||||
file in `/etc/finit.d/10-hotplug.conf`.
|
||||
|
||||
Enabled by default.
|
||||
|
||||
> See the [Services](config.md#services) section in the configuration
|
||||
> guide for an example how to run `mdevd`, alternative to plain mdev.
|
||||
@@ -217,3 +227,5 @@ Plugins like `tty.so` extend finit by acting on events, they are called
|
||||
I/O plugins and are called from the finit main loop when `poll()`
|
||||
detects an event. See the source code for `plugins/*.c` for more help
|
||||
and ideas.
|
||||
|
||||
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ static void setup(void *arg)
|
||||
|
||||
/* Generate machine id for dbus */
|
||||
if (whichp("dbus-uuidgen"))
|
||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||
run_interactive("dbus-uuidgen --ensure", "Verifying D-Bus machine UUID");
|
||||
|
||||
/*
|
||||
* Register service with Finit
|
||||
|
||||
@@ -19,6 +19,8 @@ if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
|
||||
dist_pkglibexec_SCRIPTS = coldplug
|
||||
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
# With the daemon mode ('mdev -df') we no longer need the hotplug helper
|
||||
echo "" > /proc/sys/kernel/hotplug
|
||||
|
||||
# Wait for 'mdev -df' to set up its event queue.
|
||||
sleep 1
|
||||
|
||||
# Trigger 'add' event for all devices and subsystems to load all modules
|
||||
# and any firmware needed by the hardware.
|
||||
find /sys/devices -name uevent -print | while IFS='' read X; do echo add > $X; done
|
||||
+10
-2
@@ -222,8 +222,16 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
||||
static void cond_delpath(const char *path)
|
||||
{
|
||||
nftw(path, do_delete, 20, FTW_DEPTH);
|
||||
if (remove(path) && errno != ENOENT)
|
||||
err(1, "Failed removing condition path %s", path);
|
||||
if (remove(path)) {
|
||||
switch (errno) {
|
||||
case ENOENT: /* Ignore */
|
||||
case ENOTEMPTY: /* Only at shutdown and for directories */
|
||||
break;
|
||||
default:
|
||||
err(1, "Failed removing condition path %s", path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cond_set_path(const char *path, enum cond_state next)
|
||||
|
||||
+16
-5
@@ -445,7 +445,7 @@ void conf_save_exec_order(svc_t *svc, char *cmdline, int result)
|
||||
free(prepared);
|
||||
prepared = malloc(++len);
|
||||
if (!prepared)
|
||||
return;
|
||||
goto done;
|
||||
snprintf(prepared, len, " %-7s %-64s (%s)", svc_typestr(svc), cmdline, svc->desc);
|
||||
}
|
||||
} else {
|
||||
@@ -458,7 +458,7 @@ void conf_save_exec_order(svc_t *svc, char *cmdline, int result)
|
||||
fprintf(fp, "%s %-7s %-64s (%s)\n", ststr, svc_typestr(svc), cmdline, svc->desc);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ void conf_save_service(int type, char *cfg, char *file)
|
||||
mkpath(FINIT_RUNPATH_, 0755);
|
||||
snprintf(fn, sizeof(fn), "%s/%s", FINIT_RUNPATH_, file);
|
||||
if (fexist(fn))
|
||||
warn("File %s already exists, overwriting.", fn);
|
||||
warnx("File %s already exists, overwriting.", fn);
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp) {
|
||||
err(1, "Failed creating %s", fn);
|
||||
@@ -656,11 +656,22 @@ void conf_parse_cond(svc_t *svc, char *cond)
|
||||
return;
|
||||
}
|
||||
|
||||
/* First character must be '!' if SIGHUP is not supported. */
|
||||
/*
|
||||
* First character must be '!' if:
|
||||
* - service: SIGHUP is not supported
|
||||
* - run/task: Do not block bootstrap
|
||||
*/
|
||||
ptr = cond;
|
||||
if (ptr[i] == '!') {
|
||||
svc->sighup = 0;
|
||||
ptr++;
|
||||
|
||||
if (svc_is_runtask(svc)) {
|
||||
/* see service_runtask_clean() */
|
||||
svc->sighup = 1;
|
||||
svc->once = 1;
|
||||
} else {
|
||||
svc->sighup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (ptr[i] != '>' && ptr[i] != 0)
|
||||
|
||||
@@ -695,6 +695,10 @@ int main(int argc, char *argv[])
|
||||
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
||||
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
||||
|
||||
/* Some bootstrap tasks may need to know if we're in a container. */
|
||||
if (in_container())
|
||||
cond_set("int/container");
|
||||
|
||||
/*
|
||||
* Initialize .conf system and load static /etc/finit.conf then
|
||||
* tell the world what we used.
|
||||
|
||||
+60
-16
@@ -330,14 +330,14 @@ static int lredirect(svc_t *svc)
|
||||
|
||||
snprintf(rot, sizeof(rot), "%d:%d", logfile_size_max, logfile_count_max);
|
||||
snprintf(pid, sizeof(pid), "%d", svc_pid);
|
||||
execlp("logger", "logger", "-f", svc->log.file, "-b", "-t", tag, "-p", prio, "-I", pid, "-r", rot, NULL);
|
||||
execlp("logger", "logger", "-f", svc->log.file, "-b", "-t", tag, "-p", prio, debug ? "-s" : "", "-I", pid, "-r", rot, NULL);
|
||||
} else {
|
||||
char sz[20], num[3];
|
||||
|
||||
snprintf(sz, sizeof(sz), "%d", logfile_size_max);
|
||||
snprintf(num, sizeof(num), "%d", logfile_count_max);
|
||||
|
||||
execlp(_PATH_LOGIT, "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
|
||||
execlp(_PATH_LOGIT, "logit", "-f", svc->log.file, "-n", sz, "-r", num, debug ? "-s" : "", NULL);
|
||||
}
|
||||
_exit(1);
|
||||
}
|
||||
@@ -351,9 +351,9 @@ static int lredirect(svc_t *svc)
|
||||
char pid[16];
|
||||
|
||||
snprintf(pid, sizeof(pid), "%d", svc_pid);
|
||||
execlp("logger", "logger", "-t", tag, "-p", prio, "-I", pid, NULL);
|
||||
execlp("logger", "logger", "-t", tag, "-p", prio, debug ? "-s" : "", "-I", pid, NULL);
|
||||
} else {
|
||||
execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, NULL);
|
||||
execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, debug ? "-s" : "", NULL);
|
||||
}
|
||||
_exit(1);
|
||||
}
|
||||
@@ -413,6 +413,7 @@ static void source_env(svc_t *svc)
|
||||
len = sizeof(buf);
|
||||
while (fgets(line, len, fp)) {
|
||||
char *key = chomp(line);
|
||||
wordexp_t we = { 0 };
|
||||
char *value, *end;
|
||||
|
||||
/* skip any leading whitespace */
|
||||
@@ -466,7 +467,19 @@ static void source_env(svc_t *svc)
|
||||
*end-- = 0;
|
||||
}
|
||||
|
||||
setenv(key, value, 1);
|
||||
switch (wordexp(value, &we, 0)) {
|
||||
case 0:
|
||||
setenv(key, we.we_wordv[0], 1);
|
||||
wordfree(&we);
|
||||
break;
|
||||
|
||||
case WRDE_NOSPACE:
|
||||
wordfree(&we);
|
||||
/* fallthrough */
|
||||
default:
|
||||
setenv(key, value, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@@ -979,7 +992,11 @@ int service_stop(svc_t *svc)
|
||||
if (!svc->desc[0])
|
||||
do_progress = 0;
|
||||
|
||||
if (runlevel != 1 && do_progress)
|
||||
/*
|
||||
* Skip run/tasks in progress, would otherwise print silly stuff
|
||||
* like: "Stopping Shutting down" ...
|
||||
*/
|
||||
if (runlevel != 1 && do_progress && (svc_is_daemon(svc) || svc_is_sysv(svc)))
|
||||
print_desc("Stopping ", svc->desc);
|
||||
|
||||
if (!svc_is_sysv(svc)) {
|
||||
@@ -1035,7 +1052,7 @@ int service_stop(svc_t *svc)
|
||||
}
|
||||
}
|
||||
|
||||
if (runlevel != 1 && do_progress)
|
||||
if (runlevel != 1 && do_progress && (svc_is_daemon(svc) || svc_is_sysv(svc)))
|
||||
print_result(rc);
|
||||
|
||||
return rc;
|
||||
@@ -1401,7 +1418,11 @@ static void parse_cmdline_args(svc_t *svc, char *cmd, char **args)
|
||||
* before they are started. Or restarted, or even SIGHUP'ed, when the
|
||||
* gateway changes or interfaces come and go. The special case when a
|
||||
* service is declared with <!> means it does not support SIGHUP but
|
||||
* must be STOP/START'ed at system reconfiguration.
|
||||
* must be STOP/START'ed at system reconfiguration. For run/task a <!>
|
||||
* means Finit can relax its promise to run at least once per runlevel.
|
||||
* I.e., for run/task conditions that would otherwise block bootstrap:
|
||||
*
|
||||
* task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
|
||||
*
|
||||
* Conditions can for example be: pid/NAME:ID for process dependencies,
|
||||
* net/<IFNAME>/up or net/<IFNAME>/exists. The condition handling is
|
||||
@@ -1430,6 +1451,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
char *id = NULL, *env = NULL, *cgroup = NULL;
|
||||
char *pre_script = NULL, *post_script = NULL;
|
||||
char *ready_script = NULL, *conflict = NULL;
|
||||
char ident[MAX_IDENT_LEN];
|
||||
char *ifstmt = NULL;
|
||||
char *notify = NULL;
|
||||
struct tty tty = { 0 };
|
||||
@@ -1554,8 +1576,16 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
}
|
||||
|
||||
name = parse_name(cmd, name);
|
||||
if (!id)
|
||||
strlcpy(ident, name, sizeof(ident));
|
||||
if (!id) {
|
||||
id = "";
|
||||
} else {
|
||||
strlcat(ident, ":", sizeof(ident));
|
||||
strlcat(ident, id, sizeof(ident));
|
||||
}
|
||||
|
||||
if (ifstmt && !svc_ifthen(1, ident, ifstmt))
|
||||
return 0;
|
||||
|
||||
levels = conf_parse_runlevels(runlevels);
|
||||
if (runlevel != INIT_LEVEL && !ISOTHER(levels, INIT_LEVEL)) {
|
||||
@@ -2194,6 +2224,7 @@ static void service_retry(svc_t *svc)
|
||||
static void svc_set_state(svc_t *svc, svc_state_t new_state)
|
||||
{
|
||||
svc_state_t *state = (svc_state_t *)&svc->state;
|
||||
const svc_state_t old_state = svc->state;
|
||||
|
||||
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
|
||||
if (new_state == SVC_STOPPING_STATE) {
|
||||
@@ -2214,7 +2245,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new_state)
|
||||
snprintf(failure, sizeof(failure), "%s/%s/failure", svc_typestr(svc), svc_ident(svc, NULL, 0));
|
||||
|
||||
/* create success/failure condition when entering SVC_DONE_STATE. */
|
||||
if (*state == SVC_DONE_STATE) {
|
||||
if (new_state == SVC_DONE_STATE) {
|
||||
if (svc->started && !WEXITSTATUS(svc->status))
|
||||
cond_set_oneshot(success);
|
||||
else
|
||||
@@ -2222,7 +2253,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new_state)
|
||||
}
|
||||
|
||||
/* clear all conditions when entering SVC_HALTED_STATE. */
|
||||
if (*state == SVC_HALTED_STATE) {
|
||||
if (new_state == SVC_HALTED_STATE) {
|
||||
cond_clear(success);
|
||||
cond_clear(failure);
|
||||
}
|
||||
@@ -2232,9 +2263,14 @@ static void svc_set_state(svc_t *svc, svc_state_t new_state)
|
||||
char cond[MAX_COND_LEN];
|
||||
|
||||
snprintf(cond, sizeof(cond), "service/%s/", svc_ident(svc, NULL, 0));
|
||||
cond_clear(cond);
|
||||
|
||||
switch (svc->state) {
|
||||
if ((old_state == SVC_RUNNING_STATE && new_state == SVC_PAUSED_STATE) ||
|
||||
(old_state == SVC_PAUSED_STATE && new_state == SVC_RUNNING_STATE))
|
||||
; /* only paused during reload, don't clear conds. */
|
||||
else
|
||||
cond_clear(cond);
|
||||
|
||||
switch (new_state) {
|
||||
case SVC_HALTED_STATE:
|
||||
case SVC_RUNNING_STATE:
|
||||
strlcat(cond, svc_status(svc), sizeof(cond));
|
||||
@@ -2472,7 +2508,7 @@ restart:
|
||||
|
||||
case COND_ON:
|
||||
if (svc_is_changed(svc)) {
|
||||
if (svc_nohup(svc))
|
||||
if (svc_nohup(svc) || !svc_is_daemon(svc))
|
||||
service_stop(svc);
|
||||
else {
|
||||
/*
|
||||
@@ -2573,7 +2609,12 @@ void service_runtask_clean(void)
|
||||
if (!svc_is_runtask(svc))
|
||||
continue;
|
||||
|
||||
svc->once = 0;
|
||||
/* run/task declared with <!> */
|
||||
if (svc->sighup)
|
||||
svc->once = 1;
|
||||
else
|
||||
svc->once = 0;
|
||||
|
||||
if (svc->state == SVC_DONE_STATE)
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
}
|
||||
@@ -2581,6 +2622,7 @@ void service_runtask_clean(void)
|
||||
|
||||
/**
|
||||
* service_completed - Have run/task completed in current runlevel
|
||||
* @svcp: On %FALSE return, this points to the first incomplete svc
|
||||
*
|
||||
* This function checks if all run/task have run once in the current
|
||||
* runlevel. E.g., at bootstrap we must wait for these scripts or
|
||||
@@ -2593,7 +2635,7 @@ void service_runtask_clean(void)
|
||||
* Returns:
|
||||
* %TRUE(1) or %FALSE(0)
|
||||
*/
|
||||
int service_completed(void)
|
||||
int service_completed(svc_t **svcp)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
@@ -2615,6 +2657,8 @@ int service_completed(void)
|
||||
|
||||
if (!svc->once) {
|
||||
dbg("%s has not yet completed ...", svc_ident(svc, NULL, 0));
|
||||
if (svcp)
|
||||
*svcp = svc;
|
||||
return 0;
|
||||
}
|
||||
dbg("%s has completed ...", svc_ident(svc, NULL, 0));
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ int service_step (svc_t *svc);
|
||||
void service_step_all (int types);
|
||||
void service_worker (void *unused);
|
||||
|
||||
int service_completed (void);
|
||||
int service_completed (svc_t **svc);
|
||||
void service_notify_reconf (void);
|
||||
|
||||
void service_init (uev_ctx_t *ctx);
|
||||
|
||||
@@ -52,22 +52,30 @@ sm_t sm;
|
||||
*/
|
||||
static void sm_check_bootstrap(void *work)
|
||||
{
|
||||
static int cnt = 120 * 10; /* We run with 100ms period */
|
||||
int level = cfglevel;
|
||||
static int timeout = 120;
|
||||
int bootstrap_done;
|
||||
int level = cfglevel;
|
||||
svc_t *svc = NULL;
|
||||
|
||||
dbg("Step all services ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
if (cnt-- > 0 && !service_completed()) {
|
||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||
bootstrap_done = service_completed(&svc);
|
||||
if (timeout-- > 0 && !bootstrap_done) {
|
||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", timeout);
|
||||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
if (timeout > 0) {
|
||||
dbg("All run/task have completed, resuming bootstrap.");
|
||||
else
|
||||
} else {
|
||||
dbg("Timeout, resuming bootstrap.");
|
||||
if (svc)
|
||||
print(2, "Timeout waiting for %s to run, resuming bootstrap", svc_ident(svc, NULL, 0));
|
||||
else
|
||||
print(2, "Timeout waiting for unknown run/task, resuming bootstrap");
|
||||
}
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
|
||||
@@ -710,6 +710,7 @@ int svc_conflicts(svc_t *svc)
|
||||
*/
|
||||
int svc_ifthen(int is_conf, const char *ident, char *stmt)
|
||||
{
|
||||
char stmts[MAX_IDENT_LEN];
|
||||
int not = 0;
|
||||
svc_t *svc;
|
||||
|
||||
@@ -724,39 +725,46 @@ int svc_ifthen(int is_conf, const char *ident, char *stmt)
|
||||
if (is_conf)
|
||||
return 1;
|
||||
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
|
||||
while (ptr[i] != '>' && ptr[i] != 0)
|
||||
i++;
|
||||
ptr[i] = 0;
|
||||
|
||||
cond = cond_get(stmt);
|
||||
if (not && cond == COND_ON)
|
||||
return 0;
|
||||
if (!not && cond == COND_OFF)
|
||||
return 0;
|
||||
strlcpy(stmts, stmt, sizeof(stmts));
|
||||
for (stmt = strtok(stmts, ","); stmt; stmt = strtok(NULL, ","), not = 0) {
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
|
||||
cond = cond_get(stmt);
|
||||
if (not && cond == COND_ON)
|
||||
return 0;
|
||||
if (!not && cond == COND_OFF)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!is_conf)
|
||||
return 1;
|
||||
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
strlcpy(stmts, stmt, sizeof(stmts));
|
||||
for (stmt = strtok(stmts, ","); stmt; stmt = strtok(NULL, ","), not = 0) {
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
|
||||
svc = svc_find_by_str(stmt);
|
||||
if (not && svc) {
|
||||
logit(LOG_NOTICE, "skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
if (!not && !svc) {
|
||||
logit(LOG_NOTICE, "skipping %s, %s not available.", ident, stmt);
|
||||
return 0;
|
||||
svc = svc_find_by_str(stmt);
|
||||
if (not && svc) {
|
||||
logit(LOG_NOTICE, "skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
if (!not && !svc) {
|
||||
logit(LOG_NOTICE, "skipping %s, %s not available.", ident, stmt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
# generated
|
||||
10-hotplug.conf
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# System hotplug can be handled by udev or mdev
|
||||
|
||||
# Either we have systemd-udevd or eudev, on the rare occasion we find
|
||||
# both, we opt for the latter. Remember, you can override this by a
|
||||
# custom hotplug.conf in /etc/finit.d/ or /etc/finit.d/enabled/.
|
||||
service nowarn [S12345789] cgroup.system name:udevd pid:udevd log /lib/systemd/systemd-udevd -- Device event managing daemon
|
||||
service nowarn [S12345789] cgroup.system name:udevd pid:udevd log udevd -- Device event managing daemon
|
||||
|
||||
# Wait for udevd to start, then wait a couple of seconds for it to become ready
|
||||
run nowarn if:udevd cgroup.init :1 [S] <pid/udevd> log udevadm settle -t 0 --
|
||||
run nowarn if:udevd cgroup.init :2 [S] <pid/udevd> log udevadm control --reload --
|
||||
run nowarn if:udevd cgroup.init :3 [S] <pid/udevd> log udevadm trigger -c add -t devices -- Requesting device events
|
||||
run nowarn if:udevd cgroup.init :4 [S] <pid/udevd> log udevadm trigger -c add -t subsystems -- Requesting subsystem events
|
||||
run nowarn if:udevd cgroup.init :5 [S] <pid/udevd> log udevadm settle -t 5 -- Waiting for udev to finish
|
||||
|
||||
# If udevd is not available, try mdev
|
||||
run nowarn conflict:udevd [S] mdev -s -- Populating device tree
|
||||
@@ -0,0 +1,53 @@
|
||||
# System hotplug handled by udev, mdevd, or mdev (preferred order)
|
||||
#
|
||||
# Your system usually has either udevd, mdev, or mdevd. They probe the system
|
||||
# for devices, loading modules and any firmware needed. Since the bootstrap
|
||||
# often needs to be synchronized carefully, we suggest using your system log
|
||||
# daemon as the barrier for all other services. E.g.:
|
||||
#
|
||||
# service if:udevd <run/udevadm:5/success> [S0123456789] syslogd -F -- System log daemon
|
||||
# service if:mdev <run/coldplug/success> [S0123456789] syslogd -F -- System log daemon
|
||||
# service if:mdevd <run/coldplug/success> [S0123456789] syslogd -F -- System log daemon
|
||||
#
|
||||
# This provdes a <pid/syslogd> condition that can act as a barrier for all
|
||||
# other services. Notice the `if:` statement and the condition for starting
|
||||
# syslogd is only considered if either udevd or mdev (service) is loaded and
|
||||
# is guaranteed to run after each respective run stanza have completed.
|
||||
#
|
||||
# Override this file by copying it to /etc/finit.d/, using the same name, then
|
||||
# change the contents any way you like, it can even be empty.
|
||||
|
||||
# Check for systemd-udevd and eudev, if we find both, we opt for the latter.
|
||||
service nowarn [S12345789] cgroup.system name:udevd pid:udevd log /lib/systemd/systemd-udevd -- Device event daemon (udev)
|
||||
service nowarn [S12345789] cgroup.system name:udevd pid:udevd log udevd -D -- Device event daemon (udev)
|
||||
|
||||
# Wait for udevd to start, then trigger coldplug events and module loading.
|
||||
# The last 'settle' call waits for it to finalize processing all uevents.
|
||||
run nowarn if:udevd cgroup.init :1 [S] <pid/udevd> log udevadm settle -t 0 --
|
||||
run nowarn if:udevd cgroup.init :2 [S] <pid/udevd> log udevadm control --reload --
|
||||
run nowarn if:udevd cgroup.init :3 [S] <pid/udevd> log udevadm trigger -c add -t devices -- Requesting device events
|
||||
run nowarn if:udevd cgroup.init :4 [S] <pid/udevd> log udevadm trigger -c add -t subsystems -- Requesting subsystem events
|
||||
run nowarn if:udevd cgroup.init :5 [S] <pid/udevd> log udevadm settle -t 30 -- Waiting for udev to finish
|
||||
|
||||
# If udevd is not available, check for mdevd. Unlike plain 'mdev -df', the
|
||||
# mdevd-coldplug process exits when mdevd has completed. So the condition
|
||||
# <run/coldplug/success> (same as for plain mdev below) can be relied on as a
|
||||
# barrier for services that, e.g., need to probe for switchcore ports or PHYs
|
||||
# that require firmware loading before they show up.
|
||||
service nowarn conflict:udevd,mdev cgroup.init if:!udevd \
|
||||
[S12345789] notify:s6 mdevd -O 4 -D %n -- Device event daemon (mdevd)
|
||||
run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/ready> \
|
||||
[S] mdevd-coldplug -- Cold plugging system
|
||||
|
||||
# If neither udevd or mdevd are available, fall back to mdev. The new daemon
|
||||
# mode calls `mdev -s` internally but does not create a PID file when that is
|
||||
# done, so synchronization with coldplug is fragile.
|
||||
service nowarn conflict:udevd,mdevd cgroup.init if:!udevd,!mdevd \
|
||||
[S12345789] mdev -df -S -- Device event daemon (mdev)
|
||||
|
||||
# Trigger a replay of all uevents from boot, before userspace was up and the
|
||||
# filesystem mounted. Compared to udevd, we don't know when 'mdev -df' has
|
||||
# finished processing all events, i.e., depending on <run/coldplug/success> is
|
||||
# not an indicator of all devices having been (re)discovered and fully set up.
|
||||
run nowarn conflict:udevd,mdevd cgroup.init name:coldplug if:mdev <service/mdev/running> \
|
||||
[S] @pkglibexecdir@/coldplug -- Cold plugging system
|
||||
+3
-1
@@ -1,8 +1,10 @@
|
||||
EXTRA_DIST = 10-hotplug.conf.in
|
||||
systemdir = $(system_path)
|
||||
system_DATA =
|
||||
dist_system_DATA =
|
||||
|
||||
if BUILD_HOTPLUG_PLUGIN
|
||||
dist_system_DATA += 10-hotplug.conf
|
||||
system_DATA += 10-hotplug.conf
|
||||
endif
|
||||
|
||||
if BUILD_TESTSERV_PLUGIN
|
||||
|
||||
@@ -32,6 +32,7 @@ EXTRA_DIST += crashing.sh
|
||||
EXTRA_DIST += depserv.sh
|
||||
EXTRA_DIST += devmon.sh
|
||||
EXTRA_DIST += failing-sysv.sh
|
||||
EXTRA_DIST += svc-env.sh
|
||||
EXTRA_DIST += global-envs.sh
|
||||
EXTRA_DIST += initctl-status-subset.sh
|
||||
EXTRA_DIST += notify.sh
|
||||
@@ -53,6 +54,7 @@ EXTRA_DIST += start-stop-sysv.sh
|
||||
EXTRA_DIST += start-stop-serv.sh
|
||||
EXTRA_DIST += signal-service.sh
|
||||
EXTRA_DIST += testserv.sh
|
||||
EXTRA_DIST += unexpected-restart.sh
|
||||
|
||||
AM_TESTS_ENVIRONMENT = SYSROOT='$(abs_builddir)/sysroot/';
|
||||
AM_TESTS_ENVIRONMENT += export SYSROOT;
|
||||
@@ -75,6 +77,7 @@ TESTS += crashing.sh
|
||||
TESTS += depserv.sh
|
||||
TESTS += devmon.sh
|
||||
TESTS += failing-sysv.sh
|
||||
TESTS += svc-env.sh
|
||||
TESTS += global-envs.sh
|
||||
TESTS += initctl-status-subset.sh
|
||||
TESTS += notify.sh
|
||||
@@ -98,6 +101,7 @@ TESTS += signal-service.sh
|
||||
if TESTSERV
|
||||
TESTS += testserv.sh
|
||||
endif
|
||||
TESTS += unexpected-restart.sh
|
||||
|
||||
check-recursive: setup-chroot
|
||||
|
||||
|
||||
+9
-1
@@ -143,7 +143,15 @@ log()
|
||||
|
||||
sep()
|
||||
{
|
||||
printf "\e[2m――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\e[0m\n"
|
||||
heading=${1:-}
|
||||
if [ -n "$heading" ]; then
|
||||
num=$((72 - ${#heading} - 1))
|
||||
printf "\e[1m%s " "$heading"
|
||||
printf -- "―%.0s" $(seq 1 $num)
|
||||
printf "\e[0m\n"
|
||||
else
|
||||
printf "\e[1m――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\e[0m\n"
|
||||
fi
|
||||
}
|
||||
|
||||
say()
|
||||
|
||||
@@ -37,5 +37,6 @@ while true; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
sleep 1
|
||||
texec diff -u /usr/share/runparts/ref.log /tmp/runparts.log
|
||||
texec cmp /usr/share/runparts/ref.log /tmp/runparts.log || fail "runparts in wrong order"
|
||||
|
||||
@@ -12,12 +12,12 @@ cp "$top_builddir/test/src/serv" "$SYSROOT/sbin/"
|
||||
FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$SYSROOT" make -f "$srcdir/lib/sysroot.mk"
|
||||
|
||||
# Drop plugins we don't need in test, only causes confusing FAIL in logs.
|
||||
for plugin in tty.so urandom.so rtc.so modprobe.so hotplug.so; do
|
||||
for plugin in tty.so urandom.so rtc.so modprobe.so; do
|
||||
find "$SYSROOT" -name $plugin -delete
|
||||
done
|
||||
|
||||
# Drop system .conf files we don't need in test, same as above
|
||||
for conf in hotplug.conf; do
|
||||
# shellcheck disable=SC2043
|
||||
for conf in 10-hotplug.conf; do
|
||||
find "$SYSROOT" -name $conf -delete
|
||||
done
|
||||
|
||||
|
||||
@@ -3,3 +3,5 @@
|
||||
|
||||
foo=bar
|
||||
baz=qux
|
||||
|
||||
xyzzy=$foo
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
# Ensure service environment variables are sourced and expanded properly.
|
||||
set -e
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
sep "/etc/env:"
|
||||
run "cat /etc/env"
|
||||
run "echo 'service env:/etc/env serv -np -e xyzzy:bar -- serv checks xyzzy=bar' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
@@ -37,6 +37,7 @@ while true; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
sleep 1
|
||||
texec cat /tmp/sysv.log
|
||||
texec diff -u /usr/share/runparts/sysv.log /tmp/sysv.log
|
||||
texec cmp /usr/share/runparts/sysv.log /tmp/sysv.log || fail "runparts sysv in wrong order"
|
||||
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
# A service (B) going into flux, 'initctl reload' with no changes to
|
||||
# activate, should do not cause ripple effects removing any service
|
||||
# conditions, e.g., <service/B/running>. During reload all services
|
||||
# are paused while Finit checks for any service3 changes to activate,
|
||||
# which may mean stopping or restarting existing services.
|
||||
#
|
||||
# Issue #382
|
||||
set -e
|
||||
|
||||
#DEBUG=true
|
||||
TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
run "cat >> $FINIT_CONF" <<EOF
|
||||
service log:stdout name:A serv -np -i A
|
||||
service log:stdout notify:systemd <pid/A> name:B serv -np -i B -N 0 -- B needs A
|
||||
service log:stdout notify:systemd <service/B/ready> name:C serv -np -i C -N 0 -- C needs B(service)
|
||||
service log:stdout notify:systemd <pid/B> name:D serv -np -i D -N 0 -- D needs B(pid)
|
||||
task <service/C/ready,service/D/ready> name:allup initctl cond set allup -- Everything is up
|
||||
EOF
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
pidof()
|
||||
{
|
||||
texec initctl -j status "$1" | jq .pid
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
sep "$FINIT_CONF"
|
||||
run "cat $FINIT_CONF"
|
||||
sep
|
||||
run "initctl reload"
|
||||
run "initctl status"
|
||||
sep
|
||||
|
||||
say "waiting for primary startup to complete"
|
||||
retry 'assert_status allup "done"' 100 1
|
||||
assert_status C "running"
|
||||
oldpid=$(pidof C)
|
||||
assert_status D "running"
|
||||
doldpid=$(pidof D)
|
||||
|
||||
sep "pre-reload status"
|
||||
run "initctl status"
|
||||
sep
|
||||
|
||||
say "Reload Finit, who gets restarted?"
|
||||
#run "initctl debug"
|
||||
run "initctl reload"
|
||||
sleep 2
|
||||
|
||||
assert_status A "running"
|
||||
assert_status B "running"
|
||||
assert_status C "running"
|
||||
assert_status D "running"
|
||||
|
||||
newpid=$(pidof C)
|
||||
# shellcheck disable=SC2086
|
||||
assert "C was not restarted" $oldpid -eq $newpid
|
||||
|
||||
dnewpid=$(pidof D)
|
||||
# shellcheck disable=SC2086
|
||||
assert "D was not restarted" $doldpid -eq $dnewpid
|
||||
Reference in New Issue
Block a user