Compare commits

..
124 Commits
Author SHA1 Message Date
Joachim Wiberg ce7d4cebab test: minor refactor, relocate "Test start ..." message to setup.sh
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 13:31:29 +02:00
Joachim Wiberg d5a47e2d8b doc: document new stop:script support
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 13:22:11 +02:00
Joachim Wiberg 020eefe732 test: extend start-stop-sysv to verify stop:script support
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 13:21:50 +02:00
Joachim Wiberg 14336bd407 Add stop:'script [args]' support for service/sysv stanzas
Fixes #412

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 13:20:46 +02:00
Joachim Wiberg bb841383b8 doc: document new reload:script support
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 12:05:59 +02:00
Joachim Wiberg e49763d834 test: extend start-stop-sysv to verify reload:script support
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 12:05:58 +02:00
Joachim Wiberg 57545e1ab0 Add reload:'script [args]' support for service/sysv stanzas
Fixes #446

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 12:05:51 +02:00
Joachim Wiberg 7ad802b092 Add quote support to pre/post/ready/cleanup scripts
- Allow scripts to take space separated arguments with quoting
 - Simplify script-exists check, which already checks for leading /
 - Unset current script on parse error
 - Allow setting no timeout

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 12:00:02 +02:00
Joachim Wiberg e319a606b8 tmpfiles: minor, fix memory leak
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 11:36:56 +02:00
Joachim Wiberg 7d434b1eaa Ignore new tmpfiles binary
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:28:42 +02:00
Joachim Wiberg 58d48b54b3 tmpfiles: add -d,--debug mode
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:28:02 +02:00
Joachim Wiberg 7d4603e13b Minor, simplify
clang-tidy noticed this unnecessary check.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:14:07 +02:00
Joachim Wiberg d0c5d7be5b Minor, constify
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:14:05 +02:00
Joachim Wiberg db840bdc19 Follow-up to 8be7a46, simplify linking of tmpfiles program
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:14:04 +02:00
Joachim Wiberg 3df3c51dae Relocate global configuration variables from finit.c -> conf.c
These variables really belong in conf.c.  Relocate and move external
decls. from finit.h -> conf.h to simplify linking of other programs.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:14:03 +02:00
Joachim Wiberg d37d241647 Drop log.h include from helpers.h
With the relocation of several functions, including inline functions,
from helpers to util, we no longer need to include log.h.  Which is a
good thing, since any subsystem that needs logging should explicitly
include log.h

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:14:02 +02:00
Joachim Wiberg b18b21830a Relocate functions helpers.c -> util.c
The file helpers.c should strictly only be used for misc. helper
functions to the main Finit daemon.  The functions moved in this
commit are generic enough to be used by any deamon or programs,
and for that we have util.c

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:14:00 +02:00
Joachim Wiberg 06daf2e4a5 Relocate helper function, only used by tmpfiles
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:13:59 +02:00
Joachim Wiberg eb13ccc227 plugins: minor, rename local functions
Prevent name clash with upcoming refactor and any confusion with
src/plugin.c functions with the same name.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:13:58 +02:00
Joachim Wiberg 0861373d14 Minor, relocate path definition to finit.h
This is where the other path definitions live.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:13:57 +02:00
Joachim Wiberg 1b9e69414e Refactor state machine control functions
This refactor should have been done years ago when we first introduced
the big state machine.  The old functions service_runvel() and the oddly
named service_reload_dynamic() are actually state machine control fns,
so let relocate them.

Also in this commit, remove the global variable 'sm' and rename a few of
the critical functions to better names.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:13:56 +02:00
Joachim Wiberg 39f4aa3f2c Simplify, a daemon is one of service or sysv
Historically we've kept these two apart, but their commonalities are far
more than what separates them.

This fixes a bug where ready:scripts were not called for sysv daemons,
and also opens up for adding support for a reload:script for both types.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-06 03:13:54 +02:00
Joachim Wiberg dedb56a9d0 Merge branch 'refactor-systemd-readiness'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-04 16:45:37 +02:00
Joachim Wiberg a27903c745 libsystemd: translate leading log <LEVEL> in stderr logging
This commit also switches the stdout/stderr log capture backend for all
notify:systemd services from the sysklogd project's logger tool to the
bundled logit tool.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:47:34 +02:00
Joachim Wiberg f24f76fc80 logit: parse leading <LEVEL> in log messages
Add support for systemd daemon log style.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:43:44 +02:00
Joachim Wiberg d95fc5f790 logit: fix parse_prio(), check result of parse
clang-tidy complained that parse_prio() always returned OK(0), turns out
it was right.  This patch adds validation of the parsing.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:43:43 +02:00
Joachim Wiberg 10a1257e47 logit: minor cleanup, reverse christmas tree
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:43:43 +02:00
Joachim Wiberg a7b8e1b94d libsystemd: expand with with some common sd-daemon(3) functions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:43:42 +02:00
Joachim Wiberg da83462731 libsystemd: new library, refactor sd-daemon.[ch] test code
This commit introduces a bare-bones replacement for libsystemd:

 - Build .so file and add --with-libsystemd to configure
 - Add capabilities support to test/src/serv.c
 - Update tests to account for a Finit built w/o libsystemd support

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:42:06 +02:00
Joachim Wiberg 1396177706 test: expand with command line options for increased usability
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:42:05 +02:00
Joachim Wiberg 7cf0a293fd test: adjust unexpected-restart.sh for proper systemd/s6 notify
A systemd service should only use NOTIFY_SOCKET and an s6 style
service reads its notify descript from the command line.  For
details, see notify.sh

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:59 +02:00
Joachim Wiberg d0d9b83b66 test: update serv daemon to use proper systemd abstract socket
This commit introduces a stripped down sd_notify(), taken from the
systemd man page example, which is used by the serv daemon in lieu
of the previous broken implementation.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:59 +02:00
Joachim Wiberg 76f8a18816 Fix #440: refactor systemd and s6 readiness notifcation
This patch fixes issue #440 which details how systemd readiness
notification has been broken since its inception in Finit.

