Compare commits

...
189 Commits
Author SHA1 Message Date
Joachim Wiberg f32e4d4b30 Update changelog and bump version for v4.2 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-16 05:01:03 +01:00
Joachim Wiberg eff87b3dc5 .github: add basic release general
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-16 05:00:31 +01:00
Joachim Wiberg ea4821fd18 plugins/urandom: fix resource leak, found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-16 04:56:34 +01:00
Joachim Wiberg 6285668dcd .github: action for running coverity scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-16 04:47:51 +01:00
Joachim Wiberg 449bc7d12b Follow-up to 10b72f1: periodically age service crash counter
Traditionally we've reset the service restart counter on two occasions:

  1) when a service reaches its max crash count (default 10), and
  2) when a service somehow "stabilizes"

In the second case the service is restored to normal running state and
we "forget" its bad previous behavior.  Meaning we cannot catch daemons
that act in an unstable manner outside the "rage quit" scenario.

This patch allows for slowing aging (decrementing) the restart counter
once every five minutes.  Meaning we still catch rage quitters but now
are also able catch other types of misbehavior.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-13 23:13:26 +01:00
Joachim Wiberg ee867e7f3b Update ChangeLog
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-13 12:03:12 +01:00
Joachim Wiberg b4c7ae9c8c plugins/bootmisc: check return value from symlink() log on error
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-11 17:20:22 +01:00
Joachim Wiberg 95995a45cf Add total restart counter for service & sysv daemons
This patch adds a recent feature request to keep track of the total
number of restarts (including crashes and initctl restart) of both
service and sysv daemons.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-11 17:18:59 +01:00
Joachim Wiberg 823bb82b8c initctl: display number of restarts and max restarts in job status
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-11 16:19:25 +01:00
Joachim Wiberg 9a5bb46f78 Fix #212: service PID file lost after initctl reload
Clearing of the svc->pidfile was introduced in e1b87d70 for a
restriction that has now been removed.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-11 15:54:53 +01:00
Joachim Wiberg 950ca953f5 Fix #211: drop hard-coded getty limit of 32 characters for usernames
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-11 13:40:07 +01:00
Joachim Wiberg 495c8c9eac Update changelog and bump version for v4.2-rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 21:49:24 +01:00
Joachim Wiberg 2887795586 initctl: minor, coding style cleanup
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 21:49:01 +01:00
Joachim Wiberg 6a893f50ae initctl: refactor has_utmp() capability check to use new cmd conds
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 21:46:22 +01:00
Joachim Wiberg 5d08353284 initctl: minor, fix shadowing of global variable
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 21:38:19 +01:00
Joachim Wiberg a37037ded4 Fix #188: support without cgroups v2 support
This patch adds support for detecting if the Linux kernel Fint runs on
has support for cgroups v2.  The probe is done very early, in runlevel
S, when attempting to mount /sys/fs/cgroup.  Meaning, the log message
may be lost on systems that do not run sysklogd[1].

Here's the relevant logs from a system running myLinux on a kernel
that has cgroups v2 support disabled:

    Jan 10 20:19:40 anarchy finit[1]: myLinux 2021.11-696-g8fddaf36ed, entering runlevel S
    Jan 10 20:19:40 anarchy finit[1]: Kernel does not support cgroups v2, disabling.
    Jan 10 20:19:41 anarchy finit[1]: myLinux 2021.11-696-g8fddaf36ed, entering runlevel 2

All code paths that attempt to set or query kernel cgroups config has
been short circuited when this happens.  However, this does not apply
to any cgroup related config in the Finit .conf files -- which may of
course be omitted.  Yet, if configuration directives exist, they will
be parsed and may cause error.

Also, the initctl tool checks if /sys/fs/cgroup is mounted at runtime
and disables all status output and commands that rely on the feature.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 21:21:35 +01:00
Joachim Wiberg d331b72dfd Relocate ismnt() and fismnt() to util.c, for sharing with initctl
initctl cannot link with helpers.c, so let's relocate these helper
functions to util.c instead.  Need them to probe for cgroup support.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 20:26:37 +01:00
Joachim Wiberg 3b21d35f23 Fix arrow in service desciption ASCII
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-10 13:48:46 +01:00
Joachim Wiberg 62a694b8b7 Prepare ChangeLog for upcoming v4.2 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 08:22:15 +01:00
Joachim Wiberg eeba2960f9 Document new per-service options controlling automatic respawn
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 07:35:33 +01:00
Joachim Wiberg 91550c926b Follow-up to ec2900e: use restart_sec:SEC as canonical option name
A timeout is not the same as a restart delay, which this option really
controls, but the name restart_delay is a bit too long.  Hence, this
obvious name so there's no ambiguity what unit we're dealing with.

Keeping restarttmo:SEC as a compatibility setting for the benefit of
the original authors, for now.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 07:13:06 +01:00
Joachim Wiberg 184525687c Follow-up to ec2900e: minor cleanup + signed vs unsigned comparison
Minor coding style cleanup.  Also, clang complained of a signed vs
unsigned comparison in service_retry(), max(timeout, svc->restart_tmo)

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 06:52:44 +01:00
Joachim Wiberg cdede817fd initctl: new command 'ident [NAME]' shows ids of all/named services
As suggested in issue #197, this new command: 'initctl id [NAME]'
lists identities of all, or named, services.  E.g,

    # initctl id telnetd
    telnetd:23
    telnetd:2323

The NAME argument is optional, when omitted it lists all enabled
run/task/sysv/service in the system, with their full name, and any
optional identitty.  E.g.

    # initctl id
    dropbear
    tty:console
    mdnsd
    mini-snmpd
    smcrouted
    sntpd
    ssdpd
    sysklogd
    watchdogd
    httpd
    telnetd:23
    telnetd:2323

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 06:14:42 +01:00
Joachim Wiberg df42c2f6fe Fix #197: initctl status foo should show overview of foo:1, foo:2 ..
When the system has multiple services 'foo' the initctl command
'status foo' should give a focused overview of all matching foo:*,
whereas a 'status foo:2' should show the detailed view of that
particular instance.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 06:11:57 +01:00
Joachim Wiberg b53f2f4a60 Cleanup, drop now unused internal function svc_is_unique()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 05:34:10 +01:00
Joachim Wiberg 5ff27c4fe2 Allow kernel log messages to console with loglevel=7
Since Finit v4.0 kernel console output has been silenced just prior to
the banner being printed, unless finit.debug mode was enabled.  This
patch makes sure to check the kernel loglevel, if it's >= 7, finit no
longer disables kernel console ouput.

Consequently, you now need 'quiet' on your kernel command line, or a
loglevel < 7 for a quiet boot, at least until a syslogd takes over.

This means that you now can debug the kernel and finit independently,
which should be a great comfort to anyone doing bringup or any form of
kernel debugging.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 01:34:49 +01:00
Joachim Wiberg e5fff5117d Minor, simplify internal API
Cleanup of old cruft.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 01:34:19 +01:00
Joachim Wiberg 615cd5aac3 plugins/urandom: use RNDADDENTROPY ioctl to seed kernel rng
This patch switches from "cp /var/lib/misc/random-seed /dev/urandom"
to use the kernel RNDADDENTROPY ioctl, which actually increments the
entropy count.

Also, the amount of random data saved at reboot is increased from the
fairly low 512 to 32768 bytes.

