Compare commits

..
78 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
73 changed files with 1306 additions and 447 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 --with-keventd
- 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)'
+71 -7
View File
@@ -4,6 +4,69 @@ Change Log
All relevant changes are documented in this file.
[4.2][] - 2022-01-16
--------------------
### 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
--------------------
@@ -184,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
@@ -506,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
@@ -561,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`
@@ -593,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
@@ -711,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.
@@ -807,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
@@ -975,7 +1038,8 @@ 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
+21 -21
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)
@@ -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
@@ -140,7 +140,7 @@ 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`
@@ -571,34 +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
[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
+27 -1
View File
@@ -1,4 +1,4 @@
AC_INIT(Finit, 4.1, 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])
@@ -57,6 +57,14 @@ 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])
@@ -106,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])
@@ -134,6 +146,12 @@ AS_IF([test "x$enable_auto_reload" = "xyes"], [
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])])
@@ -174,6 +192,11 @@ AS_IF([test "x$with_heading" != "xno"], [
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"], [
hostname=noname])])
@@ -255,8 +278,11 @@ Optional features:
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
@@ -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
@@ -4,4 +4,4 @@
#
# Each line is run in sequence.
#
# NOTE: Remeber to set the executable bit!
# NOTE: Remember to set the executable bit!
+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,
+1 -1
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
+1 -1
View File
@@ -44,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
+2 -2
View File
@@ -90,7 +90,7 @@ Built-in Conditions
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. Similarily, the
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
@@ -180,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
+21 -3
View File
@@ -59,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
@@ -332,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
@@ -390,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
+1 -1
View File
@@ -107,7 +107,7 @@ 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 availble today:
The following condition families are available today:
.Pp
.Bl -tag -width pid -offset indent
.It Cm net
+37 -4
View File
@@ -174,9 +174,13 @@ the default behavior for the
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 10 times
before giving up, then you have to restart it manually:
.Cm initctl restart NAME
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 ,
@@ -200,6 +204,7 @@ 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
@@ -264,6 +269,34 @@ 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
@@ -301,7 +334,7 @@ services named
may be
.Cm foo:1 ,
or any unique identifier specified in the .conf file. The
.cm post:script
.Cm post:script
is called with an additional set of environment variables:
.Bl -tag -offset indent -width 1n
.It Cm EXIT_CODE=[exited,signal]
+12 -1
View File
@@ -118,6 +118,13 @@ Show condition status, default
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 ,
@@ -132,7 +139,11 @@ 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
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
+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"
+15 -5
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
*/
@@ -121,11 +131,11 @@ static void setup(void *arg)
_d("System with new /run tmpfs ...");
if (!fisdir("/run/lock"))
makedir("/run/lock", 1777);
symlink("/run/lock", "/var/lock");
symlink("/dev/shm", "/run/shm");
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);
@@ -179,7 +189,7 @@ 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");
+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] cgroup.system @%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);
+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 {
+23 -13
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"
@@ -40,36 +44,42 @@
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);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
@@ -80,7 +90,7 @@ static void load(void *arg)
fclose(fp);
}
closedir(dirp);
closedir(dir);
}
static plugin_t plugin = {
+1 -1
View File
@@ -355,7 +355,7 @@ static void nl_resync(int all)
if (all) {
_d("============================ RESYNC =================================");
/* this doesn't update condtions, and thus does not stop services */
/* this doesn't update conditions, and thus does not stop services */
cond_deassert("net/");
nl_resync_ifaces(sd, seq++);
+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");
+1 -1
View File
@@ -1,4 +1,4 @@
/* System condtion event monitor for the Finit condition engine
/* System condition event monitor for the Finit condition engine
*
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
+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"
+70 -3
View File
@@ -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"
+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;
+41 -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,6 +175,9 @@ 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];
@@ -302,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;
@@ -318,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;
@@ -330,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)
@@ -364,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;
@@ -378,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))
@@ -409,6 +433,9 @@ void cgroup_config(void)
{
struct cg *cg;
if (!avail)
return;
TAILQ_FOREACH(cg, &cgroups, link) {
char path[256];
int leaf = 0;
@@ -437,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
@@ -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"
@@ -273,7 +277,7 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
nm = strstr((char *)fpath, COND_BASE);
if (!nm) {
_e("Incorrect condtion path %s, cannot %sassert", fpath, set ? "re" : "de");
_e("Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
return 1;
}
+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"
+2 -1
View File
@@ -2,7 +2,8 @@
#define FINIT_COND_H_
#include <paths.h>
#include <svc.h>
#include "svc.h"
#define COND_BASE "finit/cond"
#define COND_PID "pid/"
+55 -6
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"
@@ -82,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)
{
@@ -165,19 +172,41 @@ static void parse_kernel_cmdline(void)
#define parse_kernel_cmdline()
#endif
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[])
{
int dbg = 0;
for (int i = 1; i < argc; i++)
parse_arg(argv[i]);
parse_kernel_cmdline();
parse_kernel_loglevel();
log_init(dbg);
log_init();
}
static int kmod_exists(char *mod)
@@ -544,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)
@@ -580,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;
+7 -3
View File
@@ -33,7 +33,11 @@
#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"
@@ -282,7 +286,7 @@ 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[2K";
static const char clr[] = "\r\e[K";
static const char cup[] = "\e[A";
struct termios orig;
char c;
@@ -351,7 +355,7 @@ pid_t run_getty(char *tty, char *cmd, char *args[], int noclear, int nowait, str
/* 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);
}
+81 -29
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,6 +65,7 @@ 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;
@@ -82,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);
/*
@@ -117,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;
@@ -134,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();
@@ -145,17 +176,31 @@ 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)
@@ -207,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 */
@@ -232,7 +276,7 @@ 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 */
@@ -250,7 +294,7 @@ static void fs_finalize(void)
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
makedir("/dev/pts", 0755);
mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
}
/*
@@ -263,19 +307,19 @@ static void fs_finalize(void)
* for /run (and optionally /run/lock).
*/
if (fisdir("/run") && !fismnt("/run")) {
mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
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);
mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
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", MS_NOSUID | MS_NODEV, "mode=1777");
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());
@@ -299,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)
@@ -319,8 +363,6 @@ 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
@@ -330,9 +372,7 @@ static void fs_init(void)
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);
}
}
@@ -382,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);
@@ -519,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
};
@@ -550,7 +590,7 @@ int main(int argc, char *argv[])
console_init();
/*
* Initalize event context.
* Initialize event context.
*/
uev_init1(&loop, 1);
ctx = &loop;
@@ -597,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.
*/
@@ -608,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));
@@ -653,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
+6 -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 */
@@ -110,6 +114,7 @@ extern int debug;
extern int rescue;
extern int single;
extern int bootstrap;
extern int kerndebug;
extern char *rcsd;
extern char *sdown;
extern char *network;
+16 -2
View File
@@ -25,6 +25,7 @@
#include <err.h>
#include <errno.h>
#include <limits.h> /* LOGIN_NAME_MAX */
#include <paths.h>
#include <signal.h>
#include <stdio.h>
@@ -33,6 +34,7 @@
#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 "helpers.h"
@@ -42,6 +44,12 @@
#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.
*/
@@ -196,8 +204,8 @@ static int do_login(char *name)
static int getty(char *tty, speed_t speed, char *term, char *user)
{
const char cln[] = "\r\e[2K\n";
char name[33]; /* useradd(1) limit at 32 chars */
const char cln[] = "\r\e[K\n";
char name[logname_len + 1]; /* +1 for NUL termination */
pid_t sid;
/*
@@ -263,6 +271,12 @@ int main(int argc, char *argv[])
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);
}
+7 -52
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"
@@ -223,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));
@@ -308,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, ...)
@@ -560,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
+5 -4
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
@@ -126,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_ */
/**
+148 -84
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"
@@ -47,6 +51,7 @@ struct cmd {
char *cmd;
struct cmd *ctx;
int (*cb)(char *arg);
int *cond;
};
int icreate = 0;
@@ -58,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[]);
@@ -167,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;
}
@@ -180,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;
}
@@ -468,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++;
}
@@ -484,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));
@@ -509,7 +519,7 @@ int utmp_show(char *file)
static int do_utmp(char *file)
{
if (!has_utmp())
if (!utmp)
return 1;
if (fexist(file))
@@ -538,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];
@@ -548,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)
@@ -556,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++] = '-';
@@ -699,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)
@@ -718,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)));
@@ -729,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,
@@ -764,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);
@@ -784,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[] = {
@@ -880,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"
@@ -893,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;
}
@@ -918,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;
@@ -947,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[] = {
@@ -964,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':
@@ -1062,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
+5 -1
View File
@@ -37,7 +37,11 @@
#include <linux/types.h>
#include <linux/netlink.h>
#include "lite/lite.h"
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "cond.h"
#include "pid.h"
+8 -4
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 */
+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);
+5 -1
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);
+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"
+111 -13
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);
@@ -491,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);
@@ -843,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.
*/
@@ -1079,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 @
@@ -1119,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.
@@ -1136,6 +1148,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
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;
@@ -1193,6 +1208,18 @@ 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))
@@ -1277,16 +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);
@@ -1327,7 +1357,7 @@ 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)
ptr++;
@@ -1586,8 +1616,8 @@ 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->respawn) {
@@ -1599,15 +1629,22 @@ static void service_retry(svc_t *svc)
if (svc->state != SVC_HALTED_STATE ||
svc->block != SVC_BLOCK_RESTARTING) {
*restart_cnt = 0;
logit(LOG_CONSOLE | LOG_NOTICE, "Successfully restarted crashing service %s.",
svc_ident(svc, NULL, 0));
return;
}
if (*restart_cnt >= SVC_RESPAWN_MAX) {
/* 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;
}
@@ -1616,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);
}
@@ -1932,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_ */
/**
+6 -2
View File
@@ -73,7 +73,11 @@
#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"
@@ -445,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)
{
+10 -5
View File
@@ -23,6 +23,7 @@
#include "config.h" /* Generated by configure script */
#include <paths.h>
#include <sys/types.h>
#include "finit.h"
@@ -38,6 +39,10 @@
sm_t sm;
#ifndef FINIT_NOLOGIN_PATH
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */
#endif
void sm_init(sm_t *sm)
{
sm->state = SM_BOOTSTRAP_STATE;
@@ -76,16 +81,16 @@ static char *sm_status(sm_state_t state)
* Disable login in single user mode and shutdown/reboot
*
* Re-enable only when going from these runlevels, this way a user can
* manage /etc/nologin manually within the other runlevels without us
* pulling the rug from under their feet.
* manage FINIT_NOLOGIN_PATH manually within the other runlevels without
* us pulling the rug from under their feet.
*/
static void nologin(void)
{
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
touch("/etc/nologin");
touch(FINIT_NOLOGIN_PATH);
if (prevlevel == 1 || prevlevel == 0 || prevlevel == 6)
erase("/etc/nologin");
erase(FINIT_NOLOGIN_PATH);
}
void sm_set_runlevel(sm_t *sm, int newlevel)
@@ -187,7 +192,7 @@ restart:
}
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
_d("All services have been stoppped, calling runlevel change hooks ...");
_d("All services have been stopped, calling runlevel change hooks ...");
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
_d("Starting services new to this runlevel ...");
+2 -2
View File
@@ -27,9 +27,9 @@
typedef enum {
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
SM_RUNNING_STATE, /* Normal state, services running */
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occured */
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
SM_RELOAD_CHANGE_STATE, /* A reload event has occured */
SM_RELOAD_CHANGE_STATE, /* A reload event has occurred */
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */
} sm_state_t;
+5 -22
View File
@@ -29,7 +29,11 @@
#include <stdlib.h>
#include <strings.h>
#include <sys/time.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 "finit.h"
#include "svc.h"
@@ -613,27 +617,6 @@ int svc_enabled(svc_t *svc)
return 1;
}
int svc_is_unique(svc_t *svc)
{
svc_t *s, *iter = NULL;
int unique = 1;
for (s = svc_iterator(&iter, 1); s; s = svc_iterator(&iter, 0)) {
if (svc->type == SVC_TYPE_FREE)
continue;
if (s == svc)
continue;
if (s->job == svc->job) {
unique = 0;
break;
}
}
return unique;
}
/* break up "job:id job:id job:id ..." into several "job:id" tokens */
static char *tokstr(char *str, size_t len)
{
+18 -5
View File
@@ -28,8 +28,13 @@
#include <sys/ipc.h> /* IPC_CREAT */
#include <sys/resource.h>
#include <sys/types.h> /* pid_t */
#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 <uev/uev.h>
#include "cgroup.h"
@@ -40,7 +45,7 @@ typedef int svc_cmd_t;
typedef enum {
SVC_TYPE_FREE = 0, /* Free to allocate */
SVC_TYPE_SERVICE = 1, /* Monitored, will be respawned */
SVC_TYPE_TASK = 2, /* One-shot, runs in parallell */
SVC_TYPE_TASK = 2, /* One-shot, runs in parallel */
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
SVC_TYPE_TTY = 8, /* Like service, but dedicated to TTYs */
SVC_TYPE_SYSV = 32, /* SysV style init.d script w/ start/stop */
@@ -70,6 +75,11 @@ typedef enum {
SVC_BLOCK_RESTARTING,
} svc_block_t;
typedef enum {
SVC_ONCRASH_IGNORE = 0,
SVC_ONCRASH_REBOOT = 1,
} svc_oncrash_action_t;
#define MAX_ID_LEN 16
#define MAX_ARG_LEN 64
#define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1)
@@ -102,7 +112,7 @@ typedef struct svc {
struct cgroup cgroup;
/* Service details */
int sighalt; /* Signal to stop prorcess, default: SIGTERM */
int sighalt; /* Signal to stop process, default: SIGTERM */
int killdelay; /* Delay in msec before sending SIGKILL */
pid_t oldpid, pid;
char pidfile[256];
@@ -127,6 +137,10 @@ typedef struct svc {
/* Counters */
char once; /* run/task, (at least) once per runlevel */
unsigned int restart_tot; /* Total restarts ever, summarized, including `initctl restart` */
unsigned char restart_max; /* Maximum number of restarts allowed */
int restart_tmo; /* Time required for the service to start. */
unsigned char oncrash_action; /* Action to perform in crashed state. */
char respawn; /* ttys, or services with `respawn`, never increment restart_cnt */
const char restart_cnt; /* Incremented for each restart by service monitor. */
@@ -207,7 +221,6 @@ void svc_prune_bootstrap (void);
void svc_enable (svc_t *svc);
int svc_enabled (svc_t *svc);
int svc_is_unique (svc_t *svc);
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
+5 -1
View File
@@ -29,7 +29,11 @@
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "config.h" /* Generated by configure script */
#include "finit.h"
+58 -3
View File
@@ -24,6 +24,7 @@
#include "config.h"
#include <ctype.h> /* isprint() */
#include <errno.h>
#include <mntent.h>
#include <regex.h>
#include <string.h>
#include <stdlib.h>
@@ -37,7 +38,11 @@
# include <sys/ioctl.h>
#endif
#include <sys/sysinfo.h> /* sysinfo() */
#include <lite/lite.h> /* strlcat() */
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "util.h"
#ifdef HAVE_TERMIOS_H
@@ -177,7 +182,8 @@ int fnread(char *buf, size_t len, char *fmt, ...)
if (!fp)
return -1;
len = fread(buf, sizeof(char), len, fp);
len = fread(buf, sizeof(char), len - 1, fp);
buf[len] = 0;
fclose(fp);
return (int)len;
@@ -216,7 +222,7 @@ int fnwrite(char *value, char *fmt, ...)
int fngetint(char *path, int *val)
{
char buf[10];
char buf[64];
if (fnread(buf, sizeof(buf), path) <= 0)
return -1;
@@ -393,6 +399,55 @@ char *sanitize(char *arg, size_t len)
return arg;
}
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);
}
#ifdef HAVE_TERMIOS_H
/*
* Called by initctl, and by finit at boot and shutdown, to
+10 -2
View File
@@ -32,7 +32,6 @@
#include <sys/reboot.h>
#include <termios.h>
#endif
#include <lite/lite.h>
#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */
#define RB_SW_SUSPEND 0xd000fce2
@@ -45,7 +44,13 @@ extern char *prognm;
/* Define for printheader() from conio.h, used in initctl */
#define SCREEN_WIDTH ttcols
#include <lite/conio.h>
#ifdef _LIBITE_LITE
# include <libite/conio.h>
# include <libite/lite.h>
#else
# include <lite/conio.h>
# include <lite/lite.h>
#endif
char *progname (char *arg0);
@@ -65,6 +70,9 @@ char *memsz (uint64_t sz, char *buf, size_t len);
char *sanitize (char *arg, size_t len);
int ismnt (char *file, char *dir, char *mode);
int fismnt (char *dir);
#ifdef HAVE_TERMIOS_H
int ttinit (void);
int ttraw (void);
+5 -1
View File
@@ -26,7 +26,11 @@
#include <time.h>
#include <arpa/inet.h>
#include <sys/utsname.h>
#include <lite/lite.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "helpers.h"
#include "util.h"
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/sh
# Execute a given command from withing the test environment.
# Execute a given command from within the test environment.
#
# Copyright (c) 2021 Jacques de Laval <jacques@de-laval.se>
#