Compare commits

...
175 Commits
Author SHA1 Message Date
Joachim Wiberg d15e28ea6b Update ChangeLog and bump version for v4.7 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 19:48:31 +01:00
Joachim Wiberg 836bfff08b .github: update actions
... and try to fix weekly trigger

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 19:47:12 +01:00
Joachim Wiberg 59152b557c keventd: remove runlevels 0 and 6
The responsibility of the kernel event daemon is to relay kernel events
to Finit.  At shutdown and reboot it is too late for more events and the
daemon should just shut down with other services.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 15:18:52 +01:00
Joachim Wiberg 293b0ffa79 tmpfiles.d/var.conf: fix ordering and add legacy /run/lock/subsys
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 13:59:49 +01:00
Joachim Wiberg d5d9cd5645 tmpfiles: fix error message and ignore unremovable dirs (EBUSY)
Fix copy-paste of error message from cond-w.c

A read-only root filesystem may have /var/lock, while we want to remove
it and add a symlink to ../run/lock.  Ignore errors from this since we
cannot do anything about it.  It is up to the user to fix their skeleton
or use an overlay.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 13:56:31 +01:00
Joachim Wiberg 2f281665af Simplify and add links to Infix, br2-finit-demo, and Buildroot
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 02:00:47 +01:00
Joachim Wiberg b00e7394f8 Update ChangeLog and bump version for v4.7-rc1
No more changes or fixes expected.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 01:51:15 +01:00
Joachim Wiberg d5a5fffa52 Update copyright years
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 01:50:50 +01:00
Joachim Wiberg 4d24c34b28 Update screenshot URL to point to HowTo
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 01:39:30 +01:00
Joachim Wiberg 355265651e Retake new screenshot, fix resolution
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 01:32:52 +01:00
Joachim Wiberg 41093df2a9 Attempt 2, scaled
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 01:27:03 +01:00
Joachim Wiberg 0a816d1fa4 Test bump Alpine screenshot
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 01:23:03 +01:00
Joachim Wiberg 3bfc0f0fca contrib/alpine: drop softdog, we are not built with finit-watchdogd
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 00:59:27 +01:00
Joachim Wiberg 0aa6ee895c contrib/alpine: follow-up to 2c340f83
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 00:59:18 +01:00
Joachim Wiberg b1526fb2d6 contrib/alpine: bump version
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 00:56:41 +01:00
Joachim Wiberg b2624ac160 contrib/alpine: fix install script, grep for contrib/alpine
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 00:56:11 +01:00
Joachim Wiberg 2c340f83ce contrib/alpine: fix syslog.conf vs syslogd.conf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-07 00:26:19 +01:00
Joachim Wiberg 337ee003bb Mount /dev/mqueue if missing and set sticky bit to /dev/shm
Inspired by Alpine Linux, add /dev/mqueue if missing.  We should check
the /proc/filesystems first, but this is quicker.

The sticky bit ensures only the owner of files in /dev/shm can delete or
rename files.  This is also what Alpine Linux use.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 23:50:30 +01:00
Joachim Wiberg 791df0c986 Refactor, ensure basenm() returns a const char pointer of its arg.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 23:46:17 +01:00
Joachim Wiberg f29e92be21 Minor, update
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 20:02:45 +01:00
Joachim Wiberg 379a63fce4 .github: adjust path for cov-build
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 19:55:55 +01:00
Joachim Wiberg b1f9a11809 .github: update actions, sync coverity with latest
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 19:51:37 +01:00
Joachim Wiberg 2d9c63e48e test: actually verify the service asserts ready before continuing
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 16:31:45 +01:00
Joachim Wiberg d66455496a Fix #392: ensure 'ready' condition is cleared on pidfile removal
A service with notify:pid is 'ready' when the pidfile has been created,
the converse also holds true -- when a pidfile is removed the service is
no longer 'ready'.