All in all, this should greatly improve the stability of most systems
during, or close to, bootstrap.  In particular embedded systems with
limited or no HWRNG.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-02 01:04:07 +01:00
Joachim Wiberg 621d95a89e Minor, fix clang warning 'bootstrap shadows local variable'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-01 22:55:07 +01:00
Joachim Wiberg cd383167f9 plugins/rtc: instead of bailing, reset invalid RTC to kernel default
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-01 22:51:45 +01:00
Joachim Wiberg cb2969002c Fix #210: simplify escape code to clear line
Since we just want to clear the complete line, and are already a the
beginning of the line, we can use the simpler \e[K which also seems
to fix the display resize bug in #210.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-01 18:20:47 +01:00
Joachim Wiberg 1cf204e23d Fix #187: fix typos, including slight clean up
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-01-01 16:37:06 +01:00
Joachim Wiberg 393834b253 Follow-up to 4ca8256: ordering mishap
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-12-07 00:13:54 +01:00
Joachim Wiberg 4ca8256e18 Follow-up to 280d91b, fix conio.h namespace
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-12-07 00:05:47 +01:00
Joachim Wiberg 280d91b9bf Add support for new libite (-lite) header namespace
Due to an unfortunate name clash with the DirectFB project LiTE, the
libite (-lite) project had to change its header namespace from

   lite/*.h -> libite/*.h

This patch adds support for the new namepace in Finit, triggered by the
define _LIBITE_LITE, from the .pc file read by pkg-config.  This should
only be needed on systems that install libite without the compatibility
symlink lite -> libite/ in the staging include directory.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-12-06 21:38:20 +01:00
Joachim Wiberg 980152fd53 Add support for non-root users to use initctl, e.g. group wheel
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-11-30 11:44:22 +01:00
Joachim Wiberg d994420d4d plugins: minor coding style cleanup
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-11-10 10:18:02 +01:00
Joachim Wiberg 38f3ecf01f .github: run tests from distcheck
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 12:44:31 +02:00
Joachim Wiberg 5cd0d05b31 .github: install libite and libuev to /usr
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 12:27:33 +02:00
Joachim Wiberg 62519c3638 .github: avoid running tests in parallel
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 10:01:45 +02:00
Joachim Wiberg 27bb2deb1a .github: sudo do what I mean
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:56:19 +02:00
Joachim Wiberg a2c8e71f14 .github: update dynamic linker cache after installing library deps
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:53:26 +02:00
Joachim Wiberg d1f56e7c2e .github: adjust path for showing finit & intictl usage text
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:46:19 +02:00
Joachim Wiberg a9fd0cbf02 .github: simplify and fix install path
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:32:38 +02:00
Joachim Wiberg be8c89ec00 Bump version for v4.2 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:28:44 +02:00
Joachim Wiberg 4f53752693 .github: install support libs to /usr/local
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:26:54 +02:00
Joachim Wiberg 393673222d Replace Travis-CI with GitHub Actions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-23 09:05:38 +02:00
Joachim Wiberg a88f4524d5 Merge pull request #208 from liuming50/support-more-specific-control-of-services
service.c: add more parameters when starting services
2021-09-23 08:46:42 +02:00
Joachim Wiberg 3a02066a66 Merge pull request #206 from liuming50/dont-hard-code-dbus-user-pidfile
dbus: dont hard-code daemon user/pidfile
2021-09-23 08:31:19 +02:00
Joachim Wiberg 7e3981d1a3 Merge pull request #205 from liuming50/fix-a-wrong-header-include
Fix a header including syntax
2021-09-23 08:30:20 +02:00
Robert Andersson ec2900e4dd service.c: add more parameters when starting services
It would be good if we can control the services more specifically with
the following parameters like:

restart:N   - how many times shall the service to be restarted on
              failures (<10), the default max is 10.
restart_tmo - the timeout of the restarting.
norestart   - dont restart on failures.
oncrash     - once all retrying also fail, how to deal with it,
              rebooting or ignoring the failures.

Signed-off-by: Robert Andersson <robert.m.andersson@atlascopco.com>
Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-09-21 10:55:29 +02:00
Ming Liu d718a27abf dbus: dont hard-code daemon user/pidfile
Both DBUS user and pidfile is configurable in DBUS compilation, by
passing "--with-dbus-user=" and "--with-system-pid-file=", let's avoid
hard-coding them here, use macros instead.

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-09-21 10:48:25 +02:00
Ming Liu db8027911c Fix a header including syntax
Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-09-21 10:47:15 +02:00
Joachim Wiberg aef3b4117d Merge pull request #200 from liuming50/dont-hard-code-nologins-file
Dont hard-code nologin file
2021-09-18 09:48:43 +02:00
Ming Liu 6728b77aca Dont hard-code nologin file
It's configurable in /etc/login.defs as NOLOGINS_FILE, avoid to hard
coding it here, introduce a macro FINIT_NOLOGIN_PATH instead which is
configurable from compiler flags, it's not defined, then back to
_PATH_NOLOGIN from /usr/include/paths.h.

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-09-17 13:10:01 +02:00
Ming Liu a7c0b42965 configure.ac: add fastboo/fsckfix to config summary output
Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-09-10 11:35:45 +02:00
Joachim Wiberg 667b6ecbbd Merge branch 'liuming50-introduce-two-more-config-options' 2021-09-09 09:10:46 +02:00
Joachim Wiberg b852878a4a Follow-up, coding style fixes
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-09 09:10:16 +02:00
Ming Liu 940f1f7486 Introduce two more configure options
fastboot: once enabled, fsck would be skipped on filesystems listed in
          /etc/fstab.
fsckfix: once enabled, 'fsck -ys' would be run instead of 'fsck -a',
         and check the return value larger than 1 as a failure and goes
         to login console.

They are both disabled by default, no functional changes unless an end
user choose to enable them.

The idea derives from Sysvinit's "FASTBOOT" and "FSCKFIX".

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-09-09 09:08:14 +02:00
Joachim Wiberg 49c705b5ad Merge pull request #201 from liuming50/fix-a-memleak
Fix a memleak.
2021-09-09 09:04:42 +02:00
Joachim Wiberg 5163e8a433 Merge pull request #198 from timgates42/bugfix_typos
docs: Fix a few typos
2021-09-09 08:56:07 +02:00
Joachim Wiberg 71e9603e4e Merge pull request #199 from liuming50/drop-c++-key-word
Avoid using C++ key words
2021-09-09 08:55:39 +02:00
Joachim Wiberg c71102f44e Merge branch 'liuming50-fix-a-unmount-issue' 2021-09-09 08:51:41 +02:00
Joachim Wiberg 9b9158a765 Follow-up, coding style and drop extra print()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-09-09 08:51:26 +02:00
Robert Andersson 595e2b4e81 Ensure all filesystems listed in /proc/mounts are unmounted
The iterator function getmntent() is not stable. It may skip
entries if the contents of the iterated file changes, which
is the case with /proc/mounts when filesystems are unmounted.
As a result, some filesystems were never unmounted.

To fix this, iteratation is now restarted after every
sucessful unmount.

Signed-off-by: Robert Andersson <robert.m.andersson@atlascopco.com>
Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-08-30 10:16:00 +02:00
Ming Liu ae8e205343 Fix a memleak.
Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-08-29 14:02:04 +02:00
Ming Liu 00b33fbd42 Avoid using C++ key words
"protected" is a C++ key word, replace it with "is_protected" avoid
compiling failures with C++ compiler.

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2021-08-29 10:35:08 +02:00
Tim Gates 841b06df37 docs: Fix a few typos
There are small typos in:
- doc/conditions.md
- src/mount.c
- src/svc.h

Fixes:
- Should read `satisfied` rather than `satsifed`.
- Should read `process` rather than `prorcess`.
- Should read `measure` rather than `meausre`.
2021-08-27 06:23:04 +10:00
Joachim Wiberg 522a06f864 Merge pull request #181 from yangfl/typo
Fix typo
2021-06-25 07:43:08 +02:00
yangfl fa14ed1649 Fix typo
with the love from codespell
2021-06-25 13:08:14 +08:00
Joachim Wiberg 64e41e066b Change default loglevel to LOG_INFO from LOG_NOTICE
We've had several logit() messages of LOG_INFO level that never
really made it to syslog because we classified it as "debug".

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-22 17:20:17 +02:00
Joachim Wiberg 2a71f35005 Reduce log level of watchdog handover, this is not an error condition
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-22 17:20:17 +02:00
Joachim Wiberg 961a337a5e Minor, we no longer know if it's an external or bundled getty
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-22 17:20:17 +02:00
Joachim Wiberg f0622a692e Minor, format style change of comment block
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-22 17:20:17 +02:00
Joachim Wiberg ef7042dd9d finit: early log, "entering runlevel S", just after printing banner
This patch adds "the missing" first runlevel log entry when Finit has
printed the console banner and begins its bootstrap phase.

At this point we know syslogd hasn't been started yet, so we rely on
logit() to redirect this to /dev/kmsg in the meantime.  Later syslogd
will pick this up, see that it's not from the kernel, and log it to
the proper log file.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-22 17:20:17 +02:00
Joachim Wiberg 046ecfa329 Fix #180: user managed services started by initctl reload
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-14 13:16:14 +02:00
Joachim Wiberg 47fbe49861 Wrap all mount(2) calls so we at least get an error message
If any of these mount() calls fail, not counting EBUSY because that
would mean sth is already mounted, there really isn't much we can do.
So the least we should do is warn on console if it happens.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-14 11:20:08 +02:00
Joachim Wiberg 2f34315634 fnread(): make sure to NUL terminate buffer
Note, this is dead code, currently unsused in Finit.  Possibly an
external plugin makes use of it, but even that is highly unlikely.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-14 11:19:57 +02:00
Joachim Wiberg c8d6ad6546 Bump version for v4.1 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 17:30:48 +02:00
Joachim Wiberg 3dfae3074e Revert "Travis-CI: disable clang for Coverity run"
This reverts commit 8e1845f57b.
2021-06-06 17:05:09 +02:00
Joachim Wiberg 97bebe52c9 Fix logic expression in release_heading(), found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 16:57:52 +02:00
Joachim Wiberg 8e1845f57b Travis-CI: disable clang for Coverity run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 16:50:51 +02:00
Joachim Wiberg 6cd6769997 Update ChangeLog and drop man page TODO
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 16:46:59 +02:00
Joachim Wiberg 03884d3566 doc: fix minor issues, drop 'simply', nothing's simple ..
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 16:35:57 +02:00
Joachim Wiberg 899925e249 man: initial manual page for finit.conf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 16:35:37 +02:00
Joachim Wiberg efefa398ce man: initial manual page for initctl
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 12:57:21 +02:00
Joachim Wiberg 1ee24c69bc Sync with man page
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 12:50:03 +02:00
Joachim Wiberg b16a36980c man: initial manual page for finit
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 12:50:03 +02:00
Joachim Wiberg c1b52bbc04 contrib: debian: depending on the setup, a user may not need elogind
I'm writing this in X started on a system running Finit v4.1-pre that
does not have elogind installed.  It does, however, still have systemd
installed, so systemd-logind is available.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 09:05:13 +02:00
Joachim Wiberg 9461ad4d4d doc: add reminders about limitations to sys conditions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 09:04:45 +02:00
Joachim Wiberg e2ef6e9c34 plugins: sys: drop conditions not affecting any svc_t
- Fix bug when calling sys_update_conds() when dir already exists
  and we're not being called from the scandir() handler.  I.e.,
  every time but the first for each new condition sub-family

- Drop sys conditions that don't affect any svc_t.  This may seem
  counterintuitive, and we should probably not use oneshot conds,
  but if we leave these conds asserted they may cause inadvertent
  trigger if a finit.conf is loaded which ha this sys cond.  E.g.,
  if ctrlaltdel is asserted and we enable a task in finit.conf and
  call `initctl reload`, the task would start immediately, even
  though ctrl-alt-del may have been pressed a week ago

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 00:34:11 +02:00
Joachim Wiberg cdc8873f5b Let cond_update() return if any svc_t was affected
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-06 00:33:36 +02:00
Joachim Wiberg b82b205d92 contrib: debian: install available python-quit.conf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-05 23:35:26 +02:00
Joachim Wiberg 39d879f240 Add support for auto-detetcing OS heading for progress
This patch removes the cognitive overhead of having to manually set your
OS heading, --with-heading="Foo OS vX.YY".  As of this patch, Finit by
default extracts PRETTY_NAME from /etc/os-release.  It is now possible
to also disable the heading entirely using --without-heading

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-05 14:28:49 +02:00
Joachim Wiberg 9c1db9cab3 contrib: drop os marker files, check Makefile instead
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-05 14:28:49 +02:00
Jacques de Laval 2f5c00f2bd Also accept \n for "Please press Enter to activate ..."
Shouldn't be needed for real cases, but we have seen automated scripts send
'\n' instead of '\r', or '\r' + '\n'.

Signed-off-by: Jacques de Laval <Jacques.De.Laval@westermo.com>
2021-06-04 13:20:14 +02:00
Joachim Wiberg dc36b313ff getty: attempt to steal ctty if don't already have it
This fixes the following classic problem

    login: root
    -sh: can't access tty; job control turned off

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-04 08:39:48 +02:00
Joachim Wiberg 093fa0107a getty: skip 5 sec delay introduced in 94c0d1b refactor
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-04 08:33:58 +02:00
Joachim Wiberg e8f5ec2579 Simplify, drop SYNC_SHUTDOWN state file, not needed anymore
Similar to 6224166 (previous commit), this old code is a remnant of a
bygone era and not needed anymore.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-03 12:51:59 +02:00
Joachim Wiberg 62241668df Drop SIGSTOP/TSTP/CONT handlers, not needed anymore
Once upon a time, SIGSTOP was used to pause Finit during flashing (MTD)
of a system image.  This to prevent Finit from accidentally starting any
programs, i.e., reading from flash disk during or after upgrade.

This was quite intrusive, and has possible nasty side effects, e.g., any
process with root access sends SIGSTOP prevents TTY login.  So this patch
now removes the functionality and recommends using a dedcicated runlevel
for such critical tasks instead.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-03 12:18:08 +02:00
Jacques de Laval ee67c08b64 Reset the starting flag of a service when stopping it
When a service is started and then stopped before it has created it's pid file,
it could be left forever in the "stopping" state, if we don't reset the
starting flag.

Signed-off-by: Jacques de Laval <Jacques.De.Laval@westermo.com>
2021-06-02 17:01:01 +02:00
Joachim Wiberg 41a14391a2 Refactor sigchld_cb(), handle EINTR properly, restart waitpid()
The waitpid() function can return -1 due to EINTR (signal), so we should
restart it to make sure we collect all zombies.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-02 16:34:24 +02:00
Joachim Wiberg 6eccca31b9 contrib: debian: task to stop any running plymouth boot screen
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-02 08:57:36 +02:00
Joachim Wiberg d497942a9f contrib: debian: speling error demon vs daemon
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-02 08:55:29 +02:00
Joachim Wiberg 68c7352108 Update ChangeLog and bump version for 4.1-rc2
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-01 16:16:00 +02:00
Joachim Wiberg 0d40e43c4b Update ChangeLog with fixes for containers
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-01 13:33:35 +02:00
Joachim Wiberg 9867fd82df Check correct struct member to determine if / has 'ro' flag
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-01 12:50:48 +02:00
Joachim Wiberg 1c941fdfbb plugins: add support for disabling RTC and urandom plugins
Some systems may want to handle RTC and /dev/urandom by themselves, or
not at all as in the case of containers where the host does all this.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-01 11:43:58 +02:00
Joachim Wiberg 0ba67a72f8 plugins: add missing x11-common plugin to static libplug.la
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-01 11:43:26 +02:00
Joachim Wiberg 09b9e26b2d fs_init(): skip mounting proc/dev/sys if already mounted
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 17:35:07 +02:00
Joachim Wiberg d25c1d5564 logit: avoid modifying argv[] strings
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 17:03:10 +02:00
Joachim Wiberg d4358ed3f7 Drop nasty hide_args() hack, should not be needed anymore
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 16:51:08 +02:00
Joachim Wiberg cc6ffa35fc Drop parsing of /proc/cmdline by default, instead use argc + argv[]
For most use-cases the kernel will give Finit its arguments as proper
command line args in argc + argv[], like any other program.  However,
for some users, most notably Alpine Linux, there is a slightly broken
initramfs that cannot forward more than one argument using init_args,
for such systems you can re-enable the old behavior with a configure
switch --enable-kernel-cmdline -- it's not ideal but what can you do.

The main reason for removing this feature by default is to support
use-cases where Finit runs as the init for container apps that can read
/proc -- we do not want them to use the init args from the host.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 16:51:08 +02:00
Joachim Wiberg 55e9cb2f58 Update with info on dropped multiple consoles
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 13:59:21 +02:00
Joachim Wiberg 2641256254 plugins: sys: no need to compose path, name is already absolute path
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 13:58:30 +02:00
Joachim Wiberg 473116f603 Drop experimental multiple console output support
It has barely worked and only caused more problems than solved annoying
issues.  We have one console for output, /dev/console, which the kernel
sets up for us.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 10:48:37 +02:00
Joachim Wiberg e18d63df4a Always make sure to not acquire controlling TTY for output redirect
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 10:48:04 +02:00
Joachim Wiberg 4b1b3f6913 Update ChangeLog with latest changes
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 09:35:20 +02:00
Joachim Wiberg f6da5e4136 Revert "Travis-CI: disable clang temporarily for Coverity Scan run"
This reverts commit 754358113f.
2021-05-31 07:48:49 +02:00
Joachim Wiberg d1d5d39144 Fix possible NULL ptr deref, found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 07:43:29 +02:00
Joachim Wiberg 754358113f Travis-CI: disable clang temporarily for Coverity Scan run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 07:27:12 +02:00
Joachim Wiberg c24207516d keventd: properly zero terminate buffer, found by Coverity Scan
Also, fix default: case in error handling, must always continue back to
poll() on any recv() error.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 07:22:50 +02:00
Joachim Wiberg 2a23bce78d Hide progress output also on stop/shutdown for services w/o -- descr
Progress at startup has been hidden for services w/o -- description, but
for some reason this check was not added to service_stop().  This patch
rectifies the situation, finally.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 07:17:48 +02:00
Joachim Wiberg a19b82ea5f Allow tty's to always respawn, no max restart count
This patch adds a `respawn` flag for services and ttys, always set for
ttys, that allows bypassing the crash/restart counter and immediately
restart a 'crashing' service.

For tty type services this is the expected behavior, but for regular
services it is not.  That is why `respawn` flags is not advertised in
the docs.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 06:29:11 +02:00
Joachim Wiberg ed9590aef1 Fix tty default :ID => tty:S0 instead of tty:ttyS0
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-31 06:27:59 +02:00
Joachim Wiberg 25683221cc Set default envs like sysvinit and busybox does; TERM, LOGNAME, USER
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 13:22:50 +02:00
Joachim Wiberg 9cc9e3ddbb getty: if we cannot execute /bin/login, try sulogin before /bin/sh
Basic security measure, don't bail to shell if we cannot find/exec
login, instead try sulogin before falling back to plain shell.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 12:42:48 +02:00
Joachim Wiberg 654f8aeb19 getty: handle variable number of arguments, only tty required
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:55:21 +02:00
Joachim Wiberg e349abb897 stty: allow utf8 input characters
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 3027a6755f Adjust logic in finding system consoles for progress/debug output
By default, Linux gives us /dev/console for output.  This is a pseudo
device that uses the same actual device as the last console=foo listed
in /proc/cmdline.  The last one listed is the main console, which is
also the *first* one listed in /sys/class/tty/console/active, so we skip
that when we check for system consoles to avoid duplicating output.

The getty code in tty.c currently has its own handling of @console,
which we keep for now.  Ideally, however, the code should be merged.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 5404aa6037 Refactor run_getty() and run_getty2() into one
By moving the built-in getty to a stand-alone bundled getty we can now
refactor the old run_getty() functions into a single one.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg a319e32438 Clean up prepare_tty()
When TTYs became first class citizens in Finit 4.0 much of the
boilerplate setup is now down by service_start().  Also, the calls to
TIOCSCTTY, VINTR, and SIGINT ignore is not necessary to do here, it
should be done by the getty used, if any.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 2eaf57fc67 stty: simplify and ignore BREAK/SIGINT
It is up to /bin/login, sulogin, or plain shells to unblock SIGINT.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 88ec4a55cb Call setsid() before redirecting stdio or unblocking signals
We must detach from the controlling TTY before enabling signals and
setting up new stdio.  TTYs have their own handling of stdio.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 0acbc60ec1 initctl: drop confusing 'errno 0' from "Timed out" message
errno is not set when we timeout waiting for a reply from Finit.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 4362971c6a run(): Drop extra sig_unblock()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 94c0d1b833 Refactor built-in getty into a standalone getty in /libexec
This patch moves the built-in getty out of Finit into /libexec/finit/,
reducing the size of the Finit binary and simplifying the code.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 11:26:41 +02:00
Joachim Wiberg 1e795d4e16 Fix #175: Ensure finit does not acquire 'dev' as controlling TTY
When starting a getty Finit checks first that the configured TTY device
actually exists and is a TTY.  This patch, by Tobias Waldekranz, ensures
Finit (PID 1) doesn't acquire the TTY device as a controlling TTY.  If
that happens PID 1 will get all signals sent to the process actually
started with the device as its controlling TTY.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-30 00:33:31 +02:00
Joachim Wiberg 93a027ca23 plugins: netlink: fix gcc signed vs unsigned comparsion warning
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-27 11:18:06 +02:00
Joachim Wiberg 5f3958fab4 getty: max username is 32 chars, according to useradd(1)
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-27 11:18:06 +02:00
Joachim Wiberg 1351b708fe Fix parse error for detecting external getty
When an external getty is used, and an absolute path is not given, the
parser tried to use access() to determine built-in vs external getty.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-27 11:18:06 +02:00
Joachim Wiberg e867e039bb Follow-up, document SIGINT/SIGPWR in comment, add missing include
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-27 11:18:06 +02:00
Joachim Wiberg 1d1087a3b3 Merge pull request #174 from troglobit/fix-kmsg-log-level
logging: Disregard logging facility when comparing log levels
2021-05-20 19:00:08 +02:00
Jacques de Laval e91f1ea1b2 logging: Disregard logging facility when comparing log levels
If we don't extract the level (disregarding facility), statements such as
"logit(LOG_CONSOLE | LOG_NOTICE, ...)" would never reach the kernel log.

Signed-off-by: Jacques de Laval <Jacques.De.Laval@westermo.com>
2021-05-20 17:19:53 +02:00
Joachim Wiberg 55d16edadc contrib: update /etc/finit.conf examples
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-18 09:02:58 +02:00
Joachim Wiberg b79245ddb3 Add support for sys/pwr/fail and sys/key/ctrlaltdel conditions
This patch drops the default signal handlers for SIGPWR and SIGINT with
optional tasks in /etc/finit.conf, triggered by two new conditions:
sys/pwr/fail and sys/key/ctrlaltdel, respectively.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-18 08:58:11 +02:00
Joachim Wiberg e706300b6d keventd: rename fgetln() -> fgetline()
Apparently fgetln() is available in musl libc, but not glibc.  This is a
funciton that first appeared in 4.4BSD.  We take a risk that fgetline()
is free in all libc's, getline() is not.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-17 00:44:39 +02:00
Joachim Wiberg d08cbd77aa keventd: use poll.h, not sys/poll.h, fix warning on musl libc
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-17 00:41:35 +02:00
Joachim Wiberg b070ae73a4 Revert "Travis-CI: disable clang temporarily for Coverity Scan run"
This reverts commit f52c141062.
2021-05-17 00:33:30 +02:00
Joachim Wiberg 2c30eef9a1 Update changelog for v4.1 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-17 00:32:43 +02:00
Joachim Wiberg 31cdc113fc doc: update build instructions and examples
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-17 00:32:21 +02:00
Joachim Wiberg f6f813498b doc: add some info about keventd, what it does
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-17 00:32:11 +02:00
Joachim Wiberg 4c8baaf7c0 Make kevent a configure option, disbled by default
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-17 00:26:57 +02:00
Joachim Wiberg 57ca937f27 New function to create onshot conds without updating
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-16 23:37:41 +02:00
Joachim Wiberg d13e39e345 keventd ftbfs: add missing include path to libite
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-16 23:35:39 +02:00
Joachim Wiberg f52c141062 Travis-CI: disable clang temporarily for Coverity Scan run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-16 23:21:31 +02:00
Joachim Wiberg 40042da8ff contrib: debian: add anacron and cron services
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-15 10:36:05 +02:00
Joachim Wiberg c251304146 Refactor sys condition plugin into a standalone keventd
This patch is a refactor of the prototype sys condition plugin.  It
moves most of the logic to monitor kernel events into a keventd that,
currently only, sets and clears the sys/pwr/ac condition.  The sys
plugin itself is now only a monitor of conditions and ensures Finit
follows them.  This is a lot more secure and moves (at least one piece
of) netlink processing out from PID 1.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-15 10:31:08 +02:00
Joachim Wiberg c047e37a79 cgroup: ensure all services in init group remain as leaf nodes
The top-level cgroup init is a leaf group and should be treated as such,
even for user setup tasks/services.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-15 10:29:29 +02:00
Joachim Wiberg d2c57447f0 initctl: no error if failing to remove non-existing usr condition
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-15 10:29:01 +02:00
Joachim Wiberg 79e9dabc11 Fix bug: re-registering a former service as task does not work
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-15 10:28:29 +02:00
Joachim Wiberg b04dc4d457 Ensure services in plugins and from finit.c belong to a cgroup
The udevd, dbus, bundled watchdog, and others were started without a
valid cgroup.  This is a workaround to ensure they are assigned one.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-15 10:27:59 +02:00
Joachim Wiberg f86e7810be sig.c: disable kernel default ctrl-alt-delete handler
This fixes a long-standanding issue with finit not controlling the
reboot when the user presses ctrl-alt-delete (PC systems).

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-14 10:34:54 +02:00
Joachim Wiberg 2018c82ea1 plugins: sys: watch uevent to prevent feedback loop
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-13 21:20:08 +02:00
Joachim Wiberg c27f3603e6 plugins: sys: use counting semaphores to handle >1 AC supply
- Track number of ac and ac online
 - Use systemd logic to assert sys/pwr/ac also when no supply

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-13 08:45:49 +02:00
Joachim Wiberg 6f82b806ad plugins: new sys condition event monitor (wip)
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-11 07:02:49 +02:00
Joachim Wiberg cbb8935660 New functions: fnread() and fngetint(), companions to fnwrite()
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-11 07:02:30 +02:00
Joachim Wiberg 21ebbb942f plugins: bootmisc: minor, whitespace
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg 988ecd95e3 plugins: bootmisc: only create /run/lock if missing
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg 3f3e70c686 Mount /dev/pts with gid of tty group and set nosuid, noexec flags
Note, this code only runs if /dev/pts was not mounted in /etc/fstab

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg 073b040981 Prevent user DoS by mounting /run/lock as separate tmpfs
This patch does several things related to /run and system reliability.

 - Mount /run with MAX 10% of usable RAM
 - Create and mount /run/lock as a separate tmpfs with max 5 MiB

As a spin-off, this patch also fixes permisions on /run/lock to 0777
so regular users can create lock files.

Note: none of this code runs if /run is mounted alread in /etc/fstab

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg b1a058ccdd doc: update TODO a bit, remember -s for initctl
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg cbc7b8c3c7 plugins: bootmisc: add S02sudo setup for Debian systems
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg 13340e4200 contrib: debian: start tty's on tty1-tty6 clear 2-6
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg 0076c1f218 contrib: debian: add apparmor, avahi, and bluetooth services
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg 6fc71b7528 Follow-up to a1af8e8: mount /tmp with perms for all users
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-09 14:38:16 +02:00
Joachim Wiberg b42f1e99e2 README: use absolute path in sshd example, it requires that
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 22:29:23 +02:00
Joachim Wiberg afd6ad06a6 README: drop urls from initctl help text to sync with app
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 22:28:50 +02:00
Joachim Wiberg ea0bfaa2f3 Revert "Travis-CI: disable clang temporarily for Coverity Scan run"
This reverts commit 40425ee9ec.
2021-05-07 21:15:37 +02:00
Joachim Wiberg 5c3ec176c2 Update changelog, issue #173
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 20:19:31 +02:00
Joachim Wiberg 40425ee9ec Travis-CI: disable clang temporarily for Coverity Scan run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 19:45:28 +02:00
Joachim Wiberg 424db825a3 plugins: netlink: error handling fixes
Handle EAGAIN properly, for both regular and resync flow, on any error
in the regular flow (unless ENOBUFS) we want to check for nl_ifdown on
any of the successfully parsed messages.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 17:02:09 +02:00
Joachim Wiberg b9cc4cd629 Revert "plugins: fix #173, increase size of netlink socket receive buffer"
This reverts commit add55cfc2a.
2021-05-07 16:50:04 +02:00
Joachim Wiberg 243b8f025b plugins: netlink: refactor and reduce recv() buffer
This patch adds support for calling recv() repeatedly to get the netlink
response from the kernel.  As a result, the recv() buffer can be reduced
down to 4k again.

Both the regular flow and the resync flow now follow the exact same code
path, except for the ENOBUFS handling.  If we get ENOBUFS in resync, we
are screwed anyway.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 16:42:42 +02:00
Joachim Wiberg 6c60b67588 plugins: netlink: fix resync request size alignment with kernel
For RTM_GETLINK we need a `struct ifinfomsg`, not `struct rtmsg`,
otherwise the kernel will get 8 extra bytes and complain about it.

This patch makes sure to set the correct iface change mask as well, and
increases the debug logs a bit to get a fix on sizes used.  We increase
the recv() buffer 8k -> 64k to make sure we can get all data in one big
swoop.  Plan is to refactor this mess in a later commit.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 15:20:25 +02:00
Joachim Wiberg 910bb13711 plugins: netlink: redesign to handle ENOBUFS with kernel resync
This is a major redesign of the netlink plugin to be able to handle
ENOBUFS¹ properly.  Pending verification, this change replaces the patch
to increase socket buffer size, which in real life turned out to be
insufficient.

When nl_callback() calls recv() and it fails with ENOBUFS, we consider
our cache of the kernel state invalid and thus:

  1. deassert all net/ conditions
  2. open a new (temporary) netlink socket
  3. send RTM_GETLINK  and re-assert all interfaces using nl_link()
  4. send RTM_GETROUTE and re-assert all routes with nl_route()

Like before, the kernel will not send us a RTM_DELROUTE when it removes
the default route, so we still have to track this ourselves.  This patch
also refactors that functionality to only resync routes when the ifindex
associated previosly with the default route goes down or is removed.

The previous change that added nl_default() to recheck, has been dropped
to instead reuse the standard nl_route() callback.
___
¹ see netlink(7) for details.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-07 13:06:47 +02:00
Joachim Wiberg add55cfc2a plugins: fix #173, increase size of netlink socket receive buffer
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-04 13:19:54 +02:00
Joachim Wiberg 565820325b Follow-up to a1af8e8: nodev is a mount flag as well
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-04 07:36:41 +02:00
Joachim Wiberg 6bb4d67d92 Follow-up to a1af8e8: fix mount options vs mount flags
The nosuid, noexec, and relatime arguments are not mount options, but flags.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-04 07:34:39 +02:00
111 changed files with 4034 additions and 1048 deletions
+68
View File
@@ -0,0 +1,68 @@
name: Bob the Builder
# Run on all branches, including all pull requests, except the 'dev'
# branch since that's where we run Coverity Scan (limited tokens/day)
on:
push:
branches:
- '**'
- '!dev'
pull_request:
branches:
- '**'
jobs:
build:
# Verify we can build on latest Ubuntu with both gcc and clang
name: ${{ matrix.compiler }}
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [gcc, clang]
fail-fast: false
env:
MAKEFLAGS: -j3
CC: ${{ matrix.compiler }}
steps:
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.3.2.tar.xz
tar xf libite-2.3.1.tar.gz
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig
- uses: actions/checkout@v2
- name: Static Finit
run: |
./autogen.sh
./configure --prefix= --enable-static
make V=1
- name: Regular Finit
run: |
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
make clean
make V=1
- name: Install to ~/tmp and Inspect
run: |
DESTDIR=/tmp make install-strip
tree /tmp
ldd /tmp/sbin/finit
size /tmp/sbin/finit
ldd /tmp/sbin/initctl
size /tmp/sbin/initctl
ldd /tmp/sbin/reboot
size /tmp/sbin/reboot
/tmp/sbin/finit -h
/tmp/sbin/initctl -h
- name: Run Unit Tests
run: |
make -j1 distcheck
- name: Upload Test Results
uses: actions/upload-artifact@v2
with:
name: finit-test-${{ matrix.compiler }}
path: test/*
+63
View File
@@ -0,0 +1,63 @@
name: Coverity Scan
on:
push:
branches:
- 'dev'
env:
PROJECT_NAME: finit
CONTACT_EMAIL: troglobit@gmail.com
COVERITY_NAME: troglobit-finit
COVERITY_PROJ: troglobit%2Ffinit
jobs:
coverity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: coverity-toolchain-cache
with:
path: cov-analysis-linux64
key: ${{ runner.os }}-coverity
- name: Download Coverity Scan
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
-O cov-analysis-linux64.tar.gz
mkdir cov-analysis-linux64
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.3.2.tar.xz
tar xf libite-2.3.1.tar.gz
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig
- name: Build
run: |
./autogen.sh
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
cov-build --dir cov-int make
- name: Submit result to Coverity Scan
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
tar czvf ${PROJECT_NAME}.tgz cov-int
curl \
--form project=${COVERITY_NAME} \
--form token=$TOKEN \
--form email=${CONTACT_EMAIL} \
--form file=@${PROJECT_NAME}.tgz \
--form version=trunk \
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
+69
View File
@@ -0,0 +1,69 @@
name: Release General
on:
push:
tags:
- '[0-9]+.[0-9]+'
jobs:
release:
name: Create GitHub release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
release_id: ${{ steps.create_release.outputs.id }}
steps:
- uses: actions/checkout@v2
- name: Extract ChangeLog entry ...
# Hack to extract latest entry for body_path below
run: |
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|head -n -1 > release.md
cat release.md
- name: Create release ...
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Finit v${{ github.ref }}
body_path: release.md
draft: false
prerelease: false
tarball:
name: Build and upload release tarball
needs: release
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Installing dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.3.2.tar.xz
tar xf libite-2.3.1.tar.gz
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig
- name: Creating Makefiles
run: |
./autogen.sh
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
- name: Building release
run: |
make release
ls -lF ../
mkdir -p artifacts/
mv ../*.tar.* artifacts/
- name: Uploading release artifacts
uses: skx/github-action-publish-binaries@release-0.15
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
releaseId: ${{ needs.release.outputs.release_id }}
args: artifacts/*
-62
View File
@@ -1,62 +0,0 @@
# Travis CI integration -- https://travis-ci.org/troglobit/finit
# Defaults to GNU GCC and autotools: ./configure && make && make test
language: c
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
sudo: false
# Test build with both GCC and Clang (LLVM)
compiler:
- gcc
- clang
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
env:
global:
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig
- CFLAGS="-W -Wall -Wextra"
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
addons:
apt:
packages:
- tree
coverity_scan:
project:
name: "troglobit/finit"
description: "finit | Fast & Extensible init for Linux"
notification_email: troglobit@gmail.com
build_command_prepend: "./autogen.sh && ./configure --prefix= --disable-doc --disable-contrib --with-watchdog"
build_command: "make"
branch_pattern: dev
install:
- wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
- wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
- tar xf libuev-2.3.2.tar.xz
- tar xf libite-2.3.1.tar.gz
- (cd libuev-2.3.2 && ./configure --prefix=/tmp && make && make install-strip)
- (cd libite-2.3.1 && ./configure --prefix=/tmp && make && make install-strip)
# Custom build script for the time being, no "make test" yet
script:
- ./autogen.sh
- ./configure --prefix= --enable-static
- make clean
- make V=1 -j5
- ./configure --prefix= --enable-x11-common-plugin --with-watchdog
- cat config.log
- make clean
- make V=1 -j5
- make install-strip DESTDIR=/tmp/finit
- tree /tmp/finit
- ldd /tmp/finit/sbin/finit
- size /tmp/finit/sbin/finit
- size /tmp/finit/sbin/initctl
- size /tmp/finit/sbin/reboot
- LD_LIBRARY_PATH=/tmp/lib /tmp/finit/sbin/initctl -h
- unshare -V
- nsenter -V
- chroot --version
- 'LD_LIBRARY_PATH=/tmp/lib make distcheck || (cat finit-4.0-beta1/_build/sub/test/test-suite.log; exit 1)'
+151 -11
View File
@@ -4,10 +4,75 @@ Change Log
All relevant changes are documented in this file.
[4.1][UNRELEASED]
-----------------
[4.2][] - 2022-01-16
--------------------
Bug fix release.
### Changes
* Support for non-root users to use `initctl`, e.g. group wheel
* Support for new libite (-lite) header namespace
* RTC plugin now reset an invalid RTC time to the kernel default
time, 2000-01-01 00:00, prevents errors and is less crazy than
some systems coming with with <= Jan 1, 1970
* urandom plugin now use RNDADDENTROPY ioctl to seed kernel rng,
incrementing entropy count. Also, 32 kiB instead of 512 bytes are
now saved (and restored) on reboot. This should greatly improve
reliability of systems with none or poor HWRNG
* Kernel logging to console (loglevel >= 7, debug, when quiet mode is
not used) is now honored by Finit, regardless of the finit.debug
command line option
* Reduced default log level from `LOG_NOTICE` to `LOG_INFO`
* Wrapped all calls to mount(2) to add logging in case of failure
* New configure options to control fastboot (no fsck) and fsck fix
options, by Ming Liu, Atlas Copco
* Support for overriding default `/etc/nologin` file with an external
`#define`, by Ming Liu, Atlas Copco
* Support for overriding default `/var/run/dbus/pid` file with an
external `#define`, by Ming Liu, Atlas Copco
* Support for more service options to control respawn behavior of
crashing services, by Robert Andersson and Ming Liu, Atlas Copco
* Support for `initctl ident [NAME]` which lists all instances of
`NAME`, or all enabled system run/tasks and services
* Show number of total restarts and current respawn count for a
service in `initctl status foo`
* Crashing services no longer have the crash/restart counter reset as
soon as they have stabilized. Instead, a background timer will
slowly (every 300 sec) age (decrement) the counter. This will still
catch services that "rage quit", but also those that crash after a
longer period of activity
### Fixes
* Fix #180: user managed (`manual:yes`) services accidentally started
by `initctl reload`, regression introduced in Finit v4.0
* Fix #181: lots of typos all over the tree, by David Yang, Debian
* Fix #187: fix typos, incl. small cleanup, in doc/bootstrap.md
* Fix #188: support running on kernels that do not have cgroups v2.
When this is detect, all functions related to cgroups support in
Finit are disabled, *except* the .conf file parser. Hence, you
may get parse error if you have invalid cgroup configuration in
your Finit .conf files
* Fix #197: `initctl status foo` now shows a focused overview of all
matching instances; foo:1, foo:2 -- if only one instance matches the
command line argument, or if onle one instance exists, the detailed
view is shown, as before
* Fix #198: a few typos found by Tim Gates
* Fix #199: avoid using C++ reserved keywords
* Fix #201: memory leak in usr condition plugin, by Ming Liu, Atlas Copco
* Fix #203: ensure all filesystems listed in /proc/mounts are properly
unumounted on shutdown/reboot, by Robert Andersson, Atlas Copco
* Fix #210: resizing terminal (smaller) after boot causes empty lines
to be inserted between boot progress
* Fix #211: drop hard-coded 32 character limit in getty, now reads
`_SC_LOGIN_NAME_MAX` from `sysconf(3)`
* Fix #212: service PID file lost after inictl reload, visible from
the output from `initctl status foo`
[4.1][] - 2021-06-06
--------------------
Bug fix release. Also disables handlers for `SIGINT` and `SIGPWR`, a
new set of `sys` conditions are instead generated which can be used to
trigger external programs.
### Changes
* Change behavior on SIGUSR1 to be compatible with sysvinit and systemd.
@@ -16,17 +81,90 @@ Bug fix release.
sysvinit (upgrading/reinstalling causes scripts to `kill -USR1 1`)
* Change how `contrib/debian/install.sh` sets up a Grub boot entry for
finit. We now modify the $SUPPORTED_INITS variable in `10_linux`
* Disable default kernel ctrl-alt-delete handler and let Finit instead
catch `SIGINT` from kernel to be able to perform a proper reboot.
There is no default command for this, you need to set up a task that
triggers on `<sys/key/ctrlaltdel>` to issue `initctl reboot`
* Added keventd to provide `<sys/pwr/ac>` condition to Finit. keventd
is currently only responsible for monitoring `/sys/class/power_supply`
for changes to active AC mains power online status. Enable keventd
with `configure --with-keventd`
* For handling power fail events (from UPS and similar) a process may
send `SIGPWR` to PID 1. Finit no longer redirects this to `SIGUSR1`
(poweroff). There is no default command for this, you need to set up
a task that triggers on `<sys/pwr/fail>` to issue `initctl poweroff`
* Built-in Finit getty is now a standalone program
* Default termios for TTYs now enable `IUTF8` on input
* If `/bin/login` is not found, Finit now tries `sulogin` before it
falls back to an unauthenticated `/bin/sh`
* Dropped (broken) support for multiple consoles. Finit now follows
the default console selected by the kernel, `/dev/console`
* Dropped signal handlers for SIGSTOP/TSTP and SIGCONT
* Added support for `\n`, in addition to `\r`, in "Please press Enter"
prompt before starting getty
* Finit no longer parses `/proc/cmdline` for its options. Instead all
options are by default now read from `argv[]`, like a normal program,
this is also what the kernel does by default. Please note, this may
not work if your systems boots with an initramfs (ymmv), for such
cases, see `configure --enable-kernel-cmdline`
* The following plugins are now possible to disable (for containers):
`rtc.so`, `urandom.so`, you may also want to disable `hotplug.so`.
They are all enabled by default, as in Finit 4.0, but may be moved
to external tools or entries in `finit.conf` in Finit 5.0
* Added support for reading `PRETTY_NAME` from `/etc/os-release` to use
as heading in progress output, unless `--with-heading=GREET` is used.
* Added manual pages for finit(8), initctl(8), and finit.conf(5)
### Fixes
* Stricter interface name validation in netlink plugin, modeled after
the kernel. Suggested by Coverity Scan
* Fix problem of re-registering a service as a task. Previously, if a
fundamental change, like type, was made to an active service/run/task
it did not take. Only possible workaround was to remove from config
* initctl: drop warning when removing a non-existing usr condition
* initctl: drop confusing `errno 0` when timing out waiting for reply
* Ensure services in plugins and from Finit main belong to a cgroup
* Ensure init top-level cgroup remains a leaf group
* Fix tty parse error for detecting use of external getty
* Fix default `name:` and `:ID` for tty's, e.g. `ttyS0` now gives
`tty:S0` as expected. This was default for built-in getty already
* Fix max username (32 chars) in bundled Finit getty
* The `contrib/*/install.sh` scripts failed to run from tarball
* Finit no longer forcibly mounts; `/dev`, `/proc`, or `/sys`, instead
it checks first if they are already mounted (devtmpfs or container)
* Fix `/etc/fstab` parser to properly check for 'ro' to not remount the
root filesystem at boot. The wrong field was read, so a root mounted
by an initramfs, or by lxc for a container, had their root remounted
* Fix SIGCHLD handler, `waitpd()` may be interrupted by a signal
* Reset `starting` flag of services being stopped. When a service
is started and then stopped before it has created its pid file,
it could be left forever in the stopping state, unless we reset
the starting flag.
* Fix #170: detect loss of default route when interfaces go down. This
emulates the missing kernel netlink message to remove the condition
net/default/route to allow stopping dependent services
* Fix #171: restore automatic mount of `/dev/shm`, `/dev/pts`, `/run`
and `/tmp`, unless mounted already by `/etc/fstab`. This is what most
desktop systems expect PID 1 to do
desktop systems expect PID 1 to do. Here we also make sure to mount
`/run/lock` as a tmpfs as well, with write perms for regular users,
this prevents regular users from filling up `/run` and causing DoS.
* Fix #173: netlink plugin runs out of socket buffer space;
finit[1]: nl_callback():recv(): No buffer space available
Fixed by adding support for resync with kernel on `ENOBUFS`. See
netlink(7) for details. As a spin-off the plugin now supports any
number of interfaces and routes on a system. On resync, the following
message is now logged, as a warning:
finit[1]: nl_callback():busy system, resynchronizing with kernel.
* Fix #174: loss of log messages using combo of prio and facility, e.g.,
`logit(LOG_CONSOLE | LOG_NOTICE, ...)`, by Jacques de Laval, Westermo
* Fix #175: ensure Finit does not acquire a controlling TTY when checking
if a device is a TTY before starting a getty. This fixes an old bug
where Ctrl-C after logout from a shell could cause PID 1 to get SIGINT,
which in turn could lead to a system reboot
[4.0][] - 2021-04-26
@@ -109,7 +247,7 @@ make sure to read the whole change log when upgrading.
- As long as a stepped service changes state we queue another step all
event, because services may depend on each other
* Require new libuEv API: `uev_init1()` to reduce event cache so that
the kernel can invalidate deleted events before enqueing to userspace
the kernel can invalidate deleted events before enqueuing to userspace
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
from the `hwclock` tool. Note: the kernel can also be set to load
and store RTC to/from system clock at boot/halt as well, issue #110
@@ -431,7 +569,7 @@ Bug fix release.
* Add support for status/show service by `name:id`
* Enforce terse mode after boot, if verbose mode is disabled
* Reenable verbose mode at reboot, if disabled at boot
* Re-enable verbose mode at reboot, if disabled at boot
* Update section mentioning BusyBox getty
* Update debugging documentation
* Allow debug to override terse mode
@@ -486,7 +624,7 @@ handling and reconfiguration at runtime.
* Clarify how to select different plugins with the configure script
* Improve urandom plugin for embedded systems w/o random seed
* Add `--debug` flag to `initctl`
* The runlevels listed for services in `initctl show` now hightlight the
* The runlevels listed for services in `initctl show` now highlight the
active runlevel.
* Clarify in the README and in `initctl help` that the GW event to
listen for in service declarations is `GW:UP`
@@ -518,7 +656,7 @@ handling and reconfiguration at runtime.
* Do not use `-Os` use `-O2` as default optimization level. Many cross
compiler toolchains are known to have problems with `-Os`
* Do not allow build VERSION to be overloaded by an environment variable
* Fix too small MAX arguments and too few argments in `svc_t` for
* Fix too small MAX arguments and too few arguments in `svc_t` for
reading currently running services with `initctl show`
* Unblock blocked signals after forking off a child
@@ -636,7 +774,7 @@ The inetd release.
turned out to not work so well after all. For instance, launching
TTYs in a background process completely blocked inetd services from
even starting up listening sockets ... proper fork seems to work fine
though. This is the casue for *yanking* the [1.11] release, below.
though. This is the cause for *yanking* the [1.11] release, below.
* Trap segfaults caused by external plugins/callbacks in a sub-process.
This prevents a single programming mistake in by a 3rd party developer
from taking down the entire system.
@@ -732,7 +870,7 @@ Major bug fix release.
### Changes
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
similarily named callbacks. Also, only in debug mode anyway
similarly named callbacks. Also, only in debug mode anyway
* Make sure to cleanup recorded PID when a service is lost. Required by
service plugins for their callbacks to work.
* Only clear screen when in verbose mode. Maybe this should be removed
@@ -900,7 +1038,9 @@ Major bug fix release.
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.0...HEAD
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
[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
+1 -1
View File
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = plugins src test
SUBDIRS = man plugins src test
doc_DATA = README.md LICENSE contrib/finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
+29 -34
View File
@@ -1,4 +1,4 @@
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
[![License Badge][]][License] [![GitHub Status]][GitHub] [![Coverity Status]][Coverity Scan]
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
* [Introduction](#introduction)
@@ -22,19 +22,19 @@
Introduction
------------
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
was reverse engineered from the [EeePC fastinit][] over ten years ago
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
Fast init for Linux systems. Reverse engineered from the [EeePC
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
with frog DNA …"
![Alpine screenshot](img/finit4-screenshot.png)
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
Features include:
* Runlevels
* One-shot tasks, daemons, or SysV init scripts
* Runparts and rc.local
* Process supervision
* Runlevels, defined per service
* One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
* Runparts and `/etc/rc.local` support
* Process supervision similar to [systemd][]
* Sourcing environment files
* Conditions for network/process/custom dependencies
* Pre/Post script actions
@@ -119,10 +119,10 @@ some of the most common components needed to start a UNIX daemon:
```
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | `-- Optional description
| | | | | | `----------- Daemon arguments
| | | | | `-------------------------- Path to daemon
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | `---------- Optional description
| | | | | | `------------------ Daemon arguments
| | | | | `------------------------- Path to daemon
| | | | `---------------------------------------------------- Optional env. file
| | | `-------------------------------------------------------- Redirect output to log
| | `--------------------------------------------------------------- Optional conditions
@@ -134,13 +134,13 @@ Some components are optional: runlevel(s), condition(s) and description,
making it easy to create simple start scripts and still possible for more
advanced uses as well:
service sshd -D
service /usr/sbin/sshd -D
Dependencies are handled using [conditions](doc/conditions.md). One of
the most common conditions is to wait for basic networking to become
available:
service <net/route/default> nginx -- High performace HTTP server
service <net/route/default> nginx -- High performance HTTP server
Here is another example where we instruct Finit to not start BusyBox
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
@@ -460,9 +460,6 @@ Commands:
halt Halt system
poweroff Halt and power off system
suspend Suspend system
Bug report address: https://github.com/troglobit/finit/issues
Project homepage: https://troglobit.com/finit.html
```
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
@@ -574,36 +571,34 @@ This project is based on the [original finit][] by [Claudio Matsuoka][]
which was reverse engineered from syscalls of the [EeePC fastinit][] —
"gaps filled with frog DNA …"
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][].
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][6].
Please file bug reports, clone it, or send pull requests for bug fixes
and proposed extensions.
[1]: https://en.wikipedia.org/wiki/Process_supervision
[2]: http://cr.yp.to/daemontools.html
[3]: http://smarden.org/runit/
[4]: http://en.wikipedia.org/wiki/Init
[5]: http://en.wikipedia.org/wiki/Runlevel
[6]: https://www.freedesktop.org/wiki/Software/systemd/
[9]: https://github.com/troglobit/troglos
[1]: https://en.wikipedia.org/wiki/Process_supervision
[2]: https://cr.yp.to/daemontools.html
[3]: https://smarden.org/runit/
[4]: https://en.wikipedia.org/wiki/Init
[5]: https://en.wikipedia.org/wiki/Runlevel
[6]: https://github.com/troglobit/finit
[RFC862]: https://tools.ietf.org/html/rfc862
[RFC863]: https://tools.ietf.org/html/rfc863
[RFC864]: https://tools.ietf.org/html/rfc864
[RFC867]: https://tools.ietf.org/html/rfc867
[RFC868]: https://tools.ietf.org/html/rfc868
[init]: http://en.wikipedia.org/wiki/Init
[upstart]: http://upstart.ubuntu.com/
[systemd]: http://www.freedesktop.org/wiki/Software/systemd/
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
[init]: https://en.wikipedia.org/wiki/Init
[upstart]: https://upstart.ubuntu.com/
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
[original finit]: http://helllabs.org/finit/
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
[Claudio Matsuoka]: https://github.com/cmatsuoka
[Joachim Wiberg]: http://troglobit.com
[GitHub]: https://github.com/troglobit/finit
[Joachim Wiberg]: https://troglobit.com
[License]: https://en.wikipedia.org/wiki/MIT_License
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
[Travis]: https://travis-ci.org/troglobit/finit
[Travis Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
[GitHub]: https://travis-ci.org/troglobit/finit
[GitHub Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
[Coverity Scan]: https://scan.coverity.com/projects/3545
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
+50 -5
View File
@@ -1,4 +1,4 @@
AC_INIT(Finit, 4.1-rc1, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
AC_INIT(Finit, 4.2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes])
@@ -11,6 +11,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
man/Makefile
plugins/Makefile
src/Makefile
test/test.env
@@ -52,6 +53,18 @@ AC_ARG_ENABLE(auto_reload,
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
enable_auto_reload=no])
AC_ARG_ENABLE(kernel_cmdline,
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[
enable_kernel_cmdline=no])
AC_ARG_ENABLE(fastboot,
AS_HELP_STRING([--enable-fastboot], [Skip fsck check on filesystems listed in /etc/fstab]),,[
enable_fastboot=no])
AC_ARG_ENABLE(fsckfix,
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
enable_fsckfix=no])
AC_ARG_ENABLE(redirect,
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
enable_redirect=yes])
@@ -77,10 +90,12 @@ AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
# Check for extra arguments or packages
AC_ARG_WITH(heading,
AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
[heading=$withval], [heading=yes])
AC_ARG_WITH(config,
@@ -99,6 +114,10 @@ AC_ARG_WITH(sysconfig,
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
[sysconfig=$withval], [sysconfig=default])
AC_ARG_WITH(group,
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket (initctl), default: root]),
[group=$withval], [group=root])
AC_ARG_WITH(hostname,
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
[hostname=$withval], [hostname=yes])
@@ -111,6 +130,9 @@ AC_ARG_WITH(random-seed,
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
[random_seed=$withval], [random_seed=yes])
AC_ARG_WITH(keventd,
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
AC_ARG_WITH(watchdog,
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
[watchdog=$withval], [with_watchdog=no watchdog=])
@@ -121,6 +143,15 @@ AC_ARG_WITH(watchdog,
AS_IF([test "x$enable_auto_reload" = "xyes"], [
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
AS_IF([test "x$enable_fastboot" = "xyes"], [
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
AS_IF([test "x$enable_fsckfix" = "xyes"], [
AC_DEFINE(FSCK_FIX, 1, [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab])])
AS_IF([test "x$enable_redirect" = "xyes"], [
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
@@ -158,9 +189,13 @@ AS_IF([test "x$with_sysconfig" != "xno"], [
[System environment, default /etc/default & /etc/conf.d])])])
AS_IF([test "x$with_heading" != "xno"], [
AS_IF([test "x$heading" = "xyes"], [
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
AS_IF([test "x$heading" = "xyes"], [heading=""])
AC_DEFINE_UNQUOTED(INIT_OSHEADING, "$heading", [Displayed by Finit at boot, defaults to /etc/os-release PRETTY_NAME])])
AS_IF([test "x$with_group" != "xno"], [
AS_IF([test "x$group" = "xyes"], [
group=root])])
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket])
AS_IF([test "x$with_hostname" != "xno"], [
AS_IF([test "x$hostname" = "xyes"], [
@@ -179,6 +214,8 @@ AS_IF([test "x$with_random_seed" != "xno"], [
AC_EXPAND_DIR(random_path, "$random_seed")
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
AS_IF([test "x$with_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [
watchdog=/dev/watchdog])
@@ -188,6 +225,7 @@ AS_IF([test "x$with_watchdog" != "xno"], [
# Control build with automake flags
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
@@ -207,6 +245,9 @@ AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
# Generate all files
AC_OUTPUT
@@ -234,10 +275,14 @@ Behavior:
Optional features:
Install doc/..........: $enable_doc
Install contrib/......: $enable_contrib
Built-in keventd......: $with_keventd
Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate
Skip fsck check.......: $enable_fastboot
Run fsck fix mode.....: $enable_fsckfix
Redirect output.......: $enable_redirect
Default hostname......: $hostname
Default group.........: $group
Default runlevel......: $runlevel
------------- Compiler version --------------
+1 -1
View File
@@ -1,5 +1,5 @@
SUBDIRS = finit.d
docsdir := @docdir@/contrib/alpine
docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
docs_DATA = README.md finit.conf build.sh install.sh rc.local
EXTRA_DIST = $(docs_DATA)
-1
View File
@@ -1 +0,0 @@
3.6.2
+1 -1
View File
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-watchdog \
--with-heading="Alpine Linux 3.13"
--with-keventd
echo
echo "*** Building ..."
+17 -1
View File
@@ -5,6 +5,22 @@
# Default is 2
#runlevel 2
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
#cgroup init cpu.weight:100
#cgroup user cpu.weight:100
#cgroup system cpu.weight:9700
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
## Bootstrap services and tasks
# Can be listed here or in /etc/finit.d/*.conf
+2 -1
View File
@@ -8,7 +8,8 @@ if [ "x`id -u`" != "x0" ]; then
fi
# Adjust base directory
if [ -e alpine-release ]; then
grep -q alpine Makefile 2>/dev/null
if [ $? -eq 0 ]; then
cd ../..
elif [ ! -e configure.ac ]; then
echo "*** Please run this script from the Finit base directory."
+1 -1
View File
@@ -4,5 +4,5 @@
#
# Each line is run in sequence.
#
# NOTE: Remeber to set the executable bit!
# NOTE: Remember to set the executable bit!
#
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS = finit.d
docsdir := @docdir@/contrib/debian
docs_DATA = README.md finit.conf os-release build.sh install.sh
docs_DATA = README.md finit.conf build.sh install.sh
EXTRA_DIST = $(docs_DATA)
+7 -6
View File
@@ -47,12 +47,13 @@ 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.
If you want to use the X Window system, `sudo apt install elogind`
(Bullseye and later). Followed by `initctl reload` (enabled by default)
and logout/login again. The elogind daemon ensures a regular non-root
user can start and interact with an X session, otherwise keyboard and
mouse won't work. When you're happy, you can enable the lightdm.conf,
change the default runlevel to 3, and presto! you have a desktop again.
> **NOTE:** 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
> session, otherwise keyboard and mouse won't work. When you're happy,
> you can enable the lightdm.conf, change the default runlevel to 3, and
> presto! you have a desktop again.
Have fun!
+2 -3
View File
@@ -25,9 +25,8 @@ echo
--prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin \
--with-random-seed=/var/lib/urandom/random-seed \
--with-heading="Debian GNU/Linux"
--enable-alsa-utils-plugin --with-keventd \
--with-random-seed=/var/lib/urandom/random-seed
if [ $? -ne 0 ]; then
echo
+17 -1
View File
@@ -5,6 +5,22 @@
# Default is 2
#runlevel 2
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
#cgroup init cpu.weight:100
#cgroup user cpu.weight:100
#cgroup system cpu.weight:9700
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
## Bootstrap services and tasks
# Can be listed here or in /etc/finit.d/*.conf
+4 -3
View File
@@ -1,8 +1,9 @@
SUBDIRS = available
docsdir := @docdir@/contrib/debian/finit.d
d_LINKS = console-setup.conf elogind.conf getty.conf \
keyboard-setup.conf modules.conf rsyslogd.conf \
sshd.conf
d_LINKS = acpid.conf apparmor.conf avahi-daemon.conf \
bluetooth.conf console-setup.conf elogind.conf \
getty.conf keyboard-setup.conf modules.conf \
plymouth-quit.conf rsyslogd.conf sshd.conf
install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
+5 -2
View File
@@ -1,5 +1,8 @@
docsdir := @docdir@/contrib/debian/finit.d/available
docs_DATA = acpid.conf console-setup.conf elogind.conf getty.conf \
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
console-setup.conf elogind.conf getty.conf \
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
rsyslogd.conf sshd.conf syslogd.conf xdm.conf
plymouth-quit.conf rsyslogd.conf sshd.conf syslogd.conf \
xdm.conf
EXTRA_DIST = $(docs_DATA)
@@ -0,0 +1 @@
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
@@ -0,0 +1,2 @@
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
@@ -0,0 +1 @@
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
@@ -0,0 +1,3 @@
# To ignore errors like "org.freedesktop.hostname1", update the env file with
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
@@ -0,0 +1 @@
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
+5 -2
View File
@@ -1,4 +1,7 @@
# Consoles to start getty on when system is up
tty [12345] /dev/tty1 linux noclear nowait
tty [2345] /dev/tty2 linux noclear nowait
tty [2345] /dev/tty3 linux noclear nowait
tty [2345] /dev/tty2 linux nowait
tty [2345] /dev/tty3 linux nowait
tty [2345] /dev/tty4 linux nowait
tty [2345] /dev/tty5 linux nowait
tty [2345] /dev/tty6 linux nowait
@@ -0,0 +1,2 @@
# Need to stop plymouth, or it'll block stdin on tty1
task [S] /usr/bin/plymouth quit -- Stopping Plymouth Boot Screen
+1 -1
View File
@@ -8,7 +8,7 @@ if [ "x`id -u`" != "x0" ]; then
fi
# Adjust base directory
grep -q Debian os-release 2>/dev/null
grep -q debian Makefile 2>/dev/null
if [ $? -eq 0 ]; then
cd ../..
elif [ ! -e configure.ac ]; then
-8
View File
@@ -1,8 +0,0 @@
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=debian
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
+8
View File
@@ -35,6 +35,14 @@ tty /dev/tty1
tty /dev/tty2
tty /dev/tty3
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
# Alternative method instead of runparts
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS = finit.d
docsdir := @docdir@/contrib/void
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
docs_DATA = README.md finit.conf build.sh install.sh rc.local
EXTRA_DIST = $(docs_DATA)
+1 -1
View File
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-watchdog \
--with-heading="Void Linux"
--with-keventd
echo
echo "*** Building ..."
+17
View File
@@ -5,5 +5,22 @@
# Default is 2
#runlevel 2
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
#cgroup init cpu.weight:100
#cgroup user cpu.weight:100
#cgroup system cpu.weight:9700
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
## Bootstrap services and tasks
# Can be listed here or in /etc/finit.d/*.conf
+2 -1
View File
@@ -8,7 +8,8 @@ if [ "x`id -u`" != "x0" ]; then
fi
# Adjust base directory
if [ -e xbps ]; then
grep -q void Makefile 2>/dev/null
if [ $? -eq 0 ]; then
cd ../..
elif [ ! -e configure.ac ]; then
echo "*** Please run this script from the Finit base directory."
+1 -1
View File
@@ -4,4 +4,4 @@
#
# Each line is run in sequence.
#
# NOTE: Remeber to set the executable bit!
# NOTE: Remember to set the executable bit!
View File
+14 -2
View File
@@ -21,17 +21,29 @@ Some of these are also registered in the issue tracker on GitHub.
* Allow running as non-pid1 => read .conf and RCSD form cmdline
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
As of Finit v4.1 SIGPWR generates <sys/power/fail> condition and it
is up to a task to check why and take appropriate action.
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
* Write man pages for finit and `finit.conf`, steal from the excellent
`pimd` man pages ...
As of Finit v4.1 SIGINT generates <sys/key/ctrlaltdel>, but there is
no check if the signal actually originates from the kernel. To get
this verification, a new libuEv release is needed. As of June 6 -21
that functionality is not yet released.
Initctl
-------
* Add support for timed shutdown in Finit, including cancelled shutdown:
shutdown -h 03:35 "foobar was here"
* Add support for JSON output, or similar, from `initctl show`, e.g.
`initctl show --json`
* Add support for `-s` to redirect all output to syslog, for scripting
Init
+9 -10
View File
@@ -16,7 +16,9 @@ Bootstrap
11. Load all `/etc/finit.d/*.conf` files and set hostname
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
14. Mount all file systems listed in `/etc/fstab` and swap, if available
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
of error, `HOOK_MOUNT_POST` is called
15. Enable SysV init signals
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
@@ -38,16 +40,13 @@ Bootstrap
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
27. Start all configured TTYs
In (19) and (22) tasks and services defined in `/etc/finit.conf` and
`/etc/sysctl.d/*.conf` are started. Remember, all `service` and `task`
stanzas are started in parallel and `run` in sequence, and in the order
listed. Hence, to emulate a SysV `/etc/init.d/rcS` one could write a
long `finit.conf` with only `run` statements.
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
`/etc/finit.d/*.conf` are started.
Notice the five hook points that are called at various point in the
bootstrap process. This is where plugins can extend the boot in any way
they please. There are other hook points, e.g. `HOOK_MOUNT_ERROR`, for
more on this see [plugins.md](plugins.md).
Notice the seven hook points that are called at various point in the
bootstrap process. This is where plugins can extend the boot in any
way they please. There are other hook points available, for more on
this, see [plugins.md](plugins.md).
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
USB stick, convert/copy its contents to the system's `/etc/` directory,
+13 -9
View File
@@ -27,7 +27,7 @@ optional plugins to enable. It depends on two external libraries:
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 requried versions:
version of the above mentioned libraries. Currently required versions:
- libite v2.2.0
- libuEv v2.2.0
@@ -53,6 +53,10 @@ Below are a few of the main switches to configure:
built-ins (.o files) and all external libraries, except the C library
will be linked statically.
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
`/proc/cmdline`, this is not recommended since Finit may be running as the
init for container apps that can see the host's `/proc` filesystem
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
@@ -70,16 +74,16 @@ Example
First, unpack the archive:
```shell
$ tar xf finit-3.0.tar.xz
$ cd finit-3.0/
$ tar xf finit-4.1.tar.gz
$ cd finit-4.1/
```
Then configure, build and install:
```shell
$ ./configure --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \
--with-heading="Alpine Linux 3.13" --with-hostname=alpine
$ ./configure --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \
--with-keventd --with-watchdog
$ make
.
.
@@ -87,13 +91,13 @@ $ make
$ DESTDIR=/tmp/finit make install
```
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
user's home directory, configured, built and installed to a temporary
staging directory. The environment variable `DESTDIR` controls the
destination directory when installing, very useful for building binary
standalone packages.
Finit 3.0 and later can detect if it runs on an embedded system, or a
Finit 4.1 and later can detect if it runs on an embedded system, or a
system that use BusyBox tools instead of udev & C:o. On such systems
`mdev` instead of `udev` is used. However, remember to also change the
Linux config to:
@@ -171,6 +175,6 @@ it only for debugging start up issues when Finit crashes.
systems since they can potentially give a user root access.
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
[libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite
+3 -1
View File
@@ -6,6 +6,8 @@ passed on the Linux kernel command line. Not limited to Finit.
The `bool` setting is one of `on, off, true false, 1, 0`.
> **NOTE:** remember to use `--` to separate kernel parameters from
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
* `debug`: Enable kernel debug. Debug messages are printed to the
console until Finit starts up.
@@ -42,7 +44,7 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
`[1]` will be started, so a `tty [1] @console nologin` configuration
presents you with a root console without login.
For more on kernel boot paramaters, see the man page [bootparam(7)][].
For more on kernel boot parameters, see the man page [bootparam(7)][].
[config.md][]: config.md#rescue-mode
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
+14 -7
View File
@@ -87,12 +87,15 @@ Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
Built-in Conditions
-------------------
Finit comes with a `pidfile` and `netlink` plugin. When enabled, the
`pidfile` plugin watches `/var/run/` (recursively) for PID files created
by the monitored services, and sets a corresponding condition in the
`pid/` namespace. Similarily, the `netlink` plugin provides basic
conditions for when an interface is brought up/down and when a default
route (gateway) is set, in the `net/` namespace.
Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
(recursively) for PID files created by the monitored services, and sets
a corresponding condition in the `pid/` namespace. Similarly, the
`netlink` plugin provides basic conditions for when an interface is
brought up/down and when a default route (gateway) is set, in the `net/`
namespace. The `sys` and `usr` plugins monitor are passive condition
monitors where the action is provided by `keventd`, signal handlers,
and in the case of `usr`, the end-user via the `initctl` tool
With the example listed above, finit does not start the `/sbin/netd`
daemon until `setupd` and `zebra` has started *and* created their PID
@@ -111,6 +114,10 @@ Built-in conditions:
- `net/<IFNAME>/exist`
- `net/<IFNAME>/up`
- `net/<IFNAME>/running`
- `sys/pwr/ac`
- `sys/pwr/fail`
- `sys/key/ctrlaltdel`
- `usr/foo`
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
@@ -173,7 +180,7 @@ PID IDENT STATUS CONDITION (+ ON, ~ FLUX, - OFF)
Here we can see that `netd` is allowed to run since both its conditions
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
is not allowed to run since `net/vlan1/exist` condition is not satisfied.
As indicated by the `-`-prefix.
To fake interface `vlan1` suddenly appearing, and test what happens to
+55 -18
View File
@@ -26,6 +26,7 @@ Configuration
* [/etc/finit.conf](#etcfinitconf)
* [/etc/finit.d](#etcfinitd)
* [Watchdog](#watchdog)
* [keventd](#keventd)
Introduction
@@ -42,13 +43,13 @@ Not all configuration directives are available in `/etc/finit.d/*.conf`
and some directives are only available at [bootstrap][], runlevel `S`,
see the section [Limitations](#limitations) below for details.
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
call `finit q`, but that has been deprecated with the `initctl` tool).
Finit monitors all known active `.conf` files, so if you want to force
a restart of any service you can simply touch its corresponding `.conf`
file in `/etc/finit.d` and call `initctl reload`. Finit handle any
and all conditions and dependencies between services automatically.
To add a new service, drop a `.conf` file in `/etc/finit.d` and run
`initctl reload`. (It is also possible to `SIGHUP` to PID 1, or call
`finit q`, but that has been deprecated with the `initctl` tool). Finit
monitors all known active `.conf` files, so if you want to force a
restart of any service you can touch its corresponding `.conf` file in
`/etc/finit.d` and call `initctl reload`. Finit handle any and all
conditions and dependencies between services automatically.
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
and use `initctl enable` to enable a service `.conf` file. This may be
@@ -58,7 +59,7 @@ files for a package and let the user decide when to enable a service.
On `initctl reload` the following is checked for all services:
- If a service's `.conf` file has been removed, or its conditions are no
longer satisifed, the service is stopped.
longer satisfied, the service is stopped.
- If the file is modified, or a service it depends on has been reloaded,
the service is reloaded (stopped and started).
- If a new service is added it is automatically started — respecting
@@ -153,7 +154,7 @@ Top-level group configuration.
cgroup system cpu.weight:9800
Adding an extra cgroup `maint/` will require you to adjust the weight of
the above three. We leave `init/` and `user /` as-is reducing weight of
the above three. We leave `init/` and `user/` as-is reducing weight of
`system/` to 9700.
cgroup system cpu.weight:9700
@@ -183,7 +184,7 @@ The latter form also allows per-stanza limits on the form:
Notice the comma separation and the `mem.` exception to the rule: every
cgroup setting maps directly to cgroup v2 syntax. I.e., `cpu.max` maps
to the file `/sys/fs/cgroup/maint/foo/cpu.max`. There is not filtering,
to the file `/sys/fs/cgroup/maint/foo/cpu.max`. There is no filtering,
except for expanding the shorthand `mem.` to `memory.`, if the file is
not available, either the cgroup controller is not available in your
Linux kernel, or the name is misspelled.
@@ -331,8 +332,11 @@ by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
**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 10 times
before giving up, then you have to `initctl restart NAME` it manually.
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.
For daemons that support it, we recommend appending `--foreground`,
`--no-background`, `-n`, `-F`, or similar command line argument to
@@ -389,6 +393,21 @@ optional `name` argument:
name:<service-name>
As mentioned previously, services are automatically restarted, this is
configurable with the following options:
* `restart:NUM` -- number of times Finit tries to restart a crashing
service, default: 10. When this limit is reached the service is
marked *crashed* and must be restarted manually with `initctl`
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used
* `norestart` -- dont restart on failures, same as `restart:0`
* `oncrash:reboot` -- when all retries have failed, and the service
has *crashed*, if this option is set the system is rebooted.
Note, future releases may include other `oncrash:` actions
When stopping a service (run/task/sysv/service), either manually or
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
allow the process to shut down gracefully. If the process has not
@@ -472,8 +491,9 @@ size limit is reached.
`tty [LVLS] <COND> [notty] [rescue]`
The first variant of this option uses the built-in getty on the given
TTY device DEV, in the given runlevels. The DEV may be the special
keyword `@console`, or `console`, useful on embedded systems.
TTY device DEV, in the given runlevels. DEV may be the special keyword
`@console`, which is expanded from `/sys/class/tty/console/active`,
useful on embedded systems.
The default baud rate is 0, i.e., keep kernel default.
@@ -554,8 +574,8 @@ One can also use the `service` stanza to start a stand-alone shell:
### Non-privileged Services
Every `run`, `task`, or `service` can also list the privileges the
`/path/to/cmd` should be executed with. Simply prefix the path with
`[@USR[:GRP]]` like this:
`/path/to/cmd` should be executed with. Prefix the command with
`@USR[:GRP]`, group is optional, like this:
run [2345] @joe:users logger "Hello world"
@@ -653,8 +673,9 @@ Limitations
-----------
As of Finit v4 there are no limitations to where `.conf` settings can be
placed. Except for the system/global `rlimit`, which can only be set
from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
placed. Except for the system/global `rlimit` and `cgroup` top-level
group declarations, which can only be set from `/etc/finit.conf`, since
it is the first `.conf` file Finit reads.
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
Today it is mainly used for bootstrap settings like system hostname,
@@ -704,3 +725,19 @@ the only option is to remove `/libexec/finit/watchdogd` or build without
it at configure time.
[bootstrap]: bootstrap.md
keventd
-------
The kernel event daemon bundled with Finit is a simple uevent monitor
for `/sys/class/power_supply`. It provides the `sys/pwr/ac` condition,
which can be useful to prevent power hungry services like anacron to run
when a laptop is only running on battery, for instance.
Since keventd is not an integral part of Finit yet it is not enabled by
default. Enable it using `./configuure --with-keventd`. The bundled
contrib build scripts for Debian, Alpine, and Void have this enabled.
This daemon is planned to be extended with monitoring of other uevents,
patches and ideas are welcome in the issue tracker.
+2
View File
@@ -0,0 +1,2 @@
Makefile
Makefile.in
+2
View File
@@ -0,0 +1,2 @@
dist_man8_MANS = finit.8 initctl.8
dist_man5_MANS = finit.conf.5
+178
View File
@@ -0,0 +1,178 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.Dd June 6, 2021
.\" Please adjust this date whenever revising the manpage.
.Dt FINIT 8 SMM
.Os Linux
.Sh NAME
.Nm finit
.Nd Fast init for Linux systems
.Sh SYNOPSIS
.Nm /sbin/finit
.Op finit.status_style=classic
.Op finit.show_status=[on,off]
.Op finit.debug
.Op rescue | recover
.Op single | S
.Nm /sbin/telinit
.Op Fl hv
.Op q | Q | 0-9
.Sh DESCRIPTION
Fast init for Linux systems. Reverse engineered from the EeePC
fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog
DNA ...". Focus is on small and embedded systems, although Finit is
fully usable on server and desktop systems as well.
.Pp
Features include:
.Bl -bullet -width 1n -compact
.It
Runlevels, defined per service
.It
One-shot tasks, services (daemons), or SysV init start/stop scripts
.It
Runparts and
.Pa /etc/rc.local
support
.It
Process supervision similar to
.Xr systemd 8
.It
Sourcing environment files
.It
Conditions for network/process/custom dependencies
.It
Pre/Post script actions
.It
Tooling to enable/disable services
.It
Built-in getty
.It
Built-in watchdog, with support for hand-over to
.Lk https://troglobit.com/watchdogd.html watchdogd
.It
Built-in support for Debian/BusyBox
.Pa /etc/network/interfaces
.It
Cgroups v2, both configuration and monitoring in `initctl top`
.It
Plugin support for customization
.It
Proper rescue mode with bundled `sulogin` for protected maintenance shell
.El
.Sh BOOTING
.Pp
Before laucnhing services, the system needs to be bootstrapped. This
involves mounting all filesystems (not already mounted by an initramfs)
in
.Pa /etc/fstab ,
ensuring that necessary filesystems like:
.Pa /dev ,
.Pa /proc ,
.Pa /sys ,
and
.Pa /run
are available and can provide the system with the services required.
.Pp
With that out of the way, a set of plugins take over:
.Pp
.Bl -tag -width bootmisc.so -offset indent
.It Cm bootmisc.so
Cleans up stale files from previous boots and default directories are
created in tmpfs filesystems
.It Cm modprobe.so
Probes kernel modules required by the system
.It Cm procps.so
Set kernel variables from
.Pa /etc/sysctl.conf
et al
.El
.Pp
When the plugins are done, finit reads
.Pa /etc/finit.conf
and all other enabled services in
.Pa /etc/finit.d/* .
First all services, run/tasks in runlevel S (bootStrap) are started,
When all run/tasks have completed, Finit changes to the configured
runlevel (default 2), Processes are started in parallel, in dependency
order according to their conditions.
.Pp
When all services and run/tasks have been started, the console progress
is disabled and all configured getty services are started.
.Sh CONDITIONS
The condition subysystem in Finit was initially created to track PID
files of daemons. If service/task B requires service A to have started,
Finit waits for the PID file of service A to be created/updated before
it starts service B. Conversely, if service A is stopped and its PID
file removed, service B is also stopped.
.Pp
The following condition families are available today:
.Pp
.Bl -tag -width pid -offset indent
.It Cm net
Linux netlink events, e.g. net/route/default, net/eth0/up, and
net/et0/running
.It Cm pid
PID files basd on the service declaration
.Cm name:id ,
gives the condition pid/name:id
.It Cm sys
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
.It Cm usr
User conditions, assert and deassert using
.Cm initctl cond [set|clr] foo
.El
.Sh SIGNALS
PID 1 is the only process that by default blocks all signals. Finit
allows for the following signals to control operation, but recommends
instead using the
.Xr initctl 8
tool.
.Pp
.Bl -tag -width TERM
.It HUP
Tell
.Nm
to reload its configuration file(s), same as
.Cm initctl reload
.It USR1
Restart API
.Cm ( initctl )
socket.
.It USR2
Tell
.Nm
to perform a system shutdown, same as
.Cm initctl poweroff
.It TERM
Like SIGUSR2 but performs a reboot, same as
.Cm initctl reboot
.It INT
Sent from kernel when Ctrl-Alt-Del is pressed (on the console), this
asserts the sys/key/ctrlaltdel condition, which can be used to start
tasks or services
.It PWR
Sent from a a power daemon on changes to UPS status, Finit asserts
the sys/pwr/fail condition
.El
.Sh FILES
.Bl -tag -width /etc/finit.d/available/*.conf -compact
.It Pa /etc/finit.conf
Main configuration file
.It Pa /etc/finit.d/*.conf
Static service definitions
.It Pa /etc/finit.d/available/*.conf
Available services
.It Pa /etc/finit.d/enabled/*.conf
Symlinks from available
.It Pa /run/finit/
Runtime files, including the condition subsystem
.El
.Sh SEE ALSO
.Xr finit.conf 5
.Xr initctl 8
.Sh AUTHORS
.Nm
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others.
+847
View File
@@ -0,0 +1,847 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.Dd Oct 17, 2020
.Dt FINIT.CONF 5 SMM
.Os Linux
.Sh NAME
.Nm finit.conf
.Nd Finit configuration file format
.Sh SYNOPSIS
.Nm /etc/finit.conf
.Nm /etc/finit.d/*.conf
.Nm /etc/finit.d/available/*.conf
.Sh DESCRIPTION
.Nm finit
can be configured using only the original
.Pa /etc/finit.conf
file or in combination with
.Pa /etc/finit.d/*.conf .
Useful for package-based Linux distributions \(em each package can
provide its own "script" file.
.Pp
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
.It Pa /etc/finit.conf
Main configuration file
.It Pa /etc/finit.d/*.conf
Snippets, usually one service per file
.El
.Pp
Not all configuration directives are available in
.Pa /etc/finit.d/*.conf
and some directives are only available at bootstrap, runlevel
.Cm S ,
see the section
.Sx Limitations
below for details.
.Sh FILES
.Bl -tag -width /etc/finit.d/available/*.conf -compact
.It Pa /etc/finit.conf
Main configuration file
.It Pa /etc/finit.d/*.conf
Static service definitions
.It Pa /etc/finit.d/available/*.conf
Available services
.It Pa /etc/finit.d/enabled/*.conf
Enabled services, symlinks from available
.El
.Sh FILE FORMAT
Lines starting with `#' are ignored. Note that end-of-line comments are
NOT supported, comments must be on a line of their own.
.Pp
A configuration stanza must be on a single (long) line and
.Em cannot
be broken up in multiple lines by use of a backslash as the last
character.
.Sh DIRECTIVES
This section lists all supported configuration directives. There also exist
deprecated directives, see the Markdown documentation for details on these.
.Pp
.Bl -tag -width 1n
.It Cm rlimit Oo hard|soft Oc Ar RESOURCE Aq LIMIT | unlimited
.Pp
Set the hard or soft limit for a resource, or both if that argument is
omitted.
.Ar RESOURCE
is the lower-case
.Cm RLIMIT_
string constants from
.Xr setrlimit 2 ,
without prefix. E.g. to set
.Cm RLIMIT_CPU ,
use
.Cm cpu .
.Pp
.Ar LIMIT
is an integer that depends on the resource being modified, see
the man page, or the kernel
.Pa /proc/PID/limits
file, for details.
Finit versions before v3.1 used
.Cm infinity
for
.Cm unlimited ,
which is still supported, albeit deprecated.
.Bd -unfilled -offset indent
# No process is allowed more than 8MB of address space
rlimit hard as 8388608
# Core dumps may be arbitrarily large
rlimit soft core infinity
# CPU limit for all services, soft & hard = 10 sec
rlimit cpu 10
.Ed
.Pp
.Cm rlimit
can be set globally, in
.Pa /etc/finit.conf ,
or locally per each
.Pa /etc/finit.d/*.conf
read. I.e., a set of task/run/service stanzas can share the same
rlimits if they are in the same .conf.
.It Cm runlevel Aq N
The system runlevel to go to after bootstrap (S) has completed.
.Cm N
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
halt. All other can be used by operating system administrators.
Default: 2
.Pp
.Sy Note:
only read and executed in runlevel S (bootstrap).
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description.
.Pp
.Cm run
commands are guaranteed to be completed before running the next
command. Highly useful if true serialization is needed. Usually
only used in the bootstrap (S) runlevel.
.Pp
.Cm Aq COND
conditions are described in
.Xr finit 8 ,
see also the
.Sx Examples
section below.
.It Cm task Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
One-shot like
.Cm run ,
but starts in parallel with the next command.
.Pp
Both
.Cm run
and
.Cm task
commands are run in a shell, so pipes and redirects can be freely used:
.Bd -unfilled -offset indent
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
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
When entering an allowed runlevel, Finit calls
.Cm init-script start ,
when entering a disallowed runlevel, Finit calls
.Cm init-script stop ,
and if the Finit .conf, where the
.Cm sysv
stanza is declared, is modified, Finit calls
.Cm init-script restart
on
.Cm initctl reload .
Similar to how
.Cm service
stanzas work.
.Pp
Forking services started with
.Cm sysv
scripts can be monitored by Finit by declaring the PID file to look for:
.Bd -unfilled -offset indent
sysv pid:!/path/to/pidfile.pid /path/to/script ...
.Ed
.Pp
The leading '!' is to prevent Finit from managing the PID file, which is
the default behavior for the
.Cm pid:
command modifier.
.It Cm service Oo LVLS Oc Ao COND Ac Ar /path/to/daemon ARGS Op -- 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
.Em crashed .
After which they have to be restarted manually using
.Cm initctl restart NAME .
The number of restarts, the delay between each restart, and more is
configurable, see the options below.
.Pp
For daemons that support it, we recommend appending
.Cm --foreground , --no-background , -n , -F ,
or similar command line argument to prevent them from forking off a
sub-process in the background. This is the most reliable way to monitor
a service.
.Pp
However, not all daemons support running in the foreground, or they may
start logging to the foreground as well, these are called forking
services and are supported using the same syntax as forking
.Cm sysv
services, using the
.Cm pid:!/path/to/pidfile.pid
command modifier syntax.
.Pp
.Sy Example: in the case of
.Cm ospfd
(below), we omit the
.Cm -d
flag (daemonize) to prevent it from forking to the background:
.Bd -unfilled -offset indent
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
.Ed
.Pp
.Cm [2345]
denote the runlevels
.Cm ospfd
is allowed to run in, they are optional and default to runlevel 2-5 if
omitted.
.Pp
.Cm <pid/zebra>
is the condition for starting
.Cm ospfd .
In this example Finit waits for another service,
.Cm zebra ,
to have created its PID file in
.Pa /var/run/quagga/zebra.pid
before starting
.Cm ospfd .
Finit watches *all* files in
.Pa /var/run ,
for each file named
.Cm *.pid ,
.Cm */pid ,
Finit opens it and find the matching
.Cm NAME:ID
using the PID.
.Pp
Some services do not maintain a PID file and rather than patching each
application Finit provides a workaround. A
.Cm pid
modifier keyword can be set to have Finit automatically create (when
starting) and later remove (when stopping) the PID file. The file is
created in the
.Pa /var/run
directory using the
.Xr basename 3
of the service. The full syntax of the
.Cm pid
modifier is:
.Bd -unfilled -offset indent
pid[:[!][/path/to/]filename[.pid]]
.Ed
.Pp
For example, by adding
.Cm pid:/run/foo.pid
to the service
.Cm /sbin/bar ,
that PID file will, not only be created and removed automatically, but
also be used by the Finit condition subsystem. So a service/run/task
can depend on the
.Cm <pid/bar>
condition.
.Pp
If a service should not be automatically started, it can be configured
as manual with the
.Cm manual:yes
command modifier. The service can then be started at any time by
running
.Cm initctl start NAME
.Pp
The name of a service, shown by the
.Cm initctl
tool, defaults to the basename of the service executable. It can be
changed with the
.Cm name:foo
command modifier.
.Pp
As mentioned previously, services are automatically restarted should
they crash, this is configurable with the following options:
.Bl -tag -width 1n
.It Cm restart:NUM
number of times Finit tries to restart a crashing
service, default: 10. When this limit is reached the service is
marked
.Em crashed
and must be restarted manually with
.Xr initctl 8 .
.It Cm restart_sec:SEC
number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used
.It Cm norestart
dont restart on failures, same as
.Cm restart:0
.It Cm oncrash:reboot
when all retries have failed, and the service
has
.Em crashed ,
if this option is set the system is rebooted. Note, future releases
may include other
.Cm oncrash:
actions.
.El
.Pp
When stopping a service (run/task/sysv/service), either manually or when
moving to another runlevel, Finit starts by sending SIGTERM, to allow
the process to shut down gracefully. If the process has not been
collected within 3 seconds, Finit sends SIGKILL. To halt the process
using a different signal, use the command modifier
.Cm halt:SIGNAL ,
e.g.,
.Cm halt:SIGPWR .
To change the delay between your halt signal and KILL, use the command
modifier
.Cm kill:SEC ,
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
.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
.Cm post:script
is called with an additional set of environment variables:
.Bl -tag -offset indent -width 1n
.It Cm EXIT_CODE=[exited,signal]
set to one of
.Cm exited
or
.Cm signal
.It Cm 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
.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.
.Pp
.Sy Note:
the
.Cm pre:script
.Em must
be idempotent, because a service can transition between READY and HALTED
states any number of times before going to RUNNING.
.It Cm runparts Aq DIR
Call
.Xr run-parts 8
on
.Cm DIR
to run start scripts. All executable files, or scripts, in the
directory are called, in alphabetic order. The scripts in this
directory are executed at the very end of bootstrap, runlevel S.
.Pp
It can be beneficial to use
.Cm S01name ,
.Cm S02othername ,
etc. if there is a dependency order between the scripts. Symlinks to
existing daemons can talso be used, but make sure they daemonize by
default.
.Pp
Similar to the
.Pa /etc/rc.local
shell script, make sure that all your services and programs either
terminate or start in the background or you will block Finit.
.Sy Note:
only read and executed in runlevel S (bootstrap).
.It Cm include Aq CONF
Include another configuration file. Absolute path required.
.It Cm log size:BYTES count:NUM
Log rotation for run/task/services using the
.Cm log
command modifier with redirection to a log file. Global setting,
applies to all services.
.Pp
The size can be given as bytes, without a specifier, or in `k`, `M`,
or `G`, e.g.
.Cm size:10M ,
or
.Cm size:3G .
A value of
.Cm size:0
disables log rotation. The default is
.Cm size:200k .
.Pp
The count value is recommended to be between 1-5, with a default 5.
Setting count to 0 means the logfile will be truncated when the MAX
size limit is reached.
.It Cm tty Oo LVLS Oc Ao COND Ac Ar DEV Oo BAUD Oc Oo noclear Oc Oo nowait Oc Oo nologin Oc Oo TERM Oc
This form of the
.Cm tty
stanza uses the built-in getty on the given TTY device
.Ar DEV ,
in the given runlevels.
.Ar DEV may be the special keyword
.Cm @console ,
or `console`, which is expanded from `/sys/class/tty/console/active`,
useful on embedded systems.
.Pp
The default baud rate is 0, i.e., keep kernel default.
.Pp
The `tty` stanza inherits runlevel, condition (and other feature)
parsing from the `service` stanza. So TTYs can run in one or many
runlevels and depend on any condition supported by Finit. This is
useful e.g. to depend on `<pid/elogind>` before starting a TTY.
.Bd -unfilled -offset indent
tty [12345] /dev/ttyAMA0 115200 noclear vt220
.Ed
.It Cm tty Oo LVLS Oc Ao COND Ac Ar CMD DEV Oo noclear Oc Oo nowait Oc
This form of the
.Cm tty
stanza is for using an external getty, like agetty or the BusyBox getty.
.Pp
By default, these first two syntax variants
.Em clear
the TTY and
.Em wait
for the user to press enter before starting getty.
.Bd -unfilled -offset indent
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
.Ed
.Pp
The
.Cm noclear
option disables clearing the TTY after each session. Clearing the TTY
when a user logs out is usually preferable.
.Pp
The
.Cm nowait
option disables the
.Cm Please press Enter to activate console
message before actually starting the getty program. On small and
embedded systems running multiple unused getty wastes both memory and
CPU cycles, so `wait` is the preferred default.
.Pp
The
.Cm nologin
option disables getty and
.Pa /bin/login ,
and gives the user a root (login) shell on the given TTY
.Cm DEV
immediately. Needless to say, this is a rather insecure option, but can
be very useful for developer builds, during board bringup, or similar.
.Pp
Notice the ordering, the
.Cm TERM
option to the built-in getty must be the last argument.
.Pp
Embedded systems may want to enable automatic `DEV` by supplying the
special
.Cm @console
device. This works regardless weather the system uses
.Cm ttyS0 , ttyAMA0 , ttyMXC0 ,
or anything else. Finit figures it out by querying sysfs:
.Pa /sys/class/tty/console/active .
The speed can be omitted to keep the kernel default.
.Pp
Most systems get by fine by just using `console`, which will evaluate
to
.Pa /dev/console .
If you have to use
.Cm @console
to get any output, you may have some issue with your kernel config.
.Bd -unfilled -offset indent
tty [12345] @console noclear vt220
.Ed
.Pp
On really bare bones systems, or for board bringup, Finit can give you a
shell prompt as soon as bootstrap is done, without opening any device
node:
.Bd -unfilled -offset indent
tty [12345789] notty
.Ed
.Pp
This should of course not be enabled on production systems. Because it
may give a user root access without having to log in. However, for
board bringup and system debugging it can come in handy.
.Pp
One can also use the
.Cm service
stanza to start a stand-alone shell:
.Bd -unfilled -offset indent
service [12345] /bin/sh -l
.Ed
.Pp
.It Cm tty Oo LVLS Oc Ao COND Ac Oo notty Oc Oo rescue Oc
The third
.Cm tty
form is for board bringup and the
.Cm rescue
boot mode. No device node is required in this variant, the same output
that the kernel uses is reused for stdio. If the
.Cm rescue
option is omitted, a shell is started. The flags
.Cm nologin , noclear ,
and
.Cm nowait
are implied. If the
.Cm rescue
option is set the bundled
.Pa /libexec/finit/sulogin
is started to present a bare-bones root login prompt. If the root
(uid:0, gid:0) user does not have a password set, no rescue is possible.
.El
.Sh COMMAND MODIFIERS
The run/task/tty/service/sysv stanzas take modifiers, or options, to
control their behavior. This section lists them with their limitations.
All modifiers must be placed between the stanza and its command.
.Bl -tag -width 1n
.It Cm @user:group
Every
.Cm run , task ,
or
.Cm service
can also list the privileges the
.Cm /path/to/cmd
should be executed with. Prefix the command with
.Cm @USR[:GRP] ,
group is optional, like this:
.Bd -unfilled -offset indent
run [2345] @joe:users logger "Hello world"
.Ed
.Pp
For multiple instances of the same command, e.g. a DHCP client or
multiple web servers, add
.Cm :ID
somewhere between the
.Cm run , task , service
keyword and the command, like this:
.Bd -unfilled -offset indent
service :80 [2345] httpd -f -h /http -p 80 -- Web server
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
.Ed
.Pp
Without the
.Cm :ID
to the service the latter will overwrite the former and only the old web
server would be started and supervised.
.It Cm log:/path/to/file
Redirect stdout/stderr of a command to the given log file. See the
global log directive, above, for details on log rotation.
.It Cm log:console
Redirect stdout/stderr of a command to
.Pa /dev/console ,
only use this for debugging or bringup.
.It Cm log:null
Redirect stdout/stderr of a command to
.Pa /dev/null .
.It Cm log:prio:facility.level,tag:ident
Redirect stdout/stderr of a command to syslog using the given priority
and tag identity.
.Bd -unfilled -offset indent
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
.Ed
.It Cm log
Default
.Cm prio
is
.Cm daemon.info
and the default
.Cm tag
identity is the basename of the service or run/task command.
.El
.Sh RESCUE MODE
Finit supports a rescue mode which is activated by the
.Cm rescue
option on the kernel command line. The rescue mode comes in two
flavors:
.Em traditional
and
.Em fallback .
.Ss Traditional
This is what most users expect. A very early maintenance login prompt,
served by the bundled
.Pa /libexec/finit/sulogin
program, or the standard
.Cm sulogin
from util-linux or BusyBox is searched for in the UNIX default
.Cm $PATH .
If a successful login is made, or the user exits (Ctrl-D), the rescue
mode is ended and the system boots up normally.
.Pp
.Sy Note:
if the user (UID 0 and GID 0) does not have a password, or
.Em the account is locked ,
the user is presented with a password-less prompt:
.Cm "Press enter to enter maintenance mode." ,
which opens up a root shell.
.Ss Fallback
If no
.Cm sulogin
program is found, Finit tries to bring up as much of its own
functionality as possible, yet limiting many aspects, meaning; no
network, no`fsck` of file systems in
.Pa /etc/fstab ,
no
.Pa /etc/rc.local ,
no
.Cm runparts ,
and most plugins are skipped (except those that provide functionality
for the condition subsystem).
.Pp
Instead of reading
.Pa /etc/finit.conf
et al, system configuration is read from
.Pa /lib/finit/rescue.conf ,
which can be freely modified by the system administrator.
.Pp
The bundled default `rescue.conf` contains nothing more than:
.Bd -unfilled -offset indent
runlevel 1
tty [12345] rescue
.Ed
.Pp
The
.Cm tty
has the
.Cm rescue
option set, which works similar to the board bring-up tty option
.Cm notty .
The major difference being that `sulogin` is started to query for
root/admin password. If
.Cm sulogin
is not found,
.Cm rescue
behaves like
.Cm notty
and gives a plain root shell prompt.
.Pp
If Finit cannot find
.Pa /lib/finit/rescue.conf
it defaults to:
.Bd -unfilled -offset indent
tty [12345] rescue
.Ed
.Pp
There is no way to exit the
.Em fallback
rescue mode.
.Sh SERVICE ENVIRONMENT
Finit supports sourcing environment variables from
.Pa /etc/default/* ,
or similar. This is a common pattern from SysV init scripts, where the
start/stop script is a generic script for the given service,
.Cm foo ,
and the options for the service are sourced from the file
.Pa /etc/default/foo .
Like this:
.Bd -unfilled -offset indent
/etc/default/foo:
FOO_OPTIONS=--extra-arg="bar" -s -x
/etc/finit.conf:
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
.Ed
.Pp
Here the service
.Cm foo
is started with
.Op Fl -n ,
to make sure it runs in the foreground, and the with the options found
in the environment file. With the
.Cm ps
command we can see that the process is started with:
.Bd -unfilled -offset indent
foo -n --extra-arg=bar -s -x
.Ed
.Pp
.Sy Note:
the leading `-` 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
.Em not
block the start.
.Sh SERVICE WRAPPER SCRIPTS
If your service requires to run additional commands, executed before the
service is actually started, like the systemd `ExecStartPre`, you can
use a wrapper shell script to start your service.
.Pp
The Finit service
.Cm .conf
file can be put into
.Pa /etc/finit.d/available ,
so you can control the service using
.Cm initctl .
Then use the path to the wrapper script in the Finit
.Cm .conf
service stanza. The following example employs a wrapper script in
.Pa /etc/start.d .
.Bd -unfilled
/etc/finit.d/available/program.conf:
service [235] <!> /etc/start.d/program -- Example Program
/etc/start.d/program:
#!/bin/sh
# Prepare the command line options
OPTIONS="-u $(cat /etc/username)"
# Execute the program
exec /usr/bin/program $OPTIONS
.Ed
.Pp
.Sy Note:
the example sets
.Cm <!>
to denote that it doesn't support SIGHUP. That way Finit will
stop/start the service instead of sending SIGHUP at restart/reload
events.
.Sh CGROUPS
There are three major cgroup configuration directives:
.Pp
.Bl -enum -offset indent -compact
.It
Global top-level group: init, system, user, or a custom group
.It
Selecting a top-level group for a set of run/task/services
.It
Per run/task/service limits
.El
.Pp
Top-level group configuration.
.Bd -unfilled -offset indent
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
cgroup init cpu.weight:100
cgroup user cpu.weight:100
cgroup system cpu.weight:9800
.Ed
.Pp
Adding an extra cgroup
.Cm maint/
will require you to adjust the weight of the above three. We leave
.Cm init/
and
.Cm user/
as-is reducing weight of
.Cm system/
to 9700.
.Bd -unfilled -offset indent
cgroup system cpu.weight:9700
# Example extra cgroup 'maint'
cgroup maint cpu.weight:100
.Ed
.Pp
By default, the
.Cm system/
cgroup is selected for almost everything. The
.Cm init/
cgroup is reserved for PID 1 itself and its closest relatives. The
.Cm user/
cgroup is for local TTY logins spawned by getty.
.Pp
To select a different top-level cgroup, e.g.
.Cm maint/ ,
one can either define it for a group of run/task/service directives in a
.Cm .conf
or per each stanza:
.Bd -unfilled -offset indent
cgroup.maint
service [...] <...> /path/to/foo args -- description
service [...] <...> /path/to/bar args -- description
.Ed
.Pp
or
.Bd -unfilled -offset indent
service [...] <...> cgroup.maint /path/to/foo args -- description
.Ed
.Pp
The latter form also allows per-stanza limits on the form:
.Bd -unfilled -offset indent
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
.Ed
.Pp
Notice the comma separation and the
.Cm mem.
exception to the rule: every cgroup setting maps directly to cgroup v2
syntax. I.e.,
.Cm cpu.max
maps to the file
.Pm /sys/fs/cgroup/maint/foo/cpu.max .
There is no filtering, except for expanding the shorthand
.Cm mem.
to
.Cm memory. ,
if the file is not available, either the cgroup controller is not
available in your Linux kernel, or the name is misspelled.
.Pp
Linux cgroups and details surrounding values are not explained in the
Finit documentation. The Linux admin-guide cover this well:
.Lk https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
.Sh LIMITATIONS
As of Finit v4 there are no limitations to where
.Cm .conf
settings can be placed. Except for the system/global
.Cm rlimit
and
.Cm cgroup
top-level group declarations, which can only be set from
.Pa /etc/finit.conf ,
since it is the first
.Cm .conf
file Finit reads.
.Pp
Originally,
.Pp /etc/finit.conf
was the only way to set up a Finit system. Today it is mainly used for
bootstrap settings like system hostname, early module loading for
watchdogd, network bringup and system shutdown. These can now also be
set in any
.Cm .conf
file in
.Pa /etc/finit.d .
.Pp
There is, however, nothing preventing you from having all configuration
settings in
.Pa /etc/finit.conf .
.Sh SEE ALSO
.Xr finit 8 ,
.Xr initctl 8
.Sh AUTHORS
.Nm finit
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others.
+186
View File
@@ -0,0 +1,186 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.Dd June 6, 2021
.\" Please adjust this date whenever revising the manpage.
.Dt INITCTL 8 SMM
.Os Linux
.Sh NAME
.Nm initctl
.Nd Control tool for Finit
.Sh SYNOPSIS
.Nm /sbin/initctl
.Op Fl bcfhlpqtv
.Op COMMAND
.Sh DESCRIPTION
.Nm
is the official tool for interacting with
.Xr finit 8 .
It comes with functions for showing status, querying health of services,
as well as editing, enabling and disabling services.
.Sh OPTIONS
This program follows the usual UNIX command line syntax, with long
options starting with two dashes (`-'). The options are as follows:
.Bl -tag -width Ds
.It Fl b, -batch
Batch mode, no screen size probing.
.It Fl c, -create
Create missing paths (and files) as needed. Useful with the edit command.
.It Fl f, -force
Ignore missing files and arguments, never prompt.
.It Fl h, -help
Show built-in help text.
.It Fl 1, -once
Only one lap in commands like top.
.It Fl p, -plain
Use plain table headings, no ANSI control characters.
.It Fl q, -quiet
Silent, only return status of command.
.It Fl t, -no-heading
Skip table headings.
.It Fl v, -verbose
Verbose output, where applicable.
.El
.Sh COMMANDS
.Bl -tag -width Ds
.It Nm Ar debug
Toggle finit (daemon) debug to
.Pa /dev/console
.It Nm Ar help
Show built-in help text
.It Nm Ar version
Show Finit (daemon) version
.It Nm Ar ls | list
List all
.Cm *.conf
files in
.Pa /etc/finit.d
.It Nm Ar create Ar CONF
Create
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar delete Ar CONF
Delete
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar show Ar CONF
Show
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar edit Ar CONF
Edit
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar touch Ar CONF
Change (mark as modified)
.Cm .conf
in
.Pa /etc/finit.d/available ,
like
.Ar edit
this tells
.Nm finit
that a configuration has been changed and is a candidate to be restarted
(or SIGHUP'ed) on
.Cm initctl reload
.It Nm Ar enable Ar CONF
Enable
.Cm .conf
in
.Pa /etc/finit.d/available ,
i.e., add symlink in
.Pa /etc/finit.d/enabled
.It Nm Ar disable Ar CONF
Disable
.Cm .conf
in
.Pa /etc/finit.d/enabled ,
i.e., removes symlink
.It Nm Ar reload
Reload
.Cm *.conf in
.Pa /etc/finit.d ,
i.e., activates changes
.It Nm Ar cond set Ar COND
Set (assert) user-defined condition,
.Cm +usr/COND
.It Nm Ar cond clr | clear Ar COND
Clear (deassert) user-defined condition,
.Cm -usr/COND
.It Nm Ar cond status
Show condition status, default
.Cm cond
command.
.It Nm Ar cond dump
Dump all conditions and their status
.It Nm Ar ident Op Cm NAME
Display indentities of all run/task/services, or only instances
matching
.Cm NAME .
A partial string, e.g.,
.Cm NAM ,
will not match anything
.It Nm Ar log Op Cm NAME
Show ten last Finit, or
.Cm NAME ,
messages from syslog
.It Nm Ar start Cm NAME[:ID]
Start service by name, with optional ID, e.g.,
.Cm initctl start tty:1
.It Nm Ar stop Cm NAME[:ID]
Stop/Pause a running service by name
.It Nm Ar reload Cm NAME[:ID]
Reload service by name (SIGHUP or restart)
.It Nm Ar restart Cm NAME[:ID]
Restart (stop/start) service by name
.It Nm Ar status Cm NAME[:ID]
Show service status, by name. If only
.Cm NAME
is given and multiple instances exits, a summary of all matching
instances are shown. Only an exact match displays the detailed status
for a particular instance
.It Nm Ar status
Show status of all services, default command
.It Nm Ar cgroup
List cgroup config overview
.It Nm Ar ps
List processes based on cgroups
.It Nm Ar top
Show top-like listing based on cgroups
.It Nm Ar runlevel Op Ar 0-9
Show or set runlevel: 0 halt, 6 reboot
.It Nm Ar reboot
Reboot system, default if
.Cm reboot
is symlinked to
.Nm
.It Nm Ar halt
Halt system, default if
.Cm halt
is symlinked to
.Nm
.It Nm Ar poweroff
Power-off system, default if
.Cm poweroff
is symlinked to
.Nm
.It Nm Ar suspend
Suspend system, default if
.Cm suspend
is symlinked to
.Nm
.It Nm Ar utmp show
Raw dump of UTMP/WTMP db
.El
.Sh SEE ALSO
.Xr finit.conf 5
.Xr finit 8
.Sh AUTHORS
.Nm finit
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others.
+22 -2
View File
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
if STATIC
noinst_LTLIBRARIES = libplug.la
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c usr.c
libplug_la_SOURCES = bootmisc.c modprobe.c pidfile.c procps.c sys.c tty.c usr.c
if BUILD_ALSA_UTILS_PLUGIN
libplug_la_SOURCES += alsa-utils.c
@@ -33,8 +33,20 @@ if BUILD_RESOLVCONF_PLUGIN
libplug_la_SOURCES += resolvconf.c
endif
if BUILD_RTC_PLUGIN
libplug_la_SOURCES += rtc.c
endif
if BUILD_URANDOM_PLUGIN
libplug_la_SOURCES += urandom.c
endif
if BUILD_X11_COMMON_PLUGIN
libplug_la_SOURCES += x11-common.c
endif
else
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la usr.la
pkglib_LTLIBRARIES = bootmisc.la modprobe.la pidfile.la procps.la sys.la tty.la usr.la
if BUILD_ALSA_UTILS_PLUGIN
pkglib_LTLIBRARIES += alsa-utils.la
@@ -60,6 +72,14 @@ if BUILD_RESOLVCONF_PLUGIN
pkglib_LTLIBRARIES += resolvconf.la
endif
if BUILD_RTC_PLUGIN
pkglib_LTLIBRARIES += rtc.la
endif
if BUILD_URANDOM_PLUGIN
pkglib_LTLIBRARIES += urandom.la
endif
if BUILD_X11_COMMON_PLUGIN
pkglib_LTLIBRARIES += x11-common.la
endif
+6 -1
View File
@@ -21,7 +21,12 @@
* THE SOFTWARE.
*/
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
+25 -8
View File
@@ -24,7 +24,11 @@
#include <ftw.h>
#include <mntent.h>
#include <string.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "config.h"
#include "finit.h"
@@ -100,6 +104,12 @@ static void clean(void *arg)
}
}
static void ln(const char *target, const char *linkpath, int ignerr)
{
if (symlink(target, linkpath) && !ignerr)
_pe("Failed creating %s -> %s symlink", target, linkpath);
}
/*
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
*/
@@ -119,15 +129,16 @@ static void setup(void *arg)
makedir("/var/lib/urandom",0755);
if (fisdir("/run")) {
_d("System with new /run tmpfs ...");
makedir("/run/lock", 1777);
symlink("/run/lock", "/var/lock");
symlink("/dev/shm", "/run/shm");
if (!fisdir("/run/lock"))
makedir("/run/lock", 1777);
ln("/run/lock", "/var/lock", 0);
ln("/dev/shm", "/run/shm", 0);
/* compat only, should really be set up by OS/dist */
symlink("/run", "/var/run");
ln("/run", "/var/run", 1);
} else {
makedir("/var/lock", 1777);
makedir("/var/run", 0755);
makedir("/var/lock", 1777);
makedir("/var/run", 0755);
}
makedir("/var/log", 0755);
makedir("/var/mail", 0755);
@@ -178,11 +189,17 @@ static void setup(void *arg)
makedir("/var/run/sshd", 01755); /* OpenSSH */
if (!fexist("/etc/mtab"))
symlink("../proc/self/mounts", "/etc/mtab");
ln("../proc/self/mounts", "/etc/mtab", 1);
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
/* Debian has /run/sudo, ensure correct perms and SELinux label */
mksubsys("/var/run/sudo", 0711, "root", "root");
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
if (whichp("restorecon"))
run("restorecon /var/run/sudo /var/run/sudo/ts");
umask(prev);
}
+14 -4
View File
@@ -22,7 +22,11 @@
*/
#include <sys/types.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "config.h"
@@ -35,7 +39,13 @@
#define ARGS "--nofork --system --syslog-only"
#define DESC "D-Bus message bus daemon"
#ifndef DAEMONUSER
#define DAEMONUSER "messagebus"
#endif
#ifndef DAEMONPIDFILE
#define DAEMONPIDFILE "/var/run/dbus/pid"
#endif
static void setup(void *arg)
{
@@ -61,11 +71,11 @@ static void setup(void *arg)
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
/* Clean up from any previous pre-bootstrap run */
remove("/var/run/dbus/pid");
remove(DAEMONPIDFILE);
/* Register service with Finit */
snprintf(line, sizeof(line), "[S12345789] @%s:%s %s %s -- %s",
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
_pe("Failed registering %s", DAEMON);
free(cmd);
+3 -3
View File
@@ -48,17 +48,17 @@ static void setup(void *arg)
path = which("/lib/systemd/systemd-udevd");
if (path) {
/* Register udevd as a monitored service */
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
snprintf(cmd, sizeof(cmd), "[S12345789] cgroup.system pid:udevd name:udevd log %s "
"-- Device event managing daemon", path);
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
_pe("Failed registering %s", path);
} else {
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
snprintf(cmd, sizeof(cmd), "cgroup.init :1 [S] <pid/udevd> log "
"udevadm trigger -c add -t devices "
"-- Requesting device events");
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
snprintf(cmd, sizeof(cmd), "cgroup.init :2 [S] <pid/udevd> log "
"udevadm trigger -c add -t subsystems "
"-- Requesting subsystem events");
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
+6 -2
View File
@@ -40,11 +40,15 @@
#include <sys/stat.h>
#include <sys/time.h> /* gettimeofday() */
#include <sys/types.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "config.h"
#include "finit.h"
#include "helpers.h"
#include "util.h"
#include "plugin.h"
struct module {
+25 -16
View File
@@ -21,10 +21,14 @@
* THE SOFTWARE.
*/
#include <lite/lite.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
@@ -36,43 +40,48 @@
#define MODULES_LOAD_PATH "/etc/modules-load.d"
#endif
#define SERVICE_LINE \
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
static void load(void *arg)
{
FILE *fp;
DIR *dirp;
struct dirent *direntp;
struct dirent *d;
char line[256];
int index = 1;
FILE *fp;
DIR *dir;
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
dirp = opendir(MODULES_LOAD_PATH);
if (!dirp) return;
dir = opendir(MODULES_LOAD_PATH);
if (!dir)
return;
while ((direntp = readdir(dirp)))
{
while ((d = readdir(dir))) {
char module_path[PATH_MAX];
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
strlcat(module_path, direntp->d_name, sizeof(module_path));
strlcat(module_path, d->d_name, sizeof(module_path));
fp = fopen(module_path, "r");
if (!fp) continue;
if (!fp)
continue;
while (fgets(line, sizeof(line), fp)) {
char cmd[CMD_SIZE], *mod, *args;
mod = strip_line(line);
if (!*mod) continue;
if (!*mod)
continue;
mod = chomp(mod);
if (!mod || !*mod) continue;
if (!mod || !*mod)
continue;
mod = strtok_r(mod, " ", &args);
if (!mod)
continue;
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
index, mod, mod, args, mod);
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
index++;
@@ -81,7 +90,7 @@ static void load(void *arg)
fclose(fp);
}
closedir(dirp);
closedir(dir);
}
static plugin_t plugin = {
+196 -108
View File
@@ -30,27 +30,22 @@
#include "cond.h"
#include "helpers.h"
#include "plugin.h"
#include "service.h"
static int ifdown = 0;
#define NL_BUFSZ 4096
struct nl_request {
struct nlmsghdr nh;
union {
struct rtmsg rtm;
struct ifinfomsg ifi;
};
};
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
{
if (!NLMSG_OK(nh, len))
return 1;
static int nl_defidx;
static int nl_ifdown;
static char *nl_buf;
if (nh->nlmsg_type == NLMSG_DONE) {
_d("Done with netlink messages.");
return 1;
}
if (nh->nlmsg_type == NLMSG_ERROR) {
_d("Netlink reports error.");
return 1;
}
return 0;
}
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
{
@@ -109,41 +104,14 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
_d("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
if ((!dst && !plen) && (gw || idx)) {
if (nlmsg->nlmsg_type == RTM_DELROUTE)
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
cond_clear("net/route/default");
else
nl_defidx = 0;
} else {
cond_set("net/route/default");
}
}
static int nl_default(struct nlmsghdr *nlh, struct in_addr *dst, struct in_addr *gw)
{
struct in_addr nil = { 0 };
struct rtattr *a;
struct rtmsg *r;
int len;
r = (struct rtmsg *)NLMSG_DATA(nlh);
if ((r->rtm_family != AF_INET) || (r->rtm_table != RT_TABLE_MAIN))
return -1;
len = RTM_PAYLOAD(nlh);
for (a = RTM_RTA(r); RTA_OK(a, len); a = RTA_NEXT(a, len)) {
switch (a->rta_type) {
case RTA_GATEWAY:
memcpy(gw, RTA_DATA(a), sizeof(*gw));
break;
case RTA_DST:
memcpy(dst, RTA_DATA(a), sizeof(*dst));
break;
nl_defidx = idx;
}
}
if (!memcmp(dst, &nil, sizeof(nil)) && memcmp(gw, &nil, sizeof(nil)))
return 0;
return 1;
}
static void net_cond_set(char *ifname, char *cond, int set)
@@ -177,6 +145,19 @@ static int validate_ifname(const char *ifname)
return 0;
}
/*
* Check if this interface was associated with the default route
* previously, or if it's been removed. If so, trigger a recheck
* of the system default route.
*/
static void nl_check_default(char *ifname)
{
int idx = (int)if_nametoindex(ifname);
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
nl_ifdown = 1;
}
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
{
char ifname[IFNAMSIZ + 1];
@@ -218,7 +199,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
ifdown = 1;
nl_check_default(ifname);
break;
case RTM_DELLINK:
@@ -227,7 +208,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
net_cond_set(ifname, "exist", 0);
net_cond_set(ifname, "up", 0);
net_cond_set(ifname, "running", 0);
ifdown = 1;
nl_check_default(ifname);
break;
case RTM_NEWADDR:
@@ -245,76 +226,176 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
}
}
static void nl_callback(void *arg, int sd, int events)
static int nl_parse(int sd)
{
static char buf[4096];
struct nlmsghdr *nh;
ssize_t len;
while (1) {
struct nlmsghdr *nh;
ssize_t len;
size_t l;
memset(buf, 0, sizeof(buf));
len = recv(sd, buf, sizeof(buf), 0);
if (len < 0) {
if (errno != EINTR) /* Signal */
_pe("recv()");
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
switch (errno) {
case EAGAIN: /* Nothing more right now. */
return 0;
case EINTR: /* Signal */
continue;
case ENOBUFS: /* netlink(7) */
break;
default:
_pe("recv()");
break;
}
return -1;
}
_d("recv %lld bytes", len);
l = (size_t)len;
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
struct nlmsgerr *nle;
switch (nh->nlmsg_type) {
case NLMSG_DONE:
_d("Done with netlink messages.");
return 0;
case NLMSG_ERROR:
_d("Kernel netlink comm. error.");
nle = NLMSG_DATA(nh);
if (nle) {
errno = -nle->error;
_pe("Kernel netlink error %d", errno);
}
return -1;
case RTM_NEWROUTE:
case RTM_DELROUTE:
_d("Netlink route ...");
nl_route(nh, len);
break;
case RTM_NEWLINK:
case RTM_DELLINK:
_d("Netlink link ...");
nl_link(nh, len);
break;
default:
_w("unhandled netlink message, type %d", nh->nlmsg_type);
break;
}
}
}
}
static int nl_request(int sd, unsigned int seq, int type)
{
struct nl_request *nlr = (struct nl_request *)nl_buf;
memset(nlr, 0, sizeof(struct nl_request));
nlr->nh.nlmsg_type = type;
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
nlr->nh.nlmsg_seq = seq;
nlr->nh.nlmsg_pid = 1;
switch (type) {
case RTM_GETROUTE:
_d("RTM_GETROUTE");
nlr->rtm.rtm_family = AF_INET;
nlr->rtm.rtm_table = RT_TABLE_MAIN;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
break;
case RTM_GETLINK:
_d("RTM_GETLINK");
nlr->ifi.ifi_family = AF_UNSPEC;
nlr->ifi.ifi_change = 0xFFFFFFFF;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
break;
default:
_w("Cannot resync, unhandled message type %d", type);
return -1;
}
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
return 1;
return nl_parse(sd);
}
static void nl_resync_routes(int sd, unsigned int seq)
{
if (nl_request(sd, seq, RTM_GETROUTE))
_pe("Failed netlink route request");
}
static void nl_resync_ifaces(int sd, unsigned int seq)
{
if (nl_request(sd, seq, RTM_GETLINK))
_pe("Failed netlink link request");
}
/*
* We've potentially lost netlink events, let's resync with kernel.
*/
static void nl_resync(int all)
{
unsigned int seq = 0;
int sd;
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sd < 0) {
_pe("netlink socket");
return;
}
/* check for interface changes -> loss of default route */
ifdown = 0;
if (all) {
_d("============================ RESYNC =================================");
/* this doesn't update conditions, and thus does not stop services */
cond_deassert("net/");
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
nl_route(nh, len);
else
nl_link(nh, len);
nl_resync_ifaces(sd, seq++);
nl_resync_routes(sd, seq++);
/* delayed update after we've corrected things */
service_step_all(SVC_TYPE_ANY);
_d("=========================== RESYNCED ================================");
} else
nl_resync_routes(sd, seq++);
close(sd);
}
static void nl_callback(void *arg, int sd, int events)
{
if (nl_parse(sd) < 0) {
if (errno == ENOBUFS) { /* netlink(7) */
_w("busy system, resynchronizing with kernel.");
nl_resync(1);
return;
}
}
/*
* Linux doesn't send route changes, when interfaces go down, so
* Linux doesn't send route changes when interfaces go down, so
* we need to check ourselves, e.g. for loss of default route.
*/
if (ifdown) {
unsigned int seq = 0;
int found = 0;
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sd < 0) {
_pe("netlink socket");
return;
if (nl_ifdown) {
_d("interface down, checking default route.");
if (nl_defidx > 0) {
nl_defidx = 0;
nl_resync(0);
if (nl_defidx <= 0) {
cond_clear("net/route/default");
nl_defidx = 0;
}
}
memset(buf, 0, sizeof(buf));
nh = (struct nlmsghdr *)buf;
nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nh->nlmsg_type = RTM_GETROUTE;
nh->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
nh->nlmsg_seq = seq++;
nh->nlmsg_pid = 1;
if (send(sd, nh, nh->nlmsg_len, 0) < 0) {
_pe("Failed netlink route request");
close(sd);
return;
}
len = recv(sd, buf, sizeof(buf), 0);
close(sd);
for (; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
struct in_addr dst = { 0 };
struct in_addr gw = { 0 };
if (nl_default(nh, &dst, &gw))
continue;
_d("default via %s\n", inet_ntoa(gw));
found = 1;
}
/* We already get notification when adding default rt */
if (!found)
cond_clear("net/route/default");
nl_ifdown = 0;
}
}
@@ -345,7 +426,7 @@ PLUGIN_INIT(plugin_init)
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
sa.nl_pid = getpid();
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
@@ -354,6 +435,13 @@ PLUGIN_INIT(plugin_init)
return;
}
nl_buf = malloc(NL_BUFSZ);
if (!nl_buf) {
_pe("malloc()");
close(sd);
return;
}
plugin.io.fd = sd;
plugin_register(&plugin);
}
+3 -1
View File
@@ -84,8 +84,10 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
mkcond(svc, cond, sizeof(cond));
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
svc_started(svc);
if (!svc_has_pidfile(svc))
if (!svc_has_pidfile(svc)) {
_d("Setting %s PID file to %s", svc->name, fn);
pid_file_set(svc, fn, 1);
}
if (svc_is_forking(svc)) {
pid_t pid;
+5 -1
View File
@@ -22,7 +22,11 @@
*/
#include <glob.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
+5 -1
View File
@@ -21,7 +21,11 @@
* THE SOFTWARE.
*/
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
+16 -2
View File
@@ -24,7 +24,11 @@
#include <time.h>
#include <sys/ioctl.h>
#include <linux/rtc.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
@@ -152,8 +156,18 @@ static void rtc_restore(void *arg)
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
else
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
/* Been here already? */
if (rc)
goto out;
/* Attempt to set RTC to a sane value ... */
tv.tv_sec = RTC_TIMESTAMP_BEGIN_2000;
if (!gmtime_r(&tv.tv_sec, &tm))
goto out;
logit(LOG_NOTICE, "Resetting RTC to kernel default, 2000-01-01 00:00.");
rc = 2;
goto out;
}
print_desc(NULL, "Restoring system clock (UTC) from RTC");
+209
View File
@@ -0,0 +1,209 @@
/* System condition event monitor for the Finit condition engine
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <dirent.h>
#include <fnmatch.h>
#include <glob.h>
#include <limits.h>
#include <paths.h>
#include "finit.h"
#include "cond.h"
#include "pid.h"
#include "plugin.h"
#include "iwatch.h"
static struct iwatch iw_sys;
static int sys_add_path(struct iwatch *iw, char *path)
{
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
}
/*
* unlink conditions with no active task/service, otherwise they may
* trigger inadvertently when calling `initctl reload` to activate
* a new configuration.
*/
static void sys_update_conds(char *dir, char *name, uint32_t mask)
{
char path[256];
char *cond;
char *ptr;
ptr = strrchr(name, '/');
if (ptr)
snprintf(path, sizeof(path), "%s/%s", dir, ++ptr);
else
snprintf(path, sizeof(path), "%s/%s", dir, name);
cond = strstr(path, COND_BASE);
if (!cond)
return;
cond += strlen(COND_BASE) + 1;
_d("cond: %s set: %d", cond, mask & IN_CREATE ? 1 : 0);
if (!cond_update(cond))
unlink(path);
}
/* synthesize events in case of new run dirs */
static void sys_scandir(struct iwatch *iw, char *dir, int len)
{
glob_t gl;
size_t i;
char path[len + 6];
int rc;
snprintf(path, sizeof(path), "%s/*", dir);
rc = glob(path, GLOB_NOSORT, NULL, &gl);
if (rc && rc != GLOB_NOMATCH)
return;
for (i = 0; i < gl.gl_pathc; i++) {
_d("scan found %s", gl.gl_pathv[i]);
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
}
globfree(&gl);
}
/*
* create/remove sub-directory in monitored directory
*/
static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
{
char path[strlen(dir) + strlen(name) + 2];
struct iwatch_path *iwp;
paste(path, sizeof(path), dir, name);
_d("path: %s", path);
iwp = iwatch_find_by_path(iw, path);
if (mask & IN_CREATE) {
if (!iwp) {
if (!sys_add_path(iw, path))
sys_scandir(iw, path, sizeof(path));
}
} else if (mask & IN_DELETE) {
if (iwp)
iwatch_del(&iw_sys, iwp);
}
}
static void sys_callback(void *arg, int fd, int events)
{
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
struct inotify_event *ev;
ssize_t sz;
size_t off;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
_pe("invalid inotify event");
return;
}
ev_buf[sz] = 0;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
struct iwatch_path *iwp;
if (off + sizeof(*ev) > (size_t)sz)
break;
ev = (struct inotify_event *)&ev_buf[off];
if (off + sizeof(*ev) + ev->len > (size_t)sz)
break;
_d("name %s, event: 0x%08x", ev->name, ev->mask);
if (!ev->mask)
continue;
/* Find base path for this event */
iwp = iwatch_find_by_wd(&iw_sys, ev->wd);
if (!iwp)
continue;
if (ev->mask & IN_ISDIR) {
sys_handle_dir(&iw_sys, iwp->path, ev->name, ev->mask);
continue;
}
if (ev->mask & (IN_CREATE | IN_DELETE))
sys_update_conds(iwp->path, ev->name, ev->mask);
}
}
static void sys_init(void *arg)
{
char sysdir[MAX_ARG_LEN];
char *path;
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
return;
}
path = realpath(_PATH_CONDSYS, NULL);
if (!path) {
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
return;
}
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
iwatch_exit(&iw_sys);
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
};
PLUGIN_INIT(plugin_init)
{
int fd;
fd = iwatch_init(&iw_sys);
if (fd < 0)
return;
plugin.io.fd = fd;
plugin.io.cb = sys_callback;
plugin.io.flags = PLUGIN_IO_READ;
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
iwatch_exit(&iw_sys);
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+5 -1
View File
@@ -27,7 +27,11 @@
#include <unistd.h> /* read() */
#include <sys/inotify.h>
#include <sys/stat.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
+71 -4
View File
@@ -1,4 +1,4 @@
/* Setup random seed
/* Setup and save random seed at boot/shutdown
*
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
@@ -22,19 +22,34 @@
*/
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h> /* gettimeofday() */
#include <sys/types.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include <linux/random.h>
#include "config.h"
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#ifndef RANDOM_BYTES
#define RANDOM_BYTES (32*1024)
#endif
static void setup(void *arg)
{
#ifdef RANDOMSEED
struct rand_pool_info *rpi;
ssize_t len = 0;
int rc = -1;
int fd, err;
if (rescue) {
_d("Skipping %s plugin in rescue mode.", __FILE__);
return;
@@ -67,7 +82,59 @@ static void setup(void *arg)
}
print_desc("Initializing random number generator", NULL);
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
/*
* Simply copying our saved entropy to /dev/urandom doesn't
* increment the kernel "entropy count", instead we must use
* the ioctl below.
*/
fd = open(RANDOMSEED, O_RDONLY);
if (fd < 0)
goto fallback;
rpi = malloc(sizeof(*rpi) + RANDOM_BYTES);
if (!rpi) {
close(fd);
goto fallback;
}
do {
ssize_t num;
num = read(fd, &rpi->buf[len], RANDOM_BYTES - len);
if (num <= 0) {
if (num == -1 && errno == EINTR)
continue;
if (len > 0)
break;
close(fd);
free(rpi);
goto fallback;
}
len += num;
} while (len < RANDOM_BYTES);
close(fd);
fd = open("/dev/urandom", O_WRONLY);
if (fd < 0) {
free(rpi);
goto fallback;
}
rpi->buf_size = len;
rpi->entropy_count = len * 8;
rc = ioctl(fd, RNDADDENTROPY, rpi);
err = errno;
close(fd);
free(rpi);
if (rc < 0)
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
print_result(rc < 0);
return;
fallback:
print_result(512 > copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
#endif
}
@@ -84,7 +151,7 @@ static void save(void *arg)
prev = umask(077);
print_desc("Saving random seed", NULL);
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
print_result(RANDOM_BYTES != copyfile("/dev/urandom", RANDOMSEED, RANDOM_BYTES, 0));
umask(prev);
#endif
+3 -1
View File
@@ -1,4 +1,4 @@
/* User-defined condtion event monitor for the Finit condition engine
/* User-defined condition event monitor for the Finit condition engine
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
@@ -97,6 +97,8 @@ static void usr_init(void *arg)
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
iwatch_exit(&iw_usr);
free(path);
}
static plugin_t plugin = {
+5 -1
View File
@@ -24,7 +24,11 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
+2
View File
@@ -1,6 +1,8 @@
.deps/*
finit
getty
initctl
keventd
logit
reboot
sulogin
+19 -6
View File
@@ -8,18 +8,31 @@ AM_LDFLAGS = -export-dynamic
endif
sbin_PROGRAMS = finit initctl
pkglibexec_PROGRAMS = logit sulogin
pkglibexec_PROGRAMS = getty logit sulogin
if KEVENTD
pkglibexec_PROGRAMS += keventd
endif
if WATCHDOGD
pkglibexec_PROGRAMS += watchdogd
endif
finit_pkglibdir = $(pkglibdir)
finit_pkglib_SCRIPTS = rescue.conf sample.conf
getty_SOURCES = finit.h getty.c helpers.h logrotate.c stty.c utmp-api.c utmp-api.h
getty_CFLAGS = -W -Wall -Wextra -std=gnu99
getty_CFLAGS += $(lite_CFLAGS)
getty_LDADD = $(lite_LIBS)
keventd_SOURCES = keventd.c iwatch.c iwatch.h util.c util.h
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
keventd_CFLAGS += $(lite_CFLAGS)
keventd_LDADD = $(lite_LIBS)
sulogin_SOURCES = sulogin.c
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
sulogin_LDADD = -lcrypt
if WATCHDOGD
pkglibexec_PROGRAMS += watchdogd
endif
logit_SOURCES = logit.c logrotate.c
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
logit_CFLAGS += $(lite_CFLAGS)
@@ -29,7 +42,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
cond.c cond-w.c cond.h \
conf.c conf.h \
exec.c finit.c finit.h \
getty.c stty.c \
stty.c \
helpers.c helpers.h \
iwatch.c iwatch.h \
log.c log.h \
+18 -7
View File
@@ -29,7 +29,11 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include <uev/uev.h>
#include "config.h"
@@ -387,7 +391,7 @@ static void api_cb(uev_t *w, void *arg, int events)
break;
}
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
_d("Request to hand-over wdog ... to PID %d", rq.runlevel);
svc = svc_find_by_pid(rq.runlevel);
if (!svc) {
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
@@ -413,7 +417,7 @@ static void api_cb(uev_t *w, void *arg, int events)
case INIT_CMD_SVC_ITER:
// _d("svc iter, first: %d", rq.runlevel);
/*
* XXX: This severly limits the number of
* XXX: This severely limits the number of
* simultaneous client connections, but will
* have to do for now.
*/
@@ -466,12 +470,13 @@ error:
int api_init(uev_ctx_t *ctx)
{
int sd;
mode_t oldmask;
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
.sun_path = INIT_SOCKET,
};
mode_t oldmask;
int uid, gid;
int sd;
_d("Setting up external API socket ...");
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
@@ -480,20 +485,26 @@ int api_init(uev_ctx_t *ctx)
return 1;
}
uid = geteuid();
gid = getgroup(DEFGROUP);
erase(INIT_SOCKET);
oldmask = umask(0077);
oldmask = umask(0117);
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
goto error;
if (-1 == listen(sd, 10))
goto error;
if (chown(INIT_SOCKET, uid, gid))
_pe("Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
umask(oldmask);
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
return 0;
error:
_pe("Failed intializing API socket");
_pe("Failed initializing API socket");
umask(oldmask);
close(sd);
return 1;
+44 -7
View File
@@ -24,8 +24,13 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <lite/lite.h>
#include <lite/queue.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
# include <libite/queue.h> /* BSD sys/queue.h API */
#else
# include <lite/lite.h>
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include <sys/mount.h>
#include <sys/sysinfo.h> /* get_nprocs_conf() */
@@ -42,7 +47,7 @@ struct cg {
char *cfg; /* kernel settings */
int active; /* for mark & sweep */
int protected; /* for init/, user/, & system/ */
int is_protected; /* for init/, user/, & system/ */
};
static TAILQ_HEAD(, cg) cgroups = TAILQ_HEAD_INITIALIZER(cgroups);
@@ -51,6 +56,7 @@ static char controllers[256];
static struct iwatch iw_cgroup;
static uev_t cgw;
static int avail;
static void cgset(const char *path, char *ctrl, char *prop)
@@ -159,6 +165,9 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
int cgroup_user(char *name, int pid)
{
if (!avail)
return 0;
return cgroup_leaf_init("user", name, pid, NULL);
}
@@ -166,12 +175,18 @@ int cgroup_service(char *name, int pid, struct cgroup *cg)
{
char *group = "system";
if (!avail)
return 0;
if (cg && cg->name[0]) {
char path[256];
if (!strcmp(cg->name, "root"))
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
if (!strcmp(cg->name, "init"))
return fnwrite(str("%d", pid), FINIT_CGPATH "/init/cgroup.procs");
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
if (fisdir(path))
group = cg->name;
@@ -299,8 +314,11 @@ void cgroup_mark_all(void)
{
struct cg *cg;
if (!avail)
return;
TAILQ_FOREACH(cg, &cgroups, link) {
if (cg->protected)
if (cg->is_protected)
continue;
cg->active = 0;
@@ -315,6 +333,9 @@ void cgroup_cleanup(void)
struct cg *cg, *tmp;
char path[256];
if (!avail)
return;
TAILQ_FOREACH_SAFE(cg, &cgroups, link, tmp) {
if (cg->active)
continue;
@@ -327,10 +348,13 @@ void cgroup_cleanup(void)
/*
* Add, or update, settings for top-level cgroup
*/
int cgroup_add(char *name, char *cfg, int protected)
int cgroup_add(char *name, char *cfg, int is_protected)
{
struct cg *cg;
if (!avail)
return 0;
if (!name)
return -1;
if (!cfg)
@@ -361,7 +385,7 @@ int cgroup_add(char *name, char *cfg, int protected)
free(cg);
return -1;
}
cg->protected = protected;
cg->is_protected = is_protected;
cg->active = 1;
return 0;
@@ -375,6 +399,9 @@ int cgroup_del(char *dir)
struct cg *cg;
char path[256];
if (!avail)
return 0;
TAILQ_FOREACH(cg, &cgroups, link) {
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
if (strcmp(path, dir))
@@ -406,6 +433,9 @@ void cgroup_config(void)
{
struct cg *cg;
if (!avail)
return;
TAILQ_FOREACH(cg, &cgroups, link) {
char path[256];
int leaf = 0;
@@ -434,14 +464,21 @@ void cgroup_init(uev_ctx_t *ctx)
int fd;
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
_pe("Failed mounting cgroup v2");
if (errno == ENOENT)
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
else
_pe("Failed mounting cgroup v2, disabling.");
avail = 0;
return;
}
avail = 1;
/* Find available controllers */
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
if (!fp) {
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
umount(FINIT_CGPATH);
avail = 0;
return;
}
+1 -1
View File
@@ -34,7 +34,7 @@ struct cgroup {
void cgroup_mark_all(void);
void cgroup_cleanup (void);
int cgroup_add (char *name, char *cfg, int protected);
int cgroup_add (char *name, char *cfg, int is_protected);
int cgroup_del (char *dir);
void cgroup_config (void);
+9 -1
View File
@@ -30,7 +30,11 @@
#include <stdlib.h>
#include <search.h>
#include <inttypes.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include <sys/sysinfo.h> /* sysinfo() */
#include "cgutil.h"
@@ -49,6 +53,10 @@ uint64_t total_ram; /* From sysinfo() */
struct cg dummy; /* empty result "NULL" */
struct cg *list;
int cgroup_avail(void)
{
return fismnt(FINIT_CGPATH);
}
char *pid_cmdline(int pid, char *buf, size_t len)
{
+2
View File
@@ -52,6 +52,8 @@ struct cg {
} cg_cpu;
};
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);
+6 -2
View File
@@ -67,6 +67,7 @@ int client_send(struct init_request *rq, ssize_t len)
{
struct pollfd pfd = { 0 };
int sd, result = 255;
int rc;
sd = client_connect();
if (-1 == sd)
@@ -86,8 +87,11 @@ int client_send(struct init_request *rq, ssize_t len)
pfd.fd = sd;
pfd.events = POLLIN;
if (poll(&pfd, 1, 2000) <= 0) {
warn("Timed out waiting for reply from Finit, errno %d", errno);
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
if (rc)
warn("poll(), errno %d", errno);
else
warnx("Timed out waiting for reply from Finit.");
goto exit;
}
+82 -22
View File
@@ -23,8 +23,12 @@
#include <ftw.h>
#include <libgen.h>
#include <lite/lite.h>
#include <stdio.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "cond.h"
@@ -163,58 +167,92 @@ int cond_set_path(const char *path, enum cond_state next)
return next != prev;
}
/* Should only be used by cond_set*(), cond_clear(), and usr plugin! */
void cond_update(const char *name)
/* Should only be used by cond_set*(), cond_clear(), and usr/sys plugins! */
int cond_update(const char *name)
{
svc_t *svc, *iter = NULL;
int affects = 0;
_d("%s", name);
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
continue;
affects++;
_d("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
service_step(svc);
}
return affects;
}
int cond_set_noupdate(const char *name)
{
_d("%s", name);
if (string_compare(name, "nop"))
return 1;
if (!cond_set_path(cond_path(name), COND_ON))
return 1;
return 0;
}
void cond_set(const char *name)
{
_d("%s", name);
if (string_compare(name, "nop"))
return;
if (!cond_set_path(cond_path(name), COND_ON))
if (cond_set_noupdate(name))
return;
cond_update(name);
}
void cond_set_oneshot(const char *name)
int cond_set_oneshot_noupdate(const char *name)
{
const char *path;
if (string_compare(name, "nop"))
return;
return 1;
path = cond_path(name);
_d("%s => %s", name, path);
if (cond_checkpath(path))
return 1;
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
_pe("Failed creating onshot cond %s", name);
return 1;
}
return 0;
}
void cond_set_oneshot(const char *name)
{
_d("%s", name);
if (cond_set_oneshot_noupdate(name))
return;
if (symlink(_PATH_RECONF, path) && errno != EEXIST)
_pe("Failed creating onshot cond %s", name);
cond_update(name);
}
int cond_clear_noupdate(const char *name)
{
_d("%s", name);
if (string_compare(name, "nop"))
return 1;
if (!cond_set_path(cond_path(name), COND_OFF))
return 1;
return 0;
}
void cond_clear(const char *name)
{
_d("%s", name);
if (string_compare(name, "nop"))
return;
if (!cond_set_path(cond_path(name), COND_OFF))
if (cond_clear_noupdate(name))
return;
cond_update(name);
@@ -227,7 +265,7 @@ void cond_reload(void)
cond_bump_reconf();
}
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw, int set)
{
char *nm;
@@ -239,25 +277,47 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
nm = strstr((char *)fpath, COND_BASE);
if (!nm) {
_e("Incorrect condtion path %s, cannot reassert", fpath);
_e("Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
return 1;
}
nm += strlen(COND_BASE);
_d("Reasserting %s => %s", fpath, nm);
cond_set(nm);
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
if (set)
cond_set(nm);
else
cond_clear_noupdate(nm); /* important, see netlink plugin! */
return 0;
}
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
{
return do_assert(fpath, sb, tflg, ftw, 1);
}
static int deassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
{
return do_assert(fpath, sb, tflg, ftw, 0);
}
/*
* Used only by netlink plugin atm.
* type: is a one of pid/, net/, etc.
*/
void cond_reassert(const char *type)
void cond_reassert(const char *pat)
{
_d("%s", type);
nftw(cond_path(type), reassert, 20, FTW_DEPTH);
_d("%s", pat);
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
}
/*
* Used only by netlink plugin atm.
*/
void cond_deassert(const char *pat)
{
_d("%s", pat);
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
}
void cond_init(void)
+5 -1
View File
@@ -21,8 +21,12 @@
* THE SOFTWARE.
*/
#include <lite/lite.h>
#include <stdio.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "cond.h"
+14 -4
View File
@@ -2,15 +2,18 @@
#define FINIT_COND_H_
#include <paths.h>
#include <svc.h>
#include "svc.h"
#define COND_BASE "finit/cond"
#define COND_USR "usr/"
#define COND_PID "pid/"
#define COND_SYS "sys/"
#define COND_USR "usr/"
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
#define _PATH_CONDUSR _PATH_COND COND_USR
#define _PATH_CONDPID _PATH_COND COND_PID
#define _PATH_CONDSYS _PATH_COND COND_SYS
#define _PATH_CONDUSR _PATH_COND COND_USR
#define _PATH_RECONF _PATH_COND "reconf"
typedef enum cond_state {
@@ -28,13 +31,20 @@ enum cond_state cond_get (const char *name);
enum cond_state cond_get_agg (const char *names);
int cond_affects (const char *name, const char *names);
void cond_update (const char *name);
int cond_update (const char *name);
int cond_set_path (const char *path, enum cond_state new);
void cond_set (const char *name);
void cond_set_oneshot (const char *name);
void cond_clear (const char *name);
void cond_reload (void);
int cond_set_noupdate (const char *name);
int cond_set_oneshot_noupdate(const char *name);
int cond_clear_noupdate(const char *name);
void cond_reassert (const char *pat);
void cond_deassert (const char *pat);
void cond_init (void);
#endif /* FINIT_COND_H_ */
+82 -31
View File
@@ -28,14 +28,20 @@
#include <string.h>
#include <sys/inotify.h>
#include <sys/resource.h>
#include <lite/lite.h>
#include <lite/queue.h> /* BSD sys/queue.h API */
#ifdef _LIBITE_LITE
# include <libite/lite.h>
# include <libite/queue.h> /* BSD sys/queue.h API */
#else
# include <lite/lite.h>
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include <time.h>
#include <glob.h>
#include "finit.h"
#include "cond.h"
#include "iwatch.h"
#include "private.h"
#include "service.h"
#include "tty.h"
#include "helpers.h"
@@ -66,22 +72,6 @@ static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(c
static int parse_conf(char *file, int is_rcsd);
static void drop_changes(void);
static void hide_args(int argc, char *argv[])
{
/*
* Hide command line arguments from ps (in particular for
* forked children that don't execv()). This is an ugly
* hack that only works on Linux.
* https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/
*/
if (argc > 1) {
char *arg_end;
arg_end = argv[argc-1] + strlen (argv[argc-1]);
*arg_end = ' ';
}
}
int get_bool(char *arg, int default_value)
{
if (!arg)
@@ -98,6 +88,7 @@ fallback:
/*
* finit.debug = [on,off]
* finit.show_status = [on,off]
* finit.status_style = [old,classic,modern]
*/
static void parse_finit_opts(char *opt)
{
@@ -145,24 +136,27 @@ static void parse_arg(char *arg)
single = 1;
}
void conf_parse_cmdline(int argc, char *argv[])
#ifdef KERNEL_CMDLINE
/*
* Parse /proc/cmdline to find args for init. Don't use this!
*
* Instead, rely on the kernel to give Finit its arguments as
* regular argc + argv[]. Only use this if the system you run
* on has a broken initramfs system that cannot forward args
* to Finit properly.
*/
static void parse_kernel_cmdline(void)
{
int dbg = 0;
FILE *fp;
char line[LINE_SIZE], *cmdline, *tok;
for (int i = 1; i < argc; i++)
parse_arg(argv[i]);
hide_args(argc, argv);
FILE *fp;
fp = fopen("/proc/cmdline", "r");
if (!fp)
goto done;
return;
if (!fgets(line, sizeof(line), fp)) {
fclose(fp);
goto done;
return;
}
cmdline = chomp(line);
@@ -173,9 +167,46 @@ void conf_parse_cmdline(int argc, char *argv[])
parse_arg(tok);
}
fclose(fp);
}
#else
#define parse_kernel_cmdline()
#endif
done:
log_init(dbg);
static void parse_kernel_loglevel(void)
{
char line[LINE_SIZE], *ptr;
FILE *fp;
int val;
fp = fopen("/proc/sys/kernel/printk", "r");
if (!fp)
return;
if (!fgets(line, sizeof(line), fp)) {
fclose(fp);
return;
}
fclose(fp);
ptr = chomp(line);
_d("%s", ptr);
val = atoi(ptr);
if (val >= 7)
kerndebug = 1;
}
/*
* Kernel gives us all non-kernel options on our cmdline
*/
void conf_parse_cmdline(int argc, char *argv[])
{
for (int i = 1; i < argc; i++)
parse_arg(argv[i]);
parse_kernel_cmdline();
parse_kernel_loglevel();
log_init();
}
static int kmod_exists(char *mod)
@@ -542,6 +573,26 @@ static void parse_static(char *line, int is_rcsd)
cfglevel = 2; /* Fallback */
return;
}
/*
* Periodic check and instability index leveler, seconds
*/
if (MATCH_CMD(line, "service-interval ", x)) {
char *token = strip_line(x);
const char *err = NULL;
int val;
/* 0 min to 1 day, should check at least daily */
val = strtonum(token, 0, 1440, &err);
if (!err) {
int disabled = !service_interval;
service_interval = val * 1000; /* to milliseconds */
if (disabled)
service_init();
}
return;
}
}
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
@@ -578,7 +629,7 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
return;
}
/* Read contrl group limits */
/* Read control group limits */
if (MATCH_CMD(line, "cgroup ", x)) {
conf_parse_cgroup(x);
return;
+60 -84
View File
@@ -26,13 +26,19 @@
#include <ctype.h> /* isdigit() */
#include <dirent.h>
#include <err.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <termios.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include <linux/vt.h>
#include "finit.h"
#include "cgroup.h"
@@ -106,8 +112,6 @@ int run(char *cmd)
if (0 == pid) {
FILE *fp;
/* Reset signal handlers that were set by the parent process */
sig_unblock();
setsid();
/* Always redirect stdio for run() */
@@ -240,10 +244,8 @@ int exec_runtask(char *cmd, char *args[])
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
{
struct sigaction sa;
struct termios term;
char name[80];
int fd;
int fd, dummy;
fd = open(tty, O_RDWR);
if (fd < 0) {
@@ -254,44 +256,18 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
/*
* Become session leader and set controlling TTY
* to enable Ctrl-C and job control in shell.
*/
setsid();
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
logit(LOG_WARNING, "Failed TIOCSCTTY on %s: %s", tty, strerror(errno));
/* Set default TERM, run_getty() below allows override */
if (ioctl(fd, VT_OPENQRY, &dummy) == -1)
setenv("TERM", "vt102", 1); /* likely a serial line */
else
setenv("TERM", "linux", 1);
/*
* Reset to sane defaults in case of messup from prev. session
*/
stty(STDIN_FILENO, speed);
/*
* Disable ISIG (INTR, QUIT, SUSP) before handing over to getty.
* It is up to the getty process to allow them again.
*/
if (!tcgetattr(STDIN_FILENO, &term)) {
term.c_lflag &= ~ISIG;
term.c_cc[VEOF] = _POSIX_VDISABLE;
term.c_cc[VINTR] = _POSIX_VDISABLE;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
}
/* Reset signal handlers that were set by the parent process */
sig_unblock();
/*
* Ignore a few signals, needed to prevent Ctrl-C at login:
* prompt and to prevent QUIT from dumping core.
*/
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
stty(fd, speed);
close(fd);
/* Set configured limits */
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
@@ -309,8 +285,12 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
static int activate_console(int noclear, int nowait)
{
static const char msg[] = "\nPlease press Enter to activate this console.";
static const char clr[] = "\r\e[K";
static const char cup[] = "\e[A";
struct termios orig;
int ret = 0;
char c;
int rc;
if (nowait || rescue)
return 1;
@@ -329,36 +309,24 @@ static int activate_console(int noclear, int nowait)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &c);
}
while (!fexist(SYNC_SHUTDOWN)) {
char c;
static const char clr[] = "\r\e[2K";
static const char cup[] = "\e[A";
static const char msg[] = "\nPlease press Enter to activate this console.";
dprint(STDERR_FILENO, clr, strlen(clr));
dprint(STDERR_FILENO, msg, strlen(msg));
while ((rc = read(STDIN_FILENO, &c, 1)) > 0 && c != '\r' && c != '\n')
continue;
if (fexist(SYNC_STOPPED)) {
sleep(5);
continue;
}
/* On any error (likely EINTR), we avoid starting getty */
if (rc == -1)
rc = 0;
dprint(STDERR_FILENO, clr, strlen(clr));
dprint(STDERR_FILENO, msg, strlen(msg));
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\r')
continue;
if (fexist(SYNC_STOPPED))
continue;
dprint(STDERR_FILENO, clr, strlen(clr));
dprint(STDERR_FILENO, cup, strlen(cup));
ret = 1;
break;
}
/* Clear msg and move cursor up for next message/login: */
dprint(STDERR_FILENO, clr, strlen(clr));
dprint(STDERR_FILENO, cup, strlen(cup));
/* Restore TTY */
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig) == -1)
ret = 0;
rc = 0; /* TTY in bad shape, restart */
return ret;
return rc;
}
/*
@@ -380,32 +348,14 @@ static int activate_console(int noclear, int nowait)
* since /bin/login usually only disables ECHO until a password line has
* been entered. Upon starting the user's $SHELL the ISIG flag is reset
*/
pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[])
{
speed_t speed;
int rc = 1;
speed = stty_parse_speed(baud);
prepare_tty(tty, speed, "tty", rlimit);
if (activate_console(noclear, nowait)) {
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
rc = getty(tty, speed, term, NULL);
}
return rc;
}
/*
* Start external getty as defined by user in .conf file
*/
pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
pid_t run_getty(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
{
int rc = 1;
/* Dunno speed, tell stty() to not mess with it */
prepare_tty(tty, B0, "getty", rlimit);
if (activate_console(noclear, nowait)) {
logit(LOG_INFO, "Starting external getty on %s", tty);
logit(LOG_INFO, "Starting getty on %s", tty);
rc = execv(cmd, args);
}
@@ -414,6 +364,32 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st
return rc;
}
int sh(char *tty)
{
char *args[2] = {
NULL,
NULL
};
char *arg0;
size_t len;
/* The getty process is usually responsible for the UTMP login record */
utmp_set_login(tty, NULL);
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
len = strlen(_PATH_BSHELL) + 2;
arg0 = malloc(len);
if (!arg0)
err(1, "Failed allocating memory");
snprintf(arg0, len, "-%s", _PATH_BSHELL);
args[0] = arg0;
/* Unblock signals inherited from parent */
sig_unblock();
return execv(_PATH_BSHELL, args);
}
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
{
int rc = 1;
+153 -33
View File
@@ -36,7 +36,11 @@
#include <sys/mount.h>
#include <sys/stat.h> /* umask(), mkdir() */
#include <sys/wait.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "cgroup.h"
@@ -61,11 +65,13 @@ int debug = 0; /* debug mode from kernel cmdline */
int rescue = 0; /* rescue mode from kernel cmdline */
int single = 0; /* single user mode from kernel cmdline */
int bootstrap = 1; /* set while bootrapping (for TTYs) */
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
char *sdown = NULL;
char *network = NULL;
char *hostname = NULL;
char *rcsd = FINIT_RCSD;
char *runparts = NULL;
char *osheading = NULL;
uev_ctx_t *ctx = NULL; /* Main loop context */
svc_t *wdog = NULL; /* No watchdog by default */
@@ -81,7 +87,7 @@ static void banner(void)
* similar enabled to start emptying /dev/kmsg, but for
* our progress we want to own the console.
*/
if (!debug)
if (!debug && !kerndebug)
klogctl(6, NULL, 0);
/*
@@ -90,7 +96,14 @@ static void banner(void)
*/
plugin_run_hooks(HOOK_BANNER);
print_banner(INIT_HEADING);
#ifdef INIT_OSHEADING
osheading = INIT_OSHEADING;
if (osheading) {
if (!osheading[0])
osheading = release_heading();
print_banner(osheading);
}
#endif
}
/*
@@ -109,6 +122,7 @@ static int fsck(int pass)
while ((fs = getfsent())) {
char cmd[80];
struct stat st;
int fsck_rc = 0;
if (fs->fs_passno != pass)
continue;
@@ -126,8 +140,33 @@ static int fsck(int pass)
continue;
}
#ifdef FSCK_FIX
snprintf(cmd, sizeof(cmd), "fsck -yf %s", fs->fs_spec);
#else
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
rc += run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
#endif
fsck_rc = run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
/*
* "failure" is defined as exiting with a return code of
* 2 or larger. A return code of 1 indicates that filesystem
* errors were corrected but that the boot may proceed.
*/
if (fsck_rc > 1) {
char *sulogin[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(sulogin); i++) {
if (systemf(sulogin[i]))
continue;
break;
}
do_shutdown(SHUT_REBOOT);
}
rc += fsck_rc;
}
endfsent();
@@ -137,18 +176,51 @@ static int fsck(int pass)
static int fsck_all(void)
{
int pass, rc = 0;
int rc = 0;
#ifndef FAST_BOOT
int pass;
for (pass = 1; pass < 10; pass++) {
rc = fsck(pass);
if (rc)
break;
}
#endif
return rc;
}
/* Wrapper for mount(2), logs any errors to stderr */
static void fs_mount(const char *src, const char *tgt, const char *fstype,
unsigned long flags, const void *data)
{
const char *msg = !fstype ? "MS_MOVE" : "mounting";
int rc;
rc = mount(src, tgt, fstype, flags, data);
if (rc && errno != EBUSY)
_pe("Failed %s %s on %s", msg, src, tgt);
}
#ifndef SYSROOT
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
static int fs_readonly_root(struct fstab *fs)
{
char *tok, *str;
if (!fs)
return 1;
str = fs->fs_mntops;
while ((tok = strtok(str, ","))) {
if (!strcmp(tok, "ro"))
return 1;
str = NULL;
}
return 0;
}
static void fs_remount_root(int fsckerr)
{
struct fstab *fs;
@@ -161,8 +233,7 @@ static void fs_remount_root(int fsckerr)
break;
}
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
if (!fs || !strcmp(fs->fs_type, "ro"))
if (fs_readonly_root(fs))
goto out;
if (fsckerr)
@@ -181,8 +252,7 @@ static void fs_remount_root(int fsckerr)
* XXX: Untested, in the initramfs age we should
* probably use switch_root instead.
*/
if (mount(SYSROOT, "/", NULL, MS_MOVE, NULL))
_pe("Failed %s / MS_MOVE");
fs_mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
}
#endif /* SYSROOT */
@@ -206,25 +276,50 @@ static void fs_finalize(void)
*/
if (!fismnt("/dev/shm")) {
makedir("/dev/shm", 0777);
mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
fs_mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
}
/* Modern systems use /dev/pts */
if (!fismnt("/dev/pts")) {
char opts[32];
int mode;
int gid;
gid = getgroup("tty");
if (gid == -1)
gid = 0;
/* 0600 is default on Debian, use 0620 to get mesg y by default */
mode = 0620;
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
makedir("/dev/pts", 0755);
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620,ptmxmode=0666");
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
}
/* Modern systems use tmpfs for /run */
if (!fismnt("/run"))
mount("tmpfs", "/run", "tmpfs", 0, "mode=0755,nosuid,nodev,noexec,relatime");
/*
* Modern systems use tmpfs for /run. Fallback to /var/run if
* /run doesn't exist is handled by the bootmisc plugin. It
* also sets up compat symlinks.
*
* The unconditional mount of /run/lock is for DoS prevention.
* To override any of this behavior, add entries to /etc/fstab
* for /run (and optionally /run/lock).
*/
if (fisdir("/run") && !fismnt("/run")) {
fs_mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
makedir("/run/lock", 1777);
fs_mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
}
/* Modern systems use tmpfs for /tmp */
if (!fismnt("/tmp"))
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=0755,nosuid,nodev");
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
}
static void fs_mount(void)
static void fs_mount_all(void)
{
if (!rescue)
fs_remount_root(fsck_all());
@@ -248,9 +343,9 @@ static void fs_mount(void)
* We need /proc for rs_remount_root() and conf_parse_cmdline(), /dev
* for early multi-console, and /sys for the cgroups support. Any
* occurrence of these file systems in /etc/fstab will replace these
* mounts later in fs_mount()
* mounts later in fs_mount_all()
*
* Ignore any mount errors with EBUSY, kernel likely alread mounted
* Ignore any mount errors with EBUSY, kernel likely already mounted
* the filesystem for us automatically, e.g., CONFIG_DEVTMPFS_MOUNT.
*/
static void fs_init(void)
@@ -268,11 +363,16 @@ static void fs_init(void)
umask(022);
for (i = 0; i < NELEMS(fs); i++) {
int rc;
/*
* Check if already mounted, we may be running in a
* container, or an initramfs ran before us. The
* function fismnt() reliles on /proc/mounts being
* unique for each chroot/container.
*/
if (fismnt(fs[i].file))
continue;
rc = mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
if (rc && errno != EBUSY)
_pe("Failed mounting %s on %s", fs[i].spec, fs[i].file);
fs_mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
}
}
@@ -322,7 +422,7 @@ static void finalize(void *unused)
static void crank_worker(void *unused)
{
/*
* Initalize state machine and start all bootstrap tasks
* Initialize state machine and start all bootstrap tasks
* NOTE: no network available!
*/
sm_init(&sm);
@@ -459,11 +559,11 @@ static int telinit(int argc, char *argv[])
int main(int argc, char *argv[])
{
struct wq crank = {
struct wq crank_work = {
.cb = crank_worker,
.delay = 10
};
struct wq bootstrap = {
struct wq bootstrap_work = {
.cb = bootstrap_worker,
.delay = 100
};
@@ -490,7 +590,7 @@ int main(int argc, char *argv[])
console_init();
/*
* Initalize event context.
* Initialize event context.
*/
uev_init1(&loop, 1);
ctx = &loop;
@@ -500,6 +600,8 @@ int main(int argc, char *argv[])
*/
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
if (chdir("/"))
_pe("Failed cd /");
@@ -535,6 +637,11 @@ int main(int argc, char *argv[])
enable_progress(1); /* Allow progress, if enabled */
banner();
if (osheading)
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel S", osheading);
else
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel S");
/*
* Initial setup of signals, ignore all until we're up.
*/
@@ -546,13 +653,15 @@ int main(int argc, char *argv[])
cgroup_init(&loop);
/* Check and mount filesystems. */
fs_mount();
fs_mount_all();
/* Bootstrap conditions, needed for hooks */
cond_init();
/* Emit conditions for early hooks that ran before the
* condition system was initialized in case anyone . */
/*
* Emit conditions for early hooks that ran before the condition
* system was initialized in case anyone.
*/
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
@@ -565,10 +674,16 @@ int main(int argc, char *argv[])
* Start built-in watchdogd as soon as possible, if enabled
*/
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
service_register(SVC_TYPE_SERVICE, "[123456789] name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
wdog = svc_find_by_nameid("watchdog", "finit");
}
/*
* Start kernel event daemon as soon as possible, if enabled
*/
if (whichp(FINIT_LIBPATH_ "/keventd"))
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init " FINIT_LIBPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
/* Base FS up, enable standard SysV init signals */
sig_setup(&loop);
@@ -585,10 +700,15 @@ int main(int argc, char *argv[])
api_init(&loop);
_d("Starting the big state machine ...");
schedule_work(&crank);
schedule_work(&crank_work);
_d("Starting bootstrap finalize timer ...");
schedule_work(&bootstrap);
schedule_work(&bootstrap_work);
/*
* Background service tasks
*/
service_init();
/*
* Enter main loop to monitor /dev/initctl and services
+9 -1
View File
@@ -34,7 +34,11 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include <uev/uev.h>
/* just in case */
@@ -50,8 +54,10 @@
#define FINIT_CGPATH "/sys/fs/cgroup"
#endif
/* To use these, include config.h, or define FINIT_LIBPATH_ */
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
#define _PATH_GETTY FINIT_LIBPATH_ "/getty"
#define CMD_SIZE 256
#define LINE_SIZE 1024
@@ -108,11 +114,13 @@ extern int debug;
extern int rescue;
extern int single;
extern int bootstrap;
extern int kerndebug;
extern char *rcsd;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *runparts;
extern char *osheading;
extern uev_ctx_t *ctx;
#endif /* FINIT_H_ */
+79 -66
View File
@@ -21,42 +21,46 @@
* THE SOFTWARE.
*/
#include "config.h"
#include <err.h>
#include <errno.h>
#include <limits.h> /* LOGIN_NAME_MAX */
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <termios.h>
#include <unistd.h> /* sysconf() */
#include "finit.h"
#include "cgroup.h"
#include "helpers.h"
#include "sig.h"
#include "utmp-api.h"
#ifndef _PATH_LOGIN
#define _PATH_LOGIN "/bin/login"
#endif
#ifndef LOGIN_NAME_MIN
#define LOGIN_NAME_MIN 64
#endif
static long logname_len = 32; /* useradd(1) limit at 32 chars */
/*
* Read one character from stdin.
*/
static int readch(char *tty)
static int readch(void)
{
int st;
char ch1;
int st;
st = read(STDIN_FILENO, &ch1, 1);
if (st == 0) {
dprint(STDOUT_FILENO, "\n", 0);
_exit(0);
}
if (st < 0)
errx(1, "getty: %s: read error", tty);
if (st <= 0)
return -1;
return ch1 & 0xFF;
}
@@ -141,10 +145,10 @@ static void do_issue(char *tty)
/*
* Handle the process of a GETTY.
*/
static void do_getty(char *tty, char *name, size_t len)
static int get_logname(char *tty, char *name, size_t len)
{
int ch;
char *np;
int ch;
/*
* Display prompt.
@@ -155,14 +159,9 @@ static void do_getty(char *tty, char *name, size_t len)
do_issue(tty);
np = name;
while ((ch = readch(tty)) != '\n') {
if (ch == CTRL('U')) {
while (np > name) {
dprint(STDOUT_FILENO, "\b \b", 3);
np--;
}
continue;
}
while ((ch = readch()) != '\n') {
if (ch < 0)
return 1;
if (np < name + len)
*np++ = ch;
@@ -174,6 +173,7 @@ static void do_getty(char *tty, char *name, size_t len)
}
name[len - 1] = 0;
return 0;
}
/*
@@ -185,26 +185,28 @@ static int do_login(char *name)
{
struct stat st;
cgroup_user(name, 0);
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
/*
* Failed to exec login, should not happen on normal systems.
* Try a starting a rescue shell instead.
*
* Note: Add /etc/securetty handling.
*/
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_BSHELL);
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode))
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode)) {
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_SULOGIN);
execl(_PATH_SULOGIN, _PATH_SULOGIN, NULL);
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_SULOGIN, _PATH_BSHELL);
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
}
return 1; /* We shouldn't get here ... */
}
int getty(char *tty, speed_t speed, char *term, char *user)
static int getty(char *tty, speed_t speed, char *term, char *user)
{
const char cln[] = "\r\e[2K\n";
char name[30];
const char cln[] = "\r\e[K\n";
char name[logname_len + 1]; /* +1 for NUL termination */
pid_t sid;
/*
* Clean up tty name.
@@ -212,59 +214,70 @@ int getty(char *tty, speed_t speed, char *term, char *user)
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
tty += 5;
/* Set up TTY, re-enabling ISIG et al. */
stty(STDIN_FILENO, speed);
dprint(STDERR_FILENO, cln, strlen(cln));
/* The getty process is responsible for the UTMP login record */
utmp_set_login(tty, NULL);
if (!user)
do_getty(tty, name, sizeof(name));
else
/* Replace "Please press enter ..." with login: */
dprint(STDERR_FILENO, cln, strlen(cln));
restart:
stty(STDIN_FILENO, speed);
if (!user) {
if (get_logname(tty, name, sizeof(name)))
goto restart;
} else
strlcpy(name, user, sizeof(name));
/* check current session associated with our tty */
sid = tcgetsid(0);
if (sid < 0 || getpid() != sid) {
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) == -1)
err(1, "failed stealing controlling TTY");
}
if (term && term[0])
setenv("TERM", term, 1);
return do_login(name);
}
int sh(char *tty)
static int usage(int rc)
{
struct termios term;
char *args[2] = {
NULL,
NULL
};
char *arg0;
size_t len;
warnx("usage: getty [-h?] tty [speed [term]]");
return rc;
}
/* The getty process is usually responsible for the UTMP login record */
utmp_set_login(tty, NULL);
int main(int argc, char *argv[])
{
char *tty, *speed = "0", *term = NULL;
int c;
/* Set up TTY, re-enabling ISIG et al. */
stty(STDIN_FILENO, B0);
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
len = strlen(_PATH_BSHELL) + 2;
arg0 = malloc(len);
if (!arg0)
err(1, "Failed allocating memory");
snprintf(arg0, len, "-%s", _PATH_BSHELL);
args[0] = arg0;
/* Reenable Ctrl-D and Ctrl-C, and ... */
if (!tcgetattr(STDIN_FILENO, &term)) {
term.c_lflag |= ISIG;
term.c_cc[VEOF] = CEOF;
term.c_cc[VINTR] = CINTR;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
while ((c = getopt(argc, argv, "h?")) != EOF) {
switch(c) {
case 'h':
case '?':
return usage(0);
default:
return usage(1);
}
}
/* ... unblock signals in general */
sig_unblock();
if (optind >= argc)
return usage(1);
return execv(_PATH_BSHELL, args);
tty = argv[optind++];
if (optind < argc)
speed = argv[optind++];
if (optind < argc)
term = argv[optind++];
logname_len = sysconf(_SC_LOGIN_NAME_MAX);
if (logname_len == -1i)
logname_len = LOGIN_NAME_MAX;
if (logname_len < LOGIN_NAME_MIN)
logname_len = LOGIN_NAME_MIN;
return getty(tty, atoi(speed), term, NULL);
}
/**
+52 -135
View File
@@ -31,7 +31,11 @@
#include <netinet/in.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
@@ -68,92 +72,13 @@ static const char *status2[] = STATUS_CLASS;
#define CHOOSE(x,y,z) z
static const char *color[] = STATUS_CLASS;
/*
* System consoles, can be given multiple times on the kernel cmdline.
* We support only three currently. If none are given on the cmdline
* we probe /sys/class/tty/console/active and use the first (default).
*/
#define MAX_CONS 3
static char *consoles[MAX_CONS];
static int fds[MAX_CONS];
static int num_cons = 0;
/*
* System default console is always the first
*/
char *console(void)
{
return consoles[0];
}
static void add_console(char *cons)
{
char path[80];
char *ptr;
int i;
if (num_cons == NELEMS(fds)) {
_e("too many consoles, max %d supported", NELEMS(fds));
return;
}
/* drop any options */
ptr = strchr(cons, ',');
if (ptr)
*ptr = 0;
if (!strncmp(cons, "/dev/", 5))
cons += 5;
snprintf(path, sizeof(path), "/dev/%s", cons);
/* check for and skip duplicates */
for (i = 0; i < num_cons; i++) {
if (string_compare(path, consoles[i]))
return;
}
/* this requires we have /dev mounted && a device there */
fds[num_cons] = open(path, O_WRONLY);
if (fds[num_cons] < 0) {
_pe("Failed opening console %s", path);
return;
}
consoles[num_cons] = strdup(path);
num_cons++;
}
static void find_active_consoles(void)
{
char *cons, *ptr, *tok;
char buf[512];
FILE *fp;
fp = fopen("/sys/class/tty/console/active", "r");
if (!fp) {
fallback:
_d("Using fallback /dev/console");
add_console("console");
return;
}
ptr = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (!ptr)
goto fallback;
cons = chomp(ptr);
_d("Using these system consoles: %s", cons);
while ((tok = strtok(cons, " \t"))) {
cons = NULL;
add_console(tok);
}
return _PATH_CONSOLE;
}
void console_init(void)
{
find_active_consoles();
ttinit();
}
@@ -163,14 +88,12 @@ ssize_t cprintf(const char *fmt, ...)
char buf[len < 256 ? 256 : len];
size_t size;
va_list ap;
int i;
va_start(ap, fmt);
size = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
for (i = 0; i < num_cons; i++)
dprint(fds[i], buf, size);
dprint(STDERR_FILENO, buf, size);
return size;
}
@@ -205,6 +128,49 @@ void show_progress(pstyle_t style)
progress_onoff = style;
}
/*
* Find PRETTY_NAME in /etc/os-release to use as heading at boot
* and on runlevel changes. Fallback: "Finit vX.YY"
*/
char *release_heading(void)
{
char *name = NULL;
char buf[256];
FILE *fp;
fp = fopen("/etc/os-release", "r");
if (fp) {
while (fgets(buf, sizeof(buf), fp)) {
char *ptr = &buf[12];
if (strncmp(buf, "PRETTY_NAME=", 12))
continue;
if (*ptr == '"' || *ptr == '\'') {
char *end = &ptr[strlen(ptr) - 1];
char q = *ptr;
while (end > ptr && isspace(*end))
*end-- = 0;
if (*end == q) {
*end = 0;
ptr++;
}
}
name = strdup(ptr);
break;
}
fclose(fp);
}
if (!name)
name = strdup(PACKAGE_NAME " v" PACKAGE_VERSION);
return name;
}
/*
* Return screen length of string, not counting escape chars, and
* accounting for unicode characters as only one screen byte wide
@@ -261,7 +227,7 @@ void print_banner(const char *heading)
return;
buf[0] = 0;
strlcat(buf, "\r\e[2K", sizeof(buf));
strlcat(buf, "\r\e[K", sizeof(buf));
if (progress_style == PROGRESS_CLASSIC) {
strlcat(buf, "\e[1m", sizeof(buf));
@@ -346,7 +312,7 @@ void printv(const char *fmt, va_list ap)
if (progress_style == PROGRESS_CLASSIC)
cprintf("\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
else
cprintf("\r\e[2K%s%s", status(3), buf);
cprintf("\r\e[K%s%s", status(3), buf);
}
void print(int rc, const char *fmt, ...)
@@ -598,55 +564,6 @@ void endfsent(void)
}
#endif /* HAVE_GETFSENT */
static int hasopt(char *opts, char *opt)
{
char buf[strlen(opts) + 1];
char *ptr;
memcpy(buf, opts, sizeof(buf));
ptr = strtok(buf, ",");
while (ptr) {
if (!strcmp(ptr, opt))
return 1;
ptr = strtok(NULL, ",");
}
return 0;
}
int ismnt(char *file, char *dir, char *mode)
{
struct mntent *mnt;
int found = 0;
FILE *fp;
fp = setmntent(file, "r");
if (!fp)
return 0; /* Dunno, maybe not */
while ((mnt = getmntent(fp))) {
if (!strcmp(mnt->mnt_dir, dir)) {
if (mode) {
if (hasopt(mnt->mnt_opts, mode))
found = 1;
} else
found = 1;
break;
}
}
endmntent(fp);
return found;
}
/* Requires /proc to be mounted */
int fismnt(char *dir)
{
return ismnt("/proc/mounts", dir, NULL);
}
/**
* Local Variables:
* indent-tabs-mode: t
+8 -9
View File
@@ -32,7 +32,11 @@
#include <sys/types.h>
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <termios.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "log.h"
#define PROGRESS_DEFAULT PROGRESS_MODERN
@@ -68,11 +72,10 @@ char *strip_line (char *line);
void enable_progress (int onoff);
void show_progress (pstyle_t style);
int getty (char *tty, speed_t speed, char *term, char *user);
int sh (char *tty);
char *release_heading (void);
void stty (int fd, speed_t speed);
speed_t stty_parse_speed(char *baud);
void stty (int fd, speed_t speed);
void print_banner (const char *heading);
void printv (const char *fmt, va_list ap);
@@ -95,8 +98,7 @@ int complete (char *cmd, int pid);
int run (char *cmd);
int run_interactive (char *cmd, char *fmt, ...);
int exec_runtask (char *cmd, char *args[]);
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
int run_parts (char *dir, char *cmd);
@@ -128,9 +130,6 @@ static inline int dprint(int fd, const char *s, size_t len)
return rc;
}
int ismnt (char *file, char *dir, char *mode);
int fismnt (char *dir);
#endif /* FINIT_HELPERS_H_ */
/**
+150 -85
View File
@@ -33,7 +33,11 @@
#include <time.h>
#include <utmp.h>
#include <arpa/inet.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "client.h"
#include "cond.h"
@@ -41,11 +45,13 @@
#include "service.h"
#include "cgutil.h"
#include "util.h"
#include "utmp-api.h"
struct cmd {
char *cmd;
struct cmd *ctx;
int (*cb)(char *arg);
int *cond;
};
int icreate = 0;
@@ -57,6 +63,9 @@ int verbose = 0;
int plain = 0;
int quiet = 0;
int runlevel = 0;
int cgrp = 0;
int utmp = 0;
int iw, pw;
extern int reboot_main(int argc, char *argv[]);
@@ -166,11 +175,11 @@ static int do_runlevel(char *arg)
if (!arg) {
int prevlevel = 0;
int runlevel;
int currlevel;
char prev;
runlevel = runlevel_get(&prevlevel);
if (255 == runlevel) {
currlevel = runlevel_get(&prevlevel);
if (255 == currlevel) {
printf("unknown\n");
return 0;
}
@@ -179,7 +188,7 @@ static int do_runlevel(char *arg)
if (prev <= '0' || prev > '9')
prev = 'N';
printf("%c %d\n", prev , runlevel);
printf("%c %d\n", prev , currlevel);
return 0;
}
@@ -345,7 +354,7 @@ static int do_cond_act(char *arg, int creat)
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
err(1, "Failed asserting condition <%s>", &oneshot[off]);
} else {
if (erase(oneshot))
if (erase(oneshot) && errno != ENOENT)
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
}
@@ -467,15 +476,12 @@ int do_suspend (char *arg) { return do_cmd(INIT_CMD_SUSPEND); }
int utmp_show(char *file)
{
static int once = 0;
struct tm *sectm;
struct utmp *ut;
time_t sec;
int pid;
char id[sizeof(ut->ut_id) + 1], user[sizeof(ut->ut_user) + 1], when[80];
if (heading) {
static int once = 0;
print_header("%s%s ", once ? "\n" : "", file);
once++;
}
@@ -483,7 +489,12 @@ int utmp_show(char *file)
setutent();
while ((ut = getutent())) {
char user[sizeof(ut->ut_user) + 1];
char id[sizeof(ut->ut_id) + 1];
struct tm *sectm;
char when[80];
char addr[64];
int pid;
strlcpy(id, ut->ut_id, sizeof(id));
strlcpy(user, ut->ut_user, sizeof(user));
@@ -508,7 +519,7 @@ int utmp_show(char *file)
static int do_utmp(char *file)
{
if (!has_utmp())
if (!utmp)
return 1;
if (fexist(file))
@@ -537,7 +548,7 @@ static int show_version(char *arg)
* Pointer to string on the form [2345], may be up to 12 chars long,
* plus escape sequences for highlighting current runlevel.
*/
char *runlevel_string(int runlevel, int levels)
char *runlevel_string(int currlevel, int levels)
{
int i, pos = 1;
static char lvl[21];
@@ -547,7 +558,7 @@ char *runlevel_string(int runlevel, int levels)
for (i = 0; i < 10; i++) {
if (ISSET(levels, i)) {
if (!plain && runlevel == i)
if (!plain && currlevel == i)
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
if (i == 0)
@@ -555,7 +566,7 @@ char *runlevel_string(int runlevel, int levels)
else
lvl[pos++] = '0' + i;
if (!plain && runlevel == i)
if (!plain && currlevel == i)
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
} else {
lvl[pos++] = '-';
@@ -698,17 +709,27 @@ static int show_status(char *arg)
{
char ident[MAX_IDENT_LEN];
char buf[512];
int num = 0;
svc_t *svc;
runlevel = runlevel_get(NULL);
if (arg && arg[0]) {
while (arg && arg[0]) {
long now = jiffies();
char uptm[42] = "N/A";
char grbuf[128];
char path[256];
struct cg *cg;
char *group;
char *pidfn = NULL;
int exact = 0;
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
svc_ident(svc, ident, sizeof(ident));
if (string_match(ident, arg))
num++;
if (string_case_compare(ident, arg))
exact++;
}
if (num > 1 && !exact)
break;
svc = client_svc_find(arg);
if (!svc)
@@ -717,9 +738,11 @@ static int show_status(char *arg)
if (quiet)
return svc->state != SVC_RUNNING_STATE;
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
cg = cg_conf(path);
pidfn = svc->pidfile;
if (pidfn[0] == '!')
pidfn++;
else if (pidfn[0] == 0)
pidfn = "none";
printf(" Status : %s\n", status(svc, 1));
printf(" Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
@@ -728,13 +751,23 @@ static int show_status(char *arg)
printf("Environment : %s\n", svc_environ(svc, buf, sizeof(buf)));
printf("Condition(s): %s\n", svc_cond(svc, buf, sizeof(buf)));
printf(" Command : %s\n", svc_command(svc, buf, sizeof(buf)));
printf(" PID file : %s\n", svc->pidfile);
printf(" PID file : %s\n", pidfn);
printf(" PID : %d\n", svc->pid);
printf(" User : %s\n", svc->username);
printf(" Group : %s\n", svc->group);
printf(" Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, uptm, sizeof(uptm)) : uptm);
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 (svc->pid > 1) {
if (cgrp && svc->pid > 1) {
char grbuf[128];
char path[256];
struct cg *cg;
char *group;
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
cg = cg_conf(path);
printf(" Memory : %s\n", memsz(cgroup_memory(group), uptm, sizeof(uptm)));
printf(" CGroup : %s cpu %s [%s, %s] mem [%s, %s]\n",
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
@@ -763,9 +796,11 @@ static int show_status(char *arg)
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
char *lvls;
printf("%-*d ", pw, svc->pid);
svc_ident(svc, ident, sizeof(ident));
if (num && !string_match(ident, arg))
continue;
printf("%-*d ", pw, svc->pid);
printf("%-*s %s ", iw, ident, status(svc, 0));
lvls = runlevel_string(runlevel, svc->runlevels);
@@ -783,6 +818,30 @@ static int show_status(char *arg)
return 0;
}
static int show_ident(char *arg)
{
svc_t *svc;
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
char ident[MAX_IDENT_LEN];
size_t len;
char *pos;
svc_ident(svc, ident, sizeof(ident));
pos = strchr(ident, ':');
if (pos)
len = pos - ident;
else
len = strlen(ident);
if (arg && arg[0] && strncasecmp(ident, arg, len))
continue;
puts(ident);
}
return 0;
}
static int transform(char *nm)
{
char *names[] = {
@@ -879,12 +938,16 @@ static int usage(int rc)
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
" reload <NAME>[:ID] Reload service by name (SIGHUP or restart)\n"
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
" ident [NAME] Show matching identities for NAME, or all\n"
" status <NAME>[:ID] Show service status, by name\n"
" status Show status of services, default command\n"
"\n"
" cgroup List cgroup config overview\n"
" ps List processes based on cgroups\n"
" top Show top-like listing based on cgroups\n"
" status Show status of services, default command\n");
if (cgrp)
fprintf(stderr,
"\n"
" cgroup List cgroup config overview\n"
" ps List processes based on cgroups\n"
" top Show top-like listing based on cgroups\n");
fprintf(stderr,
"\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" reboot Reboot system\n"
@@ -892,13 +955,11 @@ static int usage(int rc)
" poweroff Halt and power off system\n"
" suspend Suspend system\n");
if (has_utmp())
if (utmp)
fprintf(stderr,
"\n"
" utmp show Raw dump of UTMP/WTMP db\n"
"\n");
else
fprintf(stderr, "\n");
" utmp show Raw dump of UTMP/WTMP db\n");
fprintf(stderr, "\n");
return rc;
}
@@ -917,11 +978,22 @@ static int do_help(char *arg)
return usage(0);
}
static int cmd_cond(struct cmd *cmd)
{
if (!cmd || !cmd->cond)
return 1;
return *cmd->cond;
}
static int cmd_parse(int argc, char *argv[], struct cmd *command)
{
int i, j;
for (i = 0; argc > 0 && command[i].cmd; i++) {
if (!cmd_cond(&command[i]))
continue;
if (!string_match(command[i].cmd, argv[0]))
continue;
@@ -946,7 +1018,6 @@ static int cmd_parse(int argc, char *argv[], struct cmd *command)
return command[0].cb(NULL); /* default cmd */
}
int main(int argc, char *argv[])
{
struct option long_options[] = {
@@ -963,57 +1034,62 @@ int main(int argc, char *argv[])
{ NULL, 0, NULL, 0 }
};
struct cmd cond[] = {
{ "status", NULL, do_cond_show }, /* default cmd */
{ "dump", NULL, do_cond_dump },
{ "set", NULL, do_cond_set },
{ "clr", NULL, do_cond_clr },
{ "clear", NULL, do_cond_clr },
{ NULL, NULL, NULL }
{ "status", NULL, do_cond_show, NULL }, /* default cmd */
{ "dump", NULL, do_cond_dump, NULL },
{ "set", NULL, do_cond_set, NULL },
{ "clr", NULL, do_cond_clr, NULL },
{ "clear", NULL, do_cond_clr, NULL },
{ NULL, NULL, NULL, NULL }
};
struct cmd command[] = {
{ "status", NULL, show_status }, /* default cmd */
{ "status", NULL, show_status, NULL }, /* default cmd */
{ "ident", NULL, show_ident, NULL },
{ "debug", NULL, toggle_debug },
{ "devel", NULL, do_devel },
{ "help", NULL, do_help },
{ "version", NULL, show_version },
{ "debug", NULL, toggle_debug, NULL },
{ "devel", NULL, do_devel, NULL },
{ "help", NULL, do_help, NULL },
{ "version", NULL, show_version, NULL },
{ "list", NULL, serv_list },
{ "ls", NULL, serv_list },
{ "enable", NULL, serv_enable },
{ "disable", NULL, serv_disable },
{ "touch", NULL, serv_touch },
{ "show", NULL, serv_show },
{ "edit", NULL, serv_edit },
{ "create", NULL, serv_creat },
{ "delete", NULL, serv_delete },
{ "reload", NULL, do_reload },
{ "list", NULL, serv_list, NULL },
{ "ls", NULL, serv_list, NULL },
{ "enable", NULL, serv_enable, NULL },
{ "disable", NULL, serv_disable, NULL },
{ "touch", NULL, serv_touch, NULL },
{ "show", NULL, serv_show, NULL },
{ "edit", NULL, serv_edit, NULL },
{ "create", NULL, serv_creat, NULL },
{ "delete", NULL, serv_delete, NULL },
{ "reload", NULL, do_reload, NULL },
{ "cond", cond, NULL },
{ "cond", cond, NULL, NULL },
{ "log", NULL, do_log },
{ "start", NULL, do_start },
{ "stop", NULL, do_stop },
{ "restart", NULL, do_restart },
{ "log", NULL, do_log, NULL },
{ "start", NULL, do_start, NULL },
{ "stop", NULL, do_stop, NULL },
{ "restart", NULL, do_restart, NULL },
{ "cgroup", NULL, show_cgroup },
{ "ps", NULL, show_cgps },
{ "top", NULL, show_cgtop },
{ "cgroup", NULL, show_cgroup, &cgrp },
{ "ps", NULL, show_cgps, &cgrp },
{ "top", NULL, show_cgtop, &cgrp },
{ "runlevel", NULL, do_runlevel },
{ "reboot", NULL, do_reboot },
{ "halt", NULL, do_halt },
{ "poweroff", NULL, do_poweroff },
{ "suspend", NULL, do_suspend },
{ "runlevel", NULL, do_runlevel, NULL },
{ "reboot", NULL, do_reboot, NULL },
{ "halt", NULL, do_halt, NULL },
{ "poweroff", NULL, do_poweroff, NULL },
{ "suspend", NULL, do_suspend, NULL },
{ "utmp", NULL, do_utmp },
{ NULL, NULL, NULL }
{ "utmp", NULL, do_utmp, &utmp },
{ NULL, NULL, NULL, NULL }
};
int interactive = 1, c;
if (transform(progname(argv[0])))
return reboot_main(argc, argv);
/* Enable functionality depending on system capabilities */
cgrp = cgroup_avail();
utmp = has_utmp();
while ((c = getopt_long(argc, argv, "1bcdfh?pqtv", long_options, NULL)) != EOF) {
switch(c) {
case '1':
@@ -1061,17 +1137,6 @@ int main(int argc, char *argv[])
if (interactive)
ttinit();
if (!has_utmp()) {
/* system w/o utmp support, disable 'utmp' command */
for (c = 0; command[c].cmd; c++) {
if (!string_compare(command[c].cmd, "utmp"))
continue;
command[c].cb = NULL;
break;
}
}
return cmd_parse(argc - optind, &argv[optind], command);
}
+5 -1
View File
@@ -26,7 +26,11 @@
#define FINIT_IWATCH_H_
#include <stdint.h>
#include <lite/queue.h>
#ifdef _LIBITE_LITE
# include <libite/queue.h> /* BSD sys/queue.h API */
#else
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include <sys/inotify.h>
#ifndef IN_MASK_CREATE
+283
View File
@@ -0,0 +1,283 @@
/* Listens to kernel events like AC power status and manages sys/ conditions
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <dirent.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/types.h>
#include <linux/netlink.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "cond.h"
#include "pid.h"
#include "util.h"
#define _PATH_SYSFS_PWR "/sys/class/power_supply"
static int num_ac_online;
static int num_ac;
int debug; /* debug in other modules as well */
void logit(int prio, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (!debug)
vsyslog(prio, fmt, ap);
else {
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
va_end(ap);
}
#define panic(fmt, args...) { logit(LOG_CRIT, fmt ":%s", ##args, strerror(errno)); exit(1); }
#define warn(fmt, args...) { logit(LOG_WARNING, fmt ":%s", ##args, strerror(errno)); }
static void sys_cond(char *cond, int set)
{
char oneshot[256];
snprintf(oneshot, sizeof(oneshot), "%s/%s", _PATH_CONDSYS, cond);
if (set) {
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
warn("failed asserting sys/%s", cond);
} else {
if (erase(oneshot) && errno != ENOENT)
warn("failed asserting sys/%s", cond);
}
}
static int fgetline(char *path, char *buf, size_t len)
{
FILE *fp;
fp = fopen(path, "r");
if (!fp)
return -1;
if (!fgets(buf, len, fp)) {
fclose(fp);
return -1;
}
chomp(buf);
fclose(fp);
return 0;
}
static int check_online(char *online)
{
int val;
if (!online)
return 0;
val = atoi(online);
logit(LOG_INFO, "AC %s", val ? "connected" : "disconnected");
return val;
}
static int is_ac(char *type)
{
char *types[] = {
"Mains",
"USB",
"BrickID",
"Wireless",
NULL
};
int i;
for (i = 0; types[i]; i++) {
if (!strncmp(type, types[i], strlen(types[i])))
return 1;
}
return 0;
}
static void init(void)
{
struct dirent **d = NULL;
char *cond_dirs[] = {
_PATH_CONDSYS,
_PATH_CONDSYS "/pwr",
};
char path[384];
int i, n;
for (i = 0; i < (int)NELEMS(cond_dirs); i++) {
if (mkpath(cond_dirs[i], 0755) && errno != EEXIST) {
_pe("Failed creating %s condition directory, %s", COND_SYS,
cond_dirs[i]);
return;
}
}
n = scandir(_PATH_SYSFS_PWR, &d, NULL, alphasort);
for (i = 0; i < n; i++) {
char *nm = d[i]->d_name;
char buf[10];
snprintf(path, sizeof(path), "%s/%s/type", _PATH_SYSFS_PWR, nm);
if (!fgetline(path, buf, sizeof(buf)) && is_ac(buf)) {
num_ac++;
snprintf(path, sizeof(path), "%s/%s/online", _PATH_SYSFS_PWR, nm);
if (!fgetline(path, buf, sizeof(buf))) {
if (check_online(buf))
num_ac_online++;
}
}
free(d[i]);
}
if (n > 0)
free(d);
/* if any power_supply is online, or none can be found */
if (num_ac == 0 || num_ac_online > 0)
sys_cond("pwr/ac", 1);
}
/*
* Started by Finit as soon as possible when base filesystem is up,
* modules have been probed, or insmodded from /etc/finit.conf, so by
* now we should have /sys/class/power_supply/ available for probing.
* If none is found we assert /sys/pwr/ac condition anyway, this is what
* systemd does (ConditionACPower) and also makes most sense.
*/
int main(int argc, char *argv[])
{
struct sockaddr_nl nls = { 0 };
struct pollfd pfd;
char buf[1024];
if (argc > 1) {
if (!strcmp(argv[1], "-d"))
debug = 1;
}
if (!debug) {
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
setlogmask(LOG_UPTO(LOG_NOTICE));
}
init();
pfd.events = POLLIN;
pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (pfd.fd == -1)
panic("failed creating netlink socket");
nls.nl_family = AF_NETLINK;
nls.nl_pid = 0;
nls.nl_groups = -1;
if (bind(pfd.fd, (void *)&nls, sizeof(struct sockaddr_nl)))
panic("bind failed");
logit(LOG_DEBUG, "Waiting for events ...");
while (-1 != poll(&pfd, 1, -1)) {
char *path = NULL;
int ac = 0;
int i, len;
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
if (len == -1) {
switch (errno) {
case EINTR:
continue;
case ENOBUFS:
warn("lost events");
continue;
default:
panic("unhandled");
continue;
}
}
buf[len] = 0;
/* skip libusb events, focus on kernel events/changes */
if (strncmp(buf, "change@", 7))
continue;
/* XXX: currently limited to monitoring this subsystem */
if (!strstr(buf, "power_supply"))
continue;
i = 0;
while (i < len) {
char *line = buf + i;
logit(LOG_DEBUG, "%s", line);
if (!strncmp(line, "DEVPATH=", 8)) {
path = &line[8];
logit(LOG_DEBUG, "Got path %s", path);
} else if (!strncmp(line, "POWER_SUPPLY_TYPE=", 18)) {
ac = is_ac(&line[18]);
} else if (!strncmp(line, "POWER_SUPPLY_ONLINE=", 20) && ac) {
if (check_online(&line[20])) {
if (!num_ac_online)
sys_cond("pwr/ac", 1);
num_ac_online++;
} else {
if (num_ac_online > 0)
num_ac_online--;
if (!num_ac_online)
sys_cond("pwr/ac", 0);
}
}
i += strlen(line) + 1;
}
}
close(pfd.fd);
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+9 -5
View File
@@ -24,7 +24,11 @@
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
@@ -32,14 +36,14 @@
#include "util.h"
static int up = 0;
static int loglevel = LOG_NOTICE;
static int loglevel = LOG_INFO;
void log_init(int dbg)
void log_init(void)
{
if (debug)
loglevel = LOG_DEBUG;
else
loglevel = LOG_NOTICE;
loglevel = LOG_INFO;
}
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
@@ -104,7 +108,7 @@ void logit(int prio, const char *fmt, ...)
goto done;
}
if (prio > loglevel)
if (LOG_PRI(prio) > loglevel)
goto done;
fp = fopen("/dev/kmsg", "w");
+1 -1
View File
@@ -45,7 +45,7 @@
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt "\n", __func__, ##args)
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s\n", __func__, ##args, strerror(errno))
void log_init (int dbg);
void log_init (void);
void log_exit (void);
void log_debug (void);
+19 -6
View File
@@ -30,7 +30,11 @@
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
extern int logrotate(char *file, int num, off_t sz);
@@ -98,29 +102,38 @@ static int logit(int level, char *buf, size_t len)
static int parse_prio(char *arg, int *f, int *l)
{
char *ptr;
char *duparg = strdup(arg);
char *ptr, *prio;
ptr = strchr(arg, '.');
if (!duparg)
prio = arg;
else
prio = duparg;
ptr = strchr(prio, '.');
if (ptr) {
*ptr++ = 0;
for (int i = 0; facilitynames[i].c_name; i++) {
if (!strcmp(facilitynames[i].c_name, arg)) {
if (!strcmp(facilitynames[i].c_name, prio)) {
*f = facilitynames[i].c_val;
break;
}
}
arg = ptr;
prio = ptr;
}
for (int i = 0; prioritynames[i].c_name; i++) {
if (!strcmp(prioritynames[i].c_name, arg)) {
if (!strcmp(prioritynames[i].c_name, prio)) {
*l = prioritynames[i].c_val;
break;
}
}
if (duparg != arg)
free(duparg);
return 0;
}
+5 -1
View File
@@ -20,12 +20,16 @@
* THE SOFTWARE.
*/
#include <lite/lite.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid)
{
+24 -18
View File
@@ -28,7 +28,7 @@
/*
* SysV init on Debian/Ubuntu skips these protected mount points
*
* It also skips anything below /proc, /sys and /run for good meausre so
* It also skips anything below /proc, /sys and /run for good measure so
* we do the same here. What we want is a list of non-protected tmpfs
* and regular filesystems that can be safely unmounted before we do
* swapoff, and remount / as read-only, respectively.
@@ -36,7 +36,7 @@
static int is_protected(char *dir)
{
size_t i;
char *protected[] = {
char *protected_mnts[] = {
"/sys", "/proc",
"/.dev", "/dev", "/dev/pts", "/dev/shm", "dev/.static/dev", "/dev/vcs",
"/run", "/var/run",
@@ -46,8 +46,8 @@ static int is_protected(char *dir)
"/proc/", "/sys/", "/run/", NULL
};
for (i = 0; protected[i]; i++) {
if (!strcmp(dir, protected[i]))
for (i = 0; protected_mnts[i]; i++) {
if (!strcmp(dir, protected_mnts[i]))
return 1;
}
@@ -59,46 +59,52 @@ static int is_protected(char *dir)
return 0;
}
static struct mntent *iterator(char *fstab)
static void iterator_end(FILE **fp)
{
endmntent(*fp);
*fp = NULL;
}
static struct mntent *iterator(char *fstab, FILE **fp)
{
static FILE *fp = NULL;
static struct mntent *mnt;
if (!fp && fstab) {
fp = setmntent(fstab, "r");
if (!fp)
if (!*fp && fstab) {
*fp = setmntent(fstab, "r");
if (!*fp)
return NULL;
}
while ((mnt = getmntent(fp))) {
while ((mnt = getmntent(*fp))) {
if (is_protected(mnt->mnt_dir))
continue;
return mnt;
}
endmntent(fp);
fp = NULL;
iterator_end(fp);
return NULL;
}
void unmount_tmpfs(void)
{
struct mntent *mnt;
FILE *fp = NULL;
while ((mnt = iterator("/proc/mounts"))) {
if (!strcmp("tmpfs", mnt->mnt_fsname))
umount(mnt->mnt_dir);
while ((mnt = iterator("/proc/mounts", &fp))) {
if (!strcmp("tmpfs", mnt->mnt_fsname) && !umount(mnt->mnt_dir))
iterator_end(&fp); /* Restart iteration */
}
}
void unmount_regular(void)
{
struct mntent *mnt;
FILE *fp = NULL;
while ((mnt = iterator("/proc/mounts"))) {
umount(mnt->mnt_dir);
while ((mnt = iterator("/proc/mounts", &fp))) {
if (!umount(mnt->mnt_dir))
iterator_end(&fp); /* Restart iteration */
}
}
+6 -2
View File
@@ -27,7 +27,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "pid.h"
#include "svc.h"
@@ -166,7 +170,7 @@ int pid_file_set(svc_t *svc, char *file, int not)
* The logic is explained below. Please note that using the first form
* of the syntax not only creates and removes the PID file, but it also
* calls touch to update the mtime on service_restart(), only applicable
* to processes that accept SIGHUP. This to ensure dependant services
* to processes that accept SIGHUP. This to ensure dependent services
* are sent SIGCONT properly on reload, otherwise their condition would
* never be asserted again after `initctl reload`.
*
+8 -3
View File
@@ -26,8 +26,13 @@
#include <dirent.h> /* readdir() et al */
#include <poll.h>
#include <string.h>
#include <lite/lite.h>
#include <lite/queue.h> /* BSD sys/queue.h API */
#ifdef _LIBITE_LITE
# include <libite/lite.h>
# include <libite/queue.h> /* BSD sys/queue.h API */
#else
# include <lite/lite.h>
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include "config.h"
#include "cond.h"
@@ -274,7 +279,7 @@ static int init_plugins(uev_ctx_t *ctx)
* Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from
* the plugin @name it is added before attempting to load.
*
* It is up to the plugin itself ot register itself as a "ctor" with the
* It is up to the plugin itself or register itself as a "ctor" with the
* %PLUGIN_INIT macro so that plugin_register() is called automatically.
*
* Returns:
+5 -1
View File
@@ -25,7 +25,11 @@
#define FINIT_PLUGIN_H_
#include <uev/uev.h>
#include <lite/queue.h> /* BSD sys/queue.h API */
#ifdef _LIBITE_LITE
# include <libite/queue.h> /* BSD sys/queue.h API */
#else
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include "svc.h"
+3
View File
@@ -28,6 +28,9 @@
#include "svc.h"
#include "plugin.h"
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
extern int service_interval;
int api_init (uev_ctx_t *ctx);
int api_exit (void);
+1 -1
View File
@@ -12,7 +12,7 @@
# runlevel. Finit does not restart them when they exit.
#
# - run : wait for completion before continuing with next stanza
# - task : like run but started in background, parallell with other stanzas
# - task : like run but started in background, parallel with other stanzas
# - service : supervised daemon, run in foreground, restarted if it crashes
#
# The env: is an optional path to a file with environment variables to
+5 -1
View File
@@ -28,7 +28,11 @@
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "initctl.h"
+159 -34
View File
@@ -26,11 +26,16 @@
#include <ctype.h> /* isblank() */
#include <string.h>
#include <sys/reboot.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <net/if.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include <wordexp.h>
#include "cgroup.h"
@@ -51,6 +56,7 @@
static struct wq work = {
.cb = service_worker,
};
int service_interval = SERVICE_INTERVAL_DEFAULT;
static void svc_set_state(svc_t *svc, svc_state_t new);
@@ -138,7 +144,7 @@ static int fredirect(const char *file)
{
int fd;
fd = open(file, O_WRONLY | O_APPEND);
fd = open(file, O_WRONLY | O_APPEND | O_NOCTTY);
if (-1 != fd) {
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
@@ -347,8 +353,7 @@ static void source_env(svc_t *svc)
static int is_norespawn(void)
{
return sig_stopped() ||
fexist("/mnt/norespawn") ||
return fexist("/mnt/norespawn") ||
fexist("/tmp/norespawn");
}
@@ -492,6 +497,12 @@ static int service_start(svc_t *svc)
/* Declare we're waiting for svc to create its pidfile */
svc_starting(svc);
/* Increment total restarts, unless first time or non-service */
if (svc_is_daemon(svc) || svc_is_sysv(svc)) {
if (svc->restart_cnt || svc->restart_tot)
svc->restart_tot++;
}
/* Block SIGCHLD while forking. */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
@@ -564,10 +575,6 @@ static int service_start(svc_t *svc)
}
args[i] = NULL;
if (!svc_is_tty(svc))
redirect(svc);
sig_unblock();
/*
* The setsid() call takes care to detach the process
* from its controlling terminal, preventing daemons
@@ -579,7 +586,13 @@ static int service_start(svc_t *svc)
* to the console at boot, for debugging or similar,
* have a look at redirect() and log.console instead.
*/
setsid();
pid = setsid();
if (pid < 1)
logit(LOG_ERR, "failed setsid(), pid %d: %s", pid, strerror(errno));
if (!svc_is_tty(svc))
redirect(svc);
sig_unblock();
if (svc_is_runtask(svc))
status = exec_runtask(args[0], &args[1]);
@@ -700,6 +713,7 @@ static void service_cleanup(svc_t *svc)
*/
static int service_stop(svc_t *svc)
{
int do_progress = 1;
int rc = 0;
if (!svc)
@@ -722,9 +736,19 @@ static int service_stop(svc_t *svc)
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", svc->cmd);
}
/*
* Make sure we are no longer considering the service to be starting (if
* that was the case). service_monitor() might get confused otherwise, and
* leave the service in a lingering, "stopping", state.
*/
svc_started(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
if (runlevel != 1)
if (!svc->desc[0])
do_progress = 0;
if (runlevel != 1 && do_progress)
print_desc("Stopping ", svc->desc);
if (!svc_is_sysv(svc)) {
@@ -744,6 +768,7 @@ static int service_stop(svc_t *svc)
pid = fork();
switch (pid) {
case 0:
setsid();
redirect(svc);
exec_runtask(svc->cmd, args);
_exit(0);
@@ -830,7 +855,7 @@ static int service_restart(svc_t *svc)
/**
* service_reload_dynamic - Called on SIGHUP, 'init q' or 'initctl reload'
*
* This function is called when Finit has recieved SIGHUP to 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.
*/
@@ -1066,7 +1091,7 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
* This function is used to register commands to be run on different
* system runlevels with optional username. The @type argument details
* if it's service to bo monitored/respawned (daemon), a one-shot task
* or a command that must run in sequence and not in parallell, like
* or a command that must run in sequence and not in parallel, like
* service and task commands do.
*
* The @line can optionally start with a username, denoted by an @
@@ -1106,7 +1131,7 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
*
* Without the :ID syntax, Finit replaces the first service line with
* the contents of the second. The :ID can be any string value and
* defaults to "" (emtpy string).
* defaults to "" (empty string).
*
* Returns:
* POSIX OK(0) on success, or non-zero errno exit status on failure.
@@ -1120,8 +1145,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
char *pre_script = NULL, *post_script = NULL;
struct tty tty = { 0 };
char *dev = NULL;
int respawn = 0;
int levels = 0;
int manual = 0;
int restart_max = SVC_RESPAWN_MAX;
int restart_tmo = 0;
unsigned oncrash_action = SVC_ONCRASH_IGNORE;
char *line;
svc_t *svc;
@@ -1179,6 +1208,20 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
name = cmd;
else if (!strncasecmp(cmd, "manual:yes", 10))
manual = 1;
else if (!strncasecmp(cmd, "restart:", 8))
restart_max = atoi(&cmd[8]);
else if (!strncasecmp(cmd, "restarttmo:", 11)) /* compat alias */
restart_tmo = atoi(&cmd[11]) * 1000;
else if (!strncasecmp(cmd, "restart_sec:", 12))
restart_tmo = atoi(&cmd[12]) * 1000;
else if (!strncasecmp(cmd, "norestart", 9))
restart_max = 0;
else if (!strncasecmp(cmd, "oncrash:", 8)) {
if (!strncasecmp(&cmd[8], "reboot", 6))
oncrash_action = SVC_ONCRASH_REBOOT;
}
else if (!strncasecmp(cmd, "respawn", 7))
respawn = 1;
else if (!strncasecmp(cmd, "halt:", 5))
halt = &cmd[5];
else if (!strncasecmp(cmd, "kill:", 5))
@@ -1221,7 +1264,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
len += strlen(tty.cmd);
else
len += 3;
len += tty.num + 1;
for (i = 0; i < tty.num; i++)
len += strlen(tty.args[i]) + 1;
@@ -1230,7 +1272,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
if (!line)
return errno;
snprintf(line, len, "%s", tty.cmd ?: "tty");
snprintf(line, len, "%s", tty.cmd ? tty.cmd : "tty");
for (i = 0; i < tty.num; i++) {
strlcat(line, " ", len);
strlcat(line, tty.args[i], len);
@@ -1244,6 +1286,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
dev = tty_atcon();
else
dev = tty.dev;
/* tty's always respawn, never incr. restart_cnt */
respawn = 1;
next:
svc = svc_find_by_tty(dev);
} else
@@ -1259,13 +1304,19 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
if (type == SVC_TYPE_SERVICE && manual)
svc_stop(svc);
svc->restart_max = restart_max;
svc->restart_tmo = restart_tmo;
svc->oncrash_action = oncrash_action;
} else {
/* update type, may have changed from service -> task */
svc->type = type;
/* e.g., if missing cmd or env before */
svc_unblock(svc);
if (!manual)
svc_unblock(svc);
}
/* Always clear svc PID file, for now. See TODO */
svc->pidfile[0] = 0;
/* Decode any optional pid:/optional/path/to/file.pid */
if (pid && svc_is_daemon(svc) && pid_file_parse(svc, pid))
_e("Invalid 'pid' argument to service: %s", pid);
@@ -1306,14 +1357,14 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
/* TTYs cannot be redirected */
log = NULL;
/* Create name:id tuple for identiy, e.g., tty:S0 */
/* Create name:id tuple for identity, e.g., tty:S0 */
ptr = strrchr(svc->dev, '/');
if (ptr) {
if (ptr)
ptr++;
if (!strncmp(ptr, "tty", 3))
ptr += 3;
} else
else
ptr = svc->dev;
if (!strncmp(ptr, "tty", 3))
ptr += 3;
if (!id || id[0] == 0)
id = ptr;
strlcpy(svc->name, "tty", sizeof(svc->name));
@@ -1347,6 +1398,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
parse_env(svc, env);
if (file)
strlcpy(svc->file, file, sizeof(svc->file));
if (respawn)
svc->respawn = 1;
/* Set configured limits */
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
@@ -1399,7 +1452,7 @@ void service_monitor(pid_t lost, int status)
{
svc_t *svc;
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
if (lost <= 1)
return;
svc = svc_find_by_pid(lost);
@@ -1563,24 +1616,35 @@ static void service_post_script(svc_t *svc)
static void service_retry(svc_t *svc)
{
int timeout;
char *restart_cnt = (char *)&svc->restart_cnt;
int timeout;
service_timeout_cancel(svc);
if (svc->state != SVC_HALTED_STATE ||
svc->block != SVC_BLOCK_RESTARTING) {
if (!svc_is_tty(svc))
_d("%s not crashing anymore", svc->cmd);
*restart_cnt = 0;
if (svc->respawn) {
_d("%s crashed, respawning ...", svc->cmd);
svc_unblock(svc);
service_step(svc);
return;
}
if (*restart_cnt >= SVC_RESPAWN_MAX) {
if (svc->state != SVC_HALTED_STATE ||
svc->block != SVC_BLOCK_RESTARTING) {
logit(LOG_CONSOLE | LOG_NOTICE, "Successfully restarted crashing service %s.",
svc_ident(svc, NULL, 0));
return;
}
/* Peak instability index */
if (*restart_cnt >= svc->restart_max) {
logit(LOG_CONSOLE | LOG_WARNING, "Service %s keeps crashing, not restarting.",
svc_ident(svc, NULL, 0));
svc_crashing(svc);
*restart_cnt = 0;
if (svc->oncrash_action == SVC_ONCRASH_REBOOT) {
logit(LOG_ERR, "%s issuing reboot", svc->cmd);
sync();
kill(1, SIGTERM);
}
service_step(svc);
return;
}
@@ -1589,12 +1653,14 @@ static void service_retry(svc_t *svc)
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
logit(LOG_CONSOLE | LOG_WARNING, "Service %s[%d] died, restarting (%d/%d)",
svc_ident(svc, NULL, 0), svc->oldpid, *restart_cnt, SVC_RESPAWN_MAX);
svc_ident(svc, NULL, 0), svc->oldpid, *restart_cnt, svc->restart_max);
svc_unblock(svc);
service_step(svc);
/* Wait 2s for the first 5 respawns, then back off to 5s */
timeout = ((*restart_cnt) <= (SVC_RESPAWN_MAX / 2)) ? 2000 : 5000;
timeout = ((*restart_cnt) <= (svc->restart_max / 2)) ? 2000 : 5000;
/* If a longer timeout was specified in the conf, use that instead. */
timeout = max(svc->restart_tmo, timeout);
service_timeout_after(svc, timeout, service_retry);
}
@@ -1905,6 +1971,65 @@ int service_completed(void)
return 1;
}
/*
* Every five¹ minutes we sweep over all services, skipping crashed or
* otherwise no longer running ones. Decrement non-zero crash counters
* to allow services that have started after an initial crash to slowly
* prove themselves again as stable services. Previously this counter
* was reset as soon as such services had stopped crashing at least once
* per second. This new scheme allows us to catch those that rage-quit
* immediately when we try to start them, but now also those that are
* only slightly buggy -- when they reach their restart_max, they too
* are marked 'crashed'.
*
* This does not affect the restart_tot counter, which you can see in
* the output from 'initctl status foo', along with this instability
* "index" in parethesis: total (cnt/max)
*/
static void service_interval_cb(uev_t *w, void *arg, int events)
{
svc_t *svc, *iter = NULL;
(void)arg;
if (UEV_ERROR == events) {
uev_timer_start(w);
return;
}
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (svc_is_daemon(svc) || svc_is_sysv(svc)) {
char *restart_cnt = (char *)&svc->restart_cnt;
if (!svc_is_running(svc))
continue;
if (*restart_cnt > 0) {
logit(LOG_CONSOLE | LOG_DEBUG, "Aging %s instability index (%d/%d)",
svc_ident(svc, NULL, 0), svc->restart_cnt, svc->restart_max);
(*restart_cnt)--;
}
}
}
service_init();
}
/*
* The service_interval may change (conf) between invocations, so we
* periodically reset the one-shot timer instead of using a periodic.
*/
void service_init(void)
{
static int initialized = 0;
static uev_t watcher;
if (!initialized) {
uev_timer_init(ctx, &watcher, service_interval_cb, NULL, service_interval, 0);
initialized = 1;
} else
uev_timer_set(&watcher, service_interval, 0);
}
/**
* Local Variables:
* indent-tabs-mode: t
+2
View File
@@ -41,6 +41,8 @@ void service_worker (void *unused);
int service_completed (void);
void service_init (void);
#endif /* FINIT_SERVICE_H_ */
/**
+42 -61
View File
@@ -55,7 +55,7 @@
* SIGINT
* Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
* SysV init and systemd default to reboot with `shutdown -r`.
* Finit currently forwards this to SIGTERM.
* Finit defaults to nothing but sets sys/key/ctrlaltdel condition.
*
* SIGWINCH
* Sent from kernel when the KeyboardSignal key is pressed. Some
@@ -66,16 +66,21 @@
* Sent from a power daemon, like powstatd(8), on changes to the
* UPS status. Traditionally SysV init read /etc/powerstatus and
* acted on "OK", "FAIL", or "LOW" and then removed the file.
* Finit currently forwards this to SIGUSR2.
* Finit defaults to nothing but sets sys/pwr/fail condition.
*/
#include <dirent.h>
#include <string.h> /* strerror() */
#include <sys/reboot.h>
#include <sys/wait.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "cond.h"
#include "conf.h"
#include "config.h"
#include "helpers.h"
@@ -95,11 +100,9 @@ extern svc_t *wdog;
*/
shutop_t halt = SHUT_DEFAULT;
static int stopped = 0;
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
static uev_t sigchld_watcher;
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
static struct sigmap {
int num;
@@ -210,8 +213,6 @@ void do_kill(int signo)
void do_shutdown(shutop_t op)
{
touch(SYNC_SHUTDOWN);
if (sdown)
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
@@ -311,7 +312,9 @@ static void sighup_cb(uev_t *w, void *arg, int events)
}
/*
* SIGINT: Should generate <sys/key/ctrlaltdel> condition, for now reboot
* SIGINT: generates <sys/key/ctrlaltdel> condition, which the sys.so
* plugin picks up and tells Finit to start any service(s) or
* task(s) associated with the condition.
*/
static void sigint_cb(uev_t *w, void *arg, int events)
{
@@ -321,8 +324,23 @@ static void sigint_cb(uev_t *w, void *arg, int events)
return;
}
halt = SHUT_REBOOT;
service_runlevel(6);
cond_set_oneshot_noupdate("sys/key/ctrlaltdel");
}
/*
* SIGPWR: generates <sys/pwr/fail> condition, which the sys.so plugin
* picks up and tells Finit to start any service(s) or task(s)
* associated with the condition.
*/
static void sigpwr_cb(uev_t *w, void *arg, int events)
{
_d("...");
if (UEV_ERROR == events) {
_e("Unrecoverable error in signal watcher");
return;
}
cond_set_oneshot_noupdate("sys/pwr/fail");
}
/*
@@ -385,49 +403,17 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
}
/* Reap all the children! */
do {
while (1) {
pid = waitpid(-1, &status, WNOHANG);
if (pid > 0) {
_d("Collected child %d", pid);
service_monitor(pid, status);
if (pid <= 0) {
if (pid == -1 && errno == EINTR)
continue;
break;
}
} while (pid > 0);
}
/*
* SIGSTOP/SIGTSTP: Paused by user or netflash
*/
static void sigstop_cb(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events) {
_e("Unrecoverable error in signal watcher");
return;
_d("Collected child %d", pid);
service_monitor(pid, status);
}
touch(SYNC_STOPPED);
stopped++;
}
/*
* SIGCONT: Restart service monitor
*/
static void sigcont_cb(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events) {
_e("Unrecoverable error in signal watcher");
return;
}
stopped = 0;
erase(SYNC_STOPPED);
}
/*
* Is SIGSTOP asserted?
*/
int sig_stopped(void)
{
return stopped;
}
/*
@@ -463,7 +449,7 @@ const char *sig_name(int signo)
}
/*
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
* Initial signal setup - ignore everything but SIGCHLD until we're capable of responding
*/
static void chld_handler(int sig, siginfo_t *info, void *ctx)
{
@@ -517,17 +503,17 @@ void sig_setup(uev_ctx_t *ctx)
_d("Setup signals");
/* Cleanup any stale finit control files */
erase(SYNC_SHUTDOWN);
erase(SYNC_STOPPED);
/* Standard SysV init calls ctrl-alt-delete handler */
/*
* Standard SysV init calls ctrl-alt-delete handler
* We need to disable kernel default so it sends us SIGINT
*/
reboot(RB_DISABLE_CAD);
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
/* BusyBox/SysV init style signals for halt, power-off and reboot. */
uev_signal_init(ctx, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
uev_signal_init(ctx, &sigpwr_watcher, sigusr2_cb, NULL, SIGPWR);
uev_signal_init(ctx, &sigpwr_watcher, sigpwr_cb, NULL, SIGPWR);
uev_signal_init(ctx, &sigterm_watcher, sigterm_cb, NULL, SIGTERM);
/* Some C APIs may need SIGALRM for implementing timers. */
@@ -539,11 +525,6 @@ void sig_setup(uev_ctx_t *ctx)
/* After initial bootstrap of Finit we call the service monitor to reap children */
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
/* Stopping init is a bit tricky. */
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT);
setsid();
}
-4
View File
@@ -28,9 +28,6 @@
#include <signal.h>
#include <uev/uev.h>
#define SYNC_SHUTDOWN "/var/run/finit/.shutdown"
#define SYNC_STOPPED "/var/run/finit/.stopped"
#define SETSIG(sa, sig, fun, flags) \
do { \
sa.sa_sigaction = fun; \
@@ -69,7 +66,6 @@ typedef enum {
extern shutop_t halt;
void do_shutdown (shutop_t op);
int sig_stopped (void);
int sig_num (const char *name);
void sig_init (void);
void sig_unblock (void);

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