In addition to now providing a proper abstract socket, the refactor
also drops the reliance on the Finit client API to fetch a socket.
Now an s6 descriptor is the write end of a pipe() and the systemd
socket is instead created before forking off the service.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:58 +02:00
Joachim Wiberg dc497bcd57 service: slight improvement of restart log message
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:58 +02:00
Joachim Wiberg 0da6bbe4a8 service: minor refactor of stdin redirect
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:57 +02:00
Joachim Wiberg 91f7a75bee api: ensure socket is non-blocking
Also, remember to refactor the client socket handling to prevent
blocking PID 1.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:57 +02:00
Joachim Wiberg f217d493b4 test: add --map-auto to unshare call
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 16:36:52 +02:00
Joachim Wiberg 77404a2ea0 Merge pull request #445 from troglobit/space-in-argval
Space in argval

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:50:21 +02:00
Joachim Wiberg d42a1d438b Merge pull request #444 from aanderse/master
service.c/parse_cmdline_args: handle loooooong arguments

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:43:00 +02:00
Joachim Wiberg 1275f05343 devmon: add error checking to callback
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:29:54 +02:00
Joachim Wiberg 61a92aa0b6 devmon: silence unnecessary dbg() in devmon_add_cond()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:29:54 +02:00
Joachim Wiberg b38ff0cc79 service: fix service log priority in fallback mode
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:29:53 +02:00
Joachim Wiberg 168f5bf1d8 log: new function, log_parse()
Converts from syslog priority string format to facility and level.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:29:53 +02:00
Joachim Wiberg ffd00f646c Declare unused parameters
When building with global CFLAGS=-Wunused-parameter the output from the
build looks terrible.  This commit explicitly declares unused variables
to prevent triggering -Wunused-parameter

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:29:52 +02:00
Joachim Wiberg 5e2e273cad conf: check return value of strdup() in parse_env()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:28:41 +02:00
Joachim Wiberg 33f6697cd5 conf: new function conf_parse_env()
Reduce code duplication.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:28:27 +02:00
Joachim Wiberg 6f0ba22a0f util: new function unquote()
Refactor to reduce code duplication

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:28:10 +02:00
Joachim Wiberg ecb690c9ec service: support quoted arguments to run/task/service options
Fixes #441

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-07-02 14:27:39 +02:00
Aaron Andersen 0459bb432a service.c/parse_cmdline_args: handle loooooong arguments 2025-07-01 20:31:59 -04:00
Joachim Wiberg 2760616c73 Merge pull request #443 from liuming50/fix-some-compilation-issues
Fix some compilation issues

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-06-29 12:36:17 +02:00
Ming Liu 62ab990129 cgroup.c: fix some compilation warnings
Fix the following warnings:
| cgroup.c:296:13: warning: implicit declaration of function 'conf_any_change' [-Wimplicit-function-declaration]
| cgroup.c:297:17: warning: implicit declaration of function 'service_reload_dynamic' [-Wimplicit-function-declaration]

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2025-06-27 14:31:18 +02:00
Ming Liu 0c2836d747 Makefile.am: fix tmpfiles linking issues
Fix the following linking issues of tmpfiles:
| exec.c:308: warning: stty is not implemented and will always fail
| plugin.c:237: undefined reference to `run_parts'

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2025-06-27 14:31:02 +02:00
Joachim Wiberg 8be7a462e0 Merge pull request #439 from aanderse/tmpfiles
tmpfiles: refactor into separate executable
2025-06-09 07:56:10 +02:00
Aaron Andersen 5993b4bb5d tmpfiles: refactor code into new is_dir_empty function
The existing implementation seemed useful enough to warrant a new
helper function. Care was taken to ensure the revised code no longer
suffers any memory leaks.
2025-06-05 20:53:25 -04:00
Aaron Andersen 2957246092 tmpfiles: implement remove logic for 'D'
> D
> Similar to d, but in addition the contents of the directory will be removed when --remove is used.
2025-06-02 19:27:24 -04:00
Aaron Andersen a5710125f6 tmpfiles: add --create and --remove flags
Allow execution of tmpfiles to specify which mode(s) of operation to run in.
2025-06-02 19:27:24 -04:00
Aaron Andersen ff95ebeb91 tmpfiles: split up create & remove logic
The tmpfiles.d spec contains entry types that should be acted upon in different modes
of operation: create, clean, remove, and purge - split up create & remove logic to
clarify the modes of operation finit supports.
2025-06-02 19:27:24 -04:00
Aaron Andersen 1921b3f2c5 tmpfiles: refactor into separate executable
The tmpfiles.d spec has proven useful in systemd, enough so that some developers
are starting to ship tmpfiles.d configuration files with their software.
By splitting the tmpfiles functionality in finit out into a separate executable
we are providing a useful piece of software that package managers can hook into.
2025-06-02 19:27:24 -04:00
Joachim Wiberg 051ef81e53 initctl: drop unused function pid_comm()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-30 10:45:01 +02:00
Joachim Wiberg 90993c237a Add hexdump() debug helper function
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-30 10:44:05 +02:00
Joachim Wiberg b0b4f7b2ba initctl: refactor pid_cgroup(), return allocated buffer
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-30 10:42:50 +02:00
Joachim Wiberg 4d79d84fb8 Fix #438: refactor initctl ps/top to handle loooooong command lines
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-30 10:21:24 +02:00
Joachim Wiberg d318aa00c3 Merge branch 'asan'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-05 07:37:26 +02:00
Joachim Wiberg 9684127eb7 initctl: refactor runlevel string composition
Related to issue #437

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-05 07:27:06 +02:00
Joachim Wiberg 8d2cfd69fa initctl: buffer overflow in runlevel string formatting
Fix #437

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-05 07:19:12 +02:00
Joachim Wiberg 4f252858e4 Enable address sanitizer, credits to @chipitsine
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-05 06:55:08 +02:00
Joachim Wiberg 1ccd1d6926 Bump version for 4.13 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-05 06:54:27 +02:00
Joachim Wiberg b87c51209d doc: attempt to clarify service sync a bit
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-04 07:23:07 +02:00
Joachim Wiberg 6b7478ff43 Update ChangeLog and bump version for v4.12 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-28 00:23:10 +02:00
Joachim Wiberg 6c4c16cbdb Update ChangeLog for v4.12
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-28 00:04:39 +02:00
Joachim Wiberg e539dbfe37 Merge pull request #436 from sirocyl/patch-1
README.md: typo
2025-04-27 09:56:17 +02:00
Tyler True 90c6bcd365 README.md: typo
`intictl` -> `initctl`, also linkified it to the command description
2025-04-26 23:45:19 -04:00
Joachim Wiberg c9c268f218 plugins: fix variable overloading warning in urandom plugin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 12:55:01 +02:00
Joachim Wiberg 3feff37ba5 plugins: use byte addressing of rand_pool_info data buffer
Fix out-of-bounds write in urandom plugin.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 12:52:16 +02:00
Joachim Wiberg c67d15e272 runparts: update usage text, missing '-b' flag for batch mode
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-31 14:17:55 +02:00
Joachim Wiberg 8984c655f8 cond_get_agg: minor refactor
- Use stack instead of heap memory
 - constify

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-31 14:16:24 +02:00
Joachim Wiberg 1a7b26bac3 Bump version for 4.12 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-31 07:49:05 +02:00
Joachim Wiberg 1f47718012 Merge pull request #435 from aanderse/master 2025-03-29 13:28:15 +01:00
Aaron Andersen fa13cddc28 improve notify:s6 compatibility 2025-03-29 08:03:43 -04:00
Joachim Wiberg 185a72bd14 Bump version for v4.11 GA release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 19:29:48 +01:00
Joachim Wiberg cd32c623cf plugins: ignore PID file events for svc_t in setup/teardown/cleanup
An svc_t (service/sysv) that is in setup, teardown, or cleanup state
must be ignored by the pidfile plugin for any events regarding PID
files.  E.g., a setup script for a sysv service may create a PID file
to alert the system that a setup process for the service is running.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 19:17:04 +01:00
Joachim Wiberg ac4b9c2f93 Unblock signals for pre/post/ready/cleanup scripts
The service_fork() function blocks all signals for the new process, it
is up to the callee to call sig_unblock() before calling exec().

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 19:10:56 +01:00
Joachim Wiberg 5e9591d0a8 Set correct -rc version
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 10:46:16 +01:00
Joachim Wiberg e3bcf9bf16 Update ChangeLog and bump version for v4.11 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 10:28:39 +01:00
Joachim Wiberg 84fd3196b0 doc: clarify what is required for moving from runlevel S to 2
All run/tasks must complete before Finit moves to runlevel 2.  This
critical piece of information has mysteriously been missing from the
documentation since the start.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 10:23:11 +01:00
Joachim Wiberg 994e51e34f Convert **Note:** et al to GitHub Markdown alerts
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-27 10:23:10 +01:00
Joachim Wiberg 0a7814b391 Merge commit from fork
Improve argument handling when launching login
2025-03-27 07:00:54 +01:00
Joachim Wiberg 73f72b39cf Merge pull request #433 from aanderse/patch-1 2025-03-22 19:27:41 +01:00
Aaron Andersen 02e0aa7383 fixup: links in config.md 2025-03-22 18:06:05 +00:00
Joachim Wiberg 6528628b5c getty: improve argument handling when launching login
Add explicit argument separator before username to ensure correct
parsing of the login command regardless of username format.  This
follows best practices for command execution and prevents unexpected
behavior when processing special characters in usernames.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-18 13:18:10 +01:00
Joachim Wiberg 1480657982 Update ChangeLog, serious issues with stopping services
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-18 07:27:00 +01:00
Joachim Wiberg 33e378a345 Fix #432: allow services in 'setup' to be stopped
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-18 07:21:44 +01:00
Joachim Wiberg b695b46a9d Revert last part of 91a9c83, fallback SIGKILL when stopping services
When a service is stopped, but does not respond to the default SIGTERM,
a fallback kicks in after 3 seconds (default) to send SIGKILL.  Since
91a9c83 (v3.2-rc2) this has however not worked since the signal was
only sent to the process group.

It is the job of service_monitor(), when it reaps the process leader,
to forward the signal to the process group.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-18 07:18:16 +01:00
Joachim Wiberg 0e61ed727f Add helper function, svc_is_stopped() when stopped by user
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-18 07:17:37 +01:00
Joachim Wiberg e9d60a6c04 Minor, coding style
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-18 07:17:23 +01:00
Joachim Wiberg 5e9edf9deb Update ChangeLog and bump version for 4.11 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-17 18:43:04 +01:00
Joachim Wiberg 8ed2751ae1 Fix pre/post/ready/cleanup script execution if env:file is missing
Don't try to source an optional env:file if it is missing.  Otherwise
execution of pre/post/ready/cleanup script will fail.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-17 18:39:05 +01:00
Joachim Wiberg 7fec66dc09 Simplify, svc_checkenv() already checks if optional
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-17 18:38:31 +01:00
Joachim Wiberg 75fa868a4b Fix various typos found by codepsell
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-17 16:46:28 +01:00
Joachim Wiberg 7b321de339 Update ChangeLog and bump version for v4.10 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-03 03:46:21 +01:00
Joachim Wiberg 1691ebb292 logit(): RFC3164 conformance for /dev/kmsg fallback
RFC3164 section 5.3 states; "a colon and a space character usually
follow the TAG".  This is also the reference format in the kernel:
https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-03-03 03:39:55 +01:00
Joachim Wiberg c371c10455 Update ChangeLog and bump version for 4.10-rc2
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-28 12:11:06 +01:00
Joachim Wiberg a23e152f6b plugins: rtc: follow-up to bc8118d, stop timer at shutdown
Introduced to work-around systems with broken RTCs, it also introduced a
dormant bug in Finit, triggered at shutdown on some systems.  The call
to dlclose() removed the memory to the rtc_timer which libuev later then
referenced.

Fixes #429

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-28 11:17:01 +01:00
Joachim Wiberg 9210f2851e Skip killing initctl on shutdown/reboot
Initiating a shutdown/reboot from `initctl` should not cause `initctl`
to be killed in do_shutdown().

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-25 08:37:27 +01:00
Joachim Wiberg 617609cbc5 .github: allow running coverity scan on workflow dispatch
[skip ci]

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 12:35:48 +01:00
Joachim Wiberg b022916758 doc: update svc_t state machine, drop transparent background
The transparent png is completely illegible in dark mode.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 12:34:02 +01:00
Joachim Wiberg 9a357b7aab Fix possible NULL pointer dereference
When a user sets up a TTY without a device, triggering the tty->notty
code path, the tty->dev will be NULL and tty_parse_args() still return
OK result.

Found by Coverity Scan

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 10:30:16 +01:00
Joachim Wiberg ffd01b0276 Update ChangeLog and bump version for v4.10-rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 05:43:14 +01:00
Joachim Wiberg 2c95f091ee Sync documentation and manual page
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 05:35:00 +01:00
Joachim Wiberg b75b107d6d plugins: urandom: improve entropy gathering in fallback path
Enhance fallback entropy generation by mixing in multiple sources:
runtime statistics, PID, and high-resolution timestamps.

This provides better initialization for the PRNG when neither saved
entropy nor hardware RNG are available during early boot.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:51:04 +01:00
Joachim Wiberg 1f2c1d2109 Minor, staticify
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:46:43 +01:00
Joachim Wiberg f328d24d01 Fix possible overflow in return value
Found by Coverity Scan

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:29:56 +01:00
Joachim Wiberg 211293a83d Fix possible overflow in return value
Found by Coverity Scan

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:28:26 +01:00
Joachim Wiberg 446f5bc8b8 Fix possible memory leak in sourcing of environment file
Found by Coverity Scan

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:26:54 +01:00
Joachim Wiberg 0c6f748f2c Fix invalid pointer use in log message
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:23:22 +01:00
Joachim Wiberg a677b94ad9 Minor, coding style fixes
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:05:55 +01:00
Joachim Wiberg 6552cda605 Fix #427: make sure first found binary is used as external getty
When using Finit with an external getty that supports alternative login
program argument, the tty_parse_args() function did not check if a getty
command had already been registered:

    tty [12345] /sbin/agetty -L -l /bin/login console noclear

This caused Finit to try /bin/login as the getty program.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 04:02:00 +01:00
Joachim Wiberg 3add682be3 Wait for post:script and cleanup:script before returning OK
This change introduces two new states for the big Finit state machine:
runlevel-clean and reload-clean.  Here Finit now waits for any post or
cleanup script to finish before returning OK to the initctl command.

Additionally, the service state machine has been updated to ensure a
run/task/sysv/service calls any post or cleanup script before they are
removed.  A new 'dead' state for svc_t is introduced which any removed
svc_t ends up in now instead of becing collected from 'halted' state.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>

Add cleanup:script support, runs at service removal

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 02:36:34 +01:00
Joachim Wiberg abac31682d Handle UEV_ERROR properly in all libuev callbacks
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 02:34:31 +01:00
Joachim Wiberg cfe915e6d5 Reclassify sysv, more like service than run/task
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-23 02:34:30 +01:00
Joachim Wiberg ecf65ce44b Merge pull request #428 from aanderse/path/sysctl 2025-02-21 04:27:14 +01:00
Aaron Andersen 0d742d6ae8 allow sysctl path to be configured at build time 2025-02-19 15:31:09 -05:00
Joachim Wiberg cf201a43df Add cleanup:script support, runs at service removal
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-17 05:16:28 +01:00
Joachim Wiberg 9245869e18 Update ChangeLog and bump version for v4.9 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-15 07:09:58 +01:00
119 changed files with 2665 additions and 1419 deletions
+2 -1
View File
@@ -24,7 +24,8 @@ the maintainer(s) and make it easier for them to include your code.
Coding Style
------------
> **Tip:** Always submit code that follows the style of surrounding code!
> [!TIP]
> Always submit code that follows the style of surrounding code!
First of all, lines are allowed to be longer than 72 characters these
days. In fact, there exist no enforced maximum, but keeping it around
+2 -1
View File
@@ -37,7 +37,8 @@ jobs:
run: |
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
--with-keventd
--with-keventd \
CFLAGS="-fsanitize=address -ggdb"
make -j3 clean
make -j3 V=1
- name: Install to /tmp
+1
View File
@@ -4,6 +4,7 @@ on:
push:
branches:
- 'dev'
workflow_dispatch:
env:
PROJECT_NAME: finit
+101 -41
View File
@@ -4,7 +4,64 @@ Change Log
All relevant changes are documented in this file.
[4.9][UNRELEASED]
[4.12][] - 2025-04-28
---------------------
### Changes
- Improve notify:s6 readiness compatibility, by Aaron Andersen
- Update `runparts` usage text
### Fixes
- Fix variable overloading in urandom plugin
- Fix buffer overwrite in urandom plugin, reported by Aaron Andersen
[4.11][] - 2025-03-27
---------------------
### Changes
- Update documentation regarding transition from runlevel S to 2, how
run/tasks must "complete" before Finit can move to the next runlevel
- Improve argument handling in bundled getty when launching login
### Fixes
- Fix #432: allow services in `setup` state to be stopped. This fixes
a serious blocker introduced in 4.10 that prevented systems from
being rebooted when any service was in this state
- Fix fallback `SIGKILL` when stopping a service with `SIGTERM` does
not work. This fixes a serious issue with services not responding to
the default `SIGTERM`
- Fix pre/post/ready/cleanup script execution if service has an
optional `env:file` (leading `-`)
- Fix blocked signals for pre/post/ready/cleanup scripts preventing
normal shutdown when a service/sysv is stopped in its setup state
- Fix issue where a pre:script creates a PID file in `/run` cause the
service to move from setup state to running. Any `svc_t` in setup,
teardown, or cleanup state should be ignored in the pidfile plugin
[4.10][] - 2025-03-03
---------------------
### Changes
- Add support for `cleanup:[0-3600,]script`, runs before service is
removed, unlike `post:script` that runs when service is stopped
- Improved entropy gathering in tertiary fallback of urandom plugin
- Reclassify `sysv` from run/task class to `service`
### Fixes
- Fix #427: using an external getty with custom login program cause
Finit to use login program as the getty command
- Fix #428: allow `sysctl` path to be set at build time
- Fix #429: regression in v4.9 causing Finit to segfault at shutdown
- Fix possible memory leak when sourcing a service `env:file`
- Finit now waits until all `post:scripts` have run before returning
OK to `initctl <reload|runlevel>`. This also applies to the new
`cleanup:scripts` introduced in this release
- RFC3154 conformance formatting fix for `/dev/kmsg` fallback logging
[4.9][] - 2025-02-15
--------------------
> [!CAUTION]
@@ -29,7 +86,7 @@ All relevant changes are documented in this file.
does not support SIGHUP. This helps avoid unnecessary restarts of
services that depend on a service that supports SIGHUP
- Fix #417: leaking inotify watchers in the cgroup subsystem
- Fix #422: honor `notfail` flag in `/etc/fstab`
- Fix #421: add support for `nofail` mount option in `/etc/fstab`
- Fix #425: ordering bug in detecting .conf file changes to services
and `initctl reload`, or runlevel changes
- Fix `initctl touch` of template services, previously marking a
@@ -68,7 +125,7 @@ All relevant changes are documented in this file.
### Fixes
- Fix #397: system shutdown/reboot can block on console input if action
is started remotely (ssh). Caused by legact TTY screen size probing,
is started remotely (ssh). Caused by legacy TTY screen size probing,
removed from both bootstrap and shutdown/reboot
- Fix #400: both `HOOK_MOUNT_ERROR` and `sulogin()` fail to trigger on
either mount or `fsck` errors. Problem caused by unresolved status
@@ -326,7 +383,7 @@ All relevant changes are documented in this file.
`/etc/finit.conf`.
For the complete experience a new top-level configuration file directive
`rcsd PATH` has aslo been added. It in turn can be used by `factory.conf`
`rcsd PATH` has also been added. It in turn can be used by `factory.conf`
as follows to override `/etc/finit.d`:
rcsd /etc/factory.d
@@ -909,7 +966,7 @@ make sure to read the whole change log when upgrading.
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
various distro packed udevd and other hotplugging tools
* A proper rescue mode has been added. It is started extremely early
and is protected with a bundled `suslogin`. Exiting rescue mode now
and is protected with a bundled `sulogin`. Exiting rescue mode now
brings up the system as a normal boot, as one expects
* Support for `sysv` start/stop scripts as well as monitoring forking
services, stared using `sysv` or `service` stanza
@@ -1740,44 +1797,47 @@ Major bug fix release.
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.8...HEAD
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.11...HEAD
[4.12]: https://github.com/troglobit/finit/compare/4.11...4.12
[4.11]: https://github.com/troglobit/finit/compare/4.10...4.11
[4.10]: https://github.com/troglobit/finit/compare/4.9...4.10
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
[libuEv]: https://github.com/troglobit/libuev
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
+12 -1
View File
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = man plugins src system test tmpfiles.d
SUBDIRS = man plugins src system tmpfiles.d
doc_DATA = README.md LICENSE contrib/finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
@@ -9,6 +9,17 @@ endif
if DOC
SUBDIRS += doc
endif
if LIBSYSTEMD
SUBDIRS += libsystemd
endif
if LIBSYSTEMD
SUBDIRS += test
# Explicit dependency to ensure libsystemd is built before test
test: libsystemd
else
SUBDIRS += test
endif
if BASH
bashdir = $(BASH_DIR)
+21 -16
View File
@@ -61,12 +61,13 @@ distributions:
* [Alpine Linux](contrib/alpine/), and
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
> **Note:** support for various Linux distributions does not mean Finit
> installs easily on all architectures. The bundled install scripts are
> examples for standard installations, tested on amd64 (x86_64) systems.
> Custom setups, e.g., for embedded systems, can be found in any of the
> following [Buildroot][] based examples: [myLinux][], [Infix][], or the
> plain [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
> [!NOTE]
> Support for various Linux distributions does not mean Finit installs
> easily on all architectures. The bundled install scripts are examples
> for standard installations, tested on amd64 (x86_64) systems. Custom
> setups, e.g., for embedded systems, can be found in the following
> [Buildroot][] based examples: [myLinux][], [Infix][], or the plain
> [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
Example
@@ -78,9 +79,10 @@ be placed in `/etc/finit.d/available` and enabled by an operator using
the [initctl](#commands--status) tool. See the above mentioned Linux
distributions, or [myLinux][].
> **Note:** as of Finit v4.4, .conf lines can be broken up using the
> standard UNIX continuation character (`\`), also trailing comments are
> now supported. The latter means you need to escape any hashes used in
> [!TIP]
> As of Finit v4.4, `.conf` lines can be broken up using the standard
> UNIX continuation character (`\`), trailing comments are now also
> supported. The latter means you need to escape any hashes used in
> directives and descriptions (`\#`). For more on this and examples,
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
@@ -249,7 +251,7 @@ All services in runlevel S) are started first, followed by the desired
run-time runlevel. Run tasks in runlevel S can be started in sequence
by using `run [S] cmd`. Changing runlevels at runtime is done like any
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
`intictl` tool.
[`initctl`](#commands--status) tool.
**Conditions**
@@ -285,6 +287,7 @@ run [S] /path/to/ident --
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
```
> [!TIP]
> Notice the trick with an empty description to hide the call to `ident`
> in the Finit progress output.
@@ -367,9 +370,10 @@ The `initctl` tool has three commands to help debug and optimize the
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
commands for details.
> **Note:** systems that do not support cgroups, specifically version 2,
> are automatically detected. On such systems the above functionality
> is disabled early at boot.
> [!NOTE]
> Systems that do not support cgroups, specifically version 2, are
> automatically detected. On such systems the above functionality is
> disabled early at boot.
Runparts & /etc/rc.local
@@ -573,9 +577,10 @@ file must be used to tell Finit to stop and start it on `reload` and
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
these will also affect how a service is maintained.
> **Note:** even though it is possible to start services not belonging in
> the current runlevel these services will not be respawned automatically
> by Finit if they exit (crash). Hence, if the runlevel is 2, the below
> [!NOTE]
> Even though it is possible to start services not belonging in the
> current runlevel these services will not be respawned automatically by
> Finit if they exit (crash). Hence, if the runlevel is 2, the below
> Dropbear SSH service will not be restarted if it is killed or exits.
The `status` command is the default, it displays a quick overview of all
+30 -4
View File
@@ -1,7 +1,33 @@
#!/bin/sh
# Run test suite with the correct configure params
run_make=1
jobs=17
make distclean
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --with-watchdog --with-keventd
make -j17 clean check
while [ $# -gt 0 ]; do
case "$1" in
-n|--no-make)
run_make=0
;;
-j|--jobs)
shift
jobs="$1"
;;
*)
echo "Usage: $0 [--no-make] [-j N]"
exit 1
;;
esac
shift
done
if [ "$run_make" -eq 1 ]; then
make distclean
fi
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --with-watchdog --with-keventd \
CFLAGS='-fsanitize=address -ggdb'
if [ "$run_make" -eq 1 ]; then
make -j"$jobs" clean check
fi
+19 -9
View File
@@ -1,4 +1,4 @@
AC_INIT([Finit], [4.9-rc1], [https://github.com/troglobit/finit/issues],
AC_INIT([Finit], [4.13-pre], [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])
@@ -12,6 +12,7 @@ AC_CONFIG_FILES([Makefile
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
doc/Makefile
libsystemd/Makefile libsystemd/libsystemd.pc
man/Makefile
plugins/Makefile
src/Makefile
@@ -168,6 +169,10 @@ 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(libsystemd,
AS_HELP_STRING([--with-libsystemd], [Build replacement libsystemd library, default: yes]),
[with_libsystemd=$withval], [with_libsystemd=yes])
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])
@@ -308,6 +313,9 @@ AS_IF([test "x$with_watchdog" != "xno"], [
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
watchdog=])
AS_IF([test "x$with_libsystemd" != "xno"], [
AC_DEFINE(HAVE_LIBSYSTEMD, 1, [Build replacement libsystemd library support])])
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
@@ -319,14 +327,15 @@ AS_IF([test "x$with_plugin_path" != "xno"], [
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
# Control build with automake flags
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(LIBSYSTEMD, [test "x$with_libsystemd" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
# Workaround for as-of-yet unreleased runstatedir support, planned for
# autoconf 2.70, which some major distros have backported.
@@ -408,6 +417,7 @@ Optional features:
Built-in sulogin......: $with_sulogin $sulogin
Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate
Replacement libsystemd: $with_libsystemd
Use cgroup v2.........: $enable_cgroup
Parse kernel cmdline..: $enable_kernel_cmdline
Keep kernel logging...: $enable_kernel_logging
+2 -1
View File
@@ -1,7 +1,8 @@
HowTo: Finit on Alpine Linux 3.4...3.19
=======================================
> **Blog** https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
> [!TIP]
> https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
the user has already installed make, a compiler, C library header files,
+5 -3
View File
@@ -20,8 +20,9 @@ tools pre-systemd work as intended.
root@debian:~# apt install initscripts console-setup
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
> the main section of Debian. So just install the -dev packages :)
> [!TIP]
> As of Debian 11 (Bullseye), libuev and libite are part of the main
> section of Debian. So just install the -dev packages :)
The following script can then be used to configure, build, install and
set up your system to run Finit:
@@ -47,7 +48,8 @@ comands to `initctl`, followed by `reload` to activate your changes.
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
and initialization like keyboard language etc.
> **NOTE:** X Window system, you may need to `sudo apt install elogind`
> [!NOTE]
> For the X Window system, you may need to `sudo apt install elogind`
> (Bullseye and later), followed by `initctl reload` to activate it (it
> is enabled by default), and logout/login again. The elogind daemon
> ensures a regular non-root user can start and interact with an X
+30 -24
View File
@@ -1,5 +1,5 @@
Building
========
Building Finit
==============
* [Introduction](#introduction)
* [Configure](#configure)
@@ -17,14 +17,15 @@ optional plugins to enable. It depends on two external libraries:
- [libuEv][], the event loop
- [libite][] (-lite), much needed frog DNA
**NOTE:** Most free/open source software that uses `configure` default
to install to `/usr/local`. However, some Linux distributions do no
longer search that path for installed software, e.g. Fedora and Alpine
Linux. To get finit's configure script to find its dependencies you
have to help the `pkg-config` tool a bit if you do not change the
default prefix path:
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
> [!IMPORTANT]
> Most free/open source software packages that use `configure` default
> to install to `/usr/local`. However, some Linux distributions do no
> longer search that path for installed software, e.g. Fedora and Alpine
> Linux. To get finit's configure script to find its dependencies you
> have to help the `pkg-config` tool a bit if you do not change the
> default prefix path:
>
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
The configure script checks for all dependencies, including the correct
version of the above mentioned libraries. Currently required versions:
@@ -71,12 +72,13 @@ Below are a few of the main switches to configure:
For more configure flags, see <kbd>./configure --help</kbd>
> **Note:** the configure script is not available in the GIT sources. It is
> however included in (officially supported) released tarballs. The
> idea is that you should not need GNU autotools to build, only the
> above mentioned dependencies, a POSIX shell, a C compiler and make.
> Any contributing to Finit can generate it from `configure.ac` using
> the `autogen.sh` script.
> [!NOTE]
> The configure script is not available in the GIT sources. It is
> however included in (officially supported) released tarballs. The
> idea is that you should not need GNU autotools to build, only the
> above mentioned dependencies, a POSIX shell, a C compiler and make.
> Any contributing to Finit can generate it from `configure.ac` using
> the `autogen.sh` script.
Example
@@ -115,10 +117,11 @@ Linux config to:
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
**Note:** If you run into problems starting Finit, take a look at
`finit.c`. One of the most common problems is a custom Linux kernel
build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
system `/etc/fstab`.
> [!TIP]
> If you run into problems starting Finit, take a look at `finit.c`.
> One of the most common problems is a custom Linux kernel build that
> lack `CONFIG_DEVTMPFS`. Another is too much cruft in the system
> `/etc/fstab`.
Running
@@ -157,8 +160,10 @@ 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`.
> [!IMPORTANT]
> In rescue mode `initctl` will not work, the same goes for `reboot`,
> `shutdown`, and `poweroff` commands, provided they are the Finit
> versions of these commands. Use the `-f` flag to force the action.
Debugging
@@ -187,8 +192,9 @@ kernel usually reboots: `configure --enable-emergency-shell`. However,
the behavior of Finit is severely limited when this is enabled, so use
it only for debugging start up issues when Finit crashes.
**NOTE:** Neither of these options should be enabled on production
systems since they can potentially give a user root access.
> [!CAUTION]
> None of these options should be enabled on production systems since
> they can potentially give a user root access.
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
+6 -4
View File
@@ -4,10 +4,11 @@ Tips & Tricks with the kernel cmdline
This document summarizes the different boot parameters that can be
passed on the Linux kernel command line. Not limited to Finit.
The `bool` setting is one of `on, off, true false, 1, 0`.
> [!IMPORTANT]
> Remember to use `--` to separate kernel parameters from parameters to
> init. E.g., `init=/sbin/finit -- finit.debug rescue`
> **NOTE:** remember to use `--` to separate kernel parameters from
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
The `bool` setting is one of `on, off, true false, 1, 0`.
* `debug`: Enable kernel debug. Debug messages are printed to the
console until Finit starts up, unless `loglevel=7` (below) is used.
@@ -30,7 +31,8 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
Very useful for selecting different boot modes, e.g. manufacturing test,
firmware upgrade, or rescue mode.
> Note: `<boot/...>` conditions cannot be cleared with `initctl`!
> [!NOTE]
> `<boot/...>` conditions cannot be cleared with `initctl`!
* `finit.config=/path/to/alternative/finit.conf`: override the
compile-time bootstrap config file, default:
+19 -11
View File
@@ -47,9 +47,10 @@ both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
`pid/` condition is satisfied by the corresponding service's PID file
being created, i.e., the service's default readiness notification.
**NOTE:** Conditions also stop services when a condition is no longer
asserted. I.e., if the Zebra process above stops or restarts, netd
will also stop or restart.
> [!IMPORTANT]
> Conditions also stop services when a condition is no longer asserted.
> I.e., if the `zebra` process above stops or restarts, `netd` will also
> stop or restart.
Another example is `dropbear`, it does not support `SIGHUP`, but we can
also see optional sourcing of arguments from an environment file:
@@ -106,11 +107,16 @@ on this, see [Internals](#internals).) Thus, after a reconfiguration it
is up to the "owner" of the condition to convey the new (or possibly
unchanged) state of it.
> **Note:** For `pid/` conditions it is expected that services "touch"
> or recreate their PID file on `SIGHUP`.
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
> [!IMPORTANT]
> For `pid/` conditions it is expected that the service reassert, i.e.,
> "touch" or recreate, their PID file on `SIGHUP`. This can be done by
> calling `utimensat()` on the PID file. Provided, of course, that the
> service supports reloading on `SIGHUP`, otherwise it will be restarted
> by Finit when they instead exit on the signal. For such services, use
> `<!>` to tell Finit the service does not support `SIGHUP`.
Built-in Conditions
-------------------
@@ -171,9 +177,10 @@ Built-in conditions:
- `boot/arg`
- `dev/node` and `dev/dir/node`
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
difference is that `running` tells if the NIC has link.
> [!NOTE]
> Here, `up` means administratively up, the interface flag `IFF_UP`.
> `running` is the `IFF_RUNNING` flag, meaning operatively up. The
> difference is that `running` tells if the NIC has link.
Composition
@@ -205,8 +212,9 @@ the service stanza for the daemon. It is far from optimal since any
synchronization of depending services may fail due to the daemon not
having reinitialized/created their IPC sockets, or similar.
> **Note:** in versions of Finit prior to v4, the PID conditions were
> called 'svc' conditions, and they were far more complex.
> [!NOTE]
> In versions of Finit prior to v4, the PID conditions were called 'svc'
> conditions, and they were far more complex.
Debugging
+148 -99
View File
@@ -18,8 +18,8 @@ Finit Configuration
* [Alternate rcS.d/](#alternate-rcs-d-)
* [Resource Limits](#resource-limits)
* [Runlevels](#runlevels)
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
* [One-shot Commands (parallel)](#one-shot-commands--parallel-)
* [One-shot Commands (sequence)](#one-shot-commands-sequence)
* [One-shot Commands (parallel)](#one-shot-commands-parallel)
* [SysV Init Scripts](#sysv-init-scripts)
* [Services](#services)
* [Run-parts Scripts](#run-parts-scripts)
@@ -46,8 +46,9 @@ Plugins start at [hook points](plugins.md#hooks) and can run various set
up, or install event handlers that later provide runtime services, e.g.,
PID file monitoring, or [conditions](conditions.md).
> **Tip:** see [SysV Init Compatibility](#sysv-init-compatibility) for
> help to quickly get going with an existing SysV or BusyBox init setup.
> [!TIP]
> See [SysV Init Compatibility](#sysv-init-compatibility) for help to
> quickly get going with an existing SysV or BusyBox init setup.
### Configuration Files
@@ -127,8 +128,9 @@ properties of the `run` statement. For an example on the relation of
`service` and `run` statements, and dependency handling between them,
see [Conditional Loading](#conditional-loading), below.
> **Note:** the `finit.conf` and `finit.d/` names are only defaults.
> They can be changed at compile-time with two `configure` options:
> [!NOTE]
> The names `finit.conf` and `finit.d/` are only defaults. They can be
> changed at compile-time with two `configure` options:
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
>
> They can also be overridden from the [kernel command line](cmdline.md)
@@ -187,8 +189,9 @@ above, provided their respective mount point exists.
With all filesystems mounted, Finit calls `swapon`.
> **Tip:** to see what happens when all filesystems are mounted, have a
> look at the [`bootmisc.so` plugin](plugins.md).
> [!TIP]
> To see what happens when all filesystems are mounted, have a look at
> the [`bootmisc.so` plugin](plugins.md).
At shutdown, and after having stopped all services and other lingering
processes have been killed, filesystems are unmounted in the reverse
@@ -198,6 +201,18 @@ order, and `swapoff` is called.
### Runlevels
Finit supports runlevels, but unlike other init systems runlevels are
declared per service/run/task/sysv command. When booting up a system
Finit pass through three phases:
1. Setting up the console, parsing any command line options, and other
housekeeping tasks like mounting all filesystems, and calling `fsck`
2. Starting all run/task/services in runlevel S, then waiting for all
services to have started, and all run/tasks to have completed
3. Go to runlevel 2, or whatever the user has set in the configuration
Available runlevels:
- ` S`: bootStrap
- ` 1`: Single user mode
- `2-5`: traditional multi-user mode
@@ -205,37 +220,40 @@ order, and `swapoff` is called.
- `7-9`: multi-user mode (extra)
- ` 0`: shutdown
Runlevels are declared per service/run/task/sysv command. Starting in
runlevel S (bootStrap), usually only for tasks supposed to run once at
boot, and services like `syslogd`, which you need to start and run
throughout the whole time your system is up.
Runlevel S (bootStrap), is for tasks supposed to run once at boot, and
services like `syslogd`, which need to start early and run throughout
the lifetime of your system.
Before `S` is started, however, Finit performs a lot of housekeeping
tasks like mounting all filesystems, calling `fsck` if needed, and
making sure the everything is OK.
Example:
task [S] /lib/console-setup/console-setup.sh
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
After runlevel S, Finit proceeds to runlevel 2. This can be changed in
`/etc/finit.conf` using the `runlevel N` directive, or by a script
running in runlevel S that calls, e.g., `initctl runlevel 9`. The
latter is useful if startup scripts detect problems outside of Finit's
control, e.g., critical services/devices missing or hardware problems.
When bootstrap has completed, Finit moves to runlevel 2. This can be
changed in `/etc/finit.conf` using the `runlevel N` directive, or by a
script running in runlevel S that calls, e.g., `initctl runlevel 9`.
The latter is useful if startup scripts detect problems outside of
Finit's control, e.g., critical services/devices missing or hardware
problems.
Before starting the services in runlevel 2, Finit first stops everything
that is not allowed to run in 2, and then brings up networking.
Networking is expected to be available in all runlevels except: S, 1
(single user level), 6, and 0. Networking is enabled either by the
`network script` directive, or if you have an `/etc/network/interfaces`
file, Finit calls `ifup -a` -- at the very least the loopback interface
is brought up.
Each runlevel must be allowed to "complete". Meaning, all services in
runlevel S must have started and all run/tasks have been started and
collected (exited). Finit waits 120 seconds for all run/tasks in S to
complete before proceeding to 2.
> **Note:** when moving from runlevel S to 2, all run/task/services that
> were constrained to runlevel S only are dropped from bookkeeping. So
> when reaching the prompt, `initctl` will not show these run/tasks.
> This is a safety mechanism to prevent bootstrap-only tasks from
> accidentally being run again. E.g., `console-setup.sh` above.
Finit first stops everything that is not allowed to run in 2, and then
brings up networking. Networking is expected to be available in all
runlevels except: S, 1 (single user level), 6, and 0. Networking is
enabled either by the `network script` directive, or if you have an
`/etc/network/interfaces` file, Finit calls `ifup -a` -- at the very
least the loopback interface is brought up.
> [!NOTE]
> When moving from runlevel S to 2, all run/task/services that were
> constrained to runlevel S only are dropped from bookkeeping. So when
> reaching the prompt, `initctl` will not show these run/tasks. This is
> a safety mechanism to prevent bootstrap-only tasks from accidentally
> being run again. E.g., `console-setup.sh` above.
### Managing Services
@@ -322,7 +340,8 @@ the `ps` command we can see that the process is started with:
foo -n --extra-arg=bar -s -x
> **Note:** the leading `-` determines if Finit should treat a missing
> [!NOTE]
> The leading `-` in `env:` determines if Finit should treat a missing
> environment file as blocking the start of the service or not. When
> `-` is used, a missing environment file does *not* block the start.
@@ -374,7 +393,7 @@ like this:
The `notify:none` syntax is for completeness in systems which run in
`readiness pid` mode (default). Services declared with `notify:none`
will assert ready condition as soon as Finit has started them, e.g.,
will transition to ready as soon as Finit has started them, e.g.,
`service/qux/ready`.
To synchronize two services the following condition can be used:
@@ -384,22 +403,23 @@ To synchronize two services the following condition can be used:
For details on the syntax and options, see below.
> **Note:** on `initctl reload` conditions are normally set in "flux",
> while figuring out which to stop, start or restart. Services that
> need to be restarted have their `ready` condition removed prior to
> Finit sending them SIGHUP (if they support that), or stop-starting
> them. A daemon is expected to reassert its readiness, e.g. systemd
> style daemons to write `READY=1\n`.
> [!NOTE]
> On `initctl reload` conditions are set in "flux", while figuring out
> which services to stop, start or restart. Services that need to be
> restarted have their `ready` condition removed before Finit issue a
> SIGHUP (if they support that), or stop-starting them. A daemon is
> expected to reassert its readiness, e.g. systemd style daemons to
> write `READY=1\n`.
>
> However, the s6 notify mode does not support this because in s6 you
> are expected to close your notify descriptor after having written
> `\n`. This means s6 style daemons currently must be stop-started.
> (Declare the service with `<!>` in its condition statement.)
>
> For native PID file style readiness notification a daemon is expected
> to either create its PID file, if it does not exist yet, or touch it
> using `utimensat()` or similar. This triggers both the `<pid/>` and
> `<.../ready>` conditions.
> For default, PID file style readiness notification, daemons are
> expected to either create their PID files, or touch it using
> `utimensat()` to reassert readiness. Triggering both the `<pid/>`
> and `<.../ready>` conditions.
Service Wrapper Scripts
@@ -429,9 +449,10 @@ example employs a wrapper script in `/etc/start.d`.
# Execute the program
exec /usr/bin/program $OPTIONS
> **Note:** the example sets `<!>` to denote that it doesn't support
> `SIGHUP`. That way Finit will stop/start the service
> instead of sending SIGHUP at restart/reload events.
> [!NOTE]
> The example sets `<!>` to denote that it doesn't support `SIGHUP`.
> That way Finit will stop/start the service instead of sending SIGHUP
> at restart/reload events.
Templating
@@ -514,6 +535,7 @@ A daemon using `SCHED_RR` currently need to run outside the default cgroups.
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
> [!NOTE]
> Linux cgroups and details surrounding values are not explained in the
> Finit documentation. The Linux admin-guide cover this well:
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
@@ -539,12 +561,9 @@ service name:sysklogd [S123456789] \
```
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support the
following directives:
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
> and some directives are only available at bootstrap, runlevel `S`,
> see [Limitations](#limitations) below for details.
following directives. Some directives have restrictions, e.g., only
available at bootstrap, runlevel `S`, see [Limitations](#limitations)
below for details.
### Hostname
@@ -556,7 +575,8 @@ the contents of that file is used.
Deprecated. We recommend using `/etc/hostname` instead.
> **Note:** only read and executed in runlevel S (bootstrap).
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
### Kernel Modules
@@ -574,7 +594,8 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
> **Note:** only read and executed in runlevel S (bootstrap).
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
### Networking
@@ -587,7 +608,8 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
> **Note:** only read and executed in runlevel S (bootstrap).
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
### Alternate finit.d/
@@ -608,8 +630,9 @@ another set of .conf files, e.g.:
rcsd /etc/factory.d
> **Note:** this directive is only available from the top-level
> bootstrap .conf file.
> [!NOTE]
> This directive is only available from the top-level bootstrap .conf
> file, usually `/etc/finit.conf`.
### Resource Limits
@@ -642,16 +665,18 @@ stanzas can share the same rlimits if they are in the same .conf.
**Syntax:** `runlevel <N>`
The system runlevel to go to after bootstrap (S) has completed. `N`
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
halt.
The system runlevel to go to after bootstrap (S) has completed. `N` is
the runlevel number 0-9, where 6 is reserved for reboot and 0 for halt.
Completed in this context means all services have been started and all
run/tasks have been started and collected.
It is recommended to keep runlevel 1 as single-user mode, because
Finit disables networking in this mode.
*Default:* 2
> **Note:** only read and executed in runlevel S (bootstrap).
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
### One-shot Commands (sequence)
@@ -665,10 +690,11 @@ optional arguments and description. `run` commands are guaranteed to be
completed before running the next command. Useful when serialization is
required.
> **Warning:** try to avoid the `run` command. It blocks much of the
> functionality in Finit, like (re)starting other (perhaps crashing)
> services while a `run` task is executing. Use other synchronization
> mechanisms instead, like conditions.
> [!WARNING]
> Try to avoid the `run` command. It blocks much of the functionality
> in Finit, like (re)starting other (perhaps crashing) services while a
> `run` task is executing. Use other synchronization mechanisms
> instead, like conditions.
Incomplete list of unsupported `initctl` commands in `run` tasks:
@@ -708,7 +734,7 @@ non-trivial constructs are better placed in a separate shell script.
Similar to `task` is the `sysv` stanza, which can be used to call SysV
style scripts. The primary intention for this command is to be able to
re-use much of existing setup and init scripts in Linux distributions.
reuse much of existing setup and init scripts in Linux distributions.
When entering an allowed runlevel, Finit calls `init-script start`, when
entering a disallowed runlevel, Finit calls `init-script stop`, and if
@@ -723,7 +749,8 @@ file, but rather watch that file for the resulting forked-off PID. This
syntax also works for forking daemons that do not have a command line
option to run it in the foreground, more on this below in `service`.
> **Tip:** see also [SysV Init Compatibility](#sysv-init-compatibility).
> [!TIP]
> See also [SysV Init Compatibility](#sysv-init-compatibility).
### Services
@@ -731,13 +758,13 @@ option to run it in the foreground, more on this below in `service`.
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
Service, or daemon, to be monitored and automatically restarted if it
exits prematurely. Finit tries to restart services that die, by
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.
exits prematurely. Finit tries to restart services that die, by 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 controlling this are configurable, see the options below.
> **Tip:** to allow endless restarts, see below option `respawn`
> [!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
@@ -886,9 +913,20 @@ configurable with the following options:
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.
has *crashed*, if this option is set the system is rebooted
* `oncrash:script` -- similarly, but instead of rebooting, call the
`post:script` action if set, see below.
`post:script` action with exit code `crashed`, see below
* `reload:script [args]` -- some services do not support `SIGHUP` but
may have other ways to update the configuration of a running daemon.
When `reload:script` is defined it is preferred over `SIGHUP`
* `stop:script [args]` -- some services may require alternate methods
to be stopped. When `stop:script` is defined it is preferred over
`SIGTERM` and `stop`, for `service` and `sysv` stanzas, respectively
> [!CAUTION]
> Both `reload:script` and `stop:script` are called as PID 1, without
> any timeout! Meaning, it is up to you to ensure the script is not
> blocking for seconds at a time or never terminates.
When stopping a service (run/task/sysv/service), either manually or when
moving to another runlevel, Finit starts by sending `SIGTERM`, to allow
@@ -899,32 +937,39 @@ e.g., `halt:SIGPWR`. To change the delay between the stop signal and
KILL, use the option `kill:<1-60>`, e.g., `kill:10` to wait 10 seconds
before sending `SIGKILL`.
Services, including the `sysv` variant, support pre/post/ready scripts:
Services, including the `sysv` variant, support pre/post/ready and
cleanup scripts:
* `pre:[0-3600,]script`
* `post:[0-3600,]script`
* `ready:[0-3600,]script`
* `pre:[0-3600,]script` -- called before the sysv/service is stated
* `post:[0-3600,]script` -- called after the sysv/service has stopped
* `ready:[0-3600,]script` -- called when the sysv/service is ready
* `cleanup:[0-3600,]script` -- called when run/task/sysv/service is removed
The optional number (0-3600) is the timeout before Finit kills the
script, it defaults to the kill delay value and can be disabled by
setting it to zero. These scripts run as the same `@USER:GROUP` as the
service itself, with any `env:file` sourced. The scripts must use an
absolute path, but are executed from the `$HOME` of the given user. The
scripts are not called with any argument, but get a set of environment
variables:
service itself, with any `env:file` sourced. The scripts are executed
from the `$HOME` of the given user. The scripts are not called with any
argument, but get a set of environment variables:
* `SERVICE_IDENT=foo:1`
* `SERVICE_NAME=foo`
* `SERVICE_ID=1`
The `post:script` is called with an additional set of environment
variables:
variables. Yes, the text is correct, the naming was an accident:
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
- `EXIT_CODE=[exited,signal,crashed]`: normal exit, signaled, or
crashed
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
the program, if it exited normally, or the signal name (`HUP`,
`TERM`, etc.) if it exited due to signal
When a run/task/sys/service is removed (disable + reload) it is first
stopped and then removed from the runlevel. The `post:script` always
runs when the process has stopped, and the `cleanup:script` runs when
the the stanza has been removed from the runlevel.
> [!IMPORTANT]
> These script actions are intended for setup, cleanup, and readiness
> notification. It is up to the user to ensure the scripts terminate.
@@ -1027,8 +1072,9 @@ before continuing. None of them can issue commands to start, stop, or
restart other services. Also, ensure all your services and programs
either terminate or start in the background or you will block Finit.
> **Note:** `runparts` scrips are only read and executed in runlevel S.
> See [hook scripts](plugins.md#hooks) for other ways to run scripts at
> [!NOTE]
> `runparts` scripts are only read and executed in runlevel S. See
> [hook scripts](plugins.md#hooks) for other ways to run scripts at
> certain points during the complete lifetime of the system.
**Recommendations:**
@@ -1301,8 +1347,9 @@ This rescue mode can be disabled at configure time using:
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`.
> [!NOTE]
> In this mode `initctl` will not work. Use the `-f` flag to force
> `reboot`, `shutdown`, or `poweroff`.
### Traditional
@@ -1314,11 +1361,12 @@ program is used instead. If a successful login is made, or if the user
exits (Ctrl-D), the rescue mode is ended and the system boots up
normally.
> **Note:** the bundled sulogin in Finit can at configure time be given
> another user than the default (root). If the sulogin user does not
> have a password, or __the account is locked__, the user is presented
> with a password-less `"Press enter to enter maintenance mode."`,
> prompt which opens up a root shell.
> [!WARNING]
> The bundled sulogin in Finit can at configure time be given another
> user than the default (root). If the sulogin user does not have a
> password, or __the account is locked__, the user is presented with a
> prompt: `"Press enter to enter maintenance mode."`, which will open
> up a root shell *without prompting for password*!
### Fallback
@@ -1366,10 +1414,11 @@ These can now also be set in any `.conf` file in `/etc/finit.d`.
There is, however, nothing preventing you from having all configuration
settings in `/etc/finit.conf`.
> **Note:** The `/etc/finit.d` directory was previously the default
> Finit [runparts](#run-parts-scripts) directory. Finit >=v4.0
> no longer has a default `runparts` directory, make sure to
> update your setup, or the finit configuration, accordingly.
> [!IMPORTANT]
> The default `rcsd`, i.e., `/etc/finit.d`, was previously the Finit
> [runparts](#run-parts-scripts) directory. Finit >=v4.0 no longer has
> a default `runparts` directory, make sure to update your setup, or the
> finit configuration, accordingly.
Watchdog
+3 -2
View File
@@ -34,8 +34,9 @@ build time:
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
```
> **Note:** remember `--prefix` et al as well, the default is likely
> *not* what you want. See the [build docs][1] for details.
> [!IMPORTANT]
> Remember `--prefix` et al as well, the default is likely *not* what
> you want. See the [build docs][1] for details.
The resulting directory structure is depicted below. Please notice how
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
+21 -16
View File
@@ -35,9 +35,10 @@ For your convenience a set of *optional* plugins are available:
files distributed with Finit. It is read first but can be overridden
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
> **Note:** On an embedded system both `/var` and `/run` can be `tmpfs`
> RAM disks and `/dev` is usually a `devtmpfs`. This must be defined
> in the `/etc/fstab` file and in the Linux kernel config.
> [!NOTE]
> On an embedded system both `/var` and `/run` can be `tmpfs` RAM
> disks and `/dev` is usually a `devtmpfs`. This must be defined in
> the `/etc/fstab` file and in the Linux kernel config.
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._
@@ -63,8 +64,9 @@ For your convenience a set of *optional* plugins are available:
Enabled by default.
> See the [Services](config.md#services) section in the configuration
> guide for an example how to run `mdevd`, alternative to plain mdev.
> [!TIP]
> See the [Services](config.md#services) section in the configuration
> guide for an example how to run `mdevd`, alternative to plain mdev.
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
Enabled by default.
@@ -89,16 +91,17 @@ For your convenience a set of *optional* plugins are available:
set index 1234
**Note:** unlike the traditional .conf `module` directive, which load
any listed module immediately, this plugin creates a background `task`
which load the module(s) in the background. The program is modprobe,
`/sbin/modprobe`, which you can override per .conf file:
Since these tasks run in the background, they return `[ OK ]` at boot,
unless the modprobe tool does not exist. Check syslog for warnings
and the actual status of the operation using `initctl`.
set modprobe /path/to/maybe-a-modprobe-wrapper
Since these tasks run in the background, they usually return `[ OK ]`
at boot, unless the modprobe tool does not exist. Check syslog for
warnings and the actual status of the operation using `initctl`.
> [!IMPORTANT]
> Unlike the traditional .conf `module` directive, which load any listed
> module immediately, this plugin creates a background `task` which load
> the module(s) in the background. The program is modprobe,
> `/sbin/modprobe`, which you can override per .conf file:
>
> set modprobe /path/to/maybe-a-modprobe-wrapper
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
interfaces. These events are then sent to the Finit service monitor
@@ -158,8 +161,10 @@ hook points:
EOF
$ chmod +x /libexec/finit/hook/sys/down/foo.sh
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
> [!IMPORTANT]
> To use hook scripts, even for pre-bootstrap and pre-shutdown tasks,
> you must build with `configure --enable-hook-scripts-plugin`.
### Bootstrap Hooks
+3 -2
View File
@@ -22,8 +22,9 @@ Finit can *not* start and monitor a daemon that:
| ✔ | No | No | Yes, optionally |
| ✘ | Yes | No | No |
> **Note:** PID files is one mechanism used to assert conditions to
> synchronize the start and stop of other, dependent, services.
> [!NOTE]
> PID files is one mechanism used to assert conditions to synchronize
> the start and stop of other, dependent, services.
### Forks to Background w/ PID File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 320 KiB

+2 -2
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 814 KiB

+7
View File
@@ -0,0 +1,7 @@
.deps/*
.libs/*
.dirstamp
*.lo
libsystemd.*
Makefile
Makefile.in
+12
View File
@@ -0,0 +1,12 @@
# libsystemd replacement library
lib_LTLIBRARIES = libsystemd.la
libsystemd_la_SOURCES = sd-daemon.c sd-daemon.h
libsystemd_la_LDFLAGS = -version-info 0:0:0
# pkg-config support
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsystemd.pc
# Install header to systemd/ subdirectory
systemddir = $(includedir)/systemd
systemd_HEADERS = sd-daemon.h
+10
View File
@@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libsystemd
Description: Finit replacement for systemd notification library
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lsystemd
Cflags: -I${includedir}
+217
View File
@@ -0,0 +1,217 @@
/* SPDX-License-Identifier: MIT-0 */
/*
* systemd notify protocol, supporting readiness notification on startup
* and reloading, according to the protocol defined at:
* https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
*
* This protocol is guaranteed to be stable as per:
* https://systemd.io/PORTABILITY_AND_STABILITY/
*/
#define _GNU_SOURCE 1
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#include "sd-daemon.h"
/*
* NOTE: As per spec., this function does not return POSIX OK(0) but
* rather "a positive value", i.e., 1.
*/
int sd_notify(int unset_environment, const char *state)
{
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
};
size_t len, sun_len;
const char *path;
ssize_t written;
int sd;
if (!state)
return -EINVAL;
len = strlen(state);
if (len == 0)
return -EINVAL;
/* If the variable is not set, the protocol is a noop */
path = getenv("NOTIFY_SOCKET");
if (!path)
return 0; /* Not set? Nothing to do */
/* Only AF_UNIX is supported, with path or abstract sockets */
if (path[0] != '/' && path[0] != '@')
return -EAFNOSUPPORT;
/* Ensure there is room for NUL byte */
sun_len = strlen(path);
if (sun_len >= sizeof(sun.sun_path))
return -E2BIG;
strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
if (sun.sun_path[0] == '@')
sun.sun_path[0] = 0;
sd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sd == -1)
return -errno;
if (connect(sd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + sun_len) == -1) {
close(sd);
return -errno;
}
if (unset_environment)
unsetenv("NOTIFY_SOCKET");
written = write(sd, state, len);
if (written != (ssize_t) len) {
close(sd);
return written < 0 ? -errno : -EPROTO;
}
return 1;
}
/*
* Printf-style notification function
*/
int sd_notifyf(int unset_environment, const char *format, ...)
{
va_list ap;
char *state;
int ret;
if (!format)
return -EINVAL;
va_start(ap, format);
ret = vasprintf(&state, format, ap);
va_end(ap);
if (ret < 0)
return -ENOMEM;
ret = sd_notify(unset_environment, state);
free(state);
return ret;
}
/*
* PID-specific notification function
*/
int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
{
char path[256], *env;
size_t len;
int ret;
if (!state)
return -EINVAL;
len = strlen(state);
if (len == 0)
return -EINVAL;
if (pid == 0)
pid = getpid();
env = getenv("NOTIFY_SOCKET");
if (env) {
env = strdup(env);
if (!env)
return -errno;
}
snprintf(path, sizeof(path), "@run/finit/notify/%d", pid);
setenv("NOTIFY_SOCKET", path, 1);
ret = sd_notify(unset_environment, state);
if (env) {
setenv("NOTIFY_SOCKET", env, 1);
free(env);
}
return ret;
}
/*
* PID-specific printf-style notification function
*/
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...)
{
va_list ap;
char *state;
int ret;
if (!format)
return -EINVAL;
va_start(ap, format);
ret = vasprintf(&state, format, ap);
va_end(ap);
if (ret < 0)
return -ENOMEM;
ret = sd_pid_notify(pid, unset_environment, state);
free(state);
return ret;
}
/*
* Socket activation stub - Finit doesn't support socket activation yet
* Returns 0 (no file descriptors passed)
*/
int sd_listen_fds(int unset_environment)
{
if (unset_environment) {
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
unsetenv("LISTEN_FDNAMES");
}
return 0;
}
/*
* Watchdog stub - Finit doesn't support watchdog yet
* Returns 0 (no watchdog enabled)
*/
int sd_watchdog_enabled(int unset_environment, uint64_t *usec)
{
if (unset_environment) {
unsetenv("WATCHDOG_PID");
unsetenv("WATCHDOG_USEC");
}
if (usec)
*usec = 0;
return 0;
}
/*
* System detection function
* Returns 1 to indicate systemd compatibility (trick applications)
*/
int sd_booted(void)
{
return 1;
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef SD_DAEMON_H_
#define SD_DAEMON_H_
#include <stdint.h>
#include <sys/types.h>
#define SD_LISTEN_FDS_START 3
/* systemd logging defines for stderr parsing by Finit */
#define SD_EMERG "<0>" /* system is unusable */
#define SD_ALERT "<1>" /* action must be taken immediately */
#define SD_CRIT "<2>" /* critical conditions */
#define SD_ERR "<3>" /* error conditions */
#define SD_WARNING "<4>" /* warning conditions */
#define SD_NOTICE "<5>" /* normal but significant condition */
#define SD_INFO "<6>" /* informational */
#define SD_DEBUG "<7>" /* debug-level messages */
/* Basic notification function */
int sd_notify(int unset_environment, const char *state);
/* Printf-style notification functions */
int sd_notifyf(int unset_environment, const char *format, ...);
/* PID-specific notification functions */
int sd_pid_notify(pid_t pid, int unset_environment, const char *state);
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...);
/* Socket activation stubs */
int sd_listen_fds(int unset_environment);
/* Watchdog stub */
int sd_watchdog_enabled(int unset_environment, uint64_t *usec);
/* System detection */
int sd_booted(void);
#endif /* SD_DAEMON_H_ */
+39 -25
View File
@@ -175,13 +175,13 @@ task [s] echo "foo" | cat >/tmp/bar
.Ed
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
Similar to
.Cm task
.Cm service
is the
.Cm sysv
stanza, which can be used to call SysV style start/stop scripts. The
primary intention for this command is to be able to re-use much of
existing setup and init scripts in Linux distributions.
.Pp
primary intention for this command is to be able to re-use traditional
SysV init scripts in Linux distributions.
.Pp
When entering an allowed runlevel, Finit calls
.Cm init-script start ,
when entering a disallowed runlevel, Finit calls
@@ -434,30 +434,42 @@ e.g.,
.Cm kill:10
to wait 10 seconds before sending SIGKILL.
.Pp
Services support the
.Cm pre:script
and
.Cm post:script
command actions as well. These run as the same
Services, including the
.Cm sysv
variant, support pre/post/ready and cleanup scripts:
.Bl -tag -width 1n
.It Cm pre:[0-3600,]script
called before the sysv/service is stated
.It Cm post:[0-3600,]script
called after the sysv/service has stopped
.It Cm ready:[0-3600,]script
called when the sysv/service is ready
.It Cm cleanup:[0-3600,]script
called when run/task/sysv/service is removed
.El
.Pp
The optional number (0-3600) is the timeout before Finit kills the
script, it defaults to the kill delay value and can be disabled by
setting it to zero. These scripts run as the same
.Cm @USER:GROUP
as the service itself, with any
.Cm env:file
sourced. The scripts must use an absolute path, but are executed from
the
.Cm $HOME
of the given user. The scripts are not called with any argument
(currently), but both get the
.Cm SERVICE_IDENT=foo
environment variable set. Here
.Cm foo
denotes the identity of the service, which if there are multiple
services named
.Cm foo ,
may be
.Cm foo:1 ,
or any unique identifier specified in the .conf file. The
of the given user. The scripts are not called with any argument, but
both get a set of environment variables:
.Pp
.Bl -tag -width 1n -compact
.It Cm SERVICE_IDENT=foo:1
.It Cm SERVICE_NAME=foo
.It Cm SERVICE_ID=1
.El
.Pp
The
.Cm post:script
is called with an additional set of environment variables:
is called with an additional set of environment variables, and yes the
naming looks like it should be swapped:
.Bl -tag -offset indent -width 1n
.It Cm EXIT_CODE=[exited,signal,crashed]
set to one of
@@ -471,10 +483,12 @@ set to one of exit status code from the program, if it exited normally,
or the signal name (HUP, TERM, etc.) if it exited due to signal
.El
.Pp
The scripts have a default execution time of 3 seconds before they are
SIGKILLed, this can be adjusted using the
.Cm kill:SEC
modifier syntax.
When a run/task/sys/service is removed (disable + reload) it is first
stopped and then removed from the runlevel. The
.Cm post:script
always runs when the process has stopped, and the
.Cm cleanup:script
runs when the the stanza has been removed from the runlevel.
.It Cm runparts Aq DIR
Call
.Xr run-parts 8
+2 -2
View File
@@ -65,12 +65,12 @@ static plugin_t plugin = {
.hook[HOOK_SHUTDOWN] = { .cb = save }
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+3 -4
View File
@@ -38,7 +38,6 @@
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "tmpfiles.h"
#include "util.h"
#include "utmp-api.h"
@@ -163,7 +162,7 @@ static void setup(void *arg)
kernel_links();
/* Create all system tmpfiles.d(5) */
tmpfilesd();
run_interactive(_PATH_TMPFILES " --create", "Creating required directories and files");
/* Set BOOT_TIME UTMP entry */
utmp_set_boot();
@@ -178,12 +177,12 @@ static plugin_t plugin = {
.depends = { "pidfile" },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+2 -2
View File
@@ -166,12 +166,12 @@ static plugin_t plugin = {
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+2 -2
View File
@@ -99,12 +99,12 @@ static plugin_t plugin = {
*/
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+2 -2
View File
@@ -232,12 +232,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", }
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+3 -3
View File
@@ -41,7 +41,7 @@
*
* 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!
* (or no ID), the last one read replaces any preceding one!
*/
#include <unistd.h>
@@ -216,12 +216,12 @@ static plugin_t plugin = {
.hook[HOOK_SVC_PLUGIN] = { .cb = load },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+3 -2
View File
@@ -29,6 +29,7 @@
#include "finit.h"
#include "cond.h"
#include "log.h"
#include "helpers.h"
#include "plugin.h"
#include "service.h"
@@ -414,7 +415,7 @@ static plugin_t plugin = {
},
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
struct sockaddr_nl sa;
int sd;
@@ -447,7 +448,7 @@ PLUGIN_INIT(plugin_init)
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
close(plugin.io.fd);
+19 -2
View File
@@ -80,6 +80,23 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
return;
}
switch (svc->state) {
case SVC_TEARDOWN_STATE:
case SVC_CLEANUP_STATE:
case SVC_SETUP_STATE:
/*
* E.g., a setup script for a container may run in lieu
* of crun, trying to fetch a container image from the
* network. This script may want to advertise its PID
* to the system for clean and swift reboots.
*/
dbg("%s[%d]: ignoring any PID file changes in CLEANUP/TEARDOWN/SETUP",
svc_ident(svc, NULL, 0), svc->pid);
return;
default:
break;
}
/* Service condistion to set/clear */
mkcond(svc, cond, sizeof(cond));
@@ -321,7 +338,7 @@ static plugin_t plugin = {
.depends = { "netlink" }, /* bootmisc depends on us */
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
int fd;
@@ -336,7 +353,7 @@ PLUGIN_INIT(plugin_init)
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_pidfile);
+9 -3
View File
@@ -31,6 +31,12 @@
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "conf.h"
#include "log.h"
#ifndef SYSCTL_PATH
#define SYSCTL_PATH "/sbin/sysctl"
#endif
static void setup(void *arg)
{
@@ -54,7 +60,7 @@ static void setup(void *arg)
for (i = 0; i < gl.gl_pathc; i++) {
char cmd[160];
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
snprintf(cmd, sizeof(cmd), "%s -e -p %s >/dev/null", SYSCTL_PATH, gl.gl_pathv[i]);
run(cmd, "sysctl");
}
globfree(&gl);
@@ -70,12 +76,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+2 -2
View File
@@ -57,12 +57,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+6 -2
View File
@@ -35,6 +35,9 @@
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "private.h"
#include "conf.h"
#include "log.h"
/*
* Kernel RTC driver validates against this date for sanity check. The
@@ -320,7 +323,7 @@ static plugin_t plugin = {
}
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
struct tm tm = { 0 };
@@ -336,8 +339,9 @@ PLUGIN_INIT(plugin_init)
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
uev_timer_stop(&rtc_timer);
plugin_unregister(&plugin);
}
+2 -2
View File
@@ -184,7 +184,7 @@ static plugin_t plugin = {
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
int fd;
@@ -199,7 +199,7 @@ PLUGIN_INIT(plugin_init)
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_sys);
+3 -2
View File
@@ -38,6 +38,7 @@
#include "plugin.h"
#include "service.h"
#include "tty.h"
#include "log.h"
static void tty_watcher(void *arg, int fd, int events);
@@ -108,13 +109,13 @@ static void tty_watcher(void *arg, int fd, int events)
}
}
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
setup();
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
if (plugin.io.fd)
+28 -8
View File
@@ -26,6 +26,7 @@
#include <sys/stat.h>
#include <sys/time.h> /* gettimeofday() */
#include <sys/types.h>
#include <sys/resource.h> /* getrusage() */
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
@@ -37,19 +38,35 @@
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "conf.h"
#include "log.h"
#ifndef RANDOM_BYTES
#define RANDOM_BYTES (32*1024)
#endif
#ifdef RANDOMSEED
/*
* This is the fallback seed function, please make sure you have drivers
* enabling /dev/hwrng instead.
*/
static void fallback(FILE *fp)
{
unsigned long seed;
struct timeval tv;
struct rusage ru;
int iter = 128;
gettimeofday(&tv, NULL);
srandom(tv.tv_sec % 3600);
getrusage(RUSAGE_SELF, &ru);
/* Mix multiple sources of "randomness" */
seed = tv.tv_sec ^ (tv.tv_usec << 16);
seed ^= ru.ru_utime.tv_sec ^ (ru.ru_utime.tv_usec << 16);
seed ^= ru.ru_stime.tv_sec ^ (ru.ru_stime.tv_usec << 16);
seed ^= getpid() << 8;
srandom(seed);
while (iter--) {
uint32_t i, prng = random();
@@ -63,6 +80,7 @@ static void setup(void *arg)
{
#ifdef RANDOMSEED
struct rand_pool_info *rpi;
unsigned char *rpi_buf;
ssize_t len = 0;
struct stat st;
int rc = -1;
@@ -88,13 +106,14 @@ static void setup(void *arg)
hw = fopen(hwrng, "r");
if (hw) {
char buf[512];
size_t len;
size_t num;
len = fread(buf, sizeof(buf[0]), sizeof(buf), hw);
if (len == 0)
num = fread(buf, sizeof(buf[0]), sizeof(buf), hw);
if (num == 0)
fallback(fp);
else
len = fwrite(buf, sizeof(buf[0]), len, fp);
fwrite(buf, sizeof(buf[0]), num, fp);
fclose(hw);
} else {
fallback(fp);
@@ -122,10 +141,11 @@ static void setup(void *arg)
goto fallback;
}
rpi_buf = (unsigned char *)rpi->buf;
do {
ssize_t num;
num = read(fd, &rpi->buf[len], RANDOM_BYTES - len);
num = read(fd, &rpi_buf[len], RANDOM_BYTES - len);
if (num <= 0) {
if (num == -1 && errno == EINTR)
continue;
@@ -188,12 +208,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", }
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+2 -2
View File
@@ -108,7 +108,7 @@ static plugin_t plugin = {
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
int fd;
@@ -123,7 +123,7 @@ PLUGIN_INIT(plugin_init)
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_usr);
+4 -2
View File
@@ -33,6 +33,8 @@
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "conf.h"
#include "log.h"
static void setup(void *arg)
{
@@ -50,12 +52,12 @@ static plugin_t plugin = {
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
};
PLUGIN_INIT(plugin_init)
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
+1
View File
@@ -7,6 +7,7 @@ logit
reboot
runparts
sulogin
tmpfiles
watchdogd
Makefile
Makefile.in
+7 -2
View File
@@ -8,7 +8,8 @@ AM_LDFLAGS = -export-dynamic
endif
sbin_PROGRAMS = finit initctl
pkglibexec_PROGRAMS = getty logit runparts
pkglibexec_PROGRAMS = getty logit runparts tmpfiles
if SULOGIN
pkglibexec_PROGRAMS += sulogin
endif
@@ -43,6 +44,11 @@ sulogin_SOURCES = sulogin.c
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
sulogin_LDADD = -lcrypt
tmpfiles_SOURCES = tmpfiles.c util.c util.h log.h
tmpfiles_CFLAGS = -W -Wall -Wextra -std=gnu99
tmpfiles_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
tmpfiles_LDADD = $(lite_LIBS) $(uev_LIBS)
logit_SOURCES = logit.c logrotate.c
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
logit_CFLAGS += $(lite_CFLAGS)
@@ -66,7 +72,6 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
sig.c sig.h \
sm.c sm.h \
svc.c svc.h \
tmpfiles.c tmpfiles.h \
tty.c tty.h \
util.c util.h \
utmp-api.c utmp-api.h
+31 -23
View File
@@ -47,6 +47,7 @@
#include "private.h"
#include "schedule.h"
#include "service.h"
#include "sm.h"
#include "sig.h"
#include "util.h"
@@ -59,6 +60,8 @@ static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
static int stop(svc_t *svc, void *user_data)
{
(void)user_data;
if (!svc)
return 1;
@@ -72,6 +75,8 @@ static int stop(svc_t *svc, void *user_data)
static int start(svc_t *svc, void *user_data)
{
(void)user_data;
if (!svc)
return 1;
@@ -105,6 +110,8 @@ static int restart(svc_t *svc, void *user_data)
static int reload(svc_t *svc, void *user_data)
{
(void)user_data;
if (!svc)
return 1;
@@ -149,6 +156,8 @@ static int missing(char *job, char *id, void *user_data)
{
char buf[20];
(void)user_data;
if (!job)
job = "";
if (!id)
@@ -228,6 +237,8 @@ struct wq emergency = { .cb = bypass_shutdown };
static void bypass_shutdown(void *unused)
{
(void)unused;
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
do_shutdown(halt);
}
@@ -265,19 +276,19 @@ static int do_reboot(int cmd, int timeout, char *buf, size_t len)
case INIT_CMD_REBOOT:
dbg("reboot");
halt = SHUT_REBOOT;
service_runlevel(6);
sm_runlevel(6);
break;
case INIT_CMD_HALT:
dbg("halt");
halt = SHUT_HALT;
service_runlevel(0);
sm_runlevel(0);
break;
case INIT_CMD_POWEROFF:
dbg("poweroff");
halt = SHUT_OFF;
service_runlevel(0);
sm_runlevel(0);
break;
case INIT_CMD_SUSPEND:
@@ -306,7 +317,7 @@ typedef struct {
} ev_t;
ev_t ev_list[] = {
{ "RELOAD", service_reload_dynamic },
{ "RELOAD", sm_reload },
{ NULL, NULL }
};
@@ -332,6 +343,19 @@ static void api_cb(uev_t *w, void *arg, int events)
int sd, lvl;
svc_t *svc;
(void)arg;
if (UEV_ERROR == events) {
dbg("%s(): api socket %d invalid.", __func__, w->fd);
goto error;
}
/*
* TODO: refactor to use accept4() and a new uev handler for the
* client socket instead of risking blocking PID 1 if the client
* is misbehaving.
*/
// sd = accept4(w->fd, NULL, NULL, SOCK_NONBLOCK);
sd = accept(w->fd, NULL, NULL);
if (sd < 0) {
err(1, "Failed serving API request");
@@ -414,7 +438,7 @@ static void api_cb(uev_t *w, void *arg, int events)
if (runlevel == INIT_LEVEL)
cfglevel = lvl;
else
service_runlevel(lvl);
sm_runlevel(lvl);
break;
default:
@@ -430,7 +454,7 @@ static void api_cb(uev_t *w, void *arg, int events)
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
dbg("reload");
service_reload_dynamic();
sm_reload();
break;
case INIT_CMD_START_SVC:
@@ -548,20 +572,6 @@ static void api_cb(uev_t *w, void *arg, int events)
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
break;
case INIT_CMD_NOTIFY_SOCKET:
svc = svc_find_by_pid(rq.runlevel);
if (!svc) {
errx(1, "Unknown PID, cannot register notify socket");
result = 1;
break;
}
if (uev_io_init(ctx, &svc->notify_watcher, service_notify_cb, svc, sd, UEV_READ)) {
err(1, "Falied initializing %s readiness notifier", svc_ident(svc, NULL, 0));
break;
}
return; /* Don't close sd, used for notify */
default:
dbg("Unsupported cmd: %d", rq.cmd);
break;
@@ -578,8 +588,6 @@ static void api_cb(uev_t *w, void *arg, int events)
leave:
close(sd);
if (UEV_ERROR == events)
goto error;
return;
error:
api_exit();
@@ -598,7 +606,7 @@ int api_init(uev_ctx_t *ctx)
int sd;
dbg("Setting up external API socket ...");
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (-1 == sd) {
err(1, "Failed starting external API socket");
return 1;
+16 -2
View File
@@ -37,6 +37,8 @@
#include "cgroup.h"
#include "finit.h"
#include "iwatch.h"
#include "conf.h"
#include "service.h"
#include "log.h"
#include "util.h"
@@ -86,6 +88,12 @@ static void cgset(const char *path, char *ctrl, char *prop)
}
*val++ = 0;
/* unquote value, if quoted */
if (unquote(&val, NULL)) {
errx(1, "Syntax error, unterminated quote in %s/%s.%s=%s", path, ctrl, prop, val);
return;
}
/* disallow sneaky relative paths */
if (strstr(ctrl, "..") || strstr(prop, "..")) {
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
@@ -259,6 +267,12 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
ssize_t sz;
size_t off;
(void)arg;
if (UEV_ERROR == events) {
dbg("%s(): inotify socket %d invalid.", __func__, w->fd);
return;
}
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
err(1, "invalid inotify event");
@@ -289,7 +303,7 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
#ifdef AUTO_RELOAD
if (conf_any_change())
service_reload_dynamic();
sm_reload();
#endif
}
@@ -471,7 +485,7 @@ void cgroup_init(uev_ctx_t *ctx)
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
if (errno == ENOENT)
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
else if (errno == EPERM) /* Probably inside an unpriviliged container */
else if (errno == EPERM) /* Probably inside an unprivileged container */
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
else
err(1, "Failed mounting cgroup v2");
+64 -45
View File
@@ -58,73 +58,90 @@ int cgroup_avail(void)
return fismnt(FINIT_CGPATH);
}
char *pid_cmdline(int pid, char *buf, size_t len)
static size_t flen(FILE *fp)
{
size_t i, sz;
char *ptr;
size_t total = 0, sz;
char buf[512];
while ((sz = fread(buf, 1, sizeof(buf), fp)) > 0)
total += sz;
rewind(fp);
return total;
}
char *pid_cmdline(int pid)
{
size_t i, len;
char *buf;
FILE *fp;
fp = fopenf("r", "/proc/%d/cmdline", pid);
if (!fp) {
buf[0] = 0;
return buf;
}
if (!fp)
return strdup(""); /* regular process */
sz = fread(buf, sizeof(buf[0]), len - 1, fp);
fclose(fp);
if (!sz)
len = flen(fp);
if (len == 0) {
fail:
fclose(fp);
return NULL; /* kernel thread */
buf[sz] = 0;
ptr = strchr(buf, 0);
if (ptr && ptr != buf) {
ptr++;
sz -= ptr - buf;
memmove(buf, ptr, sz + 1);
}
for (i = 0; i < sz; i++) {
if (buf[i] == 0)
buf = calloc(len + 1, 1);
if (!buf)
goto fail;
if (fread(buf, 1, len, fp) < len) {
free(buf);
goto fail;
}
/* replace all NUL chars with space */
for (i = 0; i < len; i++) {
if (buf[i] == '\0')
buf[i] = ' ';
}
return buf;
}
char *pid_comm(int pid, char *buf, size_t len)
char *pid_cgroup(int pid)
{
char *ptr = NULL;
FILE *fp;
fp = fopenf("r", "/proc/%d/comm", pid);
if (!fp)
return NULL;
if (fgets(buf, len, fp))
ptr = chomp(buf);
fclose(fp);
return ptr;
}
char *pid_cgroup(int pid, char *buf, size_t len)
{
char *ptr = NULL;
char *buf, *ptr = NULL;
size_t len;
FILE *fp;
fp = fopenf("r", "/proc/%d/cgroup", pid);
if (!fp)
return NULL;
len = flen(fp);
if (len == 0) {
fclose(fp);
return NULL;
}
len++;
buf = calloc(1, len);
if (!buf) {
fclose(fp);
return NULL;
}
if (fgets(buf, len, fp))
ptr = chomp(buf);
fclose(fp);
if (ptr)
ptr = strchr(buf, '/');
if (ptr) {
ptr = strchr(ptr, '/');
if (ptr) {
memmove(buf, ptr, strlen(ptr) + 1);
return buf;
}
}
return ptr;
free(buf);
return NULL;
}
static char *cgroup_val(char *path, char *file, char *buf, size_t len)
@@ -423,7 +440,7 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
i = 0;
while (fgets(buf, sizeof(buf), fp)) {
char comm[80] = { 0 };
char *cmdline;
pid_t pid;
pid = atoi(chomp(buf));
@@ -431,8 +448,8 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
continue;
/* skip kernel threads for now (no cmdline) */
pid_comm(pid, comm, sizeof(comm));
if (pid_cmdline(pid, buf, sizeof(buf))) {
cmdline = pid_cmdline(pid);
if (cmdline) {
char proc[ttcols];
switch (mode) {
@@ -450,7 +467,7 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
strlcat(row, pfx, rplen);
strlcat(row, ++i == num ? END : FORK, rlen);
snprintf(proc, sizeof(proc), " %d %s %s", pid, comm, buf);
snprintf(proc, sizeof(proc), " %d %s", pid, cmdline);
if (plain) {
strlcat(row, proc, rplen);
@@ -468,6 +485,8 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
}
puts(row);
free(cmdline);
}
if (mode == 1) {
+2 -3
View File
@@ -54,9 +54,8 @@ struct cg {
int cgroup_avail(void);
char *pid_cmdline (int pid, char *buf, size_t len);
char *pid_comm (int pid, char *buf, size_t len);
char *pid_cgroup (int pid, char *buf, size_t len);
char *pid_cmdline (int pid);
char *pid_cgroup (int pid);
uint64_t cgroup_memory(char *group);
-10
View File
@@ -97,16 +97,6 @@ int client_request(struct init_request *rq, ssize_t len)
return -1;
}
/*
* Exception, only command that don't need to wait for a
* response from Finit. Registers the client socket as a
* readiness notification socket with Finit
*/
if (rq->cmd == INIT_CMD_NOTIFY_SOCKET) {
rq->cmd = INIT_CMD_ACK;
return 0;
}
pfd.fd = sd;
pfd.events = POLLIN | POLLERR | POLLHUP;
if ((rc = poll(&pfd, 1, REQUEST_TIMEOUT)) <= 0) {
+7 -2
View File
@@ -113,7 +113,7 @@ static void cond_boot_strap(void)
*
* => 'pid/' + 'teamd' + '' = condition <pid/teamd>
*
* When you add a second aggrate you need to tell Finit it's a different
* When you add a second aggregate you need to tell Finit it's a different
* instance usugin the :ID syntax:
*
* service :lag2 teamd -f /etc/teamd/lag2.conf -- Aggregate lag2
@@ -202,6 +202,9 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
{
const char *cond, *ptr;
(void)sb;
(void)tflag;
if (ftw->level == 0)
return 1;
@@ -215,7 +218,7 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
err(1, "Failed removing condition %s", fpath);
cond = ptr + strlen(COND_BASE) + 1;
if (sm_is_in_teardown(&sm))
if (sm_in_reload())
cond_clear_noupdate(cond);
else
cond_update(cond);
@@ -390,6 +393,8 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
{
char *nm;
(void)sb;
if (ftw->level == 0)
return 1;
+7 -7
View File
@@ -96,16 +96,16 @@ enum cond_state cond_get(const char *name)
enum cond_state cond_get_agg(const char *names)
{
static char conds[MAX_COND_LEN];
enum cond_state s = COND_ON;
char *cond;
if (!names)
return COND_ON;
if (names) {
char conds[strlen(names) + 1];
const char *cond;
strlcpy(conds, names, sizeof(conds));
for (cond = strtok(conds, ","); s && cond; cond = strtok(NULL, ","))
s = min(s, cond_get(cond));
strlcpy(conds, names, sizeof(conds));
for (cond = strtok(conds, ","); s && cond; cond = strtok(NULL, ","))
s = min(s, cond_get(cond));
}
return s;
}
+72 -25
View File
@@ -50,6 +50,25 @@
#define BOOTSTRAP (runlevel == INIT_LEVEL)
int runlevel = INIT_LEVEL; /* 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 bootstrapping (for TTYs) */
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
int syncsec = 0; /* reboot delay */
int readiness = SVC_NOTIFY_PID;
char *finit_conf= NULL;
char *finit_rcsd= NULL;
char *fstab = NULL;
char *sdown = NULL;
char *network = NULL;
char *hostname = NULL;
char *osheading = NULL;
int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5;
@@ -490,14 +509,16 @@ void conf_save_service(int type, char *cfg, char *file)
fclose(fp);
}
/*
* 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.
/**
* conf_parse_env - Parse a key=value line
* @line: Line buffer without newline
* @value: Whitespace trimmed value
*
* Returns:
* %NULL on error, otherwise a whitespace trimmed key.
*/
static void parse_env(char *line)
char *conf_parse_env(char *line, char **value)
{
struct env_entry *node;
char *key, *val, *end;
/* skip any leading whitespace */
@@ -519,7 +540,7 @@ static void parse_env(char *line)
val = strchr(key, '=');
if (!val)
return;
return NULL;
*val++ = 0;
/* strip leading whitespace from value */
@@ -527,14 +548,8 @@ static void parse_env(char *line)
val++;
/* unquote value, if quoted */
if (val[0] == '"' || val[0] == '\'') {
char q = val[0];
if (*end == q) {
val = &val[1];
*end = 0;
}
}
unquote(&val, end);
*value = val;
/* find end of key */
end = key;
@@ -561,18 +576,42 @@ static void parse_env(char *line)
end++;
if (*end != 0) {
warnx("'%s=%s': not a valid identifier", key, val);
return; /* invalid key */
return NULL; /* invalid key */
}
return key;
}
/*
* 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;
key = conf_parse_env(line, &val);
if (!key)
return;
dbg("Global env '%s'='%s'", key, val);
setenv(key, val, 1);
node = malloc(sizeof(*node));
if (!node) {
nomem:
err(1, "Out of memory cannot track env vars");
return;
}
node->name = strdup(key);
if (!node->name) {
free(node);
goto nomem;
}
TAILQ_INSERT_HEAD(&env_list, node, link);
}
@@ -1542,6 +1581,13 @@ static int conf_iwatch_read(int fd)
static void conf_cb(uev_t *w, void *arg, int events)
{
(void)arg;
if (UEV_ERROR == events) {
dbg("%s(): iwatch socket %d invalid.", __func__, w->fd);
return;
}
if (conf_iwatch_read(w->fd)) {
err(1, "invalid inotify event");
return;
@@ -1550,7 +1596,7 @@ static void conf_cb(uev_t *w, void *arg, int events)
#ifdef AUTO_RELOAD
if (conf_any_change())
service_reload_dynamic();
sm_reload();
#endif
}
@@ -1574,25 +1620,26 @@ int conf_monitor(void)
* have or not have symlinks in place. We need to monitor for
* changes to either symlink or target.
*/
rc += iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
rc |= iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
snprintf(path, sizeof(path), "%s/available/", finit_rcsd);
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
rc |= iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
snprintf(path, sizeof(path), "%s/enabled/", finit_rcsd);
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
rc += iwatch_add(&iw_conf, finit_conf, 0);
rc |= iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
rc |= iwatch_add(&iw_conf, finit_conf, 0);
/*
* Systems with /etc/default, /etc/conf.d, or similar, can also
* monitor changes in env files sourced by .conf files (above)
* define your own with --with-sysconfig=/path/to/envfiles
*/
rc += iwatch_add(&iw_conf, "/etc/default/", IN_ONLYDIR);
rc += iwatch_add(&iw_conf, "/etc/conf.d/", IN_ONLYDIR);
rc |= iwatch_add(&iw_conf, "/etc/default/", IN_ONLYDIR);
rc |= iwatch_add(&iw_conf, "/etc/conf.d/", IN_ONLYDIR);
#ifdef FINIT_SYSCONFIG
rc += iwatch_add(&iw_conf, FINIT_SYSCONFIG, IN_ONLYDIR);
rc |= iwatch_add(&iw_conf, FINIT_SYSCONFIG, IN_ONLYDIR);
#endif
rc |= conf_reload();
return rc + conf_reload();
return rc;
}
/*
+19
View File
@@ -27,6 +27,24 @@
#include "cgroup.h"
#include "svc.h"
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 int syncsec;
extern int readiness;
extern char *fstab;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *runparts;
extern char *osheading;
extern int logfile_size_max;
extern int logfile_count_max;
@@ -47,6 +65,7 @@ void conf_saverc (void);
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
void conf_save_service (int type, char *cfg, char *file);
void conf_parse_cmdline (int argc, char *argv[]);
char *conf_parse_env (char *line, char **val);
int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond);
+10 -1
View File
@@ -77,7 +77,7 @@ void devmon_add_cond(const char *cond)
struct dev_node *node;
if (!cond || strncmp(cond, "dev/", 4)) {
dbg("no match");
// dbg("no match %s", cond ?: "<NIL>");
return;
}
@@ -164,6 +164,8 @@ static void devmon_scandir(struct iwatch *iw, char *dir, int len)
size_t i;
int rc;
(void)iw;
snprintf(path, sizeof(path), "%s/*", dir);
rc = glob(path, GLOB_NOSORT, NULL, &gl);
if (rc && rc != GLOB_NOMATCH)
@@ -207,6 +209,13 @@ static void devmon_cb(uev_t *w, void *arg, int events)
ssize_t sz;
size_t off;
(void)arg;
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in devmon watcher");
return;
}
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
err(1, "invalid inotify event");
+3 -3
View File
@@ -199,7 +199,6 @@ int run(char *cmd, char *log)
int run_interactive(char *cmd, char *fmt, ...)
{
int status, oldout = 1, olderr = 2;
char line[LINE_SIZE];
FILE *fp;
if (!cmd) {
@@ -244,6 +243,7 @@ int run_interactive(char *cmd, char *fmt, ...)
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
if (fp && !debug) {
char line[LINE_SIZE];
size_t len, written;
rewind(fp);
@@ -281,7 +281,7 @@ int exec_runtask(char *cmd, char *args[])
return execvp(_PATH_BSHELL, argv);
}
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
static void prepare_tty(char *tty, speed_t speed, const char *procname, struct rlimit rlimit[])
{
char name[80];
int fd, dummy;
@@ -351,7 +351,7 @@ static int activate_console(int noclear, int nowait)
dprint(STDERR_FILENO, clr, strlen(clr));
dprint(STDERR_FILENO, msg, strlen(msg));
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
continue;
;
/* On any error (likely EINTR), we avoid starting getty */
if (rc == -1)
+3 -22
View File
@@ -59,25 +59,6 @@
#include "util.h"
#include "utmp-api.h"
int runlevel = INIT_LEVEL; /* 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 */
int syncsec = 0; /* reboot delay */
int readiness = SVC_NOTIFY_PID;
char *finit_conf= NULL;
char *finit_rcsd= NULL;
char *fstab = NULL;
char *sdown = NULL;
char *network = NULL;
char *hostname = NULL;
char *osheading = NULL;
uev_ctx_t *ctx = NULL; /* Main loop context */
svc_t *wdog = NULL; /* No watchdog by default */
@@ -280,7 +261,7 @@ static int fsck(int pass)
sulogin(1);
}
}
rc += fsck_rc;
rc |= fsck_rc;
}
endmntent(fp);
@@ -745,8 +726,8 @@ int main(int argc, char *argv[])
* Initialize state machine and start all bootstrap tasks
* NOTE: no network available!
*/
sm_init(&sm);
sm_step(&sm);
sm_init();
sm_step();
/*
* Enter main loop to monitor /dev/initctl and services
+6 -20
View File
@@ -54,11 +54,17 @@
#define FINIT_CGPATH "/sys/fs/cgroup"
#endif
/* Prevent users from logging in at critical stages */
#ifndef FINIT_NOLOGIN_PATH
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN
#endif
/* To use these, include config.h, or define FINIT_EXECPATH_ */
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
#define _PATH_TMPFILES FINIT_EXECPATH_ "/tmpfiles"
#define CMD_SIZE 1024
#define LINE_SIZE 1024
@@ -98,7 +104,6 @@
#define INIT_CMD_SVC_FIND 131
#define INIT_CMD_SVC_FIND_BYC 132
#define INIT_CMD_SIGNAL 133
#define INIT_CMD_NOTIFY_SOCKET 200 /* For readiness notification socket */
#define INIT_CMD_NACK 254
#define INIT_CMD_ACK 255
@@ -111,25 +116,6 @@ struct init_request {
char data[368];
};
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 int syncsec;
extern int readiness;
extern char *fstab;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *runparts;
extern char *osheading;
extern uev_ctx_t *ctx;
#endif /* FINIT_H_ */
/**
+2 -2
View File
@@ -312,9 +312,9 @@ static int exec_login(char *name)
struct stat st;
if (passenv)
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", name, NULL);
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", "--", name, NULL);
else
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
execl(_PATH_LOGIN, _PATH_LOGIN, "--", name, NULL);
/*
* Failed to exec login, should not happen on normal systems.
+4 -95
View File
@@ -26,8 +26,6 @@
#include <ctype.h> /* isblank() */
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <limits.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -42,6 +40,7 @@
#include "finit.h"
#include "helpers.h"
#include "conf.h"
#include "log.h"
#include "private.h"
#include "sig.h"
@@ -87,7 +86,7 @@ void console_init(void)
/* Enable line wrap, if disabled previously, e.g., qemu */
dprint(STDOUT_FILENO, "\033[?7h", 5);
/* Reset atttributes, background and foreground color */
/* Reset attributes, background and foreground color */
dprint(STDOUT_FILENO, "\033[49m\033[39m\e[2J", 14);
log_init();
@@ -293,6 +292,8 @@ static size_t print_timestamp(char *buf, size_t len)
sscanf(buf, "%f %f", &stamp, &dummy);
return snprintf(buf, len, "[ %.6f ]", stamp);
#else
(void)buf;
(void)len;
return 0;
#endif
}
@@ -370,98 +371,6 @@ int print_result(int fail)
return fail;
}
int getuser(char *username, char **home)
{
#ifdef ENABLE_STATIC
if (home)
*home = "/"; /* XXX: Fixme */
return fgetint("/etc/passwd", "x:\n", username);
#else
struct passwd *usr;
if (!username || (usr = getpwnam(username)) == NULL)
return -1;
if (home)
*home = usr->pw_dir;
return usr->pw_uid;
#endif
}
int getgroup(char *group)
{
#ifdef ENABLE_STATIC
return fgetint("/etc/group", "x:\n", group);
#else
struct group *grp;
if ((grp = getgrnam(group)) == NULL)
return -1;
return grp->gr_gid;
#endif
}
/* get current user */
int getcuser(char *buf, size_t len)
{
char *ptr = "root";
#ifndef ENABLE_STATIC
struct passwd *pw = getpwuid(getuid());
if (pw)
ptr = pw->pw_name;
#endif
if (strlcpy(buf, ptr, len) > len)
return -1;
return 0;
}
/* get current group */
int getcgroup(char *buf, size_t len)
{
char *ptr = "root";
#ifndef ENABLE_STATIC
struct group *gr = getgrgid(getgid());
if (gr)
ptr = gr->gr_name;
#endif
if (strlcpy(buf, ptr, len) > len)
return -1;
return 0;
}
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
{
mode_t omask;
int uid, gid;
int rc = 0;
omask = umask(0);
uid = getuser(user, NULL);
if (uid >= 0) {
gid = getgroup(group);
if (gid < 0)
gid = 0;
rc = makedir(dir, mode);
if (rc && errno == EEXIST)
rc = chmod(dir, mode);
if (chown(dir, uid, gid))
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
}
umask(omask);
return rc;
}
void set_hostname(char **hostname)
{
FILE *fp;
+2 -61
View File
@@ -39,7 +39,6 @@
#else
# include <lite/lite.h>
#endif
#include "log.h"
#define PROGRESS_DEFAULT PROGRESS_MODERN
@@ -70,14 +69,6 @@ void print (int action, const char *fmt, ...) __attribute__ ((forma
void print_desc (char *action, char *desc);
int print_result (int fail);
int getuser (char *username, char **home);
int getgroup (char *group);
int getcuser (char *buf, size_t len);
int getcgroup (char *buf, size_t len);
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
void set_hostname (char **hostname);
void networking (int updown);
int in_container (void);
@@ -91,56 +82,6 @@ pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimi
pid_t run_bg (char *cmd, char *args[]);
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
/*
* Defaults to user "root" and group "wheel" (root) if:
* 1) the user is missing
* 2) the group or the file /etc/group is missing
*/
static inline int create(char *path, mode_t mode, char *user, char *group)
{
int fd, uid, gid;
if (!path) {
errno = EINVAL;
return -1;
}
uid = getuser(user, NULL);
if (uid < 0)
uid = 0;
gid = getgroup(group);
if (gid < 0)
gid = 0;
fd = creat(path, mode);
if (fd == -1) {
warn("Failed creating %s properly", path);
return -1;
}
close(fd);
if (chown(path, uid, gid)) {
warn("Failed chowning %s properly", path);
return -1;
}
return 0;
}
static inline int ln(const char *target, const char *linkpath)
{
if (!target || !linkpath) {
errno = EINVAL;
return -1;
}
if (symlink(target, linkpath)) {
if (errno != EEXIST)
warn("Failed creating %s -> %s symlink", target, linkpath);
return -1;
}
return 0;
}
static inline int dprint(int fd, const char *s, size_t len)
{
size_t loop = 3;
@@ -159,7 +100,7 @@ static inline int dprint(int fd, const char *s, size_t len)
return rc;
}
static inline char *fgetval(char *line, const char *key, char *sep)
static inline char *fgetval(const char *line, const char *key, char *sep)
{
char *ptr, *str, *copy;
size_t len;
@@ -179,7 +120,7 @@ static inline char *fgetval(char *line, const char *key, char *sep)
* Check if we should strip optional separator, e.g.,
* 'foo = bar' => '= bar' should be stripped to 'bar'
*/
while (str && strchr(sep, str[0])) {
while (strchr(sep, str[0])) {
ptr = strsep(&str, sep);
if (!ptr)
goto fail;
+18 -19
View File
@@ -767,27 +767,25 @@ static int plugins_list(char *arg)
*/
char *runlevel_string(int currlevel, int levels)
{
static char lvl[21];
static char lvl[32];
int i = INIT_LEVEL;
int pos = 1;
memset(lvl, 0, sizeof(lvl));
lvl[0] = '[';
strlcpy(lvl, "[", sizeof(lvl));
do {
if (ISSET(levels, i)) {
if (!plain && currlevel == i)
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
if (i == INIT_LEVEL)
lvl[pos++] = 'S';
else
lvl[pos++] = '0' + i;
char l[2] = { '0' + i, 0 };
if (!plain && currlevel == i)
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
strlcat(lvl, "\e[1m", sizeof(lvl));
strlcat(lvl, i == INIT_LEVEL ? "S" : l, sizeof(lvl));
if (!plain && currlevel == i)
strlcat(lvl, "\e[0m", sizeof(lvl));
} else {
lvl[pos++] = '-';
strlcat(lvl, "-", sizeof(lvl));
}
/* XXX: ugly hack to get order right: S0123456789 */
@@ -798,8 +796,7 @@ char *runlevel_string(int currlevel, int levels)
} while (i < INIT_LEVEL);
lvl[pos++] = ']';
lvl[pos] = 0;
strlcat(lvl, "]", sizeof(lvl));
return lvl;
}
@@ -872,7 +869,7 @@ static char *svc_environ(svc_t *svc, char *buf, size_t len, int ansi)
{
int bold = missing(svc);
if (!ansi || svc_checkenv(svc) || svc->env[0] == '-')
if (!ansi || svc_checkenv(svc))
bold = 0;
strlcpy(buf, bold ? "\e[1m" : "", len);
@@ -1138,14 +1135,14 @@ static int show_status(char *arg)
printf(" Restarts : %d (%d/%d)\n", svc->restart_tot, svc->restart_cnt, svc->restart_max);
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
if (cgrp && svc->pid > 1) {
char grbuf[128];
const struct cg *cg;
char path[256];
struct cg *cg;
char *group;
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
group = pid_cgroup(svc->pid);
if (!group)
goto no_cgroup; /* ... or PID doesn't exist (anymore) */
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
cg = cg_conf(path);
@@ -1154,6 +1151,8 @@ static int show_status(char *arg)
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
cg->cg_mem.min, cg->cg_mem.max);
show_cgroup_tree(group, " ");
free(group);
}
no_cgroup:
printf("\n");
+71 -1
View File
@@ -32,6 +32,9 @@
# include <lite/lite.h>
#endif
#define SYSLOG_NAMES
#include <syslog.h>
#include "finit.h"
#include "helpers.h"
#include "log.h"
@@ -106,6 +109,73 @@ static const char *l2s(int prio)
return "UNK";
}
static int s2f(const char *str)
{
for (int i = 0; facilitynames[i].c_name; i++) {
if (string_match(facilitynames[i].c_name, str))
return facilitynames[i].c_val;
}
return -1;
}
static int s2l(const char *str)
{
for (int i = 0; prioritynames[i].c_name; i++) {
if (string_match(prioritynames[i].c_name, str))
return prioritynames[i].c_val;
}
return -1;
}
/*
* Parse syslog facility.priority strings into their numerical values
* using arrays defined in <syslog.h>. Note, the 'prio' argument may
* be one of:
*
* - facility.level
* - facility
* - level
*
* It is up to the callee to assign defaults to 'facility' and 'level'
* before calling this function. If There is any match the respective
* facility or level will be assigned and this function returns OK.
*/
int log_parse(char *prio, int *facility, int *level)
{
char *fac = prio, *lvl;
int f = -1;
int l = -1;
if (!prio || !facility || !level)
return -1;
lvl = strchr(prio, '.');
if (lvl) {
*lvl = 0;
lvl++;
}
if (lvl && *lvl)
l = s2l(lvl);
f = s2f(fac);
if (l < 0)
l = s2l(fac);
if (l < 0 && f <= 0)
return -1;
if (l <= LOG_DEBUG)
*level = l;
if (f <= LOG_LOCAL7)
*facility = f;
return 0;
}
/*
* Log to /dev/kmsg until syslogd has started, then openlog()
* and continue logging as a regular daemon.
@@ -139,7 +209,7 @@ void logit(int prio, const char *fmt, ...)
goto done;
}
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
fprintf(fp, "<%d>finit[1]: ", LOG_DAEMON | prio);
vfprintf(fp, fmt, ap);
fclose(fp);
+1
View File
@@ -78,6 +78,7 @@ void log_init (void);
void log_exit (void);
void log_debug(void);
int log_parse(char *prio, int *facility, int *level);
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+66 -13
View File
@@ -36,6 +36,9 @@
# include <lite/lite.h>
#endif
#define LOG_MAX (200 * 1024)
#define LOG_NUM 5
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
extern int logrotate(char *file, int num, off_t sz);
@@ -87,23 +90,61 @@ reopen:
return fclose(fp);
}
static int logit(int level, char *buf, size_t len)
/*
* Parse possible systemd style log <level> prefix from message
* For details, see libsystemd/sd-daemon.h
*
* Returns the level, and updates buf to point past the prefix
*/
static int parse_level(char **buf, int default_level)
{
if (buf[0]) {
syslog(level, "%s", buf);
return 0;
char *msg = *buf;
if (msg[0] == '<' && msg[2] == '>' && msg[1] >= '0' && msg[1] <= '7') {
int level;
switch (msg[1]) {
case '0': level = LOG_EMERG; break;
case '1': level = LOG_ALERT; break;
case '2': level = LOG_CRIT; break;
case '3': level = LOG_ERR; break;
case '4': level = LOG_WARNING; break;
case '5': level = LOG_NOTICE; break;
case '6': level = LOG_INFO; break;
case '7': level = LOG_DEBUG; break;
default: level = default_level; break;
}
*buf = msg + 3;
return (default_level & ~LOG_PRIMASK) | level;
}
return default_level;
}
static int do_log(int level, char *msg)
{
syslog(parse_level(&msg, level), "%s", msg);
return 0;
}
static int logit(int level, char *buf, size_t len)
{
if (buf[0])
return do_log(level, buf);
while ((fgets(buf, len, stdin)))
syslog(level, "%s", buf);
do_log(level, buf);
return 0;
}
static int parse_prio(char *arg, int *f, int *l)
static int parse_prio(char *arg, int *fac, int *lvl)
{
char *duparg = strdup(arg);
char *ptr, *prio;
const char *prio;
char *ptr;
int found;
if (!duparg)
prio = arg;
@@ -114,23 +155,34 @@ static int parse_prio(char *arg, int *f, int *l)
if (ptr) {
*ptr++ = 0;
found = -1;
for (int i = 0; facilitynames[i].c_name; i++) {
if (!strcmp(facilitynames[i].c_name, prio)) {
*f = facilitynames[i].c_val;
found = facilitynames[i].c_val;
break;
}
}
if (found == -1)
return 1;
*fac = found;
prio = ptr;
}
found = -1;
for (int i = 0; prioritynames[i].c_name; i++) {
if (!strcmp(prioritynames[i].c_name, prio)) {
*l = prioritynames[i].c_val;
found = prioritynames[i].c_val;
break;
}
}
if (found == -1)
return 1;
*lvl = found;
if (duparg != arg)
free(duparg);
@@ -161,13 +213,14 @@ static int usage(int code)
int main(int argc, char *argv[])
{
int c, rc, num = 5;
char *ident = NULL, *logfile = NULL;
int log_opts = LOG_NOWAIT;
int facility = LOG_USER;
int level = LOG_INFO;
int log_opts = LOG_NOWAIT;
off_t size = 200 * 1024;
char *ident = NULL, *logfile = NULL;
off_t size = LOG_MAX;
char buf[512] = "";
int num = LOG_NUM;
int c, rc;
while ((c = getopt(argc, argv, "f:hn:p:r:st:v")) != EOF) {
switch (c) {
+4 -3
View File
@@ -31,6 +31,7 @@
#include <sys/mount.h>
#include "helpers.h"
#include "log.h"
/*
* SysV init on Debian/Ubuntu skips these protected mount points
@@ -40,7 +41,7 @@
* and regular filesystems that can be safely unmounted before we do
* swapoff, and remount / as read-only, respectively.
*/
static int is_protected(char *dir)
static int is_protected(const char *dir)
{
size_t i;
char *protected_mnts[] = {
@@ -111,7 +112,7 @@ static int unmount(const char *target)
void unmount_tmpfs(void)
{
struct mntent *mnt;
const struct mntent *mnt;
FILE *fp = NULL;
while ((mnt = iterator("/proc/mounts", &fp))) {
@@ -122,7 +123,7 @@ void unmount_tmpfs(void)
void unmount_regular(void)
{
struct mntent *mnt;
const struct mntent *mnt;
FILE *fp = NULL;
while ((mnt = iterator("/proc/mounts", &fp))) {
+1 -1
View File
@@ -192,7 +192,7 @@ int pid_file_set(svc_t *svc, char *file, int not)
* pid:foo.tla --> /run/foo.tla.pid
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
*
* An exclamation mark, or logial NOT, in the first character position
* An exclamation mark, or logical NOT, in the first character position
* indicates that Finit should *not* manage the PID file, and that the
* process uses a "non-standard" location. Eg. if service is 'bar'
* Finit would assume the PID file is /run/bar.pid and the below simply
+2
View File
@@ -320,6 +320,8 @@ static int init_plugins(uev_ctx_t *ctx)
plugin_t *p, *tmp;
int fail = 0;
(void)ctx;
PLUGIN_ITERATOR(p, tmp) {
if (plugin_io_init(p))
fail++;
+2 -1
View File
@@ -41,12 +41,13 @@ extern int service_interval;
extern char *fsck_mode;
extern char *fsck_repair;
extern uev_ctx_t *ctx;
int api_init (uev_ctx_t *ctx);
int api_exit (void);
void conf_flush_events(void);
void service_monitor (pid_t lost, int status);
void service_notify_cb(uev_t *w, void *arg, int events);
const char *plugin_hook_str (hook_point_t no);
int plugin_exists (hook_point_t no);
+1 -1
View File
@@ -193,7 +193,7 @@ int run_parts(char *dir, char *cmd, const char *env[], int progress, int sysv)
#ifndef __FINIT__
static int usage(int rc)
{
warnx("usage: runparts [-dhps?] DIRECTORY");
warnx("usage: runparts [-bdhps?] DIRECTORY");
return rc;
}
+3 -1
View File
@@ -22,7 +22,8 @@
*/
#include "config.h"
#include "finit.h"
#include "private.h"
#include "log.h"
#include "schedule.h"
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
@@ -35,6 +36,7 @@ static void cb(uev_t *w, void *arg, int events)
struct wq *work = (struct wq *)arg;
if (UEV_ERROR == events) {
dbg("%s(): spurious problem with schedule work timer, restarting.", __func__);
uev_timer_start(w);
return;
}
+444 -229
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -27,12 +27,10 @@
#include "svc.h"
void service_runlevel (int newlevel);
int service_register (int type, char *line, struct rlimit rlimit[], char *file);
void service_unregister (svc_t *svc);
void service_runtask_clean (void);
void service_reload_dynamic (void);
void service_update_rdeps (void);
void service_mark_unavail (void);
+29 -3
View File
@@ -94,6 +94,7 @@
#include "private.h"
#include "sig.h"
#include "service.h"
#include "sm.h"
#include "util.h"
#include "utmp-api.h"
@@ -232,6 +233,8 @@ void do_iterate_proc(int (*cb)(int, void *), void *data)
dbg("Skipping %s ...", file);
else if (file[0] == '@')
dbg("Skipping %s ...", &file[1]);
else if (strstr(file, "initctl"))
dbg("Skipping %s ...", file);
else
if (cb(pid, data)) {
dbg("PID %d is still alive (%s)", pid, file);
@@ -258,6 +261,7 @@ static int status_cb(int pid, void *data)
{
int *has_proc = (int *)data;
(void)pid;
*has_proc = 1;
return 1;
@@ -423,6 +427,8 @@ void do_shutdown(shutop_t op)
*/
static void sighup_cb(uev_t *w, void *arg, int events)
{
(void)arg;
dbg("...");
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
@@ -439,7 +445,7 @@ static void sighup_cb(uev_t *w, void *arg, int events)
api_init(w->ctx);
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
service_reload_dynamic();
sm_reload();
}
/*
@@ -449,6 +455,9 @@ static void sighup_cb(uev_t *w, void *arg, int events)
*/
static void sigint_cb(uev_t *w, void *arg, int events)
{
(void)w;
(void)arg;
dbg("...");
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
@@ -465,6 +474,9 @@ static void sigint_cb(uev_t *w, void *arg, int events)
*/
static void sigpwr_cb(uev_t *w, void *arg, int events)
{
(void)w;
(void)arg;
dbg("...");
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
@@ -479,6 +491,8 @@ static void sigpwr_cb(uev_t *w, void *arg, int events)
*/
static void sigusr1_cb(uev_t *w, void *arg, int events)
{
(void)arg;
dbg("...");
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
@@ -500,6 +514,9 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
*/
static void sigusr2_cb(uev_t *w, void *arg, int events)
{
(void)w;
(void)arg;
dbg("...");
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
@@ -512,7 +529,7 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
}
halt = SHUT_OFF;
service_runlevel(0);
sm_runlevel(0);
}
/*
@@ -520,6 +537,9 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
*/
static void sigterm_cb(uev_t *w, void *arg, int events)
{
(void)w;
(void)arg;
dbg("...");
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
@@ -532,7 +552,7 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
}
halt = SHUT_REBOOT;
service_runlevel(6);
sm_runlevel(6);
}
/*
@@ -543,6 +563,9 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
int status;
pid_t pid;
(void)w;
(void)arg;
if (UEV_ERROR == events) {
errx(1, "Unrecoverable error in signal watcher");
return;
@@ -599,6 +622,9 @@ const char *sig_name(int signo)
*/
static void chld_handler(int sig, siginfo_t *info, void *ctx)
{
(void)sig;
(void)info;
(void)ctx;
/* NOP */
}
+150 -64
View File
@@ -29,6 +29,7 @@
#include "finit.h"
#include "cond.h"
#include "conf.h"
#include "log.h"
#include "helpers.h"
#include "private.h"
#include "schedule.h"
@@ -38,11 +39,25 @@
#include "sm.h"
#include "utmp-api.h"
sm_t sm;
typedef enum {
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
SM_BOOTSTRAP_WAIT_STATE, /* Waiting for bootstrap to complete */
SM_RUNNING_STATE, /* Normal state, services running */
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped processes to halt */
SM_RUNLEVEL_CLEAN_STATE, /* Wait for post:scripts and cleanup:scripts */
SM_RELOAD_CHANGE_STATE, /* A reload event has occurred */
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped processes to halt */
SM_RELOAD_CLEAN_STATE, /* Wait for post:scripts and cleanup:scripts */
} sm_state_t;
static struct {
sm_state_t state; /* Running, Changed, Waiting, ... */
int newlevel; /* Set to new runlevel on change, -1 otherwise */
int reload; /* Set on reload event, else 0 */
int in_reload; /* Set when waiting for all processes to be halted */
} sm;
#ifndef FINIT_NOLOGIN_PATH
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */
#endif
/*
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
@@ -90,7 +105,7 @@ static void sm_check_bootstrap(void *work)
} else
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
service_runlevel(level);
sm_runlevel(level);
/* Clean up bootstrap-only tasks/services that never started */
dbg("Clean up all bootstrap-only tasks/services ...");
@@ -107,6 +122,9 @@ static char *sm_status(sm_state_t state)
case SM_BOOTSTRAP_STATE:
return "bootstrap";
case SM_BOOTSTRAP_WAIT_STATE:
return "bootstrap/wait";
case SM_RUNNING_STATE:
return "running";
@@ -116,18 +134,23 @@ static char *sm_status(sm_state_t state)
case SM_RUNLEVEL_WAIT_STATE:
return "runlevel/wait";
case SM_RUNLEVEL_CLEAN_STATE:
return "runlevel/clean";
case SM_RELOAD_CHANGE_STATE:
return "reload/change";
case SM_RELOAD_WAIT_STATE:
return "reload/wait";
default:
return "unknown";
case SM_RELOAD_CLEAN_STATE:
return "reload/clean";
}
return "unknown";
}
static char sm_runlevel(int lvl)
static char sm_rl2ch(int lvl)
{
if (lvl == INIT_LEVEL)
return 'S';
@@ -150,60 +173,39 @@ static void nologin(void)
erase(FINIT_NOLOGIN_PATH);
}
void sm_init(sm_t *sm)
void sm_init(void)
{
static struct wq work = {
.cb = sm_check_bootstrap,
.delay = 1000
};
sm->state = SM_BOOTSTRAP_STATE;
sm->newlevel = -1;
sm->reload = 0;
sm->in_teardown = 0;
sm.state = SM_BOOTSTRAP_STATE;
sm.newlevel = -1;
sm.reload = 0;
sm.in_reload = 0;
dbg("Starting bootstrap finalize timer ...");
schedule_work(&work);
}
void sm_set_runlevel(sm_t *sm, int newlevel)
{
sm->newlevel = newlevel;
dbg("Flushing pending .conf file events ...");
conf_flush_events();
}
void sm_set_reload(sm_t *sm)
{
sm->reload = 1;
dbg("Flushing pending .conf file events ...");
conf_flush_events();
}
int sm_is_in_teardown(sm_t *sm)
{
return sm->in_teardown;
}
void sm_step(sm_t *sm)
void sm_step(void)
{
sm_state_t old_state;
svc_t *svc;
restart:
old_state = sm->state;
old_state = sm.state;
dbg("state: %s, runlevel: %c, newlevel: %d, teardown: %d, reload: %d",
sm_status(sm->state), sm_runlevel(runlevel), sm->newlevel, sm->in_teardown, sm->reload);
sm_status(sm.state), sm_rl2ch(runlevel), sm.newlevel, sm.in_reload, sm.reload);
switch (sm->state) {
switch (sm.state) {
case SM_BOOTSTRAP_STATE:
dbg("Bootstrapping all services in runlevel S from %s", finit_conf);
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE | SVC_TYPE_SYSV);
sm->state = SM_BOOTSTRAP_WAIT_STATE;
sm.state = SM_BOOTSTRAP_WAIT_STATE;
break;
/*
@@ -224,7 +226,7 @@ restart:
/* Allow runparts to start */
cond_set_oneshot("int/bootstrap");
if (sm->newlevel == -1)
if (sm.newlevel == -1)
break;
/* Hooks that should run at the very end */
@@ -235,10 +237,10 @@ restart:
/* Disable progress output at normal runtime */
enable_progress(0);
/* System bootrapped, launch TTYs et al */
/* System bootstrapped, launch TTYs et al */
bootstrap = 0;
service_step_all(SVC_TYPE_RESPAWN);
sm->state = SM_RUNNING_STATE;
sm.state = SM_RUNNING_STATE;
break;
case SM_RUNNING_STATE:
@@ -246,26 +248,26 @@ restart:
service_step_all(SVC_TYPE_ANY);
/* runlevel changed? */
if (sm->newlevel >= 0 && sm->newlevel <= 9) {
if (runlevel == sm->newlevel) {
sm->newlevel = -1;
if (sm.newlevel >= 0 && sm.newlevel <= 9) {
if (runlevel == sm.newlevel) {
sm.newlevel = -1;
break;
}
sm->state = SM_RUNLEVEL_CHANGE_STATE;
sm.state = SM_RUNLEVEL_CHANGE_STATE;
break;
}
/* reload ? */
if (sm->reload) {
sm->reload = 0;
sm->state = SM_RELOAD_CHANGE_STATE;
if (sm.reload) {
sm.reload = 0;
sm.state = SM_RELOAD_CHANGE_STATE;
}
break;
case SM_RUNLEVEL_CHANGE_STATE:
prevlevel = runlevel;
runlevel = sm->newlevel;
sm->newlevel = -1;
runlevel = sm.newlevel;
sm.newlevel = -1;
/* Restore terse mode and run hooks before shutdown */
if (runlevel == 0 || runlevel == 6) {
@@ -274,11 +276,11 @@ restart:
plugin_run_hooks(HOOK_SHUTDOWN);
}
dbg("Setting new runlevel --> %c <-- previous %c", sm_runlevel(runlevel), sm_runlevel(prevlevel));
dbg("Setting new runlevel --> %c <-- previous %c", sm_rl2ch(runlevel), sm_rl2ch(prevlevel));
if (osheading)
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %c", osheading, sm_runlevel(runlevel));
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %c", osheading, sm_rl2ch(runlevel));
else
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel %c", sm_runlevel(runlevel));
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel %c", sm_rl2ch(runlevel));
runlevel_set(prevlevel, runlevel);
/* Disable login in single-user mode as well as shutdown/reboot */
@@ -294,10 +296,10 @@ restart:
service_runtask_clean();
dbg("Stopping services not allowed in new runlevel ...");
sm->in_teardown = 1;
sm.in_reload = 1;
service_step_all(SVC_TYPE_ANY);
sm->state = SM_RUNLEVEL_WAIT_STATE;
sm.state = SM_RUNLEVEL_WAIT_STATE;
break;
case SM_RUNLEVEL_WAIT_STATE:
@@ -316,9 +318,25 @@ restart:
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
dbg("Starting services new to this runlevel ...");
sm->in_teardown = 0;
sm.in_reload = 0;
service_step_all(SVC_TYPE_ANY);
sm.state = SM_RUNLEVEL_CLEAN_STATE;
break;
case SM_RUNLEVEL_CLEAN_STATE:
/*
* Wait for post:script or cleanup:script to be collected,
* which moves the svc to HALTED or DEAD state. We will
* be called by the service_monitor() on collect.
*/
svc = svc_clean_completed();
if (svc) {
dbg("Waiting to collect post/cleanup script for %s, cmd %s(%d) ...",
svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
break;
}
/* Cleanup stale services */
svc_clean_dynamic(service_unregister);
@@ -337,7 +355,7 @@ restart:
if (runlevel == 0 || runlevel == 6)
do_shutdown(halt);
sm->state = SM_RUNNING_STATE;
sm.state = SM_RUNNING_STATE;
break;
case SM_RELOAD_CHANGE_STATE:
@@ -349,11 +367,11 @@ restart:
* let all affected services move to WAITING/HALTED
*/
dbg("Stopping services not allowed after reconf ...");
sm->in_teardown = 1;
sm.in_reload = 1;
cond_reload();
service_step_all(SVC_TYPE_ANY);
sm->state = SM_RELOAD_WAIT_STATE;
sm.state = SM_RELOAD_WAIT_STATE;
break;
case SM_RELOAD_WAIT_STATE:
@@ -367,11 +385,27 @@ restart:
break;
}
sm->in_teardown = 0;
sm.in_reload = 0;
dbg("Starting services after reconf ...");
service_step_all(SVC_TYPE_ANY);
sm.state = SM_RELOAD_CLEAN_STATE;
break;
case SM_RELOAD_CLEAN_STATE:
/*
* Wait for post:script or cleanup:script to be collected,
* which moves the svc to HALTED or DEAD state. We will
* be called by the service_monitor() on collect.
*/
svc = svc_clean_completed();
if (svc) {
dbg("Waiting to collect post/cleanup script for %s, cmd %s(%d) ...",
svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
break;
}
/* Cleanup stale services */
svc_clean_dynamic(service_unregister);
@@ -382,14 +416,66 @@ restart:
service_notify_reconf();
dbg("Reconfiguration done");
sm->state = SM_RUNNING_STATE;
sm.state = SM_RUNNING_STATE;
break;
}
if (sm->state != old_state)
if (sm.state != old_state)
goto restart;
}
/**
* sm_in_reload - System currently in reload or runlevel change?
*
* Returns:
* %TRUE(1) or %FALSE(0)
*/
int sm_in_reload(void)
{
return sm.in_reload;
}
/**
* sm_reload - Called on SIGHUP, 'init q' or 'initctl reload'
*
* This function is called when Finit has received SIGHUP to reload
* .conf files in /etc/finit.d. It is responsible for starting,
* stopping and reloading (forwarding SIGHUP) to processes affected.
*/
void sm_reload(void)
{
sm.reload = 1;
dbg("Flushing pending .conf file events ...");
conf_flush_events();
sm_step();
}
/**
* sm_runlevel - Change to a new runlevel
* @newlevel: New runlevel to activate
*
* Stops all services not in @newlevel and starts, or lets continue to run,
* those in @newlevel. Also updates @prevlevel and active @runlevel.
*/
void sm_runlevel(int newlevel)
{
if (!rescue && (runlevel == 1 || runlevel == INIT_LEVEL) && !IS_RESERVED_RUNLEVEL(newlevel))
networking(1);
sm.newlevel = newlevel;
dbg("Flushing pending .conf file events ...");
conf_flush_events();
sm_step();
if (!rescue && IS_RESERVED_RUNLEVEL(runlevel))
networking(0);
}
/**
* Local Variables:
* indent-tabs-mode: t
+5 -23
View File
@@ -24,30 +24,12 @@
#ifndef FINIT_SM_H_
#define FINIT_SM_H_
typedef enum {
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
SM_BOOTSTRAP_WAIT_STATE, /* Waiting for bootstrap to complete */
SM_RUNNING_STATE, /* Normal state, services running */
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
SM_RELOAD_CHANGE_STATE, /* A reload event has occurred */
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */
} sm_state_t;
void sm_init (void);
void sm_step (void);
typedef struct sm {
sm_state_t state; /* Running, Changed, Waiting, ... */
int newlevel; /* Set on runlevel change to new runlevel, -1 if not change */
int reload; /* Set on reload event, else 0 */
int in_teardown; /* Set when waiting for all processes to be halted */
} sm_t;
extern sm_t sm;
void sm_init(sm_t *sm);
void sm_step(sm_t *sm);
void sm_set_runlevel(sm_t *sm, int newlevel);
void sm_set_reload(sm_t *sm);
int sm_is_in_teardown(sm_t *sm);
int sm_in_reload (void);
void sm_reload (void);
void sm_runlevel (int newlevel);
#endif /* FINIT_SM_H_ */
+39 -1
View File
@@ -37,6 +37,7 @@
#endif
#include "finit.h"
#include "conf.h"
#include "svc.h"
#include "helpers.h"
#include "pid.h"
@@ -348,6 +349,43 @@ svc_t *svc_stop_completed(void)
return NULL;
}
/**
* svc_clean_completed - Have post: and cleanup: scripts finished?
*
* Called late in runlevel and reload transitions to check if all post: and
* cleanup:scripts have completed. A removed service should end up in the
* DEAD state, while a service with a post:script ends up in HALTED.
*
* Returns:
* %NULL if post: and cleanup: scripts have run, otherwise a pointer to
* the first found svc_t waiting for post: or cleanup:script.
*/
svc_t *svc_clean_completed(void)
{
svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (svc_enabled(svc))
continue;
if (svc_is_runtask(svc) && svc->state == SVC_DONE_STATE)
continue;
if (svc_is_removed(svc)) {
if (svc->state == SVC_DEAD_STATE)
continue; /* any cleanup:script done */
} else {
if (svc->state == SVC_HALTED_STATE)
continue; /* any post:script done */
}
return svc;
}
return NULL;
}
/**
* svc_find - Find a service object by its full path name
* @name: Full path name, e.g., /sbin/syslogd
@@ -580,7 +618,7 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (svc->removed && cb)
if (svc_is_removed(svc) && cb)
cb(svc);
}
}
+33 -10
View File
@@ -52,14 +52,17 @@ typedef enum {
} svc_type_t;
#define SVC_TYPE_ANY (-1)
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_TTY)
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV)
#define SVC_TYPE_DAEMON (SVC_TYPE_SERVICE | SVC_TYPE_SYSV)
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_SYSV | SVC_TYPE_TTY)
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK)
typedef enum {
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
SVC_DONE_STATE, /* Task/Run job has been run */
SVC_DEAD_STATE, /* Process is dead and scheduled for removal */
SVC_CLEANUP_STATE, /* Running cleanup: script */
SVC_TEARDOWN_STATE, /* Running post: script */
SVC_STOPPING_STATE, /* Waiting to collect the child process */
SVC_CLEANUP_STATE, /* Running post: script */
SVC_SETUP_STATE, /* Running pre: script */
SVC_PAUSED_STATE, /* Condition is in flux, process SIGSTOPed */
SVC_WAITING_STATE, /* Enabled but condition not satisfied */
@@ -83,7 +86,7 @@ typedef enum {
SVC_ONCRASH_SCRIPT,
} svc_oncrash_action_t;
/* 0: none, 1: systemd, 2: s6 */
/* 0: none, 1: finit (native), 2: systemd, 3: s6 */
typedef enum {
SVC_NOTIFY_NONE = 0,
SVC_NOTIFY_PID,
@@ -146,7 +149,7 @@ typedef struct svc {
char cond[MAX_COND_LEN];
/* Instance specifics */
int job; /* For intenal use only, canonical ref is NAME:ID */
int job; /* For internal use only, canonical ref is NAME:ID */
char name[MAX_ARG_LEN];
char id[MAX_ID_LEN]; /* :ID */
char ifstmt[MAX_IDENT_LEN];
@@ -196,13 +199,25 @@ typedef struct svc {
char conflict[MAX_ARG_LEN];
char desc[MAX_STR_LEN];
char env[MAX_CMD_LEN];
char pre_script[MAX_CMD_LEN];
int pre_tmo;
char post_script[MAX_CMD_LEN];
int post_tmo;
char ready_script[MAX_CMD_LEN];
int ready_tmo;
char cleanup_script[MAX_CMD_LEN];
int cleanup_tmo;
/* When set, used instead of SIGHUP or stop-start */
char reload_script[MAX_CMD_LEN];
/* When set, used instead of SIGTERM or sysv 'stop' */
char stop_script[MAX_CMD_LEN];
/*
* Used to forcefully kill services that won't shutdown on
* termination and to delay restarts of crashing services.
@@ -240,6 +255,7 @@ void svc_foreach (int (*cb)(svc_t *));
void svc_foreach_type (int types, int (*cb)(svc_t *));
svc_t *svc_stop_completed (void);
svc_t *svc_clean_completed (void);
void svc_mark (svc_t *svc);
void svc_mark_dynamic (void);
@@ -256,26 +272,27 @@ int svc_ifthen (int is_conf, const char *ident, char *stmt,
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
static inline int svc_is_daemon (svc_t *svc) { return svc && (SVC_TYPE_DAEMON & svc->type); }
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
static inline int svc_is_nohup (svc_t *svc) { return svc && (0 == svc->sighup); }
static inline int svc_is_noreload (svc_t *svc) { return svc && (0 == svc->sighup && 0 == svc->reload_script[0]); }
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }
static inline int svc_has_ready (svc_t *svc) { return svc->ready_script[0];}
static inline int svc_has_cleanup (svc_t *svc) { return svc->cleanup_script[0]; }
static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
static inline int svc_is_running (svc_t *svc) { return svc && svc->state == SVC_RUNNING_STATE; }
static inline int svc_is_stopping (svc_t *svc) { return svc && svc->state == SVC_STOPPING_STATE; }
static inline int svc_is_stopped (svc_t *svc) { return svc && svc->block == SVC_BLOCK_USER; }
static inline int svc_is_removed (svc_t *svc) { return svc && svc->removed; }
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
@@ -390,12 +407,15 @@ static inline char *svc_status(svc_t *svc)
return "stopping";
}
case SVC_CLEANUP_STATE:
return "cleanup";
case SVC_TEARDOWN_STATE:
return "teardown";
case SVC_SETUP_STATE:
return "setup";
case SVC_CLEANUP_STATE:
return "cleanup";
case SVC_PAUSED_STATE:
return "paused";
@@ -408,6 +428,9 @@ static inline char *svc_status(svc_t *svc)
case SVC_RUNNING_STATE:
return "running";
case SVC_DEAD_STATE:
return "dead";
default:
return "UNKNOWN";
}
+299 -174
View File
@@ -23,12 +23,47 @@
#include "config.h" /* Generated by configure script */
#include <dirent.h>
#include <ftw.h>
#include <getopt.h>
#include <glob.h>
#include <libgen.h>
#include <grp.h>
#include <pwd.h>
#include <sys/sysmacros.h>
#include "finit.h"
#include "helpers.h"
#include "tmpfiles.h"
#include <stdlib.h>
#include <string.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "log.h"
#include "util.h"
int debug;
int c_flag = 0;
int r_flag = 0;
static int is_dir_empty(const char *path)
{
struct dirent **namelist;
int num;
num = scandir(path, &namelist, NULL, NULL);
if (num < 0)
return 0;
for (int i = 0; i < num; i++)
free(namelist[i]);
free(namelist);
return num >= 3;
}
static int glob_do(const char *path, int (*cb)(const char *))
{
int rc = 0;
@@ -75,6 +110,9 @@ static int parse_mm(char *arg, int *major, int *minor)
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
{
(void)sb;
(void)tflag;
if (ftw->level == 0)
return 1;
@@ -279,182 +317,214 @@ static void tmpfiles(char *line)
strc = stat(path, &st);
switch (type[0]) {
case 'b':
rc = parse_mm(arg, &major, &minor);
if (rc)
// file and directory removal logic
if (r_flag) {
switch (type[0]) {
case 'b':
case 'c':
case 'C':
case 'd':
break;
if (!strc) {
if (type[1] != '+')
break;
erase(path);
}
mkparent(path, 0755);
rc = blkdev(path, mode ?: 0644, major, minor);
break;
case 'c':
rc = parse_mm(arg, &major, &minor);
if (rc)
break;
if (!strc) {
if (type[1] != '+')
break;
erase(path);
}
mkparent(path, 0755);
rc = chardev(path, mode ?: 0644, major, minor);
break;
case 'C':
if (!arg) {
paste(buf, sizeof(buf), "/usr/share/factory", path);
arg = buf;
}
if (!strc) {
struct dirent **namelist;
int num;
if (!S_ISDIR(st.st_mode))
break;
num = scandir(path, &namelist, NULL, NULL);
free(namelist);
if (num >= 3)
break; /* not empty */
}
if (fisdir(arg) && !fisslashdir(arg)) {
size_t len = strlen(arg) + 2;
dst = malloc(len);
if (!dst)
break;
snprintf(dst, len, "%s/", arg);
arg = dst;
}
mkparent(path, 0755);
rc = rsync(arg, path, LITE_FOPT_KEEP_MTIME, NULL);
if (rc && errno == ENOENT)
rc = 0;
break;
case 'd':
case 'D':
mkparent(path, 0755);
rc = mksubsys(path, mode ?: 0755, user, group);
break;
case 'e':
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
break;
for (size_t i = 0; i < gl.gl_pathc; i++)
rc += mksubsys(gl.gl_pathv[i], mode ?: 0755, user, group);
break;
case 'f':
case 'F':
mkparent(path, 0755);
if (type[1] == '+' || type[0] == 'F') {
/* f+/F will create or truncate the file */
if (!arg) {
rc = create(path, mode ?: 0644, user, group);
break;
case 'D':
if (fisdir(path)) {
nftw(path, do_delete, 20, FTW_DEPTH | FTW_PHYS);
}
fp = fopen(path, "w+");
} else {
/* f will create the file if it doesn't exist */
if (strc)
fp = fopen(path, "w");
}
if (fp) {
write_arg(fp, arg);
rc = fclose(fp);
}
break;
case 'l': /* Finit extension, like 'L' but only if target exists */
if (!arg) {
paste(buf, sizeof(buf), "/usr/share/factory", path);
if (stat(buf, &ast))
break;
} else if (arg[0] != '/') {
char *tmp;
tmp = dirname(strdupa(path));
paste(buf, sizeof(buf), tmp, arg);
dst = realpath(buf, NULL);
if (!dst)
break;
if (stat(dst, &ast))
break;
} else {
if (stat(arg, &ast))
break;
}
/* fallthrough */
case 'L':
if (!strc) {
if (type[1] != '+')
break;
rmrf(path);
}
mkparent(path, 0755);
if (!arg) {
paste(buf, sizeof(buf), "/usr/share/factory", path);
arg = buf;
}
rc = ln(arg, path);
if (rc && errno == EEXIST)
rc = 0;
break;
case 'p':
if (!strc) {
if (type[1] != '+')
break;
erase(path);
}
mkparent(path, 0755);
rc = mkfifo(path, mode ?: 0644);
break;
case 'r':
rc = glob_do(path, erase);
if (rc && errno == ENOENT)
rc = 0;
break;
case 'R':
rc = glob_do(path, rmrf);
break;
case 'w':
if (!arg)
break;
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
case 'e':
case 'f':
case 'F':
case 'l': /* Finit extension, like 'L' but only if target exists */
case 'L':
case 'p':
break;
case 'r':
rc = glob_do(path, erase);
if (rc && errno == ENOENT)
rc = 0;
break;
case 'R':
rc = glob_do(path, rmrf);
break;
case 'w':
break;
case 'X':
case 'x':
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
break;
case 'Z':
case 'z':
break;
default:
errx(1, "Unsupported tmpfiles command '%s'", type);
return;
}
}
// file & directory creation logic
if (c_flag) {
switch (type[0]) {
case 'b':
rc = parse_mm(arg, &major, &minor);
if (rc)
break;
if (!strc) {
if (type[1] != '+')
break;
erase(path);
}
mkparent(path, 0755);
rc = blkdev(path, mode ?: 0644, major, minor);
break;
case 'c':
rc = parse_mm(arg, &major, &minor);
if (rc)
break;
if (!strc) {
if (type[1] != '+')
break;
erase(path);
}
mkparent(path, 0755);
rc = chardev(path, mode ?: 0644, major, minor);
break;
case 'C':
if (!arg) {
paste(buf, sizeof(buf), "/usr/share/factory", path);
arg = buf;
}
if (fisdir(path) && !is_dir_empty(path))
break;
if (fisdir(arg) && !fisslashdir(arg)) {
size_t len = strlen(arg) + 2;
dst = malloc(len);
if (!dst)
break;
snprintf(dst, len, "%s/", arg);
arg = dst;
}
mkparent(path, 0755);
rc = rsync(arg, path, LITE_FOPT_KEEP_MTIME, NULL);
if (rc && errno == ENOENT)
rc = 0;
break;
case 'd':
case 'D':
mkparent(path, 0755);
rc = mksubsys(path, mode ?: 0755, user, group);
break;
case 'e':
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
break;
for (size_t i = 0; i < gl.gl_pathc; i++)
rc += mksubsys(gl.gl_pathv[i], mode ?: 0755, user, group);
break;
case 'f':
case 'F':
mkparent(path, 0755);
if (type[1] == '+' || type[0] == 'F') {
/* f+/F will create or truncate the file */
if (!arg) {
rc = create(path, mode ?: 0644, user, group);
break;
}
fp = fopen(path, "w+");
} else {
/* f will create the file if it doesn't exist */
if (strc)
fp = fopen(path, "w");
}
for (size_t i = 0; i < gl.gl_pathc; i++) {
fp = fopen(gl.gl_pathv[i], type[1] == '+' ? "a" : "w");
if (fp) {
write_arg(fp, arg);
rc = fclose(fp);
}
}
break;
case 'X':
case 'x':
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
break;
case 'Z':
opts = "-R";
/* fallthrough */
case 'z':
if (!whichp("restorecon"))
break;
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
break;
case 'l': /* Finit extension, like 'L' but only if target exists */
if (!arg) {
paste(buf, sizeof(buf), "/usr/share/factory", path);
if (stat(buf, &ast))
break;
} else if (arg[0] != '/') {
char *tmp;
for (size_t i = 0; i < gl.gl_pathc; i++) {
snprintf(buf, sizeof(buf), "restorecon %s %s", opts, gl.gl_pathv[i]);
run(buf, "restorecon");
tmp = dirname(strdupa(path));
paste(buf, sizeof(buf), tmp, arg);
dst = realpath(buf, NULL);
if (!dst)
break;
if (stat(dst, &ast))
break;
} else {
if (stat(arg, &ast))
break;
}
/* fallthrough */
case 'L':
if (!strc) {
if (type[1] != '+')
break;
rmrf(path);
}
mkparent(path, 0755);
if (!arg) {
paste(buf, sizeof(buf), "/usr/share/factory", path);
arg = buf;
}
rc = ln(arg, path);
if (rc && errno == EEXIST)
rc = 0;
break;
case 'p':
if (!strc) {
if (type[1] != '+')
break;
erase(path);
}
mkparent(path, 0755);
rc = mkfifo(path, mode ?: 0644);
break;
case 'r':
case 'R':
break;
case 'w':
if (!arg)
break;
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
break;
for (size_t i = 0; i < gl.gl_pathc; i++) {
fp = fopen(gl.gl_pathv[i], type[1] == '+' ? "a" : "w");
if (fp) {
write_arg(fp, arg);
rc = fclose(fp);
}
}
break;
case 'X':
case 'x':
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
break;
case 'Z':
opts = "-R";
/* fallthrough */
case 'z':
if (!whichp("restorecon"))
break;
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
break;
for (size_t i = 0; i < gl.gl_pathc; i++) {
snprintf(buf, sizeof(buf), "restorecon %s %s", opts, gl.gl_pathv[i]);
system(buf);
}
break;
default:
errx(1, "Unsupported tmpfiles command '%s'", type);
return;
}
break;
default:
errx(1, "Unsupported tmpfiles command '%s'", type);
return;
}
if (dst)
@@ -464,14 +534,68 @@ static void tmpfiles(char *line)
warn("Failed %s operation on path %s", type, path);
}
/*
* Only the three last tmpfiles.d/ directories are defined in
* tmpfiles.d(5) as system search paths. Finit adds two more
* before that to have Finit specific ones sorted first, and
* a configure prefix specific one after that for user needs.
*/
void tmpfilesd(void)
static int usage(int rc)
{
fprintf(stderr,
"Usage: tmpfiles [COMMAND...]\n"
"\n"
"Commands:\n"
" -c, --create Create files and directories\n"
" -d, --debug Show developer debug messages\n"
" -r, --remove Remove files and directories marked for removal\n"
" -h, --help This help text\n"
"\n");
return rc;
}
int main(int argc, char *argv[])
{
struct option long_options[] = {
{ "create", 0, NULL, 'c' },
{ "debug", 0, NULL, 'd' },
{ "remove", 0, NULL, 'r' },
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
int c;
while ((c = getopt_long(argc, argv, "cdrh?", long_options, NULL)) != EOF) {
switch(c) {
case 'c':
c_flag = 1;
break;
case 'd':
debug = 1;
break;
case 'r':
r_flag = 1;
break;
case 'h':
case '?':
return usage(0);
default:
return usage(1);
}
}
if (c_flag + r_flag == 0) {
fprintf(stderr, "You need to specify at least one of --create or --remove.\n");
return 1;
}
/*
* Only the three last tmpfiles.d/ directories are defined in
* tmpfiles.d(5) as system search paths. Finit adds two more
* before that to have Finit specific ones sorted first, and
* a configure prefix specific one after that for user needs.
*/
/* in priority order */
char *dir[] = {
FINIT_TMPFILES "/*.conf",
@@ -518,6 +642,7 @@ void tmpfilesd(void)
continue;
tmpfiles(line);
free(line);
}
fclose(fp);
-42
View File
@@ -1,42 +0,0 @@
/* Limited tmpfiles.d implementation
*
* Copyright (c) 2024 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TMPFILES_H_
#define TMPFILES_H_
#include <dirent.h>
#include <ftw.h>
#include <glob.h>
#include <libgen.h>
#include <stdlib.h>
#include <string.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
void tmpfilesd(void);
#endif /* TMPFILES_H_ */
+5 -3
View File
@@ -38,6 +38,7 @@
#endif
#include "config.h" /* Generated by configure script */
#include "log.h"
#include "finit.h"
#include "conf.h"
#include "helpers.h"
@@ -172,7 +173,7 @@ int tty_parse_args(struct tty *tty, char *cmd, char **args)
passenv = 1;
else if (!strcmp(cmd, "rescue"))
tty->rescue = 1; /* for rescue shells */
else if (whichp(cmd)) /* in $PATH? */
else if (!tty->cmd && whichp(cmd))
tty->cmd = cmd;
else
tty->args[tty->num++] = cmd;
@@ -229,8 +230,9 @@ int tty_parse_args(struct tty *tty, char *cmd, char **args)
return errno = EINVAL;
}
dbg("Registering %s getty on TTY %s at %s baud with term %s", tty->cmd ? "external" : "built-in",
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
dbg("Registering %s getty on TTY %s at %s baud with term %s",
tty->cmd ? "external" : "built-in",
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
/* Built-in getty now comes as standalone program */
if (!tty->cmd) {
+94
View File
@@ -25,6 +25,8 @@
#include <ctype.h> /* isprint() */
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
@@ -178,6 +180,98 @@ char *str(char *fmt, ...)
return buf;
}
int getuser(char *username, char **home)
{
#ifdef ENABLE_STATIC
if (home)
*home = "/"; /* XXX: Fixme */
return fgetint("/etc/passwd", "x:\n", username);
#else
struct passwd *usr;
if (!username || (usr = getpwnam(username)) == NULL)
return -1;
if (home)
*home = usr->pw_dir;
return usr->pw_uid;
#endif
}
int getgroup(char *group)
{
#ifdef ENABLE_STATIC
return fgetint("/etc/group", "x:\n", group);
#else
struct group *grp;
if ((grp = getgrnam(group)) == NULL)
return -1;
return grp->gr_gid;
#endif
}
/* get current user */
int getcuser(char *buf, size_t len)
{
char *ptr = "root";
#ifndef ENABLE_STATIC
struct passwd *pw = getpwuid(getuid());
if (pw)
ptr = pw->pw_name;
#endif
if (strlcpy(buf, ptr, len) > len)
return -1;
return 0;
}
/* get current group */
int getcgroup(char *buf, size_t len)
{
char *ptr = "root";
#ifndef ENABLE_STATIC
struct group *gr = getgrgid(getgid());
if (gr)
ptr = gr->gr_name;
#endif
if (strlcpy(buf, ptr, len) > len)
return -1;
return 0;
}
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
{
mode_t omask;
int uid, gid;
int rc = 0;
omask = umask(0);
uid = getuser(user, NULL);
if (uid >= 0) {
gid = getgroup(group);
if (gid < 0)
gid = 0;
rc = makedir(dir, mode);
if (rc && errno == EEXIST)
rc = chmod(dir, mode);
if (chown(dir, uid, gid))
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
}
umask(omask);
return rc;
}
int fnread(char *buf, size_t len, char *fmt, ...)
{
char path[256];
+117
View File
@@ -25,6 +25,8 @@
#define FINIT_UTIL_H_
#include "config.h"
#include <ctype.h>
#ifdef HAVE_TERMIOS_H
#include <poll.h>
#include <stdio.h>
@@ -53,11 +55,21 @@ extern char *prognm;
# include <lite/conio.h>
# include <lite/lite.h>
#endif
#include "log.h"
char *progname (char *arg0);
const char *basenm (const char *path);
char *str (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
int getuser (char *username, char **home);
int getgroup (char *group);
int getcuser (char *buf, size_t len);
int getcgroup (char *buf, size_t len);
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
int fngetint (char *path, int *val);
@@ -92,6 +104,57 @@ int ttcooked (void);
#define ttcooked() 0
#endif
/*
* Defaults to user "root" and group "wheel" (root) if:
* 1) the user is missing
* 2) the group or the file /etc/group is missing
*/
static inline int create(char *path, mode_t mode, char *user, char *group)
{
int fd, uid, gid;
if (!path) {
errno = EINVAL;
return -1;
}
uid = getuser(user, NULL);
if (uid < 0)
uid = 0;
gid = getgroup(group);
if (gid < 0)
gid = 0;
fd = creat(path, mode);
if (fd == -1) {
warn("Failed creating %s properly", path);
return -1;
}
close(fd);
if (chown(path, uid, gid)) {
warn("Failed chowning %s properly", path);
return -1;
}
return 0;
}
static inline int ln(const char *target, const char *linkpath)
{
if (!target || !linkpath) {
errno = EINVAL;
return -1;
}
if (symlink(target, linkpath)) {
if (errno != EEXIST)
warn("Failed creating %s -> %s symlink", target, linkpath);
return -1;
}
return 0;
}
static inline char *strterm(char *str, size_t len)
{
str[len - 1] = 0;
@@ -130,6 +193,60 @@ static inline int suffix(char *path, size_t len, const char *sfx)
return 0;
}
static inline void hexdump(const char *buf, size_t len)
{
size_t i, j;
for (i = 0; i < len; i += 16) {
printf("%08zx ", i);
for (j = 0; j < 8 && i + j < len; j++)
printf("%02x ", buf[i + j]);
if (j == 8) {
printf(" ");
} else {
for (; j < 8; j++)
printf(" ");
printf(" ");
}
for (j = 8; j < 16 && i + j < len; j++)
printf("%02x ", buf[i + j]);
for (; j < 16; j++)
printf(" ");
printf(" |");
for (j = 0; j < 16 && i + j < len; j++) {
char c = buf[i + j];
printf("%c", isprint(c) ? c : '.');
}
printf("|\n");
}
}
/* drop quotes from a string at point, if any */
static inline int unquote(char **str, char *end)
{
char *ptr = *str;
/* unquote value, if quoted */
if (ptr[0] == '"' || ptr[0] == '\'') {
char q = ptr[0];
if (!end && !(end = strchr(&ptr[1], q)))
return -1;
if (*end == q) {
*str = &ptr[1];
*end = 0;
}
}
return 0;
}
#endif /* FINIT_UTIL_H_ */
/**
@@ -15,8 +15,6 @@ test_teardown()
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
say "Test start $(date)"
say "Add a dynamic service in $FINIT_RCSD/service.conf"
run "echo 'service [2345] kill:20 log service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
-2
View File
@@ -15,8 +15,6 @@ test_teardown()
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
say "Test start $(date)"
say "Add a dynamic service in $FINIT_CONF"
run "echo 'service [2345] kill:20 log service.sh -- Dyn service' > $FINIT_CONF"
-5
View File
@@ -11,11 +11,6 @@ BOOTSTRAP="run [S] crasher.sh -- Party crasher"
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-5
View File
@@ -7,11 +7,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-5
View File
@@ -5,11 +5,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
+1 -6
View File
@@ -1,5 +1,5 @@
#!/bin/sh
# Verify handling of dependant services, bug #314
# Verify handling of dependent services, bug #314
# Two services: foo and bar, where bar depends on foo:
#
# - bar must not start until foo is ready
@@ -14,11 +14,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-5
View File
@@ -7,11 +7,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-1
View File
@@ -8,7 +8,6 @@ TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
run "mkdir -p /etc/default"
}
-5
View File
@@ -8,11 +8,6 @@ set COLORTERM=yes\n\
b aq=oroszoe\n\
baz=qux"
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-5
View File
@@ -7,11 +7,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
+2
View File
@@ -362,6 +362,8 @@ echo "Finit running as PID $finit_pid"
#tty=/dev/$(texec cat /sys/class/tty/console/active)
#texec cat "$tty" &
sep "Test start $(date)"
# Allow Finit to start up properly before launching the test
i=0
set +u
+1 -1
View File
@@ -41,7 +41,7 @@ export PATH
# Not supported by Busybox unshare:
# --cgroup --time
exec "$unshare" \
--user --map-root-user \
--user --map-root-user --map-auto \
--fork --pid --mount-proc \
--mount \
--mount-proc \
+10 -2
View File
@@ -8,7 +8,6 @@ TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
run "mkdir -p /etc/default"
}
@@ -25,6 +24,15 @@ test_one()
type=$1
service=$2
# Skip systemd tests if serv doesn't have libsystemd support
if [ "$type" = "systemd" ]; then
if ! "$TEST_DIR/src/serv" -C | grep -q "libsystemd"; then
sep
say "Skipping systemd test - serv built without libsystemd support"
return 0
fi
fi
sep
# num=$(run "find /proc/1/fd |wc -l")
@@ -71,7 +79,7 @@ test_one()
assert_status "serv" "running"
assert_cond "service/serv/ready"
# Issue #343; pidfile.so inadvertedly marked systemd services as
# Issue #343; pidfile.so inadvertently marked systemd services as
# 'started' when they created their PID file. The serv test daemon
# waits 3 sec between pidfile and notify to trigger this bug.
if [ "$type" != "pid" ]; then
-5
View File
@@ -5,11 +5,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-5
View File
@@ -9,11 +9,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-1
View File
@@ -8,7 +8,6 @@ TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
run "mkdir -p /etc/default"
}
+5 -11
View File
@@ -1,26 +1,20 @@
#!/bin/sh
# Regression test for basic /etc/rc.local functionality
# shellcheck disable=SC2317
# shellcheck disable=2317,2034
set -eu
RCLOCAL="echo 'KILROY WAS HERE' > /tmp/rclocal"
TEST_DIR=$(dirname "$0")
#DEBUG=1
# shellcheck disable=SC2034
RCLOCAL="echo 'KILROY WAS HERE' > /tmp/rclocal"
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
}
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
sleep 1
assert_file_contains /tmp/rclocal "KILROY WAS HERE"
-5
View File
@@ -4,11 +4,6 @@ set -eu
TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
}
test_teardown()
{
say "Test done $(date)"
-1
View File
@@ -6,7 +6,6 @@ TEST_DIR=$(dirname "$0")
test_setup()
{
say "Test start $(date)"
run "mkdir -p /etc/default"
}

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