The state transition for the service has probably already been done, in
svc_set_state(), clearing all <service/foo/*> conditions when the PID
was collected.  The pidfile event may arrive later, so for completeness
we make sure the 'ready' condition is not recreated at least.

Problem introduced in 912a281 with the original supoport for service
readiness notification.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 12:25:41 +01:00
Joachim Wiberg 77cf72cb40 test: regression test to reproduce issue #392
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 12:03:33 +01:00
Joachim Wiberg 6cc587068b Log service identifier, not process name, in debug message
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 11:59:46 +01:00
Joachim Wiberg cc96e8908a Open v4.7 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 11:59:33 +01:00
Joachim Wiberg adb25d52cd test: minor, rename test case native -> pid
We now support notify:pid, so let's use it, even though it's the default.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-06 10:13:13 +01:00
Joachim Wiberg 7d09567ec8 Mention cgroup.root workaround to Linux SCHED_RR limitation
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-05 10:27:03 +01:00
Joachim Wiberg 9130af1c77 Merge pull request #390 from Stargirl-chan/master
Fix compilation on musl by implementing a custom basename

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-12-29 14:57:10 +01:00
Stargirl-chan cbea83b369 Simplified function comment and follow coding style 2023-12-29 13:37:08 +01:00
Stargirl-chan 42cd8d284b Implement custom basename function (basenm)
There exist two possible basename functions, a xpg compliant one in libgen.h
and a GLIBC exclusive one declared in string.h, that was previously also declared by musl libc.
Both implementations are expecting different parameter types (`const char *` for GLIBC and `char *` for xpg)

With the removal of the basename function from string.h in musl libc, we could only rely on the xpg implementation.

Unfortunately, the xpg implementation of basename does modify the contents of whatever you put in it,
even though that there really is no need for it.

This is an issue in some cases, where we might want to get the basename of a read-only variable, e.g. a `const char *`,
as trying to modify something read-only is undefined behavior.

So in order to keep things consistent for us, we implement our own version of basename called `basenm`,
that does not modify the passed argument.
2023-12-29 10:44:40 +01:00
Stargirl-chan 72ebc92622 Fix compilation on musl by using posix basename 2023-12-28 03:41:00 +01:00
Joachim Wiberg 06adecaaea Merge pull request #388 from soggyfries/soggyfries-log-fix
Fix log child exiting with debug disabled
2023-12-19 06:43:24 +01:00
Ryan Rorison efc0592961 Fix log child exiting with debug disabled 2023-12-18 21:00:45 -08:00
Joachim Wiberg ed88469276 Actually silence the log message, missing hunk for previous change
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-12-10 17:32:19 +01:00
Joachim Wiberg cbf96a1de0 Silence 'not available' log messages for nowarn run/task/service
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-12-10 16:42:29 +01:00
Joachim Wiberg cc979f27f1 tmpfiles.d: add missing /var/tmp and /var/lock -> /run/lock
- /var/tmp  https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html
 - /run/lock std Debian

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-22 08:08:24 +01:00
Joachim Wiberg fca5ce57ea Bump version for v4.6 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 07:03:30 +01:00
Joachim Wiberg 53aa195ad5 test: update, pid/B is no longer assert by Finit if notify != pid
As of Finit v4.6 we no longer assert the PID condition for services
declaring themselves as notify != pid.  We replace D with a forking
service to catch any future regressions in the pidfile plugin.

No need to check reload PID of D, it is enough to check PID of C.

Also, reduce the number of retries at startup.  If we haven't gone
up within 10 sec with this tiny config something is really wrong.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 06:09:35 +01:00
Joachim Wiberg e60211168e Fix type:forking regression in 66020f4, caught by tests
Premise, a service declaring itself 'notify:none' should never assert a
pid condition.  However, forking services still need to be supported and
the only way to do that is if they create a pid file.  Hence, instead of
skipping pidfile_update_conds() completely we need to filter the type.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 06:06:58 +01:00
Joachim Wiberg dc3ee9e467 Handle rare warning when registering configuration changes
2023-11-13T04:02:23 [WRN]: conf_change_act():failed registering /etc/finit.conf/ event mask 00000004: Not a directory

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 05:05:07 +01:00
Joachim Wiberg 6918f3b711 Update ChangeLog for v4.6
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 04:39:08 +01:00
Joachim Wiberg 66020f48ea Do not create PID conditions for services that do not support it
Follow-up to issue #386

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 04:37:03 +01:00
Joachim Wiberg 47b0d4cccf Reassert both PID and ready conditions when leaving paused state
Follow-up to issue #386

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 04:35:31 +01:00
Joachim Wiberg 92c2efa655 Minor, use svc_ident() instead of incomplete svc->name in debug logs
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-13 04:32:30 +01:00
Joachim Wiberg b69aa8a8bd Bump version for 4.6 bug fix release, rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 19:08:40 +01:00
Joachim Wiberg ca90bbfb04 Fix #387: sanity check environment variables before sourcing
This fixes an issue when finding a global environment variable with
spaces in the variable name:

    set COLORTERM=yes

Literally, 'set COLORTERM' was the name of the variable.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 19:07:54 +01:00
Joachim Wiberg 0b5c555c7f Add 'notify:pid' style readiness notifaction and 'readiness none'
This change expands the readiness notification system in Finit with the
native 'pid' style, which will remain the default readiness in Finit 4.x

For systems that want to transition to Finit 5.x early, a global option
to set 'readiness none' in /etc/finit.conf, has been added.  This change
the service default notification mode to 'notify:none', which can also
be set by Finit 4.x ('readiness pid') for select services.

Fixes #386.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 19:07:12 +01:00
Joachim Wiberg 6443995fc9 Fix #385: internal conditions are type oneshot, always active
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 09:04:35 +01:00
Joachim Wiberg 180faf8a40 test: minor, disable debug as final step in function
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 09:04:15 +01:00
Joachim Wiberg 0ebdd32f6b Fix #384: reassemble value fragments after wordexp() before setenv()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 08:50:12 +01:00
Joachim Wiberg 60bf858302 test: extend svc-env.sh with more common use-case
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-12 08:37:05 +01:00
Joachim Wiberg 7c86b40190 Fix #383: configure must expand FINIT_RUNPATH_ before define
This fixes an annying buglet that creeped in just before the v4.5 release
causing none of the internal services to be registered properly:

    conf_save_service():Failed creating ${localstatedir}/run/finit/system/dbus.conf: No such file or directory
    plugin_run_hook():Calling modules-load hook n:o 5 (arg: 0x55c4c8133621) ...
    load():Scanning /etc/modules-load.d for config files ...
    cond_set_oneshot():hook/svc/plugin
    cond_set_oneshot_noupdate():hook/svc/plugin => /run/finit/cond/hook/svc/plugin
    cond_update():hook/svc/plugin
    parse_conf():*** Parsing /etc/finit.conf
    conf_save_service():Failed creating ${localstatedir}/run/finit/system/runparts.conf: No such file or directory

The fix, like most, is simple when you find it.  We must expand $runstatedir
before creating the #define in config.h

For convenience, here's the patch for the generated configure script:

&<---------------------------[cut here]---------------------------
--- a/configure	2023-11-05 23:39:51.907334321 +0100
+++ b/configure	2023-11-05 23:39:58.339299795 +0100
@@ -15352,7 +15352,15 @@
 printf "%s\n" "#define FINIT_EXECPATH_ \"$pkglibexecdir\"" >>confdefs.h

-printf "%s\n" "#define FINIT_RUNPATH_ \"$runstatedir/finit/system\"" >>confdefs.h
+	finit_runpath="$runstatedir/finit/system"
+	finit_runpath=`(
+	    test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+	    test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+	    eval echo \""$finit_runpath"\"
+	    )`
+
+
+printf "%s\n" "#define FINIT_RUNPATH_ \"$finit_runpath\"" >>confdefs.h

&<---------------------------[cut here]---------------------------
Ensure you include the three empty lines for context at the end!

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-11-05 23:46:26 +01:00
Joachim Wiberg 4f3f140a09 Disable Bash completion in 'make distcheck'
We cannot rely on the auto-detection of Bash completion dir during 'make
distcheck' because autotools does not use DESTDIR, only --prefix for the
install check, and pkg-config returns a system path.

Also, show detected path in configure summary for debug.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 22:54:42 +01:00
Joachim Wiberg 10c24b1674 Minor, reorder alphabetically
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 22:53:20 +01:00
Joachim Wiberg 2b4f89ecd1 test: cannot use absolute path to initctl (distcheck)
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 22:09:54 +01:00
Joachim Wiberg c42a6f2869 Update ChangeLog and bump version for v4.5 GA
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 21:05:10 +01:00
Joachim Wiberg 89bb609a7e Update Filesystem Layout section slightly, tie in with bootmisc.so
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 21:04:02 +01:00
Joachim Wiberg da6298aecd test: wait for runparts to finish
In Finit v4.5 we've moved the start of rc.local and runparts to the
transtion from bootstrap to multi-user, so we must give it time to
finish.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 21:04:02 +01:00
Joachim Wiberg 576318cc29 Install Bash completion by default, auto-detect install path
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 20:47:11 +01:00
Joachim Wiberg 0d7d331ad4 Fix minor resource leak at boot, found by Coverity Scan
Introduced in release cycle, no need to document.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 20:11:48 +01:00
Joachim Wiberg c886ecb5cc Add support for multiple if:!foo,!bar to skip loading of service
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 19:25:10 +01:00
Joachim Wiberg 304a096877 test: wait for runparts to finish
In Finit v4.5 we've moved the start of rc.local and runparts to the
transtion from bootstrap to multi-user, so we must give it time to
finish.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 18:16:24 +01:00
Joachim Wiberg 064c7682fc Minor, do not append errno message
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 18:15:34 +01:00
Joachim Wiberg 58239b897b Silence Finit progress output for run/tasks stopping
Sync with Starting message in service_start(), should only be shown for
daemons and sysv services.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 18:01:13 +01:00
Joachim Wiberg 5281d82e80 Fix #378: add run/task support for <!> to allow transition from bootstrap
This odd little feature makes it possible to declare run/tasks with a
condition that does not block Finit transitioning from bootstrap to the
next runlevel.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 17:55:39 +01:00
Joachim Wiberg 5ff28c4dc6 system: minor, ignore generated file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 16:18:11 +01:00
Joachim Wiberg f2218836af Fix #378: warn on console if run/task times out during bootstrap
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 14:52:26 +01:00
Joachim Wiberg fbb3779d17 Fix bootstrap timeout (120 sec), off by a factor 10 (1200 sec)
Regression in v4.5 release cycle, no changelog notice needed.

Reported as part of issue #378 by Alexander Zangerl.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 13:50:43 +01:00
Joachim Wiberg 68f44f7a97 Fix #377: expand service env:file variables
This change allows us to support constructs like this:

    RUNDIR=/var/run/somesvc
    DAEMON_ARGS=--workdir $RUNDIR --other-args...

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 13:32:09 +01:00
Joachim Wiberg 50e587f447 test: new test, verify env:file variable expansion
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 13:31:36 +01:00
Joachim Wiberg fb4c560196 test: shellcheck fixes to new test
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 13:31:31 +01:00
Joachim Wiberg 8b5fa5eeaa test: add optional argument to sep() helper function
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 13:31:01 +01:00
Joachim Wiberg 88ec21e9cc plugins: change wording, we don't recreate machine-id every boot
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 10:14:32 +01:00
Joachim Wiberg 84adec4006 Fix #382: do not clear service conditions if only paused
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).

This patch not only adds this pre-condition to `cond_clearn()`, it
also clarifies which state (before or after) the particular code
is interested in.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 01:05:25 +01:00
Joachim Wiberg 19b2b2a279 test: follow-up to 2235fb83
Renamed .conf file for udev/mdev etc. caused 'mdev -df' to start in
tests.  This fix closes that again since none of that is needed in
our small namespaced world.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 01:02:33 +01:00
Joachim Wiberg e4163b7221 test: new test, issue #382
Alexander Zangerl reports that <service/foo/STATE> conditions seem to be
removed when calling `initctl reload`, even though no .conf changes have
been made.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-30 00:58:28 +01:00
Joachim Wiberg eaef302420 Drop doc/bootstrap.md, inaccurate and confusing to users
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-24 23:43:28 +02:00
Joachim Wiberg d5738da307 system: add support for mdevd, preferred over plain mdev
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 13:37:13 +02:00
Joachim Wiberg c9f930c7ad Skip registering service when if:!name matches a named svc_t
The delayed matcehd works when all run/task/services provide their own
unique identity, but for replacements this is sometimes not the case.

Example from system/10-hotplug.conf.in:

    run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/ready> \
	[S] mdevd-coldplug -- Cold plugging system

vs

    run nowarn conflict:udevd,mdevd cgroup.init name:coldplug if:!mdevd <service/mdev/running> \
	[S] @pkglibexecdir@/coldplug -- Cold plugging system

Here they both provide the <run/coldplug/*> conditions, and if the first
is loaded, because we found mdevd, then we should not attempt to load
this one.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 13:37:13 +02:00
Joachim Wiberg e2ee372b5d Fix #374: describe automount of /run, /tmp and tmpfiles.d support
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 12:18:42 +02:00
Joachim Wiberg 7ff7f93364 Fix #376: describe shell limitations with run/task stanzas
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 12:17:07 +02:00
Joachim Wiberg d5a95760ef Replace hardcoded /run/finit/system with configured path
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 11:49:37 +02:00
Joachim Wiberg 24d1425b74 Disable modprobe plugin by default, udevd and mdev loads modules
The updated 10-hotplug.conf now ensures modules are loaded, so we no
longer need the modprobe.so plugin to be enabled by default.

Also, update the hotplug "plugin" description, it is kept entirely
for backwards compatibility reasons after the plugin was converted
to 10-hotplug.conf.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 11:49:37 +02:00
Joachim Wiberg 43d9e25ba7 Fix #367: add support for mdev's netlink daemon mode
This commit replaces the `mdev -s` call to populate the device tree with
the "new" `mdev -df` daemon mode, introduced in BusyBox 1.31.0, 2019.

In daemon mode mdev listens to kernel uevents, replacing the hotplug use
of mdev.  After creating the netlink socket, 'mdev -df' performs the same
initial scan as 'mdev -s' did.

To perform device (re)discovery, module loading and setup, including any
firmware loading, a coldplug operation is typically required.  This is
done by the new /libexec/finit/coldplug script, by Alexander Zangerl.

Unlike 'mdevadm settle', mdev does not offer any mechanism to detect when
the discovery operation is done: on slower systems the triggering side,
the coldplug script, often completes quite a bit earlier than mdev's
uevent processing.  I.e., depending on <run/coldplug/success> is not an
indicator of all devices having been (re)discovered and fully set up.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-22 11:49:29 +02:00
Joachim Wiberg f27998ae4f Assert <int/container> condition if we detect running in container
Useful both for troubleshooting and for triggering if:<int/container> tasks.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-14 08:37:15 +02:00
Joachim Wiberg c8e0b6b9ef Redirect 'log*' output to console when finit.debug is enabled
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-14 08:34:06 +02:00
Joachim Wiberg f7e8fccb2f system: extend final udevadm settle timeout 5 -> 30 sec
On some systems udev may very well take more than five seconds to complete.
Probing modules, loading firmware, etc.  Note, the timeout only sets the
maximum wait time.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-14 08:29:08 +02:00
Joachim Wiberg 7bbccb1213 Silence non-critical failure to remove /run/finit/cond/ at reboot
The directory may hold various custom generated conditions that are not
managed by Finit.  Not being able to remove the directory is not a
critical error.

finit[1]: cond_delpath():Failed removing condition path /var/run/finit/cond/: Directory not empty

Therefore, ignore ENOENT and ENOTEMPTY and log everything/anything else.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-14 08:25:56 +02:00
Joachim Wiberg d38c333e04 Bump version for final candidate, v4.5-rc5
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-05 08:19:24 +02:00
Joachim Wiberg 095f6b645c Update ChangeLog, should be final changes for v4.5 GA
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 19:01:38 +02:00
Joachim Wiberg b4d10cbade Always ensure /run/finit/system exists before saving runtime service
This fixes the regression in the tests, which runs in a very stripped
down world without tmpfiles.d etc.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 18:48:13 +02:00
Joachim Wiberg 5d703fd39e Support delayed load of services from plugins and bundled services
This adds a new function conf_save_service() replacing service_register() for
plugins and bundled services like watchdogd, keventd, runparts, etc.

The benefits to this change are several:

 - Plugin/Bundled services no longer risk starting before udev or other
   critical services/task have started
 - Definitions can be overridden by an administrator (see docs)
 - Increases visibility (user: where are all these services coming from?)
   Previously the origin (file the service was loaded from) was NULL.
 - Adds another level of extensibility to Finit

The most notable change is that dbus is no longer started before udevd.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 18:37:43 +02:00
Joachim Wiberg eaaf8d862e Minor, append _ to PATH constant
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 18:25:09 +02:00
Joachim Wiberg 2468f11cd8 plugins: fix dbus pidfile locator
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 18:20:50 +02:00
Joachim Wiberg f8a6a119ac system: new name for testserv.conf -> 90-testserv.conf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 17:30:08 +02:00
Joachim Wiberg 1889b88aab Log execution order at bootstrap to /run/finit/exec.order
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 17:21:11 +02:00
Joachim Wiberg 0d70023bfe Log conf file evaluation order at bootstrap to /run/finit/conf.order
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 17:20:15 +02:00
Joachim Wiberg 41648a073b Fix evaluation order of /lib/finit/system/* vs /etc/finit.d/*
See updated documentation and inline comment for details.

Fix #371

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 17:20:15 +02:00
Joachim Wiberg 33cee0ba5f system: fix lost udevadm calls due to overloading
The system/10-hotplug.conf needs to index its calls to udevadm for all
calls to udevadm, not just the trigger calls.  Otherwise the first
udevadm is overloaded with all subseequent (unindexed) udevamd stanzas.

Also, make sure all udevadm calls to settle/reload are hidden.

Fix #372

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 17:19:46 +02:00
Joachim Wiberg 2235fb8352 system: rename *.conf files to ensure proper execution order
At bootstrap we want to start udev as soon as possible (after any
services registered by plugins).

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-04 11:39:39 +02:00
Joachim Wiberg eb9e94935e Failure to open fstab should log to console, reboot if no sulogin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 17:56:49 +02:00
Joachim Wiberg fb230f2137 .github: add makeLatest flag based on non-rc/beta/alpha
Note, the makeLatest flag can also be set to 'legacy', which takes
latest date and version.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 17:42:20 +02:00
Joachim Wiberg 6aa48a8b32 .github: fix pre-release flag input
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 17:41:52 +02:00
Joachim Wiberg 5b9cebbfd3 Update ChangeLog and bump version for v4.5-rc4
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 16:51:03 +02:00
Joachim Wiberg 38791616e0 Add commented-out developer debug for svc_enabled()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 16:39:46 +02:00
Joachim Wiberg fede3fd2e1 Fix #370: document conditional loading and execution config options
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 16:39:46 +02:00
Joachim Wiberg a46a33238d Display 'run' stanza progress only when they've completed
This is a follow-up to 4701ede.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 16:39:46 +02:00
Joachim Wiberg afe0488bf2 Add support for runtime evaluation of if:<condition> statements
The if: statement, introduced in v4.4, allows for discarding run/task/services
that depend on other services, based on that service's name, or condition.
Discarding in this context means unloading from the configuration.

At runtime, however, it has proven quite useful to be able to conditionally
qualify a run/task/service based on a condition.  Consider this example from
the Infix operating system:

run name:startup log:prio:user.notice \
	[S] <pid/sysrepo> confd -b --load startup-config -- Loading startup-config

run name:failure log:prio:user.critical if:<usr/fail-startup> \
	[S] <pid/sysrepo> confd --load failure-config -- Loading failure-config

The two run statements reside in the same .conf file so Finit runs them in true
sequence.  If loading the file `startup-config` fails confd sets the condition
usr/fail-startup, thus allowing the next run statement to load `failure-config`.

Notice the difference between <pid/sysrepo> condition and if:<usr/fail-startup>.
The former is a condition for starting and the latter is a condition to check if
a run/task/service is qualified to even be considerered.  The best comparison is
with the [runlevel] option, it too is used to qualify.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 16:39:46 +02:00
Joachim Wiberg ec5e42694d Silence noisy debug messages, useful only to developers
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 15:14:02 +02:00
Joachim Wiberg 2e73563eea Fix #369: allow runlevel change using initctl during bootstrap
This change opens up the runlevel change API from bootstrap.  The twist
is that the change is only queued, i.e., the call `initctl runlevel 9`
during bootstrap only changes the configured runlevel to go to after
bootstrap has completed.

Effectively, this change allows overriding the `runlevel` directive in
/etc/finit.conf without having to change the file.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-10-03 15:11:33 +02:00
Joachim Wiberg 338521a748 Update ChangeLog and bump for v4.5-rc3
No more changes are expected after -rc3.  Will be used for testing in
Infix and br2-ext-finit before the final v4.5 GA.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-24 14:04:28 +02:00
Joachim Wiberg 6ae1083c99 Add support for SysV-only scripts in runparts
This patch extens the SysV compatibility support in Finit by adding
support for limiting `runparts` to run only SNNfoo, or KNNfoo, style
scripts from a directory.

Additionally, by default `runparts` now runs entirely in the background
without any progress.  To enable progress, an optional argument has been
added to the runparts command line.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-24 13:25:35 +02:00
Joachim Wiberg 846806747b Fix #366: document fsck.* command line options and simplify code
As pointed out in #366, the configure options --enable-fastboot and
--enable-fsckfix should just alter the default values of the two fsck
command line options.

This commit simplifies the code and makes it possible to override using
the command line regardless of the two build options.

Finally, add the two command line options to doc/cmdline.md

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-24 11:58:07 +02:00
Joachim Wiberg 8904ca993e test: reindent
Standard Emacs shell-mode 4-space indent.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-18 06:38:59 +02:00
Joachim Wiberg efed0db16b test: reindent, don't warn on PID 0
PID 0 for a collected task is not a bug, 1 or < 0 is a bug.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-16 10:28:48 +02:00
Joachim Wiberg 11946f12d3 contrib: disable bundled watchdog for Alpine builds
In the Alpine reference builds we use 'watchdog' from the BusyBox suite.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-16 10:28:48 +02:00
Joachim Wiberg 2ba359ed80 Merge pull request #365 from markand/man-typo 2023-09-15 12:31:14 +02:00
David Demelier fafd524701 doc: fix typo in finit.8 manual page 2023-09-15 10:50:31 +02:00
Joachim Wiberg 1ee6c9f46b watchdogd: drop startup message, leaks to console
We use LOG_CONS to ensure log messages reach the operator, but since
watchdogd starts very early this means non-critical messages like the
initial greeting leaks to console because syslogd has not yet started.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-15 09:47:42 +02:00
Joachim Wiberg a88eb82a68 Simplify overly complex description, drop links to older versions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 10:03:49 +02:00
Joachim Wiberg a436a1c8cb .github: speed up release job, and support for setting pre-release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 09:40:55 +02:00
Joachim Wiberg 7cb91854b0 Update ChangeLog and bump version for v4.5-rc2
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 09:22:11 +02:00
Joachim Wiberg 939ae02a6a Increase MAX command, and arg., length: 64 -> 256
With non-standard paths, e.g., when running `make distcheck`, the
absolute path to some commands become ridiculously long.  However,
this has been a recurring issue for some users in the past, so it
is time to increase the capabilibieies of Finit to cover this.

Yes, a better way is probably to allocate all these strings when they
are used, but that would require a redesign of the initctl API and
likely cause a lot of regressions before everything has stabilized.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 09:15:55 +02:00
Joachim Wiberg 480d29175c test: minor, clarify
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 09:15:40 +02:00
Joachim Wiberg ea68413512 test: add missing scripts to dist for new runparts test
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 09:15:17 +02:00
Joachim Wiberg 4edfa9859e .github: fix variable sharing between jobs
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-14 09:14:28 +02:00
Joachim Wiberg eb6291c943 Update ChangeLog and bump version for v4.5-rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 13:26:33 +02:00
Joachim Wiberg 756b7c3fb6 Document advanced hooks/plugins to trigger rescue.conf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 13:03:20 +02:00
Joachim Wiberg 263aec292a Support for disabling invocation of rescue mode from kernel cmdline
The rescue mode that can be invoked from the kernel command line is
potentially unsafe.  Many systems lock the root user account, or use
another account for managing, e.g. 'admin'.  The sulogin program(s)
would on such systems give the user a root prompt.

In #357 we added support for setting a custom sulogin user, but for some
systems that is not enough.  On many embedded systems the /etc/passwd
and shadow files are populated at bootstrap and at the time rescue mode
runs, these files will be unpopulated.

The only, truly safe, approach on such systems is to disable rescue mode
completely.  Otherwise intricate Finit plugins have to be used that run
before rescue mode is started -- increasing the complexity of the system
as a whole.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 12:45:03 +02:00
Joachim Wiberg 5a946a4ea7 doc: clarify what single user mode does
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 12:44:33 +02:00
Joachim Wiberg c90b4d797b doc: clarify eval order of sulogins in traditional rescue mode
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 12:44:00 +02:00
Joachim Wiberg 6e7a2fb6d5 Fix #357: allow sulogin with user different from 'root'
In issue #357 there's a proposal for optionally allowing /bin/login, but
after intense discussions we've agreed that would be opening up for all
sorts of potential (security) issues.

it's better to keep things as-is but with the added twist of supporting
a custom user at configure time, e.g., 'admin'.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 11:37:15 +02:00
Joachim Wiberg ddedcf77e8 Follow-up to 4701ede: reschedule bootstrap check while not done
Non-trivial systems, like Infix[1], require more than one lap around the
track to warm up.  This is a follow-up to issue #362, commit 4701ede, in
fixing an obvious oversight in the new sm_check_bootstrap() work.  While
there are still outstanding bootstrap tasks or services that have not
yet started, we must reschedule the worker.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-13 09:35:02 +02:00
Joachim Wiberg 924ec2ef80 test: add missing runlevel/ref.log
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 21:18:28 +02:00
Joachim Wiberg a49f27c191 initctl: show runlevel 'N S' instead of 'N 10' during bootstrap
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 14:05:11 +02:00
Joachim Wiberg b41b4ce989 test: new, verify runparts order
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 14:04:26 +02:00
Joachim Wiberg 3d74e93fa2 test: when rc.local is busy, delay test until it's free
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 14:03:43 +02:00
Joachim Wiberg 443700a88e test: new, verify that a run task can call initctl
Follow-up to #362

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:30:57 +02:00
Joachim Wiberg 4701edef4c Fix #362: prevent blocking main loop when starting run tasks
Drop complete() logic, waiting for run tasks to finish, from the
service_start() funciton to the general service_monitor().  This
refactor frees up the main loop and allows us to answer any API
calls from initctl even from the run task itself.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg e6da0a22e7 Helper script for development/test
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg 7be2bbbc30 doc: add SysV Init Compatibility section
Minor updates and fixes to other sections as well.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg 3e269c632f Start runparts with -d in debug mode, otherwise -p for progress
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg f2507d9fd7 runparts: fix arg handling and skip backup files
For some specialized forms of runparts, e.g., start-stop scripts in SysV
init replacements, there is a need to append an argument.  Typically
this is 'start' or 'stop'.

This functionality has been broken for quite some time, meaning we
should consider it being unused by current users of Finit.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg e9f403bceb runparts: simplify and adjust log levels
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg c03176c42a doc: relocate text to common TODO file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg 9707bfb103 TODO: things to fix before release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg 11430f83c8 Use unbuffered stderr for runparts logging result and progress
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg a22a794f55 Clarify usage text slightly
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg 5556501287 dbg(): add missing \n for stderr logginge
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg ab554568b2 test: handle very short tests that exit before reaching runlevel 2
Bootstrap-only tests that just verify basic functionality are often very
short.  This change handles that by retrying SIGUSR2 until Finit has had
the chance to finalize bootstrap and enable signals.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg b39a4498a3 test: enable bootstrap-crash, regression test for #351
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-09-10 13:16:09 +02:00
Joachim Wiberg dead2444e2 doc: 'run' command limitation, blocks Finit completely
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-30 10:21:07 +02:00
Joachim Wiberg a58002588e Refactor initial startup, run runparts and rc.local in background
The code refactored in this commit has long been an eyesore.  The
hand-over, from the sequential main() function, to the event loop
was clumsy at best and was very difficult to debug.

Instead of using a series of workers we now delegate everything to
the big state machine by introducing a new SM_BOOTSRTAP_WAIT_STATE.

Both the runparts and rc.local scripts now run in the background, no
longer blocking the event loop from responding to initctl calls.  To
ensure they run at the same point in time two things have been done:

 1. A new <int/bootstrap> condition has been added which triggers
    runparts, which now is a regular task created by conf_init()
 2. /etc/rc.local is started from SM_RUNLEVEL_WAIT_STATE when we
    transition from runlevel S to any other runlevel.

Fixes #356

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-30 10:09:34 +02:00
Joachim Wiberg 28e101aaae Minor, ensure we can call exec_runtask() with NULL args
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-29 23:22:07 +02:00
Joachim Wiberg 6da8af8136 Minor, add debug logs and clarify comment
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-29 23:21:27 +02:00
Joachim Wiberg 3069e753e1 getty: add missing '-p' in usage text
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-27 13:34:45 +02:00
Joachim Wiberg aafd5c1010 Allow overriding SCREEN_WIDTH
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-27 13:33:57 +02:00
Joachim Wiberg 2f51c8ea0d test: minor, log() -> inf()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-27 13:33:22 +02:00
Joachim Wiberg d1130473fc Follow-up to 1fc0f36, missing %s argument
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-27 13:33:00 +02:00
Joachim Wiberg b682a5e4fe Fix #360: Bash completion for initctl
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-17 07:31:59 +02:00
Joachim Wiberg 1fc0f36c6c initctl: check [enable | disable] for absolute path, not supported
For reference, see issue #359.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-11 08:06:46 +02:00
Joachim Wiberg 5df5b22327 man: update finit.conf(5) with info on enabled and available
This should clarify the messup on the behalf of the mainatiner in not
documenting this properly, including the deviations introduced in v4.4

See issue #359 for a background.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-11 07:57:57 +02:00
Joachim Wiberg 4153c7966d Fix #358: fix modify events for /etc/finit.conf
- iwatch events return filenames in dir field, ignore file for those
 - improve warning message on failure
 - drop bogus "Out of memory" error log message

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-10 14:20:36 +02:00
Joachim Wiberg 458d68533f Update ChangeLog
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-10 13:37:25 +02:00
Joachim Wiberg 63b5db38df Refactor, ensure pre:/post:/ready: scripts run in the same cgroup
Related to issue #361.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-10 13:25:11 +02:00
Joachim Wiberg 2135639508 Update changelog with latest fixes
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-10 10:27:29 +02:00
Joachim Wiberg 9c8cd6c024 Improved logging on failure to execvp() in forked child
The execvp() call always fails with -1, so only logging exit code when
collecting the PID is not enough.  When debugging the user needs to see
the errno from execvp(), e.g., "No such file or directory", when the
command was missing the absolute path to the executable.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-10 10:23:20 +02:00
Joachim Wiberg 450f498061 Fix #361: cgroup move fail if starting service as non-root
Regression in v4.4

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-07-10 10:23:20 +02:00
Joachim Wiberg 5769500afe Bump devel version and update ChangeLog for v4.5 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-06-27 12:33:16 +02:00
Joachim Wiberg dc61969164 Check in service_stop() if the process is already dead
Related to 6f0d448 in that we check if the kernel knows about this
process before we try to stop it.  If it's already dead we clean up
and return.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-06-27 12:22:59 +02:00
Joachim Wiberg 6f0d448765 Fix #227: delayed service_kill() may stall shutdown/reboot
This turns out to be the root-cause of #227.  Finit is waiting forever
for proceeses to stop at shutdown/reboot, while a subreaper has already
collected the PID, or Finit for some reason did not collect the PID.

When the process timeout calls service_kill() we now check if the kernel
actually knows of this process or not.  If it's already been collected,
we can notify Finit of this by calling service_monitor() to clean up the
'svc' and in turn call sm_step() to finalize the state transition.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-06-27 12:18:09 +02:00
Joachim Wiberg 0c9b7a67e0 doc/plugins.md: fix script hook path
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-06-27 12:14:26 +02:00
Joachim Wiberg 5db2fb2c32 initctl: let -f force-skip check for built-in service
When calling `initctl -b create` from a start script at bootstrap you
risk blocking the boot since Finit currently cannot reply to IPC during
that period.

This patch allows -f to override this builtin check for the following
initctl commands:

 - touch
 - show
 - edit
 - create
 - delete

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-05-20 10:25:02 +02:00
162 changed files with 2985 additions and 1270 deletions
+2 -2
View File
@@ -28,7 +28,7 @@ jobs:
run: | run: |
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Static Finit - name: Static Finit
run: | run: |
./autogen.sh ./autogen.sh
@@ -61,7 +61,7 @@ jobs:
run: | run: |
make check || (cat test/test-suite.log; false) make check || (cat test/test-suite.log; false)
- name: Upload Test Results - name: Upload Test Results
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: finit-test-${{ matrix.compiler }} name: finit-test-${{ matrix.compiler }}
path: test/*.log path: test/*.log
+40 -16
View File
@@ -15,22 +15,39 @@ jobs:
coverity: coverity:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - name: Fetch latest Coverity Scan MD5
id: coverity-toolchain-cache id: var
with:
path: cov-analysis-linux64
key: ${{ runner.os }}-coverity
- name: Download Coverity Scan
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
env: env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: | run: |
wget -q https://scan.coverity.com/download/cxx/linux64 \ wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \ --post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
-O cov-analysis-linux64.tar.gz -O coverity-latest.tar.gz.md5
mkdir cov-analysis-linux64 echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 - uses: actions/cache@v3
id: cache
with:
path: coverity-latest.tar.gz
key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
restore-keys: |
${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
${{ runner.os }}-coverity-
${{ runner.os }}-coverity
- name: Download Coverity Scan
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
if [ ! -f coverity-latest.tar.gz ]; then
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
-O coverity-latest.tar.gz
else
echo "Latest Coverity Scan available from cache :-)"
md5sum coverity-latest.tar.gz
fi
mkdir coverity
tar xzf coverity-latest.tar.gz --strip 1 -C coverity
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get -y update sudo apt-get -y update
@@ -42,13 +59,15 @@ jobs:
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip) (cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip) (cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig sudo ldconfig
- name: Build - name: Configure
run: | run: |
./autogen.sh ./autogen.sh
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd ./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH - name: Build
run: |
export PATH=`pwd`/coverity/bin:$PATH
cov-build --dir cov-int make cov-build --dir cov-int make
- name: Submit result to Coverity Scan - name: Submit results to Coverity Scan
env: env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: | run: |
@@ -61,3 +80,8 @@ jobs:
--form version=trunk \ --form version=trunk \
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \ --form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
https://scan.coverity.com/builds?project=${COVERITY_PROJ} https://scan.coverity.com/builds?project=${COVERITY_PROJ}
- name: Upload build.log
uses: actions/upload-artifact@v4
with:
name: coverity-build.log
path: cov-int/build-log.txt
+20 -1
View File
@@ -10,12 +10,29 @@ jobs:
name: Build and upload release tarball name: Build and upload release tarball
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
MAKEFLAGS: -j3
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Installing dependencies ... - name: Installing dependencies ...
run: | run: |
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install pkg-config jq libuev-dev libite-dev sudo apt-get -y install pkg-config jq libuev-dev libite-dev
- name: Setting release variables ...
id: build
run: |
ver=${GITHUB_REF#refs/tags/}
echo "ver=${ver}" >> $GITHUB_OUTPUT
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
echo "pre=true" >> $GITHUB_OUTPUT
else
echo "pre=false" >> $GITHUB_OUTPUT
fi
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
echo "latest=true" >> $GITHUB_OUTPUT
else
echo "latest=false" >> $GITHUB_OUTPUT
fi
- name: Creating Makefiles ... - name: Creating Makefiles ...
run: | run: |
./autogen.sh ./autogen.sh
@@ -36,5 +53,7 @@ jobs:
- uses: ncipollo/release-action@v1 - uses: ncipollo/release-action@v1
with: with:
name: Finit v${{ github.ref_name }} name: Finit v${{ github.ref_name }}
prerelease: ${{ steps.build.outputs.pre }}
makeLatest: ${{ steps.build.outputs.latest }}
bodyFile: "release.md" bodyFile: "release.md"
artifacts: "artifacts/*" artifacts: "artifacts/*"
+3 -3
View File
@@ -13,8 +13,9 @@ jobs:
outputs: outputs:
run: ${{ steps.check.outputs.run }} run: ${{ steps.check.outputs.run }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Check for any commits since last week - name: Check for any commits since last week
id: schedule
run: | run: |
commits="$(git log --format=%H --since='1 week ago')" commits="$(git log --format=%H --since='1 week ago')"
if [ -n "$commits" ]; then if [ -n "$commits" ]; then
@@ -22,7 +23,6 @@ jobs:
else else
echo "run=false" >> $GITHUB_OUTPUT echo "run=false" >> $GITHUB_OUTPUT
fi fi
distcheck: distcheck:
needs: schedule needs: schedule
if: ${{ needs.schedule.outputs.run == 'true' }} if: ${{ needs.schedule.outputs.run == 'true' }}
@@ -32,7 +32,7 @@ jobs:
run: | run: |
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install pkg-config jq libuev-dev libite-dev sudo apt-get -y install pkg-config jq libuev-dev libite-dev
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Base run - name: Base run
run: | run: |
./autogen.sh ./autogen.sh
+4
View File
@@ -14,6 +14,7 @@ GTAGS
/autom4te.cache /autom4te.cache
/aclocal.m4 /aclocal.m4
/ar-lib /ar-lib
/backup/
/compile /compile
/config.cache /config.cache
/config.h /config.h
@@ -36,6 +37,9 @@ GTAGS
/test-driver /test-driver
/test-suite.log /test-suite.log
# Misc
/.gdb_history
# TroglOS build system # TroglOS build system
/.config /.config
/.stamp /.stamp
+149 -1
View File
@@ -4,6 +4,151 @@ Change Log
All relevant changes are documented in this file. All relevant changes are documented in this file.
[4.7][] - 2024-01-07
--------------------
### Changes
- Silence "not available" messages for run/task/service with `nowarn`
- Update docs, `cgroup.root` workaround for `SCHED_RR` tasks
- Drop runlevels 0 and 6 from `keventd`, not needed at reboot/poweroff
- Mount `/dev/shm` with mode 1777 (sticky bit)
- Mount `/dev/mqueue` if available, inspiration from Alpine Linux
- Update Alpine Linux installer and configuration files, tested on
Alpine v3.19, some assembly still required
### Fixes
- Fix confusing warning message when tmpfiles.d fails to install symlink
- Fix tmpfiles.d legacy `/run/lock/subsys`, ordering
- Add missing `/var/tmp` and `/var/lock -> /run/lock` (tmpfiles.d)
- Fix #388: log redirection broken unless Finit runs in debug mode.
Found and fixed by Ryan Rorison
- Fix #389: must libc requires `libgen.h` for `basename()` function.
Reported and worked around with new `basenm()` function by Stargirl
[4.6][] - 2023-11-13
--------------------
### Changes
- Add support for service `notify:pid` and `readiness none` global
option to change how Finit expects readiness notification, issue #386
### Fixes
- Fix #383: dbus and runparts regression in Finit v4.5. The configure
script must expand `FINIT_RUNPATH_` before defining it in `config.h`
- Fix #384: service environment variables drop everything but the first
argument, e.g., `VAR="foo bar qux"` drops everything but `foo`
- Fix #385: internal conditions, e.g., `<int/bootstrap>` turn into flux
when leaving bootstrap, causing depending services to stop
- Fix #387: global environment variables declared with `set VAR=NAME` do
not drop leading `set `, causing `'set VAR'='NAME'` in env.
- Sanity check environment variables, for services and globally. Ensure
the variable name (key) does not contain spaces, or a leading `set `
[4.5][] - 2023-10-30
--------------------
### Changes
- Refactor `runparts` and `/etc/rc.local` to no longer block the main
loop, allowing `initctl` calls to interact with Finit. Issue #356
- Refactor the `run` stanza to no longer block the main loop, issue #362
- Allow `sulogin` with a user different from `root`, issue #357
- Allow disabling invocation of rescue mode from kernel command line
- Add `initctl -f` to force-skip asking Finit for existing services
when creating new services during bootstrap, e.g. `/etc/rc.local`
- `initctl runlevel` now returns `N S` instead of `N 10` in bootstrap
- `initctl runlevel N` during bootstrap is now allowed. It changes
the next runlevel to go to when bootstrap has completed. Effectively
overriding the `runlevel N` statement in `/etc/finit.conf`
- 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 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/`
- The `runparts` code has been split into `/libexec/finit/runparts`
- The `runparts` command now takes two options: `sysv` and `progress`.
The former ensures only `SNNfoo` and `KNNfoo` scripts are run.
- Add SysV Init Compatibility section to documentation
- Increased MAX path for commands, and arguments: 64 -> 256
- The bundled watchdog daemon no longer tries to log at startup, because
syslog is not available yet, any startup message leak to console
- Extend `if:` option with runtime evaluation of conditions. E.g., start
a task only `if:<run/foo/failure>` (here the run task 'foo' failed)
- Document new `if:`, `conflict:`, `nowarn` options for run/task/service
first introduced in v4.4
- Failure to open fstab should log to console, not just log to `/dev/kmsg`
- Rename `/lib/finit/system/*.conf`, added numbered prefix to ensure
proper execution order, e.g., `udevd` should always run first
- 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
actually that Finit was waiting for a process that was no longer in
the system. The fix is to ask the kernel on process-stop-timeout and
replay the lost PID so that Finit can continue with reboot/shutdown
- Fix #358: fix inotify events for `/etc/finit.conf`, improved log
messages and error handling
- Fix #361: cgroup move fail if run/task/services start as non-root.
Regression in the v4.4 release cycle while adding support for the
pre:/post:/ready: scripts. Now the latter scripts also properly run
in their correct cgroup
- Fix #366: document `fsck.*` kernel command line options and simplify
the configure flags `--enable-fsckfix` and `--enable-fastboot` to
only adjust the default values for the `fsck.*` options.
- Fix #371: swap load order of `/lib/finit/system/*` vs `/etc/finit.d/*`
We must run `10-hotplug.conf` first to ensure devices and modules are
up and loaded before the user's run/task/services are called. The order
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 [4.4][] - 2023-05-15
-------------------- --------------------
@@ -1510,7 +1655,10 @@ Major bug fix release.
* Initial release * Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.3...HEAD [UNRELEASED]: https://github.com/troglobit/finit/compare/4.7...HEAD
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4 [4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3 [4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2 [4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+8 -3
View File
@@ -10,6 +10,10 @@ if DOC
SUBDIRS += doc SUBDIRS += doc
endif endif
if BASH
bashdir = $(BASH_DIR)
dist_bash_DATA = initctl
endif
# Compat hook # Compat hook
install-dev: install-dev:
@make -C src install-pkgincludeHEADERS @make -C src install-pkgincludeHEADERS
@@ -30,6 +34,7 @@ release: distcheck
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \ printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
done done
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \ DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
--enable-testserv-plugin --enable-x11-common-plugin \ --enable-testserv-plugin --enable-x11-common-plugin \
--with-watchdog --with-keventd --with-fstab=/etc/fstab --with-watchdog --with-keventd --with-fstab=/etc/fstab \
--with-bash-completion-dir=no
+9 -8
View File
@@ -3,7 +3,6 @@
* [Introduction](#introduction) * [Introduction](#introduction)
* [Features](#features) * [Features](#features)
* [Bootstrap](doc/bootstrap.md#bootstrap)
* [Runlevels](#runlevels) * [Runlevels](#runlevels)
* [Syntax](doc/config.md#syntax) * [Syntax](doc/config.md#syntax)
* [Runparts & /etc/rc.local](#runparts--etcrclocal) * [Runparts & /etc/rc.local](#runparts--etcrclocal)
@@ -23,11 +22,10 @@ Introduction
------------ ------------
Fast init for Linux systems. Reverse engineered from the [EeePC Fast init for Linux systems. Reverse engineered from the [EeePC
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled fastinit][] by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
with frog DNA …"
![Alpine screenshot](img/finit4-screenshot.png) ![Alpine screenshot](img/alpine-screenshot2.png)
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).* *Figure 1: Screenshot of Finit booting [Alpine Linux (HowTo)](https://github.com/troglobit/finit/tree/master/contrib/alpine).*
Features include: Features include:
@@ -66,7 +64,9 @@ distributions:
> **Note:** support for various Linux distributions does not mean Finit > **Note:** support for various Linux distributions does not mean Finit
> installs easily on all architectures. The bundled install scripts are > installs easily on all architectures. The bundled install scripts are
> examples for standard installations, tested on amd64 (x86_64) systems. > examples for standard installations, tested on amd64 (x86_64) systems.
> Custom setups, for embedded systems, can be found in [myLinux][]. > Custom setups, e.g., for embedded systems, can be found in any of the
> following [Buildroot][] based examples: [myLinux][], [Infix][], or the
> plain [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
Example Example
@@ -391,8 +391,7 @@ Right after the runlevel change when all services have started properly,
No configuration stanza in `/etc/finit.conf` is required for `rc.local`. 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 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 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/plugins.md](doc/plugins.md#hooks).
in [doc/bootstrap.md](doc/bootstrap.md).
### Limitations ### Limitations
@@ -707,6 +706,8 @@ and proposed extensions.
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process [EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
[Claudio Matsuoka]: https://github.com/cmatsuoka [Claudio Matsuoka]: https://github.com/cmatsuoka
[Joachim Wiberg]: https://troglobit.com [Joachim Wiberg]: https://troglobit.com
[Buildroot]: https://buildroot.org
[Infix]: https://kernelkit.github.io
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html [finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
[License]: https://en.wikipedia.org/wiki/MIT_License [License]: https://en.wikipedia.org/wiki/MIT_License
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg [License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
-1
View File
@@ -1 +0,0 @@
Executable
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
# Run test suite with the correct configure params
make distclean
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --with-watchdog --with-keventd
make -j17 clean check
+51 -15
View File
@@ -1,4 +1,5 @@
AC_INIT([Finit],[4.4],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/]) AC_INIT([Finit], [4.7], [https://github.com/troglobit/finit/issues],
[finit], [https://troglobit.com/projects/finit/])
AC_CONFIG_AUX_DIR(aux) AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects]) AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
@@ -14,10 +15,10 @@ AC_CONFIG_FILES([Makefile
man/Makefile man/Makefile
plugins/Makefile plugins/Makefile
src/Makefile src/Makefile
system/Makefile system/Makefile system/10-hotplug.conf
tmpfiles.d/Makefile
test/test.env test/Makefile 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() # Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
#m4_include([m4/plugin.m4]) #m4_include([m4/plugin.m4])
@@ -71,7 +72,7 @@ AC_ARG_ENABLE(redirect,
enable_redirect=yes]) enable_redirect=yes])
AC_ARG_ENABLE(logrotate, AC_ARG_ENABLE(logrotate,
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[ AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[
enable_logrotate=yes]) enable_logrotate=yes])
AC_ARG_ENABLE(doc, AC_ARG_ENABLE(doc,
@@ -82,6 +83,10 @@ AC_ARG_ENABLE(contrib,
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[ AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
enable_contrib=yes]) enable_contrib=yes])
AC_ARG_ENABLE([rescue],
AS_HELP_STRING([--disable-rescue], [Disable potentially unsafe rescue mode]),,
[enable_rescue=yes])
# Check for extra plugins to enable # Check for extra plugins to enable
AC_ARG_ENABLE(all_plugins, AC_ARG_ENABLE(all_plugins,
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]), AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
@@ -89,18 +94,22 @@ AC_ARG_ENABLE(all_plugins,
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl]) 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([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([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([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)]) 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([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([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([rtc], [yes], [Save and restore RTC using hwclock])
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial]) 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([urandom], [yes], [Setup and save random seed at boot/shutdown])
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon]) AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
# Check for extra arguments or packages # 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, AC_ARG_WITH(fstab,
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]), AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
[fstab=$withval], [fstab=yes]) [fstab=$withval], [fstab=yes])
@@ -145,10 +154,10 @@ AC_ARG_WITH(keventd,
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no]) AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
AC_ARG_WITH(sulogin, AC_ARG_WITH(sulogin,
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no]) AS_HELP_STRING([--with-sulogin@<:@=USER@:>@], [Enable built-in sulogin, optional USER to request password for (default root), default: no.]),[sulogin=$withval],[with_sulogin=no])
AC_ARG_WITH(watchdog, AC_ARG_WITH(watchdog,
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]), AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]),
[watchdog=$withval], [with_watchdog=no watchdog=]) [watchdog=$withval], [with_watchdog=no watchdog=])
AC_ARG_WITH(hook-scripts-path, AC_ARG_WITH(hook-scripts-path,
@@ -185,9 +194,18 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
AS_IF([test "x$enable_logrotate" != "xno"], [ AS_IF([test "x$enable_logrotate" != "xno"], [
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])]) AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
AS_IF([test "x$enable_rescue" != "xno"], [
AC_DEFINE([RESCUE_MODE], 1, [Define to enable support for rescue mode.])])
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"]) AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
### With features ############################################################################## ### 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$with_fstab" != "xno"], [
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab]) AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
AC_EXPAND_DIR(fstab_path, "$fstab") AC_EXPAND_DIR(fstab_path, "$fstab")
@@ -252,7 +270,12 @@ AS_IF([test "x$rtc_date" != "xno"], [
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes]) AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes]) AS_IF([test "x$with_sulogin" != "xno"], [
AS_IF([test "x$sulogin" = "xyes"], [
sulogin=root])
with_sulogin=yes
AC_DEFINE_UNQUOTED(SULOGIN_USER, "$sulogin", [Built-in sulogin user, default: root])], [
sulogin=])
AS_IF([test "x$with_watchdog" != "xno"], [ AS_IF([test "x$with_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [ AS_IF([test "x$watchdog" = "xyes"], [
@@ -272,19 +295,27 @@ 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])]) 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 # 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(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"]) AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "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(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "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 # Override default libdir, used for plugins and rescue.conf
pkglibdir=$libdir/finit pkglibdir=$libdir/finit
AC_SUBST(pkglibexecdir) AC_SUBST(pkglibexecdir)
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit") AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path]) AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
AC_EXPAND_DIR(finit_runpath, "$runstatedir/finit/system")
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$finit_runpath", [Finit runtime dynamic system services])
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins") AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
AC_SUBST(plugin_path) AC_SUBST(plugin_path)
@@ -292,7 +323,7 @@ AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d") AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d")
AC_SUBST(tmpfiles_path) AC_SUBST(tmpfiles_path)
AC_DEFINE_UNQUOTED(TMPFILES_PATH, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc]) AC_DEFINE_UNQUOTED(TMPFILES_PATH_, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc])
AC_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d") AC_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d")
AC_SUBST(finit_tmpfiles) AC_SUBST(finit_tmpfiles)
@@ -300,13 +331,16 @@ AC_DEFINE_UNQUOTED(FINIT_TMPFILES, "$finit_tmpfiles", [Finit tmpfiles.d/ .conf p
AC_EXPAND_DIR(system_path, "$pkglibdir/system") AC_EXPAND_DIR(system_path, "$pkglibdir/system")
AC_SUBST(system_path) AC_SUBST(system_path)
AC_DEFINE_UNQUOTED(FINIT_SYSPATH, "$system_path", [Static services, previously generated at runtime by plugins]) AC_DEFINE_UNQUOTED(FINIT_SYSPATH_, "$system_path", [Static services, previously generated at runtime by plugins])
AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf") AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf")
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf]) AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf") AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf")
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create]) 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" = ""], [heading="<DEFAULT>"])
AS_IF([test "$heading" = "no"], [heading="<NONE>"]) AS_IF([test "$heading" = "no"], [heading="<NONE>"])
@@ -343,13 +377,15 @@ Behavior:
Optional features: Optional features:
Install doc/..........: $enable_doc Install doc/..........: $enable_doc
Install contrib/......: $enable_contrib Install contrib/......: $enable_contrib
Bash completion.......: $bash_completion_dir
Built-in keventd......: $with_keventd Built-in keventd......: $with_keventd
Built-in sulogin......: $with_sulogin Built-in sulogin......: $with_sulogin $sulogin
Built-in watchdogd....: $with_watchdog $watchdog Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate Built-in logrotate....: $enable_logrotate
Skip fsck check.......: $enable_fastboot Skip fsck check.......: $enable_fastboot
Run fsck fix mode.....: $enable_fsckfix Run fsck fix mode.....: $enable_fsckfix
Redirect output.......: $enable_redirect Redirect output.......: $enable_redirect
Rescue mode...........: $enable_rescue
Default hostname......: $hostname Default hostname......: $hostname
Default group.........: $group Default group.........: $group
Default runlevel......: $runlevel Default runlevel......: $runlevel
+2 -2
View File
@@ -1,5 +1,5 @@
HowTo: Finit on Alpine Linux 3.4-3.6 HowTo: Finit on Alpine Linux 3.4...3.19
==================================== =======================================
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
the user has already installed make, a compiler, C library header files, the user has already installed make, a compiler, C library header files,
+1 -1
View File
@@ -17,7 +17,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--prefix=/usr --exec-prefix= \ --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \ --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-watchdog \ --enable-alsa-utils-plugin --without-watchdog \
--with-keventd --with-sulogin --with-keventd --with-sulogin
echo echo
+1 -2
View File
@@ -1,8 +1,7 @@
SUBDIRS = available SUBDIRS = available
docsdir := @docdir@/contrib/alpine/finit.d docsdir := @docdir@/contrib/alpine/finit.d
d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \ d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \
keymap.conf modules.conf ntpd.conf \ keymap.conf modules.conf ntpd.conf syslogd.conf
klogd.conf syslogd.conf
install-exec-hook: install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available @$(MKDIR_P) $(DESTDIR)$(docsdir)/available
+1 -1
View File
@@ -1,4 +1,4 @@
docsdir := @docdir@/contrib/alpine/finit.d/available docsdir := @docdir@/contrib/alpine/finit.d/available
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \ docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
lxdm.conf modules.conf ntpd.conf syslog.conf watchdog.conf lxdm.conf modules.conf ntpd.conf syslogd.conf watchdog.conf
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
@@ -4,4 +4,4 @@
#module evdev #module evdev
#module mousedev #module mousedev
#module 8139cp #module 8139cp
module softdog #module softdog
+35 -29
View File
@@ -1,45 +1,53 @@
#!/bin/sh #!/bin/sh
if [ "x`id -u`" != "x0" ]; then if [ "$(id -u)" != "0" ]; then
echo printf "\n\e[1m*** This script must run as root\e[0m\n\n"
echo "*** This script must run as root"
echo
exit 1 exit 1
fi fi
# shellcheck disable=SC3037,SC3045,SC2154
yorn()
{
printf "\e[1m> %s (y/N)?\e[0m " "$*"
read -rn1 yorn
echo
if [ "$yorn" = "y" ] || [ "$yorn" = "Y" ]; then
return 0
fi
return 1
}
# Adjust base directory # Adjust base directory
grep -q alpine Makefile 2>/dev/null if grep -q contrib/alpine Makefile 2>/dev/null; then
if [ $? -eq 0 ]; then
cd ../.. cd ../..
elif [ ! -e configure.ac ]; then fi
echo "*** Please run this script from the Finit base directory."
if [ ! -e configure.ac ]; then
printf "\n\e[1m*** Please run this script from the Finit base directory.\e[0m\n"
exit 1 exit 1
fi fi
echo printf "\n\e[1mInstall Finit on Alpine Linux\n"
echo "*** Install Finit on Alpine Linux" printf "========================================================================\e[0m\n"
echo "========================================================================" printf "/sbin/finit - PID 1\n"
echo "/sbin/finit - PID 1" printf "/lib/finit/plugins/* - All enabled Finit plugins\n"
echo "/lib/finit/plugins/* - All enabled Finit plugins" printf "/etc/finit.conf - Finit configuration file\n"
echo "/etc/finit.conf - Finit configuration file" printf "/etc/finit.d/ - Finit services\n"
echo "/etc/finit.d/ - Finit services"
echo
read -p "Do you want to continue (y/N)? " yorn
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then if yorn "Do you want to continue"; then
echo printf "\n\e[1m*** Installing Finit files ...\e[0m\n"
echo "*** Installing Finit files ..."
make install make install
cd /usr/share/doc/finit/contrib/alpine cd /usr/share/doc/finit/contrib/alpine || exit 1
for file in finit.conf rc.local; do for file in finit.conf rc.local; do
install -vbD $file /etc/$file install -vbD $file /etc/$file
done done
cp -va finit.d /etc/ cp -va finit.d /etc/
read -p "*** Install Finit as the system default Init (y/N)? " yorn if yorn "Install Finit as the system default Init"; then
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then printf "\e[1m*** Updating /sbin/init symlink --> finit ...\e[0m\n"
echo "*** Updating /sbin/init symlink --> finit ..." cd /sbin || exit 1
cd /sbin
rm init rm init
ln -s finit init ln -s finit init
@@ -48,10 +56,8 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
ln -s reboot shutdown ln -s reboot shutdown
ln -s reboot suspend ln -s reboot suspend
fi fi
echo "*** Done" printf "\n\e[1m*** Done\e[0m\n"
echo echo
else else
echo printf "\n\e[1m*** Aborting install.\e[0m\n\n"
echo "*** Aborting install."
echo
fi fi
-59
View File
@@ -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
+16 -4
View File
@@ -12,6 +12,15 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
* `debug`: Enable kernel debug. Debug messages are printed to the * `debug`: Enable kernel debug. Debug messages are printed to the
console until Finit starts up, unless `loglevel=7` (below) is used. console until Finit starts up, unless `loglevel=7` (below) is used.
* `fsck.mode=<auto,force,skip>`, default: `auto`, unless built with
`configure --enable-fastboot`, in which case the default is `skip`
* `fsck.repair=<preen,yes,no>`, default: `preen`, unless built with
`configure --enable-fsckfix`, in which case the default is `yes`.
This configure option also sets `fsck.mode=force`, unless fastboot
is selected at the same time. I.e., the `--enable-fastboot` build
option overrides the `fsck.mode` default value.
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally * `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
multiple conditions can be set using the same option, separated with a multiple conditions can be set using the same option, separated with a
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
@@ -86,13 +95,16 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
the system booted in a limited fallback mode. See [config.md][] the system booted in a limited fallback mode. See [config.md][]
for more information. for more information.
This option can be disabled with `configure --without-rescue`
**Note:** in this mode `initctl` will not work. Correct the problem **Note:** in this mode `initctl` will not work. Correct the problem
and use `reboot -f` to force reboot. and use `reboot -f` to force reboot.
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to * `single`, or `S`: Overrides the configured runlevel (default: 2) to go
debug problems with the regular runlevel. All services and TTYs in to after bootstrap by forcing it to runlevel 1, this is also known
`[1]` will be started, so a `tty [1] @console nologin` configuration as single user mode. Useful to debug startup problems. All services
presents you with a root console without login. and TTYs in `[1]` will be started, so a `tty [1] @console nologin`
configuration presents you with a root console without login.
* `1-9`, except `6`: override the configured `runlevel`. Like the `S` * `1-9`, except `6`: override the configured `runlevel`. Like the `S`
and `rescue`, giving a single number on the kernel command line tells and `rescue`, giving a single number on the kernel command line tells
+25
View File
@@ -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 during evaluation, i.e. all conditions must be satisfied in order for a
service to run. 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 ### 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 asserted. I.e., if the Zebra process above stops or restarts, netd
will also stop or restart. 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 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 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 done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
to do this, see `plugins/pidfile.c`. to do this, see `plugins/pidfile.c`.
[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html
+341 -106
View File
@@ -28,6 +28,7 @@ Finit Configuration
* [TTYs and Consoles](#ttys-and-consoles) * [TTYs and Consoles](#ttys-and-consoles)
* [Non-privileged Services](#non-privileged-services) * [Non-privileged Services](#non-privileged-services)
* [Redirecting Output](#redirecting-output) * [Redirecting Output](#redirecting-output)
* [SysV Init Compatibility](#sysv-init-compatibility)
* [Rescue Mode](#rescue-mode) * [Rescue Mode](#rescue-mode)
* [Limitations](#limitations) * [Limitations](#limitations)
* [/etc/finit.conf](#etcfinitconf) * [/etc/finit.conf](#etcfinitconf)
@@ -45,31 +46,86 @@ Plugins start at [hook points](plugins.md#hooks) and can run various set
up, or install event handlers that later provide runtime services, e.g., up, or install event handlers that later provide runtime services, e.g.,
PID file monitoring, or [conditions](conditions.md). PID file monitoring, or [conditions](conditions.md).
> **Tip:** see [SysV Init Compatibility](#sysv-init-compatibility) for
> help to quickly get going with an existing SysV or BusyBox init setup.
### Configuration Files ### Configuration Files
Originally Finit was configured using a single file, `/etc/finit.conf`. Originally Finit was configured using a single file, `/etc/finit.conf`,
Although still possible, today we recommended using the Apache-style and although still possible to use a single configuration file, today
`available/*.conf` and `enabled/*.conf` layaout. These are called the following layout is recommended:
dynamic services, in contrast to static -- the only difference being
where they are installed and if the `initctl` tool can manage them.
/etc/ /
|- finit.d/ |- etc/
| |- available/ | |- finit.d/
| | `- my-service.conf | | |- available/
: |- enabled/ | | | `- my-service.conf
: | `- my-service.conf -> ../available/my-service.conf | : |- enabled/
: : | : | `- my-service.conf -> ../available/my-service.conf
: |- static-service.conf | : :
: `- another-static.conf # eg. bootstrap run/task commands | : |- static-service.conf
: | : `- another-static.conf
`- finit.conf # global settings | :
| `- finit.conf
|- lib
| `- finit/
| `- system/
| |- 10-hotplug.conf
| `- ...
`- run/
`- finit/
`- system/
|- dbus.conf
|- keventd.conf
|- runparts.conf
|- watchdogd.conf
`- ...
Configuration files in `/etc` are provided by the user, or projects like
[finit-skel](https://github.com/troglobit/finit-skel) and extended by
the user.
The files in `/lib/finit/system/*.conf` are system critical services and
setup provided by Finit, e.g. udev/mdev that must run very early at system
bootstrap. This system directory was introduced in Finit v4.4 to replace
the hard-coded services provided by plugins before. All .conf files in this
directory be either replaced by a system administrator or overridden by a
file with the same name in `/etc/finit.d/`.
The files in `/run/finit/system/*.conf` are created by plugins and Finit
bundled services like runparts, the [watchdog](#watchdog), and `keventd`
if they are enabled. Like `/lib/finit/system/*.conf`, these files can
be overridden by file with the same name in `/etc/finit.d/`.
Services in the `available/` and `enabled/` sub-directories are called
dynamic services, in contrast to static services -- the only difference
being where they are installed and if the `initctl` tool can manage them
with the `enable` and `disable` commands. An administrator can always
create files and symlinks manually.
At bootstrap, and `initctl reload`, all .conf files are read, starting At bootstrap, and `initctl reload`, all .conf files are read, starting
with `finit.conf`, then, in alphabetical order, all `finit.d/*.conf` with `finit.conf`, then `/lib/finit/system/*.conf`, `finit.d/*.conf`,
files, and finally (still in alphabetical order) all `enabled/*.conf` and finally all `finit.d/enabled/*.conf` files. Each directory is a
files. unique group, where files within each group are sorted alphabetically.
**Example:**
/lib/finit/system/10-hotplug.conf
/lib/finit/system/90-testserv.conf
/run/finit/system/dbus.conf
/run/finit/system/runparts.conf
/etc/finit.d/10-abc.conf
/etc/finit.d/20-abc.conf
/etc/finit.d/enabled/1-aaa.conf
/etc/finit.d/enabled/1-abc.conf
The resulting combined configuration is read line by line, each `run`,
`task`, and `service` added to an ordered list that ensures they are
started in the same order. This is important because of the blocking
properties of the `run` statement. For an example on the relation of
`service` and `run` statements, and dependency handling between them,
see [Conditional Loading](#conditional-loading), below.
> **Note:** the `finit.conf` and `finit.d/` names are only defaults. > **Note:** the `finit.conf` and `finit.d/` names are only defaults.
> They can be changed at compile-time with two `configure` options: > They can be changed at compile-time with two `configure` options:
@@ -118,21 +174,25 @@ layout, as specified in the [FHS][]:
|- spool/ |- spool/
`- tmp/ `- tmp/
Finit starts (very early) by mounting `/dev`, `/proc/`, and `/sys`, Finit starts by mounting the critical file systems `/dev`, `/proc/`, and
unless they (i.e., `/dev`) are already mounted. When all plugins and `/sys`, unless they are already mounted. When all plugins and other,
other, core Finit functions, have been set up, all relevant filesystems core Finit functions, have been set up, all relevant filesystems (where
(`PASS > 0`) are checked and mounted from the selected `fstab`, either `PASS > 0`) are checked and mounted from the selected `fstab`, either
the default `/etc/fstab`, or any custom one selected from the command the default `/etc/fstab`, or any custom one selected from the command
line, or at build time. line, or at build time.
Any file system not listed `fstab` are automatically mounted by Finit, To provide a smooth ride, file system not listed in the given `fstab`,
as listed above, provided their respective mount point exists. 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`. 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 At shutdown, and after having stopped all services and other lingering
processes killed, filesystems are unmounted in the reverse order, and processes have been killed, filesystems are unmounted in the reverse
`swapoff` is called. order, and `swapoff` is called.
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html [FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
@@ -146,24 +206,30 @@ processes killed, filesystems are unmounted in the reverse order, and
- ` 0`: shutdown - ` 0`: shutdown
Runlevels are declared per service/run/task/sysv command. Starting in Runlevels are declared per service/run/task/sysv command. Starting in
runlevel S ([bootStrap](bootstrap.md)), usually only for tasks supposed runlevel S (bootStrap), usually only for tasks supposed to run once at
to run once at boot, and services like `syslogd`, which you need to boot, and services like `syslogd`, which you need to start and run
start and run throughout the whole time your system is up. Before `S` throughout the whole time your system is up.
is started, however, Finit performs a lot of housekeeping tasks like
mounting all filesystems, calling `fsck` if needed, and making sure the Before `S` is started, however, Finit performs a lot of housekeeping
everything is OK. tasks like mounting all filesystems, calling `fsck` if needed, and
making sure the everything is OK.
task [S] /lib/console-setup/console-setup.sh task [S] /lib/console-setup/console-setup.sh
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
After runlevel S, Finit proceeds to runlevel 2. (This can be changed in After runlevel S, Finit proceeds to runlevel 2. This can be changed in
`/etc/finit.conf` using the `runlevel N` directive.) Before starting `/etc/finit.conf` using the `runlevel N` directive, or by a script
the services in runlevel 2, Finit first stops everything that is not running in runlevel S that calls, e.g., `initctl runlevel 9`. The
allowed to run in 2, and then brings up networking. Networking is latter is useful if startup scripts detect problems outside of Finit's
expected to be available in all runlevels except: S, 1 (single user control, e.g., critical services/devices missing or hardware problems.
level), 6, and 0. Networking is enabled either by the `network script`
directive, or if you have an `/etc/network/interfaces` file, Finit calls Before starting the services in runlevel 2, Finit first stops everything
`ifup -a` -- at the very least the loopback interface is brought up. that is not allowed to run in 2, and then brings up networking.
Networking is expected to be available in all runlevels except: S, 1
(single user level), 6, and 0. Networking is enabled either by the
`network script` directive, or if you have an `/etc/network/interfaces`
file, Finit calls `ifup -a` -- at the very least the loopback interface
is brought up.
> **Note:** when moving from runlevel S to 2, all run/task/services that > **Note:** when moving from runlevel S to 2, all run/task/services that
> were constrained to runlevel S only are dropped from bookkeeping. So > were constrained to runlevel S only are dropped from bookkeeping. So
@@ -290,17 +356,31 @@ most notably systemd and s6, other methods for signaling "readiness"
arrived and daemons were adapted to these new schemes to a larger arrived and daemons were adapted to these new schemes to a larger
extent. extent.
As of Finit v4.4 partial support for systemd and s6 is available. The As of Finit v4.4 partial support for systemd and s6 style readiness
native PID file mode of operation is still default, the other's can be notification is available, and the native PID file mode of operation is,
defined per service, like this: as of Finit v4.6 optional, by default it is still enabled, but this can
be changed in `finit.conf`:
readiness none
This will be made the default in Finit 5.0. In this mode of operation,
every service needs to explicitly declare their readiness notification,
like this:
service notify:pid watchdogd
service notify:systemd foo service notify:systemd foo
service notify:s6 bar service notify:s6 bar
service notify:none qux
The `notify:none` syntax is for completeness in systems which run in
`readiness pid` mode (default). Services declared with `notify:none`
will assert ready condition as soon as Finit has started them, e.g.,
`service/qux/ready`.
To synchronize two services the following condition can be used: To synchronize two services the following condition can be used:
service notify:systemd A service notify:pid watchdogd
service <service/A/ready> B service <service/watchdogd/ready> stress-ng --cpu 8
For details on the syntax and options, see below. For details on the syntax and options, see below.
@@ -379,7 +459,7 @@ Cgroups
There are three major cgroup configuration directives: There are three major cgroup configuration directives:
1. Global top-level group: init, system, user, or a custom group 1. Global top-level group: `init`, `system`, `user`, or a custom group
2. Selecting a top-level group for a set of run/task/services 2. Selecting a top-level group for a set of run/task/services
3. Per run/task/service limits 3. Per run/task/service limits
@@ -430,6 +510,10 @@ except for expanding the shorthand `mem.` to `memory.`, if the file is
not available, either the cgroup controller is not available in your not available, either the cgroup controller is not available in your
Linux kernel, or the name is misspelled. Linux kernel, or the name is misspelled.
A daemon using `SCHED_RR` currently need to run outside the default cgroups.
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
> Linux cgroups and details surrounding values are not explained in the > Linux cgroups and details surrounding values are not explained in the
> Finit documentation. The Linux admin-guide cover this well: > Finit documentation. The Linux admin-guide cover this well:
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html> > <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
@@ -459,7 +543,7 @@ following directives:
> **Note:** not all directives are available in `/etc/finit.d/*.conf` > **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. > see [Limitations](#limitations) below for details.
@@ -472,7 +556,7 @@ the contents of that file is used.
Deprecated. We recommend using `/etc/hostname` instead. Deprecated. We recommend using `/etc/hostname` instead.
> **Note:** only read and executed in runlevel S ([bootstrap][]). > **Note:** only read and executed in runlevel S (bootstrap).
### Kernel Modules ### Kernel Modules
@@ -490,7 +574,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS" $MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
> **Note:** only read and executed in runlevel S ([bootstrap][]). > **Note:** only read and executed in runlevel S (bootstrap).
### Networking ### Networking
@@ -503,7 +587,7 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
or `/etc/network/interfaces` if you have a system with `ifupdown`, like or `/etc/network/interfaces` if you have a system with `ifupdown`, like
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system. Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
> **Note:** only read and executed in runlevel S ([bootstrap][]). > **Note:** only read and executed in runlevel S (bootstrap).
### Alternate finit.d/ ### Alternate finit.d/
@@ -558,7 +642,7 @@ stanzas can share the same rlimits if they are in the same .conf.
**Syntax:** `runlevel <N>` **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 is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
halt. halt.
@@ -567,40 +651,61 @@ Finit disables networking in this mode.
*Default:* 2 *Default:* 2
> **Note:** only read and executed in runlevel S ([bootstrap][]). > **Note:** only read and executed in runlevel S (bootstrap).
### One-shot Commands (sequence) ### One-shot Commands (sequence)
**Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description` **Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description.
`run` commands are guaranteed to be completed before running the next
command. Highly useful if true serialization is needed.
> `<COND>` is described in the [Services](#services) section. > `<COND>` is described in the [Services](#services) section.
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. `run` commands are guaranteed to be
completed before running the next command. Useful when serialization is
required.
> **Warning:** try to avoid the `run` command. It blocks much of the
> functionality in Finit, like (re)starting other (perhaps crashing)
> services while a `run` task is executing. Use other synchronization
> mechanisms instead, like conditions.
Incomplete list of unsupported `initctl` commands in `run` tasks:
- `initctl runlevel N`, setting runlevel
- `initctl reboot`
- `initctl halt`
- `initctl poweroff`
- `initctl suspend`
To prevent `initctl` from calling Finit when enabling and disabling
services from inside a `run` task, use the `--force` option. See
also the `--quiet` and `--batch` options.
### One-shot Commands (parallel) ### One-shot Commands (parallel)
**Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description` **Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
> `<COND>` is described in the [Services](#services) section.
One-shot like 'run', but starts in parallel with the next command. 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 Both `run` and `task` commands are run in a shell, so basic pipes and
redirects can be freely used: redirects can be used:
task [s] echo "foo" | cat >/tmp/bar task [s] echo "foo" | cat >/tmp/bar
> `<COND>` is described in the [Services](#services) section. Please note, `;`, `&&`, `||`, and similar are *not supported*. Any
non-trivial constructs are better placed in a separate shell script.
### SysV Init Scripts ### SysV Init Scripts
**Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description` **Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description`
> `<COND>` is described in the [Services](#services) section.
Similar to `task` is the `sysv` stanza, which can be used to call SysV Similar to `task` is the `sysv` stanza, which can be used to call SysV
style scripts. The primary intention for this command is to be able to style scripts. The primary intention for this command is to be able to
re-use much of existing setup and init scripts in Linux distributions. re-use much of existing setup and init scripts in Linux distributions.
@@ -618,7 +723,7 @@ file, but rather watch that file for the resulting forked-off PID. This
syntax also works for forking daemons that do not have a command line syntax also works for forking daemons that do not have a command line
option to run it in the foreground, more on this below in `service`. option to run it in the foreground, more on this below in `service`.
> `<COND>` is described in the [Services](#services) section. > **Tip:** see also [SysV Init Compatibility](#sysv-init-compatibility).
### Services ### Services
@@ -813,45 +918,106 @@ These script actions *must terminate*, so they have a default execution
time of 3 seconds before they are SIGKILLed, this can be adjusted using time of 3 seconds before they are SIGKILLed, this can be adjusted using
the above `kill:SEC` syntax. the above `kill:SEC` syntax.
#### Conditional Loading
Finit support conditional loading of stanzas. The following example is
take from the `system/hotplug.conf` file in the Finit distribution.
Here we only show a simplified subset.
Starting with the `nowarn` option.
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
service nowarn name:udevd pid:udevd udevd
When loading the .conf file Finit looks for `/lib/systemd/systemd-udevd`
if that is not found Finit automatically logs a warning. The `nowarn`
option disables this warning so that the second line can be evaluated,
which also provides a service named `udevd`.
run nowarn if:udevd <pid/udevd> :1 udevadm settle -t 0
This line is only loaded if we know of a service named `udevd`. Again,
we do not warn if `udevadm` is not found, Execution will also stop here
until the PID condition is asserted, i.e., Finit detecting udevd has
started.
run nowarn conflict:udevd [S] mdev -s -- Populating device tree
If `udevd` is not available, we try to run `mdev`, but if that is not
found, again we do not warn.
Conditional loading statements can also be negated, so the previous stanza
can also be written as:
run nowarn if:!udevd [S] mdev -s -- Populating device tree
The reason for using `confict` in this example is that a conflict can be
resolved. Stanzas marked with `conflict:foo` are rechecked at runtime.
#### Conditional Execution
Similar to conditional loading of stanzas there is conditional runtime
execution. This can be confusing at first, since Finit already has a
condition subsystem, but this is more akin to the qualification to a
runlevel. E.g., a `task [123]` is qualified to run only in runlevel 1,
2, and 3. It is not considered for other runlevels.
Conditional execution qualify a run/task/service based on a condition.
Consider this (simplified) example from the Infix operating system:
run [S] name:startup <pid/sysrepo> confd -b --load startup-config
run [S] if:<usr/fail-startup> name:failure <pid/sysrepo> confd --load failure-config
The two run statements reside in the same .conf file so Finit runs them
in true sequence. If loading the file `startup-config` fails confd sets
the condition `usr/fail-startup`, thus allowing the next run statement
to load `failure-config`.
Notice critical the difference between `<pid/sysrepo>` condition and
`if:<usr/fail-startup>`. The former is a condition for starting and the
latter is a condition to check if a run/task/service is qualified to
even be considered.
Conditional execution statements can also be negated, so provided the
file loaded did the opposite, i.e., set a condition on success, the
previous stanza can also be written as:
run [S] if:<!usr/startup-ok> name:failure <pid/sysrepo> confd ...
### Run-parts Scripts ### Run-parts Scripts
**Syntax:** `runparts <DIR>` **Syntax:** `runparts [progress] [sysv] <DIR>`
Call [run-parts(8)][] on `DIR` to run start scripts. All executable Call [run-parts(8)][] on `DIR` to run start scripts. All executable
files, or scripts, in the directory are called, in alphabetic order. files in the directory are called, in alphabetic order. The scripts in
The scripts in this directory are executed at the very end of runlevel this directory are executed at the very end of runlevel `S`.
`S`, [bootstrap][].
A common use-case for runparts scripts is to create and enable/disable 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 services, which Finit will then apply when changing runlevel from S to
whatever the next runlevel is set to be (default 2). E.g., generate a whatever the next runlevel is set to be (default 2). E.g., generate a
`/etc/chrony.conf` and `initctl enable chronyd`. `/etc/chrony.conf` and call `initctl enable chronyd`.
**Options:**
- `progress`: display the progress of each script being executed
- `sysv`: run only SysV style scripts, i.e., `SNNfoo`, or `KNNbar`,
where `NN` is a number (0-99).
If global debug mode is enabled, the `runparts` program is also called
with the debug flag.
**Limitations:** **Limitations:**
Scripts called from `runparts`, or hook scripts (see below), are limited Scripts called from `runparts`, or hook scripts (see below), are limited
in what they can do and expect from Finit: in their interaction with Finit. Like the standalone `run` stanza and
the `/etc/rc.local` shell script, Finit waits for their completion
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.
1. Finit is single threaded and all scripts executed from these two > **Note:** `runparts` scrips are only read and executed in runlevel S.
mechanisms are limited to file system operations (early or late > See [hook scripts](plugins.md#hooks) for other ways to run scripts at
hooks may not have write access!) and standard UNIX programs. > certain points during the complete lifetime of the system.
2. Thus, it is *not possible* to call `initctl` to query status of
services since that calls Finit over the `/run/finit/socket`.
3. Confusingly enough, there are some commands to `initctl` that are
available; `ls`, `enable`, `disable`, `touch`, `create`, `delete`,
and all the `cond` commands. Because all these are basically just
wrappers for manipulating files (again, write access for early/late
hooks may not be available).
Also, similar to the `/etc/rc.local` shell script, make sure that all
your services and programs either terminate or start in the background
or you will block Finit.
> **Note:** `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.
**Recommendations:** **Recommendations:**
@@ -964,8 +1130,8 @@ can be omitted to keep the kernel default.
tty [12345] @console noclear vt220 tty [12345] @console noclear vt220
On really bare bones systems, or for board bringup, Finit can give you a 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 shell prompt as soon as bootstrap is done, without opening any device
device node: node:
tty [12345789] notty tty [12345789] notty
@@ -1044,6 +1210,72 @@ sync(2) has been called, twice.
> finally written. > finally written.
SysV Init Compatibility
-----------------------
It is not possible to run unmodified SysV init systems with Finit. This
was never the intention and is not the strength of Finit. However, it
comes with a few SysV Init compatibility features to ease the transition
from a serialized boot process.
### `runparts DIRECTORY`
For a directory with traditional start/stop scripts that should run, in
order, at bootstrap, Finit provides the `runparts` directive. It runs
in runlevel S, at the very end of it (before calling `/etc/rc.local`)
making it perfect for most scenarios.
For syntax details, see [Run-parts Scripts](#run-parts-scripts) above.
Here is an example take from a Debian installation:
runparts /etc/rc2.d
Files in these directories are usually named `SNNfoo` and `KNNfoo`,
which Finit knows about and automatically appends the correct argument:
/bin/sh -c /etc/rc2.d/S01openbsd-inetd start
or
/bin/sh -c /etc/rc0.d/K01openbsd-inetd stop
Files that do not match this pattern are started similarly but without
the extra command line argument.
### Start/Stop Scripts
For syntax details, see [SysV Init Scripts](#sysv-init-scripts), above.
Here follows an example taken from a Debian installation:
sysv [2345] <pid/syslogd> /etc/init.d/openbsd-inetd -- OpenBSD inet daemon
The init script header could be parsed to extract `Default-Start:` and
other parameters for the `sysv` command to Finit. There is currently no
way to detail a generic syslogd dependency in Finit, so `Should-Start:`
in the header must be mapped to the condition system in Finit using an
absolute reference, here we depend on the sysklogd project's syslogd.
### `/etc/rc.local`
One often requested feature, early on, was a way to run a site specific
script to set up, e.g., static routes or firewall rules. A user can add
a `task` or `run` command in the Finit configuration for this, but for
compatibility reasons the more widely know `/etc/rc.local` is used if
it exists, and is executable. It is called very late in the boot process
when the system has left runlevel S, stopped all old and started all new
services in the target runlevel (default 2).
> In Finit releases before v4.5 this script blocked Finit execution and
> made it as good as impossible to call `initctl` during that time.
### `init q`
When `/sbin/finit` is installed as `/sbin/init`, it is possible to use
`init q` to reload the configuration. This is the same as calling
`initctl reload`.
Rescue Mode Rescue Mode
----------- -----------
@@ -1051,6 +1283,10 @@ Finit supports a rescue mode which is activated by the `rescue` option
on the kernel command line. See [cmdline docs](cmdline.md) for how to on the kernel command line. See [cmdline docs](cmdline.md) for how to
activate it. activate it.
This rescue mode can be disabled at configure time using:
configure --without-rescue
The rescue mode comes in two flavors; *traditional* and *fallback*. The rescue mode comes in two flavors; *traditional* and *fallback*.
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to > **Note:** in this mode `initctl` will not work. Use the `-f` flag to
@@ -1060,15 +1296,17 @@ The rescue mode comes in two flavors; *traditional* and *fallback*.
### Traditional ### Traditional
This is what most users expect. A very early maintenance login prompt, This is what most users expect. A very early maintenance login prompt,
served by the bundled `/libexec/finit/sulogin` program, or the standard served by the system `sulogin` program from util-linux, or BusyBox. If
`sulogin` from util-linux or BusyBox is searched for in the UNIX default that is not found in `$PATH`, the bundled `/libexec/finit/sulogin`
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the program is used instead. If a successful login is made, or if the user
rescue mode is ended and the system boots up normally. exits (Ctrl-D), the rescue mode is ended and the system boots up
normally.
> **Note:** if the user (UID 0 and GID 0) does not have a password, or > **Note:** the bundled sulogin in Finit can at configure time be given
> __the account is locked__, the user is presented with a password-less > another user than the default (root). If the sulogin user does not
> `"Press enter to enter maintenance mode."`, prompt which opens up a > have a password, or __the account is locked__, the user is presented
> root shell. > with a password-less `"Press enter to enter maintenance mode."`,
> prompt which opens up a root shell.
### Fallback ### Fallback
@@ -1128,12 +1366,11 @@ Watchdog
When built `--with-watchdog` a separate service is built and installed When built `--with-watchdog` a separate service is built and installed
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT 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 device node exists, Finit will start it and treat it as the elected
watchdog service to delegate its reboot to. See [bootstrap][] for watchdog service to delegate its reboot to. This delegation is to
details. This delegation is to ensure that the system is rebooted by a ensure that the system is rebooted by a hardware watchdog timer -- on
hardware watchdog timer -- on many embedded systems this is crucial to many embedded systems this is crucial to ensure all circuits on the
ensure all circuits on the board are properly reset for the next boot, board are properly reset for the next boot, in effect ensuring the
in effect ensuring the system works the same after both a power-on and system works the same after both a power-on and reboot event.
reboot event.
The delegation is performed at the very last steps of system shutdown, 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 if reboot has been selected and an elected watchdog is known, first a
@@ -1155,8 +1392,6 @@ device descriptor. If the kernel driver has been built without this,
the only option is to remove `/libexec/finit/watchdogd` or build without the only option is to remove `/libexec/finit/watchdogd` or build without
it at configure time. it at configure time.
[bootstrap]: bootstrap.md
keventd keventd
------- -------
+19 -7
View File
@@ -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` system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
file systems must be writable for this plugin to work. file systems must be writable for this plugin to work.
Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM This plugin is a wrapper for the [tmpfiles.d(5)][] implementation that
disks and `/dev` is usually a `devtmpfs`. This must be defined in the Finit has. Capable but limited: no aging, attributes, or subvolumes.
`/etc/fstab` file and in the Linux kernel config.
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. * *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._ _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` customized at build-time using the `--with-hook-scripts-path=PATH`
argument to `configure`. argument to `configure`.
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if * *hotplug.so*: Replaced with `/lib/finit/system/10-hotplug.conf`, which
available. Enabled by default. 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 > See the [Services](config.md#services) section in the configuration
> guide for an example how to run `mdevd`, alternative to plain mdev. > guide for an example how to run `mdevd`, alternative to plain mdev.
@@ -136,7 +146,7 @@ hook points:
**Example:** **Example:**
$ mkdir -p /libexec/finit/hook/sys/down $ mkdir -p /libexec/finit/hook/sys/down
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh $ cat <<EOF >/libexec/finit/hook/sys/down/foo.sh
#!/bin/sh #!/bin/sh
echo 'I run just before the reboot() syscall at shutdown/reboot' echo 'I run just before the reboot() syscall at shutdown/reboot'
echo 'I have access to /dev since devtmpfs is exempt from umount' echo 'I have access to /dev since devtmpfs is exempt from umount'
@@ -146,7 +156,7 @@ hook points:
fi fi
exit 0 exit 0
EOF EOF
$ chmod +x /libexec/finit/hook/sys/foo.sh $ chmod +x /libexec/finit/hook/sys/down/foo.sh
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown > **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
> tasks, you must build with `configure --enable-hook-scripts-plugin`. > tasks, you must build with `configure --enable-hook-scripts-plugin`.
@@ -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()` 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 detects an event. See the source code for `plugins/*.c` for more help
and ideas. and ideas.
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+141
View File
@@ -0,0 +1,141 @@
_cond()
{
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
}
_ident()
{
if [ -n "$1" ]; then
initctl ident | grep -q $1
else
initctl ident
fi
}
_svc()
{
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
}
_enabled()
{
echo "$(_svc enabled)"
}
_available()
{
all=$(mktemp)
ena=$(mktemp)
echo "$(_svc available)" >$all
echo "$(_svc enabled)" >$ena
grep -v -f $ena $all
rm $all $ena
}
# Determine first non-option word. Usually the command
_firstword() {
local firstword i
firstword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
firstword=${COMP_WORDS[i]}
break
fi
done
echo $firstword
}
# Determine last non-option word. Uusally a sub-command
_lastword() {
local lastword i
lastword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
lastword=${COMP_WORDS[i]}
fi
done
echo $lastword
}
_initctl()
{
local cur command
cur=${COMP_WORDS[COMP_CWORD]}
prev="${COMP_WORDS[COMP_CWORD-1]}"
firstword=$(_firstword)
lastword=$(_lastword)
commands="status cond debug help kill ls log version list enable \
disable touch show cat edit create delete reload start \
stop restart signal cgroup ps top plugins runlevel reboot \
halt poweroff suspend utmp"
cond_cmds="set get clear status dump"
cond_types="hook net pid service task usr"
signals="int term hup stop tstp cont usr1 usr2 pwr"
options="-b --batch \
-c --create \
-d --debug \
-f --force \
-h --help \
-j --json \
-n --noerr \
-1 --once \
-p --plain \
-q --quiet \
-t --no-heading \
-v --verbose \
-V --version"
case "${firstword}" in
enable)
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
;;
disable|touch)
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
;;
show|cat|edit|delete)
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
;;
start|stop|restart|log|status)
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
;;
signal|kill)
if $(_ident "${prev}"); then
COMPREPLY=($(compgen -W "$signals" -- $cur))
else
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
fi
;;
cond)
case "${lastword}" in
set|clear)
compopt -o nospace
COMPREPLY=($(compgen -W "usr/" -- $cur))
;;
get)
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
;;
dump)
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
;;
*)
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
;;
esac
;;
*)
COMPREPLY=($(compgen -W "$commands" -- $cur))
;;
esac
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W "$options" -- $cur))
fi
}
complete -F _initctl initctl
+1 -1
View File
@@ -275,7 +275,7 @@ The following condition families are available today:
Linux netlink events, e.g. net/route/default, net/eth0/up, and Linux netlink events, e.g. net/route/default, net/eth0/up, and
net/et0/running net/et0/running
.It Cm pid .It Cm pid
PID files basd on the service declaration PID files based on the service declaration
.Cm name:id , .Cm name:id ,
gives the condition pid/name:id gives the condition pid/name:id
.It Cm service .It Cm service
+50 -26
View File
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.Dd Apr 24, 2023 .Dd July 11, 2023
.Dt FINIT.CONF 5 SMM .Dt FINIT.CONF 5 SMM
.Os Linux .Os Linux
.Sh NAME .Sh NAME
@@ -12,40 +12,64 @@
.Nm /etc/finit.conf .Nm /etc/finit.conf
.Nm /etc/finit.d/*.conf .Nm /etc/finit.d/*.conf
.Nm /etc/finit.d/available/*.conf .Nm /etc/finit.d/available/*.conf
.Nm /etc/finit.d/enabled/*.conf
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm finit .Nm Finit
can be configured using only the original based systems can be set up with a single file:
.Pa /etc/finit.conf .Pa /etc/finit.conf .
file or in combination with This is the traditional way of doing it which can be ideal for some
.Pa /etc/finit.d/*.conf . setups since it gives a great overview of the system configuration.
Useful for package-based Linux distributions \(em each package can
provide its own "script" file.
.Pp .Pp
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact More comprehensive setups, however, require more careful planning.
.It Pa /etc/finit.conf The recommendation is per-package
Main configuration file .Cm *.conf
.It Pa /etc/finit.d/*.conf files in
Snippets, usually one service per file .Pa /etc/finit.d/available/ .
.El This allows end users to enable and disable parts of the system
configuration at runtime. Finit tracks which tasks and services belong
to a given file, so that when the user calls
.Cm initctl reload
to activate the changes they have made, only the affected tasks and
services are stopped, started, or restarted. Hence, this approach is
useful for modern package-based Linux distributions.
.Pp .Pp
Not all configuration directives are available in The following sections describe the more of this in detail, starting
.Pa /etc/finit.d/*.conf with files, the file format, and available directives. Remember to
and some directives are only available at bootstrap, runlevel also visit the other manual pages (references at the bottom).
.Cm S ,
see the section
.Sx Limitations
below for details.
.Sh FILES .Sh FILES
.Bl -tag -width /etc/finit.d/available/*.conf -compact .Bl -tag -width /etc/finit.d/available/*.conf -compact
.It Pa /etc/finit.conf .It Pa /etc/finit.conf
Main configuration file Main configuration file, optional
.It Pa /etc/finit.d/*.conf .It Pa /etc/finit.d/*.conf
Static service definitions Static (system) service definitions
.It Pa /etc/finit.d/available/*.conf .It Pa /etc/finit.d/available/*.conf
Available services Available (installed) services
.It Pa /etc/finit.d/enabled/*.conf .It Pa /etc/finit.d/enabled/*.conf
Enabled services, symlinks from available Enabled services (symlink back)
.El .El
.Pp
Static services,
.Cm .conf
files in
.Pa /etc/finit.d/ ,
cannot be enabled or disabled using
.Cm initctl [enable | disable] service[.conf] .
An enabled service is a symlink back to the corresponding
.Cm ../available/
service
.Cm .conf
file. Please use the
.Cm initctl
tool to manage these symlinks to ensure proper operation.
.Pp
.Sy NOTE:
Previous versions of
.Nm Finit
created symlinks in
.Pa /etc/finit.d/
if
.Pa /etc/finit.d/enabled/
was missing, this is as of v4.4 not supported.
.Sh FILE FORMAT .Sh FILE FORMAT
The file format is line based, empty lines and comments, lines starting The file format is line based, empty lines and comments, lines starting
with `#', are ignored. A configuration directive starts with a keyword with `#', are ignored. A configuration directive starts with a keyword
@@ -960,6 +984,6 @@ settings in
.Xr finit 8 , .Xr finit 8 ,
.Xr initctl 8 .Xr initctl 8
.Sh AUTHORS .Sh AUTHORS
.Nm finit .Nm Finit
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0, was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others. maintained by Joachim Wiberg, with contributions by many others.
+5
View File
@@ -240,6 +240,11 @@ Show top-like listing based on cgroups.
List installed plugins. List installed plugins.
.It Nm Ar runlevel Op Ar 0-9 .It Nm Ar runlevel Op Ar 0-9
Show or set runlevel: 0 halt, 6 reboot. Show or set runlevel: 0 halt, 6 reboot.
.Pp
If called at boot (runlevel S) to set the runlevel, Finit only schedules
the change, effectively overriding the configured runlevel from
.Pa /etc/finit.conf .
Useful to trigger a fail-safe mode, or similar.
.It Nm Ar reboot .It Nm Ar reboot
Reboot system, default if Reboot system, default if
.Cm reboot .Cm reboot
+1 -1
View File
@@ -1,6 +1,6 @@
/* Save and restore ALSA sound settings using alsactl /* Save and restore ALSA sound settings using alsactl
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup necessary system files for, e.g. UTMP (tracking logins) /* Setup necessary system files for, e.g. UTMP (tracking logins)
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+6 -7
View File
@@ -1,6 +1,6 @@
/* Setup and start system message bus, D-Bus /* Setup and start system message bus, D-Bus
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -83,6 +83,7 @@ static char *dbus_pidfn(void)
break; break;
} }
*pos = 0; *pos = 0;
break;
} }
fclose(fp); fclose(fp);
@@ -142,23 +143,21 @@ static void setup(void *arg)
/* Generate machine id for dbus */ /* Generate machine id for dbus */
if (whichp("dbus-uuidgen")) 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 * Register service with Finit
* Note: dbus drops privs after starting up. * Note: dbus drops privs after starting up.
*/ */
if (pidfn) { if (pidfn) {
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus pid:!%s %s %s -- %s", snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s",
pidfn, cmd, DBUS_ARGS, DBUS_DESC); pidfn, cmd, DBUS_ARGS, DBUS_DESC);
free(pidfn); free(pidfn);
} else } else
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s", snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s",
cmd, DBUS_ARGS, DBUS_DESC); cmd, DBUS_ARGS, DBUS_DESC);
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL)) conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
err(1, "Failed registering %s", DBUS_DAEMON);
free(cmd); free(cmd);
} }
+3 -4
View File
@@ -1,6 +1,6 @@
/* Coldplug modules using modalias magic /* Coldplug modules using modalias magic
* *
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -132,11 +132,10 @@ static FILE *maybe_fopen_alias(const char *file, const char *path)
{ {
const char *basename; const char *basename;
basename = rindex(path, '/'); basename = basenm(path);
if (!basename) if (!strcmp(basename, path))
return NULL; return NULL;
basename++;
if (strcmp(file, basename)) if (strcmp(file, basename))
return NULL; return NULL;
+1 -1
View File
@@ -101,7 +101,7 @@ static int modules_load(const char *file, int index)
} }
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) { while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
char cmd[CMD_SIZE * 2], *mod, *args, *set; char cmd[CMD_SIZE], *mod, *args, *set;
/* /*
* fparseln() skips regular UNIX comments only. * fparseln() skips regular UNIX comments only.
+1 -1
View File
@@ -2,7 +2,7 @@
/* Netlink plugin for IFUP/IFDN and GW events /* Netlink plugin for IFUP/IFDN and GW events
* *
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se> * Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
* Copyright (C) 2009-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (C) 2009-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
+11 -10
View File
@@ -1,7 +1,7 @@
/* Simple pidfile event monitor for the Finit condition engine /* Simple pidfile event monitor for the Finit condition engine
* *
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com> * Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -79,7 +79,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
return; return;
} }
dbg("Found svc %s for %s with pid %d", svc->name, fn, svc->pid); dbg("Found svc %s for %s with pid %d", svc_ident(svc, NULL, 0), fn, svc->pid);
mkcond(svc, cond, sizeof(cond)); mkcond(svc, cond, sizeof(cond));
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) { if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
@@ -88,7 +88,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
* systemd style services rely on their respective * systemd style services rely on their respective
* readiness notification. Issue #343 * readiness notification. Issue #343
*/ */
if (!svc->notify) if (svc->notify == SVC_NOTIFY_PID)
svc_started(svc); svc_started(svc);
if (!svc_has_pidfile(svc)) { if (!svc_has_pidfile(svc)) {
@@ -120,13 +120,14 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
} }
} }
cond_set(cond); if (svc->notify == SVC_NOTIFY_PID)
if (!svc->notify) cond_set(cond);
service_ready(svc); if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
service_ready(svc, 1);
} else if (mask & IN_DELETE) { } else if (mask & IN_DELETE) {
cond_clear(cond); cond_clear(cond);
if (!svc->notify) if (svc->notify == SVC_NOTIFY_PID)
service_ready(svc); service_ready(svc, 0);
} }
} }
@@ -240,8 +241,8 @@ static void pidfile_reconf(void *arg)
if (svc_is_changed(svc) || svc_is_starting(svc)) if (svc_is_changed(svc) || svc_is_starting(svc))
continue; continue;
if (!svc->notify) if (svc->notify == SVC_NOTIFY_PID)
service_ready(svc); service_ready(svc, 1);
mkcond(svc, cond, sizeof(cond)); mkcond(svc, cond, sizeof(cond));
if (cond_get(cond) == COND_ON) if (cond_get(cond) == COND_ON)
+1 -1
View File
@@ -1,6 +1,6 @@
/* Set kernel variables from /etc/sysctl.conf et al /* Set kernel variables from /etc/sysctl.conf et al
* *
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -1,6 +1,6 @@
/* Setup necessary files for resolvconf /* Setup necessary files for resolvconf
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -45,7 +45,7 @@ static void setup(void *arg)
touch("/etc/resolvconf/run/enable-updates"); touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface"); chdir("/etc/resolvconf/run/interface");
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0); run_parts("/etc/resolvconf/update.d", "-i", NULL, 0, 0);
chdir("/"); chdir("/");
} }
+1 -1
View File
@@ -1,6 +1,6 @@
/* Save and restore RTC using hwclock /* Save and restore RTC using hwclock
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* System condition event monitor for the Finit condition engine /* System condition event monitor for the Finit condition engine
* *
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB /* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
* *
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com> * Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup and save random seed at boot/shutdown /* Setup and save random seed at boot/shutdown
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* User-defined condition event monitor for the Finit condition engine /* User-defined condition event monitor for the Finit condition engine
* *
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Console setup (for X) /* Console setup (for X)
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1
View File
@@ -5,6 +5,7 @@ initctl
keventd keventd
logit logit
reboot reboot
runparts
sulogin sulogin
watchdogd watchdogd
Makefile Makefile
+9 -2
View File
@@ -8,7 +8,7 @@ AM_LDFLAGS = -export-dynamic
endif endif
sbin_PROGRAMS = finit initctl sbin_PROGRAMS = finit initctl
pkglibexec_PROGRAMS = getty logit pkglibexec_PROGRAMS = getty logit runparts
if SULOGIN if SULOGIN
pkglibexec_PROGRAMS += sulogin pkglibexec_PROGRAMS += sulogin
endif endif
@@ -19,6 +19,8 @@ if WATCHDOGD
pkglibexec_PROGRAMS += watchdogd pkglibexec_PROGRAMS += watchdogd
endif endif
dist_pkglibexec_SCRIPTS = coldplug
finit_pkglibdir = $(pkglibdir) finit_pkglibdir = $(pkglibdir)
finit_pkglib_SCRIPTS = rescue.conf sample.conf finit_pkglib_SCRIPTS = rescue.conf sample.conf
@@ -32,6 +34,11 @@ keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
keventd_CFLAGS += $(lite_CFLAGS) keventd_CFLAGS += $(lite_CFLAGS)
keventd_LDADD = $(lite_LIBS) keventd_LDADD = $(lite_LIBS)
runparts_SOURCES = runparts.c
runparts_CFLAGS = -W -Wall -Wextra -std=gnu99
runparts_CFLAGS += $(lite_CFLAGS)
runparts_LDADD = $(lite_LIBS)
sulogin_SOURCES = sulogin.c sulogin_SOURCES = sulogin.c
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99 sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
sulogin_LDADD = -lcrypt sulogin_LDADD = -lcrypt
@@ -54,7 +61,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
mdadm.c mount.c \ mdadm.c mount.c \
pid.c pid.h \ pid.c pid.h \
plugin.c plugin.h private.h \ plugin.c plugin.h private.h \
schedule.c schedule.h \ runparts.c schedule.c schedule.h \
service.c service.h \ service.c service.h \
sig.c sig.h \ sig.c sig.h \
sm.c sm.h \ sm.c sm.h \
+16 -4
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket. /* External client API, using UNIX domain socket.
* *
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -367,7 +367,6 @@ static void api_cb(uev_t *w, void *arg, int events)
} }
switch (rq.cmd) { switch (rq.cmd) {
case INIT_CMD_RUNLVL:
case INIT_CMD_RELOAD: case INIT_CMD_RELOAD:
case INIT_CMD_START_SVC: case INIT_CMD_START_SVC:
case INIT_CMD_RESTART_SVC: case INIT_CMD_RESTART_SVC:
@@ -378,7 +377,7 @@ static void api_cb(uev_t *w, void *arg, int events)
case INIT_CMD_POWEROFF: case INIT_CMD_POWEROFF:
case INIT_CMD_SUSPEND: case INIT_CMD_SUSPEND:
if (IS_RESERVED_RUNLEVEL(runlevel)) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("Unsupported command in runlevel S and 6."); warnx("Unsupported command in runlevel S and 6/0.");
goto leave; goto leave;
} }
default: default:
@@ -387,6 +386,14 @@ static void api_cb(uev_t *w, void *arg, int events)
switch (rq.cmd) { switch (rq.cmd) {
case INIT_CMD_RUNLVL: case INIT_CMD_RUNLVL:
/* Allow changing cfglevel in runlevel S */
if (IS_RESERVED_RUNLEVEL(runlevel)) {
if (runlevel != INIT_LEVEL) {
warnx("Cannot abort runlevel 6/0.");
break;
}
}
switch (rq.runlevel) { switch (rq.runlevel) {
case 's': case 's':
case 'S': case 'S':
@@ -400,7 +407,12 @@ static void api_cb(uev_t *w, void *arg, int events)
halt = SHUT_OFF; halt = SHUT_OFF;
if (lvl == 6) if (lvl == 6)
halt = SHUT_REBOOT; halt = SHUT_REBOOT;
service_runlevel(lvl);
/* User requested change in next runlevel */
if (runlevel == INIT_LEVEL)
cfglevel = lvl;
else
service_runlevel(lvl);
break; break;
default: default:
+1 -1
View File
@@ -1,6 +1,6 @@
/* Finit control group support functions /* Finit control group support functions
* *
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2019-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Finit control group support functions /* Finit control group support functions
* *
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2019-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool /* New client tool, replaces old /dev/initctl API and telinit tool
* *
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2019-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Cgroup utility functions for initctl /* Cgroup utility functions for initctl
* *
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2019-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket. /* External client API, using UNIX domain socket.
* *
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket. /* External client API, using UNIX domain socket.
* *
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
Executable
+11
View File
@@ -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
View File
@@ -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) static void cond_delpath(const char *path)
{ {
nftw(path, do_delete, 20, FTW_DEPTH); nftw(path, do_delete, 20, FTW_DEPTH);
if (remove(path) && errno != ENOENT) if (remove(path)) {
err(1, "Failed removing condition path %s", 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) int cond_set_path(const char *path, enum cond_state next)
+227 -17
View File
@@ -1,6 +1,6 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf /* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -62,8 +62,29 @@ static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
struct rlimit initial_rlimit[RLIMIT_NLIMITS]; struct rlimit initial_rlimit[RLIMIT_NLIMITS];
struct rlimit global_rlimit[RLIMIT_NLIMITS]; struct rlimit global_rlimit[RLIMIT_NLIMITS];
/*
* --enable-fastboot => fsck_mode: NULL => no fsck by default
* --enable-fsckfix => fsck_mode: "-f" + fsck_repair: "y"
*/
#ifdef FSCK_FIX
# ifdef FAST_BOOT
char *fsck_mode = NULL;
# else
char *fsck_mode = "-f";
# endif
char *fsck_repair = "-y";
#else
# ifdef FAST_BOOT
char *fsck_mode = NULL;
# else
char *fsck_mode = ""; char *fsck_mode = "";
# endif
char *fsck_repair = "-p"; char *fsck_repair = "-p";
#endif
char *runparts = NULL;
int runparts_progress;
int runparts_sysv;
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */ char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
@@ -246,10 +267,12 @@ static void parse_arg(char *arg)
return; return;
} }
#ifdef RESCUE_MODE
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) { if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
rescue = 1; rescue = 1;
return; return;
} }
#endif
if (string_compare(arg, "single") || string_compare(arg, "S")) { if (string_compare(arg, "single") || string_compare(arg, "S")) {
single = 1; single = 1;
@@ -391,6 +414,79 @@ void conf_saverc(void)
fclose(fp); fclose(fp);
} }
/*
* Called at bootstrap to log execution order (for debug)
*/
void conf_save_exec_order(svc_t *svc, char *cmdline, int result)
{
const char *fn = _PATH_VARRUN "finit/exec.order";
const char *ststr = !result ? "[ OK ]" : "[FAIL]";
static char *prepared = NULL;
int first = !fexist(fn);
FILE *fp;
fp = fopen(fn, "a+");
if (!fp) {
err(1, "failed writing to %s", fn);
return;
}
if (first) {
fprintf(fp, "# Execution order of run/task/services at bootstrap\n");
fprintf(fp, "# ST TYPE COMMAND LINE (DESC)\n");
}
if (result == -1) {
int len;
len = snprintf(NULL, 0, " %-7s %-64s (%s)", svc_typestr(svc), cmdline, svc->desc);
if (len > 0) {
if (prepared)
free(prepared);
prepared = malloc(++len);
if (!prepared)
goto done;
snprintf(prepared, len, " %-7s %-64s (%s)", svc_typestr(svc), cmdline, svc->desc);
}
} else {
if (prepared) {
memcpy(prepared, ststr, strlen(ststr));
fprintf(fp, "%s\n", prepared);
free(prepared);
prepared = NULL;
} else {
fprintf(fp, "%s %-7s %-64s (%s)\n", ststr, svc_typestr(svc), cmdline, svc->desc);
}
}
done:
fclose(fp);
}
/*
* Called by plugins and similar that dynamically generate system services
*/
void conf_save_service(int type, char *cfg, char *file)
{
char fn[256];
svc_t foo;
FILE *fp;
mkpath(FINIT_RUNPATH_, 0755);
snprintf(fn, sizeof(fn), "%s/%s", FINIT_RUNPATH_, file);
if (fexist(fn))
warnx("File %s already exists, overwriting.", fn);
fp = fopen(fn, "w");
if (!fp) {
err(1, "Failed creating %s", fn);
return;
}
foo.type = type;
fprintf(fp, "# Generated by finit:%s()\n", __func__);
fprintf(fp, "%s %s\n", svc_typestr(&foo), cfg);
fclose(fp);
}
/* /*
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line * Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
* from finit.conf, or other .conf file. Note, PATH is always reset in * from finit.conf, or other .conf file. Note, PATH is always reset in
@@ -449,6 +545,23 @@ static void parse_env(char *line)
*end-- = 0; *end-- = 0;
} }
/* strip any leading 'set ' */
end = key;
if (!strncmp(key, "set", 3))
end += 3;
/* check key, no spaces allowed */
while (*end && isspace(*end))
end++;
key = end;
while (*end && !isspace(*end))
end++;
if (*end != 0) {
warnx("'%s=%s': not a valid identifier", key, val);
return; /* invalid key */
}
dbg("Global env '%s'='%s'", key, val);
setenv(key, val, 1); setenv(key, val, 1);
node = malloc(sizeof(*node)); node = malloc(sizeof(*node));
@@ -560,11 +673,22 @@ void conf_parse_cond(svc_t *svc, char *cond)
return; 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; ptr = cond;
if (ptr[i] == '!') { if (ptr[i] == '!') {
svc->sighup = 0;
ptr++; 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) while (ptr[i] != '>' && ptr[i] != 0)
@@ -776,6 +900,15 @@ static int parse_static(char *line, int is_rcsd)
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) { if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
if (runparts) free(runparts); if (runparts) free(runparts);
runparts_progress = runparts_sysv = 0;
while (x) {
if (MATCH_CMD(x, "progress", x))
runparts_progress = 1;
else if (MATCH_CMD(x, "sysv", x))
runparts_sysv = 1;
else
break;
}
runparts = strdup(strip_line(x)); runparts = strdup(strip_line(x));
return 0; return 0;
} }
@@ -842,6 +975,18 @@ static int parse_static(char *line, int is_rcsd)
return 0; return 0;
} }
/*
* Before Finit 5 the default readiness notification is PID.
* This default can be changed by setting 'readiness none' in
* the file /etc/finit.conf, only read once at bootstrap.
*/
if (BOOTSTRAP && MATCH_CMD(line, "readiness ", x)) {
char *token = strip_line(x);
if (!strcmp(token, "none"))
readiness = SVC_NOTIFY_NONE;
}
if (MATCH_CMD(line, "reboot-delay ", x)) { if (MATCH_CMD(line, "reboot-delay ", x)) {
syncsec = strtonum(strip_line(x), 0, 60, NULL); syncsec = strtonum(strip_line(x), 0, 60, NULL);
return 0; return 0;
@@ -862,7 +1007,7 @@ static int parse_static(char *line, int is_rcsd)
service_interval = val * 1000; /* to milliseconds */ service_interval = val * 1000; /* to milliseconds */
if (disabled) if (disabled)
service_init(); service_init(NULL);
} }
return 0; return 0;
} }
@@ -1083,6 +1228,14 @@ int conf_reload(void)
*/ */
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit)); memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
/*
* When built with --disable-rescue mode many other 'if (rescue)'
* code paths are #ifdeffed out. This one, and the ones in the
* plugins, are not because a hook or plugin can still trigger
* the alternative rescue.conf instead of finit.conf. This for
* very advanced use-cases where files on /etc are generated at
* bootstrap, including users and passwords, from other sources.
*/
if (rescue) { if (rescue) {
int rc; int rc;
char line[80] = "tty [12345789] rescue"; char line[80] = "tty [12345789] rescue";
@@ -1112,22 +1265,53 @@ int conf_reload(void)
* but are now regular files that can be overridden by files in * but are now regular files that can be overridden by files in
* /etc/finit.d -- similar to how tmfiles.d(5) work. E.g., add * /etc/finit.d -- similar to how tmfiles.d(5) work. E.g., add
* an override .conf, or an ignore by symlinking to /dev/null * an override .conf, or an ignore by symlinking to /dev/null
*
* The .conf files (and run/task/service stanzas) are parsed and
* started in order. Each directory is sorted alphanumerically
* and then the result is appended to the overall order:
*
* /lib/finit/system/10-hotplug.conf
* /lib/finit/system/90-testserv.conf
* /run/finit/system/dbus.conf
* /run/finit/system/tty.conf
* /etc/finit.d/10-abc.conf
* /etc/finit.d/20-abc.conf
* /etc/finit.d/enabled/1-aaa.conf
* /etc/finit.d/enabled/1-abc.conf
* /etc/finit.d/enabled/2-aaa.conf
*/ */
glob_append(&gl, 0, "%s/*.conf", finit_rcsd); glob_append(&gl, 0, "%s/*.conf", FINIT_SYSPATH_);
glob_append(&gl, 1, "%s/*.conf", FINIT_SYSPATH); glob_append(&gl, 1, "%s/*.conf", FINIT_RUNPATH_);
glob_append(&gl, 1, "%s/*.conf", finit_rcsd);
glob_append(&gl, 1, "%s/enabled/*.conf", finit_rcsd); glob_append(&gl, 1, "%s/enabled/*.conf", finit_rcsd);
if (bootstrap) {
const char *fn = _PATH_VARRUN "finit/conf.order";
FILE *fp;
fp = fopen(fn, "w");
if (!fp) {
err(1, "failed creating %s", fn);
} else {
fprintf(fp, "# Evaluation & execution order of .conf files\n");
for (i = 0; i < gl.gl_pathc; i++)
fprintf(fp, "%s\n", gl.gl_pathv[i]);
fclose(fp);
}
}
for (i = 0; i < gl.gl_pathc; i++) { for (i = 0; i < gl.gl_pathc; i++) {
char *path = gl.gl_pathv[i]; char *path = gl.gl_pathv[i];
char *rp = NULL; char *rp = NULL;
struct stat st; struct stat st;
size_t j, len; size_t j, len;
/* check for FINIT_SYSPATH overrides */ /* check for FINIT_SYSPATH_ or FINIT_RUNPATH_ overrides */
for (j = i + 1; j < gl.gl_pathc; j++) { for (j = i + 1; j < gl.gl_pathc; j++) {
if (strncmp(path, FINIT_SYSPATH, strlen(FINIT_SYSPATH))) if (strncmp(path, FINIT_SYSPATH_, strlen(FINIT_SYSPATH_)) &&
strncmp(path, FINIT_RUNPATH_, strlen(FINIT_RUNPATH_)))
continue; continue;
if (strcmp(basename(path), basename(gl.gl_pathv[j]))) if (strcmp(basenm(path), basenm(gl.gl_pathv[j])))
continue; continue;
path = NULL; /* replacement later in list, skip this */ path = NULL; /* replacement later in list, skip this */
break; break;
@@ -1185,6 +1369,9 @@ done:
/* Drop record of all .conf changes */ /* Drop record of all .conf changes */
drop_changes(); drop_changes();
if (bootstrap)
wdog = svc_find("watchdog", "finit");
/* Override configured runlevel, user said 'S' on /proc/cmdline */ /* Override configured runlevel, user said 'S' on /proc/cmdline */
if (BOOTSTRAP && single) if (BOOTSTRAP && single)
cfglevel = 1; cfglevel = 1;
@@ -1235,7 +1422,11 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
struct conf_change *node; struct conf_change *node;
char *rp = NULL; char *rp = NULL;
paste(fn, sizeof(fn), dir, name); /* Check for actual printable characters, sometimes STX */
if (name[0] && name[0] >= ' ')
paste(fn, sizeof(fn), dir, name);
else
strlcpy(fn, dir, sizeof(fn));
dbg("path: %s mask: %08x", fn, mask); dbg("path: %s mask: %08x", fn, mask);
/* Handle disabling/removal of service */ /* Handle disabling/removal of service */
@@ -1266,7 +1457,7 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
dbg("event registered for %s, mask 0x%x", rp, mask); dbg("event registered for %s, mask 0x%x", rp, mask);
return 0; return 0;
fail: fail:
warn("failed registering %s event", fn); warn("failed registering %s event mask %08x", fn, mask);
return 1; return 1;
} }
@@ -1329,10 +1520,8 @@ static int conf_iwatch_read(int fd)
if (!iwp) if (!iwp)
continue; continue;
if (conf_change_act(iwp->path, ev->name, ev->mask)) { if (conf_change_act(iwp->path, ev->name, ev->mask))
err(1, " Out of memory");
break; break;
}
} }
return 0; return 0;
@@ -1420,15 +1609,16 @@ int conf_init(uev_ctx_t *ctx)
*/ */
#ifdef WDT_DEVNODE #ifdef WDT_DEVNODE
if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) { if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
service_register(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init name:watchdog :finit " FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL); conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init notify:none name:watchdog :finit "
wdog = svc_find("watchdog", "finit"); FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", "watchdogd.conf");
} }
#endif #endif
/* /*
* Start kernel event daemon as soon as possible, if enabled * Start kernel event daemon as soon as possible, if enabled
*/ */
if (whichp(FINIT_EXECPATH_ "/keventd")) if (whichp(FINIT_EXECPATH_ "/keventd"))
service_register(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init " FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL); conf_save_service(SVC_TYPE_SERVICE, "[S12345789] cgroup.init notify:none "
FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", "keventd.conf");
dbg("Allow plugins to register early runlevel 1 run/task/services ..."); dbg("Allow plugins to register early runlevel 1 run/task/services ...");
plugin_run_hooks(HOOK_SVC_PLUGIN); plugin_run_hooks(HOOK_SVC_PLUGIN);
@@ -1447,6 +1637,26 @@ int conf_init(uev_ctx_t *ctx)
return 1; return 1;
} }
/*
* Background startup scripts in the runparts directory, if any.
*/
if (runparts && fisdir(runparts) && !rescue) {
char conf[sizeof(_PATH_RUNPARTS) + strlen(runparts) + 100];
char args[10] = { 0 };
if (debug)
strlcat(args, "-d ", sizeof(args));
if (runparts_progress)
strlcat(args, "-p ", sizeof(args));
if (runparts_sysv)
strlcat(args, "-s ", sizeof(args));
snprintf(conf, sizeof(conf), "[S] <int/bootstrap> notify:none log:console %s %s %s"
" -- Calling runparts %s in the background",
_PATH_RUNPARTS, args, runparts, runparts);
conf_save_service(SVC_TYPE_TASK, conf, "runparts.conf");
}
return 0; return 0;
} }
+3 -1
View File
@@ -1,6 +1,6 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf /* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -44,6 +44,8 @@ int conf_monitor (void);
void conf_reset_env (void); void conf_reset_env (void);
void conf_saverc (void); void conf_saverc (void);
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
void conf_save_service (int type, char *cfg, char *file);
void conf_parse_cmdline (int argc, char *argv[]); void conf_parse_cmdline (int argc, char *argv[]);
int conf_parse_runlevels (char *runlevels); int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond); void conf_parse_cond (svc_t *svc, char *cond);
+3 -3
View File
@@ -1,6 +1,6 @@
/* Device node monitor for the Finit condition engine /* Device node monitor for the Finit condition engine
* *
* Copyright (c) 2022-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2022-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -237,13 +237,13 @@ static void devmon_cb(uev_t *w, void *arg, int events)
continue; continue;
} }
dbg("Got %s", ev->name); // dbg("Got %s", ev->name);
if (ev->mask & (IN_CREATE | IN_DELETE)) if (ev->mask & (IN_CREATE | IN_DELETE))
devmon_update_conds(iwp->path, ev->name, ev->mask); devmon_update_conds(iwp->path, ev->name, ev->mask);
} }
} }
void devmon_init(void) void devmon_init(uev_ctx_t *ctx)
{ {
char dir[MAX_ARG_LEN]; char dir[MAX_ARG_LEN];
+2 -2
View File
@@ -1,6 +1,6 @@
/* Device node monitor for the Finit condition engine /* Device node monitor for the Finit condition engine
* *
* Copyright (c) 2022-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2022-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,6 +27,6 @@
void devmon_add_cond(const char *cond); void devmon_add_cond(const char *cond);
void devmon_del_cond(const char *cond); void devmon_del_cond(const char *cond);
void devmon_init(void); void devmon_init(uev_ctx_t *ctx);
#endif /* FINIT_DEVMON_H_ */ #endif /* FINIT_DEVMON_H_ */
+16 -94
View File
@@ -1,7 +1,7 @@
/* Functions for exec'ing processes /* Functions for exec'ing processes
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +24,6 @@
#include "config.h" /* Generated by configure script */ #include "config.h" /* Generated by configure script */
#include <ctype.h> /* isdigit() */
#include <dirent.h>
#include <err.h> #include <err.h>
#include <stdarg.h> #include <stdarg.h>
#include <sysexits.h> #include <sysexits.h>
@@ -59,11 +57,11 @@ int complete(char *cmd, int pid)
if (waitpid(pid, &status, 0) == -1) { if (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR) if (errno == EINTR)
errx(1, "Caught unblocked signal waiting for %s, aborting", cmd); warnx("Caught unblocked signal waiting for %s, aborting", cmd);
else if (errno == ECHILD) else if (errno == ECHILD)
errx(1, "Caught SIGCHLD waiting for %s, aborting", cmd); warnx("Caught SIGCHLD waiting for %s, aborting", cmd);
else else
errx(1, "Failed starting %s, error %d: %s", cmd, errno, strerror (errno)); warnx("Failed starting %s, error %d: %s", cmd, errno, strerror(errno));
return -1; return -1;
} }
@@ -186,7 +184,7 @@ int run(char *cmd, char *log)
} else if (WIFSIGNALED(status)) { } else if (WIFSIGNALED(status)) {
dbg("Process '%s' terminated by signal %d", cmd, WTERMSIG(status)); dbg("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
if (!result) if (!result)
result = 1; /* Must alert callee that the command did complete successfully. result = 1; /* Must alert callee the command did not complete successfully.
* This is necessary since not all programs trap signals and * This is necessary since not all programs trap signals and
* change their return code accordingly. --Jocke */ * change their return code accordingly. --Jocke */
} }
@@ -272,7 +270,7 @@ int exec_runtask(char *cmd, char *args[])
size_t i; size_t i;
strlcat(buf, cmd, sizeof(buf)); strlcat(buf, cmd, sizeof(buf));
for (i = 1; args[i]; i++) { for (i = 1; args && args[i]; i++) {
strlcat(buf, " ", sizeof(buf)); strlcat(buf, " ", sizeof(buf));
strlcat(buf, args[i], sizeof(buf)); strlcat(buf, args[i], sizeof(buf));
} }
@@ -443,96 +441,20 @@ pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
return rc; return rc;
} }
static void run_env(const char *env[]) pid_t run_bg(char *cmd, char *args[])
{ {
size_t i = 0; pid_t pid;
if (!env) if (access(cmd, X_OK))
return; return 0;
while (env[i]) { print(-1, "Calling %s in the background", cmd);
size_t j = i + 1; pid = fork();
if (!pid)
_exit(exec_runtask(cmd, args));
print_result(pid == -1);
if (!env[j]) return pid;
break;
setenv(env[i], env[j], 1);
i += 2;
}
}
int run_parts(char *dir, char *cmd, const char *env[], int progress)
{
struct dirent **e;
int i, num;
num = scandir(dir, &e, NULL, alphasort);
if (num < 0) {
dbg("No files found in %s, skipping ...", dir);
return -1;
}
for (i = 0; i < num; i++) {
const char *name = e[i]->d_name;
char path[strlen(dir) + strlen(name) + 2];
struct stat st;
char *argv[4] = {
"sh",
"-c",
path,
NULL
};
pid_t pid = 0;
int status;
paste(path, sizeof(path), dir, name);
if (stat(path, &st)) {
dbg("Failed stat(%s): %s", path, strerror(errno));
continue;
}
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
if (strcmp(name, ".") && strcmp(name, ".."))
dbg("Skipping %s ...", path);
continue;
}
/* If the callee didn't supply a run_parts() argument */
if (!cmd) {
/* Check if S<NUM>service or K<NUM>service notation is used */
// dbg("Checking if %s is a sysvinit startstop script ...", name);
if (name[0] == 'S' && isdigit(name[1]))
strlcat(path, " start", sizeof(path));
else if (name[0] == 'K' && isdigit(name[1]))
strlcat(path, " stop", sizeof(path));
} else {
strlcat(path, cmd, sizeof(path));
}
if (progress)
print_desc("Calling ", path);
pid = fork();
if (!pid) {
sig_unblock();
run_env(env);
return execvp(_PATH_BSHELL, argv);
}
status = complete(path, pid);
if (WIFEXITED(status))
warnx("%s exited with status %d", path, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
warnx("%s terminated by signad %d", path, WTERMSIG(status));
if (progress)
print_result(WEXITSTATUS(status));
}
while (num--)
free(e[num]);
free(e);
return 0;
} }
/** /**
+29 -137
View File
@@ -1,7 +1,7 @@
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins /* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -58,7 +58,6 @@
#include "tty.h" #include "tty.h"
#include "util.h" #include "util.h"
#include "utmp-api.h" #include "utmp-api.h"
#include "schedule.h"
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */ int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */ int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
@@ -70,13 +69,13 @@ int single = 0; /* single user mode from kernel cmdline */
int bootstrap = 1; /* set while bootrapping (for TTYs) */ int bootstrap = 1; /* set while bootrapping (for TTYs) */
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */ int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
int syncsec = 0; /* reboot delay */ int syncsec = 0; /* reboot delay */
int readiness = SVC_NOTIFY_PID;
char *finit_conf= NULL; char *finit_conf= NULL;
char *finit_rcsd= NULL; char *finit_rcsd= NULL;
char *fstab = NULL; char *fstab = NULL;
char *sdown = NULL; char *sdown = NULL;
char *network = NULL; char *network = NULL;
char *hostname = NULL; char *hostname = NULL;
char *runparts = NULL;
char *osheading = NULL; char *osheading = NULL;
uev_ctx_t *ctx = NULL; /* Main loop context */ uev_ctx_t *ctx = NULL; /* Main loop context */
@@ -206,7 +205,7 @@ static int fsck(int pass)
fp = setmntent(fstab, "r"); fp = setmntent(fstab, "r");
if (!fp) { if (!fp) {
err(1, "Failed opening fstab: %s", fstab); logit(LOG_CONSOLE | LOG_ALERT, "Failed opening fstab: %s", fstab);
sulogin(1); sulogin(1);
} }
dbg("Opened %s, pass %d", fstab, pass); dbg("Opened %s, pass %d", fstab, pass);
@@ -256,11 +255,7 @@ static int fsck(int pass)
continue; continue;
} }
#ifdef FSCK_FIX
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
#else
snprintf(cmd, sizeof(cmd), "fsck %s %s %s", fsck_mode, fsck_repair, dev); snprintf(cmd, sizeof(cmd), "fsck %s %s %s", fsck_mode, fsck_repair, dev);
#endif
dbg("Running pass %d fsck command %s", pass, cmd); dbg("Running pass %d fsck command %s", pass, cmd);
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev); fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
/* /*
@@ -283,7 +278,6 @@ static int fsck(int pass)
static int fsck_all(void) static int fsck_all(void)
{ {
int rc = 0; int rc = 0;
#ifndef FAST_BOOT
int pass; int pass;
if (!fsck_mode) if (!fsck_mode)
@@ -294,7 +288,7 @@ static int fsck_all(void)
if (rc) if (rc)
break; break;
} }
#endif
return rc; return rc;
} }
@@ -361,6 +355,8 @@ static void fs_remount_root(int fsckerr)
*/ */
static void fs_finalize(void) static void fs_finalize(void)
{ {
int flags = MS_NOEXEC | MS_NOSUID;
/* /*
* Some systems rely on us to both create /dev/shm and, to mount * Some systems rely on us to both create /dev/shm and, to mount
* a tmpfs there. Any system with dbus needs shared memory, so * a tmpfs there. Any system with dbus needs shared memory, so
@@ -368,8 +364,8 @@ static void fs_finalize(void)
* the /etc/fstab file already. * the /etc/fstab file already.
*/ */
if (!fismnt("/dev/shm")) { if (!fismnt("/dev/shm")) {
makedir("/dev/shm", 0777); makedir("/dev/shm", 1777);
fs_mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777"); fs_mount("shm", "/dev/shm", "tmpfs", flags | MS_NODEV, "mode=1777");
} }
/* Modern systems use /dev/pts */ /* Modern systems use /dev/pts */
@@ -387,7 +383,13 @@ static void fs_finalize(void)
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode); snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
makedir("/dev/pts", 0755); makedir("/dev/pts", 0755);
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts); fs_mount("devpts", "/dev/pts", "devpts", flags, opts);
}
/* Needed on systems like Alpine Linux */
if (!fismnt("/dev/mqueue")) {
makedir("/dev/mqueue", 1777);
fs_mount("mqueue", "/dev/mqueue", "tmpfs", flags | MS_NODEV, NULL);
} }
/* /*
@@ -521,113 +523,6 @@ static void fs_init(void)
} }
/*
* Handle bootstrap transition to configured runlevel, start TTYs
*
* This is the final stage of bootstrap. It changes to the default
* (configured) runlevel, calls all external start scripts and final
* bootstrap hooks before bringing up TTYs.
*
* We must ensure that all declared `task [S]` and `run [S]` jobs in
* finit.conf, or *.conf in finit.d/, run to completion before we
* finalize the bootstrap process by calling this function.
*/
static void finalize(void *unused)
{
/* Clean up bootstrap-only tasks/services that never started */
dbg("Clean up all bootstrap-only tasks/services ...");
svc_prune_bootstrap();
/* All services/tasks/etc. in configure runlevel have started */
dbg("Running svc up hooks ...");
plugin_run_hooks(HOOK_SVC_UP);
service_step_all(SVC_TYPE_ANY);
/* Convenient SysV compat for when you just don't care ... */
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue)
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
/* Hooks that should run at the very end */
dbg("Calling all system up hooks ...");
plugin_run_hooks(HOOK_SYSTEM_UP);
service_step_all(SVC_TYPE_ANY);
/* Disable progress output at normal runtime */
enable_progress(0);
/* System bootrapped, launch TTYs et al */
bootstrap = 0;
service_step_all(SVC_TYPE_RESPAWN);
}
/*
* Start cranking the big state machine
*/
static void crank_worker(void *unused)
{
/*
* Initialize state machine and start all bootstrap tasks
* NOTE: no network available!
*/
sm_init(&sm);
sm_step(&sm);
}
/*
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
* allowed to complete their work in [S], or timeout, before we switch
* to the configured runlevel and call finalize(), should not take more
* than 120 sec.
*/
static void bootstrap_worker(void *work)
{
static struct wq final = {
.cb = finalize,
.delay = 10
};
static int cnt = 120 * 10; /* We run with 100ms period */
int level = cfglevel;
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);
schedule_work(work);
return;
}
if (cnt > 0)
dbg("All run/task have completed, resuming bootstrap.");
else
dbg("Timeout, resuming bootstrap.");
dbg("Starting runlevel change finalize ...");
schedule_work(&final);
/*
* Run startup scripts in the runparts directory, if any.
*/
if (runparts && fisdir(runparts) && !rescue)
run_parts(runparts, NULL, NULL, 1);
dbg("Flushing pending .conf file events ...");
conf_flush_events();
/*
* Start all tasks/services in the configured runlevel, or jump
* into the runlevel selected from the command line.
*/
if (cmdlevel) {
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
level = cmdlevel;
} else
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
service_runlevel(level);
}
static int version(int rc) static int version(int rc)
{ {
puts(PACKAGE_STRING); puts(PACKAGE_STRING);
@@ -658,7 +553,7 @@ static int usage(int rc)
" 2-9 Change runlevel\n" " 2-9 Change runlevel\n"
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n" " q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
" if modified, same as initctl reload or SIGHUP to PID 1\n" " if modified, same as initctl reload or SIGHUP to PID 1\n"
" 1, s, S Enter system rescue mode, runlevel 1\n" " 1, s, S Enter single user mode, no networking, runlevel 1\n"
"\n", prognm); "\n", prognm);
return rc; return rc;
@@ -708,14 +603,6 @@ static int telinit(int argc, char *argv[])
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct wq crank_work = {
.cb = crank_worker,
.delay = 10
};
struct wq bootstrap_work = {
.cb = bootstrap_worker,
.delay = 100
};
uev_ctx_t loop; uev_ctx_t loop;
/* user calling telinit or init */ /* user calling telinit or init */
@@ -765,8 +652,10 @@ int main(int argc, char *argv[])
/* /*
* In case of emergency. * In case of emergency.
*/ */
#ifdef RESCUE_MODE
if (rescue) if (rescue)
rescue = sulogin(0); rescue = sulogin(0);
#endif
/* /*
* Load plugins early, the first hook is in banner(), so we * Load plugins early, the first hook is in banner(), so we
@@ -815,11 +704,15 @@ int main(int argc, char *argv[])
cond_set_oneshot(plugin_hook_str(HOOK_BANNER)); cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP)); 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_oneshot("int/container");
/* /*
* Initialize .conf system and load static /etc/finit.conf then * Initialize .conf system and load static /etc/finit.conf then
* tell the world what we used. * tell the world what we used.
*/ */
devmon_init(); devmon_init(&loop);
conf_init(&loop); conf_init(&loop);
conf_saverc(); conf_saverc();
@@ -832,16 +725,15 @@ int main(int argc, char *argv[])
dbg("Starting initctl API responder ..."); dbg("Starting initctl API responder ...");
api_init(&loop); api_init(&loop);
dbg("Starting the big state machine ..."); dbg("Starting service interval monitor ...");
schedule_work(&crank_work); service_init(&loop);
dbg("Starting bootstrap finalize timer ...");
schedule_work(&bootstrap_work);
/* /*
* Background service tasks * Initialize state machine and start all bootstrap tasks
* NOTE: no network available!
*/ */
service_init(); sm_init(&sm);
sm_step(&sm);
/* /*
* Enter main loop to monitor /dev/initctl and services * Enter main loop to monitor /dev/initctl and services
+4 -2
View File
@@ -1,7 +1,7 @@
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins /* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -56,10 +56,11 @@
/* To use these, include config.h, or define FINIT_EXECPATH_ */ /* To use these, include config.h, or define FINIT_EXECPATH_ */
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit" #define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin" #define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
#define _PATH_GETTY FINIT_EXECPATH_ "/getty" #define _PATH_GETTY FINIT_EXECPATH_ "/getty"
#define CMD_SIZE 256 #define CMD_SIZE 1024
#define LINE_SIZE 1024 #define LINE_SIZE 1024
#define BUF_SIZE 4096 #define BUF_SIZE 4096
@@ -120,6 +121,7 @@ extern int single;
extern int bootstrap; extern int bootstrap;
extern int kerndebug; extern int kerndebug;
extern int syncsec; extern int syncsec;
extern int readiness;
extern char *fstab; extern char *fstab;
extern char *sdown; extern char *sdown;
extern char *network; extern char *network;
+2 -2
View File
@@ -1,6 +1,6 @@
/* Initialize and serve a login terminal /* Initialize and serve a login terminal
* *
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -369,7 +369,7 @@ restart:
static int usage(int rc) static int usage(int rc)
{ {
warnx("usage: getty [-h?] tty [speed [term]]"); warnx("usage: getty [-h?p] tty [speed [term]]");
return rc; return rc;
} }
+1 -1
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions for finit and its plugins /* Misc. utility functions for finit and its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+3 -2
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins /* Misc. utility functions and C-library extensions for finit and its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -88,7 +88,8 @@ int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (prin
int exec_runtask (char *cmd, char *args[]); int exec_runtask (char *cmd, char *args[]);
pid_t run_getty (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[]); pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
int run_parts (char *dir, char *cmd, const char *env[], int progress); pid_t run_bg (char *cmd, char *args[]);
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
/* /*
* Defaults to user "root" and group "wheel" (root) if: * Defaults to user "root" and group "wheel" (root) if:
+11 -4
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool /* New client tool, replaces old /dev/initctl API and telinit tool
* *
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -209,19 +209,26 @@ static int do_runlevel(char *arg)
if (!arg) { if (!arg) {
int prevlevel = 0; int prevlevel = 0;
int currlevel; int currlevel;
char prev; char prev, curr;
currlevel = runlevel_get(&prevlevel); currlevel = runlevel_get(&prevlevel);
if (255 == currlevel) { switch (currlevel) {
case 255:
printf("unknown\n"); printf("unknown\n");
return 0; return 0;
case INIT_LEVEL:
curr = 'S';
break;
default:
curr = currlevel + '0';
break;
} }
prev = prevlevel + '0'; prev = prevlevel + '0';
if (prev <= '0' || prev > '9') if (prev <= '0' || prev > '9')
prev = 'N'; prev = 'N';
printf("%c %d\n", prev , currlevel); printf("%c %c\n", prev , curr);
return 0; return 0;
} }
+1 -1
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool /* New client tool, replaces old /dev/initctl API and telinit tool
* *
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* inotify watcher for files or directories /* inotify watcher for files or directories
* *
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com> * Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* inotify watcher for files or directories /* inotify watcher for files or directories
* *
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com> * Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Listens to kernel events like AC power status and manages sys/ conditions /* Listens to kernel events like AC power status and manages sys/ conditions
* *
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Finit daemon log functions /* Finit daemon log functions
* *
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+2 -1
View File
@@ -1,6 +1,6 @@
/* Finit daemon log functions /* Finit daemon log functions
* *
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -47,6 +47,7 @@ static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
va_start(ap, fmt); va_start(ap, fmt);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
fputs("\n", stderr);
va_end(ap); va_end(ap);
} }
#define info(fmt, args...) warnx(fmt, ##args) #define info(fmt, args...) warnx(fmt, ##args)
+1 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+8 -6
View File
@@ -1,6 +1,6 @@
/* Handle MD arrays /* Handle MD arrays
* *
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -28,6 +28,7 @@
#include <string.h> #include <string.h>
#include "helpers.h" #include "helpers.h"
#include "util.h"
static glob_t *get_arrays(void) static glob_t *get_arrays(void)
@@ -48,17 +49,18 @@ static glob_t *get_arrays(void)
*/ */
void mdadm_wait(void) void mdadm_wait(void)
{ {
size_t i;
glob_t *gl; glob_t *gl;
char cmd[160];
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */ /* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
gl = get_arrays(); gl = get_arrays();
if (gl) { if (gl) {
for (i = 0; i < gl->gl_pathc; i++) { size_t i;
char *array;
array = basename(gl->gl_pathv[i]); for (i = 0; i < gl->gl_pathc; i++) {
const char *array;
char cmd[160];
array = basenm(gl->gl_pathv[i]);
snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array); snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array);
run_interactive(cmd, "Marking MD array %s as clean", array); run_interactive(cmd, "Marking MD array %s as clean", array);
} }
+1 -1
View File
@@ -1,6 +1,6 @@
/* Mount and unmount helpers /* Mount and unmount helpers
* *
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* PID and PID file helpers /* PID and PID file helpers
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* PID and PID file helpers /* PID and PID file helpers
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+15 -11
View File
@@ -1,6 +1,6 @@
/* Plugin based services architecture for finit /* Plugin based services architecture for finit
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -43,6 +43,7 @@
#include "private.h" #include "private.h"
#include "service.h" #include "service.h"
#include "sig.h" #include "sig.h"
#include "util.h"
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0) #define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
#define SEARCH_PLUGIN(str) \ #define SEARCH_PLUGIN(str) \
@@ -77,23 +78,26 @@ static char *trim_ext(char *name)
int plugin_register(plugin_t *plugin) int plugin_register(plugin_t *plugin)
{ {
const char *nm;
if (!plugin) { if (!plugin) {
errno = EINVAL; errno = EINVAL;
return 1; return 1;
} }
/* Setup default name if none is provided */ /* Setup default name if none is provided */
if (!plugin->name) { nm = plugin->name;
if (!nm) {
#ifndef ENABLE_STATIC #ifndef ENABLE_STATIC
Dl_info info; Dl_info info;
if (dladdr(plugin, &info) && info.dli_fname) if (dladdr(plugin, &info) && info.dli_fname)
plugin->name = basename(info.dli_fname); nm = basenm(info.dli_fname);
#endif #endif
if (!plugin->name) if (!nm)
plugin->name = "unknown"; nm = "unknown";
} }
plugin->name = trim_ext(strdup(plugin->name)); plugin->name = trim_ext(strdup(nm));
/* Already registered? */ /* Already registered? */
if (plugin_find(plugin->name)) { if (plugin_find(plugin->name)) {
@@ -230,7 +234,7 @@ void plugin_script_run(hook_point_t no)
} else } else
env[2] = NULL; env[2] = NULL;
run_parts(path, NULL, env, 0); run_parts(path, NULL, env, 0, 0);
} }
#else #else
void plugin_script_run(hook_point_t no) void plugin_script_run(hook_point_t no)
@@ -253,7 +257,7 @@ void plugin_run_hook(hook_point_t no, void *arg)
PLUGIN_ITERATOR(p, tmp) { PLUGIN_ITERATOR(p, tmp) {
if (p->hook[no].cb) { if (p->hook[no].cb) {
dbg("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL"); dbg("Calling %s hook n:o %d (arg: %p) ...", basenm(p->name), no, arg ?: "NIL");
p->hook[no].cb(arg ? arg : p->hook[no].arg); p->hook[no].cb(arg ? arg : p->hook[no].arg);
} }
} }
@@ -288,7 +292,7 @@ static void generic_io_cb(uev_t *w, void *arg, int events)
/* Stop watcher, callback may close descriptor on us ... */ /* Stop watcher, callback may close descriptor on us ... */
uev_io_stop(w); uev_io_stop(w);
dbg("Calling I/O %s from runloop...", basename(p->name)); // dbg("Calling I/O %s from runloop...", basename(p->name));
p->io.cb(p->io.arg, w->fd, events); p->io.cb(p->io.arg, w->fd, events);
/* Update fd, may be changed by plugin callback, e.g., if FIFO */ /* Update fd, may be changed by plugin callback, e.g., if FIFO */
@@ -301,9 +305,9 @@ int plugin_io_init(plugin_t *p)
if (!is_io_plugin(p)) if (!is_io_plugin(p))
return 0; return 0;
dbg("Initializing plugin %s for I/O", basename(p->name)); dbg("Initializing plugin %s for I/O", basenm(p->name));
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) { if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
warn("Failed setting up I/O plugin %s", basename(p->name)); warn("Failed setting up I/O plugin %s", basenm(p->name));
return 1; return 1;
} }
+1 -1
View File
@@ -1,6 +1,6 @@
/* Plugin based services architecture for finit /* Plugin based services architecture for finit
* *
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* Private header file for main finit daemon, not for plugins /* Private header file for main finit daemon, not for plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* reboot, halt, poweroff, shutdown, suspend for finit /* reboot, halt, poweroff, shutdown, suspend for finit
* *
* Copyright (c) 2009-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2009-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+230
View File
@@ -0,0 +1,230 @@
#include <ctype.h> /* isdigit() */
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#ifdef _LIBITE_LITE
# include <libite/conio.h>
# include <libite/lite.h>
#else
# include <lite/conio.h>
# include <lite/lite.h>
#endif
#include "log.h"
#include "sig.h"
#include "util.h"
#ifdef __FINIT__
#include "helpers.h"
#else
#include <sys/prctl.h>
int debug;
static void print_desc(const char *prefix, const char *msg)
{
fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
}
static void print_result(int rc)
{
if (rc)
fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
else
fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
}
void sig_unblock(void)
{
struct sigaction sa;
sigset_t nmask;
int i;
sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
sigaddset(&nmask, SIGCHLD);
sigaddset(&nmask, SIGINT);
sigaddset(&nmask, SIGPWR);
sigaddset(&nmask, SIGSTOP);
sigaddset(&nmask, SIGTSTP);
sigaddset(&nmask, SIGCONT);
sigaddset(&nmask, SIGTERM);
sigaddset(&nmask, SIGUSR1);
sigaddset(&nmask, SIGUSR2);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
}
#endif /* __FINIT__ */
static void run_env(const char *env[])
{
size_t i = 0;
if (!env)
return;
while (env[i]) {
size_t j = i + 1;
if (!env[j])
break;
setenv(env[i], env[j], 1);
i += 2;
}
}
int run_parts(char *dir, char *cmd, const char *env[], int progress, int sysv)
{
size_t cmdlen = cmd ? strlen(cmd) : strlen("start");
struct dirent **d;
int i, num;
int rc = 0;
num = scandir(dir, &d, NULL, alphasort);
if (num < 0) {
dbg("No files found in %s, skipping ...", dir);
return -1;
}
for (i = 0; i < num; i++) {
char path[strlen(dir) + strlen(d[i]->d_name) + 3 + cmdlen];
const char *name = d[i]->d_name;
char *argv[4] = {
"sh",
"-c",
path,
NULL
};
struct stat st;
int result = 0;
pid_t pid = 0;
int status;
/* skip backup files */
if (name[strlen(name) - 1] == '~')
continue;
/* cannot rely on d_type, not supported on all filesystems */
paste(path, sizeof(path), dir, name);
if (stat(path, &st)) {
warn("failed stat(%s)", path);
continue;
}
/* skip non-executable files and directories */
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
dbg("skipping %s not an executable or is a directory", path);
continue;
}
if (sysv && name[0] != 'S' && name[0] != 'K') {
dbg("S-only flag set, skipping non-SysV script: %s", name);
continue;
}
/* If the callee didn't supply a run_parts() argument */
if (!cmd) {
/* Check if S<NUM>service or K<NUM>service notation is used */
if (name[0] == 'S' && isdigit(name[1]))
strlcat(path, " start", sizeof(path));
else if (name[0] == 'K' && isdigit(name[1]))
strlcat(path, " stop", sizeof(path));
} else {
strlcat(path, " ", sizeof(path));
strlcat(path, cmd, sizeof(path));
}
if (progress)
print_desc("Calling", path);
pid = fork();
if (!pid) {
sig_unblock();
run_env(env);
_exit(execvp(_PATH_BSHELL, argv));
}
if (waitpid(pid, &status, 0) == -1) {
warnx("failed starting %s, error %d: %s", path, errno, strerror(errno));
result = 1;
} else {
if (WIFEXITED(status)) {
result = WEXITSTATUS(status);
dbg("%s exited with status %d", path, result);
} else if (WIFSIGNALED(status)) {
warnx("%s terminated by signal %d", path, WTERMSIG(status));
result = 1;
} else
result = 1;
}
if (progress)
print_result(result);
rc += result;
}
while (num--)
free(d[num]);
free(d);
return rc;
}
#ifndef __FINIT__
static int usage(int rc)
{
warnx("usage: runparts [-dhps?] DIRECTORY");
return rc;
}
int main(int argc, char *argv[])
{
int rc, c, progress = 0, sysv = 0;
char *dir;
while ((c = getopt(argc, argv, "dh?ps")) != EOF) {
switch(c) {
case 'd':
debug = 1;
break;
case 'h':
case '?':
return usage(0);
case 'p':
progress = 1;
break;
case 's':
sysv = 1;
break;
default:
return usage(1);
}
}
if (optind >= argc)
return usage(1);
dir = argv[optind];
if (!fisdir(dir))
return usage(1);
prctl(PR_SET_CHILD_SUBREAPER, 1);
rc = run_parts(dir, NULL, NULL, progress, sysv);
if (rc == -1)
err(1, "failed run-parts %s", dir);
return rc;
}
#endif /* __FINIT__ */
+1 -1
View File
@@ -1,6 +1,6 @@
/* Work queue helper functions /* Work queue helper functions
* *
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Work queue helper functions /* Work queue helper functions
* *
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+15 -1
View File
@@ -1,6 +1,6 @@
/* List and enable/disable service configurations /* List and enable/disable service configurations
* *
* Copyright (c) 2017-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2017-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -41,6 +41,10 @@ static int is_builtin(char *arg)
{ {
svc_t *svc; svc_t *svc;
/* skip check, we may be in non-responsive bootstrap */
if (iforce)
return 0;
svc = client_svc_find(arg); svc = client_svc_find(arg);
if (!svc) if (!svc)
return 0; return 0;
@@ -262,6 +266,11 @@ int serv_enable(char *arg)
return serv_list("available"); return serv_list("available");
} }
if (arg[0] == '/') {
WARNX("absolute paths not supported, this command manages %s/available/", finit_rcsd);
return serv_list("available");
}
len = strlen(arg); len = strlen(arg);
serv = alloca(len + 6); serv = alloca(len + 6);
if (!serv) if (!serv)
@@ -322,6 +331,11 @@ int do_disable(char *arg, int check)
return serv_list("enabled"); return serv_list("enabled");
} }
if (arg[0] == '/') {
WARNX("absolute paths not supported, this command manages %s/enabled/", finit_rcsd);
return serv_list("available");
}
len = strlen(arg); len = strlen(arg);
serv = alloca(len + 6); serv = alloca(len + 6);
if (!serv) if (!serv)
+1 -1
View File
@@ -1,6 +1,6 @@
/* List and enable/disable service configurations /* List and enable/disable service configurations
* *
* Copyright (c) 2017-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2017-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+237 -111
View File
@@ -1,7 +1,7 @@
/* Finit service monitor, task starter and generic API for managing svc_t /* Finit service monitor, task starter and generic API for managing svc_t
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -56,6 +56,12 @@
#include "utmp-api.h" #include "utmp-api.h"
#include "schedule.h" #include "schedule.h"
/*
* run tasks block other tasks/services from starting, we track the
* current run task here. For service_step() and service_start().
*/
static pid_t run_block_pid;
static struct wq work = { static struct wq work = {
.cb = service_worker, .cb = service_worker,
}; };
@@ -324,14 +330,15 @@ static int lredirect(svc_t *svc)
snprintf(rot, sizeof(rot), "%d:%d", logfile_size_max, logfile_count_max); snprintf(rot, sizeof(rot), "%d:%d", logfile_size_max, logfile_count_max);
snprintf(pid, sizeof(pid), "%d", svc_pid); 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, "-I", pid, "-r", rot, debug ? "-s" : NULL, NULL);
} else { } else {
char sz[20], num[3]; char sz[20], num[3];
snprintf(sz, sizeof(sz), "%d", logfile_size_max); snprintf(sz, sizeof(sz), "%d", logfile_size_max);
snprintf(num, sizeof(num), "%d", logfile_count_max); snprintf(num, sizeof(num), "%d", logfile_count_max);
execlp(_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, NULL);
} }
_exit(1); _exit(1);
} }
@@ -345,9 +352,9 @@ static int lredirect(svc_t *svc)
char pid[16]; char pid[16];
snprintf(pid, sizeof(pid), "%d", svc_pid); snprintf(pid, sizeof(pid), "%d", svc_pid);
execlp("logger", "logger", "-t", tag, "-p", prio, "-I", pid, NULL); execlp("logger", "logger", "-t", tag, "-p", prio, "-I", pid, debug ? "-s" : NULL, NULL);
} else { } else {
execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, NULL); execlp(_PATH_LOGIT, "logit", "-t", tag, "-p", prio, debug ? "-s" : NULL, NULL);
} }
_exit(1); _exit(1);
} }
@@ -388,11 +395,8 @@ static int redirect(svc_t *svc)
*/ */
static void source_env(svc_t *svc) static void source_env(svc_t *svc)
{ {
char buf[LINE_SIZE]; char *buf, *val, *line, *fn;
char *line;
size_t len;
FILE *fp; FILE *fp;
char *fn;
fn = svc_getenv(svc); fn = svc_getenv(svc);
if (!fn) if (!fn)
@@ -403,11 +407,19 @@ static void source_env(svc_t *svc)
if (!fp) if (!fp)
return; return;
buf = alloca(LINE_SIZE);
val = alloca(LINE_SIZE);
if (!buf || !val) {
warn("Failed allocating temporary env buffer");
return;
}
line = buf; line = buf;
len = sizeof(buf); while (fgets(line, LINE_SIZE, fp)) {
while (fgets(line, len, fp)) {
char *key = chomp(line); char *key = chomp(line);
wordexp_t we = { 0 };
char *value, *end; char *value, *end;
size_t i;
/* skip any leading whitespace */ /* skip any leading whitespace */
while (isspace(*key)) while (isspace(*key))
@@ -460,7 +472,40 @@ static void source_env(svc_t *svc)
*end-- = 0; *end-- = 0;
} }
setenv(key, value, 1); /* strip any leading 'set ' */
end = key;
if (!strncmp(key, "set", 3))
end += 3;
/* check key, no spaces allowed */
while (*end && isspace(*end))
end++;
key = end;
while (*end && !isspace(*end))
end++;
if (*end != 0) {
warnx("'%s=%s': not a valid identifier", key, val);
continue; /* invalid key */
}
switch (wordexp(value, &we, 0)) {
case 0:
for (i = 0, *val = 0; i < we.we_wordc; i++) {
if (i > 0)
strlcat(val, " ", LINE_SIZE);
strlcat(val, we.we_wordv[i], LINE_SIZE);
}
setenv(key, val, 1);
wordfree(&we);
break;
case WRDE_NOSPACE:
wordfree(&we);
/* fallthrough */
default:
setenv(key, value, 1);
break;
}
} }
fclose(fp); fclose(fp);
@@ -560,6 +605,15 @@ static pid_t service_fork(svc_t *svc)
source_env(svc); source_env(svc);
} }
if (pid > 1) {
char grnam[80];
if (svc_is_tty(svc))
cgroup_user("getty", pid);
else
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
}
return pid; return pid;
} }
@@ -575,7 +629,6 @@ static int service_start(svc_t *svc)
int result = 0, do_progress = 1; int result = 0, do_progress = 1;
char cmdline[CMD_SIZE] = ""; char cmdline[CMD_SIZE] = "";
sigset_t nmask, omask; sigset_t nmask, omask;
char grnam[80];
pid_t pid; pid_t pid;
size_t i; size_t i;
@@ -586,6 +639,10 @@ static int service_start(svc_t *svc)
if (is_norespawn()) if (is_norespawn())
return 1; return 1;
/* Waiting for a run task to complete */
if (run_block_pid)
return 1;
/* Don't try and start service if it doesn't exist. */ /* Don't try and start service if it doesn't exist. */
if (!whichp(svc->cmd)) { if (!whichp(svc->cmd)) {
logit(LOG_WARNING, "%s: missing %s or not in $PATH", svc_ident(svc, NULL, 0), svc->cmd); logit(LOG_WARNING, "%s: missing %s or not in $PATH", svc_ident(svc, NULL, 0), svc->cmd);
@@ -611,6 +668,9 @@ static int service_start(svc_t *svc)
} }
compose_cmdline(svc, cmdline, sizeof(cmdline)); compose_cmdline(svc, cmdline, sizeof(cmdline));
if (bootstrap)
conf_save_exec_order(svc, cmdline, -1);
if (svc_is_sysv(svc)) if (svc_is_sysv(svc))
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", cmdline); logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", cmdline);
@@ -644,29 +704,26 @@ static int service_start(svc_t *svc)
goto fail; goto fail;
} }
if (pid > 1) { if (pid > 1) {
dbg("Starting %s as PID %d", svc_ident(svc, NULL, 0), pid);
svc->pid = pid; svc->pid = pid;
svc->start_time = jiffies(); svc->start_time = jiffies();
} else if (pid == 0) { } else if (pid == 0) {
char *args[MAX_NUM_SVC_ARGS + 1]; char *args[MAX_NUM_SVC_ARGS + 1];
int status; int status;
pid = getpid(); if (!svc_is_tty(svc))
if (svc_is_tty(svc)) {
cgroup_user("getty", pid);
} else {
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
redirect(svc); redirect(svc);
}
if (!svc_is_sysv(svc)) { if (!svc_is_sysv(svc)) {
wordexp_t we = { 0 }; wordexp_t we = { 0 };
int rc; int rc;
if (svc->notify) { if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) {
if (client_command(INIT_CMD_NOTIFY_SOCKET)) { if (client_command(INIT_CMD_NOTIFY_SOCKET)) {
err(1, "%s: failed creating notify socket", svc_ident(svc, NULL, 0)); err(1, "%s: failed creating notify socket", svc_ident(svc, NULL, 0));
client_disconnect(); client_disconnect();
svc->notify = 0; /* does not change parent, restarting may work. */ /* does not change parent, restarting may work. */
svc->notify = SVC_NOTIFY_NONE;
} else { } else {
char val[20]; char val[20];
@@ -691,7 +748,7 @@ static int service_start(svc_t *svc)
if (len == 0) if (len == 0)
break; break;
if (svc->notify) { if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) {
char *ptr = strstr(arg, "%n"); char *ptr = strstr(arg, "%n");
if (ptr) { if (ptr) {
@@ -788,7 +845,7 @@ static int service_start(svc_t *svc)
*/ */
pid = setsid(); pid = setsid();
if (pid < 1) if (pid < 1)
logit(LOG_ERR, "failed setsid(), pid %d: %s", pid, strerror(errno)); syslog(LOG_ERR, "failed setsid(), pid %d: %s", pid, strerror(errno));
sig_unblock(); sig_unblock();
@@ -799,6 +856,8 @@ static int service_start(svc_t *svc)
else else
status = execvp(args[0], &args[1]); status = execvp(args[0], &args[1]);
syslog(LOG_ERR, "failed starting %s, exit code %d: %s", svc_ident(svc, NULL, 0),
status, strerror(errno));
_exit(status); _exit(status);
} else if (debug) { } else if (debug) {
dbg("Starting PID %d: %s", svc->pid, cmdline); dbg("Starting PID %d: %s", svc->pid, cmdline);
@@ -809,35 +868,21 @@ static int service_start(svc_t *svc)
switch (svc->type) { switch (svc->type) {
case SVC_TYPE_RUN: case SVC_TYPE_RUN:
svc->status = complete(svc->cmd, pid); run_block_pid = pid;
dbg("collected %s(%d), normal exit: %d, signaled: %d, exit code: %d",
svc_ident(svc, NULL, 0), pid, WIFEXITED(svc->status),
WIFSIGNALED(svc->status), WEXITSTATUS(svc->status));
if (WIFEXITED(svc->status)) {
svc->started = 1;
result = WEXITSTATUS(svc->status);
} else {
svc->started = 0;
result = 1;
}
svc->start_time = svc->pid = 0;
svc->once++;
svc_mark_clean(svc); /* done, regardless of exit status */
svc_set_state(svc, SVC_STOPPING_STATE);
break; break;
case SVC_TYPE_SERVICE: case SVC_TYPE_SERVICE:
pid_file_create(svc); pid_file_create(svc);
break; break;
default: default:
break; break;
} }
fail: fail:
sigprocmask(SIG_SETMASK, &omask, NULL); sigprocmask(SIG_SETMASK, &omask, NULL);
if (do_progress) if (do_progress && !run_block_pid)
print_result(result); print_result(result);
if (bootstrap && !run_block_pid)
conf_save_exec_order(svc, NULL, result);
return result; return result;
} }
@@ -850,17 +895,26 @@ fail:
*/ */
static void service_kill(svc_t *svc) static void service_kill(svc_t *svc)
{ {
char *nm, *id = svc_ident(svc, NULL, 0);
service_timeout_cancel(svc); service_timeout_cancel(svc);
if (svc->pid <= 1) { if (svc->pid <= 1) {
/* Avoid killing ourselves or all processes ... */ /* Avoid killing ourselves or all processes ... */
dbg("%s: Aborting SIGKILL, already terminated.", svc_ident(svc, NULL, 0)); dbg("%s: Aborting SIGKILL, already terminated.", id);
return; return;
} }
dbg("%s: Sending SIGKILL to process group %d", pid_get_name(svc->pid, NULL, 0), svc->pid); nm = pid_get_name(svc->pid, NULL, 0);
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending SIGKILL ...", if (!nm) {
svc_ident(svc, NULL, 0), svc->pid); /* PID possibly monitored by someone else? */
dbg("%s: Aborting SIGKILL, PID[%d] no longer exists.", id, svc->pid);
service_monitor(svc->pid, 0);
return;
}
dbg("%s: Sending SIGKILL to process group %d", nm, svc->pid);
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending SIGKILL ...", id, svc->pid);
if (runlevel != 1) if (runlevel != 1)
print_desc("Killing ", svc->desc); print_desc("Killing ", svc->desc);
@@ -871,6 +925,19 @@ static void service_kill(svc_t *svc)
print(2, NULL); print(2, NULL);
} }
/* Ensure we don't have any notify socket lingering */
static void service_notify_stop(svc_t *svc)
{
if (svc->notify != SVC_NOTIFY_SYSTEMD && svc->notify != SVC_NOTIFY_S6)
return;
uev_io_stop(&svc->notify_watcher);
if (svc->notify_watcher.fd > 0) {
close(svc->notify_watcher.fd);
svc->notify_watcher.fd = 0;
}
}
/* /*
* Clean up any lingering state from dead/killed services * Clean up any lingering state from dead/killed services
*/ */
@@ -886,12 +953,7 @@ static void service_cleanup(svc_t *svc)
logit(LOG_CRIT, "Failed removing service %s pidfile %s", logit(LOG_CRIT, "Failed removing service %s pidfile %s",
svc_ident(svc, NULL, 0), fn); svc_ident(svc, NULL, 0), fn);
/* Ensure we don't have any notify socket lingering */ service_notify_stop(svc);
if (svc->notify && svc->notify_watcher.fd > 0) {
uev_io_stop(&svc->notify_watcher);
close(svc->notify_watcher.fd);
svc->notify_watcher.fd = 0;
}
/* No longer running, update books. */ /* No longer running, update books. */
if (svc_is_tty(svc) && svc->pid > 1) if (svc_is_tty(svc) && svc->pid > 1)
@@ -928,13 +990,21 @@ int service_stop(svc_t *svc)
compose_cmdline(svc, cmdline, sizeof(cmdline)); compose_cmdline(svc, cmdline, sizeof(cmdline));
if (!svc_is_sysv(svc)) { if (!svc_is_sysv(svc)) {
char *nm = pid_get_name(svc->pid, NULL, 0);
const char *sig = sig_name(svc->sighalt);
char *id = svc_ident(svc, NULL, 0);
if (svc->pid <= 1) if (svc->pid <= 1)
return 1; return 1;
if (!nm) {
dbg("Skipping stop (%s) of %s, PID[%d] no longer exists.", sig, id, svc->pid);
service_cleanup(svc);
svc_set_state(svc, SVC_HALTED_STATE);
return 0;
}
dbg("Sending %s to pid:%d name:%s", sig_name(svc->sighalt), dbg("Sending %s to pid:%d name:%s(%s)", sig, svc->pid, id, nm);
svc->pid, pid_get_name(svc->pid, NULL, 0)); logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending %s ...", id, svc->pid, sig);
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending %s ...",
svc_ident(svc, NULL, 0), svc->pid, sig_name(svc->sighalt));
} else { } else {
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", cmdline); logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", cmdline);
} }
@@ -957,7 +1027,11 @@ int service_stop(svc_t *svc)
if (!svc->desc[0]) if (!svc->desc[0])
do_progress = 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); print_desc("Stopping ", svc->desc);
if (!svc_is_sysv(svc)) { if (!svc_is_sysv(svc)) {
@@ -1013,7 +1087,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); print_result(rc);
return rc; return rc;
@@ -1140,13 +1214,15 @@ static void parse_log(svc_t *svc, char *arg)
} }
} }
static int parse_notify(char *arg) static svc_notify_t parse_notify(char *arg)
{ {
if (!strcmp(arg, "systemd")) if (!strcmp(arg, "systemd"))
return 1; return SVC_NOTIFY_SYSTEMD;
if (!strcmp(arg, "s6")) if (!strcmp(arg, "s6"))
return 2; return SVC_NOTIFY_S6;
return 0; /* unsupported/disabled */ if (!strcmp(arg, "pid"))
return SVC_NOTIFY_PID;
return SVC_NOTIFY_NONE; /* unsupported/none */
} }
static void parse_env(svc_t *svc, char *env) static void parse_env(svc_t *svc, char *env)
@@ -1379,7 +1455,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 * before they are started. Or restarted, or even SIGHUP'ed, when the
* gateway changes or interfaces come and go. The special case when a * gateway changes or interfaces come and go. The special case when a
* service is declared with <!> means it does not support SIGHUP but * 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, * Conditions can for example be: pid/NAME:ID for process dependencies,
* net/<IFNAME>/up or net/<IFNAME>/exists. The condition handling is * net/<IFNAME>/up or net/<IFNAME>/exists. The condition handling is
@@ -1408,6 +1488,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
char *id = NULL, *env = NULL, *cgroup = NULL; char *id = NULL, *env = NULL, *cgroup = NULL;
char *pre_script = NULL, *post_script = NULL; char *pre_script = NULL, *post_script = NULL;
char *ready_script = NULL, *conflict = NULL; char *ready_script = NULL, *conflict = NULL;
char ident[MAX_IDENT_LEN];
char *ifstmt = NULL; char *ifstmt = NULL;
char *notify = NULL; char *notify = NULL;
struct tty tty = { 0 }; struct tty tty = { 0 };
@@ -1532,8 +1613,16 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
} }
name = parse_name(cmd, name); name = parse_name(cmd, name);
if (!id) strlcpy(ident, name, sizeof(ident));
if (!id) {
id = ""; id = "";
} else {
strlcat(ident, ":", sizeof(ident));
strlcat(ident, id, sizeof(ident));
}
if (ifstmt && !svc_ifthen(1, ident, ifstmt, nowarn))
return 0;
levels = conf_parse_runlevels(runlevels); levels = conf_parse_runlevels(runlevels);
if (runlevel != INIT_LEVEL && !ISOTHER(levels, INIT_LEVEL)) { if (runlevel != INIT_LEVEL && !ISOTHER(levels, INIT_LEVEL)) {
@@ -1698,17 +1787,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
else else
svc->log.enabled = 0; svc->log.enabled = 0;
} }
if (notify) {
int type = parse_notify(notify);
if (type <= 0) if (notify)
goto disable_notify; svc->notify = parse_notify(notify);
svc->notify = type; else
} else if (svc->notify) { svc->notify = readiness;
disable_notify:
/* XXX: close existing socket */
svc->notify = 0;
}
if (desc) if (desc)
strlcpy(svc->desc, desc, sizeof(svc->desc)); strlcpy(svc->desc, desc, sizeof(svc->desc));
else if (type == SVC_TYPE_TTY) else if (type == SVC_TYPE_TTY)
@@ -1878,6 +1962,17 @@ done:
/* No longer running, update books. */ /* No longer running, update books. */
svc->start_time = svc->pid = 0; svc->start_time = svc->pid = 0;
cont: cont:
if (lost == run_block_pid) {
int result = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
svc_mark_clean(svc); /* done, regardless of exit status */
run_block_pid = 0;
if (svc->desc[0])
print_result(result);
if (bootstrap)
conf_save_exec_order(svc, NULL, result);
}
if (!service_step(svc)) { if (!service_step(svc)) {
/* Clean out any bootstrap tasks, they've had their time in the sun. */ /* Clean out any bootstrap tasks, they've had their time in the sun. */
if (svc_clean_bootstrap(svc)) if (svc_clean_bootstrap(svc))
@@ -1933,7 +2028,7 @@ void service_mark_unavail(void)
if (!svc->ifstmt[0]) if (!svc->ifstmt[0])
continue; continue;
if (!svc_ifthen(svc_ident(svc, buf, sizeof(buf)), svc->ifstmt)) if (!svc_ifthen(1, svc_ident(svc, buf, sizeof(buf)), svc->ifstmt, svc->nowarn))
svc_mark(svc); svc_mark(svc);
} }
} }
@@ -2161,6 +2256,7 @@ static void service_retry(svc_t *svc)
static void svc_set_state(svc_t *svc, svc_state_t new_state) static void svc_set_state(svc_t *svc, svc_state_t new_state)
{ {
svc_state_t *state = (svc_state_t *)&svc->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 PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
if (new_state == SVC_STOPPING_STATE) { if (new_state == SVC_STOPPING_STATE) {
@@ -2181,7 +2277,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)); snprintf(failure, sizeof(failure), "%s/%s/failure", svc_typestr(svc), svc_ident(svc, NULL, 0));
/* create success/failure condition when entering SVC_DONE_STATE. */ /* 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)) if (svc->started && !WEXITSTATUS(svc->status))
cond_set_oneshot(success); cond_set_oneshot(success);
else else
@@ -2189,7 +2285,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new_state)
} }
/* clear all conditions when entering SVC_HALTED_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(success);
cond_clear(failure); cond_clear(failure);
} }
@@ -2199,9 +2295,14 @@ static void svc_set_state(svc_t *svc, svc_state_t new_state)
char cond[MAX_COND_LEN]; char cond[MAX_COND_LEN];
snprintf(cond, sizeof(cond), "service/%s/", svc_ident(svc, NULL, 0)); 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_HALTED_STATE:
case SVC_RUNNING_STATE: case SVC_RUNNING_STATE:
strlcat(cond, svc_status(svc), sizeof(cond)); strlcat(cond, svc_status(svc), sizeof(cond));
@@ -2229,8 +2330,8 @@ void service_forked(svc_t *svc)
svc_set_state(svc, SVC_RUNNING_STATE); svc_set_state(svc, SVC_RUNNING_STATE);
} }
/* Set service/foo/ready condition for services and call optional ready:script */ /* Set or clear service/foo/ready condition for services and call optional ready:script */
void service_ready(svc_t *svc) void service_ready(svc_t *svc, int ready)
{ {
char buf[MAX_COND_LEN]; char buf[MAX_COND_LEN];
@@ -2238,10 +2339,13 @@ void service_ready(svc_t *svc)
return; return;
snprintf(buf, sizeof(buf), "service/%s/ready", svc_ident(svc, NULL, 0)); snprintf(buf, sizeof(buf), "service/%s/ready", svc_ident(svc, NULL, 0));
cond_set(buf); if (ready) {
cond_set(buf);
if (svc_has_ready(svc)) if (svc_has_ready(svc))
service_ready_script(svc); service_ready_script(svc);
} else
cond_clear(buf);
} }
/* /*
@@ -2251,11 +2355,11 @@ void service_ready(svc_t *svc)
*/ */
int service_step(svc_t *svc) int service_step(svc_t *svc)
{ {
cond_state_t cond;
svc_state_t old_state;
svc_cmd_t enabled;
char *restart_cnt = (char *)&svc->restart_cnt; char *restart_cnt = (char *)&svc->restart_cnt;
int changed = 0; int changed = 0, waiting = 0;
svc_state_t old_state;
cond_state_t cond;
svc_cmd_t enabled;
int err; int err;
restart: restart:
@@ -2272,9 +2376,11 @@ restart:
svc_set_state(svc, SVC_WAITING_STATE); svc_set_state(svc, SVC_WAITING_STATE);
else { else {
if (svc_is_conflict(svc)) { if (svc_is_conflict(svc)) {
#if 0
logit(svc->nowarn ? LOG_DEBUG : LOG_INFO, logit(svc->nowarn ? LOG_DEBUG : LOG_INFO,
"%s in conflict with %s, checking again ...", "%s in conflict with %s, checking again ...",
svc_ident(svc, NULL, 0), svc->conflict); svc_ident(svc, NULL, 0), svc->conflict);
#endif
if (!svc_conflicts(svc)) if (!svc_conflicts(svc))
svc_unblock(svc); svc_unblock(svc);
} }
@@ -2293,11 +2399,7 @@ restart:
char condstr[MAX_COND_LEN]; char condstr[MAX_COND_LEN];
dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0)); dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
if (svc->notify && svc->notify_watcher.fd > 0) { service_notify_stop(svc);
uev_io_stop(&svc->notify_watcher);
close(svc->notify_watcher.fd);
svc->notify_watcher.fd = 0;
}
service_timeout_cancel(svc); service_timeout_cancel(svc);
cond_clear(mkcond(svc, condstr, sizeof(condstr))); cond_clear(mkcond(svc, condstr, sizeof(condstr)));
@@ -2372,6 +2474,10 @@ restart:
err = service_start(svc); err = service_start(svc);
if (err) { if (err) {
/* Busy, waiting for run task, try again later */
if (run_block_pid)
break;
if (svc_is_missing(svc)) { if (svc_is_missing(svc)) {
svc_set_state(svc, SVC_HALTED_STATE); svc_set_state(svc, SVC_HALTED_STATE);
break; break;
@@ -2413,6 +2519,7 @@ restart:
if (svc_is_runtask(svc)) { /* only run/task, not sysv here */ if (svc_is_runtask(svc)) { /* only run/task, not sysv here */
svc_set_state(svc, SVC_STOPPING_STATE); svc_set_state(svc, SVC_STOPPING_STATE);
svc->restart_tot++;
svc->once++; svc->once++;
break; break;
} }
@@ -2432,7 +2539,7 @@ restart:
case COND_ON: case COND_ON:
if (svc_is_changed(svc)) { if (svc_is_changed(svc)) {
if (svc_nohup(svc)) if (svc_nohup(svc) || !svc_is_daemon(svc))
service_stop(svc); service_stop(svc);
else { else {
/* /*
@@ -2446,6 +2553,8 @@ restart:
svc_mark_clean(svc); svc_mark_clean(svc);
} }
if (svc->notify == SVC_NOTIFY_NONE)
service_ready(svc, 1);
break; break;
} }
break; break;
@@ -2470,16 +2579,21 @@ restart:
svc_set_state(svc, SVC_RUNNING_STATE); svc_set_state(svc, SVC_RUNNING_STATE);
/* Reassert condition if we go from waiting and no change */ /* Reassert condition if we go from waiting and no change */
if (!svc_is_changed(svc)) { if (!svc_is_changed(svc)) {
char name[MAX_COND_LEN]; if (svc->notify == SVC_NOTIFY_PID) {
char name[MAX_COND_LEN];
mkcond(svc, name, sizeof(name)); mkcond(svc, name, sizeof(name));
dbg("Reassert condition %s", name); dbg("Reassert condition %s", name);
cond_set_path(cond_path(name), COND_ON); cond_set_path(cond_path(name), COND_ON);
}
dbg("Reassert %s ready condition", svc_ident(svc, NULL, 0));
service_ready(svc, 1);
} }
break; break;
case COND_OFF: case COND_OFF:
dbg("Condition for %s is off, sending SIGCONT + SIGTERM", svc->name); dbg("Condition for %s is off, sending SIGCONT + SIGTERM", svc_ident(svc, NULL, 0));
kill(svc->pid, SIGCONT); kill(svc->pid, SIGCONT);
service_stop(svc); service_stop(svc);
break; break;
@@ -2490,6 +2604,9 @@ restart:
break; break;
} }
/* Are we waiting for a run task to complete? */
waiting = run_block_pid;
if (svc->state != old_state) { if (svc->state != old_state) {
dbg("%20s(%4d): -> %8s", svc_ident(svc, NULL, 0), svc->pid, svc_status(svc)); dbg("%20s(%4d): -> %8s", svc_ident(svc, NULL, 0), svc->pid, svc_status(svc));
changed++; changed++;
@@ -2501,7 +2618,7 @@ done:
* When a run/task/service changes state, e.g. transitioning from * When a run/task/service changes state, e.g. transitioning from
* waiting to running, other services may need to change state too. * waiting to running, other services may need to change state too.
*/ */
if (changed) if (changed || waiting)
schedule_work(&work); schedule_work(&work);
return 0; return 0;
@@ -2530,7 +2647,12 @@ void service_runtask_clean(void)
if (!svc_is_runtask(svc)) if (!svc_is_runtask(svc))
continue; continue;
svc->once = 0; /* run/task declared with <!> */
if (svc->sighup)
svc->once = 1;
else
svc->once = 0;
if (svc->state == SVC_DONE_STATE) if (svc->state == SVC_DONE_STATE)
svc_set_state(svc, SVC_HALTED_STATE); svc_set_state(svc, SVC_HALTED_STATE);
} }
@@ -2538,6 +2660,7 @@ void service_runtask_clean(void)
/** /**
* service_completed - Have run/task completed in current runlevel * 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 * 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 * runlevel. E.g., at bootstrap we must wait for these scripts or
@@ -2550,7 +2673,7 @@ void service_runtask_clean(void)
* Returns: * Returns:
* %TRUE(1) or %FALSE(0) * %TRUE(1) or %FALSE(0)
*/ */
int service_completed(void) int service_completed(svc_t **svcp)
{ {
svc_t *svc, *iter = NULL; svc_t *svc, *iter = NULL;
@@ -2572,6 +2695,8 @@ int service_completed(void)
if (!svc->once) { if (!svc->once) {
dbg("%s has not yet completed ...", svc_ident(svc, NULL, 0)); dbg("%s has not yet completed ...", svc_ident(svc, NULL, 0));
if (svcp)
*svcp = svc;
return 0; return 0;
} }
dbg("%s has completed ...", svc_ident(svc, NULL, 0)); dbg("%s has completed ...", svc_ident(svc, NULL, 0));
@@ -2590,16 +2715,16 @@ void service_notify_reconf(void)
svc_t *svc, *iter = NULL; svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!svc->notify) if (svc->notify == SVC_NOTIFY_PID)
continue; /* managed by pidfile plugin */ continue; /* managed by pidfile plugin */
if (svc->state != SVC_RUNNING_STATE) if (svc->state != SVC_RUNNING_STATE)
continue; continue;
if (svc_is_changed(svc) || svc_is_starting(svc)) if (svc->notify != SVC_NOTIFY_NONE && (svc_is_changed(svc) || svc_is_starting(svc)))
continue; continue;
service_ready(svc); service_ready(svc, 1);
} }
} }
@@ -2640,10 +2765,10 @@ void service_notify_cb(uev_t *w, void *arg, int events)
* the service_notify_reconf() function to step the * the service_notify_reconf() function to step the
* generation of the READY condition. * generation of the READY condition.
*/ */
service_ready(svc); service_ready(svc, 1);
/* s6 applications close their socket after notification */ /* s6 applications close their socket after notification */
if (svc->notify == 2) { if (svc->notify == SVC_NOTIFY_S6) {
uev_io_stop(w); uev_io_stop(w);
close(w->fd); close(w->fd);
w->fd = 0; w->fd = 0;
@@ -2691,23 +2816,24 @@ static void service_interval_cb(uev_t *w, void *arg, int events)
} }
} }
service_init(); service_init(NULL);
} }
/* /*
* The service_interval may change (conf) between invocations, so we * The service_interval may change (conf) between invocations, so we
* periodically reset the one-shot timer instead of using a periodic. * periodically reset the one-shot timer instead of using a periodic.
*/ */
void service_init(void) void service_init(uev_ctx_t *ctx)
{ {
static int initialized = 0; static int initialized = 0;
static uev_t watcher; static uev_t watcher;
if (!initialized) { if (!initialized)
uev_timer_init(ctx, &watcher, service_interval_cb, NULL, service_interval, 0); uev_timer_init(ctx, &watcher, service_interval_cb, NULL, service_interval, 0);
initialized = 1; else
} else
uev_timer_set(&watcher, service_interval, 0); uev_timer_set(&watcher, service_interval, 0);
initialized = 1;
} }
/** /**
+4 -4
View File
@@ -1,7 +1,7 @@
/* Finit service monitor, task starter and generic API for managing svc_t /* Finit service monitor, task starter and generic API for managing svc_t
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -42,17 +42,17 @@ int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc
int service_timeout_cancel (svc_t *svc); int service_timeout_cancel (svc_t *svc);
void service_forked (svc_t *svc); void service_forked (svc_t *svc);
void service_ready (svc_t *svc); void service_ready (svc_t *svc, int ready);
int service_stop (svc_t *svc); int service_stop (svc_t *svc);
int service_step (svc_t *svc); int service_step (svc_t *svc);
void service_step_all (int types); void service_step_all (int types);
void service_worker (void *unused); void service_worker (void *unused);
int service_completed (void); int service_completed (svc_t **svc);
void service_notify_reconf (void); void service_notify_reconf (void);
void service_init (void); void service_init (uev_ctx_t *ctx);
#endif /* FINIT_SERVICE_H_ */ #endif /* FINIT_SERVICE_H_ */
+1 -1
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to! /* Signal management - Be conservative with what finit responds to!
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to! /* Signal management - Be conservative with what finit responds to!
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+117 -12
View File
@@ -31,6 +31,7 @@
#include "conf.h" #include "conf.h"
#include "helpers.h" #include "helpers.h"
#include "private.h" #include "private.h"
#include "schedule.h"
#include "service.h" #include "service.h"
#include "sig.h" #include "sig.h"
#include "tty.h" #include "tty.h"
@@ -43,12 +44,61 @@ sm_t sm;
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */ #define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */
#endif #endif
void sm_init(sm_t *sm) /*
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
* allowed to complete their work in [S], or timeout, before we switch
* to the configured runlevel and call finalize(), should not take more
* than 120 sec.
*/
static void sm_check_bootstrap(void *work)
{ {
sm->state = SM_BOOTSTRAP_STATE; static int timeout = 120;
sm->newlevel = -1; int bootstrap_done;
sm->reload = 0; int level = cfglevel;
sm->in_teardown = 0; svc_t *svc = NULL;
dbg("Step all services ...");
service_step_all(SVC_TYPE_ANY);
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 (timeout > 0) {
dbg("All run/task have completed, resuming bootstrap.");
} 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();
/*
* Start all tasks/services in the configured runlevel, or jump
* into the runlevel selected from the command line.
*/
if (cmdlevel) {
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
level = cmdlevel;
} else
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
service_runlevel(level);
/* Clean up bootstrap-only tasks/services that never started */
dbg("Clean up all bootstrap-only tasks/services ...");
svc_prune_bootstrap();
/* All services/tasks/etc. in configure runlevel have started */
dbg("Running svc up hooks ...");
plugin_run_hooks(HOOK_SVC_UP);
} }
static char *sm_status(sm_state_t state) static char *sm_status(sm_state_t state)
@@ -100,6 +150,22 @@ static void nologin(void)
erase(FINIT_NOLOGIN_PATH); erase(FINIT_NOLOGIN_PATH);
} }
void sm_init(sm_t *sm)
{
static struct wq work = {
.cb = sm_check_bootstrap,
.delay = 1000
};
sm->state = SM_BOOTSTRAP_STATE;
sm->newlevel = -1;
sm->reload = 0;
sm->in_teardown = 0;
dbg("Starting bootstrap finalize timer ...");
schedule_work(&work);
}
void sm_set_runlevel(sm_t *sm, int newlevel) void sm_set_runlevel(sm_t *sm, int newlevel)
{ {
sm->newlevel = newlevel; sm->newlevel = newlevel;
@@ -117,8 +183,8 @@ int sm_is_in_teardown(sm_t *sm)
void sm_step(sm_t *sm) void sm_step(sm_t *sm)
{ {
svc_t *svc;
sm_state_t old_state; sm_state_t old_state;
svc_t *svc;
restart: restart:
old_state = sm->state; old_state = sm->state;
@@ -130,10 +196,49 @@ restart:
case SM_BOOTSTRAP_STATE: case SM_BOOTSTRAP_STATE:
dbg("Bootstrapping all services in runlevel S from %s", finit_conf); dbg("Bootstrapping all services in runlevel S from %s", finit_conf);
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE); service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
sm->state = SM_BOOTSTRAP_WAIT_STATE;
break;
/*
* Handle bootstrap transition to configured runlevel, start TTYs
*
* This is the final stage of bootstrap. It changes to the default
* (configured) runlevel, calls all external start scripts and final
* bootstrap hooks before bringing up TTYs.
*
* We must ensure that all declared `task [S]` and `run [S]` jobs in
* finit.conf, or *.conf in finit.d/, run to completion before we
* finalize the bootstrap process by calling this function.
*/
case SM_BOOTSTRAP_WAIT_STATE:
/* We come here from bootstrap, runlevel change and conf reload */
service_step_all(SVC_TYPE_ANY);
/* Allow runparts to start */
cond_set_oneshot("int/bootstrap");
if (sm->newlevel == -1)
break;
/* Hooks that should run at the very end */
dbg("Calling all system up hooks ...");
plugin_run_hooks(HOOK_SYSTEM_UP);
service_step_all(SVC_TYPE_ANY);
/* Disable progress output at normal runtime */
enable_progress(0);
/* System bootrapped, launch TTYs et al */
bootstrap = 0;
service_step_all(SVC_TYPE_RESPAWN);
sm->state = SM_RUNNING_STATE; sm->state = SM_RUNNING_STATE;
break; break;
case SM_RUNNING_STATE: case SM_RUNNING_STATE:
/* We come here from bootstrap, runlevel change and conf reload */
service_step_all(SVC_TYPE_ANY);
/* runlevel changed? */ /* runlevel changed? */
if (sm->newlevel >= 0 && sm->newlevel <= 9) { if (sm->newlevel >= 0 && sm->newlevel <= 9) {
if (runlevel == sm->newlevel) { if (runlevel == sm->newlevel) {
@@ -143,6 +248,7 @@ restart:
sm->state = SM_RUNLEVEL_CHANGE_STATE; sm->state = SM_RUNLEVEL_CHANGE_STATE;
break; break;
} }
/* reload ? */ /* reload ? */
if (sm->reload) { if (sm->reload) {
sm->reload = 0; sm->reload = 0;
@@ -210,17 +316,18 @@ restart:
/* Cleanup stale services */ /* Cleanup stale services */
svc_clean_dynamic(service_unregister); svc_clean_dynamic(service_unregister);
/* Compat SysV init */
if (prevlevel == INIT_LEVEL && !rescue)
run_bg(FINIT_RC_LOCAL, NULL);
/* /*
* "I've seen things you people wouldn't believe. Attack ships on fire off * "I've seen things you people wouldn't believe. Attack ships on fire off
* the shoulder of Orion. I watched C-beams glitter in the dark near the * the shoulder of Orion. I watched C-beams glitter in the dark near the
* Tannhäuser Gate. All those .. moments .. will be lost in time, like * Tannhäuser Gate. All those .. moments .. will be lost in time, like
* tears ... in ... rain." * tears ... in ... rain."
*/ */
if (runlevel == 0 || runlevel == 6) { if (runlevel == 0 || runlevel == 6)
do_shutdown(halt); do_shutdown(halt);
sm->state = SM_RUNNING_STATE;
break;
}
sm->state = SM_RUNNING_STATE; sm->state = SM_RUNNING_STATE;
break; break;
@@ -266,9 +373,7 @@ restart:
dbg("Update configuration generation of unmodified non-native services ..."); dbg("Update configuration generation of unmodified non-native services ...");
service_notify_reconf(); service_notify_reconf();
service_step_all(SVC_TYPE_ANY);
dbg("Reconfiguration done"); dbg("Reconfiguration done");
sm->state = SM_RUNNING_STATE; sm->state = SM_RUNNING_STATE;
break; break;
} }
+1
View File
@@ -26,6 +26,7 @@
typedef enum { typedef enum {
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */ SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
SM_BOOTSTRAP_WAIT_STATE, /* Waiting for bootstrap to complete */
SM_RUNNING_STATE, /* Normal state, services running */ SM_RUNNING_STATE, /* Normal state, services running */
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */ SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */ SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
+1 -1
View File
@@ -1,6 +1,6 @@
/* Reset terminal line settings (stty sane) /* Reset terminal line settings (stty sane)
* *
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+10 -4
View File
@@ -1,6 +1,6 @@
/* poor man's sulogin, may be statically linked /* poor man's sulogin, may be statically linked
* *
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "config.h"
#include <crypt.h> #include <crypt.h>
#include <err.h> #include <err.h>
#include <paths.h> #include <paths.h>
@@ -32,6 +34,10 @@
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#ifndef SULOGIN_USER
#define SULOGIN_USER "root"
#endif
/* getpwnam() cannot be used when statically linked */ /* getpwnam() cannot be used when statically linked */
static int get_passwd(struct passwd *pw) static int get_passwd(struct passwd *pw)
{ {
@@ -44,13 +50,13 @@ static int get_passwd(struct passwd *pw)
return 1; return 1;
while ((tmp = fgets(buf, sizeof(buf), fp))) { while ((tmp = fgets(buf, sizeof(buf), fp))) {
if (!strstr(buf, ":0:0:"))
continue; /* not uid 0 */
ptr = strsep(&tmp, ":"); ptr = strsep(&tmp, ":");
if (!ptr) if (!ptr)
break; break;
pw->pw_name = strdup(ptr); pw->pw_name = strdup(ptr);
if (!pw->pw_name || strcmp(pw->pw_name, SULOGIN_USER))
continue;
ptr = strsep(&tmp, ":"); ptr = strsep(&tmp, ":");
if (!ptr) if (!ptr)
+57 -30
View File
@@ -1,7 +1,7 @@
/* Low-level service primitives and generic API for managing svc_t structures /* Low-level service primitives and generic API for managing svc_t structures
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -634,17 +634,30 @@ int svc_enabled(svc_t *svc)
if (!svc) if (!svc)
return 0; return 0;
if (!svc_in_runlevel(svc, runlevel)) if (!svc_in_runlevel(svc, runlevel)) {
// dbg("Not in runlevel");
return 0; return 0;
}
if (svc_is_removed(svc) || svc_is_blocked(svc)) if (svc_is_removed(svc) || svc_is_blocked(svc)) {
// dbg("removed (%d) / blocked (%d)", svc->removed, svc->block);
return 0; return 0;
}
if (svc_is_missing(svc)) if (svc_is_missing(svc)) {
// dbg("missing");
return 0; return 0;
}
if (svc_is_tty(svc) && bootstrap) if (!svc_ifthen(0, NULL, svc->ifstmt, svc->nowarn)) {
// dbg("ifthen:%s>", svc->ifstmt[0] ? svc->ifstmt : "<");
return 0; return 0;
}
if (svc_is_tty(svc) && bootstrap) {
// dbg("is tty in bootstrap");
return 0;
}
return 1; return 1;
} }
@@ -688,14 +701,17 @@ int svc_conflicts(svc_t *svc)
/** /**
* svc_ifthen - Check if: statement in declaration * svc_ifthen - Check if: statement in declaration
* @is_conf: Set when called by service_mark_unavail()
* @ident: svc_t identififcation (name:id) * @ident: svc_t identififcation (name:id)
* @stmt: if: statement from .conf file * @stmt: if: statement from .conf file
* @quiet: If non-zero, do not warn in syslog
* *
* Returns: * Returns:
* %TRUE(1) yes, use this svc_t, %FALSE(0) prune * %TRUE(1) yes, use this svc_t, %FALSE(0) prune
*/ */
int svc_ifthen(const char *ident, char *stmt) int svc_ifthen(int is_conf, const char *ident, char *stmt, int quiet)
{ {
char stmts[MAX_IDENT_LEN];
int not = 0; int not = 0;
svc_t *svc; svc_t *svc;
@@ -707,40 +723,51 @@ int svc_ifthen(const char *ident, char *stmt)
char *ptr = ++stmt; char *ptr = ++stmt;
int i = 0; int i = 0;
if (stmt[0] == '!') { if (is_conf)
stmt++; return 1;
not++;
}
while (ptr[i] != '>' && ptr[i] != 0) while (ptr[i] != '>' && ptr[i] != 0)
i++; i++;
ptr[i] = 0; ptr[i] = 0;
cond = cond_get(stmt); strlcpy(stmts, stmt, sizeof(stmts));
if (not && cond == COND_ON) { for (stmt = strtok(stmts, ","); stmt; stmt = strtok(NULL, ","), not = 0) {
logit(LOG_NOTICE, "skipping %s, cond %s is on.", ident, stmt); if (stmt[0] == '!') {
return 0; stmt++;
} not++;
if (!not && cond == COND_OFF) { }
logit(LOG_NOTICE, "skipping %s, cond %s is off.", ident, stmt);
return 0; cond = cond_get(stmt);
if (not && cond == COND_ON)
return 0;
if (!not && cond == COND_OFF)
return 0;
} }
return 1; return 1;
} }
if (stmt[0] == '!') { if (!is_conf)
stmt++; return 1;
not++;
}
svc = svc_find_by_str(stmt); strlcpy(stmts, stmt, sizeof(stmts));
if (not && svc) { for (stmt = strtok(stmts, ","); stmt; stmt = strtok(NULL, ","), not = 0) {
logit(LOG_NOTICE, "skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0)); if (stmt[0] == '!') {
return 0; stmt++;
} not++;
if (!not && !svc) { }
logit(LOG_NOTICE, "skipping %s, %s not available.", ident, stmt);
return 0; svc = svc_find_by_str(stmt);
if (not && svc) {
if (!quiet)
logit(LOG_NOTICE, "skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0));
return 0;
}
if (!not && !svc) {
if (!quiet)
logit(LOG_NOTICE, "skipping %s, %s not available.", ident, stmt);
return 0;
}
} }
return 1; return 1;
+19 -10
View File
@@ -1,7 +1,7 @@
/* Low-level service primitives and generic API for managing svc_t structures /* Low-level service primitives and generic API for managing svc_t structures
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -83,8 +83,17 @@ typedef enum {
SVC_ONCRASH_SCRIPT, SVC_ONCRASH_SCRIPT,
} svc_oncrash_action_t; } svc_oncrash_action_t;
/* 0: none, 1: systemd, 2: s6 */
typedef enum {
SVC_NOTIFY_NONE = 0,
SVC_NOTIFY_PID,
SVC_NOTIFY_SYSTEMD,
SVC_NOTIFY_S6,
} svc_notify_t;
#define MAX_ID_LEN 16 #define MAX_ID_LEN 16
#define MAX_ARG_LEN 64 #define MAX_ARG_LEN 64
#define MAX_CMD_LEN 256
#define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1) #define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1)
#define MAX_STR_LEN 64 #define MAX_STR_LEN 64
#define MAX_COND_LEN (MAX_ARG_LEN * 3) #define MAX_COND_LEN (MAX_ARG_LEN * 3)
@@ -118,7 +127,7 @@ typedef struct svc {
int sighalt; /* Signal to stop process, default: SIGTERM */ int sighalt; /* Signal to stop process, default: SIGTERM */
int killdelay; /* Delay in msec before sending SIGKILL */ int killdelay; /* Delay in msec before sending SIGKILL */
pid_t oldpid, pid; pid_t oldpid, pid;
char pidfile[256]; char pidfile[MAX_CMD_LEN];
long start_time; /* Start time, as seconds since boot, from sysinfo() */ long start_time; /* Start time, as seconds since boot, from sysinfo() */
int started; /* Set for run/task/sysv to track if started */ int started; /* Set for run/task/sysv to track if started */
int status; /* From waitpid() when process is collected */ int status; /* From waitpid() when process is collected */
@@ -181,15 +190,15 @@ typedef struct svc {
char group[MAX_USER_LEN]; char group[MAX_USER_LEN];
/* Command, arguments and service description */ /* Command, arguments and service description */
char cmd[MAX_ARG_LEN]; char cmd[MAX_CMD_LEN];
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN]; char args[MAX_NUM_SVC_ARGS][MAX_CMD_LEN];
int args_dirty; int args_dirty;
char conflict[MAX_ARG_LEN]; char conflict[MAX_ARG_LEN];
char desc[MAX_STR_LEN]; char desc[MAX_STR_LEN];
char env[MAX_ARG_LEN]; char env[MAX_CMD_LEN];
char pre_script[MAX_ARG_LEN]; char pre_script[MAX_CMD_LEN];
char post_script[MAX_ARG_LEN]; char post_script[MAX_CMD_LEN];
char ready_script[MAX_ARG_LEN]; char ready_script[MAX_CMD_LEN];
/* /*
* Used to forcefully kill services that won't shutdown on * Used to forcefully kill services that won't shutdown on
@@ -201,7 +210,7 @@ typedef struct svc {
/* /*
* Readiness notification socket: systemd, s6 * Readiness notification socket: systemd, s6
*/ */
int notify; /* 0: none, 1: systemd, 2: s6 */ svc_notify_t notify;
uev_t notify_watcher; /* i/o watcher */ uev_t notify_watcher; /* i/o watcher */
/* time at svc_del(), used by gc timer */ /* time at svc_del(), used by gc timer */
@@ -240,7 +249,7 @@ void svc_prune_bootstrap (void);
void svc_enable (svc_t *svc); void svc_enable (svc_t *svc);
int svc_enabled (svc_t *svc); int svc_enabled (svc_t *svc);
int svc_conflicts (svc_t *svc); int svc_conflicts (svc_t *svc);
int svc_ifthen (const char *ident, char *ifstm); int svc_ifthen (int is_conf, const char *ident, char *stmt, int quiet);
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *)); int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
+5 -5
View File
@@ -1,6 +1,6 @@
/* Limited tmpfiles.d implementation /* Limited tmpfiles.d implementation
* *
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -78,8 +78,8 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
if (ftw->level == 0) if (ftw->level == 0)
return 1; return 1;
if (remove(fpath)) if (remove(fpath) && errno != EBUSY)
warn("Failed removing condition %s", fpath); warn("Failed removing %s", fpath);
return 0; return 0;
@@ -471,7 +471,7 @@ void tmpfilesd(void)
/* in priority order */ /* in priority order */
char *dir[] = { char *dir[] = {
FINIT_TMPFILES "/*.conf", FINIT_TMPFILES "/*.conf",
TMPFILES_PATH "/*.conf", TMPFILES_PATH_ "/*.conf",
"/usr/lib/tmpfiles.d/*.conf", "/usr/lib/tmpfiles.d/*.conf",
"/run/tmpfiles.d/*.conf", "/run/tmpfiles.d/*.conf",
"/etc/tmpfiles.d/*.conf", /* local admin overrides */ "/etc/tmpfiles.d/*.conf", /* local admin overrides */
@@ -492,7 +492,7 @@ void tmpfilesd(void)
/* check for overrides */ /* check for overrides */
for (j = i + 1; j < gl.gl_pathc; j++) { for (j = i + 1; j < gl.gl_pathc; j++) {
if (strcmp(basename(fn), basename(gl.gl_pathv[j]))) if (strcmp(basenm(fn), basenm(gl.gl_pathv[j])))
continue; continue;
fn = NULL; fn = NULL;
break; break;
+1 -1
View File
@@ -1,6 +1,6 @@
/* Limited tmpfiles.d implementation /* Limited tmpfiles.d implementation
* *
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* Finit TTY handling /* Finit TTY handling
* *
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com> * Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

Some files were not shown because too many files have changed in this diff Show More