mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c99762f1 | ||
|
|
067043b298 |
@@ -9,9 +9,9 @@ For email questions/requests/alerts there is always the risk of memory
|
||||
exhaustion on the part of the maintainer(s).
|
||||
|
||||
If you are unsure of what to do, or how to implement an idea or bugfix,
|
||||
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or use the
|
||||
GitHub discussions forum, so we can discuss it. Talking about the code
|
||||
first is the best way to get started before submitting a pull request.
|
||||
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or similar,
|
||||
so we can discuss it. Talking about the code first is the best way to
|
||||
get started before submitting a pull request.
|
||||
|
||||
Either way, when sending an email, patch, or pull request, start by
|
||||
stating the version the change is made against, what it does, and why.
|
||||
@@ -73,6 +73,7 @@ It is expected of everyone engaging in the project to, in the words of
|
||||
Bill & Ted; [be excellent to each other][conduct].
|
||||
|
||||
|
||||
[github]: https://github.com/troglobit/finit/
|
||||
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||
[conduct]: CODE-OF-CONDUCT.md
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
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 tree jq libuev-dev libite-dev
|
||||
- uses: actions/checkout@v3
|
||||
- name: Static Finit
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix= --enable-static
|
||||
make V=1
|
||||
- name: Regular Finit
|
||||
run: |
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||
--with-keventd
|
||||
make clean
|
||||
make V=1
|
||||
- name: Install to /tmp
|
||||
run: |
|
||||
DESTDIR=/tmp make install-strip
|
||||
tree /tmp || true
|
||||
- name: Check dependencies
|
||||
run: |
|
||||
ldd /tmp/sbin/finit
|
||||
size /tmp/sbin/finit
|
||||
ldd /tmp/sbin/initctl
|
||||
size /tmp/sbin/initctl
|
||||
ldd /tmp/sbin/reboot
|
||||
size /tmp/sbin/reboot
|
||||
- name: Verify starting and showing usage text
|
||||
run: |
|
||||
sudo /tmp/sbin/finit -h
|
||||
sudo /tmp/sbin/initctl -h
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
make check || (cat test/test-suite.log; false)
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: finit-test-${{ matrix.compiler }}
|
||||
path: test/*.log
|
||||
@@ -1,63 +0,0 @@
|
||||
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@v3
|
||||
- uses: actions/cache@v3
|
||||
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.4.0/libuev-2.4.0.tar.xz
|
||||
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
|
||||
tar xf libuev-2.4.0.tar.xz
|
||||
tar xf libite-2.5.2.tar.gz
|
||||
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
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}
|
||||
@@ -1,40 +0,0 @@
|
||||
name: Release General
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Build and upload release tarball
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Installing dependencies ...
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||
- name: Creating Makefiles ...
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||
--with-keventd
|
||||
- name: Build release ...
|
||||
run: |
|
||||
make release || (cat test/test-suite.log; false)
|
||||
ls -lF ../
|
||||
mkdir -p artifacts/
|
||||
mv ../*.tar.* artifacts/
|
||||
- name: Extract ChangeLog entry ...
|
||||
run: |
|
||||
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||
|head -n -1 > release.md
|
||||
cat release.md
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: Finit v${{ github.ref_name }}
|
||||
bodyFile: "release.md"
|
||||
artifacts: "artifacts/*"
|
||||
@@ -1,48 +0,0 @@
|
||||
name: Weekly Distcheck
|
||||
|
||||
# Verify that `make distcheck` works as intended: all tests pass, and
|
||||
# any new files are distributed in the tarballs
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
schedule:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
run: ${{ steps.check.outputs.run }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check for any commits since last week
|
||||
run: |
|
||||
commits="$(git log --format=%H --since='1 week ago')"
|
||||
if [ -n "$commits" ]; then
|
||||
echo "run=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "run=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
distcheck:
|
||||
needs: schedule
|
||||
if: ${{ needs.schedule.outputs.run == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||
- uses: actions/checkout@v3
|
||||
- name: Base run
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var
|
||||
make -j9 V=1
|
||||
- name: Install to /tmp
|
||||
run: |
|
||||
DESTDIR=/tmp make install-strip
|
||||
- name: Check dist tarball
|
||||
run: |
|
||||
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||
dir=finit-$ver/_build/sub
|
||||
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
|
||||
@@ -45,6 +45,3 @@ GTAGS
|
||||
/.autoconf
|
||||
/.automake
|
||||
/.built
|
||||
|
||||
# VS Code user settings
|
||||
.vscode
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# GNU Global .conf file, see /etc/gtags/gtags.conf for details.
|
||||
default:\
|
||||
:tc=default@/etc/gtags/gtags.conf:\
|
||||
:tc=common:
|
||||
|
||||
common:\
|
||||
:skip=tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake,*.o,*.a,*.so,*.lo,*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,*.min.js,*min.css,sysroot/:
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# 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
|
||||
|
||||
# Use non-docker builds atm. to install libuEv and libite from source
|
||||
#sudo: true
|
||||
|
||||
# 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=/tmp"
|
||||
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=/tmp --enable-static
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog --enable-logit
|
||||
- cat config.log
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
- make install-strip
|
||||
- tree /tmp
|
||||
- ldd /tmp/sbin/finit
|
||||
- size /tmp/sbin/finit
|
||||
- size /tmp/sbin/initctl
|
||||
- size /tmp/sbin/reboot
|
||||
- LD_LIBRARY_PATH=/tmp/lib /tmp/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)'
|
||||
+29
-693
@@ -4,647 +4,12 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.4][] - 2023-05-15
|
||||
--------------------
|
||||
|
||||
> **Note 1:** this release contains changes to the `.conf` parser. If you
|
||||
> have .conf file statements with comment character (`#`) in the command
|
||||
> options or description, you must now escape them (`\#`). Issue #186
|
||||
>
|
||||
> **Note 2:** prior to this release, runlevel `S` and `0` were after
|
||||
> boot treated as the same runlevel. This caused `task [06] ...` to
|
||||
> also run at bootstrap instead of just at shutdown and reboot. The
|
||||
> changes made to Finit to separate `S` from `0` require you to update
|
||||
> the allowed runlevels for services that are allowed to continue
|
||||
> running at shutdown. I.e., change `[S123456789]` to `[S0123456789]`
|
||||
> for, e.g., `sysklogd`. Issue #352
|
||||
|
||||
### Changes
|
||||
* Add limited tmpfiles.d(5) support
|
||||
|
||||
This change adds very basic `tmpfiles.d/` support to Finit. Most of
|
||||
the basic types are supported, but not all, so for now, please check
|
||||
the code and examples for details on what is working.
|
||||
|
||||
* If a run/task/service command does not exist, skip registering it
|
||||
|
||||
This changes the semantics of Finit a bit by checking for the command
|
||||
to run when registering it, skipping commands that cannot be found in
|
||||
the absolute path provided in the command, or in `$PATH`
|
||||
|
||||
This change includes a new `nowarn` flag that can be used to prevent
|
||||
Finit from warning for missing commands. See below for an example.
|
||||
|
||||
* Add run/task/service support for `conflict:foo` handling
|
||||
* Add run/task/service support for `if:[!]ident` and `if:<[!]cond>`
|
||||
|
||||
Conditional loading of stanza depending on ident is already loaded (or
|
||||
not), or condition satisfied (or not). E.g., do not run `mdev` if we
|
||||
found and registered `udevd`, or load service only if `<boot/testing>`
|
||||
condition is set.
|
||||
|
||||
The optional leading `!` negates the comparison, if NOT foo then ...
|
||||
|
||||
* Add support for static services in `/lib/finit/system/*.conf`
|
||||
|
||||
Slowly migrating away from hard-coded services in plugins. This way
|
||||
it's possible for the user to both inspect and override as needed.
|
||||
|
||||
* Migrate hotplug plugin to a conditional `/lib/finit/system/hotplug.conf`
|
||||
|
||||
This is the first example of the just minted advanced stanza syntax with
|
||||
`if:`-statements, `conflict:` handling, and `nowarn` flags.
|
||||
|
||||
* Initial support for template services, `foo@.conf`, similar to systemd
|
||||
|
||||
$ initctl show avahi-autoipd@
|
||||
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||
|
||||
To enable ZeroConf for, e.g., `eth0`, use
|
||||
|
||||
$ initctl enable avahi-autoipd@eth0.conf
|
||||
|
||||
The enabled symlink will be set up to `avahi-autoipd@.conf` and every
|
||||
instance of `%i` will in the instantiated directive be replaced with
|
||||
`eth0`. Inspect the result with:
|
||||
|
||||
$ initctl status avahi-autoipd:eth0
|
||||
|
||||
* Add `devmon`, a `<dev/foo>` condition provider, issue #185
|
||||
* Support for line continuation character `\` in .conf files, issue #186
|
||||
|
||||
service name:sysklogd [S123456789] \
|
||||
env:-/etc/default/sysklogd \
|
||||
syslogd -F $SYSLOGD_ARGS \
|
||||
-- System log daemon
|
||||
|
||||
* `HOOK_BASEFS_UP` has been moved! External plugins that need to call
|
||||
`service_register()`, please use `HOOK_SVC_PLUGIN` from now on.
|
||||
Apologies for any inconveniences this might cause!
|
||||
* getty: add support for `/etc/os-release` to replace `uname` output
|
||||
This change, which has a fallback to `/usr/lib/os-release`, overrides
|
||||
traditional modifiers with the os-release variant. These values were
|
||||
taken from `uname`, which on Linux systems are pretty useless since
|
||||
they always return the kernel name and version instead of the
|
||||
distro/OS values.
|
||||
|
||||
E.g., \s becomes `PRETTY_NAME` instead of 'Linux' and \v becomes the
|
||||
pretty `VERSION`, while \r becomes `VERSION_ID`.
|
||||
* Support for overriding `/etc/finit.conf` and `/etc/finit.d` issue #235
|
||||
New (kernel) command line option `finit.config=PATH` which can be used
|
||||
to redirect Finit to start up with, e.g., `/etc/factory.conf` instead of
|
||||
`/etc/finit.conf`.
|
||||
|
||||
For the complete experience a new top-level configuration file directive
|
||||
`rcsd PATH` has aslo been added. It in turn can be used by `factory.conf`
|
||||
as follows to override `/etc/finit.d`:
|
||||
|
||||
rcsd /etc/factory.d
|
||||
|
||||
* Support for overriding `/etc/finit.d` from the alternate `finit.conf`
|
||||
with a new `rcsd /path/to/dot.d/` .conf file directive
|
||||
* Support for `fsck_mode=[auto,skip,force]` + `fsck_repair=[preen,no,yes]`
|
||||
* Add `set` keyword for environment variables set in `/etc/finit.conf`
|
||||
* Support `finit.cond=foo` cmdline `<boot/foo>` conditions, issue #250
|
||||
* `initctl` JSON output support for status and conditions, issue #273
|
||||
Example:
|
||||
|
||||
root@infix:~$ initctl status -j resolvconf
|
||||
{
|
||||
"identity": "resolvconf",
|
||||
"description": "Update DNS configuration",
|
||||
"type": "task",
|
||||
"forking": false,
|
||||
"status": "done",
|
||||
"exit": { "code": 0 },
|
||||
"origin": "/etc/finit.d/enabled/sysrepo.conf",
|
||||
"command": "resolvconf -u",
|
||||
"restarts": 0,
|
||||
"pidfile": "none",
|
||||
"pid": 0,
|
||||
"user": "root",
|
||||
"group": "root",
|
||||
"uptime": 0,
|
||||
"runlevels": [ 1, 2, 3, 4, 5, 7, 8, 9 ]
|
||||
}
|
||||
|
||||
The excellent tool `jq` can be used to extract parts of the output for
|
||||
further scripting. E.g. `initctl status -j foo | jq .exit.status`
|
||||
|
||||
* Add JSON support to `initctl ls` command
|
||||
|
||||
This allows for easy access to the *disabled* services:
|
||||
|
||||
root@anarchy:~# initctl ls --json |jq '.available - .enabled'
|
||||
[
|
||||
"chronyd.conf",
|
||||
"dnsmasq.conf",
|
||||
"gdbserver.conf",
|
||||
"inadyn.conf",
|
||||
"inetd.conf",
|
||||
"isisd.conf",
|
||||
"lldpd.conf",
|
||||
"mstpd.conf",
|
||||
"ntpd.conf",
|
||||
"ospf6d.conf",
|
||||
"ospfd.conf",
|
||||
"querierd.conf",
|
||||
"ripd.conf",
|
||||
"ripng.conf",
|
||||
"sshd.conf",
|
||||
"syslogd.conf",
|
||||
"telnetd.conf",
|
||||
"uftpd.conf",
|
||||
"wpa_supplicant.conf",
|
||||
"zebra.conf"
|
||||
]
|
||||
|
||||
* Allow `manual:yes` on sysv/service/run/task stanzas, issue #274
|
||||
* Add support for `oncrash:script` to call the `post:script` action, if
|
||||
defined, for a crashing service. The `EXIT_CODE` variable sent to the
|
||||
script is set to `crashed`. Issue #282
|
||||
* Search for plugins in `/usr` and `/usr/local` as well, issue #284
|
||||
* tty: add support for `passenv` flag to `/bin/login`, issue #286
|
||||
* Add reboot/shutdown/poweroff timeout `-t SEC` to initctl, issue #295
|
||||
* Add support for s6 and systemd readiness notification, issue #299.
|
||||
Service readiness notification to support daemons employing systemd
|
||||
and s6 notification. Complementing the native Finit readiness support
|
||||
using PID files that exist already.
|
||||
|
||||
The two have slightly different ways of implementing readiness:
|
||||
|
||||
- https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
- https://skarnet.org/software/s6/notifywhenup.html
|
||||
|
||||
Finit now provides both a `NOTIFY_SOCKET` environment variable, for
|
||||
systemd, and a way to start s6 daemons with a descriptor argument.
|
||||
|
||||
For details on the syntax, see the `service` documentation.
|
||||
|
||||
This change also renames internal states for run/task/services to
|
||||
avoid any confusion with the introduction of `ready:scripts`:
|
||||
|
||||
- `WAITING -> PAUSED`
|
||||
- `READY -> WAITING`
|
||||
|
||||
A service condition that used, e.g., `<service/foo/ready>` should now
|
||||
instead use `<service/foo/waiting>`
|
||||
|
||||
* Add `ready:script` for services, called when daemon is ready, issue #300
|
||||
* Add support for running scripts at shutdown at two new hook points
|
||||
during the shutdown process, issue #302. See doc/plugins.md for details:
|
||||
|
||||
- `HOOK_SVC_DN`: after all services and non-reserved processes have been
|
||||
killed (and collected)
|
||||
- `HOOK_SYS_DN`: after all file systems have been unmounted, *just prior*
|
||||
to Finit calling `reboot()` to shut down or reboot the system
|
||||
|
||||
* The `modules-load` plugin now default to runlevel `[S]`, in previous
|
||||
releases it was `[2345]`. This breaking change is to align it more
|
||||
with what users mostly want (modules loaded before services start) and
|
||||
can be changed back to the old behavior with a per-file setting:
|
||||
|
||||
set runlevel 2345
|
||||
|
||||
* The `modules-load` plugin now adds silent tasks for modprobe. This to
|
||||
prevent confusing `[ OK ]` boot messages when in fact modprobe failed.
|
||||
* The `modules-load` plugin now support `set modprobe /path/to/modprobe`
|
||||
* The header files `finit/conf.h` and `finit/service.h` are now exported
|
||||
for external plugins
|
||||
* Add support for multiple args to `initctl cond set/clr`, issue #329
|
||||
* Silence confusing `[ OK ]` progress from modules-load plugin, issue #332
|
||||
|
||||
This change drops the confusing status progress output, which was always
|
||||
OK since the actual modprobe operation runs in the background. No need
|
||||
to show status of the "added a task to finit, found modprobe" command.
|
||||
|
||||
* dbus plugin: adapt to other operating systems
|
||||
|
||||
Not all Linux systems are based on Debian, and even if they are inspired
|
||||
by Debian (Buildroot), they do not necessarily use the same defaults.
|
||||
Probes the system at runtime for:
|
||||
|
||||
- dbus user and group
|
||||
- dbus PID file
|
||||
|
||||
If the user/group cannot be found we fall back to `root`, if the PID
|
||||
file cannot be determined we ignore PID file readiness.
|
||||
|
||||
* Improve documentation for runparts and hook scripts. Issue #315, #320
|
||||
* Add `HOOK_NETWORK_DN`, called after change to runlevel 6 or 0, issue #319
|
||||
* Use sysklogd `logger` tool instead of legacy `logit` tool, issue #344
|
||||
|
||||
For log redirection Finit has the legacy `logit` tool. This change
|
||||
allows Finit to use the `sysklogd` project's extended `logger` tool
|
||||
instead, when available. Allowing logging with the process' PID.
|
||||
|
||||
* Add `initctl` aliases: `cat -> show`, `kill -> signal`
|
||||
* Add `initctl -n,--noerr` to return OK(0) if services do not exist, for
|
||||
integration with openresolv and scripts with similar requirements
|
||||
* Add `initctl plugins`, list installed plugins
|
||||
* Add timestamp to log messages in fallback and logging to `stderr`.
|
||||
When there is no log daemon, and we are running in a container, or we
|
||||
cannot log to the kernel ring buffer, then we log to `stderr`. This
|
||||
change improves log output by prefixing each message with a timestamp.
|
||||
|
||||
### Fixes
|
||||
* Fix #254: document limitations in `rc.local` and `runparts` scripts
|
||||
* Fix #269: add compulsory kernel symlinks in `/dev`
|
||||
* Fix #275: `initctl status foo` should list all instances, regression
|
||||
introduced in v4.3
|
||||
* Fix #278: enforce conditions also for running `pre:` scripts
|
||||
* Fix #279: allow `restart:always`, of crashing services. Similar to
|
||||
`respawn` but honors `restart_sec`
|
||||
* Fix #280: allow calling `initctl restart foo` from within foo
|
||||
* Fix #283: too quick timeout at bootstrap of lingering tasks
|
||||
* Fix #285: `initctl restart` should start crashed service
|
||||
* Fix #288: enable built-in `sulogin` in Alpine and Void Linux builds
|
||||
* Fix #293: modprobe plugin: support for coldplugging more devices. It
|
||||
turns out, not all buses in Linux add `modalias` attributes to their
|
||||
devices in sysfs. One notable exception are MDIO buses. The plugin's
|
||||
scan routine would thus not pick them up.
|
||||
* Fix #294: `shutdown --help` mistakenly shuts down system
|
||||
* Fix #310: Always use configured restart delay for crashing services.
|
||||
If no delay is configured, default to an initial 2000 msec for forking
|
||||
daemons and start-stop scripts, and 1 msec for non-forking daemons
|
||||
* Fix #311: document how to combine device tree with conditions
|
||||
* Fix #312: restart services with respawn set, e.g. ttys, immediately
|
||||
* Fix #313: Cancel pending restart timer on stop/start/restart/reload
|
||||
* Fix #314: skip run/task/service restart if conditions are lost
|
||||
* Fix #315: add environment variables to hook scripts
|
||||
|
||||
All hook scripts are called with at least one environment variable
|
||||
set, `FINIT_HOOK_NAME`, useful when reusing the same hook script for
|
||||
multiple hook points. It is set to the string name, also used by the
|
||||
path, e.g., `hook/net/up`
|
||||
|
||||
For all hook points from hook/sys/shutdown and later, `FINIT_SHUTDOWN`
|
||||
is also set, to one of: `halt`, `poweroff`, `reboot`
|
||||
|
||||
* Fix #317: make sure hook scripts don't run twice, also fixes #316
|
||||
* Fix #318: only show `[ OK ] Calling foo` progress for `runparts ...`
|
||||
* Fix #320: the API/IPC socket is closed immediately at shutdown/reboot
|
||||
to protect hook scripts or services calling initctl. There is no way
|
||||
to service these requests safely at that time
|
||||
* Fix #333: consider a service dirty if command line args have changed
|
||||
|
||||
This fixes `initctl reload` correctly restarting all daemons that have
|
||||
new command line arguments.
|
||||
|
||||
Previously command line arguments changes were only acted upon if the
|
||||
service was explicitly reloaded `initctl reload myservice`.
|
||||
|
||||
Found and fixed by Jack Newman
|
||||
|
||||
* Fix #338: ensure shutdown hooks are called properly; `hook/sys/down`
|
||||
and `hook/svc/down` hook scripts, found and fixed by Jack Newman
|
||||
* Fix #339: use absolute path in `/etc/finit.d/enabled/` symlinks, for
|
||||
use-cases when `/etc` is read-only and `/etc/finit.d/enabled ->
|
||||
/mnt/finit.d/enabled`, reported by Jack Newman
|
||||
* Fix #340: Finit ignores deleted/moved `.conf` file sin `/etc/finit.d`
|
||||
* Fix #342: in runlevel S (bootstrap), not all `initctl` commands can be
|
||||
supported, block the following: runlevel, reload, start/stop, restart,
|
||||
reload, halt, poweroff, suspend. Also, prevent `SIGHUP` and `SIGUSR1`
|
||||
signals when in shutdown or reboot
|
||||
* Fix #352: separate runlevel S from runlevel 0
|
||||
* Fix #355: regression in v3.2 stopping a process and its group
|
||||
|
||||
In Finit v3.2 a regression was introduced that affects the way Finit
|
||||
stops a supervised process and its process group.
|
||||
|
||||
Instead of sending SIGTERM to the process, and thus delegating the
|
||||
responsibility to that process to inform any children it may have, as
|
||||
of commit 91a9c83 Finit sends SIGTERM to the entire process group.
|
||||
For SIGKILL this is fine, SIGKILL only runs as cleanup and as a last
|
||||
ditch effort if the process doesn't respond to SIGTERM.
|
||||
|
||||
This regression, introduced in v3.2, directly affects services like
|
||||
`avahi-autoipd` that have forked off children that it needs to tell to
|
||||
exit cleanly before it returns. With the patch in question these
|
||||
children are never allowed to complete, which in turn causes lingering
|
||||
169.254 link-local addresses on interfaces.
|
||||
|
||||
* Fix bootmisc plugin: octal permission on `/run/lock` and `/var/lock`
|
||||
|
||||
* Ensure `initctl cond get` support the flux state (exit code 255)
|
||||
* Fix potential socket leak at bootstrap and shutdown
|
||||
* Fix potential NULL pointer deref in kernel command line parser
|
||||
* Fix lingering condition in service after reload of service with new
|
||||
config that has no condition
|
||||
* Fix wrong path to command in service after reload, may have changed
|
||||
* `logit`: fall back to package name if `$LOGNAME` and `$USER` are
|
||||
unset. **Note:** you should probably not use `logit` in your own
|
||||
scripts, it is only meant for internal use by Finit. We recommend
|
||||
using `logger` from the `bsdutils` or `sysklogd` packages instead
|
||||
* Fix issue where `env:`/`pre:`/`post:`/etc. is removed from a service
|
||||
|
||||
The trick is when reloading a service like this:
|
||||
|
||||
service env:/etc/env serv -np -e foo:bar
|
||||
|
||||
into this:
|
||||
|
||||
service pre:/bin/pre.sh serv -np
|
||||
|
||||
In the second the `env:` has been removed and `pre:` added. Prior to
|
||||
this patch, `env:` was kept leading to unintended behavior.
|
||||
* Fix parse/diff of command line args, e.g., `nginx -g 'daemon off;'`
|
||||
|
||||
Starting a service like this works fine:
|
||||
|
||||
service [2345789] env:-/etc/default/nginx nginx -g 'daemon off;'
|
||||
|
||||
However, on `initctl reload` (and no change to .conf files) the arg
|
||||
list was lost while parsing the .conf files. Leading to a false
|
||||
positive 'diff' in args causing nginx to be unnecessarily restarted.
|
||||
* Fix issue with disabled "linewrap" on the console TTY after login.
|
||||
The root cause is `qemu-system-x86_64 -nographics` disabling it when
|
||||
starting up. The correct `\e[?7h` escape code is now used.
|
||||
|
||||
|
||||
[4.3][] - 2022-05-15
|
||||
--------------------
|
||||
|
||||
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
|
||||
you *need* to upgrade!
|
||||
|
||||
> **Note:** system verbosity on console at start and shutdown has been
|
||||
> increased. Now the output of all commands is logged to the
|
||||
> system logger, for early services `/dev/kmsg` is used.
|
||||
>
|
||||
> **Also:** please notice the updated support for enabling and disabling
|
||||
> kernel and Finit debug messages on the system console. Very
|
||||
> useful when debugging either of them, e.g., a kernel module.
|
||||
> For details, see [cmdline.md](doc/cmdline.md).
|
||||
|
||||
### Changes
|
||||
* Support for overriding default runlevel from kernel command line. Any
|
||||
runlevel `[1-9]` may be selected, except 6 (reboot). Issue #261
|
||||
* New command line option: `finit.fstab=/etc/fstab.custom`, with full
|
||||
support for mounting, mount helpers, fsck, and swapon/off, issue #224
|
||||
* Support for special device `/dev/root`, which may not exist in `/dev`.
|
||||
Finit now looks up the matching block device for `/` in `/sys/block/`
|
||||
* Loading `module`s no longer shows arguments in progress output
|
||||
* Warning messages in progress output now in yellow, not red, issue #214
|
||||
* `initctl`, new command line option `-V,--version` for ease of use
|
||||
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
|
||||
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
|
||||
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
|
||||
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
|
||||
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
|
||||
* Conditions for services, can be used to synchronize other stanzas:
|
||||
- `service/foo/running`
|
||||
- `service/foo/halted`
|
||||
- `service/foo/missing`
|
||||
- `service/foo/crashed`
|
||||
- `service/foo/stopped`
|
||||
- `service/foo/busy`
|
||||
- `service/foo/restart`
|
||||
* `initctl signal` support, by Jörgen Sigvardsson, issue #225
|
||||
* `initctl cond get` support to match `cond [set | clear]`, issue #255
|
||||
* `[WARN]` messages on console now printed in yellow, issue #214
|
||||
* Network services now also stopped when going to runlevel 6 (reboot),
|
||||
not just runlevel 0 (shutdown) or 1 (single-user)
|
||||
* When `ifup` is missing on the system, bring at least `lo` up at boot
|
||||
* Log output from `ifup -a` (and `ifdown -a`), to syslog
|
||||
* Avoid blocking PID 1 when starting SysV init scripts
|
||||
* Allow custom `pid:` for SysV init scripts
|
||||
* Document supported types of forking/non-forking services
|
||||
* Auto-detect running in some common forms of containers
|
||||
* Simplify shutdown/reboot when running in a container
|
||||
* Log to `stderr` when running in a container w/o syslog daemon
|
||||
* Add support for `type:forking` to services, already supported but
|
||||
with a very difficult `pid:` syntax, issue #223. Docs updated
|
||||
* Support for setting global environment variables in `finit.conf`,
|
||||
please note: this also affects Finit itself, be careful!
|
||||
* Extended environment variables for pre/post scripts, issue #189
|
||||
* Document secret service option `respawn`, which bypasses the crash
|
||||
semantics, allowing endless restarts
|
||||
* Document secret `HOOK_BANNER`, the first hook point before the banner
|
||||
* Document slightly confusing `initctl reload foo` command. It does
|
||||
*not* reload the service's `.conf` file! Issue #263
|
||||
* Log changes; all instances where previously the `basename cmd` of a
|
||||
service was used to identify the service, now the proper `name:id` is
|
||||
used instead. Meaning, a service without a custom `:ID` or `name:`
|
||||
will display the same as before, but with any of those customizations
|
||||
the name and name:id will now be shown. **Note:** this may affect any
|
||||
log scrapers out there!
|
||||
* New plugin: `hook-scripts`, allows [run-parts(8)][] style scripts to
|
||||
run on any hook point. Contributed by Tobias Waldekranz
|
||||
* `initctl` (`reboot`) falls back to `-f` when it detects it is in
|
||||
`sulogin` recovery mode, issue #247
|
||||
* The bundled `sulogin` is no longer enabled by default, in favor of
|
||||
distribution versions. Enable with `./configure --with-sulogin`
|
||||
* Support args to sysv-like scripts, e.g. `bridge-stp br0 start`
|
||||
* The `modules-load` plugin now skips all lines starting with `#` and
|
||||
`;`. Furthermore, files in `/etc/modules-load.d/*.conf` are now read
|
||||
in lexicographic order and UNIX backup files (`foo.conf~`) are skipped
|
||||
* The `name:id` tuple is now more consistently used in all log and debug
|
||||
messages instead of the basename of the command
|
||||
* Simplify error output of `initctl start/stop/restart/signal`, no more
|
||||
extra usage help, just a plain error message
|
||||
* Exit codes of `initctl` have changed to use LSB script standard and BSD
|
||||
sysexits.h exit codes. As before, a non-zero exit is error or missing
|
||||
* Add support for `initctl -q` to more commands: stop, start, restart,
|
||||
reload, signal, etc.
|
||||
|
||||
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
|
||||
### Fixes
|
||||
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
|
||||
applicable to 32-bit targets with GLIBC 2.34 and later. External
|
||||
plugins must make sure to use, at least: `-D_TIME_BITS=64`
|
||||
* Fix #215: disable cgroup support at runtime if kernel lacks support
|
||||
or does not have the required controllers (cpu)
|
||||
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
|
||||
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
|
||||
* Fix #219: not all filesystems unmounted at shutdown, by Ming Liu,
|
||||
Mathias Thore, and Robert Andersson, Atlas Copco
|
||||
* Fix #226: initctl shows wrong PID for crashing services
|
||||
* Fix #227: reboot stalls if process stopped with `[WARN]`
|
||||
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
|
||||
and Ming Liu, Atlas Copco
|
||||
* Fix #248: source `env:file` also in `pre:` and `post` scripts
|
||||
* Fix #260: drop limit on device name in `Checking filesystem...` output
|
||||
* Fix start/stop and monitoring (restart) of SysV init scripts and
|
||||
forking services, see the updated documentation for details
|
||||
* Fix call to `swapoff` at shutdown, does not support `-e` flag
|
||||
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
|
||||
used, now the modern `/sys/power/state` API is used instead.
|
||||
* Fix nasty run/task/service matcher bug, triggered by stanzas using the
|
||||
same basename of a command but different `:ID`. Caused Finit to match
|
||||
with already registered but different run/task/service
|
||||
|
||||
|
||||
[4.2][] - 2022-01-16
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Support for non-root users to use `initctl`, e.g. group wheel
|
||||
* Support for new libite (-lite) header namespace
|
||||
* RTC plugin now reset an invalid RTC time to the kernel default
|
||||
time, 2000-01-01 00:00, prevents errors and is less crazy than
|
||||
some systems coming with with <= Jan 1, 1970
|
||||
* urandom plugin now use RNDADDENTROPY ioctl to seed kernel rng,
|
||||
incrementing entropy count. Also, 32 kiB instead of 512 bytes are
|
||||
now saved (and restored) on reboot. This should greatly improve
|
||||
reliability of systems with none or poor HWRNG
|
||||
* Kernel logging to console (loglevel >= 7, debug, when quiet mode is
|
||||
not used) is now honored by Finit, regardless of the finit.debug
|
||||
command line option
|
||||
* Reduced default log level from `LOG_NOTICE` to `LOG_INFO`
|
||||
* Wrapped all calls to mount(2) to add logging in case of failure
|
||||
* New configure options to control fastboot (no fsck) and fsck fix
|
||||
options, by Ming Liu, Atlas Copco
|
||||
* Support for overriding default `/etc/nologin` file with an external
|
||||
`#define`, by Ming Liu, Atlas Copco
|
||||
* Support for overriding default `/var/run/dbus/pid` file with an
|
||||
external `#define`, by Ming Liu, Atlas Copco
|
||||
* Support for more service options to control respawn behavior of
|
||||
crashing services, by Robert Andersson and Ming Liu, Atlas Copco
|
||||
* Support for `initctl ident [NAME]` which lists all instances of
|
||||
`NAME`, or all enabled system run/tasks and services
|
||||
* Show number of total restarts and current respawn count for a
|
||||
service in `initctl status foo`
|
||||
* Crashing services no longer have the crash/restart counter reset as
|
||||
soon as they have stabilized. Instead, a background timer will
|
||||
slowly (every 300 sec) age (decrement) the counter. This will still
|
||||
catch services that "rage quit", but also those that crash after a
|
||||
longer period of activity
|
||||
|
||||
### Fixes
|
||||
* Fix #180: user managed (`manual:yes`) services accidentally started
|
||||
by `initctl reload`, regression introduced in Finit v4.0
|
||||
* Fix #181: lots of typos all over the tree, by David Yang, Debian
|
||||
* Fix #187: fix typos, incl. small cleanup, in doc/bootstrap.md
|
||||
* Fix #188: support running on kernels that do not have cgroups v2.
|
||||
When this is detect, all functions related to cgroups support in
|
||||
Finit are disabled, *except* the .conf file parser. Hence, you
|
||||
may get parse error if you have invalid cgroup configuration in
|
||||
your Finit .conf files
|
||||
* Fix #197: `initctl status foo` now shows a focused overview of all
|
||||
matching instances; foo:1, foo:2 -- if only one instance matches the
|
||||
command line argument, or if onle one instance exists, the detailed
|
||||
view is shown, as before
|
||||
* Fix #198: a few typos found by Tim Gates
|
||||
* Fix #199: avoid using C++ reserved keywords
|
||||
* Fix #201: memory leak in usr condition plugin, by Ming Liu, Atlas Copco
|
||||
* Fix #203: ensure all filesystems listed in /proc/mounts are properly
|
||||
unumounted on shutdown/reboot, by Robert Andersson, Atlas Copco
|
||||
* Fix #210: resizing terminal (smaller) after boot causes empty lines
|
||||
to be inserted between boot progress
|
||||
* Fix #211: drop hard-coded 32 character limit in getty, now reads
|
||||
`_SC_LOGIN_NAME_MAX` from `sysconf(3)`
|
||||
* Fix #212: service PID file lost after inictl reload, visible from
|
||||
the output from `initctl status foo`
|
||||
|
||||
|
||||
[4.1][] - 2021-06-06
|
||||
--------------------
|
||||
|
||||
Bug fix release. Also disables handlers for `SIGINT` and `SIGPWR`, a
|
||||
new set of `sys` conditions are instead generated which can be used to
|
||||
trigger external programs.
|
||||
|
||||
### Changes
|
||||
* Change behavior on SIGUSR1 to be compatible with sysvinit and systemd.
|
||||
Previously SIGUSR1 caused Finit to halt, like BusyBox init. This had
|
||||
"interesting" side effects on Debian systems when coexisting with
|
||||
sysvinit (upgrading/reinstalling causes scripts to `kill -USR1 1`)
|
||||
* Change how `contrib/debian/install.sh` sets up a Grub boot entry for
|
||||
finit. We now modify the $SUPPORTED_INITS variable in `10_linux`
|
||||
* Disable default kernel ctrl-alt-delete handler and let Finit instead
|
||||
catch `SIGINT` from kernel to be able to perform a proper reboot.
|
||||
There is no default command for this, you need to set up a task that
|
||||
triggers on `<sys/key/ctrlaltdel>` to issue `initctl reboot`
|
||||
* Added keventd to provide `<sys/pwr/ac>` condition to Finit. keventd
|
||||
is currently only responsible for monitoring `/sys/class/power_supply`
|
||||
for changes to active AC mains power online status. Enable keventd
|
||||
with `configure --with-keventd`
|
||||
* For handling power fail events (from UPS and similar) a process may
|
||||
send `SIGPWR` to PID 1. Finit no longer redirects this to `SIGUSR1`
|
||||
(poweroff). There is no default command for this, you need to set up
|
||||
a task that triggers on `<sys/pwr/fail>` to issue `initctl poweroff`
|
||||
* Built-in Finit getty is now a standalone program
|
||||
* Default termios for TTYs now enable `IUTF8` on input
|
||||
* If `/bin/login` is not found, Finit now tries `sulogin` before it
|
||||
falls back to an unauthenticated `/bin/sh`
|
||||
* Dropped (broken) support for multiple consoles. Finit now follows
|
||||
the default console selected by the kernel, `/dev/console`
|
||||
* Dropped signal handlers for SIGSTOP/TSTP and SIGCONT
|
||||
* Added support for `\n`, in addition to `\r`, in "Please press Enter"
|
||||
prompt before starting getty
|
||||
* Finit no longer parses `/proc/cmdline` for its options. Instead all
|
||||
options are by default now read from `argv[]`, like a normal program,
|
||||
this is also what the kernel does by default. Please note, this may
|
||||
not work if your systems boots with an initramfs (ymmv), for such
|
||||
cases, see `configure --enable-kernel-cmdline`
|
||||
* The following plugins are now possible to disable (for containers):
|
||||
`rtc.so`, `urandom.so`, you may also want to disable `hotplug.so`.
|
||||
They are all enabled by default, as in Finit 4.0, but may be moved
|
||||
to external tools or entries in `finit.conf` in Finit 5.0
|
||||
* Added support for reading `PRETTY_NAME` from `/etc/os-release` to use
|
||||
as heading in progress output, unless `--with-heading=GREET` is used.
|
||||
* Added manual pages for finit(8), initctl(8), and finit.conf(5)
|
||||
|
||||
### Fixes
|
||||
* Stricter interface name validation in netlink plugin, modeled after
|
||||
the kernel. Suggested by Coverity Scan
|
||||
* Fix problem of re-registering a service as a task. Previously, if a
|
||||
fundamental change, like type, was made to an active service/run/task
|
||||
it did not take. Only possible workaround was to remove from config
|
||||
* initctl: drop warning when removing a non-existing usr condition
|
||||
* initctl: drop confusing `errno 0` when timing out waiting for reply
|
||||
* Ensure services in plugins and from Finit main belong to a cgroup
|
||||
* Ensure init top-level cgroup remains a leaf group
|
||||
* Fix tty parse error for detecting use of external getty
|
||||
* Fix default `name:` and `:ID` for tty's, e.g. `ttyS0` now gives
|
||||
`tty:S0` as expected. This was default for built-in getty already
|
||||
* Fix max username (32 chars) in bundled Finit getty
|
||||
* The `contrib/*/install.sh` scripts failed to run from tarball
|
||||
* Finit no longer forcibly mounts; `/dev`, `/proc`, or `/sys`, instead
|
||||
it checks first if they are already mounted (devtmpfs or container)
|
||||
* Fix `/etc/fstab` parser to properly check for 'ro' to not remount the
|
||||
root filesystem at boot. The wrong field was read, so a root mounted
|
||||
by an initramfs, or by lxc for a container, had their root remounted
|
||||
* Fix SIGCHLD handler, `waitpd()` may be interrupted by a signal
|
||||
* Reset `starting` flag of services being stopped. When a service
|
||||
is started and then stopped before it has created its pid file,
|
||||
it could be left forever in the stopping state, unless we reset
|
||||
the starting flag.
|
||||
* Fix #170: detect loss of default route when interfaces go down. This
|
||||
emulates the missing kernel netlink message to remove the condition
|
||||
net/default/route to allow stopping dependent services
|
||||
* Fix #171: restore automatic mount of `/dev/shm`, `/dev/pts`, `/run`
|
||||
and `/tmp`, unless mounted already by `/etc/fstab`. This is what most
|
||||
desktop systems expect PID 1 to do. Here we also make sure to mount
|
||||
`/run/lock` as a tmpfs as well, with write perms for regular users,
|
||||
this prevents regular users from filling up `/run` and causing DoS.
|
||||
* Fix #173: netlink plugin runs out of socket buffer space;
|
||||
|
||||
finit[1]: nl_callback():recv(): No buffer space available
|
||||
|
||||
Fixed by adding support for resync with kernel on `ENOBUFS`. See
|
||||
netlink(7) for details. As a spin-off the plugin now supports any
|
||||
number of interfaces and routes on a system. On resync, the following
|
||||
message is now logged, as a warning:
|
||||
|
||||
finit[1]: nl_callback():busy system, resynchronizing with kernel.
|
||||
|
||||
* Fix #174: loss of log messages using combo of prio and facility, e.g.,
|
||||
`logit(LOG_CONSOLE | LOG_NOTICE, ...)`, by Jacques de Laval, Westermo
|
||||
* Fix #175: ensure Finit does not acquire a controlling TTY when checking
|
||||
if a device is a TTY before starting a getty. This fixes an old bug
|
||||
where Ctrl-C after logout from a shell could cause PID 1 to get SIGINT,
|
||||
which in turn could lead to a system reboot
|
||||
|
||||
|
||||
[4.0][] - 2021-04-26
|
||||
--------------------
|
||||
[4.0][UNRELEASED] - 2021-02-21
|
||||
------------------------------
|
||||
|
||||
This release became v4.0, and not v3.2, because of incompatible changes
|
||||
to service conditions. There are other significant changes as well, so
|
||||
make sure to read the whole change log when upgrading.
|
||||
make sure to read the whole changelog when upgrading.
|
||||
|
||||
### Changes
|
||||
* The stand-alone `reboot` tool has been replaced with a symlink to
|
||||
@@ -653,53 +18,31 @@ make sure to read the whole change log when upgrading.
|
||||
with a fallback to sending signals as per traditional SysV init. The
|
||||
`-f` (force) flag remains, where `reboot(2)` is called directly
|
||||
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
||||
* The `inictl cond set|clear COND` have changed completely. Constrained
|
||||
to a flat `<usr/...>` namespace and automatically activated by a new
|
||||
`usr.so` plugin that checks services for usr condition changes
|
||||
* Removed built-in inetd super server. If you need this functionality,
|
||||
use an external inetd, like xinetd, instead. A pull request for a
|
||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||
* Incompatible `configure` script changes, i.e., no guessing `--prefix`
|
||||
and other paths. Also, many options have been changed, renamed, or
|
||||
flipped defaults, or even dropped altogether. There are examples in
|
||||
the documentation and the `contrib/` section
|
||||
* Service conditions change from the non-obvious `<svc/path/to/foo>` to
|
||||
`<pid/foo:id>`. Not only does this give simpler internal semantics,
|
||||
it hopefully also makes it clear that one service's `pid:!foo` pidfile
|
||||
is another service's `<pid/foo>` condition, issue #143
|
||||
* Initial support for cgroups v2:
|
||||
- services runs in a cgroup named after their respective *.conf file
|
||||
- top-level groups are; init, user, and system
|
||||
- all top-level groups can be configured from finit *.conf files
|
||||
- each service can tweak the cgroup settings
|
||||
- Use `initctl [top|ps|cgroup]` commands to inspect runtime state
|
||||
- https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||
* Incompatible `configure` script changes, i.e., you must give proper
|
||||
path arguments to the script, no more guessing just GNU defaults.
|
||||
There are examples in the documentation and the `contrib/` section
|
||||
* Change service conditions from the non-obvious `<svc/path/to/foo>` to
|
||||
`<pid/foo:id>`. This to hopefully make it clear that one service's
|
||||
'pid:!foo' pidfile is another service's `<pid/foo>` condition
|
||||
* Initial support for cgroups, every service now runs in its own cgroup
|
||||
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||
* Major refactor of Finit's `main()` function to be able to start the
|
||||
event loop earlier. This also facilitated factoring out functionality
|
||||
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
||||
various distro packed udevd and other hotplugging tools
|
||||
* A proper rescue mode has been added. It is started extremely early
|
||||
and is protected with a bundled `suslogin`. Exiting rescue mode now
|
||||
brings up the system as a normal boot, as one expects
|
||||
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||
services, stared using `sysv` or `service` stanza
|
||||
* Support for custom `kill:DELAY`, default 3 sec.
|
||||
* Support for custom `halt:SIGNAL`, default SIGTERM
|
||||
* Support for `pre:script` and `post:script`, allows for setup and
|
||||
teardown/cleanup before and after a service runs, issue #129
|
||||
* Support for `env:file` in `/etc/default/foo` or `/etc/conf.d/foo`, see
|
||||
the contrib section for examples that utilize this feature. Variables
|
||||
expanded from env files, and the env files themselves, are tracked for
|
||||
changes to see if a service .conf file is "dirty" and needs restart on
|
||||
`initctl reload`
|
||||
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
||||
useful with new `sysv` or `service` which fork to background
|
||||
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
||||
builds and work around issue with massively parallel builds
|
||||
* Support for `@console` also for external getty
|
||||
* Support for `notty` option to built-in getty, for board bring-up
|
||||
* Support for `rescue` option to built-in getty, for rescue shells
|
||||
* Add support for `@console` also for external getty
|
||||
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||
* Prefer udev to handle `/dev/` if mdev is also available
|
||||
* Redirect dbus daemon output to syslog
|
||||
@@ -719,7 +62,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 enqueuing to userspace
|
||||
the kernel can invalidate deleted events before enqueing 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
|
||||
@@ -749,8 +92,6 @@ make sure to read the whole change log when upgrading.
|
||||
* Always append `:ID` qualifier to conditions if set for a service
|
||||
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
||||
officially only supported for use by the `initctl` tool
|
||||
* The IPC socket now uses `SOCK_SEQPACKET` instead of `SOCK_STREAM`.
|
||||
Recommend using watchdogd v3.4, or later, which support this
|
||||
* Improved support for modern `/etc/network/interfaces`, which has
|
||||
include statements. No more native `ifup` of individual interfaces,
|
||||
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
||||
@@ -768,21 +109,16 @@ make sure to read the whole change log when upgrading.
|
||||
that do not have a watchdog
|
||||
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||
not yet exist (symlink to `/run`). Added compat layer for access
|
||||
* Fix #101: Built-in inetd removed
|
||||
* Fix #102: Start built-in watchdogd as a regular service
|
||||
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||
Fixed by Jonas Johansson, Westermo
|
||||
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||
* Fix #110: automatic modprobe of RTC devices, built-in hwclock
|
||||
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||
fixed by Jacques de Laval, Westermo
|
||||
* Fix #124: Lingering processes in process group when session leader
|
||||
exits. E.g., lingering `logit` processes when parent dies
|
||||
* Fix #127: Show all runparts scripts as they start, like rc.local, fixed
|
||||
by Jacques de Laval, Westermo
|
||||
* Fix service name matching, e.g. for condition handling, may match with
|
||||
wrong service, by Jonas Holmberg, Westermo
|
||||
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||
@@ -801,8 +137,6 @@ make sure to read the whole change log when upgrading.
|
||||
* Provide service description for built-in watchdog daemon
|
||||
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
||||
* Drop the '%m' GNUism, for compat with older musl libc
|
||||
* Fix #139: call `tzset()` on `initctl reload` to activate system
|
||||
timezone changes (for logging)
|
||||
|
||||
|
||||
[3.1][] - 2018-01-23
|
||||
@@ -1041,7 +375,7 @@ Bug fix release.
|
||||
|
||||
* Add support for status/show service by `name:id`
|
||||
* Enforce terse mode after boot, if verbose mode is disabled
|
||||
* Re-enable verbose mode at reboot, if disabled at boot
|
||||
* Reenable verbose mode at reboot, if disabled at boot
|
||||
* Update section mentioning BusyBox getty
|
||||
* Update debugging documentation
|
||||
* Allow debug to override terse mode
|
||||
@@ -1096,7 +430,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 highlight the
|
||||
* The runlevels listed for services in `initctl show` now hightlight the
|
||||
active runlevel.
|
||||
* Clarify in the README and in `initctl help` that the GW event to
|
||||
listen for in service declarations is `GW:UP`
|
||||
@@ -1128,7 +462,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 arguments in `svc_t` for
|
||||
* Fix too small MAX arguments and too few argments in `svc_t` for
|
||||
reading currently running services with `initctl show`
|
||||
* Unblock blocked signals after forking off a child
|
||||
|
||||
@@ -1228,7 +562,7 @@ The inetd release.
|
||||
### Changes
|
||||
* Add support for built-in inetd super server -- launch services on
|
||||
demand. Supports filtering per interface and custom Inet ports.
|
||||
* Upgrade to [libuEv][] v1.1.0 to better handle error conditions.
|
||||
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
|
||||
* Allow mixed case config directives in `finit.conf`
|
||||
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
||||
* Load plugins before parsing `finit.conf`, this makes it possible to
|
||||
@@ -1246,7 +580,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 cause for *yanking* the [1.11] release, below.
|
||||
though. This is the casue 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.
|
||||
@@ -1259,7 +593,7 @@ The inetd release.
|
||||
[1.11][] - 2015-01-24 [YANKED]
|
||||
------------------------------
|
||||
|
||||
The [libuEv][] release.
|
||||
The [libuEv] release.
|
||||
|
||||
**Note:** This release has been *yanked* from distribution due to a
|
||||
regression in launching background processes and TTY's. Fixed in
|
||||
@@ -1342,7 +676,7 @@ Major bug fix release.
|
||||
|
||||
### Changes
|
||||
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
||||
similarly named callbacks. Also, only in debug mode anyway
|
||||
similarily 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
|
||||
@@ -1411,14 +745,14 @@ Major bug fix release.
|
||||
* Makefile fixes for installation, paths encoded wrong
|
||||
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
||||
* Default install is now to `/sbin/finit` and `/usr/`
|
||||
* Note change in `$PLUGIN_DIR` environment variable to `$plugindir`
|
||||
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
|
||||
|
||||
|
||||
[1.2][] - 2012-09-27
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Update README with section on building and environment variables
|
||||
* Update README with section on building and enviroment variables
|
||||
|
||||
### Fixes
|
||||
* Fix installation paths encoded in finit binary
|
||||
@@ -1510,11 +844,7 @@ Major bug fix release.
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.3...HEAD
|
||||
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||
@@ -1546,3 +876,9 @@ Major bug fix release.
|
||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+16
-4
@@ -1,5 +1,5 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = man plugins src system test tmpfiles.d
|
||||
SUBDIRS = plugins src test
|
||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||
|
||||
@@ -30,6 +30,18 @@ release: distcheck
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-watchdog --with-keventd --with-fstab=/etc/fstab
|
||||
run:
|
||||
srcdir=@srcdir@/test \
|
||||
top_builddir=@top_builddir@ \
|
||||
TENV_ROOT=$(tenv_root) \
|
||||
@srcdir@/test/setup-root.sh
|
||||
|
||||
mkdir -p $(dir $(tenv_root)/@FINIT_CONF@)
|
||||
echo 'tty [12345] @console linux noclear nologin' > $(tenv_root)/@FINIT_CONF@
|
||||
|
||||
-TENV_ROOT=$(tenv_root) \
|
||||
TESTENV_PATH=@sbindir@:/bin \
|
||||
FINIT_RCSD=@FINIT_RCSD@ \
|
||||
test/tenv/start.sh finit
|
||||
|
||||
run : tenv_root ?= @abs_top_builddir@/run-rootfs
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
|
||||
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||
|
||||
* [Introduction](#introduction)
|
||||
@@ -22,51 +22,20 @@
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Fast init for Linux systems. Reverse engineered from the [EeePC
|
||||
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
|
||||
with frog DNA …"
|
||||
|
||||

|
||||
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
||||
|
||||
Features include:
|
||||
|
||||
* Runlevels, defined per service
|
||||
* One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
|
||||
* Runparts and `/etc/rc.local` support
|
||||
* Process supervision similar to [systemd][]
|
||||
* Sourcing environment files
|
||||
* Conditions for network/process/custom dependencies
|
||||
* Readiness notification; PID files (native) for synchronizing system
|
||||
startup, support for systemd [sd_notify()][], or [s6 style][] too
|
||||
* Limited support for [tmpfiles.d(5)][] (no aging, attributes, or subvolumes)
|
||||
* Pre/Post script actions
|
||||
* Rudimentary [templating support](doc/config.md#templating)
|
||||
* Tooling to enable/disable services
|
||||
* Built-in getty
|
||||
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
||||
* Built-in support for Debian/BusyBox `/etc/network/interfaces`
|
||||
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||
* Plugin support for customization
|
||||
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||
* Integration with [watchdogd][] for full system supervision
|
||||
* Logging to kernel ring buffer before `syslogd` has started, see the
|
||||
recommended [sysklogd][] project for complete logging integration
|
||||
and how to log to the kernel ring buffer from scripts using `logger`
|
||||
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
||||
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
||||
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
||||
|
||||
Focus is on small and embedded systems, although Finit is fully usable
|
||||
on server and desktop systems as well. For working examples, see the
|
||||
[contrib/](contrib/) section with tutorials for the following Linux
|
||||
distributions:
|
||||
[contrib/](contrib/) section with tutorials for:
|
||||
|
||||
* [Void Linux](contrib/void/),
|
||||
* [Alpine Linux](contrib/alpine/), and
|
||||
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
|
||||
* [Debian GNU/Linux](contrib/debian/)
|
||||
|
||||
> **Note:** support for various Linux distributions does not mean Finit
|
||||
> installs easily on all architectures. The bundled install scripts are
|
||||
> examples for standard installations, tested on amd64 (x86_64) systems.
|
||||
> Custom setups, for embedded systems, can be found in [myLinux][].
|
||||

|
||||
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
||||
|
||||
|
||||
Example
|
||||
@@ -75,35 +44,24 @@ Example
|
||||
This example `/etc/finit.conf` can also be split up in multiple `.conf`
|
||||
files in `/etc/finit.d`. Available, but not yet enabled, services can
|
||||
be placed in `/etc/finit.d/available` and enabled by an operator using
|
||||
the [initctl](#commands--status) tool. See the above mentioned Linux
|
||||
distributions, or [myLinux][].
|
||||
|
||||
> **Note:** as of Finit v4.4, .conf lines can be broken up using the
|
||||
> standard UNIX continuation character (`\`), also trailing comments are
|
||||
> now supported. The latter means you need to escape any hashes used in
|
||||
> directives and descriptions (`\#`). For more on this and examples,
|
||||
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
|
||||
the [initctl](#commands--status) tool.
|
||||
|
||||
```ApacheConf
|
||||
# Fallback if /etc/hostname is missing
|
||||
host default
|
||||
|
||||
# Runlevel to start after bootstrap, 'S', default: 2
|
||||
#runlevel 2
|
||||
|
||||
# Support for setting global environment variables, using foo=bar syntax
|
||||
# be careful though with variables like PATH, SHELL, LOGNAME, etc.
|
||||
#PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
runlevel 2
|
||||
|
||||
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||
log size=100k count=4
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
service [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemon
|
||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemon
|
||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||
service [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab)
|
||||
service [S12345] watchdogd -L -f -- System watchdog daemon
|
||||
service [S12345] syslogd -n -b 3 -D -- System log daemon
|
||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
||||
service [2345] lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
|
||||
|
||||
# The BusyBox ntpd does not use syslog when running in the foreground
|
||||
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||
@@ -118,29 +76,24 @@ service :80 [2345] merecat -n -p 80 /var/www -- Web server
|
||||
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
||||
|
||||
# Alternative method instead of below runparts, can also use /etc/rc.local
|
||||
#sysv [S] /etc/init.d/keyboard-setup -- Setting up preliminary keymap
|
||||
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
|
||||
#task [S] /etc/init.d/kbd -- Preparing console
|
||||
|
||||
# Hidden from boot progress, using empty `--` description
|
||||
#sysv [S] /etc/init.d/keyboard-setup --
|
||||
#sysv [S] /etc/init.d/acpid --
|
||||
#task [S] /etc/init.d/kbd --
|
||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
#task [S] /etc/init.d/kbd start -- Preparing console
|
||||
|
||||
# Run start scripts from this directory
|
||||
# runparts /etc/start.d
|
||||
|
||||
# Virtual consoles run BusyBox getty, keep kernel default speed
|
||||
tty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait noclear
|
||||
tty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait noclear
|
||||
tty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear
|
||||
tty [12345] /sbin/getty -L 0 /dev/tty1 linux
|
||||
tty [12345] /sbin/getty -L 0 /dev/tty2 linux
|
||||
tty [12345] /sbin/getty -L 0 /dev/tty3 linux
|
||||
|
||||
# Use built-in getty for serial port and USB serial
|
||||
#tty [12345] /dev/ttyAMA0 noclear nowait
|
||||
#tty [12345] /dev/ttyUSB0 noclear
|
||||
tty [12345] /dev/ttyAMA0 noclear nowait
|
||||
tty [12345] /dev/ttyUSB0 noclear
|
||||
|
||||
# Just give me a shell, I need to debug this embedded system!
|
||||
#tty [12345] console noclear nologin
|
||||
tty [12345] @console noclear nologin
|
||||
```
|
||||
|
||||
The `service` stanza, as well as `task`, `run` and others are described
|
||||
@@ -149,10 +102,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
|
||||
@@ -164,13 +117,13 @@ Some components are optional: runlevel(s), condition(s) and description,
|
||||
making it easy to create simple start scripts and still possible for more
|
||||
advanced uses as well:
|
||||
|
||||
service /usr/sbin/sshd -D
|
||||
service sshd -D
|
||||
|
||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||
the most common conditions is to wait for basic networking to become
|
||||
available:
|
||||
|
||||
service <net/route/default> nginx -- High performance HTTP server
|
||||
service <net/route/default> nginx -- High performace HTTP server
|
||||
|
||||
Here is another example where we instruct Finit to not start BusyBox
|
||||
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
||||
@@ -245,50 +198,13 @@ networking here. The configured `runlevel NUM` from `/etc/finit.conf`
|
||||
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
||||
given on the kernel cmdline, in which case runlevel 1 is started.
|
||||
|
||||
All services in runlevel S) are started first, followed by the desired
|
||||
All services in runlevel S(0) are started first, followed by the desired
|
||||
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
||||
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
||||
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
||||
`intictl` tool.
|
||||
|
||||
|
||||
**Conditions**
|
||||
|
||||
As mentioned previously, Finit has an advanced dependency system to
|
||||
handle synchronization, called [conditions](doc/conditions.md). It can
|
||||
be used in many ways; depend on another service, network availability,
|
||||
etc.
|
||||
|
||||
One *really cool* example useful for embedded systems is to run certain
|
||||
scripts if a board has a certain feature encoded in its device tree. At
|
||||
bootstrap we run the following `ident` script:
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
conddir=/var/run/finit/cond/hw/model
|
||||
dtmodel=/sys/firmware/devicetree/base/model
|
||||
|
||||
if ! test -e $dtmodel; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
model=$(cat $dtmodel | tr "[A-Z] " "[a-z]-")
|
||||
mkdir -p $conddir && ln -s ../../reconf $conddir/$model
|
||||
```
|
||||
|
||||
Provided the device tree node exists, and is a string, we can then use
|
||||
the condition `<hw/model/foo>` when starting other scripts. Here is an
|
||||
example:
|
||||
|
||||
```
|
||||
run [S] /path/to/ident --
|
||||
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
|
||||
```
|
||||
|
||||
> Notice the trick with an empty description to hide the call to `ident`
|
||||
> in the Finit progress output.
|
||||
|
||||
|
||||
**Plugins**
|
||||
|
||||
Plugins can *extend* the functionality of Finit and *hook into* the
|
||||
@@ -316,11 +232,8 @@ For more information, see [doc/plugins.md](doc/plugins.md).
|
||||
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
||||
registering any changes to `.conf` files. To activate a change the user
|
||||
must call `initctl reload`, which reloads all modified files, stops any
|
||||
removed services, starts new ones, and restarts any modified ones. If the
|
||||
command line arguments of a service have changed, the process will be
|
||||
terminated and then started again with the updated arguments. If the arguments
|
||||
have not been modified and the process supports SIGHUP, the process will
|
||||
receive a SIGHUP rather than being terminated and started.
|
||||
removed services, starts new ones, and restarts any modified ones, with
|
||||
SIGHUP if the process supports it.
|
||||
|
||||
For some use-cases the extra step of calling `initctl reload` creates an
|
||||
unnecessary overhead, which can be removed at build-time using:
|
||||
@@ -328,50 +241,6 @@ unnecessary overhead, which can be removed at build-time using:
|
||||
configure --enable-auto-reload
|
||||
|
||||
|
||||
**Cgroups**
|
||||
|
||||
Finit supports cgroups v2 and comes with the following default groups in
|
||||
which services and user sessions are placed in:
|
||||
|
||||
/sys/fs/cgroup
|
||||
|-- init/ # cpu.weight:100
|
||||
|-- system/ # cpu.weight:9800
|
||||
`-- user/ # cpu.weight:100
|
||||
|
||||
Finit itself and its helper scripts and services are placed in the
|
||||
top-level leaf-node group `init/`, which also is _reserved_.
|
||||
|
||||
All run/task/service/sysv processes are placed in their own sub-group
|
||||
in `system/`. The name of each sub-group is taken from the respective
|
||||
`.conf` file from `/etc/finit.d`.
|
||||
|
||||
All getty/tty processes are placed in their own sub-group in `user/`.
|
||||
The name of each sub-group is taken from the username.
|
||||
|
||||
A fourth group also exists, the `root` group. It is also _reserved_ and
|
||||
primarily intended for RT tasks. If you have RT tasks they need to be
|
||||
declared as such in their service stanza like this:
|
||||
|
||||
service [...] <...> cgroup.root /path/to/foo args -- description
|
||||
|
||||
or
|
||||
|
||||
cgroup.root
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
|
||||
See [doc/config.md](doc/config.md#cgroups) for more information, e.g.,
|
||||
how to configure per-group limits.
|
||||
|
||||
The `initctl` tool has three commands to help debug and optimize the
|
||||
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
||||
commands for details.
|
||||
|
||||
> **Note:** systems that do not support cgroups, specifically version 2,
|
||||
> are automatically detected. On such systems the above functionality
|
||||
> is disabled early at boot.
|
||||
|
||||
|
||||
Runparts & /etc/rc.local
|
||||
------------------------
|
||||
|
||||
@@ -395,33 +264,6 @@ in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
||||
in [doc/bootstrap.md](doc/bootstrap.md).
|
||||
|
||||
|
||||
### Limitations
|
||||
|
||||
It is not possible to call Finit via signals or use `initctl` in any
|
||||
runparts or `/etc/rc.local` script. This because Finit is single
|
||||
threaded and is calling these scripts in a blocking fashion at the end
|
||||
of runlevel S, at which point the event loop has not yet been started.
|
||||
|
||||
The event loop is the whole thing which Finit is built around, except
|
||||
for runlevel S, which remains a slow procession through a lot of set up,
|
||||
with a few hooks and blocking call outs to external scripts.
|
||||
|
||||
However, not all `initctl` commands are prohibited, supported commands:
|
||||
are:
|
||||
|
||||
- `inictl cond`: only operate of files in `/run/finit/cond`
|
||||
- `initctl enable/disable`: enabled run/task/service is activated on
|
||||
the runlevel change from S to 2
|
||||
- `initctl touch/show/create/delete/list`: `create`, provided the
|
||||
non-interactive mode is used, again changes take effect in the
|
||||
runlevel change directly after bootstrap
|
||||
- `initctl -f reboot/poweroff/halt`: provided the `-f` flag is used to
|
||||
force direct kernel commands
|
||||
|
||||
**Example:** you can set a `usr/` condition in `/etc/rc.local` and have
|
||||
a service/task in runlevel 2 depend on it to execute.
|
||||
|
||||
|
||||
Runlevels
|
||||
---------
|
||||
|
||||
@@ -506,67 +348,40 @@ Finit also implements a modern API to query status, and start/stop
|
||||
services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
||||
not return until the given command has fully completed.
|
||||
|
||||
```
|
||||
```shell
|
||||
~ $ initctl -h
|
||||
Usage: initctl [OPTIONS] [COMMAND]
|
||||
|
||||
Options:
|
||||
-b, --batch Batch mode, no screen size probing
|
||||
-c, --create Create missing paths (and files) as needed
|
||||
-f, --force Ignore missing files and arguments, never prompt
|
||||
-h, --help This help text
|
||||
-j, --json JSON output in 'status' and 'cond' commands
|
||||
-1, --once Only one lap in commands like 'top'
|
||||
-p, --plain Use plain table headings, no ctrl chars
|
||||
-q, --quiet Silent, only return status of command
|
||||
-t, --no-heading Skip table headings
|
||||
-v, --verbose Verbose output
|
||||
-V, --version Show program version
|
||||
-h, --help This help text
|
||||
|
||||
Commands:
|
||||
debug Toggle Finit (daemon) debug
|
||||
help This help text
|
||||
version Show program version
|
||||
|
||||
ls | list List all .conf in /etc/finit.d
|
||||
create <CONF> Create .conf in /etc/finit.d/available
|
||||
delete <CONF> Delete .conf in /etc/finit.d/available
|
||||
show <CONF> Show .conf in /etc/finit.d/available
|
||||
edit <CONF> Edit .conf in /etc/finit.d/available
|
||||
touch <CONF> Change .conf in /etc/finit.d/available
|
||||
enable <CONF> Enable .conf in /etc/finit.d/available
|
||||
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||
|
||||
cond set <COND> Set (assert) user-defined conditions +usr/COND
|
||||
cond get <COND> Get status of user-defined condition, see $? and -v
|
||||
cond clear <COND> Clear (deassert) user-defined conditions -usr/COND
|
||||
cond status Show condition status, default cond command
|
||||
cond dump [TYPE] Dump all, or a type of, conditions and their status
|
||||
|
||||
version Show Finit version
|
||||
|
||||
list List all .conf in /etc/finit.d/
|
||||
enable <CONF> Enable .conf in /etc/finit.d/available/
|
||||
disable <CONF> Disable .conf in /etc/finit.d/[enabled/]
|
||||
touch <CONF> Mark .conf in /etc/finit.d/ for reload
|
||||
reload Reload *.conf in /etc/finit.d/ (activates changes)
|
||||
|
||||
cond show Show condition status
|
||||
cond dump Dump all conditions and their status
|
||||
|
||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||
start <NAME>[:ID] Start service by name, with optional ID
|
||||
stop <NAME>[:ID] Stop/Pause a running service by name
|
||||
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)
|
||||
This allows restart of run/tasks that have already run
|
||||
Note: Finit .conf file(s) are *not* reloaded!
|
||||
restart <NAME>[:ID] Restart (stop/start) service by name
|
||||
signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID
|
||||
ident [NAME] Show matching identities for NAME, or all
|
||||
status <NAME>[:ID] Show service status, by name
|
||||
status Show status of services, default command
|
||||
|
||||
cgroup List cgroup config overview
|
||||
ps List processes based on cgroups
|
||||
top Show top-like listing based on cgroups
|
||||
|
||||
plugins List installed plugins
|
||||
|
||||
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
|
||||
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
||||
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||
status <JOB|NAME>[:ID] Show service status, by job# or name
|
||||
status | show Show status of services, default command
|
||||
|
||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||
reboot Reboot system
|
||||
halt Halt system
|
||||
poweroff Halt and power off system
|
||||
suspend Suspend system
|
||||
|
||||
|
||||
utmp show Raw dump of UTMP/WTMP db
|
||||
```
|
||||
|
||||
@@ -575,73 +390,22 @@ file must be used to tell Finit to stop and start it on `reload` and
|
||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||
these will also affect how a service is maintained.
|
||||
|
||||
> **Note:** even though it is possible to start services not belonging in
|
||||
> the current runlevel these services will not be respawned automatically
|
||||
> by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||
> Dropbear SSH service will not be restarted if it is killed or exits.
|
||||
**Note:** even though it is possible to start services not belonging in
|
||||
the current runlevel these services will not be respawned automatically
|
||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||
Dropbear SSH service will not be restarted if it is killed or exits.
|
||||
|
||||
The `status` command is the default, it displays a quick overview of all
|
||||
monitored run/task/services. Here we call `initctl -p`, suitable for
|
||||
scripting and documentation:
|
||||
|
||||
```
|
||||
alpine:~# initctl -p
|
||||
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
||||
======================================================================
|
||||
1506 acpid running [---2345----] ACPI daemon
|
||||
1509 crond running [---2345----] Cron daemon
|
||||
1489 dropbear running [---2345----] Dropbear SSH daemon
|
||||
1511 klogd running [S-12345----] Kernel log daemon
|
||||
1512 ntpd running [---2345----] NTP daemon
|
||||
1473 syslogd running [S-12345----] Syslog daemon
|
||||
|
||||
alpine:~# initctl -pv
|
||||
PID IDENT STATUS RUNLEVELS COMMAND
|
||||
======================================================================
|
||||
1506 acpid running [---2345----] acpid -f
|
||||
1509 crond running [---2345----] crond -f -S $CRON_OPTS
|
||||
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
|
||||
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
|
||||
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
|
||||
1473 syslogd running [S-12345----] syslogd -n
|
||||
```
|
||||
|
||||
The environment variables to each of the services above are read from,
|
||||
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
|
||||
have other directories, e.g., Debian use `/etc/default/`.
|
||||
|
||||
The `status` command takes an optional `NAME:ID` argument. Here we
|
||||
check the status of `dropbear`, which only has one instance in this
|
||||
system:
|
||||
|
||||
```
|
||||
alpine:~# initctl -p status dropbear
|
||||
Status : running
|
||||
Identity : dropbear
|
||||
Description : Dropbear SSH daemon
|
||||
Origin : /etc/finit.d/enabled/dropbear.conf
|
||||
Environment : -/etc/conf.d/dropbear
|
||||
Condition(s):
|
||||
Command : dropbear -R -F $DROPBEAR_OPTS
|
||||
PID file : !/run/dropbear.pid
|
||||
PID : 1485
|
||||
User : root
|
||||
Group : root
|
||||
Uptime : 2 hour 46 min 56 sec
|
||||
Runlevels : [---2345----]
|
||||
Memory : 1.2M
|
||||
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
||||
|- 1485 dropbear -R -F
|
||||
|- 2634 dropbear -R -F
|
||||
|- 2635 ash
|
||||
`- 2652 initctl -p status dropbear
|
||||
|
||||
Apr 8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgrounding
|
||||
Apr 8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834
|
||||
Apr 8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834
|
||||
Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect received
|
||||
Apr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576
|
||||
Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
|
||||
```shell
|
||||
~ $ initctl status -v
|
||||
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
||||
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
|
||||
3 running 478 [S12345] /sbin/klogd -n
|
||||
4:1 inetd 0 [2345] internal time allow *:37,!eth0
|
||||
4:2 inetd 0 [2345] internal time allow eth0:3737
|
||||
5:1 inetd 0 [2345] /sbin/telnetd allow *:23 deny eth0,eth1
|
||||
5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
|
||||
6:1 inetd 0 [345] /sbin/dropbear allow eth0:222
|
||||
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
||||
```
|
||||
|
||||
|
||||
@@ -679,41 +443,36 @@ 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][6].
|
||||
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][].
|
||||
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]: 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
|
||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||
[2]: http://cr.yp.to/daemontools.html
|
||||
[3]: http://smarden.org/runit/
|
||||
[4]: http://en.wikipedia.org/wiki/Init
|
||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
||||
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||
[9]: https://github.com/troglobit/troglos
|
||||
[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]: 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/
|
||||
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
[s6 style]: https://skarnet.org/software/s6/notifywhenup.html
|
||||
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||
[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
|
||||
[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]: https://troglobit.com
|
||||
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
|
||||
[Joachim Wiberg]: http://troglobit.com
|
||||
[GitHub]: https://github.com/troglobit/finit
|
||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||
[myLinux]: https://github.com/troglobit/myLinux/
|
||||
[watchdogd]: https://github.com/troglobit/watchdogd/
|
||||
[sysklogd]: https://github.com/troglobit/sysklogd/
|
||||
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
||||
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
||||
[Travis]: https://travis-ci.org/troglobit/finit
|
||||
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||
|
||||
+57
-149
@@ -1,23 +1,20 @@
|
||||
AC_INIT([Finit],[4.4],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
||||
AC_INIT(Finit, 4.0-rc1, 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])
|
||||
|
||||
AC_CONFIG_SRCDIR([src/finit.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
contrib/Makefile
|
||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||
doc/Makefile
|
||||
man/Makefile
|
||||
plugins/Makefile
|
||||
src/Makefile
|
||||
system/Makefile
|
||||
tmpfiles.d/Makefile
|
||||
test/test.env test/Makefile
|
||||
test/lib/Makefile test/src/Makefile])
|
||||
test/test.env
|
||||
test/Makefile])
|
||||
|
||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||
#m4_include([m4/plugin.m4])
|
||||
@@ -34,8 +31,9 @@ AC_PROG_INSTALL
|
||||
AC_PROG_MKDIR_P
|
||||
|
||||
# Configuration.
|
||||
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
|
||||
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fstaby.h termios.h])
|
||||
AC_CHECK_FUNCS([strstr getopt getfsenty])
|
||||
|
||||
# Check for uint[8,16,32]_t
|
||||
AC_TYPE_UINT8_T
|
||||
@@ -50,25 +48,30 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
||||
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
||||
|
||||
# Check for configured Finit features
|
||||
AC_ARG_ENABLE(emergency_shell,
|
||||
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
||||
Use only for debugging very early boot problems with Finit]),,[
|
||||
enable_emergency_shell=no])
|
||||
|
||||
AC_ARG_ENABLE(fallback_shell,
|
||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
||||
enable_fallback_shell=no])
|
||||
|
||||
AC_ARG_ENABLE(auto_reload,
|
||||
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||
enable_auto_reload=no])
|
||||
|
||||
AC_ARG_ENABLE(kernel_cmdline,
|
||||
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[
|
||||
enable_kernel_cmdline=no])
|
||||
|
||||
AC_ARG_ENABLE(fastboot,
|
||||
AS_HELP_STRING([--enable-fastboot], [Skip fsck check on filesystems listed in /etc/fstab]),,[
|
||||
enable_fastboot=no])
|
||||
|
||||
AC_ARG_ENABLE(fsckfix,
|
||||
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
|
||||
enable_fsckfix=no])
|
||||
AC_ARG_ENABLE(watchdog,
|
||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
||||
enable_watchdog=no])
|
||||
|
||||
AC_ARG_ENABLE(redirect,
|
||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||
enable_redirect=yes])
|
||||
AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
|
||||
enable_redirect_output=no])
|
||||
|
||||
AC_ARG_ENABLE(logit,
|
||||
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
||||
enable_logit=yes])
|
||||
|
||||
AC_ARG_ENABLE(logrotate,
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||
@@ -83,30 +86,18 @@ AC_ARG_ENABLE(contrib,
|
||||
enable_contrib=yes])
|
||||
|
||||
# Check for extra plugins to enable
|
||||
AC_ARG_ENABLE(all_plugins,
|
||||
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
|
||||
enable_all_plugins=$enableval, enable_all_plugins=auto)
|
||||
enable_all_plugins=auto
|
||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
AC_ARG_WITH(fstab,
|
||||
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
|
||||
[fstab=$withval], [fstab=yes])
|
||||
|
||||
AC_ARG_WITH(heading,
|
||||
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
|
||||
AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
|
||||
[heading=$withval], [heading=yes])
|
||||
|
||||
AC_ARG_WITH(config,
|
||||
@@ -125,75 +116,44 @@ 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])
|
||||
|
||||
AC_ARG_WITH(runlevel,
|
||||
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap [1-9], default: 2]),
|
||||
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
|
||||
[runlevel=$withval], [runlevel=yes])
|
||||
|
||||
AC_ARG_WITH(random-seed,
|
||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||
[random_seed=$withval], [random_seed=yes])
|
||||
|
||||
AC_ARG_WITH(keventd,
|
||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||
|
||||
AC_ARG_WITH(sulogin,
|
||||
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no])
|
||||
|
||||
AC_ARG_WITH(watchdog,
|
||||
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||
|
||||
AC_ARG_WITH(hook-scripts-path,
|
||||
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
||||
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
||||
|
||||
AC_ARG_WITH(plugin-path,
|
||||
AS_HELP_STRING([--with-plugin-path=DIR], [Search path for external plugins, default /usr/lib/finit/plugins:/usr/local/lib/finit/plugins]),
|
||||
[plugin_path=$withval], [plugin_path=yes])
|
||||
|
||||
AC_ARG_WITH(rtc-date,
|
||||
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM", default "2000-01-01 00:00"]),
|
||||
[rtc_date=$withval], [rtc_date=no])
|
||||
|
||||
### Enable features ###########################################################################
|
||||
|
||||
# Create config.h from selected features and fallback defaults
|
||||
# Create config.h from selected features and fallback defautls
|
||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
||||
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
|
||||
|
||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
||||
|
||||
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||
|
||||
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
||||
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
||||
|
||||
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||
|
||||
AS_IF([test "x$enable_fsckfix" = "xyes"], [
|
||||
AC_DEFINE(FSCK_FIX, 1, [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab])])
|
||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
||||
|
||||
AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||
|
||||
### Disable features ###########################################################################
|
||||
AS_IF([test "x$enable_logit" != "xno"], [
|
||||
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
||||
|
||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$with_fstab" != "xno"], [
|
||||
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
|
||||
AC_EXPAND_DIR(fstab_path, "$fstab")
|
||||
AC_DEFINE_UNQUOTED(FINIT_FSTAB, "$fstab_path", [Built-in default: /etc/fstab])],[
|
||||
AC_DEFINE_UNQUOTED(FINIT_FSTAB, NULL, [No built-in default fstab])])
|
||||
|
||||
AS_IF([test "x$with_config" != "xno"], [
|
||||
AS_IF([test "x$conf" = "xyes"], [
|
||||
conf=$sysconfdir/finit.conf])])
|
||||
@@ -221,13 +181,9 @@ AS_IF([test "x$with_sysconfig" != "xno"], [
|
||||
[System environment, default /etc/default & /etc/conf.d])])])
|
||||
|
||||
AS_IF([test "x$with_heading" != "xno"], [
|
||||
AS_IF([test "x$heading" = "xyes"], [heading=""])
|
||||
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$heading" = "xyes"], [
|
||||
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
|
||||
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
|
||||
|
||||
AS_IF([test "x$with_hostname" != "xno"], [
|
||||
AS_IF([test "x$hostname" = "xyes"], [
|
||||
@@ -246,73 +202,30 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
AC_EXPAND_DIR(random_path, "$random_seed")
|
||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
||||
|
||||
AS_IF([test "x$rtc_date" != "xno"], [
|
||||
AC_DEFINE(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
|
||||
rtc_date=""])
|
||||
|
||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
||||
|
||||
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
AS_IF([test "x$watchdog" = "xyes"], [
|
||||
watchdog=/dev/watchdog])
|
||||
with_watchdog=yes
|
||||
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||
watchdog=])
|
||||
|
||||
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
|
||||
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
||||
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
||||
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
|
||||
|
||||
AS_IF([test "x$with_plugin_path" != "xno"], [
|
||||
AS_IF([test "x$plugin_path" = "xyes"], [plugin_path=/usr/lib/finit/plugins:/usr/local/lib/finit/plugins])
|
||||
AC_EXPAND_DIR(plugin_path, "$plugin_path")
|
||||
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
||||
|
||||
# Override default libdir, used for plugins and rescue.conf
|
||||
pkglibdir=$libdir/finit
|
||||
AC_SUBST(pkglibexecdir)
|
||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||
AC_DEFINE_UNQUOTED(FINIT_LIBPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||
|
||||
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
||||
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
|
||||
AC_SUBST(plugin_path)
|
||||
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
||||
|
||||
AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d")
|
||||
AC_SUBST(tmpfiles_path)
|
||||
AC_DEFINE_UNQUOTED(TMPFILES_PATH, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc])
|
||||
|
||||
AC_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d")
|
||||
AC_SUBST(finit_tmpfiles)
|
||||
AC_DEFINE_UNQUOTED(FINIT_TMPFILES, "$finit_tmpfiles", [Finit tmpfiles.d/ .conf path])
|
||||
|
||||
AC_EXPAND_DIR(system_path, "$pkglibdir/system")
|
||||
AC_SUBST(system_path)
|
||||
AC_DEFINE_UNQUOTED(FINIT_SYSPATH, "$system_path", [Static services, previously generated at runtime by plugins])
|
||||
|
||||
AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf")
|
||||
AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
|
||||
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf")
|
||||
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||
|
||||
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||
|
||||
RTC_DATE=$rtc_date
|
||||
AS_IF([test "$rtc_date" = ""], [RTC_DATE="<DEFAULT>"])
|
||||
AS_IF([test "$rtc_date" = "no"], [RTC_DATE="<DEFAULT>"])
|
||||
AC_EXPAND_DIR(path_stdpath, "$sbindir:$bindir:/usr/sbin:/usr/bin:/sbin:/bin")
|
||||
AC_DEFINE_UNQUOTED(_PATH_STDPATH, "$path_stdpath", [Default PATH])
|
||||
|
||||
# Generate all files
|
||||
AC_OUTPUT
|
||||
@@ -322,10 +235,9 @@ cat <<EOF
|
||||
------------------ Summary ------------------
|
||||
$PACKAGE_NAME version $PACKAGE_VERSION
|
||||
Prefix................: $prefix
|
||||
Exec prefix...........: $eprefix
|
||||
Exec prefix...........: `eval echo $exec_prefix`
|
||||
Sysconfdir............: `eval echo $sysconfdir`
|
||||
Localstatedir.........: `eval echo $localstatedir`
|
||||
Default fstab.........: `eval echo $fstab`
|
||||
Finit config file.....: $conf_path
|
||||
Finit config.d path...: $rcsd_path
|
||||
Finit plugin path.....: $plugin_path
|
||||
@@ -338,20 +250,16 @@ cat <<EOF
|
||||
Behavior:
|
||||
Boot heading..........: $heading
|
||||
Plugins...............: $plugins
|
||||
RTC restore date......: $RTC_DATE
|
||||
|
||||
Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in sulogin......: $with_sulogin
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in watchdogd....: $enable_watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Skip fsck check.......: $enable_fastboot
|
||||
Run fsck fix mode.....: $enable_fsckfix
|
||||
Redirect output.......: $enable_redirect
|
||||
Scripting tool logit..: $enable_logit
|
||||
Emergency shell.......: $enable_emergency_shell
|
||||
Fallback shell........: $enable_fallback_shell
|
||||
Default hostname......: $hostname
|
||||
Default group.........: $group
|
||||
Default runlevel......: $runlevel
|
||||
|
||||
------------- Compiler version --------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SUBDIRS = finit.d
|
||||
docsdir := @docdir@/contrib/alpine
|
||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||
docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
3.6.2
|
||||
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--with-keventd --with-sulogin
|
||||
--enable-alsa-utils-plugin --enable-watchdog \
|
||||
--with-heading="Alpine Linux 3.13"
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
@@ -35,3 +35,4 @@ fi
|
||||
echo
|
||||
echo "*** Done"
|
||||
echo
|
||||
|
||||
|
||||
@@ -5,22 +5,6 @@
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
docsdir := @docdir@/contrib/alpine/finit.d/available
|
||||
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
||||
lxdm.conf modules.conf ntpd.conf syslog.conf watchdog.conf
|
||||
lxdm.conf modules.conf ntpd.conf klogd.conf syslog.conf \
|
||||
watchdog.conf
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Consoles to start getty on when system is up
|
||||
tty [12345] /dev/ttyS0 noclear
|
||||
tty [12345] /dev/tty1 noclear nowait
|
||||
tty [2345] /dev/tty2 noclear nowait
|
||||
tty [2345] /dev/tty3 noclear nowait
|
||||
tty [12345] /dev/tty1 noclear nowait
|
||||
tty [2345] /dev/tty2 noclear nowait
|
||||
tty [2345] /dev/tty3 noclear nowait
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Start klogd as soon as possible, after syslogd, should always run
|
||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||
@@ -4,4 +4,3 @@
|
||||
#module evdev
|
||||
#module mousedev
|
||||
#module 8139cp
|
||||
module softdog
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
# Start syslogd as soon as possible, should always run
|
||||
# Start klogd as soon as possible, but after syslogd
|
||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
|
||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
|
||||
|
||||
@@ -8,10 +8,9 @@ if [ "x`id -u`" != "x0" ]; then
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
grep -q alpine Makefile 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ -e alpine-release ]; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
elif [ ! -e autogen.sh ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
#
|
||||
# Each line is run in sequence.
|
||||
#
|
||||
# NOTE: Remember to set the executable bit!
|
||||
# NOTE: Remeber to set the executable bit!
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = finit.d
|
||||
SUBDIRS = finit.d grub.d
|
||||
docsdir := @docdir@/contrib/debian
|
||||
docs_DATA = README.md finit.conf build.sh install.sh
|
||||
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -20,42 +20,29 @@ tools pre-systemd work as intended.
|
||||
|
||||
root@debian:~# apt install initscripts console-setup
|
||||
|
||||
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
|
||||
> the main section of Debian. So just install the -dev packages :)
|
||||
|
||||
The following script can then be used to configure, build, install and
|
||||
set up your system to run Finit:
|
||||
|
||||
user@debian:~/finit$ contrib/debian/build.sh
|
||||
|
||||
However, since `/sbin/init` already exists on your system, the script
|
||||
creates another entry in your GRUB config by updating `$SUPPORTED_INITS`
|
||||
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find
|
||||
a (finit) entry in the "Advanced options for Debian GNU/Linux" section.
|
||||
It is of course also possible to change the default init to Finit:
|
||||
creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
|
||||
where `init=/sbin/finit` is added to your kernel line. It is of course
|
||||
also possible to change the default init to Finit, if you do you can
|
||||
remove the custom Grub entry:
|
||||
|
||||
user@debian:~/finit# cd /sbin
|
||||
user@debian:/sbin# sudo mv init oldinit
|
||||
user@debian:/sbin# sudo rm init
|
||||
user@debian:/sbin# sudo ln -s finit init
|
||||
|
||||
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
||||
`/etc/finit.d/*.conf` files. The build + install script above provides
|
||||
a few sample `.conf` files. See `initctl ls` after boot for a list of
|
||||
enabled and available services, you can then use `enable` and `disable`
|
||||
comands to `initctl`, followed by `reload` to activate your changes.
|
||||
a few sample `.conf` files. See `initctl list` after boot for a list of
|
||||
enabled and available services.
|
||||
|
||||
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
||||
and initialization like keyboard language etc.
|
||||
|
||||
> **NOTE:** X Window system, you may need to `sudo apt install elogind`
|
||||
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
||||
> is enabled by default), and logout/login again. The elogind daemon
|
||||
> ensures a regular non-root user can start and interact with an X
|
||||
> session, otherwise keyboard and mouse won't work. When you're happy,
|
||||
> you can enable the lightdm.conf, change the default runlevel to 3, and
|
||||
> presto! you have a desktop again.
|
||||
|
||||
|
||||
Have fun!
|
||||
/Joachim ツ
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ echo
|
||||
--prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-keventd \
|
||||
--with-random-seed=/var/lib/urandom/random-seed
|
||||
--enable-alsa-utils-plugin \
|
||||
--with-random-seed=/var/lib/urandom/random-seed \
|
||||
--with-heading="Debian GNU/Linux"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo
|
||||
@@ -59,3 +60,6 @@ else
|
||||
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
||||
echo
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,22 +5,6 @@
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
SUBDIRS = available
|
||||
docsdir := @docdir@/contrib/debian/finit.d
|
||||
d_LINKS = acpid.conf apparmor.conf avahi-daemon.conf \
|
||||
bluetooth.conf console-setup.conf elogind.conf \
|
||||
getty.conf keyboard-setup.conf modules.conf \
|
||||
plymouth-quit.conf rsyslogd.conf sshd.conf
|
||||
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
||||
modules.conf rsyslogd.conf sshd.conf
|
||||
|
||||
install-exec-hook:
|
||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
|
||||
console-setup.conf elogind.conf getty.conf \
|
||||
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||
plymouth-quit.conf rsyslogd.conf sshd.conf syslogd.conf \
|
||||
xdm.conf
|
||||
docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \
|
||||
lightdm.conf modules.conf rsyslogd.conf sntpd.conf \
|
||||
sshd.conf syslogd.conf xdm.conf
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
|
||||
@@ -1,2 +0,0 @@
|
||||
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
|
||||
@@ -1,3 +0,0 @@
|
||||
# To ignore errors like "org.freedesktop.hostname1", update the env file with
|
||||
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
|
||||
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
|
||||
@@ -1 +0,0 @@
|
||||
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
|
||||
@@ -1,4 +0,0 @@
|
||||
# On some systems, bootstrap can be really quick and cause elogind
|
||||
# to not start before a user has managed to log in. To prevent
|
||||
# this, add <pid/elogind> as condition to your TTYs in getty.conf
|
||||
service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
|
||||
@@ -1,7 +1,4 @@
|
||||
# Consoles to start getty on when system is up
|
||||
tty [12345] /dev/tty1 linux noclear nowait
|
||||
tty [2345] /dev/tty2 linux nowait
|
||||
tty [2345] /dev/tty3 linux nowait
|
||||
tty [2345] /dev/tty4 linux nowait
|
||||
tty [2345] /dev/tty5 linux nowait
|
||||
tty [2345] /dev/tty6 linux nowait
|
||||
tty [2345] /dev/tty2 linux noclear nowait
|
||||
tty [2345] /dev/tty3 linux noclear nowait
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# Need to stop plymouth, or it'll block stdin on tty1
|
||||
task [S] /usr/bin/plymouth quit -- Stopping Plymouth Boot Screen
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
exec tail -n +3 $0
|
||||
# This file provides an easy way to add custom menu entries. Simply type the
|
||||
# menu entries you want to add after this comment. Be careful not to change
|
||||
# the 'exec tail' line above.
|
||||
|
||||
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
|
||||
insmod gzio
|
||||
insmod part_msdos
|
||||
insmod ext2
|
||||
search --no-floppy --fs-uuid --set=root $BOOT
|
||||
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
|
||||
initrd /initrd.img
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
docsdir := @docdir@/contrib/debian/grub.d
|
||||
docs_DATA = 40_custom
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
@@ -8,10 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
grep -q debian Makefile 2>/dev/null
|
||||
grep -q Debian os-release 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
elif [ ! -e autogen.sh ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
|
||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||
echo "/etc/finit.conf - Finit configuration file"
|
||||
echo "/etc/finit.d/ - Finit services"
|
||||
echo "/etc/grub.d/10_linux - Add Finit to Grub's SUPPORTED_INITS"
|
||||
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
|
||||
echo
|
||||
read -p "Do you want to continue (y/N)? " yorn
|
||||
echo
|
||||
@@ -38,18 +38,12 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
cp -va finit.d /etc/
|
||||
|
||||
echo "*** Setting up a GRUB boot entry ..."
|
||||
fn=/etc/grub.d/10_linux
|
||||
if [ -e $fn ]; then
|
||||
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then
|
||||
echo "Already installed, done."
|
||||
else
|
||||
echo "Adding Finit to list of SUPPORTED_INITS ..."
|
||||
sed -i 's/SUPPORTED_INITS="[^"]*/& finit:\/sbin\/finit/' $fn
|
||||
update-grub
|
||||
fi
|
||||
else
|
||||
echo "Cannot find $fn, you'll have to set up your bootloader on your own."
|
||||
fi
|
||||
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
|
||||
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
|
||||
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
||||
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
||||
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
|
||||
update-grub
|
||||
|
||||
echo
|
||||
echo "*** Done"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
||||
NAME="Debian GNU/Linux"
|
||||
VERSION_ID="8"
|
||||
VERSION="8 (jessie)"
|
||||
ID=debian
|
||||
HOME_URL="http://www.debian.org/"
|
||||
SUPPORT_URL="http://www.debian.org/support"
|
||||
BUG_REPORT_URL="https://bugs.debian.org/"
|
||||
+2
-37
@@ -8,18 +8,6 @@ module evdev
|
||||
module loop
|
||||
module psmouse
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
cgroup init cpu.weight:100
|
||||
cgroup user cpu.weight:100
|
||||
cgroup system cpu.weight:9700 cpu.max:50000
|
||||
|
||||
# Example extra cgroup
|
||||
cgroup maint cpu.weight:100
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'
|
||||
runlevel 2
|
||||
|
||||
@@ -28,21 +16,13 @@ network service networking start
|
||||
|
||||
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||
log size:100k count:4
|
||||
log size=100k count=4
|
||||
|
||||
# Virtual consoles to start getty on
|
||||
tty /dev/tty1
|
||||
tty /dev/tty2
|
||||
tty /dev/tty3
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
# Alternative method instead of runparts
|
||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
@@ -50,24 +30,9 @@ task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
#run [2] /etc/init.d/networking start -- Start networking
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
|
||||
# klgod and syslogd are placed in the maint cgroup
|
||||
cgroup.maint
|
||||
service [2345] <pid/syslogd> klogd -n -- Kernel logging server
|
||||
service [2345] syslogd -n -- Syslog server
|
||||
|
||||
# gdm in the system cgroup (default when read from it's own .conf file)
|
||||
cgroup.system
|
||||
service [3] cgroup:cpu.weight:250,mem.max:10M gdm -- GNOME Display Manager
|
||||
|
||||
# Start SSH daemon with opts from /etc/default/ssh (if available), move
|
||||
# to user cgroup with cpu.weight:250. Default for services is system
|
||||
# group. Default weight in user group is 100 (above). Max length of
|
||||
# cgroup argument is (currently) 63 chars.
|
||||
#
|
||||
# Notice alternative syntax where current cgroup is only set for this
|
||||
# particular service.
|
||||
service [2345] cgroup.user:cpu.weight:250,mem.max:10M env:-/etc/default/ssh /usr/sbin/sshd -D $SSHD_OPTS -- OpenSSH daemon
|
||||
service [3] gdm -- GNOME Display Manager
|
||||
|
||||
# The BusyBox ntpd does not use syslog when running in the foreground
|
||||
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
In Finit issue #196 we were reminded [1] of a missing inotify flag in
|
||||
Linux older kernels, IN_MASK_CREATE. Finit makes use of this internally
|
||||
for monitoring PID conditions, and more. This is a central mechanism to
|
||||
synchronize services at boot and reload at runtime.
|
||||
|
||||
The following patch for Linux 4.9.0, was provided by Andy Savage for
|
||||
other people that may want to run Finit on slightly older kernels.
|
||||
|
||||
[1]: https://github.com/troglobit/finit/issues/196
|
||||
|
||||
Index: fs/notify/inotify/inotify_user.c
|
||||
===================================================================
|
||||
--- fs.orig/notify/inotify/inotify_user.c
|
||||
+++ fs/notify/inotify/inotify_user.c
|
||||
@@ -522,6 +522,7 @@ static int inotify_update_existing_watch
|
||||
__u32 old_mask, new_mask;
|
||||
__u32 mask;
|
||||
int add = (arg & IN_MASK_ADD);
|
||||
+ int create = (arg & IN_MASK_CREATE);
|
||||
int ret;
|
||||
|
||||
mask = inotify_arg_to_mask(arg);
|
||||
@@ -529,6 +530,8 @@ static int inotify_update_existing_watch
|
||||
fsn_mark = fsnotify_find_inode_mark(group, inode);
|
||||
if (!fsn_mark)
|
||||
return -ENOENT;
|
||||
+ else if (create)
|
||||
+ return -EEXIST;
|
||||
|
||||
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
|
||||
|
||||
@@ -726,6 +729,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int,
|
||||
if (unlikely(!f.file))
|
||||
return -EBADF;
|
||||
|
||||
+ /* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
|
||||
+ if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
/* verify that this is indeed an inotify instance */
|
||||
if (unlikely(f.file->f_op != &inotify_fops)) {
|
||||
ret = -EINVAL;
|
||||
@@ -814,7 +821,7 @@ static int __init inotify_user_setup(voi
|
||||
BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
|
||||
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
|
||||
|
||||
- BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
|
||||
+ BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
|
||||
|
||||
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
|
||||
|
||||
Index: include/linux/inotify.h
|
||||
===================================================================
|
||||
--- include.orig/linux/inotify.h
|
||||
+++ include/linux/inotify.h
|
||||
@@ -17,6 +17,6 @@ extern struct ctl_table inotify_table[];
|
||||
IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
|
||||
IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
|
||||
IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
|
||||
- IN_ISDIR | IN_ONESHOT)
|
||||
+ IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
|
||||
|
||||
#endif /* _LINUX_INOTIFY_H */
|
||||
Index: include/uapi/linux/inotify.h
|
||||
===================================================================
|
||||
--- include.orig/uapi/linux/inotify.h
|
||||
+++ include/uapi/linux/inotify.h
|
||||
@@ -52,6 +52,7 @@ struct inotify_event {
|
||||
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
|
||||
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
|
||||
#define IN_EXCL_UNLINK 0x04000000 /* exclude events on unlinked objects */
|
||||
+#define IN_MASK_CREATE 0x10000000 /* only create watches */
|
||||
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
|
||||
#define IN_ISDIR 0x40000000 /* event occurred against dir */
|
||||
#define IN_ONESHOT 0x80000000 /* only send event once */
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = finit.d
|
||||
docsdir := @docdir@/contrib/void
|
||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--with-keventd --with-sulogin
|
||||
--enable-alsa-utils-plugin --enable-watchdog \
|
||||
--with-heading="Void Linux"
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
@@ -35,3 +35,4 @@ fi
|
||||
echo
|
||||
echo "*** Done"
|
||||
echo
|
||||
|
||||
|
||||
@@ -5,22 +5,5 @@
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
docsdir := @docdir@/contrib/void/finit.d/available
|
||||
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
|
||||
keymap.conf lxdm.conf modules.conf ntpd.conf \
|
||||
sshd.conf syslog.conf uuidd.conf
|
||||
keymap.conf klogd.conf lxdm.conf modules.conf ntpd.conf \
|
||||
sshd.conf syslogd.conf uuidd.conf
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Start klogd as soon as possible, should always run
|
||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
||||
@@ -4,4 +4,3 @@
|
||||
#module evdev
|
||||
#module mousedev
|
||||
#module 8139cp
|
||||
module softdog
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Start syslogd as soon as possible, should always run
|
||||
# Start klogd as soon as possible, but after syslogd
|
||||
service [S12345] syslogd -n -- Syslog daemon
|
||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
||||
@@ -0,0 +1,2 @@
|
||||
# Start syslogd as soon as possible, should always run
|
||||
service [S12345] syslogd -n -- Syslog daemon
|
||||
@@ -8,10 +8,9 @@ if [ "x`id -u`" != "x0" ]; then
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
grep -q void Makefile 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ -e xbps ]; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
elif [ ! -e autogen.sh ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
#
|
||||
# Each line is run in sequence.
|
||||
#
|
||||
# NOTE: Remember to set the executable bit!
|
||||
# NOTE: Remeber to set the executable bit!
|
||||
|
||||
+6
-18
@@ -19,31 +19,19 @@ Some of these are also registered in the issue tracker on GitHub.
|
||||
* Add new (complimentary) .svc file format to slowly migrate away
|
||||
from the very terse one-liner format currently used
|
||||
* Allow running as non-pid1 => read .conf and RCSD form cmdline
|
||||
* When a process dies, and Finit does not restart it, we should collect
|
||||
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
|
||||
`initctl status <process>` is called to debug the issue.
|
||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||
|
||||
As of Finit v4.1 SIGPWR generates <sys/power/fail> condition and it
|
||||
is up to a task to check why and take appropriate action.
|
||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||
|
||||
As of Finit v4.1 SIGINT generates <sys/key/ctrlaltdel>, but there is
|
||||
no check if the signal actually originates from the kernel. To get
|
||||
this verification, a new libuEv release is needed. As of June 6 -21
|
||||
that functionality is not yet released.
|
||||
|
||||
|
||||
Initctl
|
||||
-------
|
||||
|
||||
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
||||
|
||||
shutdown -h 03:35 "foobar was here"
|
||||
|
||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||
`pimd` man pages ...
|
||||
* Add support for timed shutdown in Finit, including cancelled shutdown
|
||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||
`initctl show --json`
|
||||
* Add support for `-s` to redirect all output to syslog, for scripting
|
||||
|
||||
|
||||
Init
|
||||
|
||||
+14
-17
@@ -1,8 +1,6 @@
|
||||
Bootstrap
|
||||
=========
|
||||
|
||||
0. Get bearings, disable kernel logs, initialize TTY and print banner,
|
||||
unless `HOOK_BANNER` is defined, then call that instead
|
||||
1. Prepare emergency shell, if enabled
|
||||
2. Set up initial signal handlers
|
||||
3. Set up default $PATH early
|
||||
@@ -11,16 +9,12 @@ Bootstrap
|
||||
6. Load all `.so` plugins
|
||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||
9. Parse `/etc/finit.conf`
|
||||
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||
means any WDT that requires a kernel module need to be either
|
||||
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
||||
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
||||
10. Start built-in watchdog, if enabled
|
||||
11. Set hostname
|
||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
||||
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
||||
of error, `HOOK_MOUNT_POST` is called
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
||||
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
|
||||
@@ -40,15 +34,18 @@ Bootstrap
|
||||
24. Call 4th level hooks, `HOOK_SVC_UP`
|
||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||
27. Start all configured TTYs
|
||||
27. Start all configured TTYs, or a fallback shell on `/dev/console`
|
||||
|
||||
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
||||
`/etc/finit.d/*.conf` are started.
|
||||
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.
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
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,
|
||||
|
||||
+20
-43
@@ -27,10 +27,10 @@ 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 required versions:
|
||||
version of the above mentioned libraries. Currently requried versions:
|
||||
|
||||
- libite v2.2.0, or later
|
||||
- libuEv v2.2.0, or later
|
||||
- libite v2.2.0
|
||||
- libuEv v2.2.0
|
||||
|
||||
|
||||
Configure
|
||||
@@ -53,10 +53,6 @@ Below are a few of the main switches to configure:
|
||||
built-ins (.o files) and all external libraries, except the C library
|
||||
will be linked statically.
|
||||
|
||||
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||
init for container apps that can see the host's `/proc` filesystem
|
||||
|
||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||
|
||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||
@@ -65,19 +61,8 @@ Below are a few of the main switches to configure:
|
||||
|
||||
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
||||
|
||||
* `--with-sulogin`: Enable bundled `sulogin` program. Default is to use the
|
||||
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
|
||||
login if the `root` user is disabled or has no password at all.
|
||||
|
||||
For more configure flags, see <kbd>./configure --help</kbd>
|
||||
|
||||
> **Note:** the configure script is not available in the GIT sources. It is
|
||||
> however included in (officially supported) released tarballs. The
|
||||
> idea is that you should not need GNU autotools to build, only the
|
||||
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
||||
> Any contributing to Finit can generate it from `configure.ac` using
|
||||
> the `autogen.sh` script.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
@@ -85,16 +70,16 @@ Example
|
||||
First, unpack the archive:
|
||||
|
||||
```shell
|
||||
$ tar xf finit-4.3.tar.gz
|
||||
$ cd finit-4.3/
|
||||
$ tar xf finit-3.0.tar.xz
|
||||
$ cd finit-3.0/
|
||||
```
|
||||
|
||||
Then configure, build and install:
|
||||
|
||||
```shell
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-keventd --with-watchdog
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-heading="Alpine Linux 3.13" --with-hostname=alpine
|
||||
$ make
|
||||
.
|
||||
.
|
||||
@@ -102,13 +87,13 @@ $ make
|
||||
$ DESTDIR=/tmp/finit make install
|
||||
```
|
||||
|
||||
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
||||
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
|
||||
user's home directory, configured, built and installed to a temporary
|
||||
staging directory. The environment variable `DESTDIR` controls the
|
||||
destination directory when installing, very useful for building binary
|
||||
standalone packages.
|
||||
|
||||
Finit 4.1 and later can detect if it runs on an embedded system, or a
|
||||
Finit 3.0 and later can detect if it runs on an embedded system, or a
|
||||
system that use BusyBox tools instead of udev & C:o. On such systems
|
||||
`mdev` instead of `udev` is used. However, remember to also change the
|
||||
Linux config to:
|
||||
@@ -157,40 +142,32 @@ enabled. The default Finit rescue mode configuration is installed into
|
||||
|
||||
By default the a root shell, without login, is started.
|
||||
|
||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||
> force `reboot`, `shutdown`, or `poweroff`.
|
||||
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Edit, or append to, the kernel command line: remove `quiet` to enable
|
||||
kernel messages and add `finit.debug` to enable Finit debug messages.
|
||||
kernel messages and add `debug` to enable Finit debug messages.
|
||||
|
||||
```shell
|
||||
append="init=/sbin/finit -- finit.debug"
|
||||
append="init=/sbin/finit debug"
|
||||
```
|
||||
|
||||
Notice the `--` separator.
|
||||
|
||||
To debug startup issues, in particular issues with getty/login, add
|
||||
the following to your Finit .conf file:
|
||||
|
||||
tty [12345789] notty noclear
|
||||
|
||||
The `notty` option ensures reusing the stdin/stdout set up by the
|
||||
kernel. Remember, this is only for debugging and would leave your
|
||||
production system potentially wide open.
|
||||
To debug startup issues, in particular issues with getty/login, try
|
||||
`configure --enable-fallback-shell`. When no TTYs are detected, and
|
||||
Finit is configured with this option, Finit will try to start a bare
|
||||
`/bin/sh` on the boot console. Remember, this is only for debugging
|
||||
and would leave your production system potentially wide open.
|
||||
|
||||
There is also a rescue shell available, in case Finit crashes and the
|
||||
kernel usually reboots: `configure --enable-emergency-shell`. However,
|
||||
the behavior of Finit is severely limited when this is enabled, so use
|
||||
it only for debugging start up issues when Finit crashes.
|
||||
|
||||
**NOTE:** Neither of these options should be enabled on production
|
||||
systems since they can potentially give a user root access.
|
||||
**NOTE:** Neither of these two configure options should be enabled on
|
||||
production systems since they can potentially give a user root access.
|
||||
|
||||
|
||||
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
+10
-70
@@ -6,57 +6,15 @@ passed on the Linux kernel command line. Not limited to Finit.
|
||||
|
||||
The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
|
||||
> **NOTE:** remember to use `--` to separate kernel parameters from
|
||||
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||
|
||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||
|
||||
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
|
||||
multiple conditions can be set using the same option, separated with a
|
||||
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
|
||||
result in a `<boot/arg>` condition being set to control the rest of the
|
||||
system bootstrap.
|
||||
|
||||
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||
firmware upgrade, or rescue mode.
|
||||
|
||||
> Note: `<boot/...>` conditions cannot be cleared with `initctl`!
|
||||
|
||||
* `finit.config=/path/to/alternative/finit.conf`: override the
|
||||
compile-time bootstrap config file, default:
|
||||
|
||||
./configure --with-config=/etc/finit.conf
|
||||
|
||||
Useful when starting up in various rescue mode, factory, or
|
||||
production test setups. Use the top-level configuration file
|
||||
directive `rcsd /path/to/finit.d` to override the default
|
||||
rcS.d directory.
|
||||
console until Finit starts up.
|
||||
|
||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||
independently of the kernel `debug` setting. New as of Finit v4.
|
||||
independently of the kernel debug setting. New as of Finit v4.
|
||||
|
||||
* `finit.fstab=</path/to/etc/fstab.alternative>`: Tell Finit to use an
|
||||
alternate `fstab` to mount the file system from. Remember, this file
|
||||
must be on the `root=...` file system provided to Finit from the
|
||||
kernel. By default the built-in fstab is used, which itself defaults
|
||||
to `/etc/fstab`, but can be changed at build time with:
|
||||
|
||||
./configure --with-fstab=/path/to/fstab
|
||||
|
||||
It is even possible to disable a built-in default using:
|
||||
|
||||
./configure --without-fstab
|
||||
|
||||
Making `finit.fstab=/path/to/fstab` a *mandatory* command line option.
|
||||
Note, if the command line fstab is missing, Finit falls back to the
|
||||
built-in fstab, and if both are missing, the system treats this as a
|
||||
bad `fsck` and thus calls `sulogin`. If, in turn, `sulogin` is not
|
||||
available on the system, Finit calls reboot, which is also what will
|
||||
happen when a user exits from `sulogin`.
|
||||
|
||||
* `finit.status[=bool]`: Control finit boot progress, including banner.
|
||||
(Used to be `finit.show_status`, which works but is deprecated.)
|
||||
* `finit.show_status[=bool]`: Control finit boot progress, including
|
||||
banner.
|
||||
|
||||
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
||||
when enabled.
|
||||
@@ -66,41 +24,23 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
signals and has no job control. Recommend using, and modifying,
|
||||
`rescue` mode instead.
|
||||
|
||||
* `loglevel=<0-7>`, sets the kernel's log level, which is more granular
|
||||
than `debug`. Also, when `loglevel=7`, Finit will *not disable*
|
||||
kernel logs to the console. This is very useful when debugging the
|
||||
kernel at system bring-up. Since `loglevel=7` is the same as `debug`
|
||||
this means you have to use `quiet` for a quiet boot, until sysklogd
|
||||
takes over logging of kernel events.
|
||||
|
||||
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
||||
panic. This setting will cause a kernel reboot after SEC seconds.
|
||||
|
||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||
errors. Also, see `loglevel` and `quiet` above.
|
||||
errors.
|
||||
|
||||
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||
you will be given a root login to a maintenance shell. However, if
|
||||
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
||||
the system booted in a limited fallback mode. See [config.md][]
|
||||
for more information.
|
||||
|
||||
**Note:** in this mode `initctl` will not work. Correct the problem
|
||||
and use `reboot -f` to force reboot.
|
||||
* `rescue`: Start Finit rescue mode; no network, no `fsck` of file
|
||||
systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The
|
||||
configuration is read from `/lib/finit/rescue.conf`, and can be
|
||||
modified by the operator.
|
||||
|
||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
||||
debug problems with the regular runlevel. All services and TTYs in
|
||||
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
||||
presents you with a root console without login.
|
||||
|
||||
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
|
||||
and `rescue`, giving a single number on the kernel command line tells
|
||||
Finit to ignore any `runlevel` in `/etc/finit.conf` as well as the
|
||||
configure fallback `--with-runlevel=N` setting. Remember, `6` is the
|
||||
reboot runlevel and is not permitted. Any other values are ignored.
|
||||
For more on kernel boot 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
|
||||
|
||||
+13
-75
@@ -13,9 +13,9 @@ Finit Conditions
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Conditions are a relatively new addition to Finit, introduced in v3,
|
||||
with the intention of providing a mechanism for common synchronization
|
||||
problems. For example:
|
||||
Conditions are a new addition to Finit, introduced in v3, with the
|
||||
intention of providing a mechanism for common synchronization problems.
|
||||
For example:
|
||||
|
||||
- *"wait for service A to start before starting service B"*, or
|
||||
- *"wait for basic network access to be available"*
|
||||
@@ -35,7 +35,7 @@ service to run.
|
||||
In this example the Network monitor daemon `netd` is not started until
|
||||
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
||||
`pid/` condition is satisfied by the corresponding service's PID file
|
||||
being created, i.e., the service's default readiness notification.
|
||||
being created.
|
||||
|
||||
**NOTE:** Conditions also stop services when a condition is no longer
|
||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
||||
@@ -45,36 +45,7 @@ being created, i.e., the service's default readiness notification.
|
||||
Triggering
|
||||
----------
|
||||
|
||||
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
||||
|
||||
- `netlink.so`: provides `<net/...>`
|
||||
- `pidfile.so`: provides `<pid/...>`
|
||||
- Cmdline `finit.cond=arg`: provides `<boot/arg>`
|
||||
|
||||
See below for built-in conditions. Finit also supports user-defined
|
||||
conditions, sometimes referred to as static or one-shot conditions.
|
||||
They live in the `<usr/...>` namespace and are constrained to a flat
|
||||
hierarchy without any sub-directories, unlike the pidfile plugin, for
|
||||
instance.
|
||||
|
||||
User-defined conditions are controlled using the `initctl cond set` and
|
||||
`initctl cond clear` commands:
|
||||
|
||||
initctl cond set foo
|
||||
initctl cond clear foo
|
||||
|
||||
The purpose of user-defined conditions is to be able to start or stop
|
||||
services, or run/task jobs, on external site-dependent stimuli.
|
||||
Example:
|
||||
|
||||
service [2345] <usr/foo> alarm --arg foo -- Foo alarm
|
||||
|
||||
For convenience, prefixing with `usr/` is allowed, but any other slashes
|
||||
or period characters are disallowed. E.g., to trigger the `Foo alarm`,
|
||||
the same as above, can also be achieved like this:
|
||||
|
||||
initctl cond set usr/foo
|
||||
initctl cond clear usr/foo
|
||||
Conditions can only be triggered by built-in plugins.
|
||||
|
||||
Conditions retain their current state until the next reconfiguration or
|
||||
runlevel change. At that point all set conditions transition into the
|
||||
@@ -86,41 +57,16 @@ unchanged) state of it.
|
||||
> **Note:** For `pid/` conditions it is expected that services "touch"
|
||||
> or recreate their PID file on `SIGHUP`.
|
||||
|
||||
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||
|
||||
|
||||
Built-in Conditions
|
||||
-------------------
|
||||
|
||||
Finit comes with a set of plugins for conditions:
|
||||
|
||||
- `devmon` (built-in)
|
||||
- `netlink`
|
||||
- `pidfile`
|
||||
- `sys`
|
||||
- `usr`
|
||||
|
||||
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device
|
||||
nodes being created and removed. It is active only when a run, task, or
|
||||
service has declared a `<dev/foo>` or `<dev/dir/bar>` condition.
|
||||
|
||||
The `pidfile` plugin (recursively) watches `/run/` (recursively) for PID
|
||||
files created by the monitored services, and sets a corresponding
|
||||
condition in the `pid/` namespace.
|
||||
|
||||
Similarly, the `netlink` plugin provides basic conditions for when an
|
||||
interface is brought up/down and when a default route (gateway) is set,
|
||||
in the `net/` namespace.
|
||||
|
||||
The `sys` and `usr` plugins monitor are passive condition monitors where
|
||||
the action is provided by `keventd`, signal handlers, and in the case of
|
||||
`usr`, the end-user via the `initctl` tool.
|
||||
|
||||
Additionally, the various states of a run/task/sysv/service can also be
|
||||
used as conditions, the image above shows the state names. The syntax
|
||||
for a `service` type process: `<service/foo/STATE>`. The other types,
|
||||
in particular run/task/sysv, there are the additional states `success`
|
||||
and `failure`.
|
||||
Finit comes with a `pidfile` and `netlink` plugin. When enabled, the
|
||||
`pidfile` plugin watches `/var/run/` (recursively) for PID files created
|
||||
by the monitored services, and sets a corresponding condition in the
|
||||
`pid/` namespace. Similarily, the `netlink` plugin provides basic
|
||||
conditions for when an interface is brought up/down and when a default
|
||||
route (gateway) is set, in the `net/` namespace.
|
||||
|
||||
With the example listed above, finit does not start the `/sbin/netd`
|
||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||
@@ -139,14 +85,6 @@ Built-in conditions:
|
||||
- `net/<IFNAME>/exist`
|
||||
- `net/<IFNAME>/up`
|
||||
- `net/<IFNAME>/running`
|
||||
- `service/<NAME[:ID]>/<STATE>`
|
||||
- `{run, task, sysv}/<NAME[:ID]>/{<STATE>, success, failure}`
|
||||
- `sys/pwr/ac`
|
||||
- `sys/pwr/fail`
|
||||
- `sys/key/ctrlaltdel`
|
||||
- `usr/foo`
|
||||
- `boot/arg`
|
||||
- `dev/node` and `dev/dir/node`
|
||||
|
||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||
@@ -192,7 +130,7 @@ Debugging
|
||||
If a service is not being started as it should, the problem might be
|
||||
that one of its conditions is not in the expected state. Use the
|
||||
command `initctl status` to inspect service status. Services in the
|
||||
`waiting` state are pending a condition.
|
||||
`ready` state are pending a condition.
|
||||
|
||||
In that situation, running `initctl cond show` reveals which of the
|
||||
conditions that are not satisfied. Listed as `off` below.
|
||||
@@ -209,7 +147,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 satisfied.
|
||||
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
|
||||
As indicated by the `-`-prefix.
|
||||
|
||||
To fake interface `vlan1` suddenly appearing, and test what happens to
|
||||
|
||||
+71
-735
@@ -1,21 +1,12 @@
|
||||
Finit Configuration
|
||||
===================
|
||||
Configuration
|
||||
=============
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Configuration Files](#configuration-files)
|
||||
* [Runlevels](#runlevels)
|
||||
* [Managing Services](#managing-services)
|
||||
* [Environment Variables](#environment-variables)
|
||||
* [Service Environment](#service-environment)
|
||||
* [Service Synchronization](#service-synchronization)
|
||||
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
||||
* [Templating](#templating)
|
||||
* [Cgroups](#cgroups)
|
||||
* [Configuration File Syntax](#configuration-file-syntax)
|
||||
* [Hostname](#hostname)
|
||||
* [Kernel Modules](#kernel-modules)
|
||||
* [Networking](#networking)
|
||||
* [Alternate rcS.d/](#alternate-rcs-d-)
|
||||
* [Resource Limits](#resource-limits)
|
||||
* [Runlevels](#runlevels)
|
||||
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
|
||||
@@ -28,170 +19,42 @@ Finit Configuration
|
||||
* [TTYs and Consoles](#ttys-and-consoles)
|
||||
* [Non-privileged Services](#non-privileged-services)
|
||||
* [Redirecting Output](#redirecting-output)
|
||||
* [Rescue Mode](#rescue-mode)
|
||||
* [Limitations](#limitations)
|
||||
* [/etc/finit.conf](#etcfinitconf)
|
||||
* [/etc/finit.d](#etcfinitd)
|
||||
* [Watchdog](#watchdog)
|
||||
* [keventd](#keventd)
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Finit is a process starter and service monitor designed to run as PID 1
|
||||
on Linux. It consists of [plugins](plugins.md) and configuration files.
|
||||
Plugins start at [hook points](plugins.md#hooks) and can run various set
|
||||
up, or install event handlers that later provide runtime services, e.g.,
|
||||
PID file monitoring, or [conditions](conditions.md).
|
||||
Finit can be configured using only the original `/etc/finit.conf` file
|
||||
or in combination with `/etc/finit.d/*.conf`. Useful for package-based
|
||||
Linux distributions -- each package can provide its own "script" file.
|
||||
|
||||
- `/etc/finit.conf`: main configuration file
|
||||
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
||||
|
||||
### Configuration Files
|
||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
||||
and some directives are only available at bootstrap, runlevel `S`, see
|
||||
the section [Limitations](#limitations) below for details.
|
||||
|
||||
Originally Finit was configured using a single file, `/etc/finit.conf`.
|
||||
Although still possible, today we recommended using the Apache-style
|
||||
`available/*.conf` and `enabled/*.conf` layaout. These are called
|
||||
dynamic services, in contrast to static -- the only difference being
|
||||
where they are installed and if the `initctl` tool can manage them.
|
||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
||||
call `finit q`, but that has been deprecated with the `initctl` tool).
|
||||
Finit monitors all known active `.conf` files, so if you want to force
|
||||
a restart of any service you can simply touch its corresponding `.conf`
|
||||
file in `/etc/finit.d` and call `initctl reload`. Finit handle any
|
||||
and all conditions and dependencies between services automatically.
|
||||
|
||||
/etc/
|
||||
|- finit.d/
|
||||
| |- available/
|
||||
| | `- my-service.conf
|
||||
: |- enabled/
|
||||
: | `- my-service.conf -> ../available/my-service.conf
|
||||
: :
|
||||
: |- static-service.conf
|
||||
: `- another-static.conf # eg. bootstrap run/task commands
|
||||
:
|
||||
`- finit.conf # global settings
|
||||
|
||||
At bootstrap, and `initctl reload`, all .conf files are read, starting
|
||||
with `finit.conf`, then, in alphabetical order, all `finit.d/*.conf`
|
||||
files, and finally (still in alphabetical order) all `enabled/*.conf`
|
||||
files.
|
||||
|
||||
> **Note:** the `finit.conf` and `finit.d/` names are only defaults.
|
||||
> They can be changed at compile-time with two `configure` options:
|
||||
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
|
||||
>
|
||||
> They can also be overridden from the [kernel command line](cmdline.md)
|
||||
> using: `-- finit.config=/etc/bar.conf` and in that file use the
|
||||
> top-level configuration directive `rcsd /path/to/finit.d`.
|
||||
|
||||
|
||||
### Filesystem Layout
|
||||
|
||||
Finit is most comfortable with a traditional style Linux filesystem
|
||||
layout, as specified in the [FHS][]:
|
||||
|
||||
/.
|
||||
|- bin/
|
||||
|- dev/ # Mounted automatically if devtmpfs is available
|
||||
| |- pts/ # Mounted automatically by Finit if it exists
|
||||
| `- shm/ # Mounted automatically by Finit if it exists
|
||||
|- etc/
|
||||
| |- finit.d/
|
||||
| | |- available/
|
||||
| | `- enabled/
|
||||
| `- finit.conf
|
||||
|- home/
|
||||
|- lib/
|
||||
|- libexec/
|
||||
|- mnt/
|
||||
|- proc/ # Mounted automatically by Finit if it exists
|
||||
|- root/
|
||||
|- run/ # Mounted automatically by Finit if it exists
|
||||
| `- lock/ # Created automatically if Finit mounts /run
|
||||
|- sbin/
|
||||
|- sys/ # Mounted automatically by Finit if it exists
|
||||
|- tmp/ # Mounted automatically by Finit if it exists
|
||||
|- usr/
|
||||
`- var/
|
||||
|- cache/
|
||||
|- db/
|
||||
|- lib/
|
||||
| `- misc/
|
||||
|- lock/
|
||||
|- log/
|
||||
|- run -> ../run
|
||||
|- spool/
|
||||
`- tmp/
|
||||
|
||||
Finit starts (very early) by mounting `/dev`, `/proc/`, and `/sys`,
|
||||
unless they (i.e., `/dev`) are already mounted. When all plugins and
|
||||
other, core Finit functions, have been set up, all relevant filesystems
|
||||
(`PASS > 0`) are checked and mounted from the selected `fstab`, either
|
||||
the default `/etc/fstab`, or any custom one selected from the command
|
||||
line, or at build time.
|
||||
|
||||
Any file system not listed `fstab` are automatically mounted by Finit,
|
||||
as listed above, provided their respective mount point exists.
|
||||
|
||||
With all filesystems mounted, Finit calls `swapon`.
|
||||
|
||||
At shutdown, and after having stopped all services and other lingering
|
||||
processes killed, filesystems are unmounted in the reverse order, and
|
||||
`swapoff` is called.
|
||||
|
||||
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
|
||||
|
||||
### Runlevels
|
||||
|
||||
- ` S`: bootStrap
|
||||
- ` 1`: Single user mode
|
||||
- `2-5`: traditional multi-user mode
|
||||
- ` 6`: reboot
|
||||
- `7-9`: multi-user mode (extra)
|
||||
- ` 0`: shutdown
|
||||
|
||||
Runlevels are declared per service/run/task/sysv command. Starting in
|
||||
runlevel S ([bootStrap](bootstrap.md)), usually only for tasks supposed
|
||||
to run once at boot, and services like `syslogd`, which you need to
|
||||
start and run throughout the whole time your system is up. Before `S`
|
||||
is started, however, Finit performs a lot of housekeeping tasks like
|
||||
mounting all filesystems, calling `fsck` if needed, and making sure the
|
||||
everything is OK.
|
||||
|
||||
task [S] /lib/console-setup/console-setup.sh
|
||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||
|
||||
After runlevel S, Finit proceeds to runlevel 2. (This can be changed in
|
||||
`/etc/finit.conf` using the `runlevel N` directive.) Before starting
|
||||
the services in runlevel 2, Finit first stops everything that is not
|
||||
allowed to run in 2, and then brings up networking. Networking is
|
||||
expected to be available in all runlevels except: S, 1 (single user
|
||||
level), 6, and 0. Networking is enabled either by the `network script`
|
||||
directive, or if you have an `/etc/network/interfaces` file, Finit calls
|
||||
`ifup -a` -- at the very least the loopback interface is brought up.
|
||||
|
||||
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
||||
> were constrained to runlevel S only are dropped from bookkeeping. So
|
||||
> when reaching the prompt, `initctl` will not show these run/tasks.
|
||||
> This is a safety mechanism to prevent bootstrap-only tasks from
|
||||
> accidentally being run again. E.g., `console-setup.sh` above.
|
||||
|
||||
|
||||
### Managing Services
|
||||
|
||||
Using `initctl disable my-service` the symlink (above) is removed and
|
||||
the service is queued for removal. Several changes can be made to the
|
||||
system, but it is not until `initctl reload` is called that the changes
|
||||
are activated.
|
||||
|
||||
To add a new static service, drop a `.conf` file in `/etc/finit.d/` and
|
||||
run `initctl reload`. (It is also possible to `SIGHUP` PID 1, or call
|
||||
`finit q`, but that has been deprecated with the `initctl` tool). Finit
|
||||
monitors all known active `.conf` files, so if you want to force a
|
||||
restart of any service you can touch its corresponding `.conf` file in
|
||||
`/etc/finit.d` and call `initctl reload`. Finit handles all conditions
|
||||
and dependencies between services automatically, see below section on
|
||||
[Service Synchronization](#service-synchronization) for more details.
|
||||
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
|
||||
and use `initctl enable` to enable a service `.conf` file. This may be
|
||||
useful in particular to Linux distributions that may want to install all
|
||||
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 satisfied, the service is stopped.
|
||||
longer satisifed, 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
|
||||
@@ -200,37 +63,9 @@ On `initctl reload` the following is checked for all services:
|
||||
For more info on the different states of a service, see the separate
|
||||
document [Finit Services](service.md).
|
||||
|
||||
|
||||
### Environment Variables
|
||||
|
||||
In Finit v4.3 support for setting environment variables in `finit.conf`,
|
||||
and any `*.conf`, was added. It is worth noting that these are global
|
||||
and *shared with all* services -- the only way to have service-local
|
||||
environment is detailed in the next section.
|
||||
|
||||
The syntax for global environment variables is straight forward. In
|
||||
Finit v4.4 the `set` keyword was added for completeness, but the old
|
||||
syntax (without the `set ` prefix) is still honored:
|
||||
|
||||
set foo=bar
|
||||
set baz="qux"
|
||||
|
||||
On reload of .conf files, all tracked environment variables are cleared
|
||||
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
|
||||
file, it will no longer be used by Finit or any new (!) started
|
||||
run/tasks or services. The environment of already started processes can
|
||||
not be changed.
|
||||
|
||||
The only variables reset to sane defaults on .conf reload are:
|
||||
|
||||
PATH=_PATH_STDPATH
|
||||
SHELL=_PATH_BSHELL
|
||||
LOGNAME=root
|
||||
USER=root
|
||||
|
||||
It is entirely possible to override these as well from the .conf files,
|
||||
but be careful. Changing SHELL changes the behavior of `system()` and a
|
||||
lot of other commands as well.
|
||||
> When running <kbd>make install</kbd> no default `/etc/finit.conf` is
|
||||
> installed since system requirements differ too much. There are some
|
||||
> examples in the `contrib/` directory, which can be used as a base.
|
||||
|
||||
|
||||
Service Environment
|
||||
@@ -261,67 +96,6 @@ the `ps` command we can see that the process is started with:
|
||||
> `-` is used, a missing environment file does *not* block the start.
|
||||
|
||||
|
||||
Service Synchronization
|
||||
-----------------------
|
||||
|
||||
Finit was created for fast booting systems. Faster than a regular SysV
|
||||
Init based system at the time. Early on the need for a guaranteed start
|
||||
order of services (daemons) arose. I.e., service `A` must be guaranteed
|
||||
to have started (and be ready!) before `B`. The model that was chosen
|
||||
to determine this was very simple: PID files.
|
||||
|
||||
Early on in UNIX daemons were controlled with basic IPC like signals,
|
||||
and the way for a user to know that a daemon was ready to respond to
|
||||
signals (minimally having set up its signal handler), was to tell the
|
||||
user;
|
||||
|
||||
> "Hey, you can send signals to me using the PID in this file:
|
||||
> `/var/run/daemon.pid`".
|
||||
|
||||
Since most systems run fairly unchanged after boot, Finit could rely on
|
||||
the PID file for `A` being created before launching `B`. This method
|
||||
has worked well for a long time, and for systems based on Open Source it
|
||||
was easy to either add PID file support to a daemon without support for
|
||||
it, or fix ordering issues (PID file created before signal handler is
|
||||
set up) in existing daemons.
|
||||
|
||||
However, with the advent of other Init systems (Finit is rather old),
|
||||
most notably systemd and s6, other methods for signaling "readiness"
|
||||
arrived and daemons were adapted to these new schemes to a larger
|
||||
extent.
|
||||
|
||||
As of Finit v4.4 partial support for systemd and s6 is available. The
|
||||
native PID file mode of operation is still default, the other's can be
|
||||
defined per service, like this:
|
||||
|
||||
service notify:systemd foo
|
||||
service notify:s6 bar
|
||||
|
||||
To synchronize two services the following condition can be used:
|
||||
|
||||
service notify:systemd A
|
||||
service <service/A/ready> B
|
||||
|
||||
For details on the syntax and options, see below.
|
||||
|
||||
> **Note:** on `initctl reload` conditions are normally set in "flux",
|
||||
> while figuring out which to stop, start or restart. Services that
|
||||
> need to be restarted have their `ready` condition removed prior to
|
||||
> Finit sending them SIGHUP (if they support that), or stop-starting
|
||||
> them. A daemon is expected to reassert its readiness, e.g. systemd
|
||||
> style daemons to write `READY=1\n`.
|
||||
>
|
||||
> However, the s6 notify mode does not support this because in s6 you
|
||||
> are expected to close your notify descriptor after having written
|
||||
> `\n`. This means s6 style daemons currently must be stop-started.
|
||||
> (Declare the service with `<!>` in its condition statement.)
|
||||
>
|
||||
> For native PID file style readiness notification a daemon is expected
|
||||
> to either create its PID file, if it does not exist yet, or touch it
|
||||
> using `utimensat()` or similar. This triggers both the `<pid/>` and
|
||||
> `<.../ready>` conditions.
|
||||
|
||||
|
||||
Service Wrapper Scripts
|
||||
-----------------------
|
||||
|
||||
@@ -354,115 +128,9 @@ example employs a wrapper script in `/etc/start.d`.
|
||||
> instead of sending SIGHUP at restart/reload events.
|
||||
|
||||
|
||||
Templating
|
||||
----------
|
||||
|
||||
Finit comes with rudimentary support for templating, similar to that of
|
||||
systemd. Best illustrated with an example:
|
||||
|
||||
$ initctl show avahi-autoipd@
|
||||
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||
|
||||
To enable ZeroConf for, e.g., eth0, use
|
||||
|
||||
$ initctl enable avahi-autoipd@eth0.conf
|
||||
|
||||
The enabled symlink will be set up to avahi-autoipd@.conf and every in‐
|
||||
stance of %i will in the instantiated directive be replaced with eth0.
|
||||
Inspect the result with:
|
||||
|
||||
$ initctl status avahi-autoipd:eth0
|
||||
|
||||
|
||||
Cgroups
|
||||
-------
|
||||
|
||||
There are three major cgroup configuration directives:
|
||||
|
||||
1. Global top-level group: init, system, user, or a custom group
|
||||
2. Selecting a top-level group for a set of run/task/services
|
||||
3. Per run/task/service limits
|
||||
|
||||
Top-level group configuration.
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
cgroup init cpu.weight:100
|
||||
cgroup user cpu.weight:100
|
||||
cgroup system cpu.weight:9800
|
||||
|
||||
Adding an extra cgroup `maint/` will require you to adjust the weight of
|
||||
the above three. We leave `init/` and `user/` as-is reducing weight of
|
||||
`system/` to 9700.
|
||||
|
||||
cgroup system cpu.weight:9700
|
||||
|
||||
# Example extra cgroup 'maint'
|
||||
cgroup maint cpu.weight:100
|
||||
|
||||
By default, the `system/` cgroup is selected for almost everything. The
|
||||
`init/` cgroup is reserved for PID 1 itself and its closest relatives.
|
||||
The `user/` cgroup is for local TTY logins spawned by getty.
|
||||
|
||||
To select a different top-level cgroup, e.g. `maint/`, one can either
|
||||
define it for a group of run/task/service directives in a `.conf` or per
|
||||
each stanza:
|
||||
|
||||
cgroup.maint
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
|
||||
or
|
||||
|
||||
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||
|
||||
The latter form also allows per-stanza limits on the form:
|
||||
|
||||
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||
|
||||
Notice the comma separation and the `mem.` exception to the rule: every
|
||||
cgroup setting maps directly to cgroup v2 syntax. I.e., `cpu.max` maps
|
||||
to the file `/sys/fs/cgroup/maint/foo/cpu.max`. There is no filtering,
|
||||
except for expanding the shorthand `mem.` to `memory.`, if the file is
|
||||
not available, either the cgroup controller is not available in your
|
||||
Linux kernel, or the name is misspelled.
|
||||
|
||||
> Linux cgroups and details surrounding values are not explained in the
|
||||
> Finit documentation. The Linux admin-guide cover this well:
|
||||
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||
|
||||
|
||||
Configuration File Syntax
|
||||
-------------------------
|
||||
|
||||
The file format is line based, empty lines and comments, lines starting
|
||||
with `#`, are ignored. A configuration directive starts with a keyword
|
||||
followed by a space and the rest of the line is treated as the value.
|
||||
|
||||
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||
lines using the continuation character `\`, and trailing comments are
|
||||
also allowed. Example:
|
||||
|
||||
```aconf
|
||||
# Escape \# chars if you want them literal in, e.g., descriptions
|
||||
service name:sysklogd [S123456789] \
|
||||
env:-/etc/default/sysklogd \
|
||||
syslogd -F $SYSLOGD_ARGS \
|
||||
-- System log daemon \# 1 # Comments allowed now
|
||||
```
|
||||
|
||||
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support the
|
||||
following directives:
|
||||
|
||||
|
||||
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
|
||||
> and some directives are only available at [bootstrap][], runlevel `S`,
|
||||
> see [Limitations](#limitations) below for details.
|
||||
|
||||
|
||||
### Hostname
|
||||
|
||||
**Syntax:** `host <NAME>`, or `hostname <NAME>`
|
||||
@@ -472,7 +140,7 @@ the contents of that file is used.
|
||||
|
||||
Deprecated. We recommend using `/etc/hostname` instead.
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Kernel Modules
|
||||
@@ -490,7 +158,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||
|
||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Networking
|
||||
@@ -503,30 +171,9 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Alternate finit.d/
|
||||
|
||||
**Syntax:** `rcsd /path/to/finit.d`
|
||||
|
||||
The Finit rcS.d directory is set at compile time with:
|
||||
|
||||
./configure --with-rcsd=/etc/finit.d
|
||||
|
||||
A system with multiple use-cases may be bootstrapped with different
|
||||
configurations, starting with the kernel command line option:
|
||||
|
||||
-- finit.config=/etc/factory.conf
|
||||
|
||||
This file in turn can use the `rcsd` directive to tell Finit to use
|
||||
another set of .conf files, e.g.:
|
||||
|
||||
rcsd /etc/factory.d
|
||||
|
||||
> **Note:** this directive is only available from the top-level
|
||||
> bootstrap .conf file.
|
||||
|
||||
### Resource Limits
|
||||
|
||||
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
|
||||
@@ -558,16 +205,13 @@ stanzas can share the same rlimits if they are in the same .conf.
|
||||
|
||||
**Syntax:** `runlevel <N>`
|
||||
|
||||
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
Defines the system runlevel to go to after bootstrap (S) has completed.
|
||||
N is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
halt.
|
||||
|
||||
It is recommended to keep runlevel 1 as single-user mode, because
|
||||
Finit disables networking in this mode.
|
||||
Default: 2
|
||||
|
||||
*Default:* 2
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### One-shot Commands (sequence)
|
||||
@@ -613,10 +257,6 @@ calls `init-script restart` on `initctl reload`. Similar to how
|
||||
|
||||
Forking services started with `sysv` scripts can be monitored by Finit
|
||||
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||
Notice the leading `!`, it signifies Finit should not try to create the
|
||||
file, but rather watch that file for the resulting forked-off PID. This
|
||||
syntax also works for forking daemons that do not have a command line
|
||||
option to run it in the foreground, more on this below in `service`.
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
@@ -626,13 +266,8 @@ option to run it in the foreground, more on this below in `service`.
|
||||
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||
|
||||
Service, or daemon, to be monitored and automatically restarted if it
|
||||
exits prematurely. Finit tries to restart services that die, by
|
||||
default 10 times before giving up and marking them as *crashed*.
|
||||
After which they have to be manually restarted with `initctl restart
|
||||
NAME`. The limits controling this are configurable, see the options
|
||||
below.
|
||||
|
||||
> **Tip:** to allow endless restarts, see below option `respawn`
|
||||
exits prematurely. Finit tries to restart services that die 10 times
|
||||
before giving up, then you have to `initctl restart NAME` it manually.
|
||||
|
||||
For daemons that support it, we recommend appending `--foreground`,
|
||||
`--no-background`, `-n`, `-F`, or similar command line argument to
|
||||
@@ -640,19 +275,9 @@ prevent them from forking off a sub-process in the background. This is
|
||||
the most reliable way to monitor a service.
|
||||
|
||||
However, not all daemons support running in the foreground, or they may
|
||||
start logging to the foreground as well, these are forking daemons and
|
||||
are supported using the same syntax as forking `sysv` services, using
|
||||
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
|
||||
that may be more intuitive, where Finit can also guess the PID file
|
||||
based on the daemon's command name:
|
||||
|
||||
service type:forking ntpd -- NTP daemon
|
||||
|
||||
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
|
||||
basename of the binary to guess the PID file to watch for the PID:
|
||||
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
|
||||
full `pid:!/path/to/file.pid`.
|
||||
|
||||
start logging to the foreground as well, these are called forking
|
||||
services and are supported using the same syntax as forking `sysv`
|
||||
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -679,56 +304,10 @@ modified with an optional `pid:`-argument:
|
||||
|
||||
pid[:[/path/to/]filename[.pid]]
|
||||
|
||||
For example, by adding `pid:/run/bar.pid` to the service `/sbin/bar`,
|
||||
For example, by adding `pid:/run/foo.pid` to the service `/sbin/bar`,
|
||||
that PID file will, not only be created and removed automatically, but
|
||||
also be used by the Finit condition subsystem. So a service/run/task
|
||||
can depend on `<pid/bar>`, like this foo will not be started until bar
|
||||
has started:
|
||||
|
||||
service pid:/run/bar.pid bar -- Bar Service
|
||||
service <pid/bar> foo -- Foo Service
|
||||
|
||||
Needless to say, it is better if `bar` creates its own PID file when it
|
||||
has completed starting up and is ready for service.
|
||||
|
||||
As an alternative "readiness" notification, Finit supports both systemd
|
||||
and s6 style notification. This can be enabled by using the `notify`
|
||||
option:
|
||||
|
||||
* `notify:systemd` -- tells Finit the service uses the `sd_notify()`
|
||||
API to signal PID 1 when it has completed its startup and is ready
|
||||
to service events. The [sd_notify()][] API expects `NOTIFY_SOCKET`
|
||||
to be set to the socket where the application can send `"READY=1\n"`
|
||||
when it is starting up or has processed a `SIGHUP`.
|
||||
* `notify:s6` -- puts Finit in s6 compatibility mode. Compared to the
|
||||
systemd notification, [s6 expect][] compliant daemons to send `"\n"`
|
||||
and then close their socket. Finit takes care of "hard-wiring" the
|
||||
READY state as long as the application is running, events across any
|
||||
`SIGHUP`. Since s6 can give its applications the descriptor number
|
||||
(must be >3) on then command line, Finit provides the following
|
||||
syntax (`%n` is replaced by Finit with then descriptor number):
|
||||
|
||||
service [S12345789] notify:s6 mdevd -O 4 -D %n
|
||||
|
||||
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
[s6 expect]: https://skarnet.org/software/s6/notifywhenup.html
|
||||
|
||||
When a service is ready, either by Finit detecting its PID file, or
|
||||
their respective readiness mechanism has been triggered, Finit creates
|
||||
then service's ready condition which other services can depend on:
|
||||
|
||||
$ initctl -v cond get service/mdevd/ready
|
||||
on
|
||||
|
||||
This can be used to synchronize the start of another run/task/service:
|
||||
|
||||
task [S] <service/mdevd/ready> @root:root mdevd-coldplug
|
||||
|
||||
Finit waits for `mdevd` to notify it, before starting `mdevd-coldplug`.
|
||||
Notice how both start in runlevel S, and the coldplug task only runs in
|
||||
S. When the system moves to runlevel 2 (the default), coldplug is no
|
||||
longer part of the running configuration (`initctl show`), this is to
|
||||
ensure that coldplug is not called more than once.
|
||||
can depend on `<pid/bar>`.
|
||||
|
||||
> For a detailed description of conditions, and how to debug them,
|
||||
> see the [Finit Conditions](conditions.md) document.
|
||||
@@ -745,46 +324,6 @@ optional `name` argument:
|
||||
|
||||
name:<service-name>
|
||||
|
||||
If multiple instances of a service, with the same `name`, exist. Set
|
||||
the identifier `:ID` to prevent Finit from replacing previous instances:
|
||||
|
||||
service :eth1 ssdpd eth1 -- Windows discovery on eth1
|
||||
service :eth2 ssdpd eth2 -- Windows discovery on eth2
|
||||
|
||||
If you have conflicting services and want to prevent them from starting,
|
||||
use the `conflict:` argument:
|
||||
|
||||
service [S12345789] udevd -- Device event management daemon
|
||||
run [S] conflict:udevd mdev -s -- Populating device tree
|
||||
|
||||
Multiple conflicting services can be separated using `,`:
|
||||
|
||||
service :1 abc
|
||||
service :2 abc
|
||||
service conflict:abc:1,abc:2 cde
|
||||
|
||||
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, max: 255. When this limit is reached the
|
||||
service is marked *crashed* and must be restarted manually with
|
||||
`initctl restart NAME`
|
||||
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
|
||||
a crashing service, default: 2 seconds for the first five retries,
|
||||
then back-off to 5 seconds. The maximum of this configured value
|
||||
and the above (2 and 5) will be used
|
||||
* `restart:always` -- no upper limit on the number of times Finit
|
||||
tries to restart a crashing service. Same as `restart:-1`
|
||||
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
||||
endless restarts. Useful in many use-cases, but not what `service`
|
||||
was originally designed for so not the default behavior
|
||||
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||
has *crashed*, if this option is set the system is rebooted.
|
||||
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||
`post:script` action if set, see below.
|
||||
|
||||
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
|
||||
@@ -794,25 +333,6 @@ process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
||||
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
||||
sending `SIGKILL`.
|
||||
|
||||
Services support `pre:script` and `post:script` actions as well. These
|
||||
run as the same `@USER:GROUP` as the service itself, with any `env:file`
|
||||
sourced. The scripts must use an absolute path, but are executed from
|
||||
the `$HOME` of the given user. The scripts are not called with any
|
||||
argument (currently), but both get the `SERVICE_IDENT=foo` environment
|
||||
variable set. Here `foo` denotes the identity of the service, which if
|
||||
there are multiple services named `foo`, may be `foo:1`, or any unique
|
||||
identifier specified in the .conf file. The `post:script` is called
|
||||
with an additional set of environment variables:
|
||||
|
||||
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
||||
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
||||
the program, if it exited normally, or the signal name (`HUP`,
|
||||
`TERM`, etc.) if it exited due to signal
|
||||
|
||||
These script actions *must terminate*, so they have a default execution
|
||||
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
||||
the above `kill:SEC` syntax.
|
||||
|
||||
|
||||
### Run-parts Scripts
|
||||
|
||||
@@ -821,53 +341,17 @@ the above `kill:SEC` syntax.
|
||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||
files, or scripts, in the directory are called, in alphabetic order.
|
||||
The scripts in this directory are executed at the very end of runlevel
|
||||
`S`, [bootstrap][].
|
||||
`S`, bootstrap.
|
||||
|
||||
A common use-case for runparts scripts is to create and enable/disable
|
||||
services, which Finit will then apply when changing runlevel from S to
|
||||
whatever the next runlevel is set to be (default 2). E.g., generate a
|
||||
`/etc/chrony.conf` and `initctl enable chronyd`.
|
||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
||||
is a dependency order between the scripts. Symlinks to existing
|
||||
daemons can talso be used, but make sure they daemonize by default.
|
||||
|
||||
**Limitations:**
|
||||
|
||||
Scripts called from `runparts`, or hook scripts (see below), are limited
|
||||
in what they can do and expect from Finit:
|
||||
|
||||
1. Finit is single threaded and all scripts executed from these two
|
||||
mechanisms are limited to file system operations (early or late
|
||||
hooks may not have write access!) and standard UNIX programs.
|
||||
2. Thus, it is *not possible* to call `initctl` to query status of
|
||||
services since that calls Finit over the `/run/finit/socket`.
|
||||
3. Confusingly enough, there are some commands to `initctl` that are
|
||||
available; `ls`, `enable`, `disable`, `touch`, `create`, `delete`,
|
||||
and all the `cond` commands. Because all these are basically just
|
||||
wrappers for manipulating files (again, write access for early/late
|
||||
hooks may not be available).
|
||||
|
||||
Also, similar to the `/etc/rc.local` shell script, make sure that all
|
||||
your services and programs either terminate or start in the background
|
||||
or you will block Finit.
|
||||
|
||||
> **Note:** `runparts` scrips are only read and executed in runlevel S
|
||||
> ([bootstrap][]). See [hook scripts](plugins.md#hooks) for other ways
|
||||
> to run scripts at certain points during the complete lifetime of the
|
||||
> system.
|
||||
|
||||
**Recommendations:**
|
||||
|
||||
It can be beneficial to use `01-name`, `02-othername`, etc., to ensure
|
||||
the scripts are started in that order, e.g., if there is a dependency
|
||||
order between scripts. Symlinks to existing daemons can talso be used,
|
||||
but make sure they daemonize (background) themselves properly, otherwise
|
||||
Finit will lock up.
|
||||
|
||||
If `S[0-9]foo` and `K[0-9]bar` style naming is used, the executable will
|
||||
be called with an extra argument, `start` and `stop`, respectively.
|
||||
E.g., `S01foo` will be called as `S01foo start`. Of course, `S01foo`
|
||||
and `K01foo` may be a symlink to to `another/directory/foo`.
|
||||
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
Similar to the `/etc/rc.local` shell script, make sure that all your
|
||||
services and programs either terminate or start in the background or
|
||||
you will block Finit.
|
||||
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
### Including Finit Configs
|
||||
|
||||
@@ -893,40 +377,24 @@ size limit is reached.
|
||||
|
||||
### TTYs and Consoles
|
||||
|
||||
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
|
||||
`tty [LVLS] <COND> [notty] [rescue]`
|
||||
**Syntax:** `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
||||
|
||||
The first variant of this option uses the built-in getty on the given
|
||||
TTY device DEV, in the given runlevels. DEV may be the special keyword
|
||||
`@console`, which is expanded from `/sys/class/tty/console/active`,
|
||||
useful on embedded systems.
|
||||
TTY device DEV, in the given runlevels. The DEV may be the special
|
||||
keyword `@console`, or `console`, useful on embedded systems.
|
||||
|
||||
The default baud rate is 0, i.e., keep kernel default.
|
||||
|
||||
> The `tty` stanza inherits runlevel, condition (and other feature)
|
||||
> parsing from the `service` stanza. So TTYs can run in one or many
|
||||
> runlevels and depend on any condition supported by Finit. This is
|
||||
> useful e.g. to depend on `<pid/elogind>` before starting a TTY.
|
||||
|
||||
**Example:**
|
||||
|
||||
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||
|
||||
The second `tty` syntax variant is for using an external getty, like
|
||||
agetty or the BusyBox getty.
|
||||
|
||||
The third variant is for board bringup and the `rescue` boot mode. No
|
||||
device node is required in this variant, the same output that the kernel
|
||||
uses is reused for stdio. If the `rescue` option is omitted, a shell is
|
||||
started (`nologin`, `noclear`, and `nowait` are implied), if the rescue
|
||||
option is set the bundled `/libexec/finit/sulogin` is started to present
|
||||
a bare-bones root login prompt. If the root (uid:0, gid:0) user does
|
||||
not have a password set, no rescue is possible. For more information,
|
||||
see the [Rescue Mode](#rescue-mode) section.
|
||||
|
||||
By default, the first two syntax variants *clear* the TTY and *wait* for
|
||||
the user to press enter before starting getty.
|
||||
|
||||
By default both variants *clear* the TTY and *wait* for the user to
|
||||
press enter before starting getty.
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -955,23 +423,16 @@ uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
||||
it out by querying sysfs: `/sys/class/tty/console/active`. The speed
|
||||
can be omitted to keep the kernel default.
|
||||
|
||||
> Most systems get by fine by just using `console`, which will evaluate
|
||||
> to `/dev/console`. If you have to use `@console` to get any output,
|
||||
> you may have some issue with your kernel config.
|
||||
|
||||
**Example:**
|
||||
|
||||
tty [12345] @console noclear vt220
|
||||
|
||||
On really bare bones systems, or for board bringup, Finit can give you a
|
||||
shell prompt as soon as [bootstrap][] is done, without opening any
|
||||
device node:
|
||||
|
||||
tty [12345789] notty
|
||||
|
||||
This should of course not be enabled on production systems. Because it
|
||||
On really bare bones systems Finit offers a fallback shell, which
|
||||
should not be enabled on production systems since. This because it
|
||||
may give a user root access without having to log in. However, for
|
||||
board bringup and system debugging it can come in handy.
|
||||
bringup and system debugging it can come in handy:
|
||||
|
||||
configure --enable-fallback-shell
|
||||
|
||||
One can also use the `service` stanza to start a stand-alone shell:
|
||||
|
||||
@@ -981,8 +442,8 @@ One can also use the `service` stanza to start a stand-alone shell:
|
||||
### Non-privileged Services
|
||||
|
||||
Every `run`, `task`, or `service` can also list the privileges the
|
||||
`/path/to/cmd` should be executed with. Prefix the command with
|
||||
`@USR[:GRP]`, group is optional, like this:
|
||||
`/path/to/cmd` should be executed with. Simply prefix the path with
|
||||
`[@USR[:GRP]]` like this:
|
||||
|
||||
run [2345] @joe:users logger "Hello world"
|
||||
|
||||
@@ -1022,153 +483,28 @@ Log rotation is controlled using the global `log` setting.
|
||||
|
||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||
|
||||
|
||||
### Misc Settings
|
||||
|
||||
**Syntax:** `reboot-delay <0-60>`
|
||||
|
||||
Optional delay at reboot (or shutdown or halt) to allow kernel
|
||||
filesystem threads to complete after calling `sync(2)` before
|
||||
rebooting. This applies primarily to filesystems that do not
|
||||
have a reboot notifier implemented. At the point of writing,
|
||||
the only known filesystems affected are: ubifs, jffs2.
|
||||
|
||||
*Default:* 0 (disabled)
|
||||
|
||||
When enabled (non-zero), this delay runs after file systems have been
|
||||
unmounted and the root filesystem has been remounted read-only, and
|
||||
sync(2) has been called, twice.
|
||||
|
||||
> "On Linux, sync is only guaranteed to schedule the dirty blocks for
|
||||
> writing; it can actually take a short time before all the blocks are
|
||||
> finally written.
|
||||
|
||||
|
||||
Rescue Mode
|
||||
-----------
|
||||
|
||||
Finit supports a rescue mode which is activated by the `rescue` option
|
||||
on the kernel command line. See [cmdline docs](cmdline.md) for how to
|
||||
activate it.
|
||||
|
||||
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||
|
||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||
> force `reboot`, `shutdown`, or `poweroff`.
|
||||
|
||||
|
||||
### Traditional
|
||||
|
||||
This is what most users expect. A very early maintenance login prompt,
|
||||
served by the bundled `/libexec/finit/sulogin` program, or the standard
|
||||
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
|
||||
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
|
||||
rescue mode is ended and the system boots up normally.
|
||||
|
||||
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
|
||||
> __the account is locked__, the user is presented with a password-less
|
||||
> `"Press enter to enter maintenance mode."`, prompt which opens up a
|
||||
> root shell.
|
||||
|
||||
|
||||
### Fallback
|
||||
|
||||
If no `sulogin` program is found, Finit tries to bring up as much of its
|
||||
own functionality as possible, yet limiting many aspects, meaning; no
|
||||
network, no `fsck` of file systems in `/etc/fstab`, no `/etc/rc.local`,
|
||||
no `runparts`, and most plugins are skipped (except those that provide
|
||||
functionality for the condition subsystem).
|
||||
|
||||
Instead of reading `/etc/finit.conf` et al, system configuration is read
|
||||
from `/lib/finit/rescue.conf`, which can be freely modified by the
|
||||
system administrator.
|
||||
|
||||
The bundled default `rescue.conf` contains nothing more than:
|
||||
|
||||
runlevel 1
|
||||
tty [12345] rescue
|
||||
|
||||
The `tty` has the `rescue` option set, which works similar to the board
|
||||
bring-up tty option `notty`. The major difference being that `sulogin`
|
||||
is started to query for root/admin password. If `sulogin` is not found,
|
||||
`rescue` behaves like `notty` and gives a plain root shell prompt.
|
||||
|
||||
If Finit cannot find `/lib/finit/rescue.conf` it defaults to:
|
||||
|
||||
tty [12345] rescue
|
||||
|
||||
There is no way to exit the *fallback* rescue mode.
|
||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
||||
detailed description, see the [Conditions](conditions.md) document.
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
As of Finit v4 there are no limitations to where `.conf` settings can be
|
||||
placed. Except for the system/global `rlimit` and `cgroup` top-level
|
||||
group declarations, which can only be set from `/etc/finit.conf`, since
|
||||
it is the first `.conf` file Finit reads.
|
||||
placed. Except for the system/global `rlimit`, which can only be set
|
||||
from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
|
||||
|
||||
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
||||
Today it is mainly used for bootstrap settings like system hostname,
|
||||
early module loading for watchdogd, network bringup and system shutdown.
|
||||
These can now also be set in any `.conf` file in `/etc/finit.d`.
|
||||
network bringup and system shutdown. These can now also be set in any
|
||||
`.conf` file in `/etc/finit.d`.
|
||||
|
||||
There is, however, nothing preventing you from having all configuration
|
||||
settings in `/etc/finit.conf`.
|
||||
|
||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
||||
> Finit [runparts](#run-parts-scripts) directory. Finit >=v4.0
|
||||
> no longer has a default `runparts` directory, make sure to
|
||||
> update your setup, or the finit configuration, accordingly.
|
||||
> Finit `runparts` directory. Finit no longer has a default
|
||||
> `runparts`, make sure to update your setup, or the finit
|
||||
> configuration, accordingly.
|
||||
|
||||
|
||||
Watchdog
|
||||
--------
|
||||
|
||||
When built `--with-watchdog` a separate service is built and installed
|
||||
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
|
||||
device node exists, Finit will start it and treat it as the elected
|
||||
watchdog service to delegate its reboot to. See [bootstrap][] for
|
||||
details. This delegation is to ensure that the system is rebooted by a
|
||||
hardware watchdog timer -- on many embedded systems this is crucial to
|
||||
ensure all circuits on the board are properly reset for the next boot,
|
||||
in effect ensuring the system works the same after both a power-on and
|
||||
reboot event.
|
||||
|
||||
The delegation is performed at the very last steps of system shutdown,
|
||||
if reboot has been selected and an elected watchdog is known, first a
|
||||
`SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when
|
||||
the necessary steps of preparing the system for shutdown (umount etc.)
|
||||
are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a
|
||||
10 sec timeout loop waiting for the WDT to reset the board. If a reset
|
||||
is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)`
|
||||
which tells the kernel to do the reboot.
|
||||
|
||||
An external watchdog service can also be used. The more advanced cousin
|
||||
[watchdogd](https://github.com/troglobit/watchdogd/) is the recommended
|
||||
option here. It can register itself with Finit using the same IPC as
|
||||
`initctl`. If the bundled watchdogd is running a hand-over takes place,
|
||||
so it's safe to have both services installed on a system. For the
|
||||
hand-over to work it requires that the WDT driver supports the safe exit
|
||||
functionality where `"V"` is written to the device before closing the
|
||||
device descriptor. If the kernel driver has been built without this,
|
||||
the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||
it at configure time.
|
||||
|
||||
[bootstrap]: bootstrap.md
|
||||
|
||||
|
||||
keventd
|
||||
-------
|
||||
|
||||
The kernel event daemon bundled with Finit is a simple uevent monitor
|
||||
for `/sys/class/power_supply`. It provides the `sys/pwr/ac` condition,
|
||||
which can be useful to prevent power hungry services like anacron to run
|
||||
when a laptop is only running on battery, for instance.
|
||||
|
||||
Since keventd is not an integral part of Finit yet it is not enabled by
|
||||
default. Enable it using `./configuure --with-keventd`. The bundled
|
||||
contrib build scripts for Debian, Alpine, and Void have this enabled.
|
||||
|
||||
This daemon is planned to be extended with monitoring of other uevents,
|
||||
patches and ideas are welcome in the issue tracker.
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
|
||||
+25
-138
@@ -8,8 +8,7 @@ Hooks & Plugins
|
||||
* [Shutdown Hooks](#shutdown-hooks)
|
||||
|
||||
Finit can be extended to add general functionality in the form of I/O
|
||||
monitors, or hook plugins. It is even possible to run scripts at these
|
||||
hook points, see below.
|
||||
monitors, or hook plugins.
|
||||
|
||||
The following sections detail existing plugins and hook points. For
|
||||
more information, see the plugins listed below.
|
||||
@@ -35,75 +34,26 @@ For your convenience a set of *optional* plugins are available:
|
||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||
_Optional plugin._
|
||||
|
||||
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
||||
points (see [Hooks](#hooks)). _Optional plugin._
|
||||
|
||||
This plugin is particularly useful for early boot debugging that needs
|
||||
to take place before regular services are available.
|
||||
|
||||
For example, say that you want to enable some kernel tracing before
|
||||
modules are loaded. With hook scripts, you can just drop in a shell
|
||||
script in `/libexec/finit/hook/mount/all/` that will poke the right
|
||||
control files in tracefs.
|
||||
|
||||
Scripts are located in `/libexec/finit/hook` by default, this can be
|
||||
customized at build-time using the `--with-hook-scripts-path=PATH`
|
||||
argument to `configure`.
|
||||
|
||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||
available. Enabled by default.
|
||||
|
||||
> See the [Services](config.md#services) section in the configuration
|
||||
> guide for an example how to run `mdevd`, alternative to plain mdev.
|
||||
available.
|
||||
|
||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||
Enabled by default.
|
||||
|
||||
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
|
||||
load using `modprobe`. Each file can contain multiple lines with the
|
||||
name of the module to load. Any line starting with the standard UNIX
|
||||
comment character, `#`, or `;`, is skipped.
|
||||
|
||||
Modules are by default loaded in runlevel `S` using the `task` stanza.
|
||||
Each module gets a unique `name:modprobe.foo`, and optional`:ID`. The
|
||||
runlevel can be changed per file using:
|
||||
|
||||
set runlevel 2345
|
||||
|
||||
The `:ID` is a globally incremented index, which can be disabled per
|
||||
file (anywhere) using the following config line:
|
||||
|
||||
set noindex
|
||||
|
||||
To change the index used by the plugin:
|
||||
|
||||
set index 1234
|
||||
|
||||
**Note:** unlike the traditional .conf `module` directive, which load
|
||||
any listed module immediately, this plugin creates a background `task`
|
||||
which load the module(s) in the background. The program is modprobe,
|
||||
`/sbin/modprobe`, which you can override per .conf file:
|
||||
|
||||
set modprobe /path/to/maybe-a-modprobe-wrapper
|
||||
|
||||
Since these tasks run in the background, they usually return `[ OK ]`
|
||||
at boot, unless the modprobe tool does not exist. Check syslog for
|
||||
warnings and the actual status of the operation using `initctl`.
|
||||
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||
|
||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||
interfaces. These events are then sent to the Finit service monitor
|
||||
for services that may want to be SIGHUP'ed on new default route or
|
||||
interfaces going up/down. Enabled by default.
|
||||
interfaces going up/down.
|
||||
|
||||
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
||||
_Optional plugin._
|
||||
|
||||
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
||||
to start/stop getty consoles on them on demand. Useful when plugging
|
||||
in a usb2serial converter to login to your embedded device. Enabled
|
||||
by default.
|
||||
in a usb2serial converter to login to your embedded device.
|
||||
|
||||
* *urandom.so*: Setup random seed at startup. Enabled by default.
|
||||
* *urandom.so*: Setup random seed at startup.
|
||||
|
||||
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
||||
|
||||
@@ -117,101 +67,38 @@ state, etc. Available hook points are:
|
||||
Hooks
|
||||
-----
|
||||
|
||||
In the below listings, the first label is the hook point for a C plugin,
|
||||
the second is the condition name and hook script path. A hook script is
|
||||
a plain shell script, or program, that does a very small dedicated job
|
||||
at the below hook points.
|
||||
|
||||
See [Run-parts Scripts](config.md#run-parts-scripts) for details on the
|
||||
requirements, possibilities, and *limitations* of hook scripts.
|
||||
|
||||
All hook scripts are called with at least one environment variable set,
|
||||
the hook name, useful when reusing the same hook script for multiple
|
||||
hook points:
|
||||
|
||||
- `FINIT_HOOK_NAME`: set to the second label, e.g., `hook/net/up`
|
||||
- `FINIT_SHUTDOWN`: set for `hook/sys/shutdown` and later to one
|
||||
of `halt`, `poweroff`, or `reboot`.
|
||||
|
||||
**Example:**
|
||||
|
||||
$ mkdir -p /libexec/finit/hook/sys/down
|
||||
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh
|
||||
#!/bin/sh
|
||||
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||
echo "FINIT_HOOK_NAME: $FINIT_HOOK_NAME"
|
||||
if [ -n "$FINIT_SHUTDOWN" ]; then
|
||||
echo "FINIT_SHUTDOWN: $FINIT_SHUTDOWN"
|
||||
fi
|
||||
exit 0
|
||||
EOF
|
||||
$ chmod +x /libexec/finit/hook/sys/foo.sh
|
||||
|
||||
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
||||
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
||||
|
||||
### Bootstrap Hooks
|
||||
|
||||
* `HOOK_BANNER`, `hook/sys/banner`: The very first point at which a
|
||||
plugin can run. Intended to be used as a banner replacement.
|
||||
Essentially this runs just before entering runlevel S. Assume nothing
|
||||
is available, so be prepared to use absolute paths, etc.
|
||||
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
|
||||
mounted — very early
|
||||
|
||||
* `HOOK_ROOTFS_UP`, `hook/mount/root`: When `finit.conf` has been read
|
||||
and `/` has is mounted — very early
|
||||
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
|
||||
and default init signals are setup
|
||||
|
||||
* `HOOK_MOUNT_ERROR`, `hook/mount/error`: executed if `mount -a` fails
|
||||
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
|
||||
networking is up (`lo` is up and the `network` script has run)
|
||||
|
||||
* `HOOK_MOUNT_POST`, `hook/mount/post`: always executed after `mount -a`
|
||||
* `HOOK_SVC_UP`: All services in the active runlevel has been launched
|
||||
|
||||
* `HOOK_BASEFS_UP`, `hook/mount/all`: All of `/etc/fstab` is mounted,
|
||||
swap is available and default init signals are setup
|
||||
|
||||
* `HOOK_SVC_PLUGIN`, `hook/svc/plugin`: Called in `conf_init()` right
|
||||
before loading `/etc/finit.conf`. For plugins to register any early
|
||||
run/task/services, please do NOT use any earlier hook point. That
|
||||
will cause uninitialized rlimits that lead to unpredictable results
|
||||
when Finit later tries to start the run/task/service.
|
||||
|
||||
* `HOOK_NETWORK_UP`, `hook/net/up`: System bootstrap, runlevel S, has
|
||||
completed and networking is up (`lo` is up and the `network` script
|
||||
has run)
|
||||
|
||||
* `HOOK_SVC_UP`, `hook/svc/up`: All services in the active runlevel have
|
||||
been launched
|
||||
|
||||
* `HOOK_SYSTEM_UP`, `hook/sys/up`: All services *and* everything in
|
||||
`/etc/finit.d` has been launched
|
||||
* `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
|
||||
has been launched
|
||||
|
||||
### Runtime Hooks
|
||||
|
||||
* `HOOK_SVC_RECONF`, N/A: Called when the user has changed something in
|
||||
the `/etc/finit.d` directory and issued `SIGHUP`. The hook is called
|
||||
when all modified/removed services have been stopped. When the hook
|
||||
has completed, Finit continues to start all modified and new services.
|
||||
* `HOOK_SVC_RECONF`: Called when the user has changed something in the
|
||||
`/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
|
||||
all modified/removed services have been stopped. When the hook has
|
||||
completed, Finit continues to start all modified and new services.
|
||||
|
||||
* `HOOK_RUNLEVEL_CHANGE`, N/A: Called when the user has issued a
|
||||
runlevel change. The hook is called when services not matching the
|
||||
new runlevel have been been stopped. When the hook has completed,
|
||||
Finit continues to start all services in the new runlevel.
|
||||
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
||||
change. The hook is called when services not matching the new
|
||||
runlevel have been been stopped. When the hook has completed, Finit
|
||||
continues to start all services in the new runlevel.
|
||||
|
||||
### Shutdown Hooks
|
||||
|
||||
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed
|
||||
to runlevel 6, or 0, when all services have received their 'stop' signal.
|
||||
|
||||
* `HOOK_SHUTDOWN`, `hook/sys/shutdown`: Called at shutdown/reboot, right
|
||||
before all services are sent `SIGTERM`
|
||||
|
||||
* `HOOK_SVC_DN`, `hook/svc/down`: In shutdown/reboot, all services and
|
||||
non-reserved processes have been killed. **Note:** only hook scripts
|
||||
can run here!
|
||||
|
||||
* `HOOK_SYSTEM_DN`, `hook/sys/down`: In shutdown/reboot, called after
|
||||
all non-reserved file systems have been unmounted, just before Finit
|
||||
tells the kernel to reboot or shut down. **Note:** only hook scripts
|
||||
can run here!
|
||||
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
|
||||
services are sent `SIGTERM`
|
||||
|
||||
Plugins like `tty.so` extend finit by acting on events, they are called
|
||||
I/O plugins and are called from the finit main loop when `poll()`
|
||||
|
||||
+2
-56
@@ -1,59 +1,7 @@
|
||||
Finit Services
|
||||
==============
|
||||
|
||||
Starting & Monitoring
|
||||
---------------------
|
||||
|
||||
Finit can start and monitor the following types of daemons:
|
||||
|
||||
* Forks to background, creates a PID file
|
||||
* Runs in foreground:
|
||||
- creates a PID file
|
||||
- does not create a PID file -- Finit can create it for you (optional)
|
||||
|
||||
Finit can *not* start and monitor a daemon that:
|
||||
|
||||
* Forks to background and does *not* create a PID file
|
||||
|
||||
| | Forking | Creates PID File | Finit creates PID File |
|
||||
|---|---------|------------------|------------------------|
|
||||
| ✔ | Yes | Yes | No |
|
||||
| ✔ | No | Yes | No |
|
||||
| ✔ | No | No | Yes, optionally |
|
||||
| ✘ | Yes | No | No |
|
||||
|
||||
> **Note:** PID files is one mechanism used to assert conditions to
|
||||
> synchronize the start and stop of other, dependent, services.
|
||||
|
||||
### Forks to Background w/ PID File
|
||||
|
||||
There are two syntax variants, type 1 and type 2. The former is the
|
||||
traditional one used also for `sysv` start/stop scripts, and the latter
|
||||
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
|
||||
to look for based on the standard path and the basename of the command.
|
||||
|
||||
service pid:!/run/serv.pid serv -- Forking service, type 1
|
||||
service type:forking serv -- Forking service, type 2
|
||||
|
||||
In this example the resulting files to watch for are `/run/serv.pid` and
|
||||
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
|
||||
the same directory (`/var/run` is a symlink to `../run`).
|
||||
|
||||
### Runs in Foreground w/ PID File
|
||||
|
||||
service serv -n -p -- Foreground service w/ PID file
|
||||
|
||||
### Runs in Foreground w/o PID File
|
||||
|
||||
Same as previous, but we tell Finit to create the PID file, because we
|
||||
need it to synchronize start/stop of a dependent service.
|
||||
|
||||
service pid:/run/serv.pid serv -n -- Foreground service w/o PID file
|
||||
|
||||
### Runs in Foreground w/ Custom PID File
|
||||
|
||||
service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
|
||||
|
||||

|
||||
|
||||
State Machine
|
||||
-------------
|
||||
@@ -63,8 +11,6 @@ For `run`s and `task`s there is an additional end state called `DONE`,
|
||||
not shown in the diagram for brevity. Services start in the `HALTED`
|
||||
state.
|
||||
|
||||

|
||||
|
||||
The current state depends on the two following conditions:
|
||||
|
||||
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
||||
@@ -72,7 +18,7 @@ The current state depends on the two following conditions:
|
||||
|
||||
A service may be stopped, or blocked, for several reasons:
|
||||
|
||||
- The user has manually stopped the service using `initctl stop NAME`
|
||||
- The user has manually stopped the service using `initctl stop JOB`
|
||||
- The program exits immediately. I.e. keeps crashing (make sure to use
|
||||
the 'run this service in the foreground' command line option)
|
||||
- The binary is missing in the filesystem
|
||||
|
||||
+9
-17
@@ -12,36 +12,28 @@ have been adopted:
|
||||
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
||||
*.conf files in `/etc/finit.d/`
|
||||
|
||||
This also restarts the API (initctl) socket, like SysV init and systemd
|
||||
does on USR1 with their FIFO/D-Bus.
|
||||
|
||||
|
||||
`SIGUSR1`
|
||||
---------
|
||||
|
||||
Since Finit 4.1 this signal causes Finit to restart its API (initctl)
|
||||
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus.
|
||||
|
||||
Finit <= 4.0 performed a system halt (like USR2 without power-off), but
|
||||
this caused compatibility problems with systemd and sysvinit on desktop
|
||||
systems. Hence, since Finit 4.1 it is no longer possible to halt a
|
||||
system with a signal.
|
||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||
processes, and unmounts all file systems. Then tells kernel to halt.
|
||||
Most people these days want `SIGUSR2` though.
|
||||
|
||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
||||
|
||||
`SIGUSR2`
|
||||
---------
|
||||
|
||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||
processes, and unmounts all file systems. Then tells kernel to power
|
||||
off the system, if ACPI or similar exists to actually do this. If the
|
||||
kernel fails power-off, Finit falls back to halt.
|
||||
|
||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
|
||||
similar exists to actually do this. If the kernel fails power-off,
|
||||
Finit falls back to halt.
|
||||
|
||||
SysV init N/A, systemd dumps its internal state to log.
|
||||
|
||||
`SIGTERM`
|
||||
---------
|
||||
|
||||
Like `SIGUSR2`, but tell kernel to reboot the system when done.
|
||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
||||
|
||||
SysV init N/A, systemd rexecutes itself.
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 16 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 164 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.6 KiB |
+23
-19
@@ -1,6 +1,8 @@
|
||||
# From https://github.com/collectd/collectd/blob/master/configure.ac
|
||||
# Dependency handling currently unused
|
||||
|
||||
define([toupper], [translit([$1], [a-z], [A-Z])])
|
||||
define([sanitize], [translit([$1], [-], [_])])
|
||||
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
||||
|
||||
# AC_PLUGIN(name, default, info)
|
||||
@@ -8,25 +10,27 @@ define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
||||
AC_DEFUN([AC_PLUGIN],[
|
||||
m4_divert_once([HELP_ENABLE], [
|
||||
Optional Plugins:])
|
||||
define(PLUGGY, m4_translit([$1],[a-z-][A-Z-]))dnl
|
||||
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
|
||||
if test "x$enableval" = "xyes"; then
|
||||
enable_plugin="yes"
|
||||
else
|
||||
enable_plugin="no"
|
||||
fi], [
|
||||
if test "x$enable_all_plugins" = "xauto"; then
|
||||
if test "x$2" = "xyes"; then
|
||||
enable_plugin="yes"
|
||||
define(pluggy, sanitize($1))
|
||||
define(PLUGGY, toupper(pluggy))
|
||||
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
|
||||
if test "x$enableval" = "xyes"; then
|
||||
enable_plugin="yes"
|
||||
else
|
||||
enable_plugin="no"
|
||||
enable_plugin="no"
|
||||
fi], [
|
||||
if test "x$enable_all_plugins" = "xauto"; then
|
||||
if test "x$2" = "xyes"; then
|
||||
enable_plugin="yes"
|
||||
else
|
||||
enable_plugin="no"
|
||||
fi
|
||||
else
|
||||
enable_plugin="$enable_all_plugins"
|
||||
fi])
|
||||
if test "x$enable_plugin" = "xyes"; then
|
||||
AC_DEFINE([HAVE_]PLUGGY[_PLUGIN], 1, [Define to 1 if the $1 plugin is enabled.])
|
||||
plugins="$1 $plugins"
|
||||
fi
|
||||
else
|
||||
enable_plugin="$enable_all_plugins"
|
||||
fi])
|
||||
if test "x$enable_plugin" = "xyes"; then
|
||||
AC_DEFINE(HAVE_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, 1, [Define to 1 if the $1 plugin is enabled.])
|
||||
plugins="$1 $plugins"
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, test "x$enable_plugin" = "xyes")])
|
||||
AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
|
||||
enable_pluggy="$enable_plugin"])
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -1,2 +0,0 @@
|
||||
dist_man8_MANS = finit.8 initctl.8
|
||||
dist_man5_MANS = finit.conf.5
|
||||
-348
@@ -1,348 +0,0 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.Dd Apr 22, 2023
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.Dt FINIT 8 SMM
|
||||
.Os Linux
|
||||
.Sh NAME
|
||||
.Nm finit
|
||||
.Nd Fast init for Linux systems
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/finit
|
||||
.Op --
|
||||
.Op debug
|
||||
.Op finit.cond=foo[,bar[,baz]]
|
||||
.Op finit.config=/path/to/alt/finit.conf
|
||||
.Op finit.debug
|
||||
.Op finit.fstab=/etc/fstab.alt
|
||||
.Op finit.status=<on,off>
|
||||
.Op finit.status_style=<classic,modern>
|
||||
.Op loglevel=<0-7>
|
||||
.Op panic=SEC
|
||||
.Op quiet
|
||||
.Op rescue | recover
|
||||
.Op single | S
|
||||
.Nm /sbin/telinit
|
||||
.Op Fl hv
|
||||
.Op q | Q | 0-9
|
||||
.Sh DESCRIPTION
|
||||
Fast init for Linux systems. Reverse engineered from the EeePC
|
||||
fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog
|
||||
DNA ...". Focus is on small and embedded systems, although Finit is
|
||||
fully usable on server and desktop systems as well.
|
||||
.Pp
|
||||
Features include:
|
||||
.Bl -bullet -width 1n -compact
|
||||
.It
|
||||
Runlevels, defined per service
|
||||
.It
|
||||
One-shot tasks, services (daemons), or SysV init start/stop scripts
|
||||
.It
|
||||
Runparts and
|
||||
.Pa /etc/rc.local
|
||||
support
|
||||
.It
|
||||
Process supervision similar to
|
||||
.Xr systemd 8
|
||||
.It
|
||||
Sourcing environment files
|
||||
.It
|
||||
Conditions for network/process/custom dependencies
|
||||
.It
|
||||
Process readiness notification for synchronizing system startup as well
|
||||
as reconfiguration at runtime. Natively PID files are used, but systemd
|
||||
.Cm sd_notify()
|
||||
and s6 notification is also supported.
|
||||
.It
|
||||
Limited support for
|
||||
.Xr tmpfiles.d 5 ,
|
||||
no aging, attributes, or subvolumes
|
||||
.It
|
||||
Pre/Post script actions
|
||||
.It
|
||||
Tooling to enable/disable services
|
||||
.It
|
||||
Built-in getty
|
||||
.It
|
||||
Built-in watchdog, with support for hand-over to
|
||||
.Lk https://troglobit.com/watchdogd.html watchdogd
|
||||
.It
|
||||
Built-in support for Debian/BusyBox
|
||||
.Pa /etc/network/interfaces
|
||||
.It
|
||||
Cgroups v2, both configuration and monitoring in `initctl top`
|
||||
.It
|
||||
Plugin support for customization
|
||||
.It
|
||||
Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||
.El
|
||||
.Sh BOOTPARAM
|
||||
.Nm
|
||||
support the following command line parameters to alter the behavior
|
||||
at boot. Notice the
|
||||
.Cm --
|
||||
separator needed to tell the kernel which paramters should be given to
|
||||
PID 1. For more information on this, and available kernel command line
|
||||
options, see
|
||||
.Xr bootparam 7 .
|
||||
.Bl -tag -width pid -offset indent
|
||||
.It Cm debug
|
||||
Enable kernel debug. Debug messages are printed to the console until
|
||||
Finit starts up, unless
|
||||
.Cm loglevel=7
|
||||
(below) is used.
|
||||
.It Cm finit.cond=foo[,bar[,baz]]
|
||||
set
|
||||
.Cm <boot/foo>
|
||||
condition, optionally multiple conditions can be set using the same
|
||||
option, separated with a comma. Alternatively, multiple
|
||||
.Cm foo.cond=arg
|
||||
can be given. Each will result in a
|
||||
.Cm <boot/arg>
|
||||
condition being set to control the rest of the system bootstrap.
|
||||
.Pp
|
||||
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||
firmware upgrade, or rescue mode.
|
||||
.Pp
|
||||
.Sy Note:
|
||||
.Cm <boot/...>
|
||||
conditions cannot be cleared with
|
||||
.Nm initctl !
|
||||
.It Cm finit.config=/path/to/alternative/finit.conf
|
||||
override the compile-time bootstrap config file, default:
|
||||
.Bd -unfilled -offset indent
|
||||
./configure --with-config=/etc/finit.conf
|
||||
.Ed
|
||||
Useful when starting up in various rescue mode, factory, or
|
||||
production test setups. Use the top-level configuration file
|
||||
directive
|
||||
.Cm rcsd Ar /path/to/finit.d
|
||||
to override the default rcS.d directory.
|
||||
.It Cm finit.debug
|
||||
Enable Finit debug messages on system console and log. Sometimes useful
|
||||
when doing board bringup. Before the system log daemon has started,
|
||||
Finit use the kernel ring buffer,
|
||||
.Pa /dev/kmsg .
|
||||
.It Cm finit.fstab=/path/to/fstab.alt
|
||||
Tell
|
||||
.Nm
|
||||
to use an alternate
|
||||
.Cm fstab
|
||||
to mount the file system from. Remember, this file must be on the
|
||||
.Cm root=...
|
||||
file system provided to Finit from the kernel. If this file is missing,
|
||||
.Nm
|
||||
falls back to its built-in default, which can be changed at build time
|
||||
using the
|
||||
.Cm --with-fstab=/path/to/footab
|
||||
configure option. It is even possible to completely disable the
|
||||
built-in using
|
||||
.Cm --without-fstab ,
|
||||
meaning
|
||||
.Nm
|
||||
.Sy must
|
||||
be started with the
|
||||
.Cm finit.fstab
|
||||
option.
|
||||
.Pp
|
||||
Should
|
||||
.Nm
|
||||
discover that there is no fstab file available, including the fallback,
|
||||
it triggers the same failure mode as when
|
||||
.Cm fsck
|
||||
fails, starting
|
||||
.Xr sulogin 8 ,
|
||||
if that is availble. When
|
||||
.Cm sulogin
|
||||
is missing, or when the user exits from
|
||||
.Cm sulogin ,
|
||||
the system is rebooted.
|
||||
.Pp
|
||||
Default fstab, unless changed at build-time:
|
||||
.Pa /etc/fstab
|
||||
.It Cm finit.status=<on,off>
|
||||
Control finit boot progress, including banner. This used to be called
|
||||
.Cm finit.show_status ,
|
||||
which still works but is deprecated.
|
||||
.It Cm finit.status_style=<classic,modern>
|
||||
Set Finit boot progress style, when enabled.
|
||||
.It Cm loglevel=<0-7>
|
||||
set the kernel's log level, which is more granular than
|
||||
.Cm debug .
|
||||
Also, when
|
||||
.Cm loglevel=7 ,
|
||||
Finit will
|
||||
.Em not disable
|
||||
kernel logs to the console. This is very useful when debugging the
|
||||
kernel at system bring-up. Since
|
||||
.Cm loglevel=7
|
||||
is the same as
|
||||
.Cm debug
|
||||
this means you have to use
|
||||
.Cm quiet
|
||||
for a quiet boot, until sysklogd takes over logging of kernel events.
|
||||
.It Cm panic=SEC
|
||||
By default the kernel does not reboot after a kernel panic. This
|
||||
setting will cause a kernel reboot after
|
||||
.Ar SEC
|
||||
seconds.
|
||||
.It Cm quiet
|
||||
Suppress kernel logging to console, except for warnings and errors.
|
||||
Also, see
|
||||
.Cm loglevel
|
||||
and
|
||||
.Cm quiet
|
||||
above.
|
||||
.It Cm rescue | recover
|
||||
Start rescue/maintenance mode. If your system comes with the bundled
|
||||
.Cm sulogin
|
||||
program (Finit, or from util-linux/Busybox), you will be given a root
|
||||
login to a maintenance shell. However, if
|
||||
.Cm sulogin
|
||||
is missing, the file
|
||||
.Pa /lib/finit/rescue.conf
|
||||
is read and the system booted in a limited fallback mode. See
|
||||
.Xr finit.conf 5
|
||||
for more information.
|
||||
.It Cm single | S
|
||||
Single user mode, runlevel 1, in Finit. Useful to debug problems with
|
||||
the regular runlevel. All services and TTYs in
|
||||
.Cm [1]
|
||||
will be started, e.g., a
|
||||
.Cm tty [1] @console nologin
|
||||
configuration presents you with a root console without login.
|
||||
.Pp
|
||||
.Sy Note:
|
||||
by definition, single user mode does not have networking enabled. This
|
||||
is also true for runlevel 1.
|
||||
.El
|
||||
.Sh BOOTING
|
||||
.Pp
|
||||
Before laucnhing services, the system needs to be bootstrapped. This
|
||||
involves mounting all filesystems (not already mounted by an initramfs)
|
||||
in
|
||||
.Pa /etc/fstab ,
|
||||
or any alternate
|
||||
.Pa fstab
|
||||
file provided on the Finit command line using
|
||||
.Cm finit.fstab ,
|
||||
ensuring that necessary filesystems like:
|
||||
.Pa /dev ,
|
||||
.Pa /proc ,
|
||||
.Pa /sys ,
|
||||
and
|
||||
.Pa /run
|
||||
are available and can provide the system with the services required.
|
||||
.Pp
|
||||
With that out of the way, a set of plugins take over:
|
||||
.Pp
|
||||
.Bl -tag -width bootmisc.so -offset indent
|
||||
.It Cm bootmisc.so
|
||||
Cleans up stale files from previous boots and default directories are
|
||||
created in tmpfs filesystems
|
||||
.It Cm modprobe.so
|
||||
Probes kernel modules required by the system
|
||||
.It Cm procps.so
|
||||
Set kernel variables from
|
||||
.Pa /etc/sysctl.conf
|
||||
et al
|
||||
.El
|
||||
.Pp
|
||||
When the plugins are done, finit reads
|
||||
.Pa /etc/finit.conf
|
||||
and all other enabled services in
|
||||
.Pa /etc/finit.d/* .
|
||||
First all services, run/tasks in runlevel S (bootStrap) are started,
|
||||
When all run/tasks have completed, Finit changes to the configured
|
||||
runlevel (default 2), Processes are started in parallel, in dependency
|
||||
order according to their conditions.
|
||||
.Pp
|
||||
When all services and run/tasks have been started, the console progress
|
||||
is disabled and all configured getty services are started.
|
||||
.Sh CONDITIONS
|
||||
The condition subysystem in Finit was initially created to track PID
|
||||
files of daemons. If service/task B requires service A to have started,
|
||||
Finit waits for the PID file of service A to be created/updated before
|
||||
it starts service B. Conversely, if service A is stopped and its PID
|
||||
file removed, service B is also stopped.
|
||||
.Pp
|
||||
The following condition families are available today:
|
||||
.Pp
|
||||
.Bl -tag -width service -offset indent
|
||||
.It Cm net
|
||||
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
||||
net/et0/running
|
||||
.It Cm pid
|
||||
PID files basd on the service declaration
|
||||
.Cm name:id ,
|
||||
gives the condition pid/name:id
|
||||
.It Cm service
|
||||
Tracks run/task/service state stansitions, including readiness. E.g.,
|
||||
.Cm service/foo/ready
|
||||
can be used as a condition for service
|
||||
.Cm bar ,
|
||||
provided
|
||||
.Cm foo
|
||||
properly signals its readiness to Finit.
|
||||
.It Cm sys
|
||||
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
||||
.It Cm usr
|
||||
User conditions, assert and deassert using
|
||||
.Cm initctl cond [set|clr] foo
|
||||
.El
|
||||
.Sh SIGNALS
|
||||
PID 1 is the only process that by default blocks all signals. Finit
|
||||
allows for the following signals to control operation, but recommends
|
||||
instead using the
|
||||
.Xr initctl 8
|
||||
tool.
|
||||
.Pp
|
||||
.Bl -tag -width TERM
|
||||
.It HUP
|
||||
Tell
|
||||
.Nm
|
||||
to reload its configuration file(s), same as
|
||||
.Cm initctl reload
|
||||
.It USR1
|
||||
Restart API
|
||||
.Cm ( initctl )
|
||||
socket.
|
||||
.It USR2
|
||||
Tell
|
||||
.Nm
|
||||
to perform a system shutdown, same as
|
||||
.Cm initctl poweroff
|
||||
.It TERM
|
||||
Like SIGUSR2 but performs a reboot, same as
|
||||
.Cm initctl reboot
|
||||
.It INT
|
||||
Sent from kernel when Ctrl-Alt-Del is pressed (on the console), this
|
||||
asserts the sys/key/ctrlaltdel condition, which can be used to start
|
||||
tasks or services
|
||||
.It PWR
|
||||
Sent from a a power daemon on changes to UPS status, Finit asserts
|
||||
the sys/pwr/fail condition
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||
.It Pa /etc/finit.conf
|
||||
Main configuration file
|
||||
.It Pa /etc/finit.d/*.conf
|
||||
Static service definitions
|
||||
.It Pa /etc/finit.d/available/*.conf
|
||||
Available services
|
||||
.It Pa /etc/finit.d/enabled/*.conf
|
||||
Symlinks from available
|
||||
.It Pa /run/finit/
|
||||
Runtime files, including the condition subsystem
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr finit.conf 5
|
||||
.Xr initctl 8
|
||||
.Xr tmpfiles.d 5
|
||||
.Sh AUTHORS
|
||||
.Nm
|
||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||
maintained by Joachim Wiberg, with contributions by many others.
|
||||
@@ -1,965 +0,0 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.Dd Apr 24, 2023
|
||||
.Dt FINIT.CONF 5 SMM
|
||||
.Os Linux
|
||||
.Sh NAME
|
||||
.Nm finit.conf
|
||||
.Nd Finit configuration file format
|
||||
.Sh SYNOPSIS
|
||||
.Nm /etc/finit.conf
|
||||
.Nm /etc/finit.d/*.conf
|
||||
.Nm /etc/finit.d/available/*.conf
|
||||
.Sh DESCRIPTION
|
||||
.Nm finit
|
||||
can be configured using only the original
|
||||
.Pa /etc/finit.conf
|
||||
file or in combination with
|
||||
.Pa /etc/finit.d/*.conf .
|
||||
Useful for package-based Linux distributions \(em each package can
|
||||
provide its own "script" file.
|
||||
.Pp
|
||||
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
|
||||
.It Pa /etc/finit.conf
|
||||
Main configuration file
|
||||
.It Pa /etc/finit.d/*.conf
|
||||
Snippets, usually one service per file
|
||||
.El
|
||||
.Pp
|
||||
Not all configuration directives are available in
|
||||
.Pa /etc/finit.d/*.conf
|
||||
and some directives are only available at bootstrap, runlevel
|
||||
.Cm S ,
|
||||
see the section
|
||||
.Sx Limitations
|
||||
below for details.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||
.It Pa /etc/finit.conf
|
||||
Main configuration file
|
||||
.It Pa /etc/finit.d/*.conf
|
||||
Static service definitions
|
||||
.It Pa /etc/finit.d/available/*.conf
|
||||
Available services
|
||||
.It Pa /etc/finit.d/enabled/*.conf
|
||||
Enabled services, symlinks from available
|
||||
.El
|
||||
.Sh FILE FORMAT
|
||||
The file format is line based, empty lines and comments, lines starting
|
||||
with `#', are ignored. A configuration directive starts with a keyword
|
||||
followed by a space and the rest of the line is treated as the value.
|
||||
.Pp
|
||||
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||
lines using the continuation character `\\', and trailing comments are
|
||||
also allowed. Example:
|
||||
.Bd -unfilled -offset indent
|
||||
# Escape \\# chars if you want them literal in, e.g., descriptions
|
||||
service name:sysklogd [S123456789] \\
|
||||
env:-/etc/default/sysklogd \\
|
||||
syslogd -F $SYSLOGD_ARGS \\
|
||||
-- System log daemon \\# 1 # Comments allowed now
|
||||
.Ed
|
||||
.Sh DIRECTIVES
|
||||
This section lists all supported configuration directives. There also exist
|
||||
deprecated directives, see the Markdown documentation for details on these.
|
||||
.Pp
|
||||
.Bl -tag -width 1n
|
||||
.It Cm rlimit Oo hard|soft Oc Ar RESOURCE Aq LIMIT | unlimited
|
||||
.Pp
|
||||
Set the hard or soft limit for a resource, or both if that argument is
|
||||
omitted.
|
||||
.Ar RESOURCE
|
||||
is the lower-case
|
||||
.Cm RLIMIT_
|
||||
string constants from
|
||||
.Xr setrlimit 2 ,
|
||||
without prefix. E.g. to set
|
||||
.Cm RLIMIT_CPU ,
|
||||
use
|
||||
.Cm cpu .
|
||||
.Pp
|
||||
.Ar LIMIT
|
||||
is an integer that depends on the resource being modified, see
|
||||
the man page, or the kernel
|
||||
.Pa /proc/PID/limits
|
||||
file, for details.
|
||||
Finit versions before v3.1 used
|
||||
.Cm infinity
|
||||
for
|
||||
.Cm unlimited ,
|
||||
which is still supported, albeit deprecated.
|
||||
.Bd -unfilled -offset indent
|
||||
# No process is allowed more than 8MB of address space
|
||||
rlimit hard as 8388608
|
||||
|
||||
# Core dumps may be arbitrarily large
|
||||
rlimit soft core infinity
|
||||
|
||||
# CPU limit for all services, soft & hard = 10 sec
|
||||
rlimit cpu 10
|
||||
.Ed
|
||||
.Pp
|
||||
.Cm rlimit
|
||||
can be set globally, in
|
||||
.Pa /etc/finit.conf ,
|
||||
or locally per each
|
||||
.Pa /etc/finit.d/*.conf
|
||||
read. I.e., a set of task/run/service stanzas can share the same
|
||||
rlimits if they are in the same .conf.
|
||||
.It Cm runlevel Aq N
|
||||
The system runlevel to go to after bootstrap (S) has completed.
|
||||
.Cm N
|
||||
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
halt. All other can be used by operating system administrators.
|
||||
Default: 2
|
||||
.Pp
|
||||
It s recommended to keep runlevel 1 as single-user mode, because
|
||||
.Nm
|
||||
disables networking in this mode.
|
||||
.Pp
|
||||
.Sy Note:
|
||||
only read and executed in runlevel S (bootstrap).
|
||||
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description.
|
||||
.Pp
|
||||
.Cm run
|
||||
commands are guaranteed to be completed before running the next
|
||||
command. Highly useful if true serialization is needed. Usually
|
||||
only used in the bootstrap (S) runlevel.
|
||||
.Pp
|
||||
.Cm Aq COND
|
||||
conditions are described in
|
||||
.Xr finit 8 ,
|
||||
see also the
|
||||
.Sx Examples
|
||||
section below.
|
||||
.It Cm task Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||
One-shot like
|
||||
.Cm run ,
|
||||
but starts in parallel with the next command.
|
||||
.Pp
|
||||
Both
|
||||
.Cm run
|
||||
and
|
||||
.Cm task
|
||||
commands are run in a shell, so pipes and redirects can be freely used:
|
||||
.Bd -unfilled -offset indent
|
||||
task [s] echo "foo" | cat >/tmp/bar
|
||||
.Ed
|
||||
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
||||
Similar to
|
||||
.Cm task
|
||||
is the
|
||||
.Cm sysv
|
||||
stanza, which can be used to call SysV style start/stop scripts. The
|
||||
primary intention for this command is to be able to re-use much of
|
||||
existing setup and init scripts in Linux distributions.
|
||||
.Pp
|
||||
When entering an allowed runlevel, Finit calls
|
||||
.Cm init-script start ,
|
||||
when entering a disallowed runlevel, Finit calls
|
||||
.Cm init-script stop ,
|
||||
and if the Finit .conf, where the
|
||||
.Cm sysv
|
||||
stanza is declared, is modified, Finit calls
|
||||
.Cm init-script restart
|
||||
on
|
||||
.Cm initctl reload .
|
||||
Similar to how
|
||||
.Cm service
|
||||
stanzas work.
|
||||
.Pp
|
||||
Forking services started with
|
||||
.Cm sysv
|
||||
scripts can be monitored by Finit by declaring the PID file to look for:
|
||||
.Bd -unfilled -offset indent
|
||||
sysv pid:!/path/to/pidfile.pid /path/to/script ...
|
||||
.Ed
|
||||
.Pp
|
||||
The leading '!' is to prevent Finit from managing the PID file, which is
|
||||
the default behavior for the
|
||||
.Cm pid:
|
||||
command modifier.
|
||||
.It Cm service Oo LVLS Oc Ao COND Ac Ar /path/to/daemon ARGS Op -- Optional description
|
||||
Service, or daemon, to be monitored and automatically restarted if it
|
||||
exits prematurely. Finit tries to restart services that die, by
|
||||
default 10 times, before giving up and marking them as
|
||||
.Em crashed .
|
||||
After which they have to be restarted manually using
|
||||
.Cm initctl restart NAME .
|
||||
The number of restarts, the delay between each restart, and more is
|
||||
configurable, see the options below.
|
||||
.Pp
|
||||
.Bd -filled -offset indent
|
||||
.Sy Tip:
|
||||
to allow endless restarts, see below option
|
||||
.Cm respawn
|
||||
.Ed
|
||||
.Pp
|
||||
For daemons that support it, we recommend appending
|
||||
.Cm --foreground , --no-background , -n , -F ,
|
||||
or similar command line argument to prevent them from forking off a
|
||||
sub-process in the background. This is the most reliable way to monitor
|
||||
a service.
|
||||
.Pp
|
||||
However, not all daemons support running in the foreground, or they may
|
||||
start logging to the foreground as well, these are called forking
|
||||
services and are supported using the same syntax as forking
|
||||
.Cm sysv
|
||||
services, using the
|
||||
.Cm pid:!/path/to/pidfile.pid
|
||||
command modifier syntax. There is an alternative syntax that may be
|
||||
more intuitive, where Finit can also guess the PID file based on the
|
||||
daemon's command name:
|
||||
.Bd -unfilled -offset indent
|
||||
service type:forking ntpd -- NTP daemon
|
||||
.Ed
|
||||
.Pp
|
||||
Here we let BusyBox
|
||||
.Nm ntpd
|
||||
daemonize itself. Finit uses the basename of the binary to guess the
|
||||
PID file to watch for the PID:
|
||||
.Pa /var/run/ntpd.pid .
|
||||
If Finit guesses wrong, you have to submit the full
|
||||
.Cm pid:!/path/to/file.pid
|
||||
option to your service stanza.
|
||||
.Pp
|
||||
.Sy Example: in the case of
|
||||
.Cm ospfd
|
||||
(below), we omit the
|
||||
.Cm -d
|
||||
flag (daemonize) to prevent it from forking to the background:
|
||||
.Bd -unfilled -offset indent
|
||||
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
|
||||
.Ed
|
||||
.Pp
|
||||
.Cm [2345]
|
||||
denote the runlevels
|
||||
.Cm ospfd
|
||||
is allowed to run in, they are optional and default to runlevel 2-5 if
|
||||
omitted.
|
||||
.Pp
|
||||
.Cm <pid/zebra>
|
||||
is the condition for starting
|
||||
.Cm ospfd .
|
||||
In this example Finit waits for another service,
|
||||
.Cm zebra ,
|
||||
to have created its PID file in
|
||||
.Pa /var/run/quagga/zebra.pid
|
||||
before starting
|
||||
.Cm ospfd .
|
||||
Finit watches *all* files in
|
||||
.Pa /var/run ,
|
||||
for each file named
|
||||
.Cm *.pid ,
|
||||
.Cm */pid ,
|
||||
Finit opens it and find the matching
|
||||
.Cm NAME:ID
|
||||
using the PID.
|
||||
.Pp
|
||||
Some services do not maintain a PID file and rather than patching each
|
||||
application Finit provides a workaround. A
|
||||
.Cm pid
|
||||
modifier keyword can be set to have Finit automatically create (when
|
||||
starting) and later remove (when stopping) the PID file. The file is
|
||||
created in the
|
||||
.Pa /var/run
|
||||
directory using the
|
||||
.Xr basename 3
|
||||
of the service. The full syntax of the
|
||||
.Cm pid
|
||||
modifier is:
|
||||
.Bd -unfilled -offset indent
|
||||
pid[:[!][/path/to/]filename[.pid]]
|
||||
.Ed
|
||||
.Pp
|
||||
For example, by adding
|
||||
.Cm pid:/run/foo.pid
|
||||
to the service
|
||||
.Cm /sbin/bar ,
|
||||
that PID file will, not only be created and removed automatically, but
|
||||
also be used by the Finit condition subsystem. So a service/run/task
|
||||
can depend on the
|
||||
.Cm <pid/bar>
|
||||
condition.
|
||||
.Pp
|
||||
As an alternative "readiness" notification, Finit supports both systemd
|
||||
and s6 style notification. This can be enabled by using the `notify`
|
||||
option:
|
||||
.Bl -tag -width 1n
|
||||
.It Cm notify:systemd
|
||||
tells Finit the service uses the
|
||||
.Cm sd_notify()
|
||||
API to signal PID 1 when it has completed its startup and is ready
|
||||
to service events. This API expects
|
||||
the environment variable
|
||||
.Cm NOTIFY_SOCKET
|
||||
to be set to the socket where the application can send
|
||||
.Cm "READY=1\n"
|
||||
when it is starting up or has processed a
|
||||
.Cm SIGHUP .
|
||||
For details, see:
|
||||
.Pp
|
||||
.Lk https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
.It Cm notify:s6
|
||||
puts Finit in s6 compatibility mode. Compared to the systemd
|
||||
notification, s6 expect compliant daemons to send
|
||||
.Cm "\\n"
|
||||
and then close their socket. For details, see:
|
||||
.Pp
|
||||
.Lk https://skarnet.org/software/s6/notifywhenup.html
|
||||
.Pp
|
||||
Finit takes care of "hard-wiring" the READY state as long as the
|
||||
application is running, events across any `SIGHUP`. Since s6 can give
|
||||
its applications the descriptor number (must be >3) on then command
|
||||
line, Finit provides the following syntax (
|
||||
.Cm %n
|
||||
is replaced by Finit with then descriptor number):
|
||||
.Bd -unfilled -offset indent
|
||||
service notify:s6 mdevd -C -O 4 -D %n
|
||||
.Ed
|
||||
.Pp
|
||||
When a service is ready, either by Finit detecting its PID file, or
|
||||
their respective readiness mechanism has been triggered, Finit creates
|
||||
then service's ready condition which other services can depend on:
|
||||
.Bd -unfilled -offset indent
|
||||
$ initctl -v cond get service/mdevd/ready
|
||||
on
|
||||
.Ed
|
||||
.El
|
||||
.Pp
|
||||
If a service should not be automatically started, it can be configured
|
||||
as manual with the
|
||||
.Cm manual:yes
|
||||
command modifier. The service can then be started at any time by
|
||||
running
|
||||
.Cm initctl start NAME
|
||||
.Pp
|
||||
The name of a service, shown by the
|
||||
.Cm initctl
|
||||
tool, defaults to the basename of the service executable. It can be
|
||||
changed with the
|
||||
.Cm name:foo
|
||||
command modifier.
|
||||
.Pp
|
||||
As mentioned previously, services are automatically restarted should
|
||||
they crash, this is configurable with the following options:
|
||||
.Bl -tag -width 1n
|
||||
.It Cm restart:NUM
|
||||
number of times Finit tries to restart a crashing
|
||||
service, default: 10. When this limit is reached the service is
|
||||
marked
|
||||
.Em crashed
|
||||
and must be restarted manually with
|
||||
.Xr initctl 8 .
|
||||
.It Cm restart_sec:SEC
|
||||
number of seconds before Finit tries to restart
|
||||
a crashing service, default: 2 seconds for the first five retries,
|
||||
then back-off to 5 seconds. The maximum of this configured value
|
||||
and the above (2 and 5) will be used
|
||||
.It Cm restart:always
|
||||
no upper limit on the number of times Finit tries to restart a crashing
|
||||
service. Same as
|
||||
.Cm restart:-1
|
||||
.It Cm norestart
|
||||
dont restart on failures, same as
|
||||
.Cm restart:0
|
||||
.It Cm respawn
|
||||
bypasses the
|
||||
.Cm restart
|
||||
mechanism completely, allows endless restarts. Useful in many
|
||||
use-cases, but not what
|
||||
.Cm service
|
||||
was originally designed for so not the default behavior.
|
||||
.It Cm oncrash:reboot
|
||||
when all retries have failed, and the service
|
||||
has
|
||||
.Em crashed ,
|
||||
if this option is set the system is rebooted.
|
||||
.It Cm oncrash:script
|
||||
Similar to
|
||||
.Cm oncrash:reboot ,
|
||||
but instead of rebooting this action calls the
|
||||
.Cm post:script
|
||||
(see below) to let the operator decide the best course of action. If
|
||||
the post:script option is not set, this is a no-op.
|
||||
.Pp
|
||||
The post:script is called with the same environment variables
|
||||
.Sy except
|
||||
for the
|
||||
.Cm EXIT_CODE
|
||||
variable which is set to
|
||||
.Cm "crashed" .
|
||||
.El
|
||||
.Pp
|
||||
When stopping a service (run/task/sysv/service), either manually or when
|
||||
moving to another runlevel, Finit starts by sending SIGTERM, to allow
|
||||
the process to shut down gracefully. If the process has not been
|
||||
collected within 3 seconds, Finit sends SIGKILL. To halt the process
|
||||
using a different signal, use the command modifier
|
||||
.Cm halt:SIGNAL ,
|
||||
e.g.,
|
||||
.Cm halt:SIGPWR .
|
||||
To change the delay between your halt signal and KILL, use the command
|
||||
modifier
|
||||
.Cm kill:SEC ,
|
||||
e.g.,
|
||||
.Cm kill:10
|
||||
to wait 10 seconds before sending SIGKILL.
|
||||
.Pp
|
||||
Services support the
|
||||
.Cm pre:script
|
||||
and
|
||||
.Cm post:script
|
||||
command actions as well. These run as the same
|
||||
.Cm @USER:GROUP
|
||||
as the service itself, with any
|
||||
.Cm env:file
|
||||
sourced. The scripts must use an absolute path, but are executed from
|
||||
the
|
||||
.Cm $HOME
|
||||
of the given user. The scripts are not called with any argument
|
||||
(currently), but both get the
|
||||
.Cm SERVICE_IDENT=foo
|
||||
environment variable set. Here
|
||||
.Cm foo
|
||||
denotes the identity of the service, which if there are multiple
|
||||
services named
|
||||
.Cm foo ,
|
||||
may be
|
||||
.Cm foo:1 ,
|
||||
or any unique identifier specified in the .conf file. The
|
||||
.Cm post:script
|
||||
is called with an additional set of environment variables:
|
||||
.Bl -tag -offset indent -width 1n
|
||||
.It Cm EXIT_CODE=[exited,signal,crashed]
|
||||
set to one of
|
||||
.Cm exited ,
|
||||
.Cm signal ,
|
||||
or
|
||||
.Cm crashed
|
||||
(see above).
|
||||
.It Cm EXIT_STATUS=[num,SIGNAME]
|
||||
set to one of exit status code from the program, if it exited normally,
|
||||
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
||||
.El
|
||||
.Pp
|
||||
The scripts have a default execution time of 3 seconds before they are
|
||||
SIGKILLed, this can be adjusted using the
|
||||
.Cm kill:SEC
|
||||
modifier syntax.
|
||||
.It Cm runparts Aq DIR
|
||||
Call
|
||||
.Xr run-parts 8
|
||||
on
|
||||
.Cm DIR
|
||||
to run start scripts. All executable files, or scripts, in the
|
||||
directory are called, in alphabetic order. The scripts in this
|
||||
directory are executed at the very end of bootstrap, runlevel S.
|
||||
.Pp
|
||||
It can be beneficial to use
|
||||
.Cm S01name ,
|
||||
.Cm S02othername ,
|
||||
etc. if there is a dependency order between the scripts. Symlinks to
|
||||
existing daemons can talso be used, but make sure they daemonize by
|
||||
default.
|
||||
.Pp
|
||||
Similar to the
|
||||
.Pa /etc/rc.local
|
||||
shell script, make sure that all your services and programs either
|
||||
terminate or start in the background or you will block Finit.
|
||||
.Sy Note:
|
||||
only read and executed in runlevel S (bootstrap).
|
||||
.It Cm include Aq CONF
|
||||
Include another configuration file. Absolute path required.
|
||||
.It Cm log size:BYTES count:NUM
|
||||
Log rotation for run/task/services using the
|
||||
.Cm log
|
||||
command modifier with redirection to a log file. Global setting,
|
||||
applies to all services.
|
||||
.Pp
|
||||
The size can be given as bytes, without a specifier, or in `k`, `M`,
|
||||
or `G`, e.g.
|
||||
.Cm size:10M ,
|
||||
or
|
||||
.Cm size:3G .
|
||||
A value of
|
||||
.Cm size:0
|
||||
disables log rotation. The default is
|
||||
.Cm size:200k .
|
||||
.Pp
|
||||
The count value is recommended to be between 1-5, with a default 5.
|
||||
Setting count to 0 means the logfile will be truncated when the MAX
|
||||
size limit is reached.
|
||||
.It Cm tty Oo LVLS Oc Ao COND Ac Ar DEV Oo BAUD Oc Oo noclear Oc Oo nowait Oc Oo nologin Oc Oo TERM Oc
|
||||
This form of the
|
||||
.Cm tty
|
||||
stanza uses the built-in getty on the given TTY device
|
||||
.Ar DEV ,
|
||||
in the given runlevels.
|
||||
.Ar DEV may be the special keyword
|
||||
.Cm @console ,
|
||||
or `console`, which is expanded from `/sys/class/tty/console/active`,
|
||||
useful on embedded systems.
|
||||
.Pp
|
||||
The default baud rate is 0, i.e., keep kernel default.
|
||||
.Pp
|
||||
The `tty` stanza inherits runlevel, condition (and other feature)
|
||||
parsing from the `service` stanza. So TTYs can run in one or many
|
||||
runlevels and depend on any condition supported by Finit. This is
|
||||
useful e.g. to depend on `<pid/elogind>` before starting a TTY.
|
||||
.Bd -unfilled -offset indent
|
||||
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||
.Ed
|
||||
.It Cm tty Oo LVLS Oc Ao COND Ac Ar CMD DEV Oo noclear Oc Oo nowait Oc
|
||||
This form of the
|
||||
.Cm tty
|
||||
stanza is for using an external getty, like agetty or the BusyBox getty.
|
||||
.Pp
|
||||
By default, these first two syntax variants
|
||||
.Em clear
|
||||
the TTY and
|
||||
.Em wait
|
||||
for the user to press enter before starting getty.
|
||||
.Bd -unfilled -offset indent
|
||||
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
||||
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm noclear
|
||||
option disables clearing the TTY after each session. Clearing the TTY
|
||||
when a user logs out is usually preferable.
|
||||
.Pp
|
||||
The
|
||||
.Cm nowait
|
||||
option disables the
|
||||
.Cm Please press Enter to activate console
|
||||
message before actually starting the getty program. On small and
|
||||
embedded systems running multiple unused getty wastes both memory and
|
||||
CPU cycles, so `wait` is the preferred default.
|
||||
.Pp
|
||||
The
|
||||
.Cm nologin
|
||||
option disables getty and
|
||||
.Pa /bin/login ,
|
||||
and gives the user a root (login) shell on the given TTY
|
||||
.Cm DEV
|
||||
immediately. Needless to say, this is a rather insecure option, but can
|
||||
be very useful for developer builds, during board bringup, or similar.
|
||||
.Pp
|
||||
Notice the ordering, the
|
||||
.Cm TERM
|
||||
option to the built-in getty must be the last argument.
|
||||
.Pp
|
||||
Embedded systems may want to enable automatic `DEV` by supplying the
|
||||
special
|
||||
.Cm @console
|
||||
device. This works regardless weather the system uses
|
||||
.Cm ttyS0 , ttyAMA0 , ttyMXC0 ,
|
||||
or anything else. Finit figures it out by querying sysfs:
|
||||
.Pa /sys/class/tty/console/active .
|
||||
The speed can be omitted to keep the kernel default.
|
||||
.Pp
|
||||
Most systems get by fine by just using `console`, which will evaluate
|
||||
to
|
||||
.Pa /dev/console .
|
||||
If you have to use
|
||||
.Cm @console
|
||||
to get any output, you may have some issue with your kernel config.
|
||||
.Bd -unfilled -offset indent
|
||||
tty [12345] @console noclear vt220
|
||||
.Ed
|
||||
.Pp
|
||||
On really bare bones systems, or for board bringup, Finit can give you a
|
||||
shell prompt as soon as bootstrap is done, without opening any device
|
||||
node:
|
||||
.Bd -unfilled -offset indent
|
||||
tty [12345789] notty
|
||||
.Ed
|
||||
.Pp
|
||||
This should of course not be enabled on production systems. Because it
|
||||
may give a user root access without having to log in. However, for
|
||||
board bringup and system debugging it can come in handy.
|
||||
.Pp
|
||||
One can also use the
|
||||
.Cm service
|
||||
stanza to start a stand-alone shell:
|
||||
.Bd -unfilled -offset indent
|
||||
service [12345] /bin/sh -l
|
||||
.Ed
|
||||
.Pp
|
||||
.It Cm tty Oo LVLS Oc Ao COND Ac Oo notty Oc Oo rescue Oc
|
||||
The third
|
||||
.Cm tty
|
||||
form is for board bringup and the
|
||||
.Cm rescue
|
||||
boot mode. No device node is required in this variant, the same output
|
||||
that the kernel uses is reused for stdio. If the
|
||||
.Cm rescue
|
||||
option is omitted, a shell is started. The flags
|
||||
.Cm nologin , noclear ,
|
||||
and
|
||||
.Cm nowait
|
||||
are implied. If the
|
||||
.Cm rescue
|
||||
option is set the bundled
|
||||
.Pa /libexec/finit/sulogin
|
||||
is started to present a bare-bones root login prompt. If the root
|
||||
(uid:0, gid:0) user does not have a password set, no rescue is possible.
|
||||
.El
|
||||
.Sh COMMAND MODIFIERS
|
||||
The run/task/tty/service/sysv stanzas take modifiers, or options, to
|
||||
control their behavior. This section lists them with their limitations.
|
||||
All modifiers must be placed between the stanza and its command.
|
||||
.Bl -tag -width 1n
|
||||
.It Cm @user:group
|
||||
Every
|
||||
.Cm run , task ,
|
||||
or
|
||||
.Cm service
|
||||
can also list the privileges the
|
||||
.Cm /path/to/cmd
|
||||
should be executed with. Prefix the command with
|
||||
.Cm @USR[:GRP] ,
|
||||
group is optional, like this:
|
||||
.Bd -unfilled -offset indent
|
||||
run [2345] @joe:users logger "Hello world"
|
||||
.Ed
|
||||
.Pp
|
||||
For multiple instances of the same command, e.g. a DHCP client or
|
||||
multiple web servers, add
|
||||
.Cm :ID
|
||||
somewhere between the
|
||||
.Cm run , task , service
|
||||
keyword and the command, like this:
|
||||
.Bd -unfilled -offset indent
|
||||
service :80 [2345] httpd -f -h /http -p 80 -- Web server
|
||||
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
|
||||
.Ed
|
||||
.Pp
|
||||
Without the
|
||||
.Cm :ID
|
||||
to the service the latter will overwrite the former and only the old web
|
||||
server would be started and supervised.
|
||||
.It Cm log:/path/to/file
|
||||
Redirect stdout/stderr of a command to the given log file. See the
|
||||
global log directive, above, for details on log rotation.
|
||||
.It Cm log:console
|
||||
Redirect stdout/stderr of a command to
|
||||
.Pa /dev/console ,
|
||||
only use this for debugging or bringup.
|
||||
.It Cm log:null
|
||||
Redirect stdout/stderr of a command to
|
||||
.Pa /dev/null .
|
||||
.It Cm log:prio:facility.level,tag:ident
|
||||
Redirect stdout/stderr of a command to syslog using the given priority
|
||||
and tag identity.
|
||||
.Bd -unfilled -offset indent
|
||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||
.Ed
|
||||
.It Cm log
|
||||
Default
|
||||
.Cm prio
|
||||
is
|
||||
.Cm daemon.info
|
||||
and the default
|
||||
.Cm tag
|
||||
identity is the basename of the service or run/task command.
|
||||
.El
|
||||
.Sh RESCUE MODE
|
||||
Finit supports a rescue mode which is activated by the
|
||||
.Cm rescue
|
||||
option on the kernel command line. The rescue mode comes in two
|
||||
flavors:
|
||||
.Em traditional
|
||||
and
|
||||
.Em fallback .
|
||||
.Ss Traditional
|
||||
This is what most users expect. A very early maintenance login prompt,
|
||||
served by the bundled
|
||||
.Pa /libexec/finit/sulogin
|
||||
program, or the standard
|
||||
.Cm sulogin
|
||||
from util-linux or BusyBox is searched for in the UNIX default
|
||||
.Cm $PATH .
|
||||
If a successful login is made, or the user exits (Ctrl-D), the rescue
|
||||
mode is ended and the system boots up normally.
|
||||
.Pp
|
||||
.Sy Note:
|
||||
if the user (UID 0 and GID 0) does not have a password, or
|
||||
.Em the account is locked ,
|
||||
the user is presented with a password-less prompt:
|
||||
.Cm "Press enter to enter maintenance mode." ,
|
||||
which opens up a root shell.
|
||||
.Ss Fallback
|
||||
If no
|
||||
.Cm sulogin
|
||||
program is found, Finit tries to bring up as much of its own
|
||||
functionality as possible, yet limiting many aspects, meaning; no
|
||||
network, no`fsck` of file systems in
|
||||
.Pa /etc/fstab ,
|
||||
no
|
||||
.Pa /etc/rc.local ,
|
||||
no
|
||||
.Cm runparts ,
|
||||
and most plugins are skipped (except those that provide functionality
|
||||
for the condition subsystem).
|
||||
.Pp
|
||||
Instead of reading
|
||||
.Pa /etc/finit.conf
|
||||
et al, system configuration is read from
|
||||
.Pa /lib/finit/rescue.conf ,
|
||||
which can be freely modified by the system administrator.
|
||||
.Pp
|
||||
The bundled default `rescue.conf` contains nothing more than:
|
||||
.Bd -unfilled -offset indent
|
||||
runlevel 1
|
||||
tty [12345] rescue
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Cm tty
|
||||
has the
|
||||
.Cm rescue
|
||||
option set, which works similar to the board bring-up tty option
|
||||
.Cm notty .
|
||||
The major difference being that `sulogin` is started to query for
|
||||
root/admin password. If
|
||||
.Cm sulogin
|
||||
is not found,
|
||||
.Cm rescue
|
||||
behaves like
|
||||
.Cm notty
|
||||
and gives a plain root shell prompt.
|
||||
.Pp
|
||||
If Finit cannot find
|
||||
.Pa /lib/finit/rescue.conf
|
||||
it defaults to:
|
||||
.Bd -unfilled -offset indent
|
||||
tty [12345] rescue
|
||||
.Ed
|
||||
.Pp
|
||||
There is no way to exit the
|
||||
.Em fallback
|
||||
rescue mode.
|
||||
.Sh SERVICE ENVIRONMENT
|
||||
Finit supports sourcing environment variables from
|
||||
.Pa /etc/default/* ,
|
||||
or similar. This is a common pattern from SysV init scripts, where the
|
||||
start/stop script is a generic script for the given service,
|
||||
.Cm foo ,
|
||||
and the options for the service are sourced from the file
|
||||
.Pa /etc/default/foo .
|
||||
Like this:
|
||||
.Bd -unfilled -offset indent
|
||||
/etc/default/foo:
|
||||
|
||||
FOO_OPTIONS=--extra-arg="bar" -s -x
|
||||
|
||||
/etc/finit.conf:
|
||||
|
||||
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
|
||||
.Ed
|
||||
.Pp
|
||||
Here the service
|
||||
.Cm foo
|
||||
is started with
|
||||
.Op Fl -n ,
|
||||
to make sure it runs in the foreground, and the with the options found
|
||||
in the environment file. With the
|
||||
.Cm ps
|
||||
command we can see that the process is started with:
|
||||
.Bd -unfilled -offset indent
|
||||
foo -n --extra-arg=bar -s -x
|
||||
.Ed
|
||||
.Pp
|
||||
.Sy Note:
|
||||
the leading `-` determines if Finit should treat a missing environment
|
||||
file as blocking the start of the service or not. When `-` is used, a
|
||||
missing environment file does
|
||||
.Em not
|
||||
block the start.
|
||||
.Sh SERVICE WRAPPER SCRIPTS
|
||||
If your service requires to run additional commands, executed before the
|
||||
service is actually started, like the systemd `ExecStartPre`, you can
|
||||
use a wrapper shell script to start your service.
|
||||
.Pp
|
||||
The Finit service
|
||||
.Cm .conf
|
||||
file can be put into
|
||||
.Pa /etc/finit.d/available ,
|
||||
so you can control the service using
|
||||
.Cm initctl .
|
||||
Then use the path to the wrapper script in the Finit
|
||||
.Cm .conf
|
||||
service stanza. The following example employs a wrapper script in
|
||||
.Pa /etc/start.d .
|
||||
.Bd -unfilled
|
||||
/etc/finit.d/available/program.conf:
|
||||
|
||||
service [235] <!> /etc/start.d/program -- Example Program
|
||||
|
||||
/etc/start.d/program:
|
||||
|
||||
#!/bin/sh
|
||||
# Prepare the command line options
|
||||
OPTIONS="-u $(cat /etc/username)"
|
||||
|
||||
# Execute the program
|
||||
exec /usr/bin/program $OPTIONS
|
||||
.Ed
|
||||
.Pp
|
||||
.Sy Note:
|
||||
the example sets
|
||||
.Cm <!>
|
||||
to denote that it doesn't support SIGHUP. That way Finit will
|
||||
stop/start the service instead of sending SIGHUP at restart/reload
|
||||
events.
|
||||
.Sh TEMPLATING
|
||||
Finit comes with rudimentary support for templating, similar to that of
|
||||
systemd. Best illustrated with an example:
|
||||
.Bd -unfilled -offset indent
|
||||
$ initctl show avahi-autoipd@
|
||||
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||
.Ed
|
||||
.Pp
|
||||
To enable ZeroConf for, e.g.,
|
||||
.Cm eth0 ,
|
||||
use
|
||||
.Bd -unfilled -offset indent
|
||||
$ initctl enable avahi-autoipd@eth0.conf
|
||||
.Ed
|
||||
.Pp
|
||||
The enabled symlink will be set up to
|
||||
.Cm avahi-autoipd@.conf
|
||||
and every instance of
|
||||
.Cm %i
|
||||
will in the instantiated directive be replaced with
|
||||
.Cm eth0 .
|
||||
Inspect the result with:
|
||||
.Bd -unfilled -offset indent
|
||||
$ initctl status avahi-autoipd:eth0
|
||||
.Ed
|
||||
.Sh CGROUPS
|
||||
There are three major cgroup configuration directives:
|
||||
.Pp
|
||||
.Bl -enum -offset indent -compact
|
||||
.It
|
||||
Global top-level group: init, system, user, or a custom group
|
||||
.It
|
||||
Selecting a top-level group for a set of run/task/services
|
||||
.It
|
||||
Per run/task/service limits
|
||||
.El
|
||||
.Pp
|
||||
Top-level group configuration.
|
||||
.Bd -unfilled -offset indent
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
cgroup init cpu.weight:100
|
||||
cgroup user cpu.weight:100
|
||||
cgroup system cpu.weight:9800
|
||||
.Ed
|
||||
.Pp
|
||||
Adding an extra cgroup
|
||||
.Cm maint/
|
||||
will require you to adjust the weight of the above three. We leave
|
||||
.Cm init/
|
||||
and
|
||||
.Cm user/
|
||||
as-is reducing weight of
|
||||
.Cm system/
|
||||
to 9700.
|
||||
.Bd -unfilled -offset indent
|
||||
cgroup system cpu.weight:9700
|
||||
|
||||
# Example extra cgroup 'maint'
|
||||
cgroup maint cpu.weight:100
|
||||
.Ed
|
||||
.Pp
|
||||
By default, the
|
||||
.Cm system/
|
||||
cgroup is selected for almost everything. The
|
||||
.Cm init/
|
||||
cgroup is reserved for PID 1 itself and its closest relatives. The
|
||||
.Cm user/
|
||||
cgroup is for local TTY logins spawned by getty.
|
||||
.Pp
|
||||
To select a different top-level cgroup, e.g.
|
||||
.Cm maint/ ,
|
||||
one can either define it for a group of run/task/service directives in a
|
||||
.Cm .conf
|
||||
or per each stanza:
|
||||
.Bd -unfilled -offset indent
|
||||
cgroup.maint
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
.Ed
|
||||
.Pp
|
||||
or
|
||||
.Bd -unfilled -offset indent
|
||||
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||
.Ed
|
||||
.Pp
|
||||
The latter form also allows per-stanza limits on the form:
|
||||
.Bd -unfilled -offset indent
|
||||
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||
.Ed
|
||||
.Pp
|
||||
Notice the comma separation and the
|
||||
.Cm mem.
|
||||
exception to the rule: every cgroup setting maps directly to cgroup v2
|
||||
syntax. I.e.,
|
||||
.Cm cpu.max
|
||||
maps to the file
|
||||
.Pm /sys/fs/cgroup/maint/foo/cpu.max .
|
||||
There is no filtering, except for expanding the shorthand
|
||||
.Cm mem.
|
||||
to
|
||||
.Cm memory. ,
|
||||
if the file is not available, either the cgroup controller is not
|
||||
available in your Linux kernel, or the name is misspelled.
|
||||
.Pp
|
||||
Linux cgroups and details surrounding values are not explained in the
|
||||
Finit documentation. The Linux admin-guide cover this well:
|
||||
.Lk https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||
.Sh LIMITATIONS
|
||||
As of Finit v4 there are no limitations to where
|
||||
.Cm .conf
|
||||
settings can be placed. Except for the system/global
|
||||
.Cm rlimit
|
||||
and
|
||||
.Cm cgroup
|
||||
top-level group declarations, which can only be set from
|
||||
.Pa /etc/finit.conf ,
|
||||
since it is the first
|
||||
.Cm .conf
|
||||
file Finit reads.
|
||||
.Pp
|
||||
Originally,
|
||||
.Pp /etc/finit.conf
|
||||
was the only way to set up a Finit system. Today it is mainly used for
|
||||
bootstrap settings like system hostname, early module loading for
|
||||
watchdogd, network bringup and system shutdown. These can now also be
|
||||
set in any
|
||||
.Cm .conf
|
||||
file in
|
||||
.Pa /etc/finit.d .
|
||||
.Pp
|
||||
There is, however, nothing preventing you from having all configuration
|
||||
settings in
|
||||
.Pa /etc/finit.conf .
|
||||
.Sh SEE ALSO
|
||||
.Xr finit 8 ,
|
||||
.Xr initctl 8
|
||||
.Sh AUTHORS
|
||||
.Nm finit
|
||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||
maintained by Joachim Wiberg, with contributions by many others.
|
||||
-272
@@ -1,272 +0,0 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.Dd June 6, 2021
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.Dt INITCTL 8 SMM
|
||||
.Os Linux
|
||||
.Sh NAME
|
||||
.Nm initctl
|
||||
.Nd Control tool for Finit
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/initctl
|
||||
.Op Fl bcfhjlpqtvV
|
||||
.Op COMMAND
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the official tool for interacting with
|
||||
.Xr finit 8 .
|
||||
It comes with functions for showing status, querying health of services,
|
||||
as well as editing, enabling and disabling services.
|
||||
.Sh OPTIONS
|
||||
This program follows the usual UNIX command line syntax, with long
|
||||
options starting with two dashes (`-'). The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b, -batch
|
||||
Batch mode, no screen size probing. Useful for scripting.
|
||||
.It Fl c, -create
|
||||
Create missing paths (and files) as needed. Useful with the
|
||||
.Cm edit
|
||||
command.
|
||||
.It Fl f, -force
|
||||
Ignore missing files and arguments, never prompt.
|
||||
.It Fl h, -help
|
||||
Show built-in help text.
|
||||
.It Fl j, -json
|
||||
JSON output in
|
||||
.Ar status
|
||||
and
|
||||
.Ar cond
|
||||
commands.
|
||||
.It Fl n, -noerr
|
||||
When scripting
|
||||
.Nm
|
||||
to stop, start, restart, or signal a task or service, this option can be
|
||||
used to ignore error 69 (no such task or service) and instead return 0
|
||||
(OK).
|
||||
.It Fl 1, -once
|
||||
Only one lap in commands like top.
|
||||
.It Fl p, -plain
|
||||
Use plain table headings, no ANSI control characters.
|
||||
.It Fl q, -quiet
|
||||
Silent, only return status of command.
|
||||
.It Fl t, -no-heading
|
||||
Skip table headings.
|
||||
.It Fl v, -verbose
|
||||
Verbose output, where applicable.
|
||||
.It Fl V, -version
|
||||
Show program version.
|
||||
.El
|
||||
.Sh COMMANDS
|
||||
.Bl -tag -width Ds
|
||||
.It Nm Ar debug
|
||||
Toggle
|
||||
.Nm finit
|
||||
(daemon) debug to
|
||||
.Pa /dev/console
|
||||
.It Nm Ar help
|
||||
Show built-in help text.
|
||||
.It Nm Ar version
|
||||
Show program version.
|
||||
.It Nm Ar ls | list
|
||||
List all
|
||||
.Cm *.conf
|
||||
files in
|
||||
.Pa /etc/finit.d
|
||||
.It Nm Ar create Ar CONF
|
||||
Create
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available .
|
||||
.Pp
|
||||
Piping the contents into
|
||||
.Nm
|
||||
works as one would expect:
|
||||
.Bd -literal -offset indent
|
||||
echo "task name:foo /tmp/foo.sh -- Foo logger" | initctl create foo
|
||||
initctl enable foo
|
||||
initctl reload
|
||||
.Ed
|
||||
.It Nm Ar delete Ar CONF
|
||||
Delete
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available
|
||||
.It Nm Ar show Ar CONF
|
||||
Show
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available
|
||||
.It Nm Ar edit Ar CONF
|
||||
Edit
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available
|
||||
.It Nm Ar touch Ar CONF
|
||||
Change (mark as modified)
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available ,
|
||||
like
|
||||
.Ar edit
|
||||
this tells
|
||||
.Nm finit
|
||||
that a configuration has been changed and is a candidate to be restarted
|
||||
(or SIGHUP'ed) on
|
||||
.Cm initctl reload
|
||||
.It Nm Ar enable Ar CONF
|
||||
Enable
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available ,
|
||||
i.e., add symlink in
|
||||
.Pa /etc/finit.d/enabled
|
||||
.It Nm Ar disable Ar CONF
|
||||
Disable
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/enabled ,
|
||||
i.e., removes symlink.
|
||||
.It Nm Ar reload
|
||||
Reload
|
||||
.Cm *.conf in
|
||||
.Pa /etc/finit.d ,
|
||||
i.e., activates changes.
|
||||
.It Nm Ar cond set Ar COND Op COND ...
|
||||
Set (assert) user-defined condition,
|
||||
.Cm +usr/COND
|
||||
.It Nm Ar cond get Ar COND
|
||||
Get (quietly) the status of any condition. Defaults to user-defined
|
||||
condions, but if a slash is detected, e.g.,
|
||||
.Cm pid/foo
|
||||
or
|
||||
.Cm net/eth0/exist ,
|
||||
then any condition can be read.
|
||||
.Pp
|
||||
The command is geared for scripting, check the exit code to get the
|
||||
status of the condition: 0 - on, 1 - off, 255 - flux. For a more
|
||||
verbose output, use the
|
||||
.Fl v
|
||||
option.
|
||||
.It Nm Ar cond clr | clear Ar COND Op COND ...
|
||||
Clear (deassert) user-defined condition,
|
||||
.Cm -usr/COND
|
||||
.It Nm Ar cond status
|
||||
Show condition status, default
|
||||
.Cm cond
|
||||
command. Also supports the
|
||||
.Fl j
|
||||
option for detailed JSON output.
|
||||
.It Nm Ar cond dump Op Cm TYPE
|
||||
Dump all, or a given type of, conditions and their status. Also
|
||||
supports the
|
||||
.Fl j
|
||||
option for detailed JSON output.
|
||||
.It Nm Ar ident Op Cm NAME
|
||||
Display indentities of all run/task/services, or only instances
|
||||
matching
|
||||
.Cm NAME .
|
||||
A partial string, e.g.,
|
||||
.Cm NAM ,
|
||||
will not match anything.
|
||||
.It Nm Ar log Op Cm NAME
|
||||
Show ten last Finit, or
|
||||
.Cm NAME ,
|
||||
messages from syslog.
|
||||
.It Nm Ar start Cm NAME[:ID]
|
||||
Start service by name, with optional ID, e.g.,
|
||||
.Cm initctl start tty:1
|
||||
.It Nm Ar stop Cm NAME[:ID]
|
||||
Stop/Pause a running service by name.
|
||||
.It Nm Ar reload Cm NAME[:ID]
|
||||
Reload service as if its configuration had changed. Internally,
|
||||
.Nm finit
|
||||
marks the named service as "dirty" and turns the state machine,
|
||||
resulting in a SIGHUP or restart of (at least) the named service.
|
||||
Any dependant services are also restarted.
|
||||
.Pp
|
||||
.Sy Note:
|
||||
no .conf file is reloaded with this variant of the command. Essentially
|
||||
it is the same as calling
|
||||
.Cm restart .
|
||||
Except for two things:
|
||||
.Bl -enum -offset indent -compact
|
||||
.It
|
||||
if the service supports HUP, it's signaled instead of stop-started, and
|
||||
.It
|
||||
it allows restarting run/task in the same runlevel -- which is otherwise
|
||||
restricted.
|
||||
.El
|
||||
.It Nm Ar signal Cm NAME:[ID] S
|
||||
Send signal S to service, by name.
|
||||
.Cm S
|
||||
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
|
||||
.It Nm Ar restart Cm NAME[:ID]
|
||||
Restart (stop/start) service by name.
|
||||
.It Nm Ar status Cm NAME[:ID]
|
||||
Show service status, by name. If only
|
||||
.Cm NAME
|
||||
is given and multiple instances exits, a summary of all matching
|
||||
instances are shown. Only an exact match displays detailed status
|
||||
for a given instance.
|
||||
.Pp
|
||||
With the
|
||||
.Fl q
|
||||
option this command is silent, provided the
|
||||
.Ar NAME[:ID]
|
||||
selection matches a single run/task/service. The exit code of
|
||||
.Nm
|
||||
is non-zero if there is a problem. Zero is returned if a run/task has
|
||||
run (at least) once in the current runlevel, and when a service is running
|
||||
(as expected). See the
|
||||
.Fl j
|
||||
option for detailed JSON output suitable for machine parsing.
|
||||
.Pp
|
||||
.Sy Tip:
|
||||
.Xr jq 1
|
||||
is a useful scripting tool in combination with JSON output.
|
||||
.It Nm Ar status
|
||||
Show status of all services, default command. Also supports the
|
||||
.Fl j
|
||||
option for detailed JSON output.
|
||||
.It Nm Ar cgroup
|
||||
List cgroup config overview.
|
||||
.It Nm Ar ps
|
||||
List processes based on cgroups.
|
||||
.It Nm Ar top
|
||||
Show top-like listing based on cgroups.
|
||||
.It Nm Ar plugins
|
||||
List installed plugins.
|
||||
.It Nm Ar runlevel Op Ar 0-9
|
||||
Show or set runlevel: 0 halt, 6 reboot.
|
||||
.It Nm Ar reboot
|
||||
Reboot system, default if
|
||||
.Cm reboot
|
||||
is symlinked to
|
||||
.Nm .
|
||||
.It Nm Ar halt
|
||||
Halt system, default if
|
||||
.Cm halt
|
||||
is symlinked to
|
||||
.Nm .
|
||||
.It Nm Ar poweroff
|
||||
Power-off system, default if
|
||||
.Cm poweroff
|
||||
is symlinked to
|
||||
.Nm .
|
||||
.It Nm Ar suspend
|
||||
Suspend system, default if
|
||||
.Cm suspend
|
||||
is symlinked to
|
||||
.Nm .
|
||||
.It Nm Ar utmp show
|
||||
Raw dump of UTMP/WTMP db.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr finit.conf 5
|
||||
.Xr finit 8
|
||||
.Sh AUTHORS
|
||||
.Nm finit
|
||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||
maintained by Joachim Wiberg, with contributions by many others.
|
||||
+10
-42
@@ -1,13 +1,13 @@
|
||||
pkglibdir = $(plugin_path)
|
||||
AM_LDFLAGS = -module -avoid-version -shared
|
||||
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS += -D__FINIT__ $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c pidfile.c procps.c sys.c usr.c
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -17,12 +17,12 @@ if BUILD_DBUS_PLUGIN
|
||||
libplug_la_SOURCES += dbus.c
|
||||
endif
|
||||
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
libplug_la_SOURCES += modules-load.c
|
||||
if BUILD_HOTPLUG_PLUGIN
|
||||
libplug_la_SOURCES += hotplug.c
|
||||
endif
|
||||
|
||||
if BUILD_MODPROBE_PLUGIN
|
||||
libplug_la_SOURCES += modprobe.c
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
libplug_la_SOURCES += modules-load.c
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
@@ -33,24 +33,8 @@ if BUILD_RESOLVCONF_PLUGIN
|
||||
libplug_la_SOURCES += resolvconf.c
|
||||
endif
|
||||
|
||||
if BUILD_RTC_PLUGIN
|
||||
libplug_la_SOURCES += rtc.c
|
||||
endif
|
||||
|
||||
if BUILD_TTY_PLUGIN
|
||||
libplug_la_SOURCES += tty.c
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
libplug_la_SOURCES += urandom.c
|
||||
endif
|
||||
|
||||
if BUILD_X11_COMMON_PLUGIN
|
||||
libplug_la_SOURCES += x11-common.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la pidfile.la procps.la sys.la usr.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
@@ -60,18 +44,14 @@ if BUILD_DBUS_PLUGIN
|
||||
pkglib_LTLIBRARIES += dbus.la
|
||||
endif
|
||||
|
||||
if BUILD_HOOK_SCRIPTS_PLUGIN
|
||||
pkglib_LTLIBRARIES += hook-scripts.la
|
||||
if BUILD_HOTPLUG_PLUGIN
|
||||
pkglib_LTLIBRARIES += hotplug.la
|
||||
endif
|
||||
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
pkglib_LTLIBRARIES += modules-load.la
|
||||
endif
|
||||
|
||||
if BUILD_MODPROBE_PLUGIN
|
||||
pkglib_LTLIBRARIES += modprobe.la
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
pkglib_LTLIBRARIES += netlink.la
|
||||
endif
|
||||
@@ -80,18 +60,6 @@ if BUILD_RESOLVCONF_PLUGIN
|
||||
pkglib_LTLIBRARIES += resolvconf.la
|
||||
endif
|
||||
|
||||
if BUILD_RTC_PLUGIN
|
||||
pkglib_LTLIBRARIES += rtc.la
|
||||
endif
|
||||
|
||||
if BUILD_TTY_PLUGIN
|
||||
pkglib_LTLIBRARIES += tty.la
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
pkglib_LTLIBRARIES += urandom.la
|
||||
endif
|
||||
|
||||
if BUILD_X11_COMMON_PLUGIN
|
||||
pkglib_LTLIBRARIES += x11-common.la
|
||||
endif
|
||||
|
||||
+4
-19
@@ -1,6 +1,6 @@
|
||||
/* Save and restore ALSA sound settings using alsactl
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,12 +21,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include <lite/lite.h>
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
@@ -35,26 +30,16 @@
|
||||
|
||||
static void save(void *arg)
|
||||
{
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (whichp(ALSACTL)) {
|
||||
dbg("Saving sound settings ...");
|
||||
_d("Saving sound settings ...");
|
||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||
}
|
||||
}
|
||||
|
||||
static void restore(void *arg)
|
||||
{
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (whichp(ALSACTL)) {
|
||||
dbg("Restoring sound settings ...");
|
||||
_d("Restoring sound settings ...");
|
||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||
}
|
||||
}
|
||||
|
||||
+97
-74
@@ -1,6 +1,6 @@
|
||||
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,35 +21,24 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ftw.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "tmpfiles.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
static int is_tmpfs(char *path)
|
||||
{
|
||||
struct mntent mount;
|
||||
struct mntent *mnt;
|
||||
char buf[256];
|
||||
int tmpfs = 0;
|
||||
FILE *fp;
|
||||
char *dir;
|
||||
struct mntent *mnt;
|
||||
|
||||
/* If path is a symlink, check what it resolves to */
|
||||
dir = realpath(path, NULL);
|
||||
@@ -62,7 +51,7 @@ static int is_tmpfs(char *path)
|
||||
return 0; /* Dunno, maybe not */
|
||||
}
|
||||
|
||||
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(dir, mnt->mnt_dir))
|
||||
break;
|
||||
}
|
||||
@@ -76,25 +65,19 @@ static int is_tmpfs(char *path)
|
||||
return tmpfs;
|
||||
}
|
||||
|
||||
static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||
static int do_clean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||
{
|
||||
if (ftw->level == 0)
|
||||
return 1;
|
||||
|
||||
dbg("Removing %s ...", fpath);
|
||||
_d("Removing %s ...", fpath);
|
||||
(void)remove(fpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup stale files from previous boot, if any still linger on.
|
||||
* Some systems, e.g. Alpine Linux, still have a persistent /run and
|
||||
* /tmp, i.e. not tmpfs.
|
||||
*
|
||||
* We can safely skip tmpfs, nothing to clean there.
|
||||
*/
|
||||
static void clean(void *arg)
|
||||
/* We can safely skip tmpfs, nothing to clean from previous boot there */
|
||||
static void bootclean(void)
|
||||
{
|
||||
char *dir[] = {
|
||||
"/tmp/",
|
||||
@@ -107,46 +90,7 @@ static void clean(void *arg)
|
||||
if (is_tmpfs(dir[i]))
|
||||
continue;
|
||||
|
||||
nftw(dir[i], bootclean, 20, FTW_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Kernel defines the following compulsory and recommended links
|
||||
* https://github.com/torvalds/linux/blob/v5.18/Documentation/admin-guide/devices.rst#compulsory-links
|
||||
*/
|
||||
static void kernel_links(void)
|
||||
{
|
||||
struct {
|
||||
char *tgt, *lnk;
|
||||
int optional;
|
||||
} k[] = {
|
||||
{ "/proc/self/fd", "/dev/fd", 0 },
|
||||
{ "fd/0", "/dev/stdin", 0 },
|
||||
{ "fd/1", "/dev/stdout", 0 },
|
||||
{ "fd/2", "/dev/stderr", 0 },
|
||||
{ "socksys", "/dev/nfsd", 0 },
|
||||
{ "null", "/dev/X0R", 0 },
|
||||
{ "/proc/kcore", "/dev/core", 1 },
|
||||
{ "ram0", "/dev/ramdisk", 1 },
|
||||
{ "qft0", "/dev/ftape", 1 },
|
||||
{ "video0", "/dev/bttv0", 1 },
|
||||
{ "radio0", "/dev/radio", 1 },
|
||||
};
|
||||
char *fn, buf[80];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NELEMS(k); i++) {
|
||||
fn = k[i].tgt;
|
||||
|
||||
if (k[i].optional) {
|
||||
if (fn[0] != '/') {
|
||||
snprintf(buf, sizeof(buf), "/dev/%s", k[i].tgt);
|
||||
fn = buf;
|
||||
}
|
||||
if (!fexist(fn))
|
||||
continue;
|
||||
}
|
||||
ln(k[i].tgt, k[i].lnk);
|
||||
nftw(dir[i], do_clean, 20, FTW_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,26 +99,105 @@ static void kernel_links(void)
|
||||
*/
|
||||
static void setup(void *arg)
|
||||
{
|
||||
mode_t prev;
|
||||
int uid, gid;
|
||||
|
||||
prev = umask(0);
|
||||
/* Cleanup stale files, if any still linger on. */
|
||||
bootclean();
|
||||
|
||||
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */
|
||||
kernel_links();
|
||||
_d("Setting up FHS structure in /var ...");
|
||||
umask(0);
|
||||
makedir("/var/cache", 0755);
|
||||
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
||||
makedir("/var/games", 0755);
|
||||
makedir("/var/lib", 0755);
|
||||
makedir("/var/lib/misc", 0755); /* _PATH_VARDB on some systems */
|
||||
makedir("/var/lib/alarm", 0755);
|
||||
makedir("/var/lib/urandom",0755);
|
||||
if (fisdir("/run")) {
|
||||
_d("System with new /run tmpfs ...");
|
||||
makedir("/run/lock", 1777);
|
||||
symlink("/run/lock", "/var/lock");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
|
||||
/* Create all system tmpfiles.d(5) */
|
||||
tmpfilesd();
|
||||
/* compat only, should really be set up by OS/dist */
|
||||
symlink("/run", "/var/run");
|
||||
} else {
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
}
|
||||
makedir("/var/log", 0755);
|
||||
makedir("/var/mail", 0755);
|
||||
makedir("/var/opt", 0755);
|
||||
makedir("/var/spool", 0755);
|
||||
makedir("/var/spool/cron", 0755);
|
||||
makedir("/var/tmp", 0755);
|
||||
makedir("/var/empty", 0755);
|
||||
|
||||
/*
|
||||
* If /etc/group or "utmp" group is missing,
|
||||
* default to "root"/"wheel" group
|
||||
*/
|
||||
_d("Setting up necessary UTMP files ...");
|
||||
gid = getgroup("utmp");
|
||||
if (gid < 0)
|
||||
gid = 0;
|
||||
|
||||
/*
|
||||
* UTMP actually needs multiple db files
|
||||
*/
|
||||
if (has_utmp()) {
|
||||
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
||||
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
||||
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
||||
create("/var/log/lastlog", 0644, 0, gid);
|
||||
}
|
||||
|
||||
/* Set BOOT_TIME UTMP entry */
|
||||
utmp_set_boot();
|
||||
|
||||
umask(prev);
|
||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
touch("/etc/network/run/ifstate");
|
||||
#else
|
||||
erase("/etc/network/run/ifstate");
|
||||
#endif
|
||||
|
||||
_d("Setting up misc files ...");
|
||||
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
||||
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
||||
makedir("/var/run/frr", 0755); /* Needed by FRR */
|
||||
makedir("/var/log/frr", 0755); /* Needed by FRR */
|
||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
|
||||
gid = getgroup("tty");
|
||||
if (gid < 0)
|
||||
gid = 0;
|
||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||
chown("/dev/xconsole", 0, gid);
|
||||
|
||||
if (!fexist("/etc/mtab"))
|
||||
symlink("../proc/self/mounts", "/etc/mtab");
|
||||
|
||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||
uid = getuser("uuidd", NULL);
|
||||
if (uid >= 0) {
|
||||
gid = getgroup("uuidd");
|
||||
if (gid < 0)
|
||||
gid = 0;
|
||||
makedir("/var/run/uuidd", 0755);
|
||||
chown("/var/run/uuidd", uid, gid);
|
||||
}
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_MOUNT_POST] = { .cb = clean },
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = setup },
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
.depends = { "pidfile" },
|
||||
};
|
||||
|
||||
|
||||
+25
-118
@@ -1,6 +1,6 @@
|
||||
/* Setup and start system message bus, D-Bus
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,11 +22,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "config.h"
|
||||
@@ -35,136 +31,47 @@
|
||||
#include "service.h"
|
||||
#include "conf.h"
|
||||
|
||||
#define DBUS_DAEMON "dbus-daemon"
|
||||
#define DBUS_ARGS "--nofork --system --syslog-only"
|
||||
#define DBUS_DESC "D-Bus message bus daemon"
|
||||
|
||||
#ifndef DBUS_DAEMONUSER
|
||||
#define DBUS_DAEMONUSER "messagebus"
|
||||
#endif
|
||||
|
||||
#ifndef DBUS_DAEMONGROUP
|
||||
#define DBUS_DAEMONGROUP "messagebus"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dumnpster diving for the D-Bus main configuration file
|
||||
* where <pidfile> is defined.
|
||||
*/
|
||||
static char *dbus_pidfn(void)
|
||||
{
|
||||
char *alt[] = {
|
||||
"/usr/share/dbus-1/system.conf",
|
||||
"/etc/dbus-1/system.conf",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; alt[i]; i++) {
|
||||
char *fn = alt[i];
|
||||
char buf[256];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(fn, "r");
|
||||
if (!fp)
|
||||
continue;
|
||||
|
||||
fn = NULL;
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
char *pos;
|
||||
|
||||
pos = strstr(buf, "<pidfile>");
|
||||
if (!pos)
|
||||
continue;
|
||||
fn = pos + strlen("<pidfile>");
|
||||
pos = strstr(fn, "</pidfile>");
|
||||
if (!pos) {
|
||||
fn = NULL;
|
||||
break;
|
||||
}
|
||||
*pos = 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fn)
|
||||
return strdup(fn);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#define DAEMON "dbus-daemon"
|
||||
#define ARGS "--nofork --system"
|
||||
#define DESC "D-Bus message bus daemon"
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
char *group = DBUS_DAEMONGROUP;
|
||||
char *user = DBUS_DAEMONUSER;
|
||||
char line[256];
|
||||
char *pidfn;
|
||||
mode_t prev;
|
||||
char *cmd;
|
||||
char line[256];
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = which(DBUS_DAEMON);
|
||||
cmd = which(DAEMON);
|
||||
if (!cmd) {
|
||||
dbg("Skipping plugin, %s is not installed.", DBUS_DAEMON);
|
||||
_d("Skipping plugin, %s is not installed.", DAEMON);
|
||||
return;
|
||||
}
|
||||
|
||||
if (getuser(user, NULL) == -1) {
|
||||
if (getuser("dbus", NULL) == -1)
|
||||
user = "root"; /* fallback */
|
||||
else
|
||||
user = "dbus"; /* e.g., Buildroot */
|
||||
}
|
||||
umask(0);
|
||||
|
||||
if (getgroup(group) == -1) {
|
||||
if (getgroup("dbus") == -1)
|
||||
group = "root"; /* fallback */
|
||||
else
|
||||
group = "dbus"; /* e.g., Buildroot */
|
||||
}
|
||||
makedir("/var/run/dbus", 0755);
|
||||
makedir("/var/lock/subsys", 0755);
|
||||
makedir("/var/lock/subsys/messagebus", 0755);
|
||||
if (whichp("dbus-uuidgen"))
|
||||
run("dbus-uuidgen --ensure");
|
||||
|
||||
/* Clean up from any previous pre-bootstrap run */
|
||||
pidfn = dbus_pidfn();
|
||||
if (pidfn)
|
||||
remove(pidfn);
|
||||
|
||||
dbg("Creating D-Bus Required Directories ...");
|
||||
prev = umask(0);
|
||||
mksubsys("/var/run/dbus", 0755, user, group);
|
||||
mksubsys("/var/run/lock/subsys", 0755, user, group);
|
||||
mksubsys("/var/lib/dbus", 0755, user, group);
|
||||
mksubsys("/tmp/dbus", 0755, user, group);
|
||||
umask(prev);
|
||||
|
||||
/* Generate machine id for dbus */
|
||||
if (whichp("dbus-uuidgen"))
|
||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||
|
||||
/*
|
||||
* Register service with Finit
|
||||
* Note: dbus drops privs after starting up.
|
||||
*/
|
||||
if (pidfn) {
|
||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus pid:!%s %s %s -- %s",
|
||||
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
||||
free(pidfn);
|
||||
} else
|
||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s",
|
||||
cmd, DBUS_ARGS, DBUS_DESC);
|
||||
erase("/var/run/dbus/pid");
|
||||
|
||||
/* Register service with Finit */
|
||||
snprintf(line, sizeof(line), "[S12345] pid:!/run/dbus/pid log:prio:daemon.info,tag:dbus %s %s -- %s", cmd, ARGS, DESC);
|
||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||
err(1, "Failed registering %s", DBUS_DAEMON);
|
||||
|
||||
_pe("Failed registering %s", DAEMON);
|
||||
free(cmd);
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_NETWORK_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
.depends = { "bootmisc", },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/* Trigger scripts to run from finit's hooks
|
||||
*
|
||||
* Copyright (c) 2022 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "config.h"
|
||||
|
||||
extern void plugin_script_run(hook_point_t no);
|
||||
|
||||
static void hscript_run_parts(hook_point_t no)
|
||||
{
|
||||
plugin_script_run(no);
|
||||
}
|
||||
|
||||
static void hscript_banner(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_BANNER);
|
||||
}
|
||||
|
||||
static void hscript_rootfs_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_ROOTFS_UP);
|
||||
}
|
||||
|
||||
static void hscript_mount_error(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_MOUNT_ERROR);
|
||||
}
|
||||
|
||||
static void hscript_mount_post(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_MOUNT_POST);
|
||||
}
|
||||
|
||||
static void hscript_basefs_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_BASEFS_UP);
|
||||
}
|
||||
|
||||
static void hscript_network_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_NETWORK_UP);
|
||||
}
|
||||
|
||||
static void hscript_svc_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_SVC_UP);
|
||||
}
|
||||
|
||||
static void hscript_system_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_SYSTEM_UP);
|
||||
}
|
||||
|
||||
static void hscript_shutdown(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_SHUTDOWN);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BANNER] = { .cb = hscript_banner },
|
||||
.hook[HOOK_ROOTFS_UP] = { .cb = hscript_rootfs_up },
|
||||
.hook[HOOK_MOUNT_ERROR] = { .cb = hscript_mount_error },
|
||||
.hook[HOOK_MOUNT_POST] = { .cb = hscript_mount_post },
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = hscript_basefs_up },
|
||||
.hook[HOOK_NETWORK_UP] = { .cb = hscript_network_up },
|
||||
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
||||
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
||||
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
||||
/*
|
||||
* We have exited here, so these are handled a bit differently by Finit,
|
||||
* when hook scripts are enabled, just to provide the user with the same
|
||||
* interface:
|
||||
*
|
||||
* .hook[HOOK_SVC_DN] = { .cb = hscript_svc_down },
|
||||
* .hook[HOOK_SYS_DN] = { .cb = hscript_system_down },
|
||||
*/
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,110 @@
|
||||
/* Heuristically find and initialize a suitable hotplug daemon
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "conf.h"
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
char cmd[256];
|
||||
char *path;
|
||||
|
||||
/*
|
||||
* Populate /dev and prepare for runtime events from kernel.
|
||||
* Prefer udev if mdev is also available on the system.
|
||||
*/
|
||||
path = which("udevd");
|
||||
if (!path)
|
||||
path = which("/lib/systemd/systemd-udevd");
|
||||
if (path) {
|
||||
/* Register udevd as a monitored service */
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
|
||||
"-- Device event managing daemon", path);
|
||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||
_pe("Failed registering %s", path);
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t devices "
|
||||
"-- Requesting device events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t subsystems "
|
||||
"-- Requesting subsystem events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
}
|
||||
|
||||
free(path);
|
||||
|
||||
/* Debian has this little script to copy generated
|
||||
* rules while the system was read-only. TODO: When
|
||||
* this functionality was hardcoded in finit.c, this
|
||||
* call was made in crank_worker(). Now that
|
||||
* filesystems are mounted earlier we should be able
|
||||
* to make this call directly after the triggers have
|
||||
* run, but this has not been tested AT ALL. */
|
||||
if (fexist("/lib/udev/udev-finish"))
|
||||
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
||||
} else {
|
||||
path = which("mdev");
|
||||
if (path) {
|
||||
/* Embedded Linux systems usually have BusyBox mdev */
|
||||
if (debug)
|
||||
touch("/dev/mdev.log");
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
||||
free(path);
|
||||
|
||||
run_interactive(cmd, "Populating device tree");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+15
-79
@@ -1,6 +1,6 @@
|
||||
/* Coldplug modules using modalias magic
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -40,15 +40,11 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h> /* gettimeofday() */
|
||||
#include <sys/types.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "util.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
struct module {
|
||||
@@ -71,14 +67,14 @@ static int modprobe(char *alias)
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
err(1, "Failed forking modprobe child");
|
||||
_pe("Failed forking modprobe child");
|
||||
return 1;
|
||||
case 0:
|
||||
execvp(args[0], args);
|
||||
break;
|
||||
default:
|
||||
if (!complete(args[0], pid))
|
||||
dbg("Successful modprobe of %s", alias);
|
||||
_d("Successful modprobe of %s", alias);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -106,7 +102,7 @@ static void alias_remove(struct module *m)
|
||||
TAILQ_REMOVE(&modules, m, link);
|
||||
free(m->alias);
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
static int alias_exist(char *alias)
|
||||
{
|
||||
@@ -120,87 +116,27 @@ static int alias_exist(char *alias)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void alias_add_uniq(char *alias)
|
||||
static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused)
|
||||
{
|
||||
if (alias_exist(alias))
|
||||
return;
|
||||
|
||||
alias_add(alias);
|
||||
}
|
||||
|
||||
static FILE *maybe_fopen_alias(const char *file, const char *path)
|
||||
{
|
||||
const char *basename;
|
||||
|
||||
basename = rindex(path, '/');
|
||||
if (!basename)
|
||||
return NULL;
|
||||
|
||||
basename++;
|
||||
if (strcmp(file, basename))
|
||||
return NULL;
|
||||
|
||||
return fopen(path, "r");
|
||||
}
|
||||
|
||||
static int scan_modalias(const char *path)
|
||||
{
|
||||
char buf[256];
|
||||
FILE *fp;
|
||||
char buf[256];
|
||||
|
||||
fp = maybe_fopen_alias("modalias", path);
|
||||
if (fnmatch("*/modalias", path, 0))
|
||||
return 0;
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
chomp(buf);
|
||||
alias_add_uniq(buf);
|
||||
if (!alias_exist(buf))
|
||||
alias_add(buf);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_uevent(const char *path)
|
||||
{
|
||||
char buf[256];
|
||||
FILE *fp;
|
||||
|
||||
fp = maybe_fopen_alias("uevent", path);
|
||||
if (!fp)
|
||||
return 1;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
if (strstr(buf, "MODALIAS=") != buf)
|
||||
continue;
|
||||
|
||||
chomp(buf);
|
||||
|
||||
alias_add_uniq(buf + strlen("MODALIAS="));
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_alias(const char *path, const struct stat *st,
|
||||
int flag, struct FTW *unused)
|
||||
{
|
||||
/* Sanity check: is this a regular file we can read? */
|
||||
if (!(S_ISREG(st->st_mode) && (st->st_mode & S_IRUSR)))
|
||||
return 0;
|
||||
|
||||
if (!scan_uevent(path))
|
||||
return 0;
|
||||
|
||||
scan_modalias(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void coldplug(void *arg)
|
||||
{
|
||||
struct module *m, *tmp;
|
||||
|
||||
+44
-169
@@ -21,37 +21,10 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This plugin scans files in /etc/modules-load.d/, for each line in the
|
||||
* file it assumes the name of a kernel module, with optional arguments.
|
||||
* Each module is loaded when entering runlevel 2, 3, 4, or 5, using the
|
||||
* modprobe tool.
|
||||
*
|
||||
* Loading is done by inserting a `task` stanza in Finit, ensuring all
|
||||
* modules are loaded in parallel, with other modules and programs.
|
||||
* Each `task` stanza is by default given the name:modprobe.module and
|
||||
* indexed with `:ID`, starting with 1.
|
||||
*
|
||||
* Indexing can be disabled per file in /etc/modules-load.d/, anywwhere
|
||||
* in a file, by putting the keyword `noindex` on a line of its own. A
|
||||
* noindex command can appear anywhere in the file, and up to the point
|
||||
* it is read, tasks will be indexed with an incrementing `:ID`. When
|
||||
* `noindex` is read indexing is disabled and all subseequent tasks will
|
||||
* not have any `:ID` at all.
|
||||
*
|
||||
* Please note, the :ID is there for your benefit, it ensures that tasks
|
||||
* in Finit are unique. If you have two tasks with the same name and ID
|
||||
* (or no ID), the last one read replaces any preceeding one!
|
||||
*/
|
||||
|
||||
#include <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"
|
||||
@@ -62,158 +35,60 @@
|
||||
#ifndef MODULES_LOAD_PATH
|
||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||
#endif
|
||||
#define MODPROBE_PATH "/sbin/modprobe"
|
||||
#define SERVICE_LINE \
|
||||
"cgroup.init name:modprobe.%s :%d [%s] %s %s %s --"
|
||||
#define SERVICE_LINE_NOINDEX \
|
||||
"cgroup.init name:modprobe.%s [%s] %s %s %s --"
|
||||
|
||||
static int modules_load(const char *file, int index)
|
||||
{
|
||||
char module_path[PATH_MAX];
|
||||
char *modprobe_path;
|
||||
int num = 0;
|
||||
char *line;
|
||||
char *lvl;
|
||||
FILE *fp;
|
||||
|
||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||
strlcat(module_path, file, sizeof(module_path));
|
||||
|
||||
fp = fopen(module_path, "r");
|
||||
if (!fp) {
|
||||
warnx("failed opening %s for reading, skipping ...", module_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
modprobe_path = strdup(MODPROBE_PATH);
|
||||
if (!modprobe_path) {
|
||||
fail:
|
||||
warnx("failed allocating memory in modules-load plugin.");
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lvl = strdup("S");
|
||||
if (!lvl) {
|
||||
free(modprobe_path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||
char cmd[CMD_SIZE * 2], *mod, *args, *set;
|
||||
|
||||
/*
|
||||
* fparseln() skips regular UNIX comments only.
|
||||
* This is for modules-load.d(5) compat.
|
||||
*/
|
||||
if (line[0] == ';')
|
||||
goto next;
|
||||
|
||||
/* trim whitespace */
|
||||
mod = strip_line(line);
|
||||
if (!mod[0])
|
||||
goto next;
|
||||
|
||||
/* Finit extension 'set foo bar' */
|
||||
if ((set = fgetval(mod, "set", "= \t"))) {
|
||||
char *val = mod;
|
||||
|
||||
if (!strcmp(set, "noindex")) {
|
||||
index = 0;
|
||||
free(set);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if ((val = fgetval(set, "index", "= \t"))) {
|
||||
index = atoi(val);
|
||||
free(set);
|
||||
free(val);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if ((val = fgetval(set, "runlevel", "= \t"))) {
|
||||
free(lvl);
|
||||
lvl = val;
|
||||
free(set);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if ((val = fgetval(set, "modprobe", "= \t"))) {
|
||||
if (access(val, X_OK)) {
|
||||
warn("%s: cannot use %s", module_path, val);
|
||||
free(set);
|
||||
free(val);
|
||||
free(line);
|
||||
goto skip;
|
||||
} else {
|
||||
free(modprobe_path);
|
||||
modprobe_path = val;
|
||||
}
|
||||
free(set);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* unknown 'set' command, ignore. */
|
||||
goto next;
|
||||
}
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
if (!mod)
|
||||
goto next;
|
||||
|
||||
if (!index)
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, lvl, modprobe_path, mod, args);
|
||||
else
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, lvl, modprobe_path, mod, args);
|
||||
|
||||
dbg("task %s", cmd);
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
num++;
|
||||
next:
|
||||
free(line);
|
||||
}
|
||||
skip:
|
||||
free(modprobe_path);
|
||||
free(lvl);
|
||||
fclose(fp);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/* XXX: check here for .conf only? */
|
||||
static int module_filter(const struct dirent *d)
|
||||
{
|
||||
if (d->d_type == DT_DIR)
|
||||
return 0;
|
||||
if (d->d_name[0] == '.')
|
||||
return 0; /* skip dot files */
|
||||
if (d->d_name[strlen(d->d_name) - 1] == '~')
|
||||
return 0; /* skip backup files */
|
||||
|
||||
return 1;
|
||||
}
|
||||
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
|
||||
static void load(void *arg)
|
||||
{
|
||||
struct dirent **dentry;
|
||||
FILE *fp;
|
||||
DIR *dirp;
|
||||
struct dirent *direntp;
|
||||
char line[256];
|
||||
int index = 1;
|
||||
int i, num;
|
||||
|
||||
dbg("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
|
||||
if (num > 0) {
|
||||
for (i = 0; i < num; i++) {
|
||||
index += modules_load(dentry[i]->d_name, index);
|
||||
free(dentry[i]);
|
||||
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||
|
||||
dirp = opendir(MODULES_LOAD_PATH);
|
||||
if (!dirp) return;
|
||||
|
||||
while ((direntp = readdir(dirp)))
|
||||
{
|
||||
char module_path[PATH_MAX];
|
||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||
strlcat(module_path, direntp->d_name, sizeof(module_path));
|
||||
|
||||
fp = fopen(module_path, "r");
|
||||
if (!fp) continue;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
char cmd[CMD_SIZE], *mod, *args;
|
||||
|
||||
mod = strip_line(line);
|
||||
if (!*mod) continue;
|
||||
|
||||
mod = chomp(mod);
|
||||
if (!mod || !*mod) continue;
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
||||
index, mod, mod, args, mod);
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
|
||||
index++;
|
||||
}
|
||||
free(dentry);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_SVC_PLUGIN] = { .cb = load },
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = load
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
|
||||
+80
-303
@@ -1,8 +1,7 @@
|
||||
|
||||
/* Netlink plugin for IFUP/IFDN and GW events
|
||||
*
|
||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||
* Copyright (C) 2009-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (C) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -18,7 +17,6 @@
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <sys/socket.h>
|
||||
@@ -31,87 +29,68 @@
|
||||
#include "cond.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
|
||||
#define NL_BUFSZ 4096
|
||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
||||
{
|
||||
if (!NLMSG_OK(nh, len))
|
||||
return 1;
|
||||
|
||||
struct nl_request {
|
||||
struct nlmsghdr nh;
|
||||
union {
|
||||
struct rtmsg rtm;
|
||||
struct ifinfomsg ifi;
|
||||
};
|
||||
};
|
||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
||||
_d("Done with netlink messages.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nl_defidx;
|
||||
static int nl_ifdown;
|
||||
static char *nl_buf;
|
||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
||||
_d("Netlink reports error.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
static void nl_route(struct nlmsghdr *nlmsg)
|
||||
{
|
||||
char daddr[INET_ADDRSTRLEN];
|
||||
char gaddr[INET_ADDRSTRLEN];
|
||||
struct in_addr ind, ing;
|
||||
struct rtmsg *r;
|
||||
struct rtattr *a;
|
||||
int plen = 0;
|
||||
int dst = 0;
|
||||
int idx = 0;
|
||||
int gw = 0;
|
||||
int la;
|
||||
int gw = 0, dst = 0, mask = 0, idx = 0;
|
||||
|
||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||
errx(1, "Packet too small or truncated!");
|
||||
_e("Packet too small or truncated!");
|
||||
return;
|
||||
}
|
||||
|
||||
r = NLMSG_DATA(nlmsg);
|
||||
a = RTM_RTA(r);
|
||||
la = RTM_PAYLOAD(nlmsg);
|
||||
if (la >= len) {
|
||||
errx(1, "Packet too large!");
|
||||
return;
|
||||
}
|
||||
|
||||
while (RTA_OK(a, la)) {
|
||||
void *data = RTA_DATA(a);
|
||||
|
||||
switch (a->rta_type) {
|
||||
case RTA_GATEWAY:
|
||||
gw = *((int *)data);
|
||||
//dbg("GW: 0x%04x", gw);
|
||||
//_d("GW: 0x%04x", gw);
|
||||
break;
|
||||
|
||||
case RTA_DST:
|
||||
dst = *((int *)data);
|
||||
plen = r->rtm_dst_len;
|
||||
//dbg("Prefix LEN: 0x%04x", plen);
|
||||
mask = r->rtm_dst_len;
|
||||
//_d("MASK: 0x%04x", mask);
|
||||
break;
|
||||
|
||||
case RTA_OIF:
|
||||
idx = *((int *)data);
|
||||
//dbg("IDX: 0x%04x", idx);
|
||||
//_d("IDX: 0x%04x", idx);
|
||||
break;
|
||||
}
|
||||
|
||||
a = RTA_NEXT(a, la);
|
||||
}
|
||||
|
||||
ind.s_addr = dst;
|
||||
ing.s_addr = gw;
|
||||
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
||||
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
||||
dbg("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
||||
|
||||
if ((!dst && !plen) && (gw || idx)) {
|
||||
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
||||
if ((!dst && !mask) && (gw || idx)) {
|
||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
||||
cond_clear("net/route/default");
|
||||
nl_defidx = 0;
|
||||
} else {
|
||||
else
|
||||
cond_set("net/route/default");
|
||||
nl_defidx = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,277 +105,83 @@ static void net_cond_set(char *ifname, char *cond, int set)
|
||||
cond_clear(msg);
|
||||
}
|
||||
|
||||
static int validate_ifname(const char *ifname)
|
||||
static void nl_link(struct nlmsghdr *nlmsg)
|
||||
{
|
||||
if (!ifname || !ifname[0])
|
||||
return 1;
|
||||
|
||||
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
|
||||
return 1;
|
||||
|
||||
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
|
||||
return 1;
|
||||
|
||||
while (*ifname) {
|
||||
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
|
||||
return 1;
|
||||
ifname++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this interface was associated with the default route
|
||||
* previously, or if it's been removed. If so, trigger a recheck
|
||||
* of the system default route.
|
||||
*/
|
||||
static void nl_check_default(char *ifname)
|
||||
{
|
||||
int idx = (int)if_nametoindex(ifname);
|
||||
|
||||
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
|
||||
nl_ifdown = 1;
|
||||
}
|
||||
|
||||
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
{
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
struct ifinfomsg *i;
|
||||
struct rtattr *a;
|
||||
int la;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
struct rtattr *a;
|
||||
struct ifinfomsg *i;
|
||||
|
||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||
errx(1, "Packet too small or truncated!");
|
||||
_e("Packet too small or truncated!");
|
||||
return;
|
||||
}
|
||||
|
||||
i = NLMSG_DATA(nlmsg);
|
||||
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
||||
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
||||
if (la >= len) {
|
||||
errx(1, "Packet too large!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (; RTA_OK(a, la); a = RTA_NEXT(a, la)) {
|
||||
if (a->rta_type != IFLA_IFNAME)
|
||||
continue;
|
||||
|
||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||
if (validate_ifname(ifname)) {
|
||||
dbg("Invalid interface name '%s', skipping ...", ifname);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (nlmsg->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
/*
|
||||
* New interface has appeared, or interface flags has changed.
|
||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||
*/
|
||||
dbg("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||
net_cond_set(ifname, "exist", 1);
|
||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
|
||||
nl_check_default(ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
/* NOTE: Interface has disappeared, not link down ... */
|
||||
dbg("%s: Delete link", ifname);
|
||||
net_cond_set(ifname, "exist", 0);
|
||||
net_cond_set(ifname, "up", 0);
|
||||
net_cond_set(ifname, "running", 0);
|
||||
nl_check_default(ifname);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
dbg("%s: New Address", ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
dbg("%s: Deconfig Address", ifname);
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int nl_parse(int sd)
|
||||
{
|
||||
while (1) {
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
size_t l;
|
||||
|
||||
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN: /* Nothing more right now. */
|
||||
return 0;
|
||||
|
||||
case EINTR: /* Signal */
|
||||
continue;
|
||||
|
||||
case ENOBUFS: /* netlink(7) */
|
||||
break;
|
||||
|
||||
default:
|
||||
err(1, "recv()");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// dbg("recv %zd bytes", len);
|
||||
l = (size_t)len;
|
||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||
struct nlmsgerr *nle;
|
||||
|
||||
switch (nh->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
// dbg("Done with netlink messages.");
|
||||
return 0;
|
||||
|
||||
case NLMSG_ERROR:
|
||||
// dbg("Kernel netlink comm. error.");
|
||||
nle = NLMSG_DATA(nh);
|
||||
if (nle) {
|
||||
errno = -nle->error;
|
||||
err(1, "Kernel netlink error %d", errno);
|
||||
}
|
||||
return -1;
|
||||
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
// dbg("Netlink route ...");
|
||||
nl_route(nh, len);
|
||||
break;
|
||||
|
||||
while (RTA_OK(a, la)) {
|
||||
if (a->rta_type == IFLA_IFNAME) {
|
||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||
switch (nlmsg->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
/*
|
||||
* New interface has appeared, or interface flags has changed.
|
||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||
*/
|
||||
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||
net_cond_set(ifname, "exist", 1);
|
||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
// dbg("Netlink link ...");
|
||||
nl_link(nh, len);
|
||||
/* NOTE: Interface has disappeared, not link down ... */
|
||||
_d("%s: Delete link", ifname);
|
||||
net_cond_set(ifname, "exist", 0);
|
||||
net_cond_set(ifname, "up", 0);
|
||||
net_cond_set(ifname, "running", 0);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
_d("%s: New Address", ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
_d("%s: Deconfig Address", ifname);
|
||||
break;
|
||||
|
||||
default:
|
||||
warnx("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
a = RTA_NEXT(a, la);
|
||||
}
|
||||
}
|
||||
|
||||
static int nl_request(int sd, unsigned int seq, int type)
|
||||
{
|
||||
struct nl_request *nlr = (struct nl_request *)nl_buf;
|
||||
|
||||
memset(nlr, 0, sizeof(struct nl_request));
|
||||
nlr->nh.nlmsg_type = type;
|
||||
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||
nlr->nh.nlmsg_seq = seq;
|
||||
nlr->nh.nlmsg_pid = 1;
|
||||
|
||||
switch (type) {
|
||||
case RTM_GETROUTE:
|
||||
// dbg("RTM_GETROUTE");
|
||||
nlr->rtm.rtm_family = AF_INET;
|
||||
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
break;
|
||||
|
||||
case RTM_GETLINK:
|
||||
// dbg("RTM_GETLINK");
|
||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
break;
|
||||
|
||||
default:
|
||||
warnx("Cannot resync, unhandled message type %d", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
|
||||
return 1;
|
||||
|
||||
return nl_parse(sd);
|
||||
}
|
||||
|
||||
static void nl_resync_routes(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||
err(1, "Failed netlink route request");
|
||||
}
|
||||
|
||||
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_request(sd, seq, RTM_GETLINK))
|
||||
err(1, "Failed netlink link request");
|
||||
}
|
||||
|
||||
/*
|
||||
* We've potentially lost netlink events, let's resync with kernel.
|
||||
*/
|
||||
static void nl_resync(int all)
|
||||
{
|
||||
unsigned int seq = 0;
|
||||
int sd;
|
||||
|
||||
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
if (sd < 0) {
|
||||
err(1, "netlink socket");
|
||||
return;
|
||||
}
|
||||
|
||||
if (all) {
|
||||
dbg("============================ RESYNC =================================");
|
||||
/* this doesn't update conditions, and thus does not stop services */
|
||||
cond_deassert("net/");
|
||||
|
||||
nl_resync_ifaces(sd, seq++);
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
/* delayed update after we've corrected things */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
dbg("=========================== RESYNCED ================================");
|
||||
} else
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
close(sd);
|
||||
}
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
{
|
||||
if (nl_parse(sd) < 0) {
|
||||
if (errno == ENOBUFS) { /* netlink(7) */
|
||||
warnx("busy system, resynchronizing with kernel.");
|
||||
nl_resync(1);
|
||||
return;
|
||||
}
|
||||
ssize_t len;
|
||||
static char buf[4096];
|
||||
struct nlmsghdr *nh;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = recv(sd, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
if (errno != EINTR) /* Signal */
|
||||
_pe("recv()");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux doesn't send route changes when interfaces go down, so
|
||||
* we need to check ourselves, e.g. for loss of default route.
|
||||
*/
|
||||
if (nl_ifdown) {
|
||||
dbg("interface down, checking default route.");
|
||||
if (nl_defidx > 0) {
|
||||
nl_defidx = 0;
|
||||
nl_resync(0);
|
||||
if (nl_defidx <= 0) {
|
||||
cond_clear("net/route/default");
|
||||
nl_defidx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nl_ifdown = 0;
|
||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
||||
nl_route(nh);
|
||||
else
|
||||
nl_link(nh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,29 +201,22 @@ static plugin_t plugin = {
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
struct sockaddr_nl sa;
|
||||
int sd;
|
||||
struct sockaddr_nl sa;
|
||||
|
||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sd < 0) {
|
||||
err(1, "socket()");
|
||||
_pe("socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
|
||||
sa.nl_pid = getpid();
|
||||
|
||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
err(1, "bind()");
|
||||
close(sd);
|
||||
return;
|
||||
}
|
||||
|
||||
nl_buf = malloc(NL_BUFSZ);
|
||||
if (!nl_buf) {
|
||||
err(1, "malloc()");
|
||||
_pe("bind()");
|
||||
close(sd);
|
||||
return;
|
||||
}
|
||||
@@ -450,7 +228,6 @@ PLUGIN_INIT(plugin_init)
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
close(plugin.io.fd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+37
-81
@@ -1,7 +1,7 @@
|
||||
/* Simple pidfile event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -52,13 +52,13 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
|
||||
ptr = slash++;
|
||||
slash = strchr(ptr, '/');
|
||||
if (slash) {
|
||||
dbg("Path too deep, skipping.");
|
||||
_d("Path too deep, skipping.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||
return iwatch_add(iw, path, IN_ONLYDIR);
|
||||
}
|
||||
|
||||
static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
@@ -68,66 +68,34 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
svc_t *svc;
|
||||
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
_d("path: %s, mask: %08x", fn, mask);
|
||||
|
||||
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
||||
return;
|
||||
|
||||
dbg("path: %s, mask: %08x", fn, mask);
|
||||
|
||||
svc = svc_find_by_pidfile(fn);
|
||||
if (!svc) {
|
||||
dbg("No matching svc for %s", fn);
|
||||
_d("No matching svc for %s", fn);
|
||||
return;
|
||||
}
|
||||
|
||||
dbg("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
|
||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||
/*
|
||||
* only mark native services as started, the s6 and
|
||||
* systemd style services rely on their respective
|
||||
* readiness notification. Issue #343
|
||||
*/
|
||||
if (!svc->notify)
|
||||
svc_started(svc);
|
||||
|
||||
if (!svc_has_pidfile(svc)) {
|
||||
dbg("Setting %s PID file to %s", svc->name, fn);
|
||||
pid_file_set(svc, fn, 1);
|
||||
}
|
||||
|
||||
if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||
svc_started(svc);
|
||||
if (svc_is_forking(svc)) {
|
||||
pid_t pid;
|
||||
|
||||
pid = pid_file_read(fn);
|
||||
if (pid == -1) {
|
||||
/* handle case when service dies immediately */
|
||||
if (!fexist(fn))
|
||||
cond_clear(cond);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Service is not crashing, let's tell state machine! */
|
||||
service_forked(svc);
|
||||
|
||||
if (pid != svc->pid) {
|
||||
dbg("Forking service %s (cmd %s) changed PID from %d to %d",
|
||||
svc_ident(svc, NULL, 0), svc->cmd, svc->pid, pid);
|
||||
svc->pid = pid;
|
||||
|
||||
/* Complement log in service.c for non-forking services */
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Started %s[%d]", svc_ident(svc, NULL, 0), pid);
|
||||
}
|
||||
pid = pid_file_read(pid_file(svc));
|
||||
_d("Forking service %s changed PID from %d to %d",
|
||||
svc->cmd, svc->pid, pid);
|
||||
svc->pid = pid;
|
||||
}
|
||||
|
||||
cond_set(cond);
|
||||
if (!svc->notify)
|
||||
service_ready(svc);
|
||||
} else if (mask & IN_DELETE) {
|
||||
} else if (mask & IN_DELETE)
|
||||
cond_clear(cond);
|
||||
if (!svc->notify)
|
||||
service_ready(svc);
|
||||
}
|
||||
}
|
||||
|
||||
/* synthesize events in case of new run dirs */
|
||||
@@ -149,7 +117,7 @@ static void pidfile_scandir(struct iwatch *iw, char *dir, int len)
|
||||
return;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
dbg("scan found %s", gl.gl_pathv[i]);
|
||||
_d("scan found %s", gl.gl_pathv[i]);
|
||||
pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||
}
|
||||
globfree(&gl);
|
||||
@@ -164,7 +132,7 @@ static void pidfile_handle_dir(struct iwatch *iw, char *dir, char *name, int mas
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
paste(path, sizeof(path), dir, name);
|
||||
dbg("path: %s", path);
|
||||
_d("path: %s", path);
|
||||
|
||||
iwp = iwatch_find_by_path(iw, path);
|
||||
|
||||
@@ -183,29 +151,24 @@ static void pidfile_callback(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
ssize_t sz, off;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
_pe("invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||
|
||||
/* Find base path for this event */
|
||||
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
|
||||
if (!iwp)
|
||||
@@ -216,7 +179,12 @@ static void pidfile_callback(void *arg, int fd, int events)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->mask & (IN_CLOSE_WRITE | IN_DELETE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||
if (ev->mask & IN_DELETE) {
|
||||
_d("pidfile %s/%s removed ...", iwp->path, ev->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||
pidfile_update_conds(iwp->path, ev->name, ev->mask);
|
||||
}
|
||||
}
|
||||
@@ -240,9 +208,6 @@ static void pidfile_reconf(void *arg)
|
||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||
continue;
|
||||
|
||||
if (!svc->notify)
|
||||
service_ready(svc);
|
||||
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
if (cond_get(cond) == COND_ON)
|
||||
continue;
|
||||
@@ -251,9 +216,9 @@ static void pidfile_reconf(void *arg)
|
||||
}
|
||||
|
||||
/*
|
||||
* This calls service_step(), which in turn schedules itself as
|
||||
* long as stepped services change state. Services going from
|
||||
* PAUSED to RUNNING reassert their conditions in that loop,
|
||||
* This will call service_step(), which in turn will schedule itself
|
||||
* as long as stepped services change state. Services going from
|
||||
* WAITING to RUNNING will reassert their conditions in that loop,
|
||||
* which in turn may unlock other services, and so on.
|
||||
*/
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
||||
@@ -261,14 +226,8 @@ static void pidfile_reconf(void *arg)
|
||||
|
||||
static void pidfile_init(void *arg)
|
||||
{
|
||||
char piddir[MAX_ARG_LEN];
|
||||
char *path;
|
||||
|
||||
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
||||
err(1, "Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bootmisc plugin is responsible for setting up /var/run.
|
||||
* and/or /run, with proper symlinks etc. We depend on bootmisc
|
||||
@@ -276,18 +235,15 @@ static void pidfile_init(void *arg)
|
||||
*/
|
||||
path = realpath(_PATH_VARRUN, NULL);
|
||||
if (!path) {
|
||||
dbg("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
||||
path = realpath("/run", NULL);
|
||||
if (!path) {
|
||||
errx(1, "System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pidfile_add_path(&iw_pidfile, path))
|
||||
iwatch_exit(&iw_pidfile);
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -300,15 +256,15 @@ static void pidfile_init(void *arg)
|
||||
*
|
||||
* service <net/iface/lo> /sbin/dropbear ...
|
||||
*
|
||||
* This service provides the <pid/dropbear> condition, which will not be
|
||||
* set by pidfile.so during `initctl reload` because dropbear is still
|
||||
* SIGSTP:ed (in state PAUSED) waiting for <net/iface/lo>.
|
||||
* Which provides the <pid/dropbear> condition, will not be set by
|
||||
* pidfile.so during `initctl reload` because dropbear is still
|
||||
* SIGSTP:ed waiting for <net/iface/lo>.
|
||||
*/
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
||||
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
||||
.depends = { "netlink" }, /* bootmisc depends on us */
|
||||
.depends = { "netlink" },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
@@ -328,8 +284,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_pidfile);
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-20
@@ -1,6 +1,6 @@
|
||||
/* Set kernel variables from /etc/sysctl.conf et al
|
||||
*
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,24 +22,14 @@
|
||||
*/
|
||||
|
||||
#include <glob.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include <lite/lite.h>
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
char buf[160];
|
||||
|
||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
@@ -49,13 +39,9 @@ static void setup(void *arg)
|
||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||
if (gl.gl_pathc > 0) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char cmd[160];
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(cmd, "sysctl");
|
||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(buf);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Setup necessary files for resolvconf
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,11 +21,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -37,7 +33,7 @@
|
||||
*/
|
||||
static void setup(void *arg)
|
||||
{
|
||||
dbg("Setting up the resolver ...");
|
||||
_d("Setting up the resolver ...");
|
||||
mkpath("/etc/resolvconf", 0755);
|
||||
mkpath("/etc/resolvconf/run", 0755);
|
||||
mkpath("/var/run/resolvconf", 0755);
|
||||
@@ -45,7 +41,7 @@ static void setup(void *arg)
|
||||
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0);
|
||||
run_parts("/etc/resolvconf/update.d", "-i");
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
|
||||
+9
-50
@@ -1,6 +1,6 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,29 +21,17 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/rtc.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
/* Kernel RTC driver validates against this date for sanity check */
|
||||
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
|
||||
#ifdef RTC_TIMESTAMP_CUSTOM
|
||||
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
|
||||
#else
|
||||
static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||
#endif
|
||||
static time_t rtc_date_fallback = 946684800LL;
|
||||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
||||
|
||||
static void tz_set(char *tz, size_t len)
|
||||
{
|
||||
@@ -96,21 +84,16 @@ static void rtc_save(void *arg)
|
||||
int fd, rc = 0;
|
||||
char tz[128];
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
tz_set(tz, sizeof(tz));
|
||||
rc = gettimeofday(&tv, NULL);
|
||||
if (rc < 0 || tv.tv_sec < rtc_date_fallback) {
|
||||
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||
invalid:
|
||||
logit(LOG_ERR, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
|
||||
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
||||
rc = 2;
|
||||
goto out;
|
||||
}
|
||||
@@ -138,16 +121,9 @@ static void rtc_restore(void *arg)
|
||||
int fd, rc = 0;
|
||||
char tz[128];
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0) {
|
||||
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
|
||||
if (fd < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
tz_set(tz, sizeof(tz));
|
||||
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||
@@ -161,29 +137,19 @@ static void rtc_restore(void *arg)
|
||||
invalid:
|
||||
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||
if (EINVAL == errno)
|
||||
logit(LOG_ERR, "RTC time is too old (before %s)", rtc_timestamp);
|
||||
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
|
||||
else if (ENOENT == errno)
|
||||
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_date_fallback;
|
||||
if (!gmtime_r(&tv.tv_sec, &tm))
|
||||
goto out;
|
||||
|
||||
logit(LOG_NOTICE, "Resetting RTC to kernel default, %s.", rtc_timestamp);
|
||||
rc = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
||||
tv.tv_sec = mktime(&tm);
|
||||
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
|
||||
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||
errno = EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
@@ -209,13 +175,6 @@ static plugin_t plugin = {
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
struct tm tm = { 0 };
|
||||
|
||||
if (!strptime(rtc_timestamp, "%Y-%m-%d %H:%M", &tm))
|
||||
rtc_date_fallback = mktime(&tm);
|
||||
else
|
||||
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
|
||||
-213
@@ -1,213 +0,0 @@
|
||||
/* System condition event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <glob.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "pid.h"
|
||||
#include "plugin.h"
|
||||
#include "iwatch.h"
|
||||
|
||||
static struct iwatch iw_sys;
|
||||
|
||||
|
||||
static int sys_add_path(struct iwatch *iw, char *path)
|
||||
{
|
||||
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
* unlink conditions with no active task/service, otherwise they may
|
||||
* trigger inadvertently when calling `initctl reload` to activate
|
||||
* a new configuration.
|
||||
*/
|
||||
static void sys_update_conds(char *dir, char *name, uint32_t mask)
|
||||
{
|
||||
char path[256];
|
||||
char *cond;
|
||||
char *ptr;
|
||||
|
||||
ptr = strrchr(name, '/');
|
||||
if (ptr)
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, ++ptr);
|
||||
else
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
|
||||
cond = strstr(path, COND_BASE);
|
||||
if (!cond)
|
||||
return;
|
||||
|
||||
cond += strlen(COND_BASE) + 1;
|
||||
dbg("cond: %s set: %d", cond, (mask & IN_CREATE) ? 1 : 0);
|
||||
if (!cond_update(cond))
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
/* synthesize events in case of new run dirs */
|
||||
static void sys_scandir(struct iwatch *iw, char *dir, int len)
|
||||
{
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
char path[len + 6];
|
||||
int rc;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/*", dir);
|
||||
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||
if (rc && rc != GLOB_NOMATCH)
|
||||
return;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
dbg("scan found %s", gl.gl_pathv[i]);
|
||||
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
/*
|
||||
* create/remove sub-directory in monitored directory
|
||||
*/
|
||||
static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
||||
{
|
||||
char path[strlen(dir) + strlen(name) + 2];
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
paste(path, sizeof(path), dir, name);
|
||||
dbg("path: %s", path);
|
||||
|
||||
iwp = iwatch_find_by_path(iw, path);
|
||||
|
||||
if (mask & IN_CREATE) {
|
||||
if (!iwp) {
|
||||
if (!sys_add_path(iw, path))
|
||||
sys_scandir(iw, path, sizeof(path));
|
||||
}
|
||||
} else if (mask & IN_DELETE) {
|
||||
if (iwp)
|
||||
iwatch_del(&iw_sys, iwp);
|
||||
}
|
||||
}
|
||||
|
||||
static void sys_callback(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
/* Find base path for this event */
|
||||
iwp = iwatch_find_by_wd(&iw_sys, ev->wd);
|
||||
if (!iwp)
|
||||
continue;
|
||||
|
||||
if (ev->mask & IN_ISDIR) {
|
||||
sys_handle_dir(&iw_sys, iwp->path, ev->name, ev->mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||
sys_update_conds(iwp->path, ev->name, ev->mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void sys_init(void *arg)
|
||||
{
|
||||
char sysdir[MAX_ARG_LEN];
|
||||
char *path;
|
||||
|
||||
mkpath(_PATH_COND, 0755);
|
||||
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||
err(1, "Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
path = realpath(_PATH_CONDSYS, NULL);
|
||||
if (!path) {
|
||||
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||
iwatch_exit(&iw_sys);
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
||||
.depends = { "bootmisc", },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = iwatch_init(&iw_sys);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
plugin.io.fd = fd;
|
||||
plugin.io.cb = sys_callback;
|
||||
plugin.io.flags = PLUGIN_IO_READ;
|
||||
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_sys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+30
-54
@@ -1,7 +1,7 @@
|
||||
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
||||
*
|
||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,23 +27,18 @@
|
||||
#include <unistd.h> /* read() */
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
#include "tty.h"
|
||||
|
||||
static void tty_watcher(void *arg, int fd, int events);
|
||||
static void watcher(void *arg, int fd, int events);
|
||||
|
||||
static plugin_t plugin = {
|
||||
.io = {
|
||||
.cb = tty_watcher,
|
||||
.cb = watcher,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
@@ -55,56 +50,36 @@ static void setup(void)
|
||||
|
||||
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
||||
err(1, "Failed starting TTY watcher");
|
||||
_pe("Failed starting TTY watcher");
|
||||
}
|
||||
|
||||
static void do_tty(char *tty, size_t len, int creat)
|
||||
static void watcher(void *arg, int fd, int events)
|
||||
{
|
||||
char name[len + 6];
|
||||
svc_t *svc;
|
||||
char buf[EVENT_SIZE];
|
||||
int len = 0;
|
||||
|
||||
snprintf(name, sizeof(name), "/dev/%s", tty);
|
||||
svc = svc_find_by_tty(name);
|
||||
if (svc) {
|
||||
if (svc_is_blocked(svc) && creat) {
|
||||
dbg("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
||||
svc_start(svc);
|
||||
} else if (svc->pid) {
|
||||
dbg("%s: missing ...", svc_ident(svc, NULL, 0));
|
||||
svc_missing(svc);
|
||||
while ((len = read(fd, buf, sizeof(buf)))) {
|
||||
struct inotify_event *notified = (struct inotify_event *)buf;
|
||||
char name[notified->len + 6];
|
||||
struct tty *entry;
|
||||
|
||||
if (-1 == len) {
|
||||
if (errno == EINVAL)
|
||||
setup();
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
break; /* Likely EAGAIN */
|
||||
}
|
||||
|
||||
service_step_all(SVC_TYPE_TTY);
|
||||
}
|
||||
}
|
||||
|
||||
static void tty_watcher(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
dbg("tty %s, event: 0x%08x", ev->name, ev->mask);
|
||||
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
||||
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
||||
entry = tty_find(name);
|
||||
if (entry && tty_enabled(entry)) {
|
||||
if (notified->mask & IN_CREATE)
|
||||
tty_start(entry);
|
||||
else if (entry->pid)
|
||||
tty_stop(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,9 +91,10 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
if (plugin.io.fd)
|
||||
close(plugin.io.fd);
|
||||
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-92
@@ -1,6 +1,6 @@
|
||||
/* Setup and save random seed at boot/shutdown
|
||||
/* Setup random seed
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,46 +22,25 @@
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h> /* gettimeofday() */
|
||||
#include <sys/types.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <linux/random.h>
|
||||
#include <lite/lite.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) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fexist(RANDOMSEED)) {
|
||||
int ret = 1;
|
||||
mode_t prev;
|
||||
FILE *fp;
|
||||
|
||||
print_desc("Bootstrapping random seed", NULL);
|
||||
prev = umask(077);
|
||||
umask(077);
|
||||
fp = fopen(RANDOMSEED, "w");
|
||||
if (fp) {
|
||||
int iter = 128;
|
||||
@@ -78,82 +57,21 @@ static void setup(void *arg)
|
||||
ret = fclose(fp);
|
||||
}
|
||||
print_result(ret);
|
||||
umask(prev);
|
||||
umask(0);
|
||||
}
|
||||
|
||||
print_desc("Seeding random number generator", NULL);
|
||||
|
||||
/*
|
||||
* 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));
|
||||
print_desc("Initializing random number generator", NULL);
|
||||
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void save(void *arg)
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
mode_t prev;
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
prev = umask(077);
|
||||
|
||||
umask(077);
|
||||
print_desc("Saving random seed", NULL);
|
||||
print_result(RANDOM_BYTES != copyfile("/dev/urandom", RANDOMSEED, RANDOM_BYTES, 0));
|
||||
|
||||
umask(prev);
|
||||
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
||||
umask(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
/* User-defined condition event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <glob.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "pid.h"
|
||||
#include "plugin.h"
|
||||
#include "iwatch.h"
|
||||
|
||||
static struct iwatch iw_usr;
|
||||
|
||||
|
||||
static void usr_cond(char *name, uint32_t mask)
|
||||
{
|
||||
char cond[MAX_COND_LEN] = COND_USR;
|
||||
|
||||
strlcat(cond, name, sizeof(cond));
|
||||
cond_update(cond);
|
||||
}
|
||||
|
||||
static void usr_callback(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
if (ev->mask & IN_ISDIR)
|
||||
continue; /* unsupported */
|
||||
|
||||
if (ev->mask & IN_DELETE)
|
||||
sync(); /* dont ask */
|
||||
|
||||
usr_cond(ev->name, ev->mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void usr_init(void *arg)
|
||||
{
|
||||
char usrdir[MAX_ARG_LEN];
|
||||
char *path;
|
||||
|
||||
mkpath(_PATH_COND, 0755);
|
||||
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
||||
err(1, "Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
||||
return;
|
||||
}
|
||||
|
||||
path = realpath(_PATH_CONDUSR, NULL);
|
||||
if (!path) {
|
||||
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
|
||||
iwatch_exit(&iw_usr);
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
||||
.depends = { "bootmisc", },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = iwatch_init(&iw_usr);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
plugin.io.fd = fd;
|
||||
plugin.io.cb = usr_callback;
|
||||
plugin.io.flags = PLUGIN_IO_READ;
|
||||
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_usr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+32
-13
@@ -1,6 +1,6 @@
|
||||
/* Console setup (for X)
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,11 +24,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -36,18 +32,41 @@
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
}
|
||||
#ifdef PAM_CONSOLE
|
||||
int fd;
|
||||
#endif
|
||||
char line[LINE_SIZE];
|
||||
const char *username = "nobody";
|
||||
|
||||
if (fexist("/var/run/console/console.lock") && which("pam_console_apply"))
|
||||
run("pam_console_apply", "pam-console");
|
||||
umask(0);
|
||||
|
||||
makedir("/var/run/console", 01777);
|
||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||
touch(line);
|
||||
|
||||
#ifdef PAM_CONSOLE
|
||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, username, strlen(username));
|
||||
close(fd);
|
||||
run("pam_console_apply");
|
||||
}
|
||||
#endif
|
||||
|
||||
makedir("/tmp/.X11-unix", 01777);
|
||||
makedir("/tmp/.ICE-unix", 01777);
|
||||
|
||||
if (whichp("restorecon"))
|
||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||
.hook[HOOK_NETWORK_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
.depends = { "bootmisc", }
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
.deps/*
|
||||
finit
|
||||
getty
|
||||
initctl
|
||||
keventd
|
||||
logit
|
||||
reboot
|
||||
sulogin
|
||||
watchdogd
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
+22
-47
@@ -1,5 +1,6 @@
|
||||
EXTRA_DIST = rescue.conf sample.conf
|
||||
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
EXTRA_DIST = cgreaper.sh rescue.conf sample.conf
|
||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
if STATIC
|
||||
AM_CPPFLAGS += -DENABLE_STATIC
|
||||
AM_LDFLAGS = -static-libtool-libs
|
||||
@@ -7,47 +8,27 @@ else
|
||||
AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS = getty logit
|
||||
if SULOGIN
|
||||
pkglibexec_PROGRAMS += sulogin
|
||||
endif
|
||||
if KEVENTD
|
||||
pkglibexec_PROGRAMS += keventd
|
||||
endif
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_SCRIPTS = cgreaper.sh
|
||||
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
getty_SOURCES = finit.h getty.c helpers.h logrotate.c stty.c utmp-api.c utmp-api.h
|
||||
getty_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
getty_CFLAGS += $(lite_CFLAGS)
|
||||
getty_LDADD = $(lite_LIBS)
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS = watchdogd
|
||||
endif
|
||||
|
||||
keventd_SOURCES = keventd.c iwatch.c iwatch.h util.c util.h
|
||||
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
keventd_CFLAGS += $(lite_CFLAGS)
|
||||
keventd_LDADD = $(lite_LIBS)
|
||||
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
sulogin_LDADD = -lcrypt
|
||||
|
||||
logit_SOURCES = logit.c logrotate.c
|
||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
logit_CFLAGS += $(lite_CFLAGS)
|
||||
logit_LDADD = $(lite_LIBS)
|
||||
if LOGIT
|
||||
pkglibexec_PROGRAMS = logit
|
||||
logit_SOURCES = logit.c
|
||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
endif
|
||||
|
||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
client.c client.h \
|
||||
cond.c cond-w.c cond.h \
|
||||
conf.c conf.h \
|
||||
devmon.c devmon.h \
|
||||
exec.c finit.c finit.h \
|
||||
stty.c \
|
||||
getty.c stty.c \
|
||||
helpers.c helpers.h \
|
||||
iwatch.c iwatch.h \
|
||||
log.c log.h \
|
||||
@@ -59,18 +40,11 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
sig.c sig.h \
|
||||
sm.c sm.h \
|
||||
svc.c svc.h \
|
||||
tmpfiles.c tmpfiles.h \
|
||||
tty.c tty.h \
|
||||
util.c util.h \
|
||||
utmp-api.c utmp-api.h
|
||||
if LOGROTATE
|
||||
finit_SOURCES += logrotate.c
|
||||
endif
|
||||
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h
|
||||
|
||||
pkginclude_HEADERS = cgroup.h cond.h conf.h finit.h helpers.h log.h \
|
||||
plugin.h svc.h service.h
|
||||
|
||||
finit_CPPFLAGS = $(AM_CPPFLAGS) -D__FINIT__
|
||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||
@@ -80,19 +54,20 @@ else
|
||||
finit_LDADD += -ldl
|
||||
endif
|
||||
|
||||
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
||||
client.c client.h cond.c cond.h reboot.c \
|
||||
serv.c serv.h svc.h util.c util.h log.h
|
||||
initctl_SOURCES = initctl.c client.c client.h \
|
||||
reboot.c serv.c serv.h svc.h \
|
||||
cond.c cond.h util.c util.h
|
||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||
initctl_CFLAGS += $(lite_CFLAGS)
|
||||
initctl_LDADD = $(lite_LIBS)
|
||||
|
||||
INIT_LNKS = init telinit
|
||||
INIT_LNKS = init
|
||||
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
||||
|
||||
if WATCHDOGD
|
||||
watchdogd_SOURCES = watchdog.c watchdog.h
|
||||
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
#log.c log.h
|
||||
endif
|
||||
|
||||
# Hook in install to add finit and reboot symlink(s)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,8 +21,6 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -31,13 +29,10 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <lite/lite.h>
|
||||
#include <uev/uev.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "conf.h"
|
||||
@@ -45,73 +40,47 @@
|
||||
#include "log.h"
|
||||
#include "plugin.h"
|
||||
#include "private.h"
|
||||
#include "schedule.h"
|
||||
#include "service.h"
|
||||
#include "sig.h"
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
|
||||
extern svc_t *wdog;
|
||||
static uev_t api_watcher;
|
||||
|
||||
static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||
{
|
||||
return svc_parse_jobstr(buf, len, NULL, action, NULL);
|
||||
return svc_parse_jobstr(buf, len, action, NULL);
|
||||
}
|
||||
|
||||
static int stop(svc_t *svc, void *user_data)
|
||||
static int stop(svc_t *svc)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
svc_stop(svc);
|
||||
service_step(svc);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start(svc_t *svc, void *user_data)
|
||||
static int start(svc_t *svc)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
svc_start(svc);
|
||||
service_step(svc);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: this does not wait for svc to be stopped first, that is the
|
||||
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
||||
* or introduce some nasty race conditions.
|
||||
*/
|
||||
static int restart(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
if (!svc_is_running(svc))
|
||||
return start(svc, user_data);
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
service_stop(svc);
|
||||
service_step(svc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload(svc_t *svc, void *user_data)
|
||||
static int restart(svc_t *svc)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
if (svc_is_blocked(svc))
|
||||
svc_start(svc);
|
||||
else
|
||||
service_timeout_cancel(svc);
|
||||
|
||||
svc_mark_dirty(svc);
|
||||
service_step(svc);
|
||||
@@ -119,33 +88,12 @@ static int reload(svc_t *svc, void *user_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
||||
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||
static int do_reload (char *buf, size_t len) { return call(reload, buf, len); }
|
||||
|
||||
static int do_signal_svc(svc_t *svc, void *user_data)
|
||||
{
|
||||
int signo;
|
||||
|
||||
if (!svc || !user_data || !svc_is_running(svc))
|
||||
return 1;
|
||||
|
||||
signo = *(int *)user_data;
|
||||
return !!kill(svc->pid, signo);
|
||||
}
|
||||
|
||||
static int do_signal(char *buf, size_t len, int sig)
|
||||
{
|
||||
/* Sanity check: do we know this signal? */
|
||||
if (!*sig2str(sig))
|
||||
return 1;
|
||||
|
||||
return svc_parse_jobstr(buf, len, &sig, do_signal_svc, NULL);
|
||||
}
|
||||
|
||||
static char query_buf[368];
|
||||
static int missing(char *job, char *id, void *user_data)
|
||||
static int missing(char *job, char *id)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
@@ -162,8 +110,8 @@ static int missing(char *job, char *id, void *user_data)
|
||||
|
||||
static int do_query(char *buf, size_t len)
|
||||
{
|
||||
query_buf[0] = 0;
|
||||
if (svc_parse_jobstr(buf, len, NULL, NULL, missing)) {
|
||||
memset(query_buf, 0, sizeof(query_buf));
|
||||
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
||||
memcpy(buf, query_buf, len);
|
||||
return 1;
|
||||
}
|
||||
@@ -207,93 +155,70 @@ static svc_t *do_find(char *buf, size_t len)
|
||||
if (!id)
|
||||
return svc_named_iterator(&iter, 1, input);
|
||||
|
||||
return svc_find(input, id);
|
||||
return svc_find_by_nameid(input, id);
|
||||
}
|
||||
|
||||
static svc_t *do_find_byc(char *buf, size_t len)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
char *input;
|
||||
|
||||
input = sanitize(buf, len);
|
||||
if (!input) {
|
||||
dbg("Invalid input");
|
||||
_d("Invalid input");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return svc_find_by_cond(input);
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
char cond[MAX_COND_LEN];
|
||||
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
_d("Comparing input %s with cond %s", input, cond);
|
||||
if (string_compare(cond, input))
|
||||
return svc;
|
||||
}
|
||||
|
||||
_d("None found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bypass_shutdown(void *);
|
||||
struct wq emergency = { .cb = bypass_shutdown };
|
||||
|
||||
static void bypass_shutdown(void *unused)
|
||||
{
|
||||
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
|
||||
do_shutdown(halt);
|
||||
}
|
||||
|
||||
static int do_reboot(int cmd, int timeout, char *buf, size_t len)
|
||||
static int do_reboot(int cmd, char *buf, size_t len)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
switch (cmd) {
|
||||
case INIT_CMD_REBOOT:
|
||||
halt = SHUT_REBOOT;
|
||||
break;
|
||||
|
||||
case INIT_CMD_HALT:
|
||||
halt = SHUT_HALT;
|
||||
break;
|
||||
|
||||
case INIT_CMD_POWEROFF:
|
||||
halt = SHUT_OFF;
|
||||
break;
|
||||
|
||||
case INIT_CMD_SUSPEND:
|
||||
break;
|
||||
|
||||
default:
|
||||
return 255;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
emergency.delay = timeout * 1000;
|
||||
schedule_work(&emergency);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case INIT_CMD_REBOOT:
|
||||
dbg("reboot");
|
||||
_d("reboot");
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(6);
|
||||
break;
|
||||
|
||||
case INIT_CMD_HALT:
|
||||
dbg("halt");
|
||||
_d("halt");
|
||||
halt = SHUT_HALT;
|
||||
service_runlevel(0);
|
||||
break;
|
||||
|
||||
case INIT_CMD_POWEROFF:
|
||||
dbg("poweroff");
|
||||
_d("poweroff");
|
||||
halt = SHUT_OFF;
|
||||
service_runlevel(0);
|
||||
break;
|
||||
|
||||
case INIT_CMD_SUSPEND:
|
||||
dbg("suspend");
|
||||
_d("suspend");
|
||||
sync();
|
||||
rc = suspend();
|
||||
rc = reboot(RB_SW_SUSPEND);
|
||||
if (rc) {
|
||||
if (errno == EINVAL)
|
||||
snprintf(buf, len, "Kernel does not support suspend to RAM.");
|
||||
snprintf(buf, len, "Kernel does not support suspend.");
|
||||
else
|
||||
snprintf(buf, len, "Failed: %s", strerror(errno));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Handled previously */
|
||||
rc = 255;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -312,7 +237,7 @@ ev_t ev_list[] = {
|
||||
|
||||
static void send_svc(int sd, svc_t *svc)
|
||||
{
|
||||
svc_t empty = { 0 };
|
||||
svc_t empty;
|
||||
size_t len;
|
||||
|
||||
if (!svc) {
|
||||
@@ -322,19 +247,19 @@ static void send_svc(int sd, svc_t *svc)
|
||||
|
||||
len = write(sd, svc, sizeof(*svc));
|
||||
if (len != sizeof(*svc))
|
||||
dbg("Failed sending svc_t to client");
|
||||
_d("Failed sending svc_t to client");
|
||||
}
|
||||
|
||||
static void api_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
static svc_t *iter = NULL;
|
||||
struct init_request rq;
|
||||
int sd, lvl;
|
||||
svc_t *svc;
|
||||
static svc_t *iter = NULL;
|
||||
struct init_request rq;
|
||||
|
||||
sd = accept(w->fd, NULL, NULL);
|
||||
if (sd < 0) {
|
||||
err(1, "Failed serving API request");
|
||||
_pe("Failed serving API request");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -351,37 +276,14 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
if (EAGAIN == errno)
|
||||
break;
|
||||
|
||||
/* we get here when client restarts itself */
|
||||
if (ECONNRESET == errno)
|
||||
break;
|
||||
|
||||
errx(1, "Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||
errx(1, "Invalid initctl request");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
case INIT_CMD_RELOAD:
|
||||
case INIT_CMD_START_SVC:
|
||||
case INIT_CMD_RESTART_SVC:
|
||||
case INIT_CMD_STOP_SVC:
|
||||
case INIT_CMD_RELOAD_SVC:
|
||||
case INIT_CMD_REBOOT:
|
||||
case INIT_CMD_HALT:
|
||||
case INIT_CMD_POWEROFF:
|
||||
case INIT_CMD_SUSPEND:
|
||||
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||
warnx("Unsupported command in runlevel S and 6.");
|
||||
goto leave;
|
||||
}
|
||||
default:
|
||||
_e("Invalid initctl request");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -394,7 +296,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
/* fallthrough */
|
||||
|
||||
case '0'...'9':
|
||||
dbg("Setting new runlevel %c", rq.runlevel);
|
||||
_d("Setting new runlevel %c", rq.runlevel);
|
||||
lvl = rq.runlevel - '0';
|
||||
if (lvl == 0)
|
||||
halt = SHUT_OFF;
|
||||
@@ -404,55 +306,41 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg("Unsupported runlevel: %d", rq.runlevel);
|
||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case INIT_CMD_DEBUG:
|
||||
dbg("debug");
|
||||
_d("debug");
|
||||
log_debug();
|
||||
break;
|
||||
|
||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||
dbg("reload");
|
||||
_d("reload");
|
||||
service_reload_dynamic();
|
||||
break;
|
||||
|
||||
case INIT_CMD_START_SVC:
|
||||
dbg("start %s", rq.data);
|
||||
_d("start %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_start(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_RESTART_SVC:
|
||||
dbg("restart %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_restart(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_STOP_SVC:
|
||||
dbg("stop %s", rq.data);
|
||||
_d("stop %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_stop(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_RELOAD_SVC:
|
||||
dbg("reload %s", rq.data);
|
||||
case INIT_CMD_RESTART_SVC:
|
||||
_d("restart %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_reload(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_GET_PLUGINS:
|
||||
result = plugin_list(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_PLUGIN_DEPS:
|
||||
result = plugin_deps(rq.data, sizeof(rq.data));
|
||||
result = do_restart(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_GET_RUNLEVEL:
|
||||
dbg("get runlevel");
|
||||
_d("get runlevel");
|
||||
rq.runlevel = runlevel;
|
||||
rq.sleeptime = prevlevel;
|
||||
break;
|
||||
@@ -461,47 +349,41 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
case INIT_CMD_HALT:
|
||||
case INIT_CMD_POWEROFF:
|
||||
case INIT_CMD_SUSPEND:
|
||||
result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data));
|
||||
result = do_reboot(rq.cmd, rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_ACK:
|
||||
dbg("Client failed reading ACK");
|
||||
_d("Client failed reading ACK");
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_WDOG_HELLO:
|
||||
dbg("wdog hello");
|
||||
_d("wdog hello");
|
||||
if (rq.runlevel <= 0) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
dbg("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||
svc = svc_find_by_pid(rq.runlevel);
|
||||
if (!svc) {
|
||||
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||
if (!svc_find_by_pid(rq.runlevel)) {
|
||||
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wdog && wdog != svc) {
|
||||
char name[32];
|
||||
|
||||
svc_ident(svc, name, sizeof(name));
|
||||
logit(LOG_NOTICE, "Handing over wdog ctrl from %s[%d] to %s[%d]",
|
||||
svc_ident(wdog, NULL, 0), wdog->pid, name, svc->pid);
|
||||
|
||||
/* Disable and allow Finit to collect bundled watchdog */
|
||||
if (wdog) {
|
||||
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
||||
stop(wdog);
|
||||
if (wdog->protect) {
|
||||
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||
stop(wdog, NULL);
|
||||
svc_del(wdog);
|
||||
wdog->protect = 0;
|
||||
wdog->runlevels = 0;
|
||||
}
|
||||
}
|
||||
wdog = svc;
|
||||
break;
|
||||
|
||||
case INIT_CMD_SVC_ITER:
|
||||
// dbg("svc iter, first: %d", rq.runlevel);
|
||||
_d("svc iter, first: %d", rq.runlevel);
|
||||
/*
|
||||
* XXX: This severely limits the number of
|
||||
* XXX: This severly limits the number of
|
||||
* simultaneous client connections, but will
|
||||
* have to do for now.
|
||||
*/
|
||||
@@ -510,46 +392,25 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_SVC_QUERY:
|
||||
dbg("svc query: %s", rq.data);
|
||||
_d("svc query: %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_query(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_SVC_FIND:
|
||||
dbg("svc find: %s", rq.data);
|
||||
_d("svc find: %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_SVC_FIND_BYC:
|
||||
dbg("svc find by cond: %s", rq.data);
|
||||
_d("svc find by cond: %s", rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_SIGNAL:
|
||||
/* runlevel is reused for signal */
|
||||
dbg("svc signal %d: %s", rq.runlevel, rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
||||
break;
|
||||
|
||||
case INIT_CMD_NOTIFY_SOCKET:
|
||||
svc = svc_find_by_pid(rq.runlevel);
|
||||
if (!svc) {
|
||||
errx(1, "Unknown PID, cannot register notify socket");
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uev_io_init(ctx, &svc->notify_watcher, service_notify_cb, svc, sd, UEV_READ)) {
|
||||
err(1, "Falied initializing %s readiness notifier", svc_ident(svc, NULL, 0));
|
||||
break;
|
||||
}
|
||||
return; /* Don't close sd, used for notify */
|
||||
|
||||
default:
|
||||
dbg("Unsupported cmd: %d", rq.cmd);
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -559,7 +420,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
rq.cmd = INIT_CMD_ACK;
|
||||
len = write(sd, &rq, sizeof(rq));
|
||||
if (len != sizeof(rq))
|
||||
dbg("Failed sending ACK/NACK back to client");
|
||||
_d("Failed sending ACK/NACK back to client");
|
||||
}
|
||||
|
||||
leave:
|
||||
@@ -570,46 +431,39 @@ leave:
|
||||
error:
|
||||
api_exit();
|
||||
if (api_init(w->ctx))
|
||||
errx(1, "Unrecoverable error on API socket");
|
||||
_e("Unrecoverable error on API socket");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
dbg("Setting up external API socket ...");
|
||||
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||
_d("Setting up external API socket ...");
|
||||
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (-1 == sd) {
|
||||
err(1, "Failed starting external API socket");
|
||||
_pe("Failed starting external API socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uid = geteuid();
|
||||
gid = getgroup(DEFGROUP);
|
||||
|
||||
erase(INIT_SOCKET);
|
||||
oldmask = umask(0117);
|
||||
oldmask = umask(0077);
|
||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||
goto error;
|
||||
|
||||
if (-1 == listen(sd, 10))
|
||||
goto error;
|
||||
|
||||
if (chown(INIT_SOCKET, uid, gid))
|
||||
err(1, "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:
|
||||
err(1, "Failed initializing API socket");
|
||||
_pe("Failed intializing API socket");
|
||||
umask(oldmask);
|
||||
close(sd);
|
||||
return 1;
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
# Called by kernel when last child in cgroup exists
|
||||
|
||||
BASE=/sys/fs/cgroup/finit
|
||||
PROC=`basename $1`
|
||||
DIR="$BASE$1"
|
||||
|
||||
/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
||||
rmdir $DIR
|
||||
|
||||
exit 0
|
||||
+83
-488
@@ -1,6 +1,6 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,517 +24,112 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.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 <lite/lite.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysinfo.h> /* get_nprocs_conf() */
|
||||
|
||||
#include "cgroup.h"
|
||||
#include "finit.h"
|
||||
#include "iwatch.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
struct cg {
|
||||
TAILQ_ENTRY(cg) link;
|
||||
|
||||
char *name; /* top-level group name */
|
||||
char *cfg; /* kernel settings */
|
||||
|
||||
int active; /* for mark & sweep */
|
||||
int is_protected; /* for init/, user/, & system/ */
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(, cg) cgroups = TAILQ_HEAD_INITIALIZER(cgroups);
|
||||
|
||||
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)
|
||||
{
|
||||
char *val;
|
||||
|
||||
dbg("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
||||
if (!path || !ctrl) {
|
||||
errx(1, "Missing path or controller, skipping!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!prop) {
|
||||
prop = strchr(ctrl, '.');
|
||||
if (!prop) {
|
||||
errx(1, "Invalid cgroup ctrl syntax: %s", ctrl);
|
||||
return;
|
||||
}
|
||||
|
||||
*prop++ = 0;
|
||||
}
|
||||
|
||||
val = strchr(prop, ':');
|
||||
if (!val) {
|
||||
errx(1, "Missing cgroup ctrl value, prop %s", prop);
|
||||
return;
|
||||
}
|
||||
*val++ = 0;
|
||||
|
||||
/* disallow sneaky relative paths */
|
||||
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
||||
return;
|
||||
}
|
||||
|
||||
dbg("%s/%s.%s <= %s", path, ctrl, prop, val);
|
||||
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
||||
err(1, "Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Settings for a cgroup are on the form: cpu.weight:1234,mem.max:4321,...
|
||||
* Finit supports the short-form 'mem.', replacing it with 'memory.' when
|
||||
* writing the setting to the file system.
|
||||
*/
|
||||
static void group_init(char *path, int leaf, const char *cfg)
|
||||
{
|
||||
char *ptr, *s;
|
||||
|
||||
dbg("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
||||
if (!fisdir(path)) {
|
||||
if (mkdir(path, 0755)) {
|
||||
err(1, "Failed creating cgroup %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* enable detected controllers on domain groups */
|
||||
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
||||
err(1, "Failed enabling %s for %s", controllers, path);
|
||||
}
|
||||
|
||||
if (!cfg || !cfg[0])
|
||||
return;
|
||||
|
||||
s = strdupa(cfg);
|
||||
if (!s) {
|
||||
err(1, "Failed activating cgroup cfg for %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
dbg("%s <=> %s", path, s);
|
||||
ptr = strtok(s, ",");
|
||||
while (ptr) {
|
||||
dbg("ptr: %s", ptr);
|
||||
if (!strncmp("mem.", ptr, 4))
|
||||
cgset(path, "memory", &ptr[4]);
|
||||
else
|
||||
cgset(path, ptr, NULL);
|
||||
|
||||
ptr = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
|
||||
static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
dbg("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
||||
if (pid < 0 || pid == 1) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create and initialize new group */
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
||||
group_init(path, 1, cfg);
|
||||
|
||||
/* move process to new group */
|
||||
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
||||
err(1, "Failed moving pid %d to group %s", pid, path);
|
||||
|
||||
strlcat(path, "/cgroup.events", sizeof(path));
|
||||
|
||||
return iwatch_add(&iw_cgroup, path, 0);
|
||||
}
|
||||
|
||||
int cgroup_user(char *name, int pid)
|
||||
{
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
return cgroup_leaf_init("user", name, pid, NULL);
|
||||
}
|
||||
|
||||
int cgroup_service(char *name, int pid, struct cgroup *cg)
|
||||
{
|
||||
char *group = "system";
|
||||
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
if (cg && cg->name[0]) {
|
||||
char path[256];
|
||||
|
||||
if (!strcmp(cg->name, "root"))
|
||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
|
||||
|
||||
if (!strcmp(cg->name, "init"))
|
||||
return fnwrite(str("%d", pid), FINIT_CGPATH "/init/cgroup.procs");
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
|
||||
if (fisdir(path))
|
||||
group = cg->name;
|
||||
}
|
||||
|
||||
return cgroup_leaf_init(group, name, pid, cg ? cg->cfg : NULL);
|
||||
}
|
||||
|
||||
static void append_ctrl(char *ctrl)
|
||||
{
|
||||
if (controllers[0])
|
||||
strlcat(controllers, " ", sizeof(controllers));
|
||||
|
||||
strlcat(controllers, "+", sizeof(controllers));
|
||||
strlcat(controllers, ctrl, sizeof(controllers));
|
||||
}
|
||||
|
||||
static void cgroup_handle_event(char *event, uint32_t mask)
|
||||
{
|
||||
char path[strlen(event) + 1];
|
||||
char buf[80];
|
||||
char *ptr;
|
||||
FILE *fp;
|
||||
|
||||
dbg("event: '%s', mask: %08x", event, mask);
|
||||
if (!(mask & IN_MODIFY))
|
||||
return;
|
||||
|
||||
fp = fopen(event, "r");
|
||||
if (!fp) {
|
||||
dbg("Failed opening %s, skipping ...", event);
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
if (strncmp(buf, "populated", 9))
|
||||
continue;
|
||||
|
||||
chomp(buf);
|
||||
if (atoi(&buf[10]))
|
||||
break;
|
||||
|
||||
strlcpy(path, event, sizeof(path));
|
||||
ptr = strrchr(path, '/');
|
||||
if (ptr) {
|
||||
*ptr = 0;
|
||||
if (!cgroup_del(path)) {
|
||||
/*
|
||||
* try with parent, top-level group, we
|
||||
* may get events out-of-order *sigh*
|
||||
*/
|
||||
ptr = strrchr(path, '/');
|
||||
if (!ptr)
|
||||
break;
|
||||
*ptr = 0;
|
||||
cgroup_del(path);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
/* Find base path for this event */
|
||||
iwp = iwatch_find_by_wd(&iw_cgroup, ev->wd);
|
||||
if (!iwp || !iwp->path)
|
||||
continue;
|
||||
|
||||
cgroup_handle_event(iwp->path, ev->mask);
|
||||
}
|
||||
|
||||
#ifdef AUTO_RELOAD
|
||||
if (conf_any_change())
|
||||
service_reload_dynamic();
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct cg *cgroup_find(char *name)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||
if (strcmp(cg->name, name))
|
||||
continue;
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Marks all unprotected cgroups for deletion (during reload)
|
||||
*/
|
||||
void cgroup_mark_all(void)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
if (!avail)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||
if (cg->is_protected)
|
||||
continue;
|
||||
|
||||
cg->active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove (try to) all unused cgroups
|
||||
*/
|
||||
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;
|
||||
|
||||
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||
cgroup_del(path);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add, or update, settings for top-level cgroup
|
||||
*/
|
||||
int cgroup_add(char *name, char *cfg, int is_protected)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
if (!cfg)
|
||||
cfg = "";
|
||||
|
||||
cg = cgroup_find(name);
|
||||
if (!cg) {
|
||||
cg = malloc(sizeof(struct cg));
|
||||
if (!cg) {
|
||||
err(1, "Failed allocating 'struct cg' for %s", name);
|
||||
return -1;
|
||||
}
|
||||
cg->name = strdup(name);
|
||||
if (!cg->name) {
|
||||
err(1, "Failed setting cgroup name %s", name);
|
||||
free(cg);
|
||||
return -1;
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&cgroups, cg, link);
|
||||
} else
|
||||
free(cg->cfg);
|
||||
|
||||
cg->cfg = strdup(cfg);
|
||||
if (!cg->cfg) {
|
||||
err(1, "Failed add/update of cgroup %s", name);
|
||||
TAILQ_REMOVE(&cgroups, cg, link);
|
||||
free(cg->name);
|
||||
free(cg);
|
||||
return -1;
|
||||
}
|
||||
cg->is_protected = is_protected;
|
||||
cg->active = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove inactive top-level cgroup
|
||||
*/
|
||||
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))
|
||||
continue;
|
||||
|
||||
if (cg->active)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rmdir(dir) && errno != ENOENT) {
|
||||
dbg("Failed removing %s: %s", dir, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cg) {
|
||||
TAILQ_REMOVE(&cgroups, cg, link);
|
||||
free(cg->name);
|
||||
free(cg->cfg);
|
||||
free(cg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the top-level init cgroup is a leaf, that's ensured in cgroup_init() */
|
||||
void cgroup_config(void)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
if (!avail)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||
char path[256];
|
||||
int leaf = 0;
|
||||
|
||||
if (!cg->active)
|
||||
continue;
|
||||
if (!strcmp(cg->name, "init"))
|
||||
leaf = 1; /* reserved */
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, cg->name);
|
||||
group_init(path, leaf, cg->cfg);
|
||||
|
||||
strlcat(path, "/cgroup.events", sizeof(path));
|
||||
iwatch_add(&iw_cgroup, path, 0);
|
||||
}
|
||||
}
|
||||
static int cg_init = 0;
|
||||
|
||||
/*
|
||||
* Called by Finit at early boot to mount initial cgroups
|
||||
*/
|
||||
void cgroup_init(uev_ctx_t *ctx)
|
||||
void cgroup_init(void)
|
||||
{
|
||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||
char buf[80];
|
||||
FILE *fp;
|
||||
int fd;
|
||||
char buf[80];
|
||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||
|
||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||
if (errno == ENOENT)
|
||||
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
||||
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
||||
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
||||
else
|
||||
err(1, "Failed mounting cgroup v2");
|
||||
avail = 0;
|
||||
return;
|
||||
}
|
||||
avail = 1;
|
||||
|
||||
/* Find available controllers */
|
||||
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||
fp = fopen("/proc/cgroups", "r");
|
||||
if (!fp) {
|
||||
err(1, "Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||
abort:
|
||||
umount(FINIT_CGPATH);
|
||||
avail = 0;
|
||||
_d("No cgroup support");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
if (mount("none", "/sys/fs/cgroup", "tmpfs", opts, NULL)) {
|
||||
_d("Failed mounting cgroups");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Skip first line, header */
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
char *cgroup;
|
||||
char rc[80];
|
||||
|
||||
cgroup = strtok(chomp(buf), "\t ");
|
||||
while (cgroup) {
|
||||
append_ctrl(cgroup);
|
||||
cgroup = strtok(NULL, "\t ");
|
||||
}
|
||||
cgroup = strtok(buf, "\t ");
|
||||
if (!cgroup)
|
||||
continue;
|
||||
|
||||
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
||||
if (mkdir(rc, 0755) && EEXIST != errno)
|
||||
continue;
|
||||
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
||||
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
||||
}
|
||||
|
||||
/* Default cgroups for process monitoring */
|
||||
if (mkdir("/sys/fs/cgroup/finit", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
if (mount("none", "/sys/fs/cgroup/finit", "cgroup", opts, "none,name=finit")) {
|
||||
_pe("Failed mounting Finit cgroup hierarchy");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set up reaper and enable callbacks */
|
||||
echo("/sys/fs/cgroup/finit/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
||||
echo("/sys/fs/cgroup/finit/notify_on_release", 0, "1");
|
||||
|
||||
/* Default groups, PID 1, services, and user/login processes */
|
||||
if (mkdir("/sys/fs/cgroup/finit/init", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
if (mkdir("/sys/fs/cgroup/finit/system", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
if (mkdir("/sys/fs/cgroup/finit/user", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
|
||||
/* Move ourselves to init */
|
||||
echo("/sys/fs/cgroup/finit/init/cgroup.procs", 0, "1");
|
||||
|
||||
/* We have signal, main screen turn on! */
|
||||
cg_init = 1;
|
||||
fail:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* Check for cpu controller, abort if missing */
|
||||
if (!strstr(controllers, "+cpu")) {
|
||||
logit(LOG_NOTICE, "Missing CPU controller, disabling cgroup support.");
|
||||
goto abort;
|
||||
static int move_pid(char *group, char *name, char *id, int pid)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s:%s", group, name, id);
|
||||
if (mkdir(path, 0755) && errno != EEXIST)
|
||||
return 1;
|
||||
|
||||
strlcat(path, "/cgroup.procs", sizeof(path));
|
||||
|
||||
return echo(path, 0, "%d", pid);
|
||||
}
|
||||
|
||||
int cgroup_user(char *name)
|
||||
{
|
||||
if (!cg_init)
|
||||
return 0;
|
||||
|
||||
return move_pid("finit/user", name, "0", getpid());
|
||||
}
|
||||
|
||||
int cgroup_service(char *nm, char *id, int pid)
|
||||
{
|
||||
if (!cg_init)
|
||||
return 0;
|
||||
|
||||
if (pid <= 0) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Enable all controllers */
|
||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
||||
err(1, "Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* prepare cgroup.events watcher */
|
||||
fd = iwatch_init(&iw_cgroup);
|
||||
if (fd == -1)
|
||||
goto abort;
|
||||
|
||||
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
||||
err(1, "Failed setting up cgroup.events watcher");
|
||||
iwatch_exit(&iw_cgroup);
|
||||
close(fd);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||
cgroup_add("init", "cpu.weight:100", 1);
|
||||
cgroup_add("system", "cpu.weight:9800", 1);
|
||||
cgroup_add("user", "cpu.weight:100", 1);
|
||||
cgroup_config();
|
||||
|
||||
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||
err(1, "Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||
uev_io_stop(&cgw);
|
||||
iwatch_exit(&iw_cgroup);
|
||||
close(fd);
|
||||
goto abort;
|
||||
}
|
||||
return move_pid("finit/system", nm, id, pid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-18
@@ -1,6 +1,6 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,23 +24,9 @@
|
||||
#ifndef FINIT_CGROUP_H_
|
||||
#define FINIT_CGROUP_H_
|
||||
|
||||
#include <uev/uev.h>
|
||||
void cgroup_init (void);
|
||||
|
||||
struct cgroup {
|
||||
char name[16];
|
||||
char cfg[128];
|
||||
};
|
||||
|
||||
void cgroup_mark_all(void);
|
||||
void cgroup_cleanup (void);
|
||||
|
||||
int cgroup_add (char *name, char *cfg, int is_protected);
|
||||
int cgroup_del (char *dir);
|
||||
void cgroup_config (void);
|
||||
|
||||
void cgroup_init (uev_ctx_t *ctx);
|
||||
|
||||
int cgroup_user (char *name, int pid);
|
||||
int cgroup_service (char *name, int pid, struct cgroup *cg);
|
||||
int cgroup_user (char *name);
|
||||
int cgroup_service (char *cmd, char *id, int pid);
|
||||
|
||||
#endif /* FINIT_CGROUP_H_ */
|
||||
|
||||
-664
@@ -1,664 +0,0 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <search.h>
|
||||
#include <inttypes.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <sys/sysinfo.h> /* sysinfo() */
|
||||
|
||||
#include "cgutil.h"
|
||||
#include "initctl.h"
|
||||
#include "log.h"
|
||||
|
||||
#define CDIM plain ? "" : "\e[2m"
|
||||
#define CRST plain ? "" : "\e[0m"
|
||||
|
||||
#define NONE " "
|
||||
#define PIPE plain ? "| " : "│ "
|
||||
#define FORK plain ? "|-" : "├─"
|
||||
#define END plain ? "`-" : "└─"
|
||||
|
||||
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)
|
||||
{
|
||||
size_t i, sz;
|
||||
char *ptr;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "/proc/%d/cmdline", pid);
|
||||
if (!fp) {
|
||||
buf[0] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
sz = fread(buf, sizeof(buf[0]), len - 1, fp);
|
||||
fclose(fp);
|
||||
if (!sz)
|
||||
return NULL; /* kernel thread */
|
||||
|
||||
buf[sz] = 0;
|
||||
|
||||
ptr = strchr(buf, 0);
|
||||
if (ptr && ptr != buf) {
|
||||
ptr++;
|
||||
sz -= ptr - buf;
|
||||
memmove(buf, ptr, sz + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
if (buf[i] == 0)
|
||||
buf[i] = ' ';
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *pid_comm(int pid, char *buf, size_t len)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "/proc/%d/comm", pid);
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
if (fgets(buf, len, fp))
|
||||
ptr = chomp(buf);
|
||||
fclose(fp);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *pid_cgroup(int pid, char *buf, size_t len)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "/proc/%d/cgroup", pid);
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
if (fgets(buf, len, fp))
|
||||
ptr = chomp(buf);
|
||||
fclose(fp);
|
||||
|
||||
if (ptr)
|
||||
ptr = strchr(buf, '/');
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static char *cgroup_val(char *path, char *file, char *buf, size_t len)
|
||||
{
|
||||
char *val = NULL;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "%s/%s", path, file);
|
||||
if (fp) {
|
||||
if (fgets(buf, len, fp)) {
|
||||
val = chomp(buf);
|
||||
len = strcspn(val, " \t");
|
||||
val[len] = 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint64_t cgroup_uint64(char *path, char *file)
|
||||
{
|
||||
uint64_t val = 0;
|
||||
char buf[42];
|
||||
|
||||
if (cgroup_val(path, file, buf, sizeof(buf)))
|
||||
val = strtoull(buf, NULL, 10);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static char *cgroup_memval(char *path, char *file, char *buf, size_t len)
|
||||
{
|
||||
char data[42];
|
||||
|
||||
if (cgroup_val(path, file, data, sizeof(data))) {
|
||||
if (!strcmp(data, "max"))
|
||||
strlcpy(buf, data, len);
|
||||
else
|
||||
memsz(strtoull(data, NULL, 10), buf, len);
|
||||
} else
|
||||
buf[0] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static uint64_t cgroup_memuse(struct cg *cg)
|
||||
{
|
||||
char buf[42];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "%s/memory.stat", cg->cg_path);
|
||||
if (fp) {
|
||||
cg->cg_rss = 0;
|
||||
cg->cg_vmlib = 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
chomp(buf);
|
||||
|
||||
if (!strncmp(buf, "anon", 4)) {
|
||||
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "slab", 4)) {
|
||||
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "kernel_stack", 12)) {
|
||||
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "pagetables", 10)) {
|
||||
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "percpu", 6)) {
|
||||
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "sock", 4)) {
|
||||
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "file", 4)) {
|
||||
cg->cg_vmlib += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(buf, "file_mapped", 11)) {
|
||||
cg->cg_vmlib += strtoull(&buf[5], NULL, 10);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
cg->cg_memshare = (float)(cg->cg_rss * 100 / total_ram);
|
||||
|
||||
return cg->cg_vmsize = cgroup_uint64(cg->cg_path, "memory.current");
|
||||
}
|
||||
|
||||
uint64_t cgroup_memory(char *group)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
paste(path, sizeof(path), FINIT_CGPATH, group);
|
||||
|
||||
return cgroup_uint64(path, "memory.current");
|
||||
}
|
||||
|
||||
static float cgroup_cpuload(struct cg *cg)
|
||||
{
|
||||
char fn[256];
|
||||
char buf[64];
|
||||
FILE *fp;
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s/cpu.stat", cg->cg_path);
|
||||
fp = fopen(fn, "r");
|
||||
if (!fp)
|
||||
ERR(72, "Cannot open %s", fn);
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
uint64_t curr;
|
||||
|
||||
chomp(buf);
|
||||
if (strncmp(buf, "usage_usec", 10))
|
||||
continue;
|
||||
|
||||
curr = strtoull(&buf[11], NULL, 10);
|
||||
if (cg->cg_prev != 0) {
|
||||
uint64_t diff = curr - cg->cg_prev;
|
||||
|
||||
/* this expects 1 sec poll interval */
|
||||
cg->cg_load = (float)(diff / 1000000);
|
||||
cg->cg_load *= 100.0;
|
||||
}
|
||||
cg->cg_prev = curr;
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return cg->cg_load;
|
||||
}
|
||||
|
||||
static struct cg *append(char *path)
|
||||
{
|
||||
struct cg *cg;
|
||||
char fn[256];
|
||||
ENTRY item;
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s/cpu.stat", path);
|
||||
if (access(fn, F_OK)) {
|
||||
/* older kernels, 4.19, don't have summary cpu.stat in root */
|
||||
if (strcmp(path, FINIT_CGPATH))
|
||||
WARN("not a cgroup path with cpu controller, %s", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cg = calloc(1, sizeof(struct cg));
|
||||
if (!cg)
|
||||
ERR(71, "failed allocating struct cg");
|
||||
|
||||
cg->cg_path = strdup(path);
|
||||
if (list)
|
||||
cg->cg_next = list;
|
||||
list = cg;
|
||||
|
||||
item.key = cg->cg_path;
|
||||
item.data = cg;
|
||||
if (!hsearch(item, ENTER))
|
||||
ERR(70, "failed adding to hash table");
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
static struct cg *find(char *path)
|
||||
{
|
||||
ENTRY *ep, item = { path, NULL };
|
||||
|
||||
ep = hsearch(item, FIND);
|
||||
if (ep)
|
||||
return ep->data;
|
||||
|
||||
return append(path);
|
||||
}
|
||||
|
||||
/* update stats */
|
||||
struct cg *cg_stats(char *path)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
cg = find(path);
|
||||
if (!cg)
|
||||
return &dummy;
|
||||
|
||||
cgroup_cpuload(cg);
|
||||
cgroup_memuse(cg);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
/* query config */
|
||||
struct cg *cg_conf(char *path)
|
||||
{
|
||||
static struct cg cg;
|
||||
|
||||
cgroup_val(path, "memory.min", cg.cg_mem.min, sizeof(cg.cg_mem.min));
|
||||
cgroup_memval(path, "memory.max", cg.cg_mem.max, sizeof(cg.cg_mem.max));
|
||||
cgroup_val(path, "cpu.weight", cg.cg_cpu.weight, sizeof(cg.cg_cpu.weight));
|
||||
cgroup_val(path, "cpu.max", cg.cg_cpu.max, sizeof(cg.cg_cpu.max));
|
||||
cgroup_val(path, "cpuset.cpus.effective", cg.cg_cpu.set, sizeof(cg.cg_cpu.set));
|
||||
cg.cg_vmsize = cgroup_uint64(path, "memory.current");
|
||||
|
||||
return &cg;
|
||||
}
|
||||
|
||||
static int cgroup_filter(const struct dirent *entry)
|
||||
{
|
||||
/* Skip current dir ".", and prev dir "..", from list of files */
|
||||
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
|
||||
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
|
||||
return 0;
|
||||
|
||||
if (entry->d_name[0] == '.')
|
||||
return 0;
|
||||
|
||||
if (entry->d_type != DT_DIR)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
||||
{
|
||||
struct dirent **namelist = NULL;
|
||||
char s[32], r[32], l[32];
|
||||
char row[ttcols + 9]; /* + control codes */
|
||||
size_t rlen = sizeof(row) - 1;
|
||||
size_t rplen = rlen - 9;
|
||||
struct stat st;
|
||||
struct cg *cg;
|
||||
char buf[512];
|
||||
int rc = 0;
|
||||
FILE *fp;
|
||||
int i, n;
|
||||
int num;
|
||||
|
||||
if (pos >= ttrows)
|
||||
return 0;
|
||||
|
||||
if (-1 == lstat(path, &st))
|
||||
return 1;
|
||||
|
||||
if ((st.st_mode & S_IFMT) != S_IFDIR) {
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = fopenf("r", "%s/cgroup.procs", path);
|
||||
if (!fp)
|
||||
return -1;
|
||||
num = 0;
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
num++;
|
||||
|
||||
if (!pfx) {
|
||||
pfx = "";
|
||||
switch (mode) {
|
||||
case 1:
|
||||
cg = cg_stats(path);
|
||||
snprintf(row, rplen, "\r %6.6s %6.6s %6.6s %5.1f %5.1f %s",
|
||||
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||
memsz(cg->cg_rss, r, sizeof(r)),
|
||||
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||
cg->cg_memshare, cg->cg_load, path);
|
||||
break;
|
||||
case 2:
|
||||
cg = cg_conf(path);
|
||||
snprintf(row, rplen, "\r%6.6s [%-6.6s%6.6s] %6s [%-6.6s%6.6s] %s",
|
||||
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||
cg->cg_mem.min, cg->cg_mem.max, cg->cg_cpu.set,
|
||||
cg->cg_cpu.weight, cg->cg_cpu.max, path);
|
||||
break;
|
||||
default:
|
||||
strlcpy(row, "\r", rplen);
|
||||
strlcat(row, path, rplen);
|
||||
break;
|
||||
}
|
||||
|
||||
puts(row);
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
rewind(fp);
|
||||
|
||||
i = 0;
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
char comm[80] = { 0 };
|
||||
pid_t pid;
|
||||
|
||||
pid = atoi(chomp(buf));
|
||||
if (pid <= 0)
|
||||
continue;
|
||||
|
||||
/* skip kernel threads for now (no cmdline) */
|
||||
pid_comm(pid, comm, sizeof(comm));
|
||||
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
||||
char proc[ttcols];
|
||||
|
||||
switch (mode) {
|
||||
case 1:
|
||||
snprintf(row, rplen, "\r%37s", " ");
|
||||
break;
|
||||
case 2:
|
||||
snprintf(row, rplen, "\r --.-- [ ] [ ] ");
|
||||
break;
|
||||
default:
|
||||
strlcpy(row, "\r", rplen);
|
||||
break;
|
||||
}
|
||||
|
||||
strlcat(row, pfx, rplen);
|
||||
strlcat(row, ++i == num ? END : FORK, rlen);
|
||||
|
||||
snprintf(proc, sizeof(proc), " %d %s %s", pid, comm, buf);
|
||||
|
||||
if (plain) {
|
||||
strlcat(row, proc, rplen);
|
||||
} else {
|
||||
int len;
|
||||
|
||||
strlcat(row, CDIM, rlen);
|
||||
strlcat(row, proc, rlen);
|
||||
|
||||
len = strlen(row) + strlen(CRST);
|
||||
if (len > (int)rlen)
|
||||
row[rlen - strlen(CRST)] = 0;
|
||||
|
||||
strlcat(row, CRST, sizeof(row));
|
||||
}
|
||||
|
||||
puts(row);
|
||||
}
|
||||
|
||||
if (mode == 1) {
|
||||
pos += i;
|
||||
if (pos >= ttrows)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
n = scandir(path, &namelist, cgroup_filter, alphasort);
|
||||
if (n > 0) {
|
||||
for (i = 0; i < n; i++) {
|
||||
char *nm = namelist[i]->d_name;
|
||||
char prefix[80];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s", path, nm);
|
||||
switch (mode) {
|
||||
case 1:
|
||||
cg = cg_stats(buf);
|
||||
snprintf(row, rplen,
|
||||
"\r %6.6s %6.6s %6.6s %5.1f %5.1f ",
|
||||
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||
memsz(cg->cg_rss, r, sizeof(r)),
|
||||
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||
cg->cg_memshare, cg->cg_load);
|
||||
break;
|
||||
case 2:
|
||||
cg = cg_conf(buf);
|
||||
snprintf(row, rplen, "\r%6.6s [%-6.6s%6.6s] %6.6s [%-6.6s%6.6s] ",
|
||||
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||
cg->cg_mem.min, cg->cg_mem.max,
|
||||
cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max);
|
||||
break;
|
||||
default:
|
||||
strlcpy(row, "\r", rplen);
|
||||
break;
|
||||
}
|
||||
|
||||
strlcat(row, pfx, rplen);
|
||||
if (i + 1 == n) {
|
||||
strlcat(row, END, rplen);
|
||||
snprintf(prefix, sizeof(prefix), "%s ", pfx);
|
||||
} else {
|
||||
strlcat(row, FORK, rplen);
|
||||
snprintf(prefix, sizeof(prefix), "%s%s ", pfx, PIPE);
|
||||
}
|
||||
strlcat(row, " ", rplen);
|
||||
|
||||
strlcat(row, nm, rplen);
|
||||
strlcat(row, "/ ", rplen);
|
||||
|
||||
puts(row);
|
||||
|
||||
rc += cgroup_tree(buf, prefix, mode, pos + i);
|
||||
|
||||
free(namelist[i]);
|
||||
}
|
||||
|
||||
free(namelist);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int show_cgps(char *arg)
|
||||
{
|
||||
char path[512];
|
||||
|
||||
if (!arg)
|
||||
arg = FINIT_CGPATH;
|
||||
else if (arg[0] != '/') {
|
||||
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||
arg = path;
|
||||
}
|
||||
|
||||
return cgroup_tree(arg, NULL, 0, 0);
|
||||
}
|
||||
|
||||
static void cgtop(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)w;
|
||||
(void)events;
|
||||
|
||||
fputs("\e[2J\e[1;1H", stdout);
|
||||
if (heading)
|
||||
print_header(" VmSIZE RSS VmLIB %%MEM %%CPU GROUP");
|
||||
cgroup_tree(arg, NULL, 1, 0);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
ttcooked();
|
||||
showcursor();
|
||||
puts("");
|
||||
}
|
||||
|
||||
static void leave(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)arg;
|
||||
(void)events;
|
||||
|
||||
uev_exit(w->ctx);
|
||||
}
|
||||
|
||||
static void key(uev_t *w, void *arg, int events)
|
||||
{
|
||||
char ch;
|
||||
|
||||
(void)arg;
|
||||
(void)events;
|
||||
|
||||
if (read(w->fd, &ch, sizeof(ch)) != -1) {
|
||||
switch (ch) {
|
||||
case 'q':
|
||||
uev_exit(w->ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg("Got char 0x%02x", ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int show_cgtop(char *arg)
|
||||
{
|
||||
struct sysinfo si = { 0 };
|
||||
uev_t timer, input, sigint, sigterm, sigquit;
|
||||
char path[512];
|
||||
uev_ctx_t ctx;
|
||||
|
||||
if (!arg)
|
||||
arg = FINIT_CGPATH;
|
||||
else if (arg[0] != '/') {
|
||||
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||
arg = path;
|
||||
}
|
||||
|
||||
if (!hcreate(ttrows + 25))
|
||||
ERR(70, "failed creating hash table");
|
||||
|
||||
sysinfo(&si);
|
||||
total_ram = si.totalram * si.mem_unit;
|
||||
|
||||
uev_init(&ctx);
|
||||
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
|
||||
|
||||
if (!ionce && !plain) {
|
||||
int flags;
|
||||
|
||||
atexit(cleanup);
|
||||
ttraw();
|
||||
hidecursor();
|
||||
|
||||
flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||
if (flags != -1)
|
||||
(void)fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
|
||||
(void)uev_io_init(&ctx, &input, key, NULL, STDIN_FILENO, UEV_READ);
|
||||
|
||||
(void)uev_signal_init(&ctx, &sigint, leave, NULL, SIGINT);
|
||||
(void)uev_signal_init(&ctx, &sigterm, leave, NULL, SIGTERM);
|
||||
(void)uev_signal_init(&ctx, &sigquit, leave, NULL, SIGQUIT);
|
||||
}
|
||||
|
||||
return uev_run(&ctx, 0);
|
||||
}
|
||||
|
||||
int show_cgroup(char *arg)
|
||||
{
|
||||
char path[512];
|
||||
|
||||
if (!arg)
|
||||
arg = FINIT_CGPATH;
|
||||
else if (arg[0] != '/') {
|
||||
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||
arg = path;
|
||||
}
|
||||
|
||||
/* memory.current memory.min memory.max cpuset.cpus cpu.weight cpu.max */
|
||||
if (heading)
|
||||
print_header(" MEM [MIN MAX] CPU [WEIGHT MAX] GROUP");
|
||||
|
||||
return cgroup_tree(arg, NULL, 2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,79 +0,0 @@
|
||||
/* Cgroup utility functions for initctl
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_CGUTIL_H_
|
||||
#define FINIT_CGUTIL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct cg {
|
||||
struct cg *cg_next;
|
||||
|
||||
/* stats */
|
||||
char *cg_path; /* path in /sys/fs/cgroup */
|
||||
uint64_t cg_prev; /* cpuacct.usage */
|
||||
uint64_t cg_rss; /* memory.stat */
|
||||
uint64_t cg_vmlib; /* memory.stat */
|
||||
uint64_t cg_vmsize; /* memory.current */
|
||||
float cg_memshare; /* cg_rss / total_ram * 100 */
|
||||
float cg_load; /* curr - prev / 10000000.0 */
|
||||
|
||||
/* config */
|
||||
struct {
|
||||
char min[32];
|
||||
char max[32];
|
||||
} cg_mem;
|
||||
|
||||
struct {
|
||||
char set[16];
|
||||
char weight[32];
|
||||
char max[32];
|
||||
} 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);
|
||||
|
||||
uint64_t cgroup_memory(char *group);
|
||||
|
||||
struct cg *cg_stats(char *path);
|
||||
struct cg *cg_conf (char *path);
|
||||
|
||||
int cgroup_tree (char *path, char *pfx, int mode, int pos);
|
||||
|
||||
int show_cgroup (char *arg);
|
||||
int show_cgtop (char *arg);
|
||||
int show_cgps (char *arg);
|
||||
|
||||
#endif /* FINIT_CGUTIL_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user