Compare commits

...
80 Commits
Author SHA1 Message Date
Joachim Wiberg ceb2945da9 Update ChangeLog and bump version for v4.3-rc2
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-09 06:55:21 +02:00
Joachim Wiberg 1b8a0951f5 initctl: update usage text with missing initctl cond get <COND>
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-08 14:09:27 +02:00
Joachim Wiberg a27b8462d1 Fix #260: drop limit on device name in "Checking filesystem" output
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-08 09:59:51 +02:00
Joachim Wiberg edc2d53923 cgroup: reduce loglevel for missing/disallowed cgroup support
A user with no cgroup support in kernel does not know what they are
missing, and a user running in a container has someone else managing
cgroups.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-08 09:57:18 +02:00
Joachim Wiberg 4aae3403f5 test: new test, verify default runlevel from command line
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-08 09:57:18 +02:00
Joachim Wiberg 73423699fd test: add support for overriding default runlevel
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-08 09:57:18 +02:00
Joachim Wiberg 0cce69892a Fix #261: support for overriding default runlevel from command line
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-08 09:57:18 +02:00
Joachim Wiberg 3ca6256f87 doc: update modules-load plugin description, recommend .conf files
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-07 16:29:18 +02:00
Joachim Wiberg eca3098c0e plugins: refactor modules-load to read files in lexicographic order
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-07 16:29:18 +02:00
Joachim Wiberg 7af3461e3c Merge pull request #262 from wkz/hook-scripts
plugins: hook-scripts: new plugin for run-parts scripts on hooks

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 15:04:27 +02:00
Tobias Waldekranz b62c975dc4 plugins: hook-scripts: Add
Add a plugin that will allow the user to trigger the execution of
scripts from plugin hook points. This is particularly useful for early
boot debugging that needs to take place before regular services are
available.

For example, let's say that you want to enable some kernel tracing
before modules are loaded. With hook-scripts, you can just drop in a
shell script in /libexec/finit/hook/mount/all/ that will poke the
right control files in tracefs.
2022-05-06 10:36:37 +02:00
Joachim Wiberg b368bd1420 Document hidden HOOK_BANNER
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 08:22:01 +02:00
Joachim Wiberg 060e97d64e test: minor, drop comment within comment confusing shellcheck
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 08:07:44 +02:00
Joachim Wiberg 9b17ce0b7c Fix restart logic of sysv start/stop scripts and forking services
Init script return pretty quickly after launch, so we cannot use that to
detect if they, or the daemon they launched, have crashed.  So we start
the service_retry() with a 2 sec delay, which should be ample time to
allow the pidfile plugin to detect a forking service's new PID.

In release-cycle regression, no public issue needed.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:08 +02:00
Joachim Wiberg 50f2cbf600 Export service timeout APIs, for pidfile plugin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:08 +02:00
Joachim Wiberg 837bca3947 test: new test, verify sysv services are restarted properly
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:08 +02:00
Joachim Wiberg 16180675db test: minor coding style fixups
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:08 +02:00
Joachim Wiberg d3c6351ed8 Fix nasty service matcher bug
In some conditions, typically when the same command is used for multiple
services, e.g. the modules-load plugin, the svc_find() function returned
an existing "similar" entry instead of NULL, causing loss of config.

When creating, and searching for, a run/task/service we must follow the
new name:id paradigm to the letter.  Always create based on name:id and
always search for matching name:id.  The name may be derived from the
command, but they cannot be used interchangably.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:08 +02:00
Joachim Wiberg 7e37ac348e Refactor service name: parser slightly
This change makes it possible to see the new service's resulting name
and id before we create it with svc_new().  We extend the debug output
slightly to see what's going on and why we sometimes lose modules from
the modules-load plugin ...

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:07 +02:00
Joachim Wiberg 30e68658ae Use name:id instead consistently in debug messages
For many usecases, e.g. the modules-load plugin, the same command can be
used to create multple run/task/services makeing it real difficult to
debug such systems when Finit does not show the correct task name.  It
also hides nasty bugs, as will be shown in a later commit.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:07 +02:00
Joachim Wiberg a179308819 Simplify, tabstospaces() have already been called
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:07 +02:00
Joachim Wiberg 4cdd5f8ccc Export tabstospaces() from conf.c to helpers.[ch]
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:07 +02:00
Joachim Wiberg 7f19474d8d plugins: skip backup files in modules-load plugin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:07 +02:00
Joachim Wiberg a5941165a0 plugins: add support for 'set noindex' to modules-load plugin
This adds support for a `set` directive in the modules-load plugin.
Currently only `set noindex` and `set index = NUM` are supported and
either disable indexing (:ID) of modules, or reset the index to NUM,
for the given file.  For each new file read the index is reset to
the value it would have had.  E.g.

01-foo.conf:          => name:id
   esp4.ko            => modprobe.esp4.ko:1
   set noindex
   deflate.ko         => modprobe.deflate.ko
02-bar.conf:
   nls_iso8859-15.ko  => modprobe.nls_iso8859-15.ko:3
   nls_utf8.ko        => modprobe.nls_utf8.ko:4

Fixes issue #257

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-06 07:57:07 +02:00
Joachim Wiberg 181d9556a1 Drop config.h include from helpers.h, exported header file
Drop the config.h include from helpers.h after a report from a colleague
trying to build an external plugin from the latest GIT sources.

Instead, make sure config.h is included, and properly commented, in all
.c files that have configure #ifdefs and other deps.  Also, move more
ot the includes from helpers.h to their respective .c file instead to
reduce the amount of headers an external plugin pulls in.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-05 14:48:30 +02:00
Joachim Wiberg bf72e6b9c8 Make bundled sulogin optional, use ./configure --with-sulogin
The bundled sulogin could be considered insecure, so leave it up to the
administrator, or system integrator, to decide which sulogin(8) is best
suited.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-03 05:58:57 +02:00
Joachim Wiberg 8db521d379 Fix minor memory leak in sulogin() handling
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-03 05:58:24 +02:00
Joachim Wiberg f46ac20fb0 doc: document support for global environment variables
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-02 00:16:04 +02:00
Joachim Wiberg d70d86e9fe test: new test, verify behavior of global environment variables
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-02 00:03:07 +02:00
Joachim Wiberg 38db52aa4e Add support for setting environment variables from finit.conf
Finit can now track and set environment variables from finit.conf.  The
syntax is pretty much what you'd expect:

    foo=bar
    baz="qux"

On reload of .conf files, all tracked environment variables are cleared
so if `foo=bar` is removed from finit.conf, or any finit.d/*.conf file,
it will no longer be used by Finit or any new (!) started run/tasks or
services.

The only variables reset to sane defaults on .conf reload are:

    PATH=_PATH_STDPATH
    SHELL=_PATH_BSHELL
    LOGNAME=root
    USER=root

It is entirely possible to override these as well from the .conf files,
but be careful.  Changing SHELL changes the behavior of system() and a
lot of other commands as well.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-02 00:02:44 +02:00
Joachim Wiberg bf62bee440 Update project homepage
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-01 22:43:39 +02:00
Joachim Wiberg e50fe3b060 plugins: use reentrant API getmntent_r()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-01 22:12:02 +02:00
Joachim Wiberg d6c55282ef Fix #253: use reentrant getmntent_r() API
When iterating over the system fstab file to call fsck, Finit calls the
helper function ismnt(), which opens /proc/mounts to make sure mounted
file systems are not fsck'ed.  Both the main function and ismnt() used
the same non-reentrant getmntent() API which caused ismnt() to set the
fstab pointer for the first out of whack.

This change replaces getmntent() in the two critical functions with the
getmntent_r() API instead.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-01 21:43:13 +02:00
Joachim Wiberg 1015124530 Use sys/sysmacros.h, if available, for minor() and major()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-01 20:50:17 +02:00
Joachim Wiberg 38885aaa67 Issue #253: handle fsck of magic /dev/root device
Some systems have /dev/root declared in their /etc/fastb as /.  This is
as special device node created by the kernel based on the root=, and a
few other variables.  This may be a symlink, and if so, and on a mdev
system, the symlink may point to the wrong device node ... so we must
try to figure out the major:minor from / and then traverse /sys/block
to find our root device.

Note: this commit also does a bit of refactoring for readability and
      also adds a few debug lines that may be dropped before release.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-01 19:31:51 +02:00
Joachim Wiberg a685b698c2 Follow-up to 5593372f, regression in remounting read-write at boot
A subtle regression was introduced in 5593372f, when moving to get
getmntent() family of APIs.  Finding the 'ro' flag (or not) in the
system fstab broke and Finit never tried to remount / read-write.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-05-01 19:28:50 +02:00
Joachim Wiberg 9bce8f9584 initctl: add cond get foo, supports -v option
Fix issue #255

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-30 10:28:47 +02:00
Joachim Wiberg d04b04d73a Follow-up to 7212543, fix args to svc_ident()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-30 10:20:53 +02:00
Joachim Wiberg 72125430e6 Fix #252: run/task success+failure conditions do not use :ID
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-30 08:50:14 +02:00
Joachim Wiberg 561387ce57 test: new test, verify pre:post: scripts with optional env:file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-30 08:46:05 +02:00
Joachim Wiberg e2d1930e6c Fix #248: source env:file also in pre:post: scripts
This change basically add this for pre/post scripts:

    sh -ac '. /path/to/env; exec ./pre-post.sh'

Meaning the env file can be a simple foo=bar file, which Finit reads and
call setenv() on all variables, and the user do not need to call export
on all variables -- additionally, any functions defined in an env file
can be used by the pre-post scripts, but are ignored by Finit.  I.e.,
the service only gets the variables set, no functions.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-30 08:43:44 +02:00
Joachim Wiberg 6f2a124240 doc: update documentation for modules-load plugin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-27 07:50:21 +02:00
Joachim Wiberg 10392e9639 plugins: modules-load: skip lines starting with '#'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-27 07:46:03 +02:00
Joachim Wiberg 605c489937 Follow-up to 57c97d8, issue #224: add swapon/swapoff fstab wrappers
The swapon and swapoff commands do not support a custom fstab, they
assume /etc/fstab is the only true source of swap devices and files.

This change adds rudimentary (!) support for figuring out any swap
device or file to use from any finit.fstab.  Please note, options are
not supported at the moment.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 22:57:22 +02:00
Joachim Wiberg 26409bc860 Follow-up to 57c97d8, issue #224: fsck needs FSTAB_FILE env. set
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 21:59:11 +02:00
Joachim Wiberg b01f9f38f2 Improve logging of forking services having started and stopped
Since a forking service, e.g. a sysv init script, will exit very early
we cannot log the same as for regular services "Starting foo[123]", so
instead we log "Started bar[321]" when we get the pidfile update and
the same when stopping a forking service, log "Stopped bar[321]" when
we collect the PID.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 20:58:57 +02:00
Joachim Wiberg 2ddbb805ca Improve logging of sysv start/stop scripts, include full command
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 20:58:57 +02:00
Joachim Wiberg ed999d9a80 Fix log regression introduced in 82cc10be
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 20:58:57 +02:00
Joachim Wiberg 82cc10be88 Fix #246: conditions for running/halted services
This change adds the following service conditions, which can be used to
synchronize other stanzas:

  - service/foo/running
  - service/foo/halted
  - service/foo/missing
  - service/foo/crashed
  - service/foo/stopped
  - service/foo/busy
  - service/foo/restart

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 00:07:44 +02:00
Joachim Wiberg 30fb9780d7 initctl: slight improvement to status output for sysv services
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 00:07:44 +02:00
Joachim Wiberg 09f46f62b4 Support args to sysv-like scripts, e.g. bridge-stp br0 start
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-26 00:07:44 +02:00
Joachim Wiberg bc4e7a8d8d Revert "Fix starting and stopping of SysV init scripts"
This reverts commit c63279630b which
clearly was not needed to fix the problem.  After this revert the
test(s) still pass, but now we can also start bridge-stp, e.g.

     bridge-stp br0 start

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 23:38:52 +02:00
Joachim Wiberg e2753d75f8 plugins: silence netlink developer debug messages
Default debug level for the netlink plugin is just too noisy.  Let's
drop debug messages (mostly) intended for developers.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 23:35:02 +02:00
Joachim Wiberg addb8c4019 Fix #247: fall back to reboot -f in sulogin mode
When logged in from sulogin we cannot send IPC to Finit, not even
signals, to delegate reboot.  For usability, attempt to tell reboot that
it's in sulogin mode -- provided the bundled sulogin is used -- to let
reboot trigger over to forced reboot.

We cannot do much about initctl, just document this as a limitation.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 21:44:33 +02:00
Joachim Wiberg 0c4a9b62c2 initctl: allow client_connect() to return error
This lets any callers of client_connect() decide what to do wrt. error
recovery and fallback mechanisms.  E.g., reboot may want to check if
it's in sulogin mode, or fall back to sending signals to PID 1.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 21:44:33 +02:00
Joachim Wiberg 57c97d8190 Fix #224: support for cmdline -- finit.fstab=/etc/fstab.secondary
This adds support for bringing up the system with an alternate fstab at
boot.  E.g., when using a primary/secondary setup for boot partitions.

By default /etc/fstab is read, like before, this can now be changed
using configure --with-fstab=/path/to/fstab.primary, which sets the
default that can be overridden using finit.fstab=/etc/fstab.secondary

If mounting, or fsck, fails in any way, Finit calls its own bundled
sulogin, or the system sulogin(8), to let the user handle the issue.
If there is no sulogin available, Finit will try to start up in its
rescue.conf boot mode.

Please note, in either of these rescue modes, use `reboot -f` to get the
system to reboot.  Finit is on pause in the background in rescue mode
and cannot be relied on (since there may not be any writable filesystems
available.).

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 21:44:33 +02:00
Joachim Wiberg b0d0ca76cf Minor, coding style
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 21:37:59 +02:00
Joachim Wiberg 5240c0cf19 Follow-up to a91e197: allow umount fail on EBUSY, skip error message
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 18:52:16 +02:00
Joachim Wiberg a02f369a89 Minor, rename local variable
The iterator works on any fstab like file, but to keep confusion to a
minimum, rename local variable.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-25 18:51:17 +02:00
Joachim Wiberg fa2a113cbf test: fix path to Finit rcs.d in distcheck
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 15:22:35 +02:00
Joachim Wiberg 4c5ac38e2c test: attempt to use /etc/finit.conf instead, azure 5/N
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 14:42:49 +02:00
Joachim Wiberg f89ebb91a8 test: even more azure debug 4/N
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 14:39:03 +02:00
Joachim Wiberg 477bc064d5 test: more debug azure 3/N
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 14:28:57 +02:00
Joachim Wiberg 96376126b3 test: debug azure 2/N
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 14:21:58 +02:00
Joachim Wiberg 1c150928cb test: debug cond test in azure
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 14:14:35 +02:00
Joachim Wiberg 7a8d4e2c6b test: wait for Finit to reach runlevel 2 before starting tests
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 13:19:10 +02:00
Joachim Wiberg fb956fd2f5 test: silence Hint:, does not work anymore, need to debug it
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 13:18:41 +02:00
Joachim Wiberg e6e4d814f3 test: extend initial wait for azure env.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 12:55:37 +02:00
Joachim Wiberg 544d44886a test: let Finit start up properly before starting tests
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-24 11:36:30 +02:00
Joachim Wiberg cec2d5a4db test: add missing sbin/task.sh to skeleton dist.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-22 18:21:19 +02:00
Joachim Wiberg 539d215d0e test: add missing finit.d to skeleton rootfs
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-22 17:51:04 +02:00
Joachim Wiberg 10ef0e7de6 doc: document previously secret service option respawn
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-22 07:21:19 +02:00
Joachim Wiberg 05e6b3e752 test: new test, verify task behavior with conditions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-21 20:52:34 +02:00
Joachim Wiberg 3e4be9a122 man: document command line options, complementing bootparam(7)
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-20 07:51:58 +02:00
Joachim Wiberg 5593372ffb Refactor, replace deprecated setfsent() & C:o with setmntent()
The setfsent() family of APIs was never standardized and on Linux only
GLIBC implement them.  We've tried to overcome this limitation, and to
support uClibc/uClibc-ng and musl libc, by providing replacements APIs
in helpers.c.

However, and since we want to support alternative /etc/fstab files, the
setmntent() family of APIs is more widespread and supports reading from
any fstab or mtab file.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-20 07:20:33 +02:00
Joachim Wiberg 05be281301 Rely on (now working) fstab.h check in configure
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-19 20:04:03 +02:00
Joachim Wiberg 108bbf56dd Update copyright years
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-19 19:35:49 +02:00
Joachim Wiberg a61aa73419 configure: check for fstab.h, no fstaby.h
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-19 19:29:01 +02:00
Joachim Wiberg f39626f132 Minor, fix format string to systemf()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-17 14:25:32 +02:00
Joachim Wiberg c0b6f3af08 .github: build with latest libite version
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-17 14:22:09 +02:00
99 changed files with 1815 additions and 490 deletions
+3 -3
View File
@@ -29,11 +29,11 @@ jobs:
sudo apt-get -y update
sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
tar xf libuev-2.3.2.tar.xz
tar xf libite-2.3.1.tar.gz
tar xf libite-2.5.2.tar.gz
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig
- uses: actions/checkout@v2
- name: Static Finit
+45 -6
View File
@@ -20,17 +20,30 @@ you *need* to upgrade!
> For details, see [cmdline.md](doc/cmdline.md).
### Changes
* Support for overriding default runlevel from kernel command line. Any
runlevel `[1-9]` may be selected, except 6 (reboot). Issue #261
* New command line option: `finit.fstab=/etc/fstab.custom`, with full
support for mounting, mount helpers, fsck, and swapon/off, issue #224
* Support for special device `/dev/root`, which may not exist in `/dev`.
Finit now looks up the matching block device for `/` in `/sys/block/`
* Loading `module`s no longer shows arguments in progress output
* Warning messages in progress output now in yellow, not red, issue #214
* `initctl`, new command line option `-v,--version` for ease of use
* Extended environment variables for pre/post scripts, issue #189
* `initctl`, new command line option `-V,--version` for ease of use
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
* initctl support for sending signals to services, by Jörgen
Sigvardsson, issue #225
* Conditions for services, can be used to synchronize other stanzas:
- `service/foo/running`
- `service/foo/halted`
- `service/foo/missing`
- `service/foo/crashed`
- `service/foo/stopped`
- `service/foo/busy`
- `service/foo/restart`
* `initctl signal` support, by Jörgen Sigvardsson, issue #225
* `initctl cond get` support to match `cond [set | clear]`, issue #255
* `[WARN]` messages on console now printed in yellow, issue #214
* Network services now also stopped when going to runlevel 6 (reboot),
not just runlevel 0 (shutdown) or 1 (single-user)
@@ -43,7 +56,27 @@ you *need* to upgrade!
* Simplify shutdown/reboot when running in a container
* Log to `stderr` when running in a container w/o syslog daemon
* Add support for `type:forking` to services, already supported but
with a very difficult `pid:` syntax. Documentation updated
with a very difficult `pid:` syntax, issue #223. Docs updated
* Support for setting global environment variables in `finit.conf`,
please note: this also affects Finit itself, be careful!
* Extended environment variables for pre/post scripts, issue #189
* Document secret service option `respawn`, which bypasses the crash
semantics, allowing endless restarts
* Document secret `HOOK_BANNER`, the first hook point before the banner
* New plugin: `hook-scripts`, allows [run-parts(8)][] style scripts to
run on any hook point. Contributed by Tobias Waldekranz
* `initctl` (`reboot`) falls back to `-f` when it detects it is in
`sulogin` recovery mode, issue #247
* The bundled `sulogin` is no longer enabled by default, in favor of
distribution versions. Enable with `./configure --with-sulogin`
* Support args to sysv-like scripts, e.g. `bridge-stp br0 start`
* The `modules-load` plugin now skips all lines starting with `#` and
`;`. Furthermore, files in `/etc/modules-load.d/*.conf` are now read
in lexicographic order and UNIX backup files (`foo.conf~`) are skipped
* The `name:id` tuple is now more consistently used in all log and debug
messages instead of the basename of the command
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
### Fixes
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
@@ -59,10 +92,16 @@ you *need* to upgrade!
* Fix #227: reboot stalls if process stopped with `[WARN]`
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
and Ming Liu, Atlas Copco
* Fix start/stop of SysV init scripts
* Fix #248: source `env:file` also in `pre:` and `post` scripts
* Fix #260: drop limit on device name in `Checking filesystem`...` output
* Fix start/stop and monitoring (restart) of SysV init scripts and
forking services, see the updated documentation for details
* Fix call to `swapoff` at shutdown, does not support `-e` flag
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
used, now the modern `/sys/power/state` API is used instead.
* Fix nasty run/task/service matcher bug, triggered by stanzas using the
same basename of a command but different `:ID`. Caused Finit to match
with already registered but different run/task/service
[4.2][] - 2022-01-16
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+2
View File
@@ -29,3 +29,5 @@ release: distcheck
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
done
DISTCHECK_CONFIGURE_FLAGS = --with-fstab=/etc/fstab
+33 -4
View File
@@ -1,4 +1,4 @@
AC_INIT(Finit, 4.3-rc1, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
AC_INIT(Finit, 4.3-rc2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/projects/finit/)
AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes])
@@ -33,8 +33,8 @@ AC_PROG_MKDIR_P
# Configuration.
AC_HEADER_STDC
AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h])
AC_CHECK_FUNCS([strstr getopt getfsenty])
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
# Check for uint[8,16,32]_t
AC_TYPE_UINT8_T
@@ -90,12 +90,17 @@ AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
# Check for extra arguments or packages
AC_ARG_WITH(fstab,
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
[fstab=$withval], [fstab=yes])
AC_ARG_WITH(heading,
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
[heading=$withval], [heading=yes])
@@ -125,7 +130,7 @@ AC_ARG_WITH(hostname,
[hostname=$withval], [hostname=yes])
AC_ARG_WITH(runlevel,
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap [1-9], default: 2]),
[runlevel=$withval], [runlevel=yes])
AC_ARG_WITH(random-seed,
@@ -135,10 +140,18 @@ AC_ARG_WITH(random-seed,
AC_ARG_WITH(keventd,
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
AC_ARG_WITH(sulogin,
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no])
AC_ARG_WITH(watchdog,
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
[watchdog=$withval], [with_watchdog=no watchdog=])
AC_ARG_WITH(hook-scripts-path,
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
[hook_scripts_path=$withval], [hook_scripts_path=yes])
### Enable features ###########################################################################
# Create config.h from selected features and fallback defaults
@@ -164,6 +177,12 @@ AS_IF([test "x$enable_logrotate" != "xno"], [
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
### With features ##############################################################################
AS_IF([test "x$with_fstab" != "xno"], [
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
AC_EXPAND_DIR(fstab_path, "$fstab")
AC_DEFINE_UNQUOTED(FINIT_FSTAB, "$fstab_path", [Built-in default: /etc/fstab])],[
AC_DEFINE_UNQUOTED(FINIT_FSTAB, NULL, [No built-in default fstab])])
AS_IF([test "x$with_config" != "xno"], [
AS_IF([test "x$conf" = "xyes"], [
conf=$sysconfdir/finit.conf])])
@@ -218,6 +237,8 @@ AS_IF([test "x$with_random_seed" != "xno"], [
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_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [
watchdog=/dev/watchdog])
@@ -225,9 +246,15 @@ AS_IF([test "x$with_watchdog" != "xno"], [
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
watchdog=])
AS_IF([test "x$enable_hook_scripts_plugin" = "xyes" -a "x$with_hook_scripts_path" != "xno"], [
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
# Control build with automake flags
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
@@ -261,6 +288,7 @@ cat <<EOF
Exec prefix...........: $eprefix
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
Default fstab.........: `eval echo $fstab`
Finit config file.....: $conf_path
Finit config.d path...: $rcsd_path
Finit plugin path.....: $plugin_path
@@ -278,6 +306,7 @@ Optional features:
Install doc/..........: $enable_doc
Install contrib/......: $enable_contrib
Built-in keventd......: $with_keventd
Built-in sulogin......: $with_sulogin
Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate
Skip fsck check.......: $enable_fastboot
+2
View File
@@ -1,6 +1,8 @@
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
+7
View File
@@ -65,6 +65,10 @@ Below are a few of the main switches to configure:
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
* `--with-sulgin`: Enable bundled `sulogin` program. Default is to use the
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
login if the `root` user is disabled or has no password at all.
For more configure flags, see <kbd>./configure --help</kbd>
> **Note:** the configure script is not available in the GIT sources. It is
@@ -153,6 +157,9 @@ enabled. The default Finit rescue mode configuration is installed into
By default the a root shell, without login, is started.
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
> force `reboot`, `shutdown`, or `poweroff`.
Debugging
---------
+29 -1
View File
@@ -15,6 +15,25 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
* `finit.debug[=bool]`: Enable finit debug. This is operated
independently of the kernel `debug` setting. New as of Finit v4.
* `finit.fstab=</path/to/etc/fstab.alternative>`: Tell Finit to use an
alternate `fstab` to mount the file system from. Remember, this file
must be on the `root=...` file system provided to Finit from the
kernel. By default the built-in fstab is used, which itself defaults
to `/etc/fstab`, but can be changed at build time with:
./configure --with-fstab=/path/to/fstab
It is even possible to disable a built-in default using:
./configure --without-fstab
Making `finit.fstab=/path/to/fstab` a *mandatory* command line option.
Note, if the command line fstab is missing, Finit falls back to the
built-in fstab, and if both are missing, the system treats this as a
bad `fsck` and thus calls `sulogin`. If, in turn, `sulogin` is not
available on the system, Finit calls reboot, which is also what will
happen when a user exits from `sulogin`.
* `finit.status[=bool]`: Control finit boot progress, including banner.
(Used to be `finit.show_status`, which works but is deprecated.)
@@ -44,13 +63,22 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
you will be given a root login to a maintenance shell. However, if
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
the system booted in a limited fallback mode. See [config.md][]
for more information.
for more information.
**Note:** in this mode `initctl` will not work. Correct the problem
and use `reboot -f` to force reboot.
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
debug problems with the regular runlevel. All services 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`
and `rescue`, giving a single number on the kernel command line tells
Finit to ignore any `runlevel` in `/etc/finit.conf` as well as the
configure fallback `--with-runlevel=N` setting. Remember, `6` is the
reboot runlevel and is not permitted. Any other values are ignored.
For more on kernel boot parameters, see the man page [bootparam(7)][].
[config.md]: config.md#rescue-mode
+41 -2
View File
@@ -73,6 +73,36 @@ document [Finit Services](service.md).
> examples in the `contrib/` directory, which can be used as a base.
### Environment Variables
In Finit v4.3 support for setting environment variables in `finit.conf`,
and any `*.conf`, was added. It is worth noting that these are global
and *shared with all* services -- the only way to have service-local
environment is detailed in the next section.
The syntax for global environment variables is straight forward:
foo=bar
baz="qux"
On reload of .conf files, all tracked environment variables are cleared
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
file, it will no longer be used by Finit or any new (!) started
run/tasks or services. The environment of already started processes can
not be changed.
The only variables reset to sane defaults on .conf reload are:
PATH=_PATH_STDPATH
SHELL=_PATH_BSHELL
LOGNAME=root
USER=root
It is entirely possible to override these as well from the .conf files,
but be careful. Changing SHELL changes the behavior of `system()` and a
lot of other commands as well.
Service Environment
-------------------
@@ -341,6 +371,8 @@ default 10 times before giving up and marking them as *crashed*.
After which they have to be manually restarted with `initctl restart
NAME`. The limits controling this are configurable, see the options
below.
> **Tip:** to allow endless restarts, see below option `respawn`
For daemons that support it, we recommend appending `--foreground`,
`--no-background`, `-n`, `-F`, or similar command line argument to
@@ -411,13 +443,17 @@ As mentioned previously, services are automatically restarted, this is
configurable with the following options:
* `restart:NUM` -- number of times Finit tries to restart a crashing
service, default: 10. When this limit is reached the service is
marked *crashed* and must be restarted manually with `initctl`
service, default: 10, max: 255. When this limit is reached the
service is marked *crashed* and must be restarted manually with
`initctl restart NAME`
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used
* `norestart` -- dont restart on failures, same as `restart:0`
* `respawn` -- bypasses the `restart` mechanism completely, allows
endless restarts. Useful in many use-cases, but not what `service`
was originally designed for so not the default behavior
* `oncrash:reboot` -- when all retries have failed, and the service
has *crashed*, if this option is set the system is rebooted.
Note, future releases may include other `oncrash:` actions
@@ -639,6 +675,9 @@ activate it.
The rescue mode comes in two flavors; *traditional* and *fallback*.
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
> force `reboot`, `shutdown`, or `poweroff`.
### Traditional
+28 -1
View File
@@ -34,13 +34,35 @@ For your convenience a set of *optional* plugins are available:
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
points (see [Hooks](#hooks)). Scripts are located in
`/libexec/finit/hook` by default, this can be build-time customized
by using the `--with-hook-scripts-path=PATH` argument to
`configure`. _Optional plugin._
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
available. Enabled by default.
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
Enabled by default.
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
load using `modprobe`. Each file can contain multiple lines with the
name of the module to load. Any line starting with the standard UNIX
comment character, `#`, is skipped.
Modules are loaded when entering runlevel `[2345]` using the `task`
stanza. Each module gets a unique `name:modprobe.foo`, and
optional`:ID`. The `:ID` is a globally incremented index, which can
be disabled per file (anywhere) using the following config line:
set noindex
**Note:** unlike the traditional .conf `module` directive, which load
any listed module immediately, this plugin creates standard `taks`
directives which load the module(s) in the background. As long as
the `modprobe` program is found in the path, these tasks will always
return `[ OK ]` at boot. Check the actual status using `initctl`.
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
interfaces. These events are then sent to the Finit service monitor
@@ -71,6 +93,11 @@ Hooks
### Bootstrap Hooks
* `HOOK_BANNER`: The very first point at which a plugin can run.
Intended to be used as a banner replacement. Essentially this runs
just before entering runlevel S. Assume nothing is available, so
be prepared to use absolute paths, etc.
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
mounted — very early
+84 -2
View File
@@ -12,9 +12,10 @@
.Sh SYNOPSIS
.Nm /sbin/finit
.Op --
.Op finit.status=[on,off]
.Op finit.status_style=[classic,modern]
.Op finit.debug
.Op finit.fstab=/etc/fstab.alt
.Op finit.status=<on,off>
.Op finit.status_style=<classic,modern>
.Op rescue | recover
.Op single | S
.Nm /sbin/telinit
@@ -62,12 +63,93 @@ Plugin support for customization
.It
Proper rescue mode with bundled `sulogin` for protected maintenance shell
.El
.Sh BOOTPARAM
.Nm
support the following command line parameters to alter the behavior
at boot. Notice the
.Cm --
separator needed to tell the kernel which paramters should be given to
PID 1. For more information on this, and available kernel command line
options, see
.Xr bootparam 7 .
.Bl -tag -width pid -offset indent
.It Cm finit.debug
Enable Finit debug messages on system console and log. Sometimes useful
when doing board bringup. Before the system log daemon has started,
Finit use the kernel ring buffer,
.Pa /dev/kmsg .
.It Cm finit.fstab=/path/to/fstab.alt
Tell
.Nm
to use an alternate
.Cm fstab
to mount the file system from. Remember, this file must be on the
.Cm root=...
file system provided to Finit from the kernel. If this file is missing,
.Nm
falls back to its built-in default, which can be changed at build time
using the
.Cm --with-fstab=/path/to/footab
configure option. It is even possible to completely disable the
built-in using
.Cm --without-fstab ,
meaning
.Nm
.Sy must
be started with the
.Cm finit.fstab
option.
.Pp
Should
.Nm
discover that there is no fstab file available, including the fallback,
it triggers the same failure mode as when
.Cm fsck
fails, starting
.Xr sulogin 8 ,
if that is availble. When
.Cm sulogin
is missing, or when the user exits from
.Cm sulogin ,
the system is rebooted.
.Pp
Default fstab, unless changed at build-time:
.Pa /etc/fstab
.It Cm finit.status=<on,off>
Control finit boot progress, including banner. This used to be called
.Cm finit.show_status ,
which still works but is deprecated.
.It Cm finit.status_style=<classic,modern>
Set Finit boot progress style, when enabled.
.It Cm rescue | recover
Start rescue/maintenance mode. If your system comes with the bundled
.Cm sulogin
program (Finit, or from util-linux/Busybox), you will be given a root
login to a maintenance shell. However, if
.Cm sulogin
is missing, the file
.Pa /lib/finit/rescue.conf
is read and the system booted in a limited fallback mode. See
.Xr finit.conf 5
for more information.
.It Cm single | S
Single user mode, runlevel 1, in Finit. Useful to debug problems with
the regular runlevel. All services and TTYs in
.Cm [1]
will be started, e.g., a
.Cm tty [1] @console nologin
configuration presents you with a root console without login.
.El
.Sh BOOTING
.Pp
Before laucnhing services, the system needs to be bootstrapped. This
involves mounting all filesystems (not already mounted by an initramfs)
in
.Pa /etc/fstab ,
or any alternate
.Pa fstab
file provided on the Finit command line using
.Cm finit.fstab ,
ensuring that necessary filesystems like:
.Pa /dev ,
.Pa /proc ,
+13
View File
@@ -181,6 +181,12 @@ After which they have to be restarted manually using
.Cm initctl restart NAME .
The number of restarts, the delay between each restart, and more is
configurable, see the options below.
.Pp
.Bd -filled -offset indent
.Sy Tip:
to allow endless restarts, see below option
.Cm respawn
.Ed
.Pp
For daemons that support it, we recommend appending
.Cm --foreground , --no-background , -n , -F ,
@@ -301,6 +307,13 @@ and the above (2 and 5) will be used
.It Cm norestart
dont restart on failures, same as
.Cm restart:0
.It Cm respawn
bypasses the
.Cm restart
mechanism completely, allows endless restarts. Useful in many
use-cases, but not what
.Cm service
was originally designed for so not the default behavior.
.It Cm oncrash:reboot
when all retries have failed, and the service
has
+4
View File
@@ -64,6 +64,10 @@ if BUILD_DBUS_PLUGIN
pkglib_LTLIBRARIES += dbus.la
endif
if BUILD_HOOK_SCRIPTS_PLUGIN
pkglib_LTLIBRARIES += hook-scripts.la
endif
if BUILD_HOTPLUG_PLUGIN
pkglib_LTLIBRARIES += hotplug.la
endif
+1 -1
View File
@@ -1,6 +1,6 @@
/* Save and restore ALSA sound settings using alsactl
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+9 -3
View File
@@ -1,6 +1,6 @@
/* Setup necessary system files for, e.g. UTMP (tracking logins)
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,12 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ftw.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <string.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
@@ -39,10 +43,12 @@
static int is_tmpfs(char *path)
{
struct mntent mount;
struct mntent *mnt;
char buf[256];
int tmpfs = 0;
FILE *fp;
char *dir;
struct mntent *mnt;
/* If path is a symlink, check what it resolves to */
dir = realpath(path, NULL);
@@ -55,7 +61,7 @@ static int is_tmpfs(char *path)
return 0; /* Dunno, maybe not */
}
while ((mnt = getmntent(fp))) {
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
if (!strcmp(dir, mnt->mnt_dir))
break;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup and start system message bus, D-Bus
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+116
View File
@@ -0,0 +1,116 @@
/* Trigger scripts to run from finit's hooks
*
* Copyright (c) 2022 Tobias Waldekranz <tobias@waldekranz.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "config.h"
#define CHOOSE(x, y) y
static const char *hscript_paths[] = HOOK_TYPES;
#undef CHOOSE
static void hscript_run_parts(hook_point_t hook)
{
char path[CMD_SIZE] = "";
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
strlcat(path, hscript_paths[hook] + 4, sizeof(path));
run_parts(path, NULL);
}
static void hscript_banner(void *arg)
{
hscript_run_parts(HOOK_BANNER);
}
static void hscript_rootfs_up(void *arg)
{
hscript_run_parts(HOOK_ROOTFS_UP);
}
static void hscript_mount_error(void *arg)
{
hscript_run_parts(HOOK_MOUNT_ERROR);
}
static void hscript_mount_post(void *arg)
{
hscript_run_parts(HOOK_MOUNT_POST);
}
static void hscript_basefs_up(void *arg)
{
hscript_run_parts(HOOK_BASEFS_UP);
}
static void hscript_network_up(void *arg)
{
hscript_run_parts(HOOK_NETWORK_UP);
}
static void hscript_svc_up(void *arg)
{
hscript_run_parts(HOOK_SVC_UP);
}
static void hscript_system_up(void *arg)
{
hscript_run_parts(HOOK_SYSTEM_UP);
}
static void hscript_shutdown(void *arg)
{
hscript_run_parts(HOOK_SHUTDOWN);
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BANNER] = { .cb = hscript_banner },
.hook[HOOK_ROOTFS_UP] = { .cb = hscript_rootfs_up },
.hook[HOOK_MOUNT_ERROR] = { .cb = hscript_mount_error },
.hook[HOOK_MOUNT_POST] = { .cb = hscript_mount_post },
.hook[HOOK_BASEFS_UP] = { .cb = hscript_basefs_up },
.hook[HOOK_NETWORK_UP] = { .cb = hscript_network_up },
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+1 -1
View File
@@ -1,6 +1,6 @@
/* Heuristically find and initialize a suitable hotplug daemon
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Coldplug modules using modalias magic
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+103 -43
View File
@@ -21,6 +21,29 @@
* THE SOFTWARE.
*/
/*
* This plugin scans files in /etc/modules-load.d/, for each line in the
* file it assumes the name of a kernel module, with optional arguments.
* Each module is loaded when entering runlevel 2, 3, 4, or 5, using the
* modprobe tool.
*
* Loading is done by inserting a `task` stanza in Finit, ensuring all
* modules are loaded in parallel, with other modules and programs.
* Each `task` stanza is by default given the name:modprobe.module and
* indexed with `:ID`, starting with 1.
*
* Indexing can be disabled per file in /etc/modules-load.d/, anywwhere
* in a file, by putting the keyword `noindex` on a line of its own. A
* noindex command can appear anywhere in the file, and up to the point
* it is read, tasks will be indexed with an incrementing `:ID`. When
* `noindex` is read indexing is disabled and all subseequent tasks will
* not have any `:ID` at all.
*
* Please note, the :ID is there for your benefit, it ensures that tasks
* in Finit are unique. If you have two tasks with the same name and ID
* (or no ID), the last one read replaces any preceeding one!
*/
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
@@ -40,57 +63,94 @@
#define MODULES_LOAD_PATH "/etc/modules-load.d"
#endif
#define SERVICE_LINE \
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
"cgroup.init name:modprobe.%s :%d [2345] /sbin/modprobe %s %s -- Kernel module: %s"
#define SERVICE_LINE_NOINDEX \
"cgroup.init name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
static int load_file(const char *file, int index)
{
char module_path[PATH_MAX];
char line[256];
int num = 0;
FILE *fp;
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
strlcat(module_path, file, sizeof(module_path));
fp = fopen(module_path, "r");
if (!fp)
return 0;
while (fgets(line, sizeof(line), fp)) {
char cmd[CMD_SIZE], *mod, *args;
chomp(line);
mod = strip_line(line);
if (!mod[0])
continue;
if (mod[0] == '#' || mod[0] == ';')
continue;
if (!strcmp(mod, "set noindex")) {
index = 0;
continue;
}
if (!strncmp(mod, "set index", 9)) {
mod += 9;
args = strchr(mod, '=');
if (args) /* optional */
mod = args + 1;
index = atoi(mod);
continue;
}
mod = strtok_r(mod, " ", &args);
if (!mod)
continue;
if (!index)
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, mod, args, mod);
else
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, mod, args, mod);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
num++;
}
fclose(fp);
return num;
}
/* XXX: check here for .conf only? */
static int module_filter(const struct dirent *d)
{
if (d->d_type == DT_DIR)
return 0;
if (d->d_name[0] == '.')
return 0; /* skip dot files */
if (d->d_name[strlen(d->d_name) - 1] == '~')
return 0; /* skip backup files */
return 1;
}
static void load(void *arg)
{
struct dirent *d;
char line[256];
struct dirent **dentry;
int index = 1;
FILE *fp;
DIR *dir;
int i, num;
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
dir = opendir(MODULES_LOAD_PATH);
if (!dir)
return;
while ((d = readdir(dir))) {
char module_path[PATH_MAX];
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
strlcat(module_path, d->d_name, sizeof(module_path));
fp = fopen(module_path, "r");
if (!fp)
continue;
while (fgets(line, sizeof(line), fp)) {
char cmd[CMD_SIZE], *mod, *args;
mod = strip_line(line);
if (!*mod)
continue;
mod = chomp(mod);
if (!mod || !*mod)
continue;
mod = strtok_r(mod, " ", &args);
if (!mod)
continue;
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
index++;
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
if (num > 0) {
for (i = 0; i < num; i++) {
index += load_file(dentry[i]->d_name, index);
free(dentry[i]);
}
fclose(fp);
free(dentry);
}
closedir(dir);
}
static plugin_t plugin = {
+8 -8
View File
@@ -2,7 +2,7 @@
/* Netlink plugin for IFUP/IFDN and GW events
*
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
* Copyright (C) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (C) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -253,18 +253,18 @@ static int nl_parse(int sd)
return -1;
}
_d("recv %zd bytes", len);
// _d("recv %zd bytes", len);
l = (size_t)len;
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
struct nlmsgerr *nle;
switch (nh->nlmsg_type) {
case NLMSG_DONE:
_d("Done with netlink messages.");
// _d("Done with netlink messages.");
return 0;
case NLMSG_ERROR:
_d("Kernel netlink comm. error.");
// _d("Kernel netlink comm. error.");
nle = NLMSG_DATA(nh);
if (nle) {
errno = -nle->error;
@@ -274,13 +274,13 @@ static int nl_parse(int sd)
case RTM_NEWROUTE:
case RTM_DELROUTE:
_d("Netlink route ...");
// _d("Netlink route ...");
nl_route(nh, len);
break;
case RTM_NEWLINK:
case RTM_DELLINK:
_d("Netlink link ...");
// _d("Netlink link ...");
nl_link(nh, len);
break;
@@ -304,14 +304,14 @@ static int nl_request(int sd, unsigned int seq, int type)
switch (type) {
case RTM_GETROUTE:
_d("RTM_GETROUTE");
// _d("RTM_GETROUTE");
nlr->rtm.rtm_family = AF_INET;
nlr->rtm.rtm_table = RT_TABLE_MAIN;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
break;
case RTM_GETLINK:
_d("RTM_GETLINK");
// _d("RTM_GETLINK");
nlr->ifi.ifi_family = AF_UNSPEC;
nlr->ifi.ifi_change = 0xFFFFFFFF;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+7 -1
View File
@@ -1,7 +1,7 @@
/* Simple pidfile event monitor for the Finit condition engine
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -98,10 +98,16 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
return;
}
/* Service is not crashing, let's tell state machine! */
service_forked(svc);
if (pid != svc->pid) {
_d("Forking service %s changed PID from %d to %d",
svc->cmd, svc->pid, pid);
svc->pid = pid;
/* Complement log in service.c for non-forking services */
logit(LOG_CONSOLE | LOG_NOTICE, "Started %s[%d]", svc_ident(svc, NULL, 0), pid);
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* Set kernel variables from /etc/sysctl.conf et al
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup necessary files for resolvconf
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Save and restore RTC using hwclock
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* System condition event monitor for the Finit condition engine
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* 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-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup and save random seed at boot/shutdown
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* User-defined condition event monitor for the Finit condition engine
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Console setup (for X)
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+4 -1
View File
@@ -8,7 +8,10 @@ AM_LDFLAGS = -export-dynamic
endif
sbin_PROGRAMS = finit initctl
pkglibexec_PROGRAMS = getty logit sulogin
pkglibexec_PROGRAMS = getty logit
if SULOGIN
pkglibexec_PROGRAMS += sulogin
endif
if KEVENTD
pkglibexec_PROGRAMS += keventd
endif
+4 -3
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -36,7 +38,6 @@
#endif
#include <uev/uev.h>
#include "config.h"
#include "finit.h"
#include "cond.h"
#include "conf.h"
@@ -197,7 +198,7 @@ static svc_t *do_find(char *buf, size_t len)
if (!id)
return svc_named_iterator(&iter, 1, input);
return svc_find_by_nameid(input, id);
return svc_find(input, id);
}
static svc_t *do_find_byc(char *buf, size_t len)
+3 -3
View File
@@ -1,6 +1,6 @@
/* Finit control group support functions
*
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -465,9 +465,9 @@ void cgroup_init(uev_ctx_t *ctx)
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
if (errno == ENOENT)
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
else if (errno == EPERM) /* Probably inside an unpriviliged container */
logit(LOG_NOTICE, "Not allowed to mount cgroups v2, disabling.");
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
else
_pe("Failed mounting cgroup v2");
avail = 0;
+1 -1
View File
@@ -1,6 +1,6 @@
/* Finit control group support functions
*
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool
*
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Cgroup utility functions for initctl
*
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+11 -5
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,11 +39,17 @@ int client_connect(void)
};
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (-1 == sd)
err(1, "Failed creating UNIX domain socket");
if (-1 == sd) {
warn("Failed creating UNIX domain socket");
return -1;
}
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
err(1, "Failed connecting to finit");
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
if (errno != ENOENT)
warnx("Failed connecting to finit");
close(sd);
return -1;
}
return sd;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+32 -2
View File
@@ -21,6 +21,7 @@
* THE SOFTWARE.
*/
#include <dirent.h>
#include <ftw.h>
#include <libgen.h>
#include <stdio.h>
@@ -132,6 +133,25 @@ static int cond_checkpath(const char *path)
return 0;
}
/* Intended for 'service/foo/`, nothing else */
static void cond_delpath(const char *path)
{
char fn[PATH_MAX];
struct dirent *d;
DIR *dir;
dir = opendir(path);
if (!dir)
return;
while ((d = readdir(dir))) {
paste(fn, sizeof(fn), path, d->d_name);
remove(fn);
}
closedir(dir);
unlink(path);
}
int cond_set_path(const char *path, enum cond_state next)
{
enum cond_state prev;
@@ -155,8 +175,18 @@ int cond_set_path(const char *path, enum cond_state next)
break;
case COND_OFF:
if (unlink(path) && errno != ENOENT)
_pe("Failed removing condition '%s'", path);
if (unlink(path)) {
switch (errno) {
case ENOENT:
break;
case EISDIR:
cond_delpath(path);
break;
default:
_pe("Failed removing condition '%s'", path);
break;
}
}
break;
default:
+176 -37
View File
@@ -1,6 +1,6 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -54,6 +54,12 @@
int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5;
struct env_entry {
TAILQ_ENTRY(env_entry) link;
char *name;
};
static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
struct rlimit global_rlimit[RLIMIT_NLIMITS];
@@ -67,7 +73,7 @@ struct conf_change {
static struct iwatch iw_conf;
static uev_t etcw;
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
static int parse_conf(char *file, int is_rcsd);
static void drop_changes(void);
@@ -87,6 +93,7 @@ fallback:
/*
* finit.debug = [on,off]
* finit.fstab = /path/to/etc/fstab.aternative
* finit.status = [on,off] (compat finit.show_status)
* finit.status_style = [old,classic,modern]
*/
@@ -103,6 +110,11 @@ static void parse_finit_opts(char *opt)
return;
}
if (string_compare(opt, "fstab")) {
fstab = arg;
return;
}
if (string_compare(opt, "status_style")) {
if (!arg) {
_e("status_style option requires an argument, skipping.");
@@ -122,6 +134,33 @@ static void parse_finit_opts(char *opt)
}
}
/*
* When runlevel (single integer) is given on the command line,
* it overrides the runlevel in finit.conf and the built-in
* default (from configure). It do however have to pass the
* same sanity checks.
*/
static int parse_runlevel(char *arg)
{
const char *err = NULL;
char *ptr = arg;
long long num;
/* Sanity check the token is just digit(s) */
while (*ptr) {
if (!isdigit(*ptr++))
return 0;
}
num = strtonum(arg, 1, 9, &err);
if (err || num == 6) {
_d("Not a valid runlevel (%s), valid levels are [1-9], excluding 6, skipping.", arg);
return 0;
}
return (int)num;
}
static void parse_arg(char *arg)
{
if (!strncmp(arg, "finit.", 6)) {
@@ -129,11 +168,19 @@ static void parse_arg(char *arg)
return;
}
if (string_compare(arg, "rescue") || string_compare(arg, "recover"))
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
rescue = 1;
return;
}
if (string_compare(arg, "single") || string_compare(arg, "S"))
if (string_compare(arg, "single") || string_compare(arg, "S")) {
single = 1;
return;
}
/* Put any new command line options before this line. */
cmdlevel = parse_runlevel(arg);
}
#ifdef KERNEL_CMDLINE
@@ -207,6 +254,98 @@ void conf_parse_cmdline(int argc, char *argv[])
parse_kernel_loglevel();
}
/*
* Clear all environment variables read in parse_env(), they may be
* removed now so let the next call to parse_env() restore them.
*/
void conf_reset_env(void)
{
struct env_entry *node, *tmp;
TAILQ_FOREACH_SAFE(node, &env_list, link, tmp) {
TAILQ_REMOVE(&env_list, node, link);
if (node->name) {
unsetenv(node->name);
free(node->name);
}
free(node);
}
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
}
/*
* 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
* the conf_reset_env() function.
*/
static void parse_env(char *line)
{
struct env_entry *node;
char *key, *val, *end;
/* skip any leading whitespace */
key = line;
while (isspace(*key))
key++;
/* find end of line */
end = key;
while (*end)
end++;
/* strip trailing whitespace */
if (end > key) {
end--;
while (isspace(*end))
*end-- = 0;
}
val = strchr(key, '=');
if (!val)
return;
*val++ = 0;
/* strip leading whitespace from value */
while (isspace(*val))
val++;
/* unquote value, if quoted */
if (val[0] == '"' || val[0] == '\'') {
char q = val[0];
if (*end == q) {
val = &val[1];
*end = 0;
}
}
/* find end of key */
end = key;
while (*end)
end++;
/* strip trailing whitespace */
if (end > key) {
end--;
while (isspace(*end))
*end-- = 0;
}
setenv(key, val, 1);
node = malloc(sizeof(*node));
if (!node) {
_pe("Out of memory cannot track env vars");
return;
}
node->name = strdup(key);
TAILQ_INSERT_HEAD(&env_list, node, link);
}
static int kmod_exists(char *mod)
{
char buf[256];
@@ -478,7 +617,7 @@ static void conf_parse_cgroup(char *line)
cgroup_add(name, config, 0);
}
static void parse_static(char *line, int is_rcsd)
static int parse_static(char *line, int is_rcsd)
{
char cmd[CMD_SIZE];
char *x;
@@ -486,7 +625,7 @@ static void parse_static(char *line, int is_rcsd)
if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
return;
return 0;
}
if (BOOTSTRAP && MATCH_CMD(line, "mknod ", x)) {
@@ -495,25 +634,25 @@ static void parse_static(char *line, int is_rcsd)
strcpy(cmd, "mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
return;
return 0;
}
/* Kernel module to load */
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
kmod_load(strip_line(x));
return;
return 0;
}
if (BOOTSTRAP && MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
return;
return 0;
}
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
if (runparts) free(runparts);
runparts = strdup(strip_line(x));
return;
return 0;
}
if (MATCH_CMD(line, "include ", x)) {
@@ -522,11 +661,10 @@ static void parse_static(char *line, int is_rcsd)
strlcpy(cmd, file, sizeof(cmd));
if (!fexist(cmd)) {
_e("Cannot find include file %s, absolute path required!", x);
return;
return 1;
}
parse_conf(cmd, is_rcsd);
return;
return parse_conf(cmd, is_rcsd);
}
if (MATCH_CMD(line, "log ", x)) {
@@ -547,12 +685,14 @@ static void parse_static(char *line, int is_rcsd)
logfile_size_max = size;
if (count >= 0)
logfile_count_max = count;
return 0;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
return;
return 0;
}
/*
@@ -569,7 +709,7 @@ static void parse_static(char *line, int is_rcsd)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
return;
return 0;
}
/*
@@ -589,72 +729,65 @@ static void parse_static(char *line, int is_rcsd)
if (disabled)
service_init();
}
return;
return 0;
}
return 1;
}
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
static int parse_dynamic(char *line, struct rlimit rlimit[], char *file)
{
char *x;
/* Monitored daemon, will be respawned on exit */
if (MATCH_CMD(line, "service ", x)) {
service_register(SVC_TYPE_SERVICE, x, rlimit, file);
return;
return 0;
}
/* One-shot task, will not be respawned */
if (MATCH_CMD(line, "task ", x)) {
service_register(SVC_TYPE_TASK, x, rlimit, file);
return;
return 0;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
service_register(SVC_TYPE_RUN, x, rlimit, file);
return;
return 0;
}
/* Similar to task but is treated like a SysV init script */
if (MATCH_CMD(line, "sysv ", x)) {
service_register(SVC_TYPE_SYSV, x, rlimit, file);
return;
return 0;
}
/* Read resource limits */
if (MATCH_CMD(line, "rlimit ", x)) {
conf_parse_rlimit(x, rlimit);
return;
return 0;
}
/* Read control group limits */
if (MATCH_CMD(line, "cgroup ", x)) {
conf_parse_cgroup(x);
return;
return 0;
}
/* Set current cgroup for the following services/run/tasks */
if (MATCH_CMD(line, "cgroup.", x)) {
strlcpy(cgroup_current, x, sizeof(cgroup_current));
return;
return 0;
}
/* Regular or serial TTYs to run getty */
if (MATCH_CMD(line, "tty ", x)) {
service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file);
return;
return 0;
}
}
static void tabstospaces(char *line)
{
if (!line)
return;
for (int i = 0; line[i]; i++) {
if (line[i] == '\t')
line[i] = ' ';
}
return 1;
}
static int parse_conf(char *file, int is_rcsd)
@@ -688,8 +821,13 @@ static int parse_conf(char *file, int is_rcsd)
if (MATCH_CMD(line, "#", x))
continue;
parse_static(line, is_rcsd);
parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file);
if (!parse_static(line, is_rcsd))
continue;
if (!parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file))
continue;
/* Not static or dynamic conf, check if it is a global env. */
parse_env(line);
}
fclose(fp);
@@ -713,6 +851,7 @@ int conf_reload(void)
/* Mark and sweep */
cgroup_mark_all();
svc_mark_dynamic();
conf_reset_env();
/*
* Reset global rlimit to bootstrap values from conf_init().
+2 -1
View File
@@ -1,6 +1,6 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,6 +42,7 @@ int conf_any_change (void);
int conf_changed (char *file);
int conf_monitor (void);
void conf_reset_env (void);
void conf_parse_cmdline (int argc, char *argv[]);
int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond);
+1 -1
View File
@@ -1,7 +1,7 @@
/* Functions for exec'ing processes
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+215 -88
View File
@@ -1,7 +1,7 @@
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,16 +26,18 @@
#include <ctype.h>
#include <dirent.h>
#ifdef HAVE_FSTAB_H
#include <fstab.h>
#endif
#include <getopt.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <time.h> /* tzet() */
#include <sys/klog.h>
#include <sys/mount.h>
#include <sys/stat.h> /* umask(), mkdir() */
#include <sys/wait.h>
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
@@ -60,12 +62,14 @@
int runlevel = 0; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int cmdlevel = 0; /* runlevel override from cmdline */
int prevlevel = -1;
int debug = 0; /* debug mode from kernel cmdline */
int rescue = 0; /* rescue mode from kernel cmdline */
int single = 0; /* single user mode from kernel cmdline */
int bootstrap = 1; /* set while bootrapping (for TTYs) */
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
char *fstab = FINIT_FSTAB;
char *sdown = NULL;
char *network = NULL;
char *hostname = NULL;
@@ -106,70 +110,167 @@ static void banner(void)
#endif
}
static int sulogin(int do_reboot)
{
int rc = EX_OSFILE;
char *cmd[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(cmd); i++) {
char *path = which(cmd[i]);
if (access(path, X_OK)) {
free(path);
continue;
}
rc = systemf("%s", path);
free(path);
break;
}
if (do_reboot) {
do_shutdown(SHUT_REBOOT);
exit(rc);
}
return rc;
}
char *fs_root_dev(char *real, size_t len)
{
struct dirent *d;
struct stat st;
int found = 0;
dev_t dev;
DIR *dir;
if (stat("/", &st))
return NULL;
if (S_ISBLK(st.st_mode))
dev = st.st_rdev;
else
dev = st.st_dev;
dir = opendir("/sys/block");
if (!dir)
return NULL;
while ((d = readdir(dir))) {
char buf[10];
char *ptr;
if (fnread(buf, sizeof(buf), "/sys/block/%s/dev", d->d_name) == -1)
continue;
ptr = strchr(buf, ':');
if (!ptr)
continue;
*ptr++ = 0;
if (atoi(buf) == (int)major(dev) && atoi(ptr) == (int)minor(dev)) {
/* Guess name, assume no renaming */
snprintf(real, len, "/dev/%s", d->d_name);
found = 1;
break;
}
}
closedir(dir);
if (!found)
return NULL;
return real;
}
/*
* Check all filesystems in /etc/fstab with a fs_passno > 0
*/
static int fsck(int pass)
{
struct fstab *fs;
struct mntent mount;
struct mntent *mnt;
char real[192];
char buf[256];
int rc = 0;
FILE *fp;
if (!setfsent()) {
_pe("Failed opening fstab");
return 1;
fp = setmntent(fstab, "r");
if (!fp) {
_pe("Failed opening fstab: %s", fstab);
sulogin(1);
}
while ((fs = getfsent())) {
char cmd[80];
struct stat st;
_d("Opened %s, pass %d", fstab, pass);
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
int fsck_rc = 0;
struct stat st;
char cmd[256];
char *dev;
if (fs->fs_passno != pass)
_d("got: fsname '%s' dir '%s' type '%s' opts '%s' freq '%d' passno '%d'",
mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
mnt->mnt_freq, mnt->mnt_passno);
if (mnt->mnt_passno == 0 || mnt->mnt_passno != pass)
continue;
/* Device to maybe fsck, */
dev = mnt->mnt_fsname;
errno = 0;
if (stat(fs->fs_spec, &st) || !S_ISBLK(st.st_mode)) {
if (!string_match(fs->fs_spec, "UUID=") && !string_match(fs->fs_spec, "LABEL=")) {
_d("Cannot fsck %s, not a block device: %s", fs->fs_spec, strerror(errno));
if (stat(dev, &st) || !S_ISBLK(st.st_mode)) {
int skip = 1;
if (string_match(dev, "UUID=") || string_match(dev, "LABEL="))
skip = 0;
/*
* Kernel short form for root= device, figure out
* actual device since we cannot rely on symlinks
* https://bugs.busybox.net/show_bug.cgi?id=8891
*/
else if (string_compare(dev, "/dev/root")) {
if (fs_root_dev(real, sizeof(real))) {
dev = real;
skip = 0;
}
}
if (skip) {
_d("Cannot fsck %s, not a block device: %s", dev, strerror(errno));
continue;
}
}
if (ismnt("/proc/mounts", fs->fs_file, "rw")) {
_d("Skipping fsck of %s, already mounted rw on %s.", fs->fs_spec, fs->fs_file);
if (ismnt("/proc/mounts", mnt->mnt_dir, "rw")) {
_d("Skipping fsck of %s, already mounted rw on %s.", dev, mnt->mnt_dir);
continue;
}
#ifdef FSCK_FIX
snprintf(cmd, sizeof(cmd), "fsck -yf %s", fs->fs_spec);
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
#else
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
snprintf(cmd, sizeof(cmd), "fsck -a %s", dev);
#endif
fsck_rc = run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
_d("Running pass %d fsck command %s", pass, cmd);
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
/*
* "failure" is defined as exiting with a return code of
* 2 or larger. A return code of 1 indicates that filesystem
* errors were corrected but that the boot may proceed.
*/
if (fsck_rc > 1) {
char *sulogin[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(sulogin); i++) {
if (systemf(sulogin[i]))
continue;
break;
}
do_shutdown(SHUT_REBOOT);
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
sulogin(1);
}
rc += fsck_rc;
}
endfsent();
endmntent(fp);
return rc;
}
@@ -202,38 +303,22 @@ static void fs_mount(const char *src, const char *tgt, const char *fstype,
}
#ifndef SYSROOT
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
static int fs_readonly_root(struct fstab *fs)
{
char *tok, *str;
if (!fs)
return 1;
str = fs->fs_mntops;
while ((tok = strtok(str, ","))) {
if (!strcmp(tok, "ro"))
return 1;
str = NULL;
}
return 0;
}
static void fs_remount_root(int fsckerr)
{
struct fstab *fs;
struct mntent *mnt;
FILE *fp;
if (!setfsent())
fp = setmntent(fstab, "r");
if (!fp)
return;
while ((fs = getfsent())) {
if (!strcmp(fs->fs_file, "/"))
while ((mnt = getmntent(fp))) {
if (!strcmp(mnt->mnt_dir, "/"))
break;
}
if (fs_readonly_root(fs))
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
if (!mnt || hasmntopt(mnt, "ro"))
goto out;
if (fsckerr)
@@ -243,7 +328,7 @@ static void fs_remount_root(int fsckerr)
"Remounting / as read-write");
out:
endfsent();
endmntent(fp);
}
#else
static void fs_remount_root(int fsckerr)
@@ -319,22 +404,69 @@ static void fs_finalize(void)
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
}
static void fs_swapon(char *cmd, size_t len)
{
struct mntent *mnt;
FILE *fp;
if (!whichp("swapon"))
return;
fp = setmntent(fstab, "r");
if (!fp)
return;
while ((mnt = getmntent(fp))) {
if (strcmp(mnt->mnt_type, MNTTYPE_SWAP))
continue;
snprintf(cmd, len, "swapon %s", mnt->mnt_fsname);
run_interactive(cmd, "Enabling swap %s", mnt->mnt_fsname);
}
endmntent(fp);
}
static void fs_mount_all(void)
{
char cmd[256] = "mount -na";
if (!fstab || !fexist(fstab)) {
logit(LOG_CONSOLE | LOG_NOTICE, "%s system fstab %s, trying fallback ...",
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
fstab = FINIT_FSTAB;
}
if (!fstab || !fexist(fstab)) {
logit(LOG_CONSOLE | LOG_EMERG, "%s system fstab %s, attempting sulogin ...",
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
sulogin(1);
}
/*
* Needed by fsck, both BusyBox and util-linux support this.
* We leave it set in the env. for the benefit of any mount
* helpers and other system tools that the user expects to
* behave even if we've booted with a different fstab.
*/
setenv("FSTAB_FILE", fstab, 1);
if (!rescue)
fs_remount_root(fsck_all());
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
if (run_interactive("mount -na", "Mounting filesystems"))
if (fstab && strcmp(fstab, "/etc/fstab"))
snprintf(cmd, sizeof(cmd), "mount -na -T %s", fstab);
if (run_interactive(cmd, "Mounting filesystems from %s", fstab))
plugin_run_hooks(HOOK_MOUNT_ERROR);
_d("Calling extra mount hook, after mount -a ...");
plugin_run_hooks(HOOK_MOUNT_POST);
if (whichp("swapon"))
run_interactive("swapon -ea", "Enabling system swap");
_d("Enable any swap ...");
fs_swapon(cmd, sizeof(cmd));
_d("Finalize, ensure common file systems are available ...");
fs_finalize();
@@ -438,11 +570,12 @@ static void crank_worker(void *unused)
*/
static void bootstrap_worker(void *work)
{
static int cnt = 120;
static struct wq final = {
.cb = finalize,
.delay = 10
};
static int cnt = 120;
int level = cfglevel;
_d("Step all services ...");
service_step_all(SVC_TYPE_ANY);
@@ -467,11 +600,18 @@ static void bootstrap_worker(void *work)
if (runparts && fisdir(runparts) && !rescue)
run_parts(runparts, NULL);
/*
* Start all tasks/services in the configured runlevel
* Start all tasks/services in the configured runlevel, or jump
* into the runlevel selected from the command line.
*/
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
service_runlevel(cfglevel);
if (cmdlevel) {
_d("Runlevel %d requested from command line, starting all services ...", cmdlevel);
level = cmdlevel;
} else
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
service_runlevel(level);
}
static int version(int rc)
@@ -599,10 +739,7 @@ int main(int argc, char *argv[])
/*
* Set PATH, SHELL, and PWD early to something sane
*/
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
conf_reset_env();
if (chdir("/"))
_pe("Failed cd /");
@@ -610,21 +747,8 @@ int main(int argc, char *argv[])
/*
* In case of emergency.
*/
if (rescue) {
char *sulogin[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(sulogin); i++) {
if (systemf(sulogin[i]))
continue;
rescue = 0;
break;
}
}
if (rescue)
rescue = sulogin(0);
/*
* Load plugins early, the first hook is in banner(), so we
@@ -653,7 +777,10 @@ int main(int argc, char *argv[])
*/
cgroup_init(&loop);
/* Check and mount filesystems. */
/*
* Check custom fstab from cmdline, including fallback, then run
* fsck before mounting all filesystems, on error call sulogin.
*/
fs_mount_all();
/* Bootstrap conditions, needed for hooks */
@@ -676,7 +803,7 @@ int main(int argc, char *argv[])
*/
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
wdog = svc_find_by_nameid("watchdog", "finit");
wdog = svc_find("watchdog", "finit");
}
/*
+4 -2
View File
@@ -1,7 +1,7 @@
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -110,16 +110,18 @@ struct init_request {
extern int runlevel;
extern int cfglevel;
extern int cmdlevel;
extern int prevlevel;
extern int debug;
extern int rescue;
extern int single;
extern int bootstrap;
extern int kerndebug;
extern char *rcsd;
extern char *fstab;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *rcsd;
extern char *runparts;
extern char *osheading;
extern uev_ctx_t *ctx;
+2 -2
View File
@@ -1,6 +1,6 @@
/* Initialize and serve a login terminal
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
* THE SOFTWARE.
*/
#include "config.h"
#include "config.h" /* Generated by configure script */
#include <err.h>
#include <errno.h>
+14 -43
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,6 +22,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isblank() */
#include <errno.h>
#include <grp.h>
@@ -100,6 +102,17 @@ ssize_t cprintf(const char *fmt, ...)
return size;
}
void tabstospaces(char *line)
{
if (!line)
return;
for (int i = 0; line[i]; i++) {
if (line[i] == '\t')
line[i] = ' ';
}
}
char *strip_line(char *line)
{
char *ptr;
@@ -587,48 +600,6 @@ int in_container(void)
return 0;
}
#ifndef HAVE_GETFSENT
static lfile_t *fstab = NULL;
int setfsent(void)
{
if (fstab)
lfclose(fstab);
fstab = lfopen("/etc/fstab", " \t\n");
if (!fstab)
return 0;
return 1;
}
struct fstab *getfsent(void)
{
static struct fstab fs;
fs.fs_spec = lftok(fstab);
if (fs.fs_spec == NULL)
return NULL;
fs.fs_file = lftok(fstab);
fs.fs_vfstype = lftok(fstab);
fs.fs_mntops = lftok(fstab);
fs.fs_type = "rw";
fs.fs_freq = atoi(lftok(fstab) ?: "0");
fs.fs_passno = atoi(lftok(fstab) ?: "0");
return &fs;
}
void endfsent(void)
{
if (fstab)
lfclose(fstab);
fstab = NULL;
}
#endif /* HAVE_GETFSENT */
/**
* Local Variables:
* indent-tabs-mode: t
+2 -19
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,8 +25,6 @@
#ifndef FINIT_HELPERS_H_
#define FINIT_HELPERS_H_
#include <mntent.h>
#include <sched.h> /* sched_yield() */
#include <stdarg.h>
#include <sys/resource.h>
#include <sys/types.h>
@@ -47,26 +45,11 @@ typedef enum {
PROGRESS_MODERN,
} pstyle_t;
#ifndef HAVE_GETFSENT
struct fstab {
char *fs_spec; /* block device name */
char *fs_file; /* mount point */
char *fs_vfstype; /* file-system type */
char *fs_mntops; /* mount options */
const char *fs_type; /* rw/rq/ro/sw/xx option */
int fs_freq; /* dump frequency, in days */
int fs_passno; /* pass number on parallel dump */
};
int setfsent (void);
void endfsent (void);
struct fstab *getfsent (void);
#endif /* HAVE_GETFSENT */
char *console (void);
void console_init (void);
ssize_t cprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
void tabstospaces (char *line);
char *strip_line (char *line);
void enable_progress (int onoff);
+25 -4
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool
*
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -391,7 +391,7 @@ static int do_cond_dump(char *arg)
return 0;
}
static int do_cond_act(char *arg, int creat)
static int do_cond_act(char *arg, int op)
{
char oneshot[256];
size_t off;
@@ -409,17 +409,29 @@ static int do_cond_act(char *arg, int creat)
snprintf(oneshot, sizeof(oneshot), _PATH_CONDUSR "%s", arg);
off = strlen(_PATH_COND);
if (creat) {
switch (op) {
case 2:
off = !fexist(oneshot);
if (verbose)
puts(off ? "off" : "on");
return off;
case 1:
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
err(1, "Failed asserting condition <%s>", &oneshot[off]);
} else {
break;
case 0:
if (erase(oneshot) && errno != ENOENT)
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
break;
default:
errx(1, "Unsupported operation (%d)", op);
break;
}
return 0;
}
static int do_cond_get(char *arg) { return do_cond_act(arg, 2); }
static int do_cond_set(char *arg) { return do_cond_act(arg, 1); }
static int do_cond_clr(char *arg) { return do_cond_act(arg, 0); }
@@ -664,6 +676,13 @@ static char *svc_command(svc_t *svc, char *buf, size_t len)
strlcat(buf, svc->args[i], len);
}
if (svc_is_sysv(svc)) {
char *cmd = svc->state == SVC_HALTED_STATE ? "stop" : "start";
strlcat(buf, " ", len);
strlcat(buf, cmd, len);
}
strlcat(buf, bold ? "\e[0m" : "", len);
return buf;
@@ -999,6 +1018,7 @@ static int usage(int rc)
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
"\n"
" cond set <COND> Set (assert) user-defined condition +usr/COND\n"
" cond get <COND> Get status of user-defined condition, see $? and -v\n"
" cond clear <COND> Clear (deassert) user-defined condition -usr/COND\n"
" cond status Show condition status, default cond command\n"
" cond dump Dump all conditions and their status\n"
@@ -1113,6 +1133,7 @@ int main(int argc, char *argv[])
{ "status", NULL, do_cond_show, NULL, NULL }, /* default cmd */
{ "dump", NULL, do_cond_dump, NULL, NULL },
{ "set", NULL, do_cond_set, NULL, NULL },
{ "get", NULL, do_cond_get, NULL, NULL },
{ "clr", NULL, do_cond_clr, NULL, NULL },
{ "clear", NULL, do_cond_clr, NULL, NULL },
{ NULL, NULL, NULL, NULL, NULL }
+1 -1
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool
*
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* inotify watcher for files or directories
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* inotify watcher for files or directories
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Listens to kernel events like AC power status and manages sys/ conditions
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+3 -2
View File
@@ -1,6 +1,6 @@
/* Finit daemon log functions
*
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,8 @@
* THE SOFTWARE.
*/
#include "config.h"
#include "config.h" /* Generated by configure script */
#include <stdio.h>
#include <stdarg.h>
#ifdef _LIBITE_LITE
+1 -1
View File
@@ -1,6 +1,6 @@
/* Finit daemon log functions
*
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+3 -1
View File
@@ -1,6 +1,6 @@
/* Handle MD arrays
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <glob.h>
#include <stdio.h>
#include <string.h>
+11 -6
View File
@@ -1,6 +1,6 @@
/* Mount and unmount helpers
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,9 +21,13 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <string.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <sys/mount.h>
#include "helpers.h"
@@ -68,12 +72,12 @@ static void iterator_end(FILE **fp)
*fp = NULL;
}
static struct mntent *iterator(char *fstab, FILE **fp)
static struct mntent *iterator(char *filename, FILE **fp)
{
static struct mntent *mnt;
if (!*fp && fstab) {
*fp = setmntent(fstab, "r");
if (!*fp && filename) {
*fp = setmntent(filename, "r");
if (!*fp)
return NULL;
}
@@ -94,8 +98,9 @@ static int unmount(const char *target)
int rc;
rc = umount(target);
if (rc && errno != EBUSY) {
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
if (rc) {
if (errno != EBUSY)
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
return rc;
}
print(0, "Unmounting %s", target);
+3 -1
View File
@@ -1,7 +1,7 @@
/* PID and PID file helpers
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,6 +22,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <paths.h>
#include <stdio.h>
+1 -1
View File
@@ -1,7 +1,7 @@
/* PID and PID file helpers
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+3 -2
View File
@@ -1,6 +1,6 @@
/* Plugin based services architecture for finit
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <dlfcn.h> /* dlopen() et al */
#include <dirent.h> /* readdir() et al */
@@ -34,7 +36,6 @@
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include "config.h"
#include "cond.h"
#include "finit.h"
#include "helpers.h"
+1 -1
View File
@@ -1,6 +1,6 @@
/* Plugin based services architecture for finit
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,7 +1,7 @@
/* Private header file for main finit daemon, not for plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+6 -1
View File
@@ -1,6 +1,6 @@
/* reboot, halt, poweroff, shutdown, suspend for finit
*
* Copyright (c) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,7 @@
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "util.h"
@@ -159,6 +160,10 @@ int reboot_main(int argc, char *argv[])
/* Check for any overrides */
transform(NULL);
/* Check if we're in sulogin shell */
if (getenv("SULOGIN"))
force = 1;
if (force) {
sync();
+1 -1
View File
@@ -1,6 +1,6 @@
/* Work queue helper functions
*
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Work queue helper functions
*
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* List and enable/disable service configurations
*
* Copyright (c) 2017-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2017-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* List and enable/disable service configurations
*
* Copyright (c) 2017-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2017-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+163 -77
View File
@@ -1,7 +1,7 @@
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +25,7 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isblank() */
#include <sched.h> /* sched_yield() */
#include <string.h>
#include <sys/reboot.h>
#include <sys/prctl.h>
@@ -89,7 +90,7 @@ static void service_timeout_cb(uev_t *w, void *arg, int events)
* Returns:
* POSIX OK(0) on success, non-zero on error.
*/
static int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
{
if (svc->timer_cb)
return -EBUSY;
@@ -107,7 +108,7 @@ static int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc)
* Returns:
* POSIX OK(0) on success, non-zero on error.
*/
static int service_timeout_cancel(svc_t *svc)
int service_timeout_cancel(svc_t *svc)
{
int err;
@@ -381,6 +382,20 @@ static char *group_name(svc_t *svc, char *buf, size_t len)
return buf;
}
static void compose_cmdline(svc_t *svc, char *buf, size_t len)
{
size_t i;
strlcpy(buf, svc->cmd, len);
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
if (!strlen(svc->args[i]))
break;
strlcat(buf, " ", len);
strlcat(buf, svc->args[i], len);
}
}
static pid_t service_fork(svc_t *svc)
{
pid_t pid;
@@ -445,6 +460,7 @@ static pid_t service_fork(svc_t *svc)
static int service_start(svc_t *svc)
{
int result = 0, do_progress = 1;
char cmdline[CMD_SIZE] = "";
sigset_t nmask, omask;
char grnam[80];
pid_t pid;
@@ -481,8 +497,9 @@ static int service_start(svc_t *svc)
}
}
compose_cmdline(svc, cmdline, sizeof(cmdline));
if (svc_is_sysv(svc))
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", svc->cmd);
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", cmdline);
if (!svc->desc[0])
do_progress = 0;
@@ -569,9 +586,16 @@ static int service_start(svc_t *svc)
}
wordfree(&we);
} else {
size_t j;
i = 0;
args[i++] = svc->cmd;
args[i++] = svc->cmd;
/* this handles, e.g., bridge-stop br0 start */
for (j = 0; j < MAX_NUM_SVC_ARGS; j++) {
if (!strlen(svc->args[j]))
break;
args[i++] = svc->args[j];
}
args[i++] = "start";
}
args[i] = NULL;
@@ -604,16 +628,7 @@ static int service_start(svc_t *svc)
_exit(status);
} else if (debug) {
char buf[CMD_SIZE] = "";
for (i = 0; i < MAX_NUM_SVC_ARGS; i++) {
if (strlen(svc->args[i]) == 0)
break;
if (buf[0])
strlcat(buf, " ", sizeof(buf));
strlcat(buf, svc->args[i], sizeof(buf));
}
_d("Starting %s %s", svc->cmd, buf);
_d("Starting %s", cmdline);
}
if (svc_is_tty(svc))
@@ -621,7 +636,8 @@ static int service_start(svc_t *svc)
else
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
if (!svc_is_sysv(svc))
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
svc->pid = pid;
svc->start_time = jiffies();
@@ -717,6 +733,7 @@ static void service_cleanup(svc_t *svc)
*/
static int service_stop(svc_t *svc)
{
char cmdline[CMD_SIZE] = "";
int do_progress = 1;
int rc = 0;
@@ -728,6 +745,7 @@ static int service_stop(svc_t *svc)
service_timeout_cancel(svc);
compose_cmdline(svc, cmdline, sizeof(cmdline));
if (!svc_is_sysv(svc)) {
if (svc->pid <= 1)
return 1;
@@ -737,7 +755,7 @@ static int service_stop(svc_t *svc)
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending %s ...",
svc_ident(svc, NULL, 0), svc->pid, sig_name(svc->sighalt));
} else {
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", svc->cmd);
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", cmdline);
}
/*
@@ -777,19 +795,30 @@ static int service_stop(svc_t *svc)
svc_set_state(svc, SVC_HALTED_STATE);
}
} else {
char *args[] = { svc->cmd, "stop", NULL };
char *args[MAX_NUM_SVC_ARGS + 1];
size_t i = 0, j;
pid_t pid;
args[i++] = svc->cmd;
/* this handles, e.g., bridge-stop br0 stop */
for (j = 0; j < MAX_NUM_SVC_ARGS; j++) {
if (!strlen(svc->args[j]))
break;
args[i++] = svc->args[j];
}
args[i++] = "stop";
args[i] = NULL;
pid = fork();
switch (pid) {
case 0:
setsid();
redirect(svc);
exec_runtask(svc->cmd, args);
exec_runtask(args[0], &args[1]);
_exit(0);
break;
case -1:
_pe("Failed fork() to call sysv script '%s stop'", svc->cmd);
_pe("Failed fork() to call sysv script '%s stop'", cmdline);
rc = 1;
break;
default:
@@ -997,20 +1026,33 @@ static void parse_script(char *type, char *script, char *buf, size_t len)
}
/*
* name:<name>
* 'name:<name>' or derived from '/path/to/cmd args'
*/
static void parse_name(svc_t *svc, char *arg)
static char *parse_name(char *cmd, char *arg)
{
char *name = NULL;
if (arg && !strncasecmp(arg, "name:", 5)) {
name = arg + 5;
} else {
name = strrchr(svc->cmd, '/');
name = name ? name + 1 : svc->cmd;
char *ptr;
ptr = strchr(cmd, ' ');
if (!ptr)
ptr = cmd + strlen(cmd);
while (ptr > cmd) {
if (*ptr == '/') {
ptr++;
break;
}
ptr--;
}
name = ptr;
}
strlcpy(svc->name, name, sizeof(svc->name));
return name;
}
/*
@@ -1268,6 +1310,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
return 0;
}
name = parse_name(cmd, name);
if (!id)
id = "";
@@ -1309,11 +1352,11 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
next:
svc = svc_find_by_tty(dev);
} else
svc = svc_find(cmd, id);
svc = svc_find(name, id);
if (!svc) {
_d("Creating new svc for %s id #%s type %d", cmd, id, type);
svc = svc_new(cmd, id, type);
_d("Creating new svc for %s name %s id %s type %d", cmd, name, id, type);
svc = svc_new(cmd, name, id, type);
if (!svc) {
_e("Out of memory, cannot register service %s", cmd);
return errno = ENOMEM;
@@ -1326,6 +1369,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
svc->restart_tmo = restart_tmo;
svc->oncrash_action = oncrash_action;
} else {
_d("Found existing svc for %s name %s id %s type %d", cmd, name, id, type);
/* update type, may have changed from service -> task */
svc->type = type;
@@ -1348,7 +1393,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
}
svc->runlevels = levels;
_d("Service %s runlevel 0x%02x", svc->cmd, svc->runlevels);
_d("Service %s runlevel 0x%02x", svc_ident(svc, NULL, 0), svc->runlevels);
conf_parse_cond(svc, cond);
@@ -1382,8 +1427,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
id = ptr;
strlcpy(svc->name, "tty", sizeof(svc->name));
strlcpy(svc->id, id, sizeof(svc->id));
} else
parse_name(svc, name);
}
parse_cmdline_args(svc, cmd);
@@ -1503,17 +1547,23 @@ void service_monitor(pid_t lost, int status)
default:
_d("collected %s(%d), normal exit: %d, signaled: %d, exit code: %d",
svc->cmd, lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
svc_ident(svc, NULL, 0), lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
svc->status = status;
break;
}
/* Forking sysv/services declare themselves with pid:!/path/to/pid.file */
if (svc_is_starting(svc) && svc_is_forking(svc)) {
svc->pid = 0; /* Expect no more activity from this one */
return;
if (svc_is_forking(svc)) {
/* Likely start script exiting */
if (svc_is_starting(svc)) {
svc->pid = 0; /* Expect no more activity from this one */
goto cont;
}
logit(LOG_CONSOLE | LOG_NOTICE, "Stopped %s[%d]", svc_ident(svc, NULL, 0), lost);
}
/* Terminate any children in the same proess group, e.g. logit */
kill(-svc->pid, SIGKILL);
@@ -1531,11 +1581,11 @@ void service_monitor(pid_t lost, int status)
done:
/* No longer running, update books. */
svc->start_time = svc->pid = 0;
cont:
if (!service_step(svc)) {
/* Clean out any bootstrap tasks, they've had their time in the sun. */
if (svc_clean_bootstrap(svc))
_d("collected bootstrap task %s(%d), removing.", svc->cmd, lost);
_d("collected bootstrap task %s(%d), removing.", svc_ident(svc, NULL, 0), lost);
}
sm_step(&sm);
@@ -1587,20 +1637,11 @@ static void service_kill_script(svc_t *svc)
static void set_pre_post_envs(svc_t *svc, const char *type)
{
char buf[25 + 256] = "/etc/default:/etc/conf.d";
const char *fn = svc_getenv(svc);
const char *exist = "0";
setenv("SERVICE_TYPE", svc_typestr(svc), 1);
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
setenv("SERVICE_SCRIPT_TYPE", type, 1);
if (fn) {
setenv("SERVICE_ENV_FILE", fn, 1);
if (!access(fn, R_OK))
exist = "1";
}
setenv("SERVICE_ENV_FILE_EXIST", exist, 1);
#ifdef FINIT_SYSCONFIG
strlcat(buf, ":", sizeof(buf));
strlcat(buf, FINIT_SYSCONFIG, sizeof(buf));
@@ -1617,12 +1658,20 @@ static void service_pre_script(svc_t *svc)
}
if (svc->pid == 0) {
char buf[CMD_SIZE];
char *argv[4] = {
"sh",
"-c",
svc->pre_script,
"-ac",
buf,
NULL
};
char *env_file;
env_file = svc_getenv(svc);
if (env_file)
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->pre_script);
else
strlcpy(buf, svc->pre_script, sizeof(buf));
set_pre_post_envs(svc, "pre");
execvp(_PATH_BSHELL, argv);
@@ -1642,17 +1691,24 @@ static void service_post_script(svc_t *svc)
}
if (svc->pid == 0) {
char buf[CMD_SIZE];
char *argv[4] = {
"sh",
"-c",
svc->post_script,
"-ac",
buf,
NULL
};
char *env_file;
int rc, sig;
rc = WEXITSTATUS(svc->status);
sig = WTERMSIG(svc->status);
env_file = svc_getenv(svc);
if (env_file)
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->post_script);
else
strlcpy(buf, svc->post_script, sizeof(buf));
set_pre_post_envs(svc, "post");
if (WIFEXITED(svc->status)) {
@@ -1681,7 +1737,7 @@ static void service_retry(svc_t *svc)
service_timeout_cancel(svc);
if (svc->respawn) {
_d("%s crashed/exited, respawning ...", svc->cmd);
_d("%s crashed/exited, respawning ...", svc_ident(svc, NULL, 0));
svc_unblock(svc);
service_step(svc);
return;
@@ -1689,6 +1745,7 @@ static void service_retry(svc_t *svc)
if (svc->state != SVC_HALTED_STATE ||
svc->block != SVC_BLOCK_RESTARTING) {
svc_set_state(svc, SVC_RUNNING_STATE);
logit(LOG_CONSOLE | LOG_NOTICE, "Successfully restarted crashing service %s.",
svc_ident(svc, NULL, 0));
return;
@@ -1701,7 +1758,7 @@ static void service_retry(svc_t *svc)
svc_crashing(svc);
*restart_cnt = 0;
if (svc->oncrash_action == SVC_ONCRASH_REBOOT) {
logit(LOG_ERR, "%s issuing reboot", svc->cmd);
logit(LOG_ERR, "%s issuing reboot", svc_ident(svc, NULL, 0));
sync();
kill(1, SIGTERM);
}
@@ -1711,7 +1768,7 @@ static void service_retry(svc_t *svc)
(*restart_cnt)++;
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
_d("%s crashed, trying to start it again, attempt %d", svc_ident(svc, NULL, 0), *restart_cnt);
logit(LOG_CONSOLE | LOG_WARNING, "Service %s[%d] died, restarting (%d/%d)",
svc_ident(svc, NULL, 0), svc->oldpid, *restart_cnt, svc->restart_max);
svc_unblock(svc);
@@ -1733,7 +1790,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
if (*state == SVC_STOPPING_STATE) {
_d("%s is stopping, wait %d sec before sending SIGKILL ...",
svc->cmd, svc->killdelay / 1000);
svc_ident(svc, NULL, 0), svc->killdelay / 1000);
service_timeout_cancel(svc);
service_timeout_after(svc, svc->killdelay, service_kill);
}
@@ -1741,8 +1798,8 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
if (svc_is_runtask(svc)) {
char success[MAX_COND_LEN], failure[MAX_COND_LEN];
snprintf(success, sizeof(success), "%s/%s/success", svc_typestr(svc), svc->name);
snprintf(failure, sizeof(failure), "%s/%s/failure", svc_typestr(svc), svc->name);
snprintf(success, sizeof(success), "%s/%s/success", 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. */
if (*state == SVC_DONE_STATE) {
@@ -1758,6 +1815,39 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
cond_clear(failure);
}
}
if (svc_is_daemon(svc)) {
char cond[MAX_COND_LEN];
snprintf(cond, sizeof(cond), "service/%s/", svc_ident(svc, NULL, 0));
cond_clear(cond);
switch (svc->state) {
case SVC_HALTED_STATE:
case SVC_RUNNING_STATE:
strlcat(cond, svc_status(svc), sizeof(cond));
cond_set_oneshot(cond);
break;
default:
break;
}
}
}
/*
* Called by pidfile plugin for forking services that have successfully started.
* We get here when the service_monitor() collects the PID, sets svc->pid to 0,
* and the state machine prepares for the worst bu setting state to HALTED.
*/
void service_forked(svc_t *svc)
{
/* Stop forking_retry() timer */
service_timeout_cancel(svc);
/* Not crashing, restore RUNNING state */
svc_unblock(svc);
svc_set_state(svc, SVC_RUNNING_STATE);
}
/*
@@ -1778,7 +1868,7 @@ restart:
old_state = svc->state;
enabled = svc_enabled(svc);
_d("%20s(%4d): %8s %3sabled/%-7s cond:%-4s", svc->cmd, svc->pid,
_d("%20s(%4d): %8s %3sabled/%-7s cond:%-4s", svc_ident(svc, NULL, 0), svc->pid,
svc_status(svc), enabled ? "en" : "dis", svc_dirtystr(svc),
condstr(cond_get_agg(svc->cond)));
@@ -1802,7 +1892,7 @@ restart:
if (!svc->pid) {
char condstr[MAX_COND_LEN];
_d("%s: stopped, cleaning up timers and conditions ...", svc->cmd);
_d("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
service_timeout_cancel(svc);
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
@@ -1870,30 +1960,26 @@ restart:
}
if (!svc->pid) {
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
if (svc_is_forking(svc))
break;
if (svc_is_daemon(svc) || svc_is_sysv(svc) || svc_is_tty(svc)) {
svc_restarting(svc);
svc_set_state(svc, SVC_HALTED_STATE);
/*
* Restart directly after the first crash,
* then retry after 2 sec
* Restart directly after the first crash, except for forking services
* which we need to wait for the forked-off child to create its pid
* file. In both cases, after that, retry after 2 sec
*/
if (!svc->respawn)
_d("delayed restart of %s", svc->cmd);
service_timeout_after(svc, 1, service_retry);
_d("delayed restart of %s", svc_ident(svc, NULL, 0));
if (svc_is_forking(svc))
service_timeout_after(svc, 2000, service_retry);
else
service_timeout_after(svc, 1, service_retry);
break;
}
if (svc_is_runtask(svc)) {
if (svc_is_sysv(svc)) {
if (!svc->started)
svc_set_state(svc, SVC_STOPPING_STATE);
} else {
svc_set_state(svc, SVC_STOPPING_STATE);
}
if (svc_is_runtask(svc)) { /* only run/task, not sysv here */
svc_set_state(svc, SVC_STOPPING_STATE);
svc->once++;
break;
}
@@ -1972,7 +2058,7 @@ restart:
}
if (svc->state != old_state) {
_d("%20s(%4d): -> %8s", svc->cmd, svc->pid, svc_status(svc));
_d("%20s(%4d): -> %8s", svc_ident(svc, NULL, 0), svc->pid, svc_status(svc));
changed++;
goto restart;
}
@@ -2043,15 +2129,15 @@ int service_completed(void)
if (strstr(svc->cond, plugin_hook_str(HOOK_SVC_UP)) ||
strstr(svc->cond, plugin_hook_str(HOOK_SYSTEM_UP))) {
_d("Skipping %s(%s), post-strap hook", svc->desc, svc->cmd);
_d("Skipping %s(%s), post-strap hook", svc->desc, svc_ident(svc, NULL, 0));
continue;
}
if (!svc->once) {
_d("%s has not yet completed ...", svc->cmd);
_d("%s has not yet completed ...", svc_ident(svc, NULL, 0));
return 0;
}
_d("%s has completed ...", svc->cmd);
_d("%s has completed ...", svc_ident(svc, NULL, 0));
}
return 1;
+6 -1
View File
@@ -1,7 +1,7 @@
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -35,6 +35,11 @@ void service_runtask_clean (void);
void service_reload_dynamic (void);
void service_update_rdeps (void);
int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc));
int service_timeout_cancel (svc_t *svc);
void service_forked (svc_t *svc);
int service_step (svc_t *svc);
void service_step_all (int types);
void service_worker (void *unused);
+35 -7
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to!
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -69,7 +69,12 @@
* Finit defaults to nothing but sets sys/pwr/fail condition.
*/
#include "config.h" /* Generated by configure script */
#include <dirent.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <string.h> /* strerror() */
#include <sched.h>
#include <sys/reboot.h>
@@ -166,6 +171,30 @@ void mdadm_wait(void);
void unmount_tmpfs(void);
void unmount_regular(void);
static void fs_swapoff(void)
{
struct mntent *mnt;
char cmd[256];
FILE *fp;
if (!whichp("swapoff"))
return;
fp = setmntent(fstab, "r");
if (!fp)
return;
while ((mnt = getmntent(fp))) {
if (strcmp(mnt->mnt_type, MNTTYPE_SWAP))
continue;
snprintf(cmd, sizeof(cmd), "swapoff %s", mnt->mnt_fsname);
run_interactive(cmd, "Disabling swap %s", mnt->mnt_fsname);
}
endmntent(fp);
}
/*
* Kernel threads have no cmdline so fgets() returns NULL for them. We
* also skip "special" processes, e.g. mdadm/mdmon or watchdogd that must
@@ -323,8 +352,7 @@ void do_shutdown(shutop_t op)
/* Unmount any tmpfs before unmounting swap ... */
unmount_tmpfs();
if (whichp("swapoff"))
run_interactive("swapoff -a", "Disabling system swap");
fs_swapoff();
/* ... unmount remaining regular file systems. */
unmount_regular();
@@ -468,8 +496,8 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
*/
static void sigchld_cb(uev_t *w, void *arg, int events)
{
pid_t pid;
int status;
pid_t pid;
if (UEV_ERROR == events) {
_e("Unrecoverable error in signal watcher");
@@ -532,8 +560,8 @@ static void chld_handler(int sig, siginfo_t *info, void *ctx)
void sig_init(void)
{
int i;
struct sigaction sa;
int i;
for (i = 1; i < NSIG; i++)
IGNSIG(sa, i, SA_RESTART);
@@ -546,9 +574,9 @@ void sig_init(void)
*/
void sig_unblock(void)
{
int i;
sigset_t nmask;
struct sigaction sa;
sigset_t nmask;
int i;
sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
+1 -1
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to!
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+5 -3
View File
@@ -1,6 +1,6 @@
/* Reset terminal line settings (stty sane)
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,10 +21,12 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <stdlib.h>
#include <unistd.h> /* _POSIX_VDISABLE */
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <unistd.h> /* _POSIX_VDISABLE */
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <termios.h>
#include "helpers.h"
+4 -1
View File
@@ -1,6 +1,6 @@
/* poor man's sulogin, may be statically linked
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -193,6 +193,9 @@ int main(void)
nopass:
freepw(&pw);
/* tell initctl/reboot to trigger force mode */
setenv("SULOGIN", "finit", 1);
return sh();
}
}
+13 -32
View File
@@ -1,7 +1,7 @@
/* Low-level service primitives and generic API for managing svc_t structures
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,6 +22,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <err.h>
#include <ctype.h> /* isdigit() */
#include <time.h>
@@ -105,16 +107,17 @@ static void svc_gc(void *arg)
/**
* svc_new - Create a new service
* @cmd: External program to call
* @name: Default or custom svc name
* @id: Instance id
* @type: Service type, one of service, task, run
*
* Returns:
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
*/
svc_t *svc_new(char *cmd, char *id, int type)
svc_t *svc_new(char *cmd, char *name, char *id, int type)
{
int job = -1;
svc_t *svc, *iter = NULL;
int job = -1;
/* Find first job n:o if registering multiple instances */
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
@@ -132,6 +135,8 @@ svc_t *svc_new(char *cmd, char *id, int type)
svc->type = type;
svc->job = job;
if (name)
strlcpy(svc->name, name, sizeof(svc->name));
if (id && id[0])
strlcpy(svc->id, id, sizeof(svc->id));
if (cmd)
@@ -346,13 +351,13 @@ svc_t *svc_stop_completed(void)
/**
* svc_find - Find a service object by its full path name
* @cmd: Full path name, e.g., /sbin/syslogd
* @id: Optional instance id
* @name: Full path name, e.g., /sbin/syslogd
* @id: Optional instance id
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find(char *cmd, char *id)
svc_t *svc_find(char *name, char *id)
{
svc_t *svc, *iter = NULL;
@@ -360,7 +365,7 @@ svc_t *svc_find(char *cmd, char *id)
id = "";
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!strcmp(svc->cmd, cmd) && !strcmp(svc->id, id))
if (!strcmp(svc->name, name) && !strcmp(svc->id, id))
return svc;
}
@@ -409,30 +414,6 @@ svc_t *svc_find_by_jobid(int job, char *id)
return NULL;
}
/**
* svc_find_by_nameid - Find an service object by its basename:ID
* @name: Process name to match
* @id: Optional instance id
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find_by_nameid(char *name, char *id)
{
svc_t *svc, *iter = NULL;
if (!id)
id = "";
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!strcmp(svc->id, id) && !strcmp(name, svc->name))
return svc;
}
return NULL;
}
svc_t *svc_find_by_tty(char *dev)
{
svc_t *svc, *iter = NULL;
@@ -718,7 +699,7 @@ int svc_parse_jobstr(char *str, size_t len, void *user_data, int (*found)(svc_t
*ptr++ = 0;
id = ptr;
svc = svc_find_by_nameid(token, id);
svc = svc_find(token, id);
if (!svc && not_found)
result += not_found(token, id, user_data);
else if (found)
+3 -4
View File
@@ -1,7 +1,7 @@
/* Low-level service primitives and generic API for managing svc_t structures
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -193,14 +193,13 @@ typedef struct svc {
struct timespec gc;
} svc_t;
svc_t *svc_new (char *cmd, char *id, int type);
svc_t *svc_new (char *cmd, char *name, char *id, int type);
int svc_del (svc_t *svc);
void svc_validate (svc_t *svc);
svc_t *svc_find (char *cmd, char *id);
svc_t *svc_find (char *name, char *id);
svc_t *svc_find_by_pid (pid_t pid);
svc_t *svc_find_by_jobid (int job, char *id);
svc_t *svc_find_by_nameid (char *name, char *id);
svc_t *svc_find_by_tty (char *dev);
svc_t *svc_find_by_pidfile (char *fn);
+4 -2
View File
@@ -1,7 +1,7 @@
/* Finit TTY handling
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,6 +22,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isdigit() */
#include <signal.h>
#include <termios.h>
@@ -170,7 +172,7 @@ int tty_parse_args(char *cmd, struct tty *tty)
else
tty->args[tty->num++] = cmd;
cmd = strtok(NULL, " \t");
cmd = strtok(NULL, " ");
} while (cmd && tty->num < NELEMS(tty->args));
/* rescue shells are always notty */
+1 -1
View File
@@ -1,7 +1,7 @@
/* Finit TTY handling
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+8 -3
View File
@@ -1,6 +1,6 @@
/* Misc. shared utility functions for initctl, reboot and finit
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,10 +21,13 @@
* THE SOFTWARE.
*/
#include "config.h"
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isprint() */
#include <errno.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <regex.h>
#include <string.h>
#include <stdlib.h>
@@ -488,7 +491,9 @@ static int hasopt(char *opts, char *opt)
int ismnt(char *file, char *dir, char *mode)
{
struct mntent mount;
struct mntent *mnt;
char buf[256];
int found = 0;
FILE *fp;
@@ -496,7 +501,7 @@ int ismnt(char *file, char *dir, char *mode)
if (!fp)
return 0; /* Dunno, maybe not */
while ((mnt = getmntent(fp))) {
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
if (!strcmp(mnt->mnt_dir, dir)) {
if (mode) {
if (hasopt(mnt->mnt_opts, mode))
+1 -1
View File
@@ -1,6 +1,6 @@
/* Misc. shared utility functions for initctl, reboot and finit
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -1,6 +1,6 @@
/* UTMP API
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
* THE SOFTWARE.
*/
#include "config.h"
#include "config.h" /* Generated by configure script */
#include <time.h>
#include <arpa/inet.h>
+1 -1
View File
@@ -1,6 +1,6 @@
/* UTMP API
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Built-in watchdog daemon
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Built-in watchdog daemon
*
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+25 -13
View File
@@ -1,23 +1,30 @@
SUBDIRS = common tenv
EXTRA_DIST = skel/bin/busybox-x86_64.md5 skel/sbin/service.sh skel/bin/slay \
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
skel/etc/init.d/S01-service.sh skel/home/.empty \
skel/proc/.empty skel/root/.empty skel/run/.empty \
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
skel/usr/games/.empty skel/usr/src/.empty \
skel/usr/share/.empty skel/usr/include/.empty \
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
skel/usr/local/share/.empty skel/usr/local/src/.empty \
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
EXTRA_DIST = skel/bin/busybox-x86_64.md5 skel/sbin/service.sh skel/bin/slay \
skel/etc/env skel/bin/pre.sh skel/bin/post.sh skel/sbin/task.sh \
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
skel/etc/finit.d/.empty skel/etc/init.d/S01-service.sh \
skel/etc/init.d/S02-serv.sh \
skel/proc/.empty skel/root/.empty skel/run/.empty \
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
skel/home/.empty skel/usr/games/.empty skel/usr/src/.empty \
skel/usr/share/.empty skel/usr/include/.empty \
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
skel/usr/local/share/.empty skel/usr/local/src/.empty \
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
skel/usr/local/etc/.empty skel/var/.empty
EXTRA_DIST += setup-root.sh
EXTRA_DIST += add-remove-dynamic-service.sh
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
EXTRA_DIST += cond-start-task.sh
EXTRA_DIST += failing-sysv.sh
EXTRA_DIST += global-envs.sh
EXTRA_DIST += pre-post-serv.sh
EXTRA_DIST += runlevel.sh
EXTRA_DIST += start-stop-service.sh
EXTRA_DIST += start-stop-service-sub-config.sh
EXTRA_DIST += start-kill-service.sh
@@ -41,6 +48,11 @@ TESTS = checkself.sh
TESTS += setup-root.sh
TESTS += add-remove-dynamic-service.sh
TESTS += add-remove-dynamic-service-sub-config.sh
TESTS += cond-start-task.sh
TESTS += failing-sysv.sh
TESTS += global-envs.sh
TESTS += pre-post-serv.sh
TESTS += runlevel.sh
TESTS += start-stop-service.sh
TESTS += start-stop-service-sub-config.sh
TESTS += start-kill-service.sh
+42 -2
View File
@@ -15,6 +15,38 @@
#define PROGNM "serv"
static void verify_env(char *arg)
{
char *key, *value;
char *replica;
char *env;
key = replica = strdup(arg);
if (!replica)
err(1, "Failed duplicating arg %s", arg);
value = strchr(replica, ':');
if (!value)
errx(1, "Invalid format of KEY:VALUE arg, missing ':' in %s", replica);
*(value++) = 0;
env = getenv(key);
if (!env)
errx(1, "No '%s' in environment", key);
if (strcmp(env, value))
errx(1, "Mismatch, environment '%s' vs expected value '%s'", env, value);
}
static void verify_noenv(char *key)
{
char *val;
val = getenv(key);
if (val)
errx(1, "Error, key %s is set in environment to '%s'", key, val);
}
static void sig(int signo)
{
warnx("We got signal %d ...", signo);
@@ -48,8 +80,10 @@ static int usage(int rc)
fprintf(fp,
"%s [-nhp] [-P FILE]\n"
"\n"
" -n Run in foreground\n"
" -h Show help text (this)\n"
" -e K:V Verify K environment variable is V value\n"
" -E K Verify K is not set in the environment\n"
" -n Run in foreground\n"
" -p Create PID file despite running in foreground\n"
" -P FILE Create PID file using FILE\n"
"\n"
@@ -69,10 +103,16 @@ int main(int argc, char *argv[])
char *pidfn = NULL;
int c;
while ((c = getopt(argc, argv, "hnpP:")) != EOF) {
while ((c = getopt(argc, argv, "e:E:hnpP:")) != EOF) {
switch (c) {
case 'h':
return usage(0);
case 'e':
verify_env(optarg);
break;
case 'E':
verify_noenv(optarg);
break;
case 'n':
do_background = 0;
do_pidfile--;
+91
View File
@@ -0,0 +1,91 @@
#!/bin/sh
# A run/task runs once per runlevel, unless its .conf is touched
# then it will run again on initctl reload. This test verifies
# this behavior, with the added twist of starting the task by
# asserting a condition.
set -eu
TEST_DIR=$(dirname "$0")
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
TEST_CONF=$FINIT_RCSD/cond.conf
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
say "Running test teardown."
texec rm -f "$TEST_CONF"
}
test_one()
{
cond=$1
stanza=$2
sleep 5
say 'Enable finit debug, try to figure out what is going on ...'
texec sh -c "initctl debug"
say "Add stanza '$stanza' to $TEST_CONF ..."
texec sh -c "echo '$stanza' > $TEST_CONF"
texec sh -c "ls -l /run/ /run/finit/"
say 'Reload Finit'
texec sh -c "initctl ls"
texec sh -c "initctl reload"
texec sh -c "initctl status"
texec sh -c "ps"
date
sleep 2
date
texec sh -c "ls -l /run/ /run/finit/"
say 'Asserting condition'
texec sh -c "initctl cond set $cond"
date
sleep 2
date
texec sh -c "ls -l /run/ /run/finit/"
texec sh -c "initctl status"
texec sh -c "ps"
texec sh -c "initctl status task.sh"
sleep 1
texec sh -c "echo Hej; cat /run/task.state"
assert_file_contains /run/task.state 1
say 'Reload Finit'
texec sh -c "initctl reload"
sleep 1
say 'Ensure task has not run again ...'
assert_file_contains /run/task.state 1
say 'Switch to another runlevel ...'
texec sh -c "initctl runlevel 3"
sleep 1
say 'Ensure task has run again ...'
assert_file_contains /run/task.state 2
say 'Touch task.sh .conf file and reload Finit ...'
texec sh -c "touch $TEST_CONF"
texec sh -c "initctl reload"
sleep 1
# texec sh -c "initctl status task.sh"
assert_file_contains /run/task.state 3
say "Done, drop stanza from $TEST_CONF ..."
texec sh -c "rm $TEST_CONF"
texec sh -c "initctl reload"
}
test_one "hello" "task <usr/hello> task.sh -- Hello task"
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh
# Verify what happesn when sysv scripts start services that keep
# crashing -- hint: crashing sysv services should be detected by
# Finit just like regular services.
set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
texec sh -c "mkdir -p /etc/default"
}
test_teardown()
{
say "Test done $(date)"
say "Running test teardown."
texec rm -f "$FINIT_CONF"
}
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
# This instructs serv to check the environment, and exit
# if it cannot find "xyzzy", thus triggering a premature
# exit which Finit should act on to retstart it.
say "Setting up bogus /etc/default/serv"
texec sh -c "echo 'SERV_ARGS=\"-e xyzzy:lives\"' > /etc/default/serv"
say "Add sysv stanza to $FINIT_CONF"
texec sh -c "echo 'sysv restart:5 [2345] pid:!/run/serv.pid name:serv /etc/init.d/S02-serv.sh -- Crashing SysV service' > $FINIT_CONF"
#texec sh -c "initctl debug"
say 'Reload Finit'
texec sh -c "initctl reload"
#texec sh -c "initctl status serv"
#texec sh -c "ps"
say 'Pending sysv restarts by Finit ...'
#texec sh -c "initctl status serv"
#texec sh -c "ps"
retry 'assert_restarts 5 serv' 20 1
return 0
+56
View File
@@ -0,0 +1,56 @@
#!/bin/sh
set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
texec rm -f "$FINIT_CONF"
}
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
#texec sh -c "initctl debug"
say "Add custom envs to $FINIT_CONF ..."
texec sh -c "echo 'foo=bar' > $FINIT_CONF"
texec sh -c "echo 'baz=qux' >> $FINIT_CONF"
say "Add service stanza to $FINIT_CONF ..."
texec sh -c "echo 'service serv -np -e foo:bar -- Verify foo=bar' >> $FINIT_CONF"
say 'Reload Finit'
texec sh -c "initctl reload"
sleep 1
retry 'assert_num_children 1 serv'
say "Modify $FINIT_CONF slightly ..."
texec sh -c "sed -i 's/foo:bar/baz:qux/; s/foo=bar/baz=qux/' $FINIT_CONF"
say 'Reload Finit'
texec sh -c "initctl reload"
sleep 1
retry 'assert_num_children 1 serv'
say "Swap envs completely in $FINIT_CONF ..."
texec sh -c "echo 'bar=foo' > $FINIT_CONF"
texec sh -c "echo 'qux=baz' >> $FINIT_CONF"
say "Add swapped service stanza to $FINIT_CONF ..."
texec sh -c "echo 'service serv -np -e bar:foo -E baz -- Verify bar=foo and no baz' >> $FINIT_CONF"
say 'Reload Finit'
texec sh -c "initctl reload"
sleep 1
retry 'assert_num_children 1 serv'
say "Done, drop service from $FINIT_CONF ..."
texec sh -c "rm $FINIT_CONF"
texec sh -c "initctl reload"
+62
View File
@@ -0,0 +1,62 @@
#!/bin/sh
set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
texec rm -f "$FINIT_CONF"
}
test_one()
{
pre=$1
precont=$2
service=$3
post=$4
postcont=$5
say "Add service stanza '$service' to $FINIT_CONF ..."
texec sh -c "echo '$service' > $FINIT_CONF"
say 'Reload Finit'
texec sh -c "initctl reload"
retry 'assert_num_children 1 serv'
if [ -n "$pre" ]; then
assert_file_contains "$pre" "$precont"
texec sh -c "rm -f $pre"
fi
say 'Stop the service'
texec sh -c "initctl stop serv"
retry 'assert_num_children 0 serv'
if [ -n "$post" ]; then
assert_file_contains "$post" "$postcont"
texec sh -c "rm -f $post"
fi
say "Done, drop service from $FINIT_CONF ..."
texec sh -c "rm $FINIT_CONF"
texec sh -c "initctl reload"
}
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
#texec sh -c "initctl debug"
test_one "" "" "service serv -np -- Regular fg service, no pre/post scripts" "" ""
test_one "" "" "service env:/etc/env serv -np -e foo:bar -- serv + env, no pre/post scripts" "" ""
test_one /tmp/pre PRE "service pre:/bin/pre.sh serv -np -- serv + pre script" "" ""
test_one /tmp/pre bar "service env:/etc/env pre:/bin/pre.sh serv -np -e baz:qux -- Env + pre script" "" ""
test_one "" "" "service post:/bin/post.sh serv -np -- Regular fg service, post script" /tmp/post POST
test_one "" "" "service env:/etc/env post:/bin/post.sh serv -np -- Regular fg service, post script" /tmp/post qux
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# Verify selecting alternate runlevel from cmdline
set -eu
TEST_DIR=$(dirname "$0")
# shellcheck disable=SC2034
FINIT_RUNLEVEL=9
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
}
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
say 'Check runlevel'
lvl=$(texec sh -c "initctl runlevel | awk '{print \$2;}'")
if [ "$lvl" -eq "9" ]; then
return 0
fi
return 1
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
marker="POST"
# shellcheck disable=SC2154
if [ -n "$baz" ]; then
marker=$baz
fi
echo "$marker" > /tmp/post
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
marker="PRE"
# shellcheck disable=SC2154
if [ -n "$foo" ]; then
marker=$foo
fi
echo "$marker" > /tmp/pre
+5
View File
@@ -0,0 +1,5 @@
# Some environments to be sourced by Finit services
# and their pre:- and post:scripts
foo=bar
baz=qux
View File
+55
View File
@@ -0,0 +1,55 @@
#!/bin/sh
# SysV style start script for serv
DAEMON="/sbin/serv"
PIDFILE="/var/run/serv.pid"
# shellcheck source=/dev/null
[ -r "/etc/default/serv" ] && . "/etc/default/serv"
start()
{
printf 'Starting %s: ' "$DAEMON $SERV_ARGS"
# shellcheck disable=SC2086
start-stop-daemon -S -b -q -p "$PIDFILE" -x "$DAEMON" -- $SERV_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop()
{
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart()
{
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1"
;;
*)
echo "Usage: $0 {start|stop|restart}, got $0 $1"
exit 1
esac
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
num=$(cat /run/task.state)
if [ -z "$num" ]; then
num=0
fi
num=$((num + 1))
echo $num > /run/task.state
+2 -1
View File
@@ -7,7 +7,8 @@ TEST_DIR=$(dirname "$0")
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
test_teardown() {
test_teardown()
{
say "Test done $(date)"
say "Running test teardown."
+36 -7
View File
@@ -21,6 +21,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
assert_file_contains()
{
assert "File $1 contains the string $2" "$(texec grep "$2" "$1")"
}
assert_num_children()
{
assert "$1 services are running" "$(texec pgrep -P 1 "$2" | wc -l)" -eq "$1"
@@ -29,7 +34,12 @@ assert_num_children()
# shellcheck disable=SC2086
assert_new_pid()
{
assert "Finit has registered new PID" "$(texec initctl |grep $1 |awk '{print $1}')" -eq "$(texec cat $2)"
assert "Finit has registered new PID" "$(texec initctl |grep $1 | awk '{print $1;}')" -eq "$(texec cat $2)"
}
assert_restarts()
{
assert "Finit has registered restarts" "$(texec initctl status "$2" | awk '/Restarts/{print $3;}')" -ge "$1"
}
# shellcheck disable=SC2086
@@ -153,20 +163,39 @@ export TENV_ROOT
if [ -n "${DEBUG:-}" ]; then
FINIT_ARGS="${FINIT_ARGS:-} finit.debug=on"
fi
# Tests may want to override runlevel
if [ -n "${FINIT_RUNLEVEL:-}" ]; then
FINIT_ARGS="${FINIT_ARGS:-} $FINIT_RUNLEVEL"
else
FINIT_RUNLEVEL=2
fi
# shellcheck disable=2086
"$TEST_DIR/tenv/start.sh" finit ${FINIT_ARGS:-} &
finit_ppid=$!
echo "$finit_ppid" > "$TENV_ROOT"/running_test.pid
>&2 echo "Hint: Execute 'TENV_ROOT=$TENV_ROOT $TEST_DIR/tenv/enter.sh' to enter the test namespace"
log "$color_reset" 'Setup of test environment done, waiting for Finit to start up ...' ''
#>&2 echo "Hint: Execute 'TENV_ROOT=$TENV_ROOT $TEST_DIR/tenv/enter.sh' to enter the test namespace"
log "$color_reset" 'Setup of test environment done, waiting for Finit ...' ''
finit_pid=$(retry "pgrep -P $finit_ppid")
#tty=/dev/$(texec cat /sys/class/tty/console/active)
#texec cat "$tty" &
# Allow Finit to start up properly before launching the test
i=0
while [ $i -lt 10 ]; do
lvl=$(texec sh -c "initctl runlevel | awk '{print \$2;}'")
if [ "$lvl" -eq "$FINIT_RUNLEVEL" ]; then
# say "Reached runlevel $FINIT_RUNLEVEL, releasing test."
break;
fi
i=$((i + 1))
sleep 1
done
if type test_setup > /dev/null 2>&1 ; then
test_setup
fi
#tty=/dev/$(texec cat /sys/class/tty/console/active)
#texec cat "$tty" &
#sleep